/// <summary>
        /// Return the screen on which the taskbar with the given handle is displayed
        /// </summary>
        /// <param name="taskbarHwnd"></param>
        /// <returns></returns>
        private static Screen FindTaskbarScreen(IntPtr taskbarHwnd)
        {
            Rectangle taskbarRect = WindowUtils.GetWindowBounds(taskbarHwnd);
            var       screens     = Screen.AllScreens.ToList();

            return(screens.FirstOrDefault(x => x.Bounds.IntersectsWith(taskbarRect)));
        }
        /// <summary>
        /// Get the docking position of the taskbar with the given handle
        /// </summary>
        /// <param name="taskbarHwnd"></param>
        /// <returns></returns>
        internal static TaskbarDockPosition GetTaskbarDockPosition(IntPtr taskbarHwnd)
        {
            Screen screen      = FindTaskbarScreen(taskbarHwnd);
            var    taskbarRect = WindowUtils.GetWindowBounds(taskbarHwnd);

            if (screen.Bounds.Left == taskbarRect.Left && screen.Bounds.Top == taskbarRect.Top)
            {
                // taskbar touches the top left corner
                if (taskbarRect.Right == screen.Bounds.Right)
                {
                    // ... and the top right corner as well
                    return(TaskbarDockPosition.Top);
                }
                else
                {
                    return(TaskbarDockPosition.Left);
                }
            }
            else
            {
                // taskbar touches the bottom right corner
                if (taskbarRect.Left == screen.Bounds.Left)
                {
                    // and the bottom left corner as welt
                    return(TaskbarDockPosition.Bottom);
                }
                else
                {
                    return(TaskbarDockPosition.Right);
                }
            }
        }
        /// <summary>
        /// Reevaluates the DockPosition and Bounds
        /// and raises the PositionOrSizeChanged event if necessary
        /// </summary>
        public void Update(IntPtr childHwnd)
        {
            var oldDockPosition = DockPosition;
            var oldBounds       = Bounds;

            if (childHwnd == IntPtr.Zero)
            {
                DockPosition = TaskbarUtils.GetTaskbarDockPosition(Handle);
                Bounds       = WindowUtils.GetWindowBounds(Handle);

                // raised by the main taskbar, check if it was moved
                if (oldDockPosition != DockPosition || oldBounds != Bounds)
                {
                    RaisePositionOrSizeChanged(IntPtr.Zero);
                }
            }
            else
            {
                if (ObservedChildBoundChanges.TryGetValue(childHwnd, out Rectangle childRect))
                {
                    // check if the child bounds have really changed
                    var screenRect = WindowUtils.GetWindowBounds(childHwnd);

                    if (!screenRect.Equals(childRect))
                    {
                        RaisePositionOrSizeChanged(childHwnd);
                    }
                }
            }
        }
 public void RegisterObservableChild(IntPtr hwnd)
 {
     if (hwnd != IntPtr.Zero)
     {
         ObservedChildBoundChanges[hwnd] = WindowUtils.GetWindowBounds(hwnd);
     }
 }
        /// <summary>
        /// Show the primary taskbar's calendar flyout at the given location with the given alignment
        /// </summary>
        public static void ShowCalendarFlyOut(Rectangle alignTo, FlyoutAlignment alignment)
        {
            // get all window handles which have the same class as the
            // flyout, so that we know these are not the flyout
            var nonFlyoutHandles = WindowUtils.ListWindowsWithClass(CalendarFlyoutClassName);

            // invoke the primary taskbar's calendar flyout
            if (TaskbarUtils.InvokeCalendarFlyOut())
            {
                // wait for it to open (max. 2 seconds)
                IntPtr flyoutHwnd = IntPtr.Zero;
                int    start      = Environment.TickCount;
                while (flyoutHwnd == IntPtr.Zero && (Environment.TickCount - start <= 2000))
                {
                    flyoutHwnd = TaskbarUtils.GetCalendarFlyoutHwnd(nonFlyoutHandles);
                }

                if (flyoutHwnd != IntPtr.Zero)
                {
                    // and move it to this clock's location
                    NativeImports.RECT flyoutRect;
                    if (NativeImports.GetWindowRect(flyoutHwnd, out flyoutRect))
                    {
                        int flyoutWidth  = flyoutRect.Right - flyoutRect.Left;
                        int flyoutHeight = flyoutRect.Bottom - flyoutRect.Top;

                        switch (alignment)
                        {
                        case FlyoutAlignment.Below:
                            // place the calendar flyout below the clock
                            NativeImports.SetWindowPos(flyoutHwnd, IntPtr.Zero, alignTo.Right - flyoutWidth, alignTo.Bottom, 0, 0, NativeImports.SetWindowPosFlags.SWP_NOSIZE);
                            break;

                        case FlyoutAlignment.Above:
                            // place the calendar flyout above the clock
                            NativeImports.SetWindowPos(flyoutHwnd, IntPtr.Zero, alignTo.Right - flyoutWidth, alignTo.Top - flyoutHeight, 0, 0, NativeImports.SetWindowPosFlags.SWP_NOSIZE);
                            break;

                        case FlyoutAlignment.ToTheRight:
                            // place the calendar flyout to the right of the clock
                            NativeImports.SetWindowPos(flyoutHwnd, IntPtr.Zero, alignTo.Right, alignTo.Bottom - flyoutHeight, 0, 0, NativeImports.SetWindowPosFlags.SWP_NOSIZE);
                            break;

                        case FlyoutAlignment.ToTheLeft:
                            // place the calendar flyout to the left of the clock
                            NativeImports.SetWindowPos(flyoutHwnd, IntPtr.Zero, alignTo.Left - flyoutWidth, alignTo.Bottom - flyoutHeight, 0, 0, NativeImports.SetWindowPosFlags.SWP_NOSIZE);
                            break;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Return the handle of the taskbar's calendar flyout window
        /// </summary>
        /// <param name="exceptHandles">Only a potenial flyout window with a handle not in this set is returned</param>
        /// <returns></returns>
        private static IntPtr GetCalendarFlyoutHwnd(ISet <IntPtr> exceptHandles)
        {
            // since the text of the calendar flyout is language-dependent and the
            // class name is not unique, we search for a window of class
            // Windows.UI.Core.CoreWindow which touches the primary taskbar's clock
            // and is not contained in the passed set exceptHandles
            IntPtr    taskbarClockHwnd = GetPrimaryTaskbarClockHwnd();
            Rectangle taskbarClockRect = WindowUtils.GetWindowBounds(taskbarClockHwnd);

            IntPtr candidateHwnd = NativeImports.FindWindowEx(IntPtr.Zero, IntPtr.Zero, CalendarFlyoutClassName, null);

            while (candidateHwnd != IntPtr.Zero)
            {
                // is this window a potential candidate to be the calendar flyout?
                if (!exceptHandles.Contains(candidateHwnd))
                {
                    // does the current window touch the primary taskbar's clock?
                    Rectangle candidateRect = WindowUtils.GetWindowBounds(candidateHwnd);
                    candidateRect.Intersect(taskbarClockRect);

                    // if the two rectangles touch, intersect results in a rectangle
                    // where exactly one dimension is zero
                    if ((candidateRect.Width == 0 && candidateRect.Height > 0) ||
                        (candidateRect.Width > 0 && candidateRect.Height == 0))
                    {
                        // with a very high probability, this is the calendar flyout
                        return(candidateHwnd);
                    }
                }

                // find the next window with the calendar class
                candidateHwnd = NativeImports.FindWindowEx(IntPtr.Zero, candidateHwnd, CalendarFlyoutClassName, null);
            }

            return(IntPtr.Zero);

            /*
             * // if we have the localized window text, we may use the following
             * const string flyoutClassname = "Windows.UI.Core.CoreWindow";
             * const string flyoutText = "Datums- und Uhrzeitinformationen";
             *
             * IntPtr hwnd = NativeImports.FindWindowEx(IntPtr.Zero, IntPtr.Zero, flyoutClassname, flyoutText);
             * return hwnd;*/
        }
        /// <summary>
        /// Return all visible taskbars
        /// </summary>
        public static IList <TaskbarRef> ListTaskbars()
        {
            List <TaskbarRef> taskbars = new List <TaskbarRef>();

            // get the primary taskbar
            var primaryHwnd = GetPrimaryTaskbarHwnd();

            taskbars.Add(new TaskbarRef(true, primaryHwnd, WindowUtils.GetWindowBounds(primaryHwnd), GetTaskbarDockPosition(primaryHwnd)));

            // find all secondary taskbars
            IntPtr secondaryHwnd = NativeImports.FindWindowEx(IntPtr.Zero, IntPtr.Zero, SecondaryTaskbarClassName, null);

            while (secondaryHwnd != IntPtr.Zero)
            {
                taskbars.Add(new TaskbarRef(false, secondaryHwnd, WindowUtils.GetWindowBounds(secondaryHwnd), GetTaskbarDockPosition(secondaryHwnd)));

                // get the next secondary taskbar (if any)
                secondaryHwnd = NativeImports.FindWindowEx(IntPtr.Zero, secondaryHwnd, SecondaryTaskbarClassName, null);
            }

            return(taskbars);
        }