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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
23 // Jackson Harper (jackson@ximian.com)
30 using System.Drawing.Drawing2D;
31 using System.Runtime.InteropServices;
33 namespace System.Windows.Forms {
35 internal class MdiWindowManager : InternalWindowManager {
37 private MainMenu merged_menu;
38 private MainMenu maximized_menu;
39 private MenuItem icon_menu;
40 private ContextMenu icon_popup_menu;
41 internal bool was_minimized;
43 private PaintEventHandler draw_maximized_buttons;
44 internal EventHandler form_closed_handler;
46 private MdiClient mdi_container;
47 private Rectangle prev_virtual_position;
49 private Point icon_clicked;
50 private DateTime icon_clicked_time;
51 private bool icon_dont_show_popup;
53 private TitleButtons maximized_title_buttons;
54 private bool is_visible_pending;
55 private byte last_activation_event; // 0 = none, 1 = activated, 2 = deactivated.
57 public void RaiseActivated ()
59 if (last_activation_event == 1)
62 last_activation_event = 1;
63 form.OnActivatedInternal ();
64 form.SelectActiveControl ();
67 public void RaiseDeactivate ()
69 if (last_activation_event != 1)
71 last_activation_event = 2;
72 form.OnDeactivateInternal ();
75 public override int MenuHeight {
77 // Mdi children don't get menus on the form, they're shown on the main form.
82 internal bool IsVisiblePending {
84 return is_visible_pending;
87 is_visible_pending = value;
91 private TitleButtons MaximizedTitleButtons {
93 if (maximized_title_buttons == null) {
94 maximized_title_buttons = new TitleButtons (this.Form);
95 maximized_title_buttons.CloseButton.Visible = true;
96 maximized_title_buttons.RestoreButton.Visible = true;
97 maximized_title_buttons.MinimizeButton.Visible = true;
99 return maximized_title_buttons;
103 internal override Rectangle MaximizedBounds {
105 Rectangle pb = mdi_container.ClientRectangle;
106 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
107 int tw = TitleBarHeight;
109 Rectangle new_bounds = new Rectangle (pb.Left - bw,
112 pb.Height + tw + bw * 2);
119 public MdiWindowManager (Form form, MdiClient mdi_container) : base (form)
121 this.mdi_container = mdi_container;
122 if (form.WindowState == FormWindowState.Normal) {
123 NormalBounds = form.Bounds;
125 form_closed_handler = new EventHandler (FormClosed);
126 form.Closed += form_closed_handler;
127 form.TextChanged += new EventHandler (FormTextChangedHandler);
128 form.SizeChanged += new EventHandler (FormSizeChangedHandler);
129 form.LocationChanged += new EventHandler (FormLocationChangedHandler);
130 form.VisibleChanged += new EventHandler (FormVisibleChangedHandler);
131 draw_maximized_buttons = new PaintEventHandler (DrawMaximizedButtons);
135 private void FormVisibleChangedHandler (object sender, EventArgs e)
137 if (mdi_container == null)
141 mdi_container.ActivateChild (form);
142 } else if (mdi_container.Controls.Count > 1) {
143 mdi_container.ActivateActiveMdiChild ();
147 private void FormTextChangedHandler (object sender, EventArgs e)
149 mdi_container.SetParentText (false);
152 if (form.MdiParent.MainMenuStrip != null)
153 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
157 private void FormLocationChangedHandler (object sender, EventArgs e)
159 if (form.window_state == FormWindowState.Minimized)
160 IconicBounds = form.Bounds;
161 form.MdiParent.MdiContainer.SizeScrollBars ();
164 private void FormSizeChangedHandler (object sender, EventArgs e)
166 if (form.window_state == FormWindowState.Maximized && form.Bounds != MaximizedBounds)
167 form.Bounds = MaximizedBounds;
169 form.MdiParent.MdiContainer.SizeScrollBars ();
172 public MainMenu MergedMenu {
174 if (merged_menu == null)
175 merged_menu = CreateMergedMenu ();
180 private MainMenu CreateMergedMenu ()
182 Form parent = (Form) mdi_container.Parent;
184 if (parent.Menu != null)
185 clone = (MainMenu) parent.Menu.CloneMenu ();
187 clone = new MainMenu ();
189 if (form.WindowState == FormWindowState.Maximized) {
192 clone.MergeMenu (form.Menu);
193 clone.MenuChanged += new EventHandler (MenuChangedHandler);
194 clone.SetForm (parent);
198 public MainMenu MaximizedMenu {
200 if (maximized_menu == null)
201 maximized_menu = CreateMaximizedMenu ();
202 return maximized_menu;
206 private MainMenu CreateMaximizedMenu ()
208 Form parent = (Form) mdi_container.Parent;
211 if (form.MainMenuStrip != null || parent.MainMenuStrip != null)
215 MainMenu res = new MainMenu ();
217 if (parent.Menu != null) {
218 MainMenu clone = (MainMenu) parent.Menu.CloneMenu ();
219 res.MergeMenu (clone);
222 if (form.Menu != null) {
223 MainMenu clone = (MainMenu) form.Menu.CloneMenu ();
224 res.MergeMenu (clone);
227 if (res.MenuItems.Count == 0)
228 res.MenuItems.Add (new MenuItem ()); // Dummy item to get the menu height correct
230 res.MenuItems.Insert (0, icon_menu);
232 res.SetForm (parent);
236 private void CreateIconMenus ()
238 icon_menu = new MenuItem ();
239 icon_popup_menu = new ContextMenu ();
241 icon_menu.OwnerDraw = true;
242 icon_menu.MeasureItem += new MeasureItemEventHandler (MeasureIconMenuItem);
243 icon_menu.DrawItem += new DrawItemEventHandler (DrawIconMenuItem);
244 icon_menu.Click += new EventHandler (ClickIconMenuItem);
246 MenuItem restore = new MenuItem ("&Restore", new EventHandler (RestoreItemHandler));
247 MenuItem move = new MenuItem ("&Move", new EventHandler (MoveItemHandler));
248 MenuItem size = new MenuItem ("&Size", new EventHandler (SizeItemHandler));
249 MenuItem minimize = new MenuItem ("Mi&nimize", new EventHandler (MinimizeItemHandler));
250 MenuItem maximize = new MenuItem ("Ma&ximize", new EventHandler (MaximizeItemHandler));
251 MenuItem close = new MenuItem ("&Close", new EventHandler (CloseItemHandler));
252 MenuItem next = new MenuItem ("Nex&t", new EventHandler (NextItemHandler));
254 icon_menu.MenuItems.AddRange (new MenuItem [] { restore, move, size, minimize,
255 maximize, close, next });
256 icon_popup_menu.MenuItems.AddRange (new MenuItem [] { restore, move, size, minimize,
257 maximize, close, next });
260 private void ClickIconMenuItem(object sender, EventArgs e)
262 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) {
266 icon_clicked_time = DateTime.Now;
267 Point pnt = Point.Empty;
268 pnt = form.MdiParent.PointToScreen (pnt);
269 pnt = form.PointToClient (pnt);
273 internal void ShowPopup (Point pnt)
276 // If we are using MainMenuStrip, display that menu instead
277 if (form.WindowState == FormWindowState.Maximized && form.MdiParent.MainMenuStrip != null)
278 if (form.MdiParent.MainMenuStrip.Items.Count > 0) {
279 ToolStripItem tsi = form.MdiParent.MainMenuStrip.Items[0];
281 if (tsi is MdiControlStrip.SystemMenuItem) {
282 (tsi as MdiControlStrip.SystemMenuItem).ShowDropDown ();
288 icon_popup_menu.MenuItems[0].Enabled = form.window_state != FormWindowState.Normal; // restore
289 icon_popup_menu.MenuItems[1].Enabled = form.window_state != FormWindowState.Maximized; // move
290 icon_popup_menu.MenuItems[2].Enabled = form.window_state != FormWindowState.Maximized; // size
291 icon_popup_menu.MenuItems[3].Enabled = form.window_state != FormWindowState.Minimized; // minimize
292 icon_popup_menu.MenuItems[4].Enabled = form.window_state != FormWindowState.Maximized; // maximize
293 icon_popup_menu.MenuItems[5].Enabled = true; // close
294 icon_popup_menu.MenuItems[6].Enabled = true; // next
296 icon_popup_menu.Show(form, pnt);
299 private void RestoreItemHandler (object sender, EventArgs e)
301 form.WindowState = FormWindowState.Normal;
304 private void MoveItemHandler (object sender, EventArgs e)
309 PointToScreen (ref x, ref y);
310 Cursor.Position = new Point (x, y);
311 form.Cursor = Cursors.Cross;
312 state = State.Moving;
316 private void SizeItemHandler (object sender, EventArgs e)
321 PointToScreen (ref x, ref y);
322 Cursor.Position = new Point (x, y);
323 form.Cursor = Cursors.Cross;
324 state = State.Sizing;
328 private void MinimizeItemHandler (object sender, EventArgs e)
330 form.WindowState = FormWindowState.Minimized;
333 private void MaximizeItemHandler (object sender, EventArgs e)
335 if (form.WindowState != FormWindowState.Maximized)
336 form.WindowState = FormWindowState.Maximized;
339 private void CloseItemHandler (object sender, EventArgs e)
344 private void NextItemHandler (object sender, EventArgs e)
346 mdi_container.ActivateNextChild ();
349 private void DrawIconMenuItem (object sender, DrawItemEventArgs de)
351 de.Graphics.DrawIcon (form.Icon, new Rectangle (de.Bounds.X + 2, de.Bounds.Y + 2,
352 de.Bounds.Height - 4, de.Bounds.Height - 4));
355 private void MeasureIconMenuItem (object sender, MeasureItemEventArgs me)
357 int size = SystemInformation.MenuHeight;
358 me.ItemHeight = size;
359 me.ItemWidth = size + 2; // some padding
362 private void MenuChangedHandler (object sender, EventArgs e)
367 public override void PointToClient (ref int x, ref int y)
369 XplatUI.ScreenToClient (mdi_container.Handle, ref x, ref y);
372 public override void PointToScreen (ref int x, ref int y)
374 XplatUI.ClientToScreen (mdi_container.Handle, ref x, ref y);
377 public override void UpdateWindowDecorations (FormWindowState window_state)
379 if (MaximizedMenu != null) {
380 switch (window_state) {
381 case FormWindowState.Minimized:
382 case FormWindowState.Normal:
383 MaximizedMenu.Paint -= draw_maximized_buttons;
384 MaximizedTitleButtons.Visible = false;
385 TitleButtons.Visible = true;
387 case FormWindowState.Maximized:
388 MaximizedMenu.Paint += draw_maximized_buttons;
389 MaximizedTitleButtons.Visible = true;
390 TitleButtons.Visible = false;
395 base.UpdateWindowDecorations (window_state);
398 public override void SetWindowState (FormWindowState old_state, FormWindowState window_state)
400 mdi_container.SetWindowState (form, old_state, window_state, false);
403 private void FormClosed (object sender, EventArgs e)
405 mdi_container.ChildFormClosed (form);
408 if (form.MdiParent.MainMenuStrip != null)
409 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
411 mdi_container.RemoveControlMenuItems (this);
415 public override void DrawMaximizedButtons (object sender, PaintEventArgs pe)
417 Size bs = ThemeEngine.Current.ManagedWindowGetMenuButtonSize (this);
418 Point pnt = XplatUI.GetMenuOrigin (mdi_container.ParentForm.Handle);
419 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
420 TitleButtons buttons = MaximizedTitleButtons;
422 buttons.Visible = true;
423 TitleButtons.Visible = false;
425 buttons.CloseButton.Rectangle = new Rectangle (mdi_container.ParentForm.Size.Width - 1 - bw - bs.Width - 2,
426 pnt.Y + 2, bs.Width, bs.Height);
428 buttons.RestoreButton.Rectangle = new Rectangle (buttons.CloseButton.Rectangle.Left - 2 - bs.Width,
429 pnt.Y + 2, bs.Width, bs.Height);
431 buttons.MinimizeButton.Rectangle = new Rectangle (buttons.RestoreButton.Rectangle.Left - bs.Width,
432 pnt.Y + 2, bs.Width, bs.Height);
434 DrawTitleButton (pe.Graphics, buttons.MinimizeButton, pe.ClipRectangle);
435 DrawTitleButton (pe.Graphics, buttons.RestoreButton, pe.ClipRectangle);
436 DrawTitleButton (pe.Graphics, buttons.CloseButton, pe.ClipRectangle);
438 buttons.MinimizeButton.Rectangle.Y -= pnt.Y;
439 buttons.RestoreButton.Rectangle.Y -= pnt.Y;
440 buttons.CloseButton.Rectangle.Y -= pnt.Y;
443 public bool HandleMenuMouseDown (MainMenu menu, int x, int y)
445 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
447 HandleTitleBarDown (pt.X, pt.Y);
448 return TitleButtons.AnyPushedTitleButtons;
451 public void HandleMenuMouseUp (MainMenu menu, int x, int y)
453 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
455 HandleTitleBarUp (pt.X, pt.Y);
458 public void HandleMenuMouseLeave (MainMenu menu, int x, int y)
460 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
461 HandleTitleBarLeave (pt.X, pt.Y);
465 public void HandleMenuMouseMove (MainMenu menu, int x, int y)
467 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
469 HandleTitleBarMouseMove (pt.X, pt.Y);
473 protected override void HandleTitleBarLeave (int x, int y)
475 base.HandleTitleBarLeave (x, y);
477 if (maximized_title_buttons != null) {
478 maximized_title_buttons.MouseLeave (x, y);
482 XplatUI.InvalidateNC (form.MdiParent.Handle);
485 protected override void HandleTitleBarUp (int x, int y)
487 if (IconRectangleContains (x, y)) {
488 if (!icon_dont_show_popup) {
490 ClickIconMenuItem (null, null);
492 ShowPopup (Point.Empty);
494 icon_dont_show_popup = false;
499 bool was_maximized = IsMaximized;
500 base.HandleTitleBarUp (x, y);
501 if (maximized_title_buttons != null && was_maximized) {
502 maximized_title_buttons.MouseUp (x, y);
506 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
509 protected override void HandleTitleBarDoubleClick (int x, int y)
511 if (IconRectangleContains (x, y)) {
513 } else if (form.MaximizeBox == true) {
514 form.WindowState = FormWindowState.Maximized;
516 base.HandleTitleBarDoubleClick (x, y);
519 protected override void HandleTitleBarDown (int x, int y)
521 if (IconRectangleContains (x, y)) {
522 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime && icon_clicked.X == x && icon_clicked.Y == y) {
525 icon_clicked_time = DateTime.Now;
533 base.HandleTitleBarDown (x, y);
535 if (maximized_title_buttons != null) {
536 maximized_title_buttons.MouseDown (x, y);
540 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
544 protected override void HandleTitleBarMouseMove (int x, int y)
546 base.HandleTitleBarMouseMove (x, y);
548 if (maximized_title_buttons != null && maximized_title_buttons.MouseMove (x, y))
549 XplatUI.InvalidateNC (form.MdiParent.Handle);
552 protected override bool HandleLButtonDblClick (ref Message m)
555 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
556 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
558 // Correct since we are in NC land.
559 NCClientToNC (ref x, ref y);
561 if (IconRectangleContains (x, y)) {
562 icon_popup_menu.Wnd.Hide ();
567 return base.HandleLButtonDblClick (ref m);
570 protected override bool HandleLButtonDown (ref Message m)
573 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
574 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
576 // Correct y since we are in NC land.
577 NCClientToNC(ref x, ref y);
579 if (IconRectangleContains (x, y)){
580 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) {
581 if (icon_popup_menu != null && icon_popup_menu.Wnd != null) {
582 icon_popup_menu.Wnd.Hide ();
586 } else if (form.Capture) {
587 icon_dont_show_popup = true;
590 return base.HandleLButtonDown (ref m);
593 protected override bool ShouldRemoveWindowManager (FormBorderStyle style)
598 protected override void HandleWindowMove (Message m)
600 Point pos = Cursor.Position;
601 Point move = MouseMove (pos);
603 if (move.X == 0 && move.Y == 0)
606 int x = virtual_position.X + move.X;
607 int y = virtual_position.Y + move.Y;
609 Rectangle client = mdi_container.ClientRectangle;
610 if (mdi_container.VerticalScrollbarVisible)
611 client.Width -= SystemInformation.VerticalScrollBarWidth;
612 if (mdi_container.HorizontalScrollbarVisible)
613 client.Height -= SystemInformation.HorizontalScrollBarHeight;
615 UpdateVP (x, y, form.Width, form.Height);
620 protected override bool HandleNCMouseMove (ref Message m)
622 XplatUI.RequestAdditionalWM_NCMessages (form.Handle, true, true);
623 return base.HandleNCMouseMove (ref m);
626 protected override void DrawVirtualPosition (Rectangle virtual_position)
628 ClearVirtualPosition ();
630 if (form.Parent != null)
631 XplatUI.DrawReversibleRectangle (form.Parent.Handle, virtual_position, 2);
632 prev_virtual_position = virtual_position;
635 protected override void ClearVirtualPosition ()
637 if (prev_virtual_position != Rectangle.Empty && form.Parent != null)
638 XplatUI.DrawReversibleRectangle (form.Parent.Handle,
639 prev_virtual_position, 2);
640 prev_virtual_position = Rectangle.Empty;
643 protected override void OnWindowFinishedMoving ()
648 public override bool IsActive {
650 if (mdi_container == null)
652 return mdi_container.ActiveMdiChild == form;
656 protected override void Activate ()
658 if (mdi_container.ActiveMdiChild != form) {
659 mdi_container.ActivateChild (form);