Widow – Rev 15

Subversion Repositories:
Rev:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using Windows;
using Widow.Properties;

namespace Widow
{
    public class WindowManipulation : IDisposable
    {
        #region Public Enums, Properties and Fields

        public bool OnWindowCreate { get; set; }

        public int ApplyEveryTime { get; set; }

        public bool ApplyEveryTimeEnabled { get; set; }

        #endregion

        #region Private Delegates, Events, Enums, Properties, Indexers and Fields

        private MainForm Form { get; }

        private Windows.Windows WindowsToManipulate { get; }

        private CancellationTokenSource CancellationTokenSource { get; set; }

        private Task ApplyEveryTask { get; }

        private BufferBlock<WindowModification> WindowsBufferBlock { get; }

        private ActionBlock<WindowModification> WindowsActionBlock { get; }

        private IDisposable WindowsLink { get; set; }

        #endregion

        #region Constructors, Destructors and Finalizers

        public WindowManipulation()
        {
            CancellationTokenSource = new CancellationTokenSource();
            WindowsBufferBlock = new BufferBlock<WindowModification>();
            WindowsActionBlock = new ActionBlock<WindowModification>(ManipulateWindows);
            WindowsLink = WindowsBufferBlock.LinkTo(WindowsActionBlock);

            ApplyEveryTask = ApplyEvery(CancellationTokenSource.Token);
        }

        public WindowManipulation(MainForm mainForm) : this()
        {
            Form = mainForm;

            Form.WindowCreated += Form_WindowCreated;
        }

        public WindowManipulation(MainForm mainForm, Windows.Windows windowsToManipulate) : this(mainForm)
        {
            WindowsToManipulate = windowsToManipulate;
        }

        public WindowManipulation(MainForm mainForm, Windows.Windows windowsToManipulate, Settings settings) : this(
            mainForm,
            windowsToManipulate)
        {
            OnWindowCreate = settings.OnWindowCreate;
            ApplyEveryTimeEnabled = settings.ApplyEveryTimeEnabled;
            if (int.TryParse(settings.ApplyEveryTime, out var time))
            {
                ApplyEveryTime = time;
            }
        }

        public void Dispose()
        {
            WindowsLink?.Dispose();
            WindowsLink = null;

            Form.WindowCreated -= Form_WindowCreated;
            CancellationTokenSource.Cancel();
            ApplyEveryTask.Wait();
            CancellationTokenSource.Dispose();
            CancellationTokenSource = null;
        }

        #endregion

        #region Event Handlers

        private async void Form_WindowCreated(object sender, WindowCreatedEventArgs e)
        {
            if (!OnWindowCreate)
            {
                return;
            }

            var @class = Helpers.GetWindowClass(e.Handle);
            if (!WindowsToManipulate.TryGetWindow(new WindowHash(e.Title, @class), out _))
            {
                return;
            }

            await Apply();
        }

        #endregion

        #region Public Methods

        public async Task Apply()
        {
            var windows = new List<WindowModification>();
            foreach (var hWnd in Helpers.FindWindows((wnd, param) => true))
            {
                var windowTitle = Helpers.GetWindowTitle(hWnd);

                if (string.IsNullOrEmpty(windowTitle))
                {
                    continue;
                }

                var windowClass = Helpers.GetWindowClass(hWnd);
                if (string.IsNullOrEmpty(windowClass))
                {
                    continue;
                }

                var windowHash = new WindowHash(windowTitle, windowClass);
                if (!WindowsToManipulate.TryGetWindow(windowHash, out var window))
                {
                    continue;
                }

                windows.Add(new WindowModification(hWnd, window));
            }

            await Task.WhenAll(windows.Select(modification => WindowsBufferBlock.SendAsync(modification)));
        }

        #endregion

        #region Private Methods

        private static void ManipulateWindows(WindowModification modification)
        {
            if (modification.Handle == IntPtr.Zero)
            {
                return;
            }

            if (!Natives.GetWindowRect(modification.Handle, out var rect))
            {
                return;
            }

            var left = modification.Window.Left;
            if (modification.Window.IgnoreLeft)
            {
                left = rect.Left;
            }

            var top = modification.Window.Top;
            if (modification.Window.IgnoreTop)
            {
                top = rect.Top;
            }

            var width = modification.Window.Width;
            if (modification.Window.IgnoreWidth)
            {
                width = rect.Left - rect.Right;
            }

            var height = modification.Window.Height;
            if (modification.Window.IgnoreHeight)
            {
                height = rect.Top - rect.Bottom;
            }

            Natives.MoveWindow(modification.Handle, left, top, width, height, true);
        }

        private async Task ApplyEvery(CancellationToken cancellationToken)
        {
            do
            {
                if (!ApplyEveryTimeEnabled)
                {
                    await Task.Delay(1000, cancellationToken);
                    continue;
                }

                await Task.Delay(ApplyEveryTime, cancellationToken);

                await Apply();
            } while (!cancellationToken.IsCancellationRequested);
        }

        #endregion
    }
}

Generated by GNU Enscript 1.6.5.90.