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) 2004 Novell, Inc.
23 // Peter Bartok pbartok@novell.com
29 // Revision 1.22 2004/11/08 20:50:29 pbartok
30 // - Fixed arguments for updated SetTopmost method
32 // Revision 1.21 2004/11/04 14:47:58 jordi
33 // collection completion, drawing issues, missing features
35 // Revision 1.20 2004/10/29 15:55:26 jordi
36 // Menu key navigation, itemcollection completion, menu fixes
38 // Revision 1.19 2004/10/20 03:56:23 pbartok
39 // - Added private FormParentWindow class which acts as the container for
40 // our form and as the non-client area where menus are drawn
41 // - Added/Moved required tie-ins to Jordi's menus
42 // - Fixed/Implemented the FormStartPosition functionality
44 // Revision 1.18 2004/10/18 04:47:09 pbartok
45 // - Fixed Form.ControlCollection to handle owner relations
46 // - Added Owner/OwnedForms handling
47 // - Implemented Z-Ordering for owned forms
48 // - Removed unneeded private overload of ShowDialog
49 // - Fixed ShowDialog, added the X11 incarnation of modal handling (or so I
51 // - Fixed Close(), had wrong default
52 // - Added firing of OnLoad event
53 // - Added some commented out debug code for Ownership handling
55 // Revision 1.17 2004/10/15 12:43:19 jordi
56 // menu work, mainmenu, subitems, etc
58 // Revision 1.16 2004/10/14 06:17:58 ravindra
59 // Fixed class signature. ShowDialog (Control) is not a public method.
61 // Revision 1.15 2004/10/08 08:50:29 jordi
64 // Revision 1.14 2004/10/02 19:05:52 pbartok
65 // - Added KeyPreview property
66 // - Added Menu property (still incomplete, pending Jordi's menu work)
67 // - Implemented ProcessCmdKey
68 // - Implemented ProcessDialogKey
69 // - Implemented ProcessKeyPreview
71 // Revision 1.13 2004/10/01 17:53:26 jackson
72 // Implement the Close method so work on MessageBox can continue.
74 // Revision 1.12 2004/09/23 19:08:59 jackson
77 // Revision 1.11 2004/09/22 20:09:44 pbartok
78 // - Added Form.ControllCollection class
79 // - Added handling for Form owners: Owner, OwnedForms, AddOwnedForm,
80 // RemoveOwnedForm (still incomplete, missing on-top and common
81 // minimize/maximize behaviour)
82 // - Added StartPosition property (still incomplete, does not use when
84 // - Added ShowDialog() methods (still incomplete, missing forcing the dialog
87 // Revision 1.10 2004/09/13 16:56:04 pbartok
88 // - Fixed #region names
89 // - Moved properties and methods into their proper #regions
91 // Revision 1.9 2004/09/13 16:51:29 pbartok
92 // - Added Accept and CancelButton properties
93 // - Added ProcessDialogKey() method
95 // Revision 1.8 2004/09/01 02:05:18 pbartok
96 // - Added (partial) implementation of DialogResult; rest needs to be
97 // implemented when the modal loop code is done
99 // Revision 1.7 2004/08/23 22:10:02 pbartok
100 // - Fixed handling of WM_CLOSE message
101 // - Removed debug output
103 // Revision 1.6 2004/08/22 21:10:30 pbartok
104 // - Removed OverlappedWindow style from Control, instead it's default
106 // - Made form windows OverlappedWindow by default
108 // Revision 1.5 2004/08/19 21:30:37 pbartok
109 // - Added handling of WM_CLOSE
111 // Revision 1.4 2004/08/11 22:20:59 pbartok
114 // Revision 1.3 2004/08/04 21:13:47 pbartok
115 // - Added AutoScale properties
117 // Revision 1.2 2004/07/13 15:31:45 jordi
118 // commit: new properties and fixes form size problems
120 // Revision 1.1 2004/07/09 05:21:25 pbartok
121 // - Initial check-in
128 using System.Drawing;
129 using System.ComponentModel;
130 using System.Collections;
131 using System.Runtime.InteropServices;
132 using System.Threading;
134 namespace System.Windows.Forms {
135 public class Form : ContainerControl {
136 #region Local Variables
137 internal bool closing;
141 ShowInTaskbar = 0x0001,
142 MaximizeBox = 0x0002,
143 MinimizeBox = 0x0004,
147 Flags flags = Flags.ShowInTaskbar | Flags.MaximizeBox | Flags.MinimizeBox;
148 FormBorderStyle formBorderStyle = FormBorderStyle.Sizable;
149 private static bool autoscale;
150 private static Size autoscale_base_size;
151 private bool is_modal;
152 internal bool end_modal; // This var is being monitored by the application modal loop
153 private IButtonControl accept_button;
154 private IButtonControl cancel_button;
155 private DialogResult dialog_result;
156 private FormStartPosition start_position;
158 private Form.ControlCollection owned_forms;
159 private bool key_preview;
160 private MainMenu menu;
161 internal FormParentWindow form_parent_window;
162 #endregion // Local Variables
164 #region Private Classes
166 // This class will take over for the client area
167 internal class FormParentWindow : Control {
168 #region FormParentWindow Class Local Variables
170 #endregion // FormParentWindow Class Local Variables
172 #region FormParentWindow Class Constructor
173 internal FormParentWindow(Form owner) : base() {
179 BackColor = owner.BackColor;
181 this.Location = new Point(0, 0);
182 this.Dock = DockStyle.Fill;
184 MouseDown += new MouseEventHandler (OnMouseDownForm);
185 MouseMove += new MouseEventHandler (OnMouseMoveForm);
186 owner.TextChanged += new EventHandler(OnFormTextChanged);
188 #endregion // FormParentWindow Class Constructor
190 #region FormParentWindow Class Protected Instance Methods
\r
191 protected override CreateParams CreateParams {
\r
195 cp = base.CreateParams;
\r
197 cp.Style = (int)(WindowStyles.WS_OVERLAPPEDWINDOW |
198 WindowStyles.WS_VISIBLE |
199 WindowStyles.WS_CLIPSIBLINGS |
200 WindowStyles.WS_CLIPCHILDREN);
206 if (this.IsHandleCreated) {
\r
214 XplatUI.GetWindowPos(this.window.Handle, out x, out y, out width, out height, out cwidth, out cheight);
\r
215 UpdateBounds(x, y, width, height);
\r
216 owner.UpdateBounds(x, y, width, height);
\r
224 protected override void OnResize(EventArgs e) {
\r
226 //owner.SetBoundsCore(owner.Bounds.X, owner.Bounds.Y, ClientSize.Width, ClientSize.Height, BoundsSpecified.All);
227 if (owner.menu == null) {
228 owner.SetBoundsCore(0, 0, ClientSize.Width, ClientSize.Height, BoundsSpecified.All);
232 menu_height = MenuAPI.MenuBarCalcSize(DeviceContext, owner.Menu.menu_handle, ClientSize.Width);
233 Invalidate (new Rectangle (0, 0, ClientSize.Width, menu_height));
234 owner.SetBoundsCore(0, menu_height, ClientSize.Width, ClientSize.Height-menu_height, BoundsSpecified.All);
238 protected override void OnPaint(PaintEventArgs pevent) {
\r
239 OnDrawMenu (pevent.Graphics);
242 protected override void WndProc(ref Message m) {
\r
243 switch((Msg)m.Msg) {
\r
244 case Msg.WM_CLOSE: {
\r
245 CancelEventArgs args = new CancelEventArgs();
\r
247 owner.OnClosing(args);
\r
249 if (!args.Cancel) {
\r
250 owner.OnClosed(EventArgs.Empty);
\r
251 owner.closing = true;
\r
252 base.WndProc(ref m);
\r
259 base.WndProc (ref m);
\r
264 #endregion // FormParentWindow Class Protected Instance Methods
\r
266 #region FormParentWindow Class Private Methods
\r
267 private void OnMouseDownForm (object sender, MouseEventArgs e) {
268 if (owner.menu != null)
269 owner.menu.OnMouseDown (owner, e);
272 private void OnMouseMoveForm (object sender, MouseEventArgs e) {
273 if (owner.menu != null)
274 owner.menu.OnMouseMove (owner, e);
278 private void OnDrawMenu (Graphics dc) {
279 if (owner.menu != null) {
280 Rectangle rect = new Rectangle (0,0, Width, 0);
281 MenuAPI.DrawMenuBar (dc, owner.menu.Handle, rect);
284 private void OnFormTextChanged(object sender, EventArgs e) {
\r
285 this.Text = ((Control)sender).Text;
\r
287 #endregion // FormParentWindow Class Private Methods
289 #endregion // Private Classes
291 #region Public Classes
292 public class ControlCollection : Control.ControlCollection {
295 public ControlCollection(Form owner) : base(owner) {
296 this.form_owner = owner;
299 public override void Add(Control value) {
300 for (int i=0; i<list.Count; i++) {
301 if (list[i]==value) {
302 // Do we need to do anything here?
307 ((Form)value).owner=(Form)owner;
310 public override void Remove(Control value) {
\r
311 ((Form)value).owner = null;
\r
312 base.Remove (value);
\r
315 #endregion // Public Classes
317 #region Public Constructor & Destructor
322 dialog_result = DialogResult.None;
323 start_position = FormStartPosition.WindowsDefaultLocation;
327 owned_forms = new Form.ControlCollection(this);
329 #endregion // Public Constructor & Destructor
332 #region Public Static Properties
334 public static Form ActiveForm {
\r
336 //FIXME: create next driver call
\r
341 #endregion // Public Static Properties
343 #region Public Instance Properties
344 public IButtonControl AcceptButton {
346 return accept_button;
350 accept_button = value;
354 public bool AutoScale {
364 public virtual Size AutoScaleBaseSize {
366 return autoscale_base_size;
370 autoscale_base_size=value;
374 public IButtonControl CancelButton {
376 return cancel_button;
380 cancel_button = value;
384 public DialogResult DialogResult {
386 return dialog_result;
390 dialog_result = value;
392 if (is_modal && (dialog_result != DialogResult.None)) {
398 public FormBorderStyle FormBorderStyle {
\r
400 return formBorderStyle;
\r
403 formBorderStyle = value;
\r
409 public bool KeyPreview {
419 public bool MaximizeBox {
\r
421 return (flags & Flags.MaximizeBox) != 0;
\r
425 flags &= ~Flags.MaximizeBox;
\r
427 flags |= Flags.MaximizeBox;
\r
431 public MainMenu Menu {
439 form_parent_window.Width = form_parent_window.Width; // Trigger a resize
444 // To simulate the non-client are for menus we create a
445 // new control as the 'client area' of our form. This
446 // way, the origin stays 0,0 and we don't have to fiddle with
447 // coordinates. The menu area is part of the original container
449 form_parent_window.Width = form_parent_window.Width; // Trigger a resize
453 MenuAPI.SetMenuBarWindow (menu.Handle, form_parent_window);
458 public bool MinimizeBox {
\r
460 return (flags & Flags.MinimizeBox) != 0;
\r
464 flags &= ~Flags.MinimizeBox;
\r
466 flags |= Flags.MinimizeBox;
\r
476 public Form[] OwnedForms {
480 form_list = new Form[owned_forms.Count];
482 for (int i=0; i<owned_forms.Count; i++) {
483 form_list[i] = (Form)owned_forms[i];
496 if (owner != value) {
498 owner.RemoveOwnedForm(this);
501 owner.AddOwnedForm(this);
503 XplatUI.SetTopmost(this.window.Handle, owner.window.Handle, true);
505 XplatUI.SetTopmost(this.window.Handle, IntPtr.Zero, false);
511 public bool ShowInTaskbar {
\r
513 return (flags & Flags.ShowInTaskbar) != 0;
\r
517 flags &= ~Flags.ShowInTaskbar;
\r
519 flags |= Flags.ShowInTaskbar;
\r
523 public FormStartPosition StartPosition {
525 return start_position;
529 if (start_position == FormStartPosition.WindowsDefaultLocation) { // Only do this if it's not set yet
530 start_position = value;
531 if (form_parent_window.IsHandleCreated) {
532 switch(start_position) {
533 case FormStartPosition.CenterParent: {
534 if (Parent!=null && Width>0 && Height>0) {
535 this.Location = new Point(Parent.Size.Width/2-Width/2, Parent.Size.Height/2-Height/2);
540 case FormStartPosition.CenterScreen: {
541 if (Width>0 && Height>0) {
544 XplatUI.GetDisplaySize(out DisplaySize);
545 this.Location = new Point(DisplaySize.Width/2-Width/2, DisplaySize.Height/2-Height/2);
559 public bool TopMost {
\r
561 return (flags & Flags.TopMost) != 0;
\r
564 if (TopMost == value)
\r
568 flags &= ~Flags.TopMost;
\r
570 flags |= Flags.TopMost;
\r
572 XplatUI.SetTopmost(window.Handle, owner != null ? owner.window.Handle : IntPtr.Zero, TopMost);
576 #endregion // Public Instance Properties
578 #region Protected Instance Properties
579 [MonoTODO("Need to add MDI support")]
580 protected override CreateParams CreateParams {
582 CreateParams cp = new CreateParams();
584 if (this.form_parent_window == null) {
585 form_parent_window = new FormParentWindow(this);
588 cp.Caption = "ClientArea";
589 cp.ClassName=XplatUI.DefaultClassName;
593 cp.Parent = this.form_parent_window.window.Handle;
599 cp.Style = (int)WindowStyles.WS_CHILD;
600 cp.Style |= (int)WindowStyles.WS_VISIBLE;
601 cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;
602 cp.Style |= (int)WindowStyles.WS_CLIPCHILDREN;
605 cp.ExStyle |= (int)WindowStyles.WS_EX_APPWINDOW;
607 cp.Style |= (int)WindowStyles.WS_MAXIMIZEBOX;
609 cp.Style |= (int)WindowStyles.WS_MINIMIZEBOX;
615 protected override Size DefaultSize {
617 return new Size (250, 250);
621 protected override void OnPaint (PaintEventArgs pevent)
623 base.OnPaint (pevent);
626 #endregion // Protected Instance Properties
629 #region Public Static Methods
630 #endregion // Public Static Methods
632 #region Public Instance Methods
633 public void AddOwnedForm(Form ownedForm) {
634 owned_forms.Add(ownedForm);
637 public void RemoveOwnedForm(Form ownedForm) {
638 owned_forms.Remove(ownedForm);
641 public DialogResult ShowDialog() {
642 return ShowDialog(null);
645 public DialogResult ShowDialog(IWin32Window ownerWin32) {
646 Control owner = null;
648 if (ownerWin32 != null) {
649 owner = Control.FromHandle(ownerWin32.Handle);
653 return DialogResult.None;
657 throw new InvalidOperationException("Already visible forms cannot be displayed as a modal dialog. Set the Visible property to 'false' prior to calling Form.ShowDialog.");
660 if (!IsHandleCreated) {
664 XplatUI.SetModal(window.Handle, true);
669 Application.ModalRun(this);
673 XplatUI.SetModal(window.Handle, false);
680 CancelEventArgs args = new CancelEventArgs ();
683 OnClosed (EventArgs.Empty);
689 #endregion // Public Instance Methods
691 #region Protected Instance Methods
692 protected override void CreateHandle() {
\r
693 base.CreateHandle ();
\r
696 protected override void OnCreateControl() {
\r
697 base.OnCreateControl ();
\r
698 OnLoad(EventArgs.Empty);
\r
701 protected override void OnHandleCreated(EventArgs e) {
\r
702 base.OnHandleCreated (e);
\r
705 protected override void OnHandleDestroyed(EventArgs e) {
\r
706 base.OnHandleDestroyed (e);
\r
710 protected override void OnResize(EventArgs e) {
714 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
\r
715 if (base.ProcessCmdKey (ref msg, keyData)) {
\r
719 // Give our menu a shot
\r
720 if (menu != null) {
\r
721 return menu.ProcessCmdKey(ref msg, keyData);
\r
727 protected override bool ProcessDialogKey(Keys keyData) {
728 if (keyData == Keys.Enter && accept_button != null) {
729 accept_button.PerformClick();
731 } else if (keyData == Keys.Enter && cancel_button != null) {
732 cancel_button.PerformClick();
735 return base.ProcessDialogKey(keyData);
738 protected override bool ProcessKeyPreview(ref Message msg) {
\r
740 if (ProcessKeyEventArgs(ref msg)) {
\r
744 return base.ProcessKeyPreview (ref msg);
\r
747 protected override void WndProc(ref Message m) {
\r
748 switch((Msg)m.Msg) {
\r
749 case Msg.WM_CLOSE: {
\r
750 CancelEventArgs args = new CancelEventArgs();
\r
754 if (!args.Cancel) {
\r
755 OnClosed(EventArgs.Empty);
\r
757 base.WndProc(ref m);
\r
763 #if topmost_workaround
764 case Msg.WM_ACTIVATE: {
\r
765 if (this.OwnedForms.Length>0) {
766 XplatUI.SetZOrder(this.OwnedForms[0].window.Handle, this.window.Handle, false, false);
772 base.WndProc (ref m);
\r
777 #endregion // Protected Instance Methods
780 protected virtual void OnActivated(EventArgs e) {
781 if (Activated != null) {
786 protected virtual void OnClosed(EventArgs e) {
787 if (Closed != null) {
792 protected virtual void OnClosing(System.ComponentModel.CancelEventArgs e) {
793 if (Closing != null) {
798 protected virtual void OnDeactivate(EventArgs e) {
799 if (Deactivate != null) {
804 protected virtual void OnInputLanguageChanged(InputLanguageChangedEventArgs e) {
805 if (InputLanguageChanged!=null) {
806 InputLanguageChanged(this, e);
810 protected virtual void OnInputLanguageChanging(InputLanguageChangingEventArgs e) {
811 if (InputLanguageChanging!=null) {
812 InputLanguageChanging(this, e);
816 protected virtual void OnLoad(EventArgs e) {
822 protected virtual void OnMaximizedBoundsChanged(EventArgs e) {
823 if (MaximizedBoundsChanged != null) {
824 MaximizedBoundsChanged(this, e);
828 protected virtual void OnMaximumSizeChanged(EventArgs e) {
829 if (MaximumSizeChanged != null) {
830 MaximumSizeChanged(this, e);
834 protected virtual void OnMdiChildActivate(EventArgs e) {
835 if (MdiChildActivate != null) {
836 MdiChildActivate(this, e);
840 protected virtual void OnMenuComplete(EventArgs e) {
841 if (MenuComplete != null) {
842 MenuComplete(this, e);
846 protected virtual void OnMenuStart(EventArgs e) {
847 if (MenuStart != null) {
852 protected virtual void OnMinimumSizeChanged(EventArgs e) {
853 if (MinimumSizeChanged != null) {
854 MinimumSizeChanged(this, e);
858 public event EventHandler Activated;
859 public event EventHandler Closed;
860 public event CancelEventHandler Closing;
861 public event EventHandler Deactivate;
862 public event InputLanguageChangedEventHandler InputLanguageChanged;
863 public event InputLanguageChangingEventHandler InputLanguageChanging;
864 public event EventHandler Load;
865 public event EventHandler MaximizedBoundsChanged;
866 public event EventHandler MaximumSizeChanged;
867 public event EventHandler MdiChildActivate;
868 public event EventHandler MenuComplete;
869 public event EventHandler MenuStart;
870 public event EventHandler MinimumSizeChanged;