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
30 using System.ComponentModel;
31 using System.Collections;
32 using System.Runtime.InteropServices;
33 using System.Threading;
35 namespace System.Windows.Forms {
36 public class Form : ContainerControl {
37 #region Local Variables
38 internal static Form active_form;
39 internal bool closing;
40 FormBorderStyle formBorderStyle;
41 private static bool autoscale;
42 private static Size autoscale_base_size;
43 internal bool is_modal;
44 internal bool end_modal; // This var is being monitored by the application modal loop
45 private bool control_box;
46 private bool minimize_box;
47 private bool maximize_box;
48 private bool help_button;
49 private bool show_in_taskbar;
51 private IButtonControl accept_button;
52 private IButtonControl cancel_button;
53 private DialogResult dialog_result;
54 private FormStartPosition start_position;
56 private Form.ControlCollection owned_forms;
57 private bool key_preview;
58 private MainMenu menu;
59 internal FormParentWindow form_parent_window;
60 private bool created_form_parent;
62 private Size maximum_size;
63 private Size minimum_size;
64 #endregion // Local Variables
66 #region Private Classes
68 // This class will take over for the client area
69 internal class FormParentWindow : Control {
70 #region FormParentWindow Class Local Variables
72 #endregion // FormParentWindow Class Local Variables
74 #region FormParentWindow Class Constructor
75 internal FormParentWindow(Form owner) : base() {
81 BackColor = owner.BackColor;
83 this.Dock = DockStyle.Fill;
84 this.is_visible = false;
86 // We must set this via the internal var, the SetTopLevel method will too much stuff
89 MouseDown += new MouseEventHandler (OnMouseDownForm);
90 MouseMove += new MouseEventHandler (OnMouseMoveForm);
91 owner.TextChanged += new EventHandler(OnFormTextChanged);
92 CreateControl(); // Create us right away, we have code referencing this.window
94 #endregion // FormParentWindow Class Constructor
96 #region FormParentWindow Class Protected Instance Methods
97 protected override void OnResize(EventArgs e) {
100 if (owner.menu == null) {
101 owner.SetBoundsCore(0, 0, ClientSize.Width, ClientSize.Height, BoundsSpecified.All);
105 menu_height = MenuAPI.MenuBarCalcSize(DeviceContext, owner.Menu.menu_handle, ClientSize.Width);
106 Invalidate (new Rectangle (0, 0, ClientSize.Width, menu_height));
107 owner.SetBoundsCore(0, menu_height, ClientSize.Width, ClientSize.Height-menu_height, BoundsSpecified.All);
111 protected override void OnPaint(PaintEventArgs pevent) {
112 OnDrawMenu (pevent.Graphics);
115 protected override void Select(bool directed, bool forward) {
\r
116 base.Select (directed, forward);
\r
119 protected override void WndProc(ref Message m) {
122 CancelEventArgs args = new CancelEventArgs();
124 owner.OnClosing(args);
127 owner.OnClosed(EventArgs.Empty);
128 owner.closing = true;
135 case Msg.WM_ACTIVATE: {
136 if (m.WParam != (IntPtr)WindowActiveFlags.WA_INACTIVE) {
137 owner.OnActivated(EventArgs.Empty);
139 owner.OnDeactivate(EventArgs.Empty);
144 #if topmost_workaround
145 case Msg.WM_ACTIVATE: {
146 if (this.OwnedForms.Length>0) {
147 XplatUI.SetZOrder(this.OwnedForms[0].window.Handle, this.window.Handle, false, false);
153 case Msg.WM_SETFOCUS: {
154 owner.WndProc(ref m);
158 case Msg.WM_KILLFOCUS: {
159 owner.WndProc(ref m);
164 base.WndProc (ref m);
169 #endregion // FormParentWindow Class Protected Instance Methods
171 #region FormParentWindow Class Private & Internal Methods
172 internal void MenuChanged() {
173 OnResize(EventArgs.Empty);
176 private void OnMouseDownForm (object sender, MouseEventArgs e) {
177 if (owner.menu != null)
178 owner.menu.OnMouseDown (owner, e);
181 private void OnMouseMoveForm (object sender, MouseEventArgs e) {
182 if (owner.menu != null)
183 owner.menu.OnMouseMove (owner, e);
187 private void OnDrawMenu (Graphics dc) {
188 if (owner.menu != null) {
189 Rectangle rect = new Rectangle (0,0, Width, 0);
190 MenuAPI.DrawMenuBar (dc, owner.menu.Handle, rect);
193 private void OnFormTextChanged(object sender, EventArgs e) {
194 this.Text = ((Control)sender).Text;
196 #endregion // FormParentWindow Class Private & Internal Methods
198 #endregion // Private Classes
200 #region Public Classes
201 public new class ControlCollection : Control.ControlCollection {
204 public ControlCollection(Form owner) : base(owner) {
205 this.form_owner = owner;
208 public override void Add(Control value) {
209 for (int i=0; i<list.Count; i++) {
210 if (list[i]==value) {
211 // Do we need to do anything here?
216 ((Form)value).owner=(Form)owner;
219 public override void Remove(Control value) {
220 ((Form)value).owner = null;
224 #endregion // Public Classes
226 #region Public Constructor & Destructor
231 dialog_result = DialogResult.None;
232 start_position = FormStartPosition.WindowsDefaultLocation;
233 formBorderStyle = FormBorderStyle.Sizable;
237 minimum_size = new Size(0, 0);
238 maximum_size = new Size(0, 0);
243 show_in_taskbar = true;
244 ime_mode = ImeMode.NoControl;
246 owned_forms = new Form.ControlCollection(this);
248 #endregion // Public Constructor & Destructor
251 #region Public Static Properties
253 public static Form ActiveForm {
257 active = FromHandle(XplatUI.GetActive());
259 if (active != null) {
260 if ( !(active is Form)) {
261 if (active is FormParentWindow) {
262 return ((FormParentWindow)active).owner;
266 parent = active.Parent;
267 while (parent != null) {
268 if (parent is Form) {
271 parent = parent.Parent;
282 #endregion // Public Static Properties
284 #region Public Instance Properties
285 public IButtonControl AcceptButton {
287 return accept_button;
291 accept_button = value;
295 public bool AutoScale {
305 public virtual Size AutoScaleBaseSize {
307 return autoscale_base_size;
311 autoscale_base_size=value;
315 public IButtonControl CancelButton {
317 return cancel_button;
321 cancel_button = value;
325 public Size ClientSize {
327 return base.ClientSize;
331 form_parent_window.ClientSize = value;
335 public bool ControlBox {
341 if (control_box != value) {
348 public Rectangle DesktopBounds {
350 return new Rectangle(form_parent_window.Location, form_parent_window.Size);
354 this.form_parent_window.Bounds = value;
358 public Point DesktopLocation {
360 return form_parent_window.Location;
364 form_parent_window.Location = value;
368 public DialogResult DialogResult {
370 return dialog_result;
374 dialog_result = value;
376 if (is_modal && (dialog_result != DialogResult.None)) {
382 public FormBorderStyle FormBorderStyle {
384 return formBorderStyle;
387 formBorderStyle = value;
392 public bool HelpButton {
398 if (help_button != value) {
417 public bool IsRestrictedWindow {
423 public bool KeyPreview {
433 public bool MaximizeBox {
438 if (maximize_box != value) {
439 maximize_box = value;
445 public Size MaximumSize {
451 if (maximum_size != value) {
452 maximum_size = value;
457 public MainMenu Menu {
464 // To simulate the non-client are for menus we create a
465 // new control as the 'client area' of our form. This
466 // way, the origin stays 0,0 and we don't have to fiddle with
467 // coordinates. The menu area is part of the original container
472 MenuAPI.SetMenuBarWindow (menu.Handle, form_parent_window);
474 form_parent_window.MenuChanged();
479 public bool MinimizeBox {
484 if (minimize_box != value) {
485 minimize_box = value;
491 public Size MinimumSize {
497 if (minimum_size != value) {
498 minimum_size = value;
509 public Form[] OwnedForms {
513 form_list = new Form[owned_forms.Count];
515 for (int i=0; i<owned_forms.Count; i++) {
516 form_list[i] = (Form)owned_forms[i];
529 if (owner != value) {
531 owner.RemoveOwnedForm(this);
534 owner.AddOwnedForm(this);
536 XplatUI.SetTopmost(this.window.Handle, owner.window.Handle, true);
538 XplatUI.SetTopmost(this.window.Handle, IntPtr.Zero, false);
544 public bool ShowInTaskbar {
546 return show_in_taskbar;
549 if (show_in_taskbar != value) {
550 show_in_taskbar = value;
558 return form_parent_window.Size;
562 form_parent_window.Size = value;
566 public FormStartPosition StartPosition {
568 return start_position;
572 if (start_position == FormStartPosition.WindowsDefaultLocation) { // Only do this if it's not set yet
573 start_position = value;
574 if (form_parent_window.IsHandleCreated) {
575 switch(start_position) {
576 case FormStartPosition.CenterParent: {
577 if (Parent!=null && Width>0 && Height>0) {
578 this.Location = new Point(Parent.Size.Width/2-Width/2, Parent.Size.Height/2-Height/2);
583 case FormStartPosition.CenterScreen: {
584 if (Width>0 && Height>0) {
587 XplatUI.GetDisplaySize(out DisplaySize);
588 this.Location = new Point(DisplaySize.Width/2-Width/2, DisplaySize.Height/2-Height/2);
602 public bool TopLevel {
604 return GetTopLevel();
612 public bool TopMost {
618 if (topmost != value) {
620 XplatUI.SetTopmost(window.Handle, owner != null ? owner.window.Handle : IntPtr.Zero, value);
625 public FormWindowState WindowState {
627 return XplatUI.GetWindowState(form_parent_window.window.Handle);
631 XplatUI.SetWindowState(form_parent_window.window.Handle, value);
635 #endregion // Public Instance Properties
638 internal CreateParams CreateClientAreaParams {
640 CreateParams cp = new CreateParams();
642 if (this.form_parent_window == null) {
643 form_parent_window = new FormParentWindow(this);
644 form_parent_window.MenuChanged();
647 cp.Caption = "ClientArea";
648 cp.ClassName=XplatUI.DefaultClassName;
652 cp.Parent = form_parent_window.window.Handle;
655 cp.Width = form_parent_window.ClientSize.Width;
656 cp.Height = form_parent_window.ClientSize.Width;
658 cp.Style = (int)WindowStyles.WS_CHILD;
659 cp.Style |= (int)WindowStyles.WS_VISIBLE;
660 cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS;
661 cp.Style |= (int)WindowStyles.WS_CLIPCHILDREN;
667 internal CreateParams CreateFormParams {
673 #region Protected Instance Properties
674 [MonoTODO("Need to add MDI support")]
675 protected override CreateParams CreateParams {
679 if (!created_form_parent) {
680 created_form_parent = true;
681 form_parent_window = new FormParentWindow(this);
684 cp = new CreateParams();
686 cp.Caption = "FormWindow";
687 cp.ClassName=XplatUI.DefaultClassName;
691 cp.Parent = IntPtr.Zero;
692 // if (start_position == FormStartPosition.WindowsDefaultLocation) {
693 cp.X = unchecked((int)0x80000000);
694 cp.Y = unchecked((int)0x80000000);
702 cp.Style = (int)(WindowStyles.WS_OVERLAPPEDWINDOW |
703 WindowStyles.WS_CLIPSIBLINGS |
704 WindowStyles.WS_CLIPCHILDREN);
707 cp.ExStyle |= (int)WindowStyles.WS_EX_APPWINDOW;
711 cp.Style |= (int)WindowStyles.WS_MAXIMIZEBOX;
715 cp.Style |= (int)WindowStyles.WS_MINIMIZEBOX;
719 cp.Style |= (int)WindowStyles.WS_SYSMENU;
723 cp.ExStyle |= (int)WindowStyles.WS_EX_CONTEXTHELP;
729 protected override Size DefaultSize {
731 return new Size (250, 250);
735 protected override void OnPaint (PaintEventArgs pevent)
737 base.OnPaint (pevent);
740 #endregion // Protected Instance Properties
743 #region Public Static Methods
744 #endregion // Public Static Methods
746 #region Public Instance Methods
747 public void Activate() {
750 // The docs say activate only activates if our app is already active
752 if ((active != null) && (this != active)) {
753 XplatUI.Activate(form_parent_window.window.Handle);
757 public void AddOwnedForm(Form ownedForm) {
758 owned_forms.Add(ownedForm);
761 public void RemoveOwnedForm(Form ownedForm) {
762 owned_forms.Remove(ownedForm);
765 public void SetDesktopBounds(int x, int y, int width, int height) {
766 DesktopBounds = new Rectangle(x, y, width, height);
769 public void SetDesktopLocation(int x, int y) {
770 DesktopLocation = new Point(x, y);
773 public DialogResult ShowDialog() {
774 return ShowDialog(null);
777 public DialogResult ShowDialog(IWin32Window ownerWin32) {
781 Control owner = null;
783 if (ownerWin32 != null) {
784 owner = Control.FromHandle(ownerWin32.Handle);
789 return DialogResult.None;
793 throw new InvalidOperationException("Already visible forms cannot be displayed as a modal dialog. Set the Visible property to 'false' prior to calling Form.ShowDialog.");
797 // Can't do this, will screw us in the modal loop
798 form_parent_window.Parent = owner;
801 previous = Form.ActiveForm;
803 if (!IsHandleCreated) {
807 XplatUI.SetModal(form_parent_window.window.Handle, true);
813 Application.ModalRun(this);
817 XplatUI.SetModal(form_parent_window.window.Handle, false);
819 if (previous != null) {
820 // Cannot use Activate(), it has a check for the current active window...
821 XplatUI.Activate(previous.form_parent_window.window.Handle);
829 CancelEventArgs args = new CancelEventArgs ();
832 OnClosed (EventArgs.Empty);
838 #endregion // Public Instance Methods
840 #region Protected Instance Methods
841 protected override void CreateHandle() {
842 base.CreateHandle ();
845 protected override void OnCreateControl() {
846 base.OnCreateControl ();
847 if (this.ActiveControl == null) {
848 if (SelectNextControl(this, true, true, true, true) == false) {
852 OnLoad(EventArgs.Empty);
854 // Send initial location
855 OnLocationChanged(EventArgs.Empty);
858 protected override void OnHandleCreated(EventArgs e) {
859 base.OnHandleCreated (e);
862 protected override void OnHandleDestroyed(EventArgs e) {
863 base.OnHandleDestroyed (e);
867 protected override void OnResize(EventArgs e) {
871 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
872 if (base.ProcessCmdKey (ref msg, keyData)) {
876 // Give our menu a shot
878 return menu.ProcessCmdKey(ref msg, keyData);
884 protected override bool ProcessDialogKey(Keys keyData) {
885 if ((keyData & Keys.Modifiers) == 0) {
886 if (keyData == Keys.Enter && accept_button != null) {
887 accept_button.PerformClick();
889 } else if (keyData == Keys.Escape && cancel_button != null) {
890 cancel_button.PerformClick();
894 return base.ProcessDialogKey(keyData);
897 protected override bool ProcessKeyPreview(ref Message msg) {
899 if (ProcessKeyEventArgs(ref msg)) {
903 return base.ProcessKeyPreview (ref msg);
906 protected override void SetClientSizeCore(int x, int y) {
907 if ((minimum_size.Width != 0) && (x < minimum_size.Width)) {
908 x = minimum_size.Width;
909 } else if ((maximum_size.Width != 0) && (x > maximum_size.Width)) {
910 x = maximum_size.Width;
913 if ((minimum_size.Height != 0) && (y < minimum_size.Height)) {
914 y = minimum_size.Height;
915 } else if ((maximum_size.Height != 0) && (y > maximum_size.Height)) {
916 y = maximum_size.Height;
919 base.SetClientSizeCore (x, y);
923 protected override void WndProc(ref Message m) {
926 CancelEventArgs args = new CancelEventArgs();
931 OnClosed(EventArgs.Empty);
939 case Msg.WM_KILLFOCUS: {
943 case Msg.WM_SETFOCUS: {
944 if (this.ActiveControl != null) {
945 ActiveControl.Focus();
951 base.WndProc (ref m);
956 #endregion // Protected Instance Methods
959 protected virtual void OnActivated(EventArgs e) {
960 if (Activated != null) {
965 protected virtual void OnClosed(EventArgs e) {
966 if (Closed != null) {
971 protected virtual void OnClosing(System.ComponentModel.CancelEventArgs e) {
972 if (Closing != null) {
977 protected virtual void OnDeactivate(EventArgs e) {
978 if (Deactivate != null) {
983 protected virtual void OnInputLanguageChanged(InputLanguageChangedEventArgs e) {
984 if (InputLanguageChanged!=null) {
985 InputLanguageChanged(this, e);
989 protected virtual void OnInputLanguageChanging(InputLanguageChangingEventArgs e) {
990 if (InputLanguageChanging!=null) {
991 InputLanguageChanging(this, e);
995 protected virtual void OnLoad(EventArgs e) {
1001 protected virtual void OnMaximizedBoundsChanged(EventArgs e) {
1002 if (MaximizedBoundsChanged != null) {
1003 MaximizedBoundsChanged(this, e);
1007 protected virtual void OnMaximumSizeChanged(EventArgs e) {
1008 if (MaximumSizeChanged != null) {
1009 MaximumSizeChanged(this, e);
1013 protected virtual void OnMdiChildActivate(EventArgs e) {
1014 if (MdiChildActivate != null) {
1015 MdiChildActivate(this, e);
1019 protected virtual void OnMenuComplete(EventArgs e) {
1020 if (MenuComplete != null) {
1021 MenuComplete(this, e);
1025 protected virtual void OnMenuStart(EventArgs e) {
1026 if (MenuStart != null) {
1031 protected virtual void OnMinimumSizeChanged(EventArgs e) {
1032 if (MinimumSizeChanged != null) {
1033 MinimumSizeChanged(this, e);
1037 public event EventHandler Activated;
1038 public event EventHandler Closed;
1039 public event CancelEventHandler Closing;
1040 public event EventHandler Deactivate;
1041 public event InputLanguageChangedEventHandler InputLanguageChanged;
1042 public event InputLanguageChangingEventHandler InputLanguageChanging;
1043 public event EventHandler Load;
1044 public event EventHandler MaximizedBoundsChanged;
1045 public event EventHandler MaximumSizeChanged;
1046 public event EventHandler MdiChildActivate;
1047 public event EventHandler MenuComplete;
1048 public event EventHandler MenuStart;
1049 public event EventHandler MinimumSizeChanged;
1050 #endregion // Events