* InternalWindowManager.cs: Remove an unused field.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / InternalWindowManager.cs
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 //      Jackson Harper (jackson@ximian.com)
24 //
25 //
26
27
28 using System;
29 using System.Drawing;
30 using System.Runtime.InteropServices;
31
32
33 namespace System.Windows.Forms {
34
35         internal class InternalWindowManager {
36                 private Size MinTitleBarSize = new Size (115, 25);
37
38                 internal Form form;
39
40                 internal TitleButton close_button;
41                 internal TitleButton maximize_button;
42                 internal TitleButton minimize_button;
43                 protected Rectangle icon_rect;
44                 
45                 private TitleButton [] title_buttons = new TitleButton [3];
46                 
47                 // moving windows
48                 internal Point start;
49                 internal State state;
50                 protected Point clicked_point;
51                 private FormPos sizing_edge;
52                 internal Rectangle virtual_position;
53
54                 private bool is_mouse_down_menu;
55                 
56                 public class TitleButton {
57                         public Rectangle Rectangle;
58                         public ButtonState State;
59                         public CaptionButton Caption;
60                         public EventHandler Clicked;
61
62                         public TitleButton (CaptionButton caption, EventHandler clicked)
63                         {
64                                 Caption = caption;
65                                 Clicked = clicked;
66                         }
67                 }
68
69                 public enum State {
70                         Idle,
71                         Moving,
72                         Sizing,
73                 }
74
75                 [Flags]
76                 public enum FormPos {
77                         None,
78
79                         TitleBar = 1,
80
81                         Top = 2,
82                         Left = 4,
83                         Right = 8,
84                         Bottom = 16,
85
86                         TopLeft = Top | Left,
87                         TopRight = Top | Right,
88
89                         BottomLeft = Bottom | Left,
90                         BottomRight = Bottom | Right,
91
92                         AnyEdge = Top | Left | Right | Bottom,
93                 }
94
95                 public InternalWindowManager (Form form)
96                 {
97                         this.form = form;
98
99                         form.SizeChanged += new EventHandler (FormSizeChangedHandler);
100
101                         CreateButtons ();
102                 }
103
104                 public Form Form {
105                         get { return form; }
106                 }
107
108                 public Rectangle CloseButtonRect {
109                         get { return close_button.Rectangle; }
110                         set { close_button.Rectangle = value; }
111                 }
112
113                 public Rectangle MinimizeButtonRect {
114                         get { return minimize_button.Rectangle; }
115                         set { minimize_button.Rectangle = value; }
116                 }
117
118                 public Rectangle MaximizeButtonRect {
119                         get { return maximize_button.Rectangle; }
120                         set { maximize_button.Rectangle = value; }
121                 }
122
123                 public Rectangle IconRect {
124                         get { return icon_rect; }
125                         set { value = icon_rect; }
126                 }
127
128                 public int IconWidth {
129                         get { return TitleBarHeight - 5; }
130                 }
131
132                 public virtual bool HandleMessage (ref Message m)
133                 {
134                         switch ((Msg)m.Msg) {
135
136
137                                 // The mouse handling messages are actually
138                                 // not WM_NC* messages except for the first button and NCMOVEs
139                                 // down because we capture on the form
140
141                         case Msg.WM_MOUSEMOVE:
142                                 return HandleMouseMove (form, ref m);
143
144                         case Msg.WM_LBUTTONUP:
145                                 HandleLButtonUp (ref m);
146                                 break;
147
148                         case Msg.WM_RBUTTONDOWN:
149                         case Msg.WM_LBUTTONDOWN:
150                                 return HandleButtonDown (ref m);
151                         case Msg.WM_PARENTNOTIFY:
152                                 if (Control.LowOrder(m.WParam.ToInt32()) == (int) Msg.WM_LBUTTONDOWN) 
153                                         Activate ();
154                                 break;
155                                 
156                         case Msg.WM_NCHITTEST:
157                                 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
158                                 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
159
160                                 NCPointToClient (ref x, ref y);
161
162                                 FormPos pos = FormPosForCoords (x, y);
163                                 
164                                 if (pos == FormPos.TitleBar) {
165                                         m.Result = new IntPtr ((int) HitTest.HTCAPTION);
166                                         return true;
167                                 }
168
169                                 if (!IsSizable)
170                                         return false;
171
172                                 switch (pos) {
173                                 case FormPos.Top:
174                                         m.Result = new IntPtr ((int) HitTest.HTTOP);
175                                         break;
176                                 case FormPos.Left:
177                                         m.Result = new IntPtr ((int) HitTest.HTLEFT);
178                                         break;
179                                 case FormPos.Right:
180                                         m.Result = new IntPtr ((int) HitTest.HTRIGHT);
181                                         break;
182                                 case FormPos.Bottom:
183                                         m.Result = new IntPtr ((int) HitTest.HTBOTTOM);
184                                         break;
185                                 case FormPos.TopLeft:
186                                         m.Result = new IntPtr ((int) HitTest.HTTOPLEFT);
187                                         break;
188                                 case FormPos.TopRight:
189                                         m.Result = new IntPtr ((int) HitTest.HTTOPRIGHT);
190                                         break;
191                                 case FormPos.BottomLeft:
192                                         m.Result = new IntPtr ((int) HitTest.HTBOTTOMLEFT);
193                                         break;
194                                 case FormPos.BottomRight:
195                                         m.Result = new IntPtr ((int) HitTest.HTBOTTOMRIGHT);
196                                         break;
197                                 default:
198                                         // We return false so that DefWndProc handles things
199                                         return false;
200                                 }
201                                 return true;
202
203                                 // Return true from these guys, otherwise win32 will mess up z-order
204                         case Msg.WM_NCLBUTTONUP:
205                                 HandleNCLButtonUp (ref m);
206                                 return true;
207
208                         case Msg.WM_NCLBUTTONDOWN:
209                                 HandleNCLButtonDown (ref m);
210                                 return true;
211
212                         case Msg.WM_NCMOUSEMOVE:
213                                 HandleNCMouseMove (ref m);
214                                 return true;
215                                 
216                         case Msg.WM_NCLBUTTONDBLCLK:
217                                 HandleNCLButtonDblClick (ref m);
218                                 break;
219
220                         case Msg.WM_NCMOUSELEAVE:
221                                 HandleNCMouseLeave (ref m);
222                                 break;
223                         
224                         case Msg.WM_MOUSE_LEAVE:
225                                 FormMouseLeave (ref m);
226                                 break;
227
228                         case Msg.WM_NCCALCSIZE:
229                                 XplatUIWin32.NCCALCSIZE_PARAMS  ncp;
230
231                                 if (m.WParam == (IntPtr) 1) {
232                                         ncp = (XplatUIWin32.NCCALCSIZE_PARAMS) Marshal.PtrToStructure (m.LParam,
233                                                         typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
234
235                                         int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
236
237                                         if (HasBorders) {
238                                                 ncp.rgrc1.top += TitleBarHeight + bw;
239                                                 ncp.rgrc1.bottom -= bw;
240                                                 ncp.rgrc1.left += bw;
241                                                 ncp.rgrc1.right -= bw;
242                                         }
243
244                                         Marshal.StructureToPtr(ncp, m.LParam, true);
245                                 }
246
247                                 break;
248
249                         case Msg.WM_NCPAINT:
250                                 PaintEventArgs pe = XplatUI.PaintEventStart (form.Handle, false);
251
252                                 Rectangle clip;
253                                 // clip region is not correct on win32.
254                                 // if (m.WParam.ToInt32 () > 1) {
255                                 //      Region r = Region.FromHrgn (m.WParam);
256                                 //      RectangleF rf = r.GetBounds (pe.Graphics);
257                                 //      clip = new Rectangle ((int) rf.X, (int) rf.Y, (int) rf.Width, (int) rf.Height);
258                                 //} else {      
259                                 clip = new Rectangle (0, 0, form.Width, form.Height);
260                                 //}
261
262                                 ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this);
263                                 XplatUI.PaintEventEnd (form.Handle, false);
264                                 return true;
265                         }
266
267                         return false;
268                 }
269
270                 public virtual void UpdateBorderStyle (FormBorderStyle border_style)
271                 {
272                         XplatUI.SetBorderStyle (form.Handle, border_style);
273
274                         if (ShouldRemoveWindowManager (border_style)) {
275                                 form.RemoveWindowManager ();
276                                 return;
277                         }
278                                 
279                         CreateButtons ();
280                 }
281
282                 public bool HandleMenuMouseDown (MainMenu menu, int x, int y)
283                 {
284                         Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
285
286                         is_mouse_down_menu = false;
287                         foreach (TitleButton button in title_buttons) {
288                                 if (button != null) {
289                                         if (button.Rectangle.Contains (pt)) {
290                                                 button.State = ButtonState.Pushed;
291                                                 is_mouse_down_menu = true;
292                                         } else {
293                                                 button.State = ButtonState.Normal;
294                                         }
295                                 }
296                         }
297                         XplatUI.InvalidateNC (menu.GetForm().Handle);
298                         return is_mouse_down_menu;
299                 }
300
301                 public void HandleMenuMouseUp (MainMenu menu, int x, int y)
302                 {
303                         Point pt = MenuTracker.ScreenToMenu (menu, new Point(x, y));
304
305                         foreach (TitleButton button in title_buttons) {
306                                 if (button != null) {
307                                         if (button.Rectangle.Contains (pt)) {
308                                                 button.Clicked (this, EventArgs.Empty);
309                                                 button.State = ButtonState.Pushed;
310                                         } else {
311                                                 button.State = ButtonState.Normal;
312                                         }
313                                 }
314                         }
315                         XplatUI.InvalidateNC (menu.GetForm().Handle);
316                         is_mouse_down_menu = false;
317                         return;
318                 }
319                 
320                 public void HandleMenuMouseLeave(MainMenu menu, int x, int y)
321                 {
322                         foreach (TitleButton button in title_buttons) {
323                                 if (button != null) {
324                                         button.State = ButtonState.Normal;
325                                 }
326                         }
327                         XplatUI.InvalidateNC (menu.GetForm().Handle);
328                         return;
329                 }
330                 
331                 public void HandleMenuMouseMove (MainMenu menu, int x, int y)
332                 {
333                         Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y));
334                         
335                         if (!is_mouse_down_menu)
336                                 return;
337                                 
338                         bool any_change = false;
339                         foreach (TitleButton button in title_buttons) {
340                                 if (button == null) 
341                                         continue;
342                                 
343                                 if (button.Rectangle.Contains(pt)) {
344                                         any_change |= button.State != ButtonState.Pushed;
345                                         button.State = ButtonState.Pushed;
346                                 } else {
347                                         any_change |= button.State != ButtonState.Normal;
348                                         button.State = ButtonState.Normal;
349                                 }
350                         }
351                         if (any_change)
352                                 XplatUI.InvalidateNC (menu.GetForm().Handle);
353                 }
354                 
355                 public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state)
356                 {
357                 }
358
359                 public virtual FormWindowState GetWindowState ()
360                 {
361                         return form.window_state;
362                 }
363
364                 public virtual void PointToClient (ref int x, ref int y)
365                 {
366                         // toolwindows stay in screencoords we just have to make sure
367                         // they obey the working area
368                         Rectangle working = SystemInformation.WorkingArea;
369
370                         if (x > working.Right)
371                                 x = working.Right;
372                         if (x < working.Left)
373                                 x = working.Left;
374
375                         if (y < working.Top)
376                                 y = working.Top;
377                         if (y > working.Bottom)
378                                 y = working.Bottom;
379                 }
380
381                 public virtual void PointToScreen (ref int x, ref int y)
382                 {
383                         XplatUI.ClientToScreen (form.Handle, ref x, ref y);
384                 }
385
386                 protected virtual bool ShouldRemoveWindowManager (FormBorderStyle style)
387                 {
388                         return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow;
389                 }
390
391                 protected virtual void Activate ()
392                 {
393                         // Hack to get a paint
394                         //NativeWindow.WndProc (form.Handle, Msg.WM_NCPAINT, IntPtr.Zero, IntPtr.Zero);
395                         form.Refresh ();
396                 }
397
398                 public virtual bool IsActive ()
399                 {
400                         return true;
401                 }
402
403
404                 private void FormSizeChangedHandler (object sender, EventArgs e)
405                 {
406                         ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
407                         Message m = new Message ();
408                         m.Msg = (int) Msg.WM_NCPAINT;
409                         m.HWnd = form.Handle;
410                         m.LParam = IntPtr.Zero;
411                         m.WParam = new IntPtr (1);
412                         XplatUI.SendMessage (ref m);
413                 }
414
415                 protected void CreateButtons ()
416                 {
417                         switch (form.FormBorderStyle) {
418                         case FormBorderStyle.None:
419                                 close_button = null;
420                                 minimize_button = null;
421                                 maximize_button = null;
422                                 if (IsMaximized || IsMinimized)
423                                         goto case FormBorderStyle.Sizable;
424                                 break;
425                         case FormBorderStyle.FixedToolWindow:
426                         case FormBorderStyle.SizableToolWindow:
427                                 close_button = new TitleButton (CaptionButton.Close, new EventHandler (CloseClicked));
428                                 if (IsMaximized || IsMinimized)
429                                         goto case FormBorderStyle.Sizable;
430                                 break;
431                         case FormBorderStyle.FixedSingle:
432                         case FormBorderStyle.Fixed3D:
433                         case FormBorderStyle.FixedDialog:
434                         case FormBorderStyle.Sizable:
435                                 close_button = new TitleButton (CaptionButton.Close, new EventHandler (CloseClicked));
436                                 minimize_button = new TitleButton (CaptionButton.Minimize, new EventHandler (MinimizeClicked));
437                                 maximize_button = new TitleButton (CaptionButton.Maximize, new EventHandler (MaximizeClicked));
438                                 break;
439                         }
440
441                         title_buttons [0] = close_button;
442                         title_buttons [1] = minimize_button;
443                         title_buttons [2] = maximize_button;
444
445                         ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
446                 }
447
448                 protected virtual bool HandleButtonDown (ref Message m)
449                 {
450                         Activate ();
451                         return false;
452                 }
453
454                 protected virtual bool HandleNCMouseLeave (ref Message m)
455                 {
456                         int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
457                         int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
458
459                         NCPointToClient (ref x, ref y);
460                         FormPos pos = FormPosForCoords (x, y);
461
462                         if (pos != FormPos.TitleBar) {
463                                 HandleTitleBarLeave (x, y);
464                                 return true;
465                         }
466
467                         return true;
468                 }
469                 
470                 protected virtual bool HandleNCMouseMove (ref Message m)
471                 {
472
473                         int x = Control.LowOrder((int)m.LParam.ToInt32( ));
474                         int y = Control.HighOrder((int)m.LParam.ToInt32( ));
475
476                         NCPointToClient (ref x, ref y);
477                         FormPos pos = FormPosForCoords (x, y);
478
479                         if (pos == FormPos.TitleBar) {
480                                 HandleTitleBarMove (x, y);
481                                 return true;
482                         }
483
484                         return true;
485                         
486                 }
487                 
488                 protected virtual bool HandleNCLButtonDown (ref Message m)
489                 {
490                         Activate ();
491
492                         start = Cursor.Position;
493                         virtual_position = form.Bounds;
494
495                         is_mouse_down_menu = false;
496                         
497                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
498                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
499                         
500                         // Need to adjust because we are in NC land
501                         NCPointToClient (ref x, ref y);
502                         FormPos pos = FormPosForCoords (x, y);
503                         
504                         if (pos == FormPos.TitleBar) {
505                                 HandleTitleBarDown (x, y);
506                                 return true;
507                         }
508
509                         if (IsSizable) {
510                                 if ((pos & FormPos.AnyEdge) == 0)
511                                         return false;
512
513                                 virtual_position = form.Bounds;
514                                 state = State.Sizing;
515                                 sizing_edge = pos;
516                                 form.Capture = true;
517                                 return true;
518                         }
519
520                         return false;
521                 }
522
523                 protected virtual void HandleNCLButtonDblClick (ref Message m)
524                 {
525                 }
526                 
527                 protected virtual void HandleTitleBarLeave (int x, int y)
528                 {
529                         is_mouse_down_menu = false;
530                 }
531                 
532                 protected virtual void HandleTitleBarMove (int x, int y)
533                 {
534                         if (!is_mouse_down_menu)
535                                 return;
536                         
537                         bool any_change = false;
538                         foreach (TitleButton button in title_buttons) {
539                                 if (button == null)
540                                         continue;
541                                 
542                                 if (button.Rectangle.Contains (x, y)) {
543                                         any_change |= button.State != ButtonState.Pushed;
544                                         button.State = ButtonState.Pushed;
545                                 } else {
546                                         any_change |= button.State != ButtonState.Normal;
547                                         button.State = ButtonState.Normal;
548                                 }
549                         }
550                         if (any_change)
551                                 XplatUI.InvalidateNC (form.Handle);
552                 }
553                 
554                 protected virtual void HandleTitleBarUp (int x, int y)
555                 {
556                         is_mouse_down_menu = false;
557                         
558                         foreach (TitleButton button in title_buttons) {
559                                 if (button == null)
560                                         continue;
561                                         
562                                 button.State = ButtonState.Normal;
563                                 if (button.Rectangle.Contains (x, y)) {
564                                         button.Clicked (this, EventArgs.Empty);
565                                 } 
566                         }
567                 }
568                 
569                 protected virtual void HandleTitleBarDown (int x, int y)
570                 {
571                         foreach (TitleButton button in title_buttons) {
572                                 if (button != null && button.Rectangle.Contains (x, y)) {
573                                         button.State = ButtonState.Pushed;
574                                         XplatUI.InvalidateNC (form.Handle);
575                                         is_mouse_down_menu = true;
576                                         return;
577                                 }
578                         }
579
580                         if (IsMaximized)
581                                 return;
582
583                         state = State.Moving;
584                         clicked_point = new Point(x, y);
585                         form.Capture = true;
586                 }
587
588                 private bool HandleMouseMove (Form form, ref Message m)
589                 {
590                         switch (state) {
591                         case State.Moving:
592                                 HandleWindowMove (m);
593                                 return true;
594                         case State.Sizing:
595                                 HandleSizing (m);
596                                 return true;
597                         }
598
599                         /*
600                         if (IsSizable) {
601                                 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
602                                 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
603                                 FormPos pos = FormPosForCoords (x, y);
604                                 Console.WriteLine ("position:   " + pos);
605                                 SetCursorForPos (pos);
606
607                                 ClearVirtualPosition ();
608                                 state = State.Idle;
609                         }
610                         */
611                         
612                         return false;
613                 }
614
615                 private void FormMouseLeave (ref Message m)
616                 {
617                         form.ResetCursor ();
618                 }
619         
620                 protected virtual void HandleWindowMove (Message m)
621                 {
622                         Point move = MouseMove (m);
623
624                         UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y,
625                                         virtual_position.Width, virtual_position.Height);
626                 }
627
628                 private void HandleSizing (Message m)
629                 {
630                         Rectangle pos = virtual_position;
631                         int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
632                         int mw = MinTitleBarSize.Width + (bw * 2);
633                         int mh = MinTitleBarSize.Height + (bw * 2);
634                         int x = Cursor.Position.X;
635                         int y = Cursor.Position.Y;
636
637                         PointToClient (ref x, ref y);
638
639                         if ((sizing_edge & FormPos.Top) != 0) {
640                                 if (pos.Bottom - y < mh)
641                                         y = pos.Bottom - mh;
642                                 pos.Height = pos.Bottom - y;
643                                 pos.Y = y;
644                         } else if ((sizing_edge & FormPos.Bottom) != 0) {
645                                 int height = y - pos.Top;
646                                 if (height <= mh)
647                                         height = mh;
648                                 pos.Height = height;
649                         }
650
651                         if ((sizing_edge & FormPos.Left) != 0) {
652                                 if (pos.Right - x < mw)
653                                         x = pos.Right - mw;
654                                 pos.Width = pos.Right - x;
655                                 pos.X = x;
656                         } else if ((sizing_edge & FormPos.Right) != 0) {
657                                 int width = x - form.Left;
658                                 if (width <= mw)
659                                         width = mw;
660                                 pos.Width = width;
661                         }
662
663                         UpdateVP (pos);
664                 }
665
666                 public bool IsMaximized {
667                         get { return GetWindowState () == FormWindowState.Maximized; }
668                 }
669
670                 public bool IsMinimized {
671                         get { return GetWindowState () == FormWindowState.Minimized; }
672                 }
673
674                 public bool IsSizable {
675                         get {
676                                 switch (form.FormBorderStyle) {
677                                 case FormBorderStyle.Sizable:
678                                 case FormBorderStyle.SizableToolWindow:
679                                         return (form.window_state != FormWindowState.Minimized);
680                                 default:
681                                         return false;
682                                 }
683                         }
684                 }
685
686                 public bool HasBorders {
687                         get {
688                                 return form.FormBorderStyle != FormBorderStyle.None;
689                         }
690                 }
691
692                 public bool IsToolWindow {
693                         get {
694                                 if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
695                                                 form.FormBorderStyle == FormBorderStyle.FixedToolWindow)
696                                         return true;
697                                 return false;
698                         }
699                 }
700
701                 public int TitleBarHeight {
702                         get {
703                                 return ThemeEngine.Current.ManagedWindowTitleBarHeight (this);
704                         }
705                 }
706
707                 protected void UpdateVP (Rectangle r)
708                 {
709                         UpdateVP (r.X, r.Y, r.Width, r.Height);
710                 }
711
712                 protected void UpdateVP (Point loc, int w, int h)
713                 {
714                         UpdateVP (loc.X, loc.Y, w, h);
715                 }
716
717                 protected void UpdateVP (int x, int y, int w, int h)
718                 {
719                         virtual_position.X = x;
720                         virtual_position.Y = y;
721                         virtual_position.Width = w;
722                         virtual_position.Height = h;
723
724                         DrawVirtualPosition (virtual_position);
725                 }
726
727                 private void HandleLButtonUp (ref Message m)
728                 {
729                         if (state == State.Idle)
730                                 return;
731
732                         ClearVirtualPosition ();
733
734                         form.Capture = false;
735                         form.Bounds = virtual_position;
736                         state = State.Idle;
737
738                         OnWindowFinishedMoving ();
739                 }
740
741                 private bool HandleNCLButtonUp (ref Message m)
742                 {
743                         if (form.Capture) {
744                                 ClearVirtualPosition ();
745
746                                 form.Capture = false;
747                                 state = State.Idle;
748                                 if (form.MdiContainer != null)
749                                         form.MdiContainer.SizeScrollBars();
750                         }
751                                 
752                         int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
753                         int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
754
755                         NCPointToClient (ref x, ref y);
756                         FormPos pos = FormPosForCoords (x, y);
757
758                         if (pos == FormPos.TitleBar) {
759                                 HandleTitleBarUp (x, y);
760                                 return true;
761                         }
762                         
763                         return true;
764                 }
765                 
766                 protected void DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip)
767                 {
768                         if (!button.Rectangle.IntersectsWith (clip))
769                                 return;
770
771                         dc.FillRectangle (SystemBrushes.Control, button.Rectangle);
772                         ControlPaint.DrawCaptionButton (dc, button.Rectangle,
773                                         button.Caption, button.State);
774                 }
775
776                 public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe)
777                 {
778                 }
779
780                 protected virtual void CloseClicked (object sender, EventArgs e)
781                 {
782                         form.Close ();
783                 }
784
785                 private void MinimizeClicked (object sender, EventArgs e)
786                 {
787                         if (GetWindowState () != FormWindowState.Minimized) {
788                                 form.WindowState = FormWindowState.Minimized;
789                         } else {
790                                 form.WindowState = FormWindowState.Normal;
791                         }
792                 }
793
794                 private void MaximizeClicked (object sender, EventArgs e)
795                 {
796                         if (GetWindowState () != FormWindowState.Maximized) {
797                                 form.WindowState = FormWindowState.Maximized;
798                         } else {
799                                 form.WindowState = FormWindowState.Normal;
800                         }
801                 }
802
803                 protected Point MouseMove (Message m)
804                 {
805                         Point cp = Cursor.Position;
806                         return new Point (cp.X - start.X, cp.Y - start.Y);
807                 }
808
809                 protected virtual void DrawVirtualPosition (Rectangle virtual_position)
810                 {
811                         form.Bounds = virtual_position;
812                         start = Cursor.Position;
813                 }
814
815                 protected virtual void ClearVirtualPosition ()
816                 {
817                         
818                 }
819
820                 protected virtual void OnWindowFinishedMoving ()
821                 {
822                 }
823
824                 protected virtual void NCPointToClient(ref int x, ref int y) {
825                         form.PointToClient(ref x, ref y);
826                         y += TitleBarHeight;
827                         y += ThemeEngine.Current.ManagedWindowBorderWidth (this);
828                 }
829
830                 protected FormPos FormPosForCoords (int x, int y)
831                 {
832                         int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
833                         if (y < TitleBarHeight + bw) {
834                                 //      Console.WriteLine ("A");
835                                 if (y > bw && x > bw &&
836                                                 x < form.Width - bw)
837                                         return FormPos.TitleBar;
838
839                                 if (x < bw || (x < 20 && y < bw))
840                                         return FormPos.TopLeft;
841
842                                 if (x > form.Width - bw ||
843                                         (x > form.Width - 20 && y < bw))
844                                         return FormPos.TopRight;
845
846                                 if (y < bw)
847                                         return FormPos.Top;
848
849                         } else if (y > form.Height - 20) {
850                                 //      Console.WriteLine ("B");
851                                 if (x < bw ||
852                                                 (x < 20 && y > form.Height - bw))
853                                         return FormPos.BottomLeft;
854
855                                 if (x > form.Width - (bw * 2) ||
856                                                 (x > form.Width - 20 &&
857                                                  y > form.Height - bw))
858                                         return FormPos.BottomRight;
859
860                                 if (y > form.Height - (bw * 2))
861                                         return FormPos.Bottom;
862
863
864                         } else if (x < bw) {
865                                 //      Console.WriteLine ("C");
866                                 return FormPos.Left;
867                         } else if (x > form.Width - (bw * 2)) {
868 //                              Console.WriteLine ("D");
869                                 return FormPos.Right;
870                         } else {
871                                 //                      Console.WriteLine ("E   {0}", form.Width - bw);
872                         }
873                         
874                         return FormPos.None;
875                 }
876         }
877 }
878
879