1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //	Peter Bartok	pbartok@novell.com
24 //
25 //
26 
27 // NOT COMPLETE
28 
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Drawing;
32 using System.Runtime.InteropServices;
33 
34 namespace System.Windows.Forms {
35 	[ComVisible (true)]
36 	[ClassInterface(ClassInterfaceType.AutoDispatch)]
37 	[DesignTimeVisible(false)]
38 	[ToolboxItem(false)]
39 	public sealed class MdiClient : Control {
40 		#region Local Variables
41 		private int mdi_created;
42 		private ImplicitHScrollBar hbar;
43 		private ImplicitVScrollBar vbar;
44 		private SizeGrip sizegrip;
45 		private int hbar_value;
46 		private int vbar_value;
47 		private bool lock_sizing;
48 		private bool initializing_scrollbars;
49 		private int prev_bottom;
50 		private bool setting_windowstates = false;
51 		internal ArrayList mdi_child_list;
52 		private string form_text;
53 		private bool setting_form_text;
54 		private Form active_child;
55 
56 		#endregion	// Local Variables
57 
58 		#region Public Classes
59 		[ComVisible (false)]
60 		public new class ControlCollection : Control.ControlCollection {
61 
62 			private MdiClient owner;
63 
ControlCollection(MdiClient owner)64 			public ControlCollection(MdiClient owner) : base(owner) {
65 				this.owner = owner;
66 			}
67 
Add(Control value)68 			public override void Add(Control value) {
69 				if ((value is Form) == false || !(((Form)value).IsMdiChild)) {
70 					throw new ArgumentException("Form must be MdiChild");
71 				}
72 				owner.mdi_child_list.Add (value);
73 				base.Add (value);
74 
75 				// newest member is the active one
76 				Form form = (Form) value;
77 				owner.ActiveMdiChild = form;
78 			}
79 
Remove(Control value)80 			public override void Remove(Control value)
81 			{
82 				Form form = value as Form;
83 				if (form != null) {
84 					MdiWindowManager wm = form.WindowManager as MdiWindowManager;
85 					if (wm != null) {
86 						form.Closed -= wm.form_closed_handler;
87 					}
88 				}
89 
90 				owner.mdi_child_list.Remove (value);
91 				base.Remove (value);
92 			}
93 		}
94 		#endregion	// Public Classes
95 
96 		#region Public Constructors
MdiClient()97 		public MdiClient()
98 		{
99 			mdi_child_list = new ArrayList ();
100 			BackColor = SystemColors.AppWorkspace;
101 			Dock = DockStyle.Fill;
102 			SetStyle (ControlStyles.Selectable, false);
103 		}
104 		#endregion	// Public Constructors
105 
SendFocusToActiveChild()106 		internal void SendFocusToActiveChild ()
107 		{
108 			Form active = this.ActiveMdiChild;
109 			if (active == null) {
110 				ParentForm.SendControlFocus (this);
111 			} else {
112 				active.SendControlFocus (active);
113 				ParentForm.ActiveControl = active;
114 			}
115 		}
116 
117 		internal bool HorizontalScrollbarVisible {
118 			get { return hbar != null && hbar.Visible; }
119 		}
120 		internal bool VerticalScrollbarVisible {
121 			get { return vbar != null && vbar.Visible; }
122 		}
123 
SetParentText(bool text_changed)124 		internal void SetParentText(bool text_changed)
125 		{
126 			if (setting_form_text)
127 				return;
128 
129 			setting_form_text = true;
130 
131 			if (text_changed)
132 				form_text = ParentForm.Text;
133 
134 			if (ParentForm.ActiveMaximizedMdiChild == null) {
135 				ParentForm.Text = form_text;
136 			} else {
137 				string childText = ParentForm.ActiveMaximizedMdiChild.form.Text;
138 				if (childText.Length > 0) {
139 					ParentForm.Text = form_text + " - [" + ParentForm.ActiveMaximizedMdiChild.form.Text + "]";
140 				} else {
141 					ParentForm.Text = form_text;
142 				}
143 			}
144 
145 			setting_form_text = false;
146 		}
147 
OnPaintBackgroundInternal(PaintEventArgs pe)148 		internal override void OnPaintBackgroundInternal (PaintEventArgs pe)
149 		{
150 			if (BackgroundImage != null)
151 				return;
152 
153 			if (Parent == null || Parent.BackgroundImage == null)
154 				return;
155 			Parent.PaintControlBackground (pe);
156 		}
157 
158 		internal Form ParentForm {
159 			get { return (Form) Parent; }
160 		}
161 
CreateControlsInstance()162 		protected override Control.ControlCollection CreateControlsInstance ()
163 		{
164 			return new MdiClient.ControlCollection (this);
165 		}
166 
WndProc(ref Message m)167 		protected override void WndProc(ref Message m) {
168 			switch ((Msg)m.Msg) {
169 			case Msg.WM_NCPAINT:
170 				PaintEventArgs pe = XplatUI.PaintEventStart (ref m, Handle, false);
171 
172 				Rectangle clip;
173 				clip = new Rectangle (0, 0, Width, Height);
174 
175 				ControlPaint.DrawBorder3D (pe.Graphics, clip, Border3DStyle.Sunken);
176 				XplatUI.PaintEventEnd (ref m, Handle, false);
177 				m.Result = IntPtr.Zero;
178 				return ;
179 			}
180 
181 			base.WndProc (ref m);
182 		}
183 
OnResize(EventArgs e)184 		protected override void OnResize (EventArgs e)
185 		{
186 			base.OnResize (e);
187 
188 			if (Parent != null && Parent.IsHandleCreated)
189 				XplatUI.InvalidateNC (Parent.Handle);
190 			// Should probably make this into one loop
191 			SizeScrollBars ();
192 			ArrangeWindows ();
193 		}
194 
ScaleControl(SizeF factor, BoundsSpecified specified)195 		protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
196 		{
197 			// Never change the MdiClient's location
198 			specified &= ~BoundsSpecified.Location;
199 
200 			base.ScaleControl (factor, specified);
201 		}
202 
203 		[System.ComponentModel.EditorBrowsable (EditorBrowsableState.Never)]
ScaleCore(float dx, float dy)204 		protected override void ScaleCore (float dx, float dy)
205 		{
206 			base.ScaleCore (dx, dy);
207 		}
208 
SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)209 		protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
210 		{
211 			base.SetBoundsCore (x, y, width, height, specified);
212 		}
213 
214 		#region Public Instance Properties
215 		[Localizable(true)]
216 		public override System.Drawing.Image BackgroundImage {
217 			get {
218 				return base.BackgroundImage;
219 			}
220 			set {
221 				base.BackgroundImage = value;
222 			}
223 		}
224 
225 		[EditorBrowsable (EditorBrowsableState.Never)]
226 		[Browsable (false)]
227 		public override ImageLayout BackgroundImageLayout {
228 			get {
229 				return base.BackgroundImageLayout;
230 			}
231 			set {
232 				base.BackgroundImageLayout = value;
233 			}
234 		}
235 
236 		public Form [] MdiChildren {
237 			get {
238 				if (mdi_child_list == null)
239 					return new Form [0];
240 				return (Form []) mdi_child_list.ToArray (typeof (Form));
241 			}
242 		}
243 		#endregion	// Public Instance Properties
244 
245 #region Protected Instance Properties
246 		protected override CreateParams CreateParams {
247 			get {
248 				CreateParams result = base.CreateParams;
249 				result.ExStyle |= (int) WindowExStyles.WS_EX_CLIENTEDGE;
250 				return result;
251 			}
252 		}
253 		#endregion	// Protected Instance Properties
254 
255 		#region Public Instance Methods
LayoutMdi(MdiLayout value)256 		public void LayoutMdi (MdiLayout value) {
257 
258 			// Don't forget to always call ArrangeIconicWindows
259 			ArrangeIconicWindows (true);
260 
261 			switch (value) {
262 			case MdiLayout.Cascade: {
263 				int i = 0;
264 				for (int c = Controls.Count - 1; c >= 0; c--) {
265 					Form form = (Form) Controls [c];
266 
267 					if (form.WindowState == FormWindowState.Minimized)
268 						continue;
269 
270 					if (form.WindowState == FormWindowState.Maximized)
271 						form.WindowState = FormWindowState.Normal;
272 
273 					form.Width = System.Convert.ToInt32 (ClientSize.Width * 0.8);
274 					form.Height = Math.Max (
275 								System.Convert.ToInt32 (ClientSize.Height * 0.8),
276 								SystemInformation.MinimumWindowSize.Height + 2);
277 
278 					int l = 22 * i;
279 					int t = 22 * i;
280 
281 					if (i != 0 && (l + form.Width > ClientSize.Width || t + form.Height > ClientSize.Height)) {
282 						i = 0;
283 						l = 22 * i;
284 						t = 22 * i;
285 					}
286 
287 					form.Left = l;
288 					form.Top = t;
289 
290 					i++;
291 				}
292 				break;
293 				}
294 			case MdiLayout.TileHorizontal:
295 			case MdiLayout.TileVertical: {
296 				// First count number of windows to tile
297 				int total = 0;
298 
299 				// And space used by iconic windows
300 				int clientHeight = ClientSize.Height;
301 
302 				for (int i = 0; i < Controls.Count; i++) {
303 					Form form = Controls [i] as Form;
304 
305 					if (form == null)
306 						continue;
307 
308 					if (!form.Visible)
309 						continue;
310 
311 					if (form.WindowState == FormWindowState.Maximized)
312 						form.WindowState = FormWindowState.Normal;
313 					else if (form.WindowState == FormWindowState.Minimized) {
314 						if (form.Bounds.Top < clientHeight)
315 							clientHeight = form.Bounds.Top;
316 						continue;
317 					}
318 
319 					total++;
320 				}
321 				if (total <= 0)
322 					return;
323 
324 				// Calculate desired height and width
325 				Size newSize;
326 				Size offset;
327 
328 				if (value == MdiLayout.TileHorizontal) {
329 					newSize = new Size(ClientSize.Width, clientHeight / total);
330 					offset = new Size (0, newSize.Height);
331 				} else {
332 					newSize = new Size(ClientSize.Width / total, clientHeight);
333 					offset = new Size (newSize.Width, 0);
334 				}
335 
336 				// Loop again and set the size and location.
337 				Point nextLocation = Point.Empty;
338 
339 				for (int i = 0; i < Controls.Count; i++) {
340 					Form form = Controls [i] as Form;
341 
342 					if (form == null)
343 						continue;
344 
345 					if (!form.Visible)
346 						continue;
347 
348 					if (form.WindowState == FormWindowState.Minimized)
349 						continue;
350 
351 					form.Size = newSize;
352 					form.Location = nextLocation;
353 					nextLocation += offset;
354 				}
355 
356 				break;
357 				}
358 			}
359 		}
360 		#endregion	// Public Instance Methods
361 
362 		#region Protected Instance Methods
363 		#endregion	// Protected Instance Methods
364 
SizeScrollBars()365 		internal void SizeScrollBars ()
366 		{
367 			if (lock_sizing)
368 				return;
369 
370 			if (!IsHandleCreated)
371 				return;
372 
373 			if (Controls.Count == 0 || ((Form) Controls [0]).WindowState == FormWindowState.Maximized) {
374 				if (hbar != null)
375 					hbar.Visible = false;
376 				if (vbar != null)
377 					vbar.Visible = false;
378 				if (sizegrip != null)
379 					sizegrip.Visible = false;
380 				return;
381 			}
382 
383 			int right = 0;
384 			int left = 0;
385 			int top = 0;
386 			int bottom = 0;
387 
388 			foreach (Form child in Controls) {
389 				if (!child.Visible)
390 					continue;
391 				if (child.Right > right)
392 					right = child.Right;
393 				if (child.Left < left) {
394 					left = child.Left;
395 				}
396 
397 				if (child.Bottom > bottom)
398 					bottom = child.Bottom;
399 				if (child.Top < 0) {
400 					top = child.Top;
401 				}
402 			}
403 
404 			int available_width = ClientSize.Width;
405 			int available_height = ClientSize.Height;
406 
407 			bool need_hbar = false;
408 			bool need_vbar = false;
409 
410 			if (right - left > available_width || left < 0) {
411 				need_hbar = true;
412 				available_height -= SystemInformation.HorizontalScrollBarHeight;
413 			}
414 			if (bottom - top > available_height || top < 0) {
415 				need_vbar = true;
416 				available_width -= SystemInformation.VerticalScrollBarWidth;
417 
418 				if (!need_hbar && (right - left > available_width || left < 0)) {
419 					need_hbar = true;
420 					available_height -= SystemInformation.HorizontalScrollBarHeight;
421 				}
422 			}
423 
424 			if (need_hbar) {
425 				if (hbar == null) {
426 					hbar = new ImplicitHScrollBar ();
427 					Controls.AddImplicit (hbar);
428 				}
429 				hbar.Visible = true;
430 				CalcHBar (left, right, need_vbar);
431 			} else if (hbar != null)
432 				hbar.Visible = false;
433 
434 			if (need_vbar) {
435 				if (vbar == null) {
436 					vbar = new ImplicitVScrollBar ();
437 					Controls.AddImplicit (vbar);
438 				}
439 				vbar.Visible = true;
440 				CalcVBar (top, bottom, need_hbar);
441 			} else if (vbar != null)
442 				vbar.Visible = false;
443 
444 			if (need_hbar && need_vbar) {
445 				if (sizegrip == null) {
446 					sizegrip = new SizeGrip (this.ParentForm);
447 					Controls.AddImplicit (sizegrip);
448 				}
449 				sizegrip.Location = new Point (hbar.Right, vbar.Bottom);
450 				sizegrip.Visible = true;
451 				XplatUI.SetZOrder (sizegrip.Handle, vbar.Handle, false, false);
452 			} else if (sizegrip != null) {
453 				sizegrip.Visible = false;
454 			}
455 
456 			XplatUI.InvalidateNC (Handle);
457 		}
458 
CalcHBar(int left, int right, bool vert_vis)459 		private void CalcHBar (int left, int right, bool vert_vis)
460 		{
461 			initializing_scrollbars = true;
462 
463 			hbar.Left = 0;
464 			hbar.Top = ClientRectangle.Bottom - hbar.Height;
465 			hbar.Width = ClientRectangle.Width - (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0);
466 			hbar.LargeChange = 50;
467 			hbar.Minimum = Math.Min (left, 0);
468 			hbar.Maximum = Math.Max (right - ClientSize.Width + 51 + (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0), 0);
469 			hbar.Value = 0;
470 			hbar_value = 0;
471 			hbar.ValueChanged += new EventHandler (HBarValueChanged);
472 			XplatUI.SetZOrder (hbar.Handle, IntPtr.Zero, true, false);
473 
474 			initializing_scrollbars = false;
475 		}
476 
CalcVBar(int top, int bottom, bool horz_vis)477 		private void CalcVBar (int top, int bottom, bool horz_vis)
478 		{
479 			initializing_scrollbars = true;
480 
481 			vbar.Top = 0;
482 			vbar.Left = ClientRectangle.Right - vbar.Width;
483 			vbar.Height = ClientRectangle.Height - (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0);
484 			vbar.LargeChange = 50;
485 			vbar.Minimum = Math.Min (top, 0);
486 			vbar.Maximum = Math.Max (bottom - ClientSize.Height + 51 + (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0), 0);
487 			vbar.Value = 0;
488 			vbar_value = 0;
489 			vbar.ValueChanged += new EventHandler (VBarValueChanged);
490 			XplatUI.SetZOrder (vbar.Handle, IntPtr.Zero, true, false);
491 
492 			initializing_scrollbars = false;
493 		}
494 
HBarValueChanged(object sender, EventArgs e)495 		private void HBarValueChanged (object sender, EventArgs e)
496 		{
497 			if (initializing_scrollbars)
498 				return;
499 
500 			if (hbar.Value == hbar_value)
501 				return;
502 
503 			lock_sizing = true;
504 
505 			try {
506 				int diff = hbar_value - hbar.Value;
507 				foreach (Form child in Controls) {
508 					child.Left += diff;
509 				}
510 			} finally {
511 				lock_sizing = false;
512 			}
513 
514 			hbar_value = hbar.Value;
515 		}
516 
VBarValueChanged(object sender, EventArgs e)517 		private void VBarValueChanged (object sender, EventArgs e)
518 		{
519 			if (initializing_scrollbars)
520 				return;
521 
522 			if (vbar.Value == vbar_value)
523 				return;
524 
525 			lock_sizing = true;
526 
527 			try {
528 				int diff = vbar_value - vbar.Value;
529 				foreach (Form child in Controls) {
530 					child.Top += diff;
531 				}
532 			} finally {
533 				lock_sizing = false;
534 			}
535 
536 			vbar_value = vbar.Value;
537 		}
538 
ArrangeWindows()539 		private void ArrangeWindows ()
540 		{
541 			if (!IsHandleCreated)
542 				return;
543 
544 			int change = 0;
545 			if (prev_bottom != -1)
546 				change = Bottom - prev_bottom;
547 
548 			foreach (Control c in Controls) {
549 				Form child = c as Form;
550 
551 				if (c == null || !child.Visible)
552 					continue;
553 
554 				MdiWindowManager wm = child.WindowManager as MdiWindowManager;
555 				if (wm.GetWindowState () == FormWindowState.Maximized)
556 					child.Bounds = wm.MaximizedBounds;
557 
558 				if (wm.GetWindowState () == FormWindowState.Minimized) {
559 					child.Top += change;
560 				}
561 
562 			}
563 
564 			prev_bottom = Bottom;
565 		}
566 
ArrangeIconicWindows(bool rearrange_all)567 		internal void ArrangeIconicWindows (bool rearrange_all)
568 		{
569 			Rectangle rect = Rectangle.Empty;
570 
571 			lock_sizing = true;
572 			foreach (Form form in Controls) {
573 				if (form.WindowState != FormWindowState.Minimized)
574 					continue;
575 
576 				MdiWindowManager wm = (MdiWindowManager) form.WindowManager;
577 
578 				if (wm.IconicBounds != Rectangle.Empty && !rearrange_all) {
579 					if (form.Bounds != wm.IconicBounds)
580 						form.Bounds = wm.IconicBounds;
581 					continue;
582 				}
583 
584 				bool success = true;
585 				int startx, starty, currentx, currenty;
586 
587 				rect.Size = wm.IconicSize;
588 
589 				startx = 0;
590 				starty = ClientSize.Height - rect.Height;
591 				currentx = startx;
592 				currenty = starty;
593 
594 				do {
595 					rect.X = currentx;
596 					rect.Y = currenty;
597 					success = true;
598 					foreach (Form form2 in Controls) {
599 						if (form2 == form || form2.window_state != FormWindowState.Minimized)
600 							continue;
601 
602 						if (form2.Bounds.IntersectsWith(rect)) {
603 							success = false;
604 							break;
605 						}
606 					}
607 					if (!success) {
608 						currentx += rect.Width;
609 						if (currentx + rect.Width > Right) {
610 							currentx = startx;
611 							currenty -= rect.Height;
612 						}
613 					}
614 				} while (!success);
615 				wm.IconicBounds = rect;
616 				form.Bounds = wm.IconicBounds;
617 			}
618 			lock_sizing = false;
619 		}
620 
ChildFormClosed(Form form)621 		internal void ChildFormClosed (Form form)
622 		{
623 			FormWindowState closed_form_windowstate = form.WindowState;
624 
625 			form.Visible = false;
626 			Controls.Remove (form);
627 
628 			if (Controls.Count == 0) {
629 				((MdiWindowManager) form.window_manager).RaiseDeactivate ();
630 			} else if (closed_form_windowstate == FormWindowState.Maximized) {
631 				Form current = (Form) Controls [0];
632 				current.WindowState = FormWindowState.Maximized;
633 				ActivateChild(current);
634 			}
635 
636 			if (Controls.Count == 0) {
637 				XplatUI.RequestNCRecalc (Parent.Handle);
638 				ParentForm.PerformLayout ();
639 
640 				// If we closed the last child, unmerge the menus.
641 				// If it's not the last child, the menu will be unmerged
642 				// when another child takes focus.
643 				MenuStrip parent_menu = form.MdiParent.MainMenuStrip;
644 
645 				if (parent_menu != null)
646 					if (parent_menu.IsCurrentlyMerged)
647 						ToolStripManager.RevertMerge (parent_menu);
648 			}
649 			SizeScrollBars ();
650 			SetParentText (false);
651 			form.Dispose();
652 		}
653 
ActivateNextChild()654 		internal void ActivateNextChild ()
655 		{
656 			if (Controls.Count < 1)
657 				return;
658 			if (Controls.Count == 1 && Controls[0] == ActiveMdiChild)
659 				return;
660 
661 			Form front = (Form) Controls [0];
662 			Form form = (Form) Controls [1];
663 
664 			ActivateChild (form);
665 			front.SendToBack ();
666 		}
667 
ActivatePreviousChild()668 		internal void ActivatePreviousChild ()
669 		{
670 			if (Controls.Count <= 1)
671 				return;
672 
673 			Form back = (Form) Controls [Controls.Count - 1];
674 
675 			ActivateChild (back);
676 		}
677 
ActivateChild(Form form)678 		internal void ActivateChild (Form form)
679 		{
680 			if (Controls.Count < 1)
681 				return;
682 
683 			if (ParentForm.is_changing_visible_state > 0)
684 				return;
685 
686 			Form current = (Form) Controls [0];
687 			bool raise_deactivate = ParentForm.ActiveControl == current;
688 
689 			// We want to resize the new active form before it is
690 			// made active to avoid flickering. Can't do it in the
691 			// normal way (form.WindowState = Maximized) since it's not
692 			// active yet and everything would just return to before.
693 			// We also won't suspend layout, this way the layout will
694 			// happen before the form is made active (and in many cases
695 			// before it is visible, which avoids flickering as well).
696 			MdiWindowManager wm = (MdiWindowManager)form.WindowManager;
697 
698 			if (current.WindowState == FormWindowState.Maximized && form.WindowState != FormWindowState.Maximized && form.Visible) {
699 				FormWindowState old_state = form.window_state;
700 				SetWindowState (form, old_state, FormWindowState.Maximized, true);
701 				wm.was_minimized = form.window_state == FormWindowState.Minimized;
702 				form.window_state = FormWindowState.Maximized;
703 				SetParentText (false);
704 			}
705 
706 			form.BringToFront ();
707 			form.SendControlFocus (form);
708 			SetWindowStates (wm);
709 			if (current != form) {
710 				form.has_focus = false;
711 				if (current.IsHandleCreated)
712 					XplatUI.InvalidateNC (current.Handle);
713 				if (form.IsHandleCreated)
714 					XplatUI.InvalidateNC (form.Handle);
715 				if (raise_deactivate) {
716 					MdiWindowManager current_wm = (MdiWindowManager) current.window_manager;
717 					current_wm.RaiseDeactivate ();
718 
719 				}
720 			}
721 			active_child = (Form) Controls [0];
722 
723 			if (active_child.Visible) {
724 				bool raise_activated = ParentForm.ActiveControl != active_child;
725 				ParentForm.ActiveControl = active_child;
726 				if (raise_activated) {
727 					MdiWindowManager active_wm = (MdiWindowManager) active_child.window_manager;
728 					active_wm.RaiseActivated ();
729 				}
730 			}
731 		}
732 
AfterTopMostControl()733 		internal override IntPtr AfterTopMostControl ()
734 		{
735 			// order of scrollbars:
736 			// top = vertical
737 			//       sizegrid
738 			// bottom = horizontal
739 			if (hbar != null && hbar.Visible)
740 				return hbar.Handle;
741 			// no need to check for sizegrip since it will only
742 			// be visible if hbar is visible.
743 			if (vbar != null && vbar.Visible)
744 				return vbar.Handle;
745 
746 			return base.AfterTopMostControl ();
747 		}
748 
SetWindowStates(MdiWindowManager wm)749 		internal bool SetWindowStates (MdiWindowManager wm)
750 		{
751 		/*
752 			MDI WindowState behaviour:
753 			- If the active window is maximized, all other maximized windows are normalized.
754 			- If a normal window gets focus and the original active window was maximized,
755 			  the normal window gets maximized and the original window gets normalized.
756 			- If a minimized window gets focus and the original window was maximized,
757 			  the minimzed window gets maximized and the original window gets normalized.
758 			  If the ex-minimized window gets deactivated, it will be normalized.
759 		*/
760 			Form form = wm.form;
761 
762 			if (setting_windowstates) {
763 				return false;
764 			}
765 
766 			if (!form.Visible)
767 				return false;
768 
769 			bool is_active = wm.IsActive;
770 			bool maximize_this = false;
771 
772 			if (!is_active){
773 				return false;
774 			}
775 
776 			ArrayList minimize_these = new ArrayList ();
777 			ArrayList normalize_these = new ArrayList ();
778 
779 			setting_windowstates = true;
780 			foreach (Form frm in mdi_child_list) {
781 				if (frm == form) {
782 					continue;
783 				} else if (!frm.Visible){
784 					continue;
785 				}
786 				if (frm.WindowState == FormWindowState.Maximized && is_active) {
787 					maximize_this = true;
788 					if (((MdiWindowManager) frm.window_manager).was_minimized) {
789 						minimize_these.Add (frm);
790 					} else {
791 						normalize_these.Add (frm);
792 					}
793 				}
794 			}
795 
796 			if (maximize_this && form.WindowState != FormWindowState.Maximized) {
797 				wm.was_minimized = form.window_state == FormWindowState.Minimized;
798 				form.WindowState = FormWindowState.Maximized;
799 			}
800 
801 			foreach (Form frm in minimize_these)
802 				frm.WindowState = FormWindowState.Minimized;
803 
804 			foreach (Form frm in normalize_these)
805 				frm.WindowState = FormWindowState.Normal;
806 
807 
808 			SetParentText (false);
809 
810 			XplatUI.RequestNCRecalc (ParentForm.Handle);
811 			XplatUI.RequestNCRecalc (Handle);
812 
813 			SizeScrollBars ();
814 
815 			setting_windowstates = false;
816 
817 			if (form.MdiParent.MainMenuStrip != null)
818 				form.MdiParent.MainMenuStrip.RefreshMdiItems ();
819 
820 			// Implicit menu strip merging
821 			// - When child is activated
822 			// - Parent form must have a MainMenuStrip
823 			// - Find the first menustrip on the child
824 			// - Merge
825 			MenuStrip parent_menu = form.MdiParent.MainMenuStrip;
826 
827 			if (parent_menu != null) {
828 				if (parent_menu.IsCurrentlyMerged)
829 					ToolStripManager.RevertMerge (parent_menu);
830 
831 				MenuStrip child_menu = LookForChildMenu (form);
832 
833 				if (form.WindowState != FormWindowState.Maximized)
834 					RemoveControlMenuItems (wm);
835 
836 				if (form.WindowState == FormWindowState.Maximized) {
837 					bool found = false;
838 
839 					foreach (ToolStripItem tsi in parent_menu.Items) {
840 						if (tsi is MdiControlStrip.SystemMenuItem) {
841 							(tsi as MdiControlStrip.SystemMenuItem).MdiForm = form;
842 							found = true;
843 						} else if (tsi is MdiControlStrip.ControlBoxMenuItem) {
844 							(tsi as MdiControlStrip.ControlBoxMenuItem).MdiForm = form;
845 							found = true;
846 						}
847 					}
848 
849 					if (!found) {
850 						parent_menu.SuspendLayout ();
851 						parent_menu.Items.Insert (0, new MdiControlStrip.SystemMenuItem (form));
852 						parent_menu.Items.Add (new MdiControlStrip.ControlBoxMenuItem (form, MdiControlStrip.ControlBoxType.Close));
853 						parent_menu.Items.Add (new MdiControlStrip.ControlBoxMenuItem (form, MdiControlStrip.ControlBoxType.Max));
854 						parent_menu.Items.Add (new MdiControlStrip.ControlBoxMenuItem (form, MdiControlStrip.ControlBoxType.Min));
855 						parent_menu.ResumeLayout ();
856 					}
857 				}
858 
859 				if (child_menu != null)
860 					ToolStripManager.Merge (child_menu, parent_menu);
861 			}
862 
863 			return maximize_this;
864 		}
865 
LookForChildMenu(Control parent)866 		private MenuStrip LookForChildMenu (Control parent)
867 		{
868 			foreach (Control c in parent.Controls) {
869 				if (c is MenuStrip)
870 					return (MenuStrip)c;
871 
872 				if (c is ToolStripContainer || c is ToolStripPanel) {
873 					MenuStrip ms = LookForChildMenu (c);
874 
875 					if (ms != null)
876 						return ms;
877 				}
878 			}
879 
880 			return null;
881 		}
882 
RemoveControlMenuItems(MdiWindowManager wm)883 		internal void RemoveControlMenuItems (MdiWindowManager wm)
884 		{
885 			Form form = wm.form;
886 			MenuStrip parent_menu = form.MdiParent.MainMenuStrip;
887 
888 			// Only remove the items if the form requesting still owns the menu items
889 			if (parent_menu != null) {
890 				parent_menu.SuspendLayout ();
891 
892 				for (int i = parent_menu.Items.Count - 1; i >= 0; i--) {
893 					if (parent_menu.Items[i] is MdiControlStrip.SystemMenuItem) {
894 						if ((parent_menu.Items[i] as MdiControlStrip.SystemMenuItem).MdiForm == form)
895 							parent_menu.Items.RemoveAt (i);
896 					} else if (parent_menu.Items[i] is MdiControlStrip.ControlBoxMenuItem) {
897 						if ((parent_menu.Items[i] as MdiControlStrip.ControlBoxMenuItem).MdiForm == form)
898 							parent_menu.Items.RemoveAt (i);
899 					}
900 				}
901 
902 				parent_menu.ResumeLayout ();
903 			}
904 		}
905 
SetWindowState(Form form, FormWindowState old_window_state, FormWindowState new_window_state, bool is_activating_child)906 		internal void SetWindowState (Form form, FormWindowState old_window_state, FormWindowState new_window_state, bool is_activating_child)
907 		{
908 			bool mdiclient_layout;
909 
910 			MdiWindowManager wm = (MdiWindowManager) form.window_manager;
911 
912 			if (!is_activating_child && new_window_state == FormWindowState.Maximized && !wm.IsActive) {
913 				ActivateChild (form);
914 				return;
915 			}
916 
917 			if (old_window_state == FormWindowState.Normal)
918 				wm.NormalBounds = form.Bounds;
919 
920 			if (SetWindowStates (wm))
921 				return;
922 
923 			if (old_window_state == new_window_state)
924 				return;
925 
926 			mdiclient_layout = old_window_state == FormWindowState.Maximized || new_window_state == FormWindowState.Maximized;
927 
928 			switch (new_window_state) {
929 			case FormWindowState.Minimized:
930 				ArrangeIconicWindows (false);
931 				break;
932 			case FormWindowState.Maximized:
933 				form.Bounds = wm.MaximizedBounds;
934 				break;
935 			case FormWindowState.Normal:
936 				form.Bounds = wm.NormalBounds;
937 				break;
938 			}
939 
940 			wm.UpdateWindowDecorations (new_window_state);
941 
942 			form.ResetCursor ();
943 
944 			if (mdiclient_layout)
945 				Parent.PerformLayout ();
946 
947 			XplatUI.RequestNCRecalc (Parent.Handle);
948 			XplatUI.RequestNCRecalc (form.Handle);
949 			if (!setting_windowstates)
950 				SizeScrollBars ();
951 		}
952 		internal int ChildrenCreated {
953 			get { return mdi_created; }
954 			set { mdi_created = value; }
955 		}
956 
957 		internal Form ActiveMdiChild {
958 			get {
959 				if (ParentForm != null && !ParentForm.Visible)
960 					return null;
961 
962 				if (Controls.Count < 1)
963 					return null;
964 
965 				if (!ParentForm.IsHandleCreated)
966 					return null;
967 
968 				if (!ParentForm.has_been_visible)
969 					return null;
970 
971 				if (!ParentForm.Visible)
972 					return active_child;
973 
974 				active_child = null;
975 				for (int i = 0; i < Controls.Count; i++) {
976 					if (Controls [i].Visible) {
977 						active_child = (Form) Controls [i];
978 						break;
979 					}
980 				}
981 				return active_child;
982 			}
983 			set {
984 				ActivateChild (value);
985 			}
986 		}
987 
ActivateActiveMdiChild()988 		internal void ActivateActiveMdiChild ()
989 		{
990 			if (ParentForm.is_changing_visible_state > 0)
991 				return;
992 
993 			for (int i = 0; i < Controls.Count; i++) {
994 				if (Controls [i].Visible) {
995 					ActivateChild ((Form) Controls [i]);
996 					return;
997 				}
998 			}
999 		}
1000 	}
1001 }
1002 
1003