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);
151 if (form.MdiParent.MainMenuStrip != null)
152 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
155 private void FormLocationChangedHandler (object sender, EventArgs e)
157 if (form.window_state == FormWindowState.Minimized)
158 IconicBounds = form.Bounds;
159 form.MdiParent.MdiContainer.SizeScrollBars ();
162 private void FormSizeChangedHandler (object sender, EventArgs e)
164 if (form.window_state == FormWindowState.Maximized && form.Bounds != MaximizedBounds)
165 form.Bounds = MaximizedBounds;
167 form.MdiParent.MdiContainer.SizeScrollBars ();
170 public MainMenu MergedMenu {
172 if (merged_menu == null)
173 merged_menu = CreateMergedMenu ();
178 private MainMenu CreateMergedMenu ()
180 Form parent = (Form) mdi_container.Parent;
182 if (parent.Menu != null)
183 clone = (MainMenu) parent.Menu.CloneMenu ();
185 clone = new MainMenu ();
187 if (form.WindowState == FormWindowState.Maximized) {
190 clone.MergeMenu (form.Menu);
191 clone.MenuChanged += new EventHandler (MenuChangedHandler);
192 clone.SetForm (parent);
196 public MainMenu MaximizedMenu {
198 if (maximized_menu == null)
199 maximized_menu = CreateMaximizedMenu ();
200 return maximized_menu;
204 private MainMenu CreateMaximizedMenu ()
206 Form parent = (Form) mdi_container.Parent;
208 if (form.MainMenuStrip != null || parent.MainMenuStrip != null)
211 MainMenu res = new MainMenu ();
213 if (parent.Menu != null) {
214 MainMenu clone = (MainMenu) parent.Menu.CloneMenu ();
215 res.MergeMenu (clone);
218 if (form.Menu != null) {
219 MainMenu clone = (MainMenu) form.Menu.CloneMenu ();
220 res.MergeMenu (clone);
223 if (res.MenuItems.Count == 0)
224 res.MenuItems.Add (new MenuItem ()); // Dummy item to get the menu height correct
226 res.MenuItems.Insert (0, icon_menu);
228 res.SetForm (parent);
232 private void CreateIconMenus ()
234 icon_menu = new MenuItem ();
235 icon_popup_menu = new ContextMenu ();
237 icon_menu.OwnerDraw = true;
238 icon_menu.MeasureItem += new MeasureItemEventHandler (MeasureIconMenuItem);
239 icon_menu.DrawItem += new DrawItemEventHandler (DrawIconMenuItem);
240 icon_menu.Click += new EventHandler (ClickIconMenuItem);
242 MenuItem restore = new MenuItem ("&Restore", new EventHandler (RestoreItemHandler));
243 MenuItem move = new MenuItem ("&Move", new EventHandler (MoveItemHandler));
244 MenuItem size = new MenuItem ("&Size", new EventHandler (SizeItemHandler));
245 MenuItem minimize = new MenuItem ("Mi&nimize", new EventHandler (MinimizeItemHandler));
246 MenuItem maximize = new MenuItem ("Ma&ximize", new EventHandler (MaximizeItemHandler));
247 MenuItem close = new MenuItem ("&Close", new EventHandler (CloseItemHandler));
248 MenuItem next = new MenuItem ("Nex&t", new EventHandler (NextItemHandler));
250 icon_menu.MenuItems.AddRange (new MenuItem [] { restore, move, size, minimize,
251 maximize, close, next });
252 icon_popup_menu.MenuItems.AddRange (new MenuItem [] { restore, move, size, minimize,
253 maximize, close, next });
256 private void ClickIconMenuItem(object sender, EventArgs e)
258 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) {
262 icon_clicked_time = DateTime.Now;
263 Point pnt = Point.Empty;
264 pnt = form.MdiParent.PointToScreen (pnt);
265 pnt = form.PointToClient (pnt);
269 internal void ShowPopup (Point pnt)
271 // If we are using MainMenuStrip, display that menu instead
272 if (form.WindowState == FormWindowState.Maximized && form.MdiParent.MainMenuStrip != null)
273 if (form.MdiParent.MainMenuStrip.Items.Count > 0) {
274 ToolStripItem tsi = form.MdiParent.MainMenuStrip.Items[0];
276 if (tsi is MdiControlStrip.SystemMenuItem) {
277 (tsi as MdiControlStrip.SystemMenuItem).ShowDropDown ();
282 icon_popup_menu.MenuItems[0].Enabled = form.window_state != FormWindowState.Normal; // restore
283 icon_popup_menu.MenuItems[1].Enabled = form.window_state != FormWindowState.Maximized; // move
284 icon_popup_menu.MenuItems[2].Enabled = form.window_state != FormWindowState.Maximized; // size
285 icon_popup_menu.MenuItems[3].Enabled = form.window_state != FormWindowState.Minimized; // minimize
286 icon_popup_menu.MenuItems[4].Enabled = form.window_state != FormWindowState.Maximized; // maximize
287 icon_popup_menu.MenuItems[5].Enabled = true; // close
288 icon_popup_menu.MenuItems[6].Enabled = true; // next
290 icon_popup_menu.Show(form, pnt);
293 private void RestoreItemHandler (object sender, EventArgs e)
295 form.WindowState = FormWindowState.Normal;
298 private void MoveItemHandler (object sender, EventArgs e)
303 PointToScreen (ref x, ref y);
304 Cursor.Position = new Point (x, y);
305 form.Cursor = Cursors.Cross;
306 state = State.Moving;
310 private void SizeItemHandler (object sender, EventArgs e)
315 PointToScreen (ref x, ref y);
316 Cursor.Position = new Point (x, y);
317 form.Cursor = Cursors.Cross;
318 state = State.Sizing;
322 private void MinimizeItemHandler (object sender, EventArgs e)
324 form.WindowState = FormWindowState.Minimized;
327 private void MaximizeItemHandler (object sender, EventArgs e)
329 if (form.WindowState != FormWindowState.Maximized)
330 form.WindowState = FormWindowState.Maximized;
333 private void CloseItemHandler (object sender, EventArgs e)
338 private void NextItemHandler (object sender, EventArgs e)
340 mdi_container.ActivateNextChild ();
343 private void DrawIconMenuItem (object sender, DrawItemEventArgs de)
345 de.Graphics.DrawIcon (form.Icon, new Rectangle (de.Bounds.X + 2, de.Bounds.Y + 2,
346 de.Bounds.Height - 4, de.Bounds.Height - 4));
349 private void MeasureIconMenuItem (object sender, MeasureItemEventArgs me)
351 int size = SystemInformation.MenuHeight;
352 me.ItemHeight = size;
353 me.ItemWidth = size + 2; // some padding
356 private void MenuChangedHandler (object sender, EventArgs e)
361 public override void PointToClient (ref int x, ref int y)
363 XplatUI.ScreenToClient (mdi_container.Handle, ref x, ref y);
366 public override void PointToScreen (ref int x, ref int y)
368 XplatUI.ClientToScreen (mdi_container.Handle, ref x, ref y);
371 public override void UpdateWindowDecorations (FormWindowState window_state)
373 if (MaximizedMenu != null) {
374 switch (window_state) {
375 case FormWindowState.Minimized:
376 case FormWindowState.Normal:
377 MaximizedMenu.Paint -= draw_maximized_buttons;
378 MaximizedTitleButtons.Visible = false;
379 TitleButtons.Visible = true;
381 case FormWindowState.Maximized:
382 MaximizedMenu.Paint += draw_maximized_buttons;
383 MaximizedTitleButtons.Visible = true;
384 TitleButtons.Visible = false;
389 base.UpdateWindowDecorations (window_state);
392 public override void SetWindowState (FormWindowState old_state, FormWindowState window_state)
394 mdi_container.SetWindowState (form, old_state, window_state, false);
397 private void FormClosed (object sender, EventArgs e)
399 mdi_container.ChildFormClosed (form);
401 if (form.MdiParent.MainMenuStrip != null)
402 form.MdiParent.MainMenuStrip.RefreshMdiItems ();
404 mdi_container.RemoveControlMenuItems (this);
407 public override void DrawMaximizedButtons (object sender, PaintEventArgs pe)
409 Size bs = ThemeEngine.Current.ManagedWindowGetMenuButtonSize (this);
410 Point pnt = XplatUI.GetMenuOrigin (mdi_container.ParentForm.Handle);
411 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
412 TitleButtons buttons = MaximizedTitleButtons;
414 buttons.Visible = true;
415 TitleButtons.Visible = false;
417 buttons.CloseButton.Rectangle = new Rectangle (mdi_container.ParentForm.Size.Width - 1 - bw - bs.Width - 2,
418 pnt.Y + 2, bs.Width, bs.Height);
420 buttons.RestoreButton.Rectangle = new Rectangle (buttons.CloseButton.Rectangle.Left - 2 - bs.Width,
421 pnt.Y + 2, bs.Width, bs.Height);
423 buttons.MinimizeButton.Rectangle = new Rectangle (buttons.RestoreButton.Rectangle.Left - bs.Width,
424 pnt.Y + 2, bs.Width, bs.Height);
426 DrawTitleButton (pe.Graphics, buttons.MinimizeButton, pe.ClipRectangle);
427 DrawTitleButton (pe.Graphics, buttons.RestoreButton, pe.ClipRectangle);
428 DrawTitleButton (pe.Graphics, buttons.CloseButton, pe.ClipRectangle);
430 buttons.MinimizeButton.Rectangle.Y -= pnt.Y;
431 buttons.RestoreButton.Rectangle.Y -= pnt.Y;
432 buttons.CloseButton.Rectangle.Y -= pnt.Y;
435 public bool HandleMenuMouseDown (MainMenu menu, int x, int y)
437 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
439 HandleTitleBarDown (pt.X, pt.Y);
440 return TitleButtons.AnyPushedTitleButtons;
443 public void HandleMenuMouseUp (MainMenu menu, int x, int y)
445 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
447 HandleTitleBarUp (pt.X, pt.Y);
450 public void HandleMenuMouseLeave (MainMenu menu, int x, int y)
452 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
453 HandleTitleBarLeave (pt.X, pt.Y);
457 public void HandleMenuMouseMove (MainMenu menu, int x, int y)
459 Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
461 HandleTitleBarMouseMove (pt.X, pt.Y);
465 protected override void HandleTitleBarLeave (int x, int y)
467 base.HandleTitleBarLeave (x, y);
469 if (maximized_title_buttons != null) {
470 maximized_title_buttons.MouseLeave (x, y);
474 XplatUI.InvalidateNC (form.MdiParent.Handle);
477 protected override void HandleTitleBarUp (int x, int y)
479 if (IconRectangleContains (x, y)) {
480 if (!icon_dont_show_popup) {
482 ClickIconMenuItem (null, null);
484 ShowPopup (Point.Empty);
486 icon_dont_show_popup = false;
491 bool was_maximized = IsMaximized;
492 base.HandleTitleBarUp (x, y);
493 if (maximized_title_buttons != null && was_maximized) {
494 maximized_title_buttons.MouseUp (x, y);
498 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
501 protected override void HandleTitleBarDoubleClick (int x, int y)
503 if (IconRectangleContains (x, y)) {
505 } else if (form.MaximizeBox == true) {
506 form.WindowState = FormWindowState.Maximized;
508 base.HandleTitleBarDoubleClick (x, y);
511 protected override void HandleTitleBarDown (int x, int y)
513 if (IconRectangleContains (x, y)) {
514 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime && icon_clicked.X == x && icon_clicked.Y == y) {
517 icon_clicked_time = DateTime.Now;
525 base.HandleTitleBarDown (x, y);
527 if (maximized_title_buttons != null) {
528 maximized_title_buttons.MouseDown (x, y);
532 XplatUI.InvalidateNC (mdi_container.Parent.Handle);
536 protected override void HandleTitleBarMouseMove (int x, int y)
538 base.HandleTitleBarMouseMove (x, y);
540 if (maximized_title_buttons != null && maximized_title_buttons.MouseMove (x, y))
541 XplatUI.InvalidateNC (form.MdiParent.Handle);
544 protected override bool HandleLButtonDblClick (ref Message m)
547 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
548 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
550 // Correct since we are in NC land.
551 NCClientToNC (ref x, ref y);
553 if (IconRectangleContains (x, y)) {
554 icon_popup_menu.Wnd.Hide ();
559 return base.HandleLButtonDblClick (ref m);
562 protected override bool HandleLButtonDown (ref Message m)
565 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
566 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
568 // Correct y since we are in NC land.
569 NCClientToNC(ref x, ref y);
571 if (IconRectangleContains (x, y)){
572 if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) {
573 if (icon_popup_menu != null && icon_popup_menu.Wnd != null) {
574 icon_popup_menu.Wnd.Hide ();
578 } else if (form.Capture) {
579 icon_dont_show_popup = true;
582 return base.HandleLButtonDown (ref m);
585 protected override bool ShouldRemoveWindowManager (FormBorderStyle style)
590 protected override void HandleWindowMove (Message m)
592 Point pos = Cursor.Position;
593 Point move = MouseMove (pos);
595 if (move.X == 0 && move.Y == 0)
598 int x = virtual_position.X + move.X;
599 int y = virtual_position.Y + move.Y;
601 Rectangle client = mdi_container.ClientRectangle;
602 if (mdi_container.VerticalScrollbarVisible)
603 client.Width -= SystemInformation.VerticalScrollBarWidth;
604 if (mdi_container.HorizontalScrollbarVisible)
605 client.Height -= SystemInformation.HorizontalScrollBarHeight;
607 UpdateVP (x, y, form.Width, form.Height);
612 protected override bool HandleNCMouseMove (ref Message m)
614 XplatUI.RequestAdditionalWM_NCMessages (form.Handle, true, true);
615 return base.HandleNCMouseMove (ref m);
618 protected override void DrawVirtualPosition (Rectangle virtual_position)
620 ClearVirtualPosition ();
622 if (form.Parent != null)
623 XplatUI.DrawReversibleRectangle (form.Parent.Handle, virtual_position, 2);
624 prev_virtual_position = virtual_position;
627 protected override void ClearVirtualPosition ()
629 if (prev_virtual_position != Rectangle.Empty && form.Parent != null)
630 XplatUI.DrawReversibleRectangle (form.Parent.Handle,
631 prev_virtual_position, 2);
632 prev_virtual_position = Rectangle.Empty;
635 protected override void OnWindowFinishedMoving ()
640 public override bool IsActive {
642 if (mdi_container == null)
644 return mdi_container.ActiveMdiChild == form;
648 protected override void Activate ()
650 if (mdi_container.ActiveMdiChild != form) {
651 mdi_container.ActivateChild (form);