File: winforms\Managed\System\WinForms\MDIControlStrip.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="MDIControlStrip.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
 
namespace System.Windows.Forms {
    using System;
    using System.Security;
    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
 
    /// <devdoc> this is the toolstrip used for merging the [:)]    [_][#][X] buttons onto an 
    ///          mdi parent when an MDI child is maximized.
    /// </devdoc>
    internal class MdiControlStrip : MenuStrip {
 
            private ToolStripMenuItem system;
            private ToolStripMenuItem close;
            private ToolStripMenuItem minimize;
            private ToolStripMenuItem restore;
            private MenuStrip mergedMenu;
            
            private IWin32Window target;
 
            /// <devdoc> target is ideally the MDI Child to send the system commands to.
            ///          although there's nothing MDI child specific to it... you could have this
            ///          a toplevel window.
            /// </devdoc>
            public MdiControlStrip(IWin32Window target) {
                IntPtr hMenu= UnsafeNativeMethods.GetSystemMenu(new HandleRef(this, Control.GetSafeHandle(target)), /*bRevert=*/false);
                this.target = target;
 
                // The menu item itself takes care of enabledness and sending WM_SYSCOMMAND messages to the target.
                minimize    = new ControlBoxMenuItem(hMenu, NativeMethods.SC_MINIMIZE, target);
                close       = new ControlBoxMenuItem(hMenu, NativeMethods.SC_CLOSE,    target);
                restore     = new ControlBoxMenuItem(hMenu, NativeMethods.SC_RESTORE,  target);
 
                // The dropDown of the system menu is the one that talks to native.
                system = new SystemMenuItem();
             
                // However in the event that the target handle changes we have to push the new handle into everyone.
                Control controlTarget = target as Control;
                if (controlTarget != null) {
                    controlTarget.HandleCreated += new EventHandler(OnTargetWindowHandleRecreated);
                    controlTarget.Disposed += new EventHandler(OnTargetWindowDisposed);
                }
 
                // add in opposite order to how you want it merged
                this.Items.AddRange(new ToolStripItem[] { minimize, restore,close, system });
                this.SuspendLayout();
                foreach (ToolStripItem item in this.Items) {
                    item.DisplayStyle   = ToolStripItemDisplayStyle.Image;
                    item.MergeIndex     = 0;
                    item.MergeAction    = MergeAction.Insert;
                    item.Overflow       = ToolStripItemOverflow.Never;
                    item.Alignment      = ToolStripItemAlignment.Right;
                    item.Padding        = Padding.Empty;
                    // image is not scaled well on high dpi devices. Setting property to fit to size.                    
                    item.ImageScaling   = ToolStripItemImageScaling.SizeToFit;
                }
 
                // set up the sytem menu
          
          
                system.Image            = GetTargetWindowIcon();
                system.Alignment        = ToolStripItemAlignment.Left;
                system.DropDownOpening += new EventHandler(OnSystemMenuDropDownOpening);   
                system.ImageScaling     = ToolStripItemImageScaling.None;
                system.DoubleClickEnabled = true;
                system.DoubleClick     += new EventHandler(OnSystemMenuDoubleClick);
                system.Padding          = Padding.Empty;
                system.ShortcutKeys     = Keys.Alt | Keys.OemMinus;
                this.ResumeLayout(false);
            }
 
 
            #region Buttons
            /* Unused
            public ToolStripMenuItem System {
                get { return system; }
            }
            */
 
            public ToolStripMenuItem Close {
                 get { return close; }
            }
 
            /* Unused
            public ToolStripMenuItem Minimize {
                get { return minimize; }
            }
            
            public ToolStripMenuItem Restore {
                get { return restore; }
            }
            */
            #endregion
 
            internal MenuStrip MergedMenu {
                get {
                    return mergedMenu;
                }
                set {
                    mergedMenu = value;
                }
            }
                
/* PERF: consider shutting off layout
#region ShutOffLayout
            protected override void OnLayout(LayoutEventArgs e) {
                return;  // if someone attempts 
            }
 
            protected override Size GetPreferredSize(Size proposedSize) {
                return Size.Empty;
            }
#endregion
*/
 
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            private Image GetTargetWindowIcon() {
                Image systemIcon = null;
                IntPtr hIcon = UnsafeNativeMethods.SendMessage(new HandleRef(this, Control.GetSafeHandle(target)), NativeMethods.WM_GETICON, NativeMethods.ICON_SMALL, 0);
                IntSecurity.ObjectFromWin32Handle.Assert();
                try {
                    Icon icon =  (hIcon != IntPtr.Zero) ? Icon.FromHandle(hIcon) : Form.DefaultIcon;
                    Icon smallIcon = new Icon(icon, SystemInformation.SmallIconSize);
 
                    systemIcon = smallIcon.ToBitmap();
                    smallIcon.Dispose();
                } finally {
                    CodeAccessPermission.RevertAssert();
                }
 
                return systemIcon;
                
            }
            
            protected internal override void OnItemAdded(ToolStripItemEventArgs e) {
                base.OnItemAdded(e);
                Debug.Assert(Items.Count <= 4, "Too many items in the MDIControlStrip.  How did we get into this situation?");    
            }
 
            private void OnTargetWindowDisposed(object sender, EventArgs e) {
                UnhookTarget();
                target = null;
            }
 
            private void OnTargetWindowHandleRecreated(object sender, EventArgs e) {
 
                // in the case that the handle for the form is recreated we need to set 
                // up the handles to point to the new window handle for the form.
                
                system.SetNativeTargetWindow(target);
                minimize.SetNativeTargetWindow(target);
                close.SetNativeTargetWindow(target);
                restore.SetNativeTargetWindow(target);
 
                IntPtr hMenu= UnsafeNativeMethods.GetSystemMenu(new HandleRef(this, Control.GetSafeHandle(target)), /*bRevert=*/false);
                system.SetNativeTargetMenu(hMenu);
                minimize.SetNativeTargetMenu(hMenu);
                close.SetNativeTargetMenu(hMenu);
                restore.SetNativeTargetMenu(hMenu);
 
                // clear off the System DropDown.
                if (system.HasDropDownItems) {
                    // next time we need one we'll just fetch it fresh.
                    system.DropDown.Items.Clear();
                    system.DropDown.Dispose();
                }
 
                system.Image = GetTargetWindowIcon();
            }
            
            private void OnSystemMenuDropDownOpening(object sender, EventArgs e) {
                if (!system.HasDropDownItems && (target != null)) {
                    system.DropDown = ToolStripDropDownMenu.FromHMenu(UnsafeNativeMethods.GetSystemMenu(new HandleRef(this, Control.GetSafeHandle(target)), /*bRevert=*/false), target);
                }
                else if (MergedMenu == null) {
                    system.DropDown.Dispose(); 
                }
            }
 
            private void OnSystemMenuDoubleClick(object sender, EventArgs e) {
                Close.PerformClick();
            }
 
            protected override void Dispose(bool disposing) {
                if (disposing) {
                     UnhookTarget();
                     target = null;
                }
                base.Dispose(disposing);
            }
 
            private void UnhookTarget() {
                if (target != null) {
                    Control controlTarget = target as Control;
                    if (controlTarget != null) {
                        controlTarget.HandleCreated -= new EventHandler(OnTargetWindowHandleRecreated);
                        controlTarget.Disposed -= new EventHandler(OnTargetWindowDisposed);
                    }
                    target = null;
                }
 
            }
 
            // when the system menu item shortcut is evaluated - pop the dropdown          
            internal class ControlBoxMenuItem : ToolStripMenuItem {
                internal ControlBoxMenuItem(IntPtr hMenu, int nativeMenuCommandId, IWin32Window targetWindow) :
                                            base(hMenu, nativeMenuCommandId, targetWindow) {
                }
                
                internal override bool CanKeyboardSelect {
                    get { 
                        return false;
                    }
                }
            }
 
            // when the system menu item shortcut is evaluated - pop the dropdown          
            internal class SystemMenuItem : ToolStripMenuItem {
                   public SystemMenuItem(){
                       if (AccessibilityImprovements.Level1) {
                           AccessibleName = SR.GetString(SR.MDIChildSystemMenuItemAccessibleName);
                       }
                   }
                   protected internal override bool ProcessCmdKey(ref Message m, Keys keyData) {
                        if (Visible && ShortcutKeys == keyData) {
                            ShowDropDown();
                            this.DropDown.SelectNextToolStripItem(null, true);
                            return true;
                        }
                        return base.ProcessCmdKey(ref m, keyData);
                   }
                   protected override void OnOwnerChanged(EventArgs e) {
                       if (HasDropDownItems && DropDown.Visible) {
                            HideDropDown(); 
                       }
                       base.OnOwnerChanged(e);
                   }
 
            }
        }
}