2008-08-15 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / XplatUIX11.cs
index d44a3e6dbcbf0ac136b9809a54457d1708d205e7..c83cf70c15d06533c009ea37b81112a336478021 100644 (file)
@@ -101,6 +101,7 @@ namespace System.Windows.Forms {
 
                // Message Loop
                private static Hashtable        MessageQueues;          // Holds our thread-specific XEventQueues
+               private static ArrayList        unattached_timer_list; // holds timers that are enabled but not attached to a window.
                #if __MonoCS__                                          //
                private static Pollfd[]         pollfds;                // For watching the X11 socket
                private static bool wake_waiting;
@@ -132,6 +133,9 @@ namespace System.Windows.Forms {
                // Caret
                private static CaretStruct      Caret;                  //
 
+               // Last window containing the pointer
+               private static IntPtr           LastPointerWindow;      // The last window containing the pointer
+
                // Our atoms
                private static IntPtr WM_PROTOCOLS;
                private static IntPtr WM_DELETE_WINDOW;
@@ -226,6 +230,7 @@ namespace System.Windows.Forms {
                                                   EventMask.ExposureMask |
                                                   EventMask.FocusChangeMask |
                                                   EventMask.PointerMotionMask | 
+                                                  EventMask.PointerMotionHintMask | 
                                                   EventMask.SubstructureNotifyMask);
 
                static readonly object lockobj = new object ();
@@ -238,7 +243,9 @@ namespace System.Windows.Forms {
 
                        // Now regular initialization
                        XlibLock = new object ();
+                       X11Keyboard.XlibLock = XlibLock;
                        MessageQueues = Hashtable.Synchronized (new Hashtable(7));
+                       unattached_timer_list = ArrayList.Synchronized (new ArrayList (3));
                        XInitThreads();
 
                        ErrorExceptions = false;
@@ -439,7 +446,8 @@ namespace System.Windows.Forms {
                                DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
 
                                // Create the foster parent
-                               FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero);
+                               // it is important that border_width is kept in synch with the other XCreateWindow calls
+                               FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 0, UIntPtr.Zero, UIntPtr.Zero);
                                if (FosterParent==IntPtr.Zero) {
                                        Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
                                }
@@ -507,7 +515,7 @@ namespace System.Windows.Forms {
                                SetupAtoms();
 
                                // Grab atom changes off the root window to catch certain WM events
-                               XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int)EventMask.PropertyChangeMask));
+                               XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int) (EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
 
                                // Handle any upcoming errors
                                ErrorHandler = new XErrorHandler(HandleError);
@@ -777,8 +785,12 @@ namespace System.Windows.Forms {
                         */
                        Rectangle rect = hwnd.ClientRect;
                        Form form = ctrl as Form;
-                       if (form != null && form.window_manager == null) {
-                               CreateParams cp = form.GetCreateParams ();
+                       CreateParams cp = null;
+
+                       if (form != null)
+                               cp = form.GetCreateParams ();
+
+                       if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
                                Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
                                Rectangle xrect = rect;
 
@@ -801,28 +813,32 @@ namespace System.Windows.Forms {
                }
 
                internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp)
+               {
+                       return TranslateWindowSizeToXWindowSize (cp, new Size (cp.Width, cp.Height));
+               }
+
+               internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp, Size size)
                {
                        /* 
                         * If this is a form with no window manager, X is handling all the border and caption painting
                         * so remove that from the area (since the area we set of the window here is the part of the window 
                         * we're painting in only)
                         */
-                       Size rect = new Size (cp.Width, cp.Height);
                        Form form = cp.control as Form;
-                       if (form != null && form.window_manager == null) {
+                       if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
                                Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
-                               Size xrect = rect;
+                               Size xrect = size;
 
                                xrect.Width -= borders.left + borders.right;
                                xrect.Height -= borders.top + borders.bottom;
 
-                               rect = xrect;
+                               size = xrect;
                        }
-                       if (rect.Height == 0)
-                               rect.Height = 1;
-                       if (rect.Width == 0)
-                               rect.Width = 1;
-                       return rect;
+                       if (size.Height == 0)
+                               size.Height = 1;
+                       if (size.Width == 0)
+                               size.Width = 1;
+                       return size;
                }
 
                internal static Size TranslateXWindowSizeToWindowSize (CreateParams cp, int xWidth, int xHeight)
@@ -834,7 +850,7 @@ namespace System.Windows.Forms {
                         */
                        Size rect = new Size (xWidth, xHeight);
                        Form form = cp.control as Form;
-                       if (form != null && form.window_manager == null) {
+                       if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
                                Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
                                Size xrect = rect;
 
@@ -986,7 +1002,7 @@ namespace System.Windows.Forms {
                                   is ignored by metacity. */
                                functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
                        } else if (form != null && form.FormBorderStyle == FormBorderStyle.None) {
-                               // No functions nor decorations whatsoever.
+                               functions |= MotifFunctions.All;
                        } else {
                                if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
                                        functions |= MotifFunctions.Move;
@@ -1102,7 +1118,7 @@ namespace System.Windows.Forms {
                                        XSetTransientForHint (DisplayHandle, hwnd.whole_window, transient_for_parent);
                                }
 
-                               XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
+                               MoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
 
                                if (hide_from_taskbar) {
                                        /* this line keeps the window from showing up in gnome's taskbar */
@@ -1344,7 +1360,7 @@ namespace System.Windows.Forms {
                }
 
                private int NextTimeout (ArrayList timers, DateTime now) {
-                       int timeout = Int32.MaxValue
+                       int timeout = 0
 
                        foreach (Timer timer in timers) {
                                int next = (int) (timer.Expires - now).TotalMilliseconds;
@@ -1378,9 +1394,11 @@ namespace System.Windows.Forms {
 
                                timer = (Timer) timers [i];
 
-                               if (timer.Enabled && timer.Expires <= now) {
+                               if (timer.Enabled && timer.Expires <= now && !timer.Busy) {
+                                       timer.Busy = true;
                                        timer.Update (now);
                                        timer.FireTick ();
+                                       timer.Busy = false;
                                }
                        }
                }
@@ -1420,10 +1438,12 @@ namespace System.Windows.Forms {
 
                private void MapWindow(Hwnd hwnd, WindowType windows) {
                        if (!hwnd.mapped) {
-                               if (Control.FromHandle(hwnd.Handle) is Form) {
-                                       Form f = Control.FromHandle(hwnd.Handle) as Form;
-                                       if (f.WindowState == FormWindowState.Normal)
+                               Form f = Control.FromHandle(hwnd.Handle) as Form;
+                               if (f != null) {
+                                       if (f.WindowState == FormWindowState.Normal) {
+                                               f.waiting_showwindow = true;
                                                SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
+                                       }
                                }
 
                                // it's possible that our Hwnd is no
@@ -1432,44 +1452,40 @@ namespace System.Windows.Forms {
                                if (hwnd.zombie)
                                        return;
 
-                               bool need_to_wait = false;
-
                                if ((windows & WindowType.Whole) != 0) {
                                        XMapWindow(DisplayHandle, hwnd.whole_window);
                                }
                                if ((windows & WindowType.Client) != 0) {
                                        XMapWindow(DisplayHandle, hwnd.client_window);
-
-                                       need_to_wait = true;
                                }
 
                                hwnd.mapped = true;
 
-                               if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
+                               if (f != null && f.waiting_showwindow)
                                        WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
                        }
                }
 
                private void UnmapWindow(Hwnd hwnd, WindowType windows) {
                        if (hwnd.mapped) {
+                               Form f = null;
                                if (Control.FromHandle(hwnd.Handle) is Form) {
-                                       Form f = Control.FromHandle(hwnd.Handle) as Form;
-                                       if (f.WindowState == FormWindowState.Normal)
+                                       f = Control.FromHandle(hwnd.Handle) as Form;
+                                       if (f.WindowState == FormWindowState.Normal) {
+                                               f.waiting_showwindow = true;
                                                SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
+                                       }
                                }
 
                                // it's possible that our Hwnd is no
                                // longer valid after making that
                                // SendMessage call, so check here.
+                               // FIXME: it is likely wrong, as it has already sent WM_SHOWWINDOW
                                if (hwnd.zombie)
                                        return;
 
-                               bool need_to_wait = false;
-
                                if ((windows & WindowType.Client) != 0) {
                                        XUnmapWindow(DisplayHandle, hwnd.client_window);
-
-                                       need_to_wait = true;
                                }
                                if ((windows & WindowType.Whole) != 0) {
                                        XUnmapWindow(DisplayHandle, hwnd.whole_window);
@@ -1477,7 +1493,7 @@ namespace System.Windows.Forms {
 
                                hwnd.mapped = false;
 
-                               if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
+                               if (f != null && f.waiting_showwindow)
                                        WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
                        }
                }
@@ -1551,11 +1567,18 @@ namespace System.Windows.Forms {
 
                                        XNextEvent (DisplayHandle, ref xevent);
 
-                                       if (xevent.AnyEvent.type == XEventName.KeyPress) {
-                                               if (XFilterEvent(ref xevent, FosterParent)) {
+                                       if (xevent.AnyEvent.type == XEventName.KeyPress ||
+                                           xevent.AnyEvent.type == XEventName.KeyRelease) {
+                                               // PreFilter() handles "shift key state updates.
+                                               Keyboard.PreFilter (xevent);
+                                               if (XFilterEvent (ref xevent, Keyboard.ClientWindow)) {
+                                                       // probably here we could raise WM_IME_KEYDOWN and
+                                                       // WM_IME_KEYUP, but I'm not sure it is worthy.
                                                        continue;
                                                }
                                        }
+                                       else if (XFilterEvent (ref xevent, IntPtr.Zero))
+                                               continue;
                                }
 
                                hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
@@ -1711,6 +1734,10 @@ namespace System.Windows.Forms {
                                }
 
                                case XEventName.KeyPress:
+                                       hwnd.Queue.EnqueueLocked (xevent);
+                                       /* Process KeyPresses immediately. Otherwise multiple Compose messages as a result of a
+                                        * single physical keypress are not processed correctly */
+                                       return;
                                case XEventName.ButtonPress:
                                case XEventName.ButtonRelease:
                                case XEventName.EnterNotify:
@@ -1762,7 +1789,7 @@ namespace System.Windows.Forms {
                                                                // Modality handling, if we are modal and the new active window is one
                                                                // of ours but not the modal one, switch back to the modal window
 
-                                                               if (NativeWindow.FindWindow(ActiveWindow) != null) {
+                                                               if (NativeWindow.FromHandle(ActiveWindow) != null) {
                                                                        if (ActiveWindow != (IntPtr)ModalWindows.Peek()) {
                                                                                Activate((IntPtr)ModalWindows.Peek());
                                                                        }
@@ -1774,6 +1801,7 @@ namespace System.Windows.Forms {
                                        else if (xevent.PropertyEvent.atom == _NET_WM_STATE) {
                                                // invalidate our cache - we'll query again the next time someone does GetWindowState.
                                                hwnd.cached_window_state = (FormWindowState)(-1);
+                                               PostMessage (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
                                        }
                                        break;
 
@@ -1925,10 +1953,10 @@ namespace System.Windows.Forms {
                        rect = TranslateClientRectangleToXClientRectangle (hwnd);
 
                        if (hwnd.visible) {
-                               XMoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
+                               MoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
                        }
 
-                       AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
+                       AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
                }
                #endregion      // Private Methods
 
@@ -1970,7 +1998,7 @@ namespace System.Windows.Forms {
 
                #region Public Properties
 
-               internal override int Caption {
+               internal override int CaptionHeight {
                        get {
                                return 19;
                        }
@@ -1999,7 +2027,7 @@ namespace System.Windows.Forms {
                        get {
                                return new Size(4, 4);
                        }
-               } 
+               }
 
                internal override  Size FrameBorderSize { 
                        get {
@@ -2096,13 +2124,13 @@ namespace System.Windows.Forms {
                        get {
                                return new Size (WorkingArea.Width, WorkingArea.Height);
                        }
-               } 
+               }
 
-               internal override  Size MinimizedWindowSize {
+               internal override bool MenuAccessKeysUnderlined {
                        get {
-                               return new Size(1, 1);
+                               return false;
                        }
-               } 
+               }
 
                internal override  Size MinimizedWindowSpacingSize {
                        get {
@@ -2112,16 +2140,22 @@ namespace System.Windows.Forms {
 
                internal override  Size MinimumWindowSize {
                        get {
-                               return new Size(1, 1);
+                               return new Size(110, 22);
                        }
                } 
 
-               internal override  Size MinWindowTrackSize {
-                       get {
-                               return new Size(1, 1);
-                       }
+               internal override Size MinimumFixedToolWindowSize {
+                       get { return new Size (27, 22); }
+               }
+
+               internal override Size MinimumSizeableToolWindowSize {
+                       get { return new Size (37, 22); }
                }
 
+               internal override Size MinimumNoBorderWindowSize {
+                       get { return new Size (2, 2); }
+               }
+               
                internal override Keys ModifierKeys {
                        get {
                                return Keyboard.ModifierKeys;
@@ -2311,6 +2345,12 @@ namespace System.Windows.Forms {
                #endregion      // Public properties
 
                #region Public Static Methods
+               internal override void RaiseIdle (EventArgs e)
+               {
+                       if (Idle != null)
+                               Idle (this, e);
+               }
+               
                internal override IntPtr InitializeDriver() {
                        lock (this) {
                                if (DisplayHandle==IntPtr.Zero) {
@@ -2343,6 +2383,16 @@ namespace System.Windows.Forms {
                                lock (XlibLock) {
                                        if (true /* the window manager supports NET_ACTIVE_WINDOW */) {
                                                SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
+                                               XEventQueue q = null;
+                                               lock (unattached_timer_list) {
+                                                       foreach (Timer t in unattached_timer_list) {
+                                                               if (q == null)
+                                                                       q= (XEventQueue) MessageQueues [Thread.CurrentThread];
+                                                               t.thread = q.Thread;
+                                                               q.timer_list.Add (t);
+                                                       }
+                                                       unattached_timer_list.Clear ();
+                                               }
                                        }
 //                                     else {
 //                                             XRaiseWindow(DisplayHandle, handle);
@@ -2559,41 +2609,11 @@ namespace System.Windows.Forms {
                        }
 
                        // Set the default location location for forms.
-                       Point previous, next;
-                       Rectangle within;
+                       Point next;
                        if (cp.control is Form) {
-                               if (parent_hwnd != null) {
-                                       previous = parent_hwnd.previous_child_startup_location;
-                                       within = parent_hwnd.client_rectangle;
-                               } else {
-                                       previous = Hwnd.previous_main_startup_location;
-                                       within = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
-                               }
-                               
-                               if (previous.X == int.MinValue || previous.Y == int.MinValue) {
-                                       next = Point.Empty;
-                               } else {
-                                       next = new Point (previous.X + 22, previous.Y + 22);
-                               }
-                               
-                               if (!within.Contains (next.X * 3, next.Y * 3)) {
-                                       next = Point.Empty;
-                               }
-                               
-                               if (next == Point.Empty && cp.Parent == IntPtr.Zero) {
-                                       next = new Point (22, 22);
-                               }
-                               
-                               if (parent_hwnd != null) {
-                                       parent_hwnd.previous_child_startup_location = next;
-                               } else {
-                                       Hwnd.previous_main_startup_location = next;
-                               }
-                               
-                               if (X == int.MinValue && Y == int.MinValue) {
-                                       X = next.X;
-                                       Y = next.Y;
-                               }
+                               next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd);
+                               X = next.X;
+                               Y = next.Y;
                        }
                        ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
 
@@ -2668,9 +2688,9 @@ namespace System.Windows.Forms {
                        }
 
                        lock (XlibLock) {
-                               XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask)));
+                               XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
                                if (hwnd.whole_window != hwnd.client_window)
-                                       XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask)));
+                                       XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | Keyboard.KeyEventMask)));
                        }
 
                        if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
@@ -3055,6 +3075,20 @@ namespace System.Windows.Forms {
 
                internal override IntPtr DefWndProc(ref Message msg) {
                        switch ((Msg)msg.Msg) {
+                               
+                               case Msg.WM_IME_COMPOSITION:
+                                       string s = Keyboard.GetCompositionString ();
+                                       foreach (char c in s)
+                                               SendMessage (msg.HWnd, Msg.WM_IME_CHAR, (IntPtr) c, msg.LParam);
+                                       return IntPtr.Zero;
+
+                               case Msg.WM_IME_CHAR:
+                                       // On Windows API it sends two WM_CHAR messages for each byte, but
+                                       // I wonder if it is worthy to emulate it (also no idea how to 
+                                       // reconstruct those bytes into chars).
+                                       SendMessage (msg.HWnd, Msg.WM_CHAR, msg.WParam, msg.LParam);
+                                       return IntPtr.Zero;
+
                                case Msg.WM_PAINT: {
                                        Hwnd hwnd;
 
@@ -3088,14 +3122,17 @@ namespace System.Windows.Forms {
 
                                                // Add all the stuff X is supposed to draw.
                                                Control ctrl = Control.FromHandle (hwnd.Handle);
-                                               Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null);
-                                               
-                                               ncp.rgrc1.top += rect.top;
-                                               ncp.rgrc1.bottom -= rect.bottom;
-                                               ncp.rgrc1.left += rect.left;
-                                               ncp.rgrc1.right -= rect.right;
                                                
-                                               Marshal.StructureToPtr (ncp, msg.LParam, true);
+                                               if (ctrl != null) {
+                                                       Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null);
+                                                       
+                                                       ncp.rgrc1.top += rect.top;
+                                                       ncp.rgrc1.bottom -= rect.bottom;
+                                                       ncp.rgrc1.left += rect.left;
+                                                       ncp.rgrc1.right -= rect.right;
+                                                       
+                                                       Marshal.StructureToPtr (ncp, msg.LParam, true);
+                                               }
                                        }
 
                                        return IntPtr.Zero;
@@ -3244,12 +3281,14 @@ namespace System.Windows.Forms {
                                        #if DriverDebug || DriverDebugDestroy
                                        Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32());
                                        #endif
+                                       Keyboard.DestroyICForWindow (hwnd.whole_window);
                                        XDestroyWindow(DisplayHandle, hwnd.whole_window);
                                }
                                else if (hwnd.client_window != IntPtr.Zero) {
                                        #if DriverDebug || DriverDebugDestroy
                                        Console.WriteLine ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32());
                                        #endif
+                                       Keyboard.DestroyICForWindow (hwnd.client_window);
                                        XDestroyWindow(DisplayHandle, hwnd.client_window);
                                }
 
@@ -3335,6 +3374,9 @@ namespace System.Windows.Forms {
 
                internal override void DrawReversibleLine(Point start, Point end, Color backColor)
                {
+                       if (backColor.GetBrightness() < 0.5)
+                               backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
                        IntPtr gc = GetReversibleScreenGC (backColor);
 
                        XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y);
@@ -3344,6 +3386,9 @@ namespace System.Windows.Forms {
 
                internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
                {
+                       if (backColor.GetBrightness() < 0.5)
+                               backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
                        IntPtr gc = GetReversibleScreenGC (backColor);
 
                        if (rectangle.Width < 0) {
@@ -3378,6 +3423,9 @@ namespace System.Windows.Forms {
 
                internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor) 
                {
+                       if (backColor.GetBrightness() < 0.5)
+                               backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
                        IntPtr gc = GetReversibleScreenGC (backColor);
 
                        if (rectangle.Width < 0) {
@@ -3393,7 +3441,8 @@ namespace System.Windows.Forms {
                        XFreeGC(DisplayHandle, gc);
                }
 
-               internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) {
+               internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width)
+               {
                        IntPtr          gc;
                        Control control = Control.FromHandle(handle);
 
@@ -3521,6 +3570,11 @@ namespace System.Windows.Forms {
                        }
                        return IntPtr.Zero;
                }
+               
+               // This is a nop on win32 and x11
+               internal override IntPtr GetPreviousWindow(IntPtr handle) {
+                       return handle;
+               }
 
                internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
                        IntPtr  use_handle;
@@ -3615,7 +3669,7 @@ namespace System.Windows.Forms {
                        // hwnds, since much of the event handling code makes requests using the hwnd's
                        // client_window, and that'll result in BadWindow errors if there's some lag
                        // between the XDestroyWindow call and the DestroyNotify event.
-                       if (hwnd == null || hwnd.zombie) {
+                       if (hwnd == null || hwnd.zombie && xevent.AnyEvent.type != XEventName.ClientMessage) {
                                #if DriverDebug || DriverDebugDestroy
                                        Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
                                #endif
@@ -3632,14 +3686,39 @@ namespace System.Windows.Forms {
 
                        msg.hwnd = hwnd.Handle;
 
+                       // Windows sends WM_ENTERSIZEMOVE when a form resize/move operation starts and WM_EXITSIZEMOVE 
+                       // when it is done. The problem in X11 is that there is no concept of start-end of a moving/sizing.
+                       // Configure events ("this window has resized/moved") are sent for each step of the resize. We send a
+                       // WM_ENTERSIZEMOVE when we get the first Configure event. The problem is the WM_EXITSIZEMOVE.
+                       // 
+                       //  - There is no way for us to know which is the last Configure event. We can't traverse the events 
+                       //    queue, because the next configure event might not be pending yet.
+                       //  - We can't get ButtonPress/Release events for the window decorations, because they are not part 
+                       //    of the window(s) we manage.
+                       //  - We can't rely on the mouse state to change to "up" before the last Configure event. It doesn't.
+                       // 
+                       // We are almost 100% guaranteed to get another event (e.g Expose or other), but we can't know for sure 
+                       // which, so we have here to check if the mouse buttons state is "up" and send the WM_EXITSIZEMOVE
+                       //
+                       if (hwnd.resizing_or_moving) {
+                               int root_x, root_y, win_x, win_y, keys_buttons;
+                               IntPtr  root, child;
+                               XQueryPointer (DisplayHandle, hwnd.Handle, out root, out child, out root_x, out root_y, 
+                                              out win_x, out win_y, out keys_buttons);
+                               if ((keys_buttons & (int)MouseKeyMasks.Button1Mask) == 0 &&
+                                   (keys_buttons & (int)MouseKeyMasks.Button2Mask) == 0 &&
+                                   (keys_buttons & (int)MouseKeyMasks.Button3Mask) == 0) {
+                                       hwnd.resizing_or_moving = false;
+                                       SendMessage (hwnd.Handle, Msg.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
+                               }
+                       }
+
                        //
                        // If you add a new event to this switch make sure to add it in
                        // UpdateMessage also unless it is not coming through the X event system.
                        //
                        switch(xevent.type) {
                                case XEventName.KeyPress: {
-                                       if (Dnd.InDrag ())
-                                               Dnd.HandleKeyPress (ref xevent);
                                        Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
                                        break;
                                }
@@ -3655,12 +3734,12 @@ namespace System.Windows.Forms {
                                                        MouseState |= MouseButtons.Left;
                                                        if (client) {
                                                                msg.message = Msg.WM_LBUTTONDOWN;
+                                                               msg.wParam = GetMousewParam (0);
                                                        } else {
                                                                msg.message = Msg.WM_NCLBUTTONDOWN;
+                                                               msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                                MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
                                                        }
-                                                       // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
-                                                       msg.wParam=GetMousewParam(0);
                                                        break;
                                                }
 
@@ -3668,11 +3747,12 @@ namespace System.Windows.Forms {
                                                        MouseState |= MouseButtons.Middle;
                                                        if (client) {
                                                                msg.message = Msg.WM_MBUTTONDOWN;
+                                                               msg.wParam = GetMousewParam (0);
                                                        } else {
                                                                msg.message = Msg.WM_NCMBUTTONDOWN;
+                                                               msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                                MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
                                                        }
-                                                       msg.wParam=GetMousewParam(0);
                                                        break;
                                                }
 
@@ -3680,11 +3760,12 @@ namespace System.Windows.Forms {
                                                        MouseState |= MouseButtons.Right;
                                                        if (client) {
                                                                msg.message = Msg.WM_RBUTTONDOWN;
+                                                               msg.wParam = GetMousewParam (0);
                                                        } else {
                                                                msg.message = Msg.WM_NCRBUTTONDOWN;
+                                                               msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                                MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
                                                        }
-                                                       msg.wParam=GetMousewParam(0);
                                                        break;
                                                }
 
@@ -3767,23 +3848,17 @@ namespace System.Windows.Forms {
                                }
 
                                case XEventName.ButtonRelease: {
-                                       if (Dnd.InDrag()) {
-                                               if (Dnd.HandleButtonRelease (ref xevent)) {
-                                                       break;
-                                               }
-                                               // Allow the LBUTTONUP message to get through
-                                       }
-
                                        switch(xevent.ButtonEvent.button) {
                                                case 1: {
                                                        if (client) {
                                                                msg.message = Msg.WM_LBUTTONUP;
                                                        } else {
                                                                msg.message = Msg.WM_NCLBUTTONUP;
+                                                               msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                                MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
                                                        }
                                                        MouseState &= ~MouseButtons.Left;
-                                                       msg.wParam=GetMousewParam(0);
+                                                       msg.wParam = GetMousewParam (0);
                                                        break;
                                                }
 
@@ -3792,10 +3867,11 @@ namespace System.Windows.Forms {
                                                                msg.message = Msg.WM_MBUTTONUP;
                                                        } else {
                                                                msg.message = Msg.WM_NCMBUTTONUP;
+                                                               msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                                MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
                                                        }
                                                        MouseState &= ~MouseButtons.Middle;
-                                                       msg.wParam=GetMousewParam(0);
+                                                       msg.wParam = GetMousewParam (0);
                                                        break;
                                                }
 
@@ -3804,10 +3880,11 @@ namespace System.Windows.Forms {
                                                                msg.message = Msg.WM_RBUTTONUP;
                                                        } else {
                                                                msg.message = Msg.WM_NCRBUTTONUP;
+                                                               msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                                MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
                                                        }
                                                        MouseState &= ~MouseButtons.Right;
-                                                       msg.wParam=GetMousewParam(0);
+                                                       msg.wParam = GetMousewParam (0);
                                                        break;
                                                }
 
@@ -3857,8 +3934,6 @@ namespace System.Windows.Forms {
                                                        Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                #endif
 
-                                               if (Dnd.HandleMotionNotify (ref xevent))
-                                                       goto ProcessNextMessage;
                                                if (Grab.Hwnd != IntPtr.Zero) {
                                                        msg.hwnd = Grab.Hwnd;
                                                } else {
@@ -3867,6 +3942,18 @@ namespace System.Windows.Forms {
                                                        }
                                                }
 
+                                               if (xevent.MotionEvent.is_hint != 0)
+                                               {
+                                                       IntPtr root, child;
+                                                       int mask;
+                                                       XQueryPointer (DisplayHandle, xevent.AnyEvent.window,
+                                                                                       out root, out child,
+                                                                                       out xevent.MotionEvent.x_root, 
+                                                                                       out xevent.MotionEvent.y_root,
+                                                                                       out xevent.MotionEvent.x,      
+                                                                                       out xevent.MotionEvent.y, out mask);
+                                               }
+
                                                msg.message = Msg.WM_MOUSEMOVE;
                                                msg.wParam = GetMousewParam(0);
                                                msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
@@ -3911,14 +3998,7 @@ namespace System.Windows.Forms {
                                                        msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
                                                }
 
-                                               // The hit test is sent in screen coordinates
-                                               XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, RootWindow,
-                                                               xevent.MotionEvent.x, xevent.MotionEvent.y,
-                                                               out screen_x, out screen_y, out dummy);
-
-                                               msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF);
-                                               ht = (HitTest)NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST,
-                                                               IntPtr.Zero, msg.lParam).ToInt32 ();
+                                               ht = NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
                                                NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
 
                                                mouse_position.X = xevent.MotionEvent.x;
@@ -3932,14 +4012,38 @@ namespace System.Windows.Forms {
                                        if (!hwnd.Enabled) {
                                                goto ProcessNextMessage;
                                        }
-                                       if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
+                                       if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || LastPointerWindow == xevent.CrossingEvent.window ||
+                                                       hwnd.client_window == IntPtr.Zero) {
                                                goto ProcessNextMessage;
                                        }
+                                       if (LastPointerWindow != IntPtr.Zero) {
+                                               Point enter_loc = new Point (xevent.ButtonEvent.x, xevent.ButtonEvent.y);
+
+                                               // We need this due to EnterNotify being fired on all the parent controls
+                                               // of the Control being grabbed, and obviously in that scenario we are not
+                                               // actuallty entering them
+                                               Control ctrl = Control.FromHandle (hwnd.client_window);
+                                               foreach (Control child_control in ctrl.Controls)
+                                                       if (child_control.Bounds.Contains (enter_loc))
+                                                               goto ProcessNextMessage;
+                                       }
+
+                                       LastPointerWindow = xevent.AnyEvent.window;
+
                                        msg.message = Msg.WM_MOUSE_ENTER;
                                        HoverState.X = xevent.CrossingEvent.x;
                                        HoverState.Y = xevent.CrossingEvent.y;
                                        HoverState.Timer.Enabled = true;
                                        HoverState.Window = xevent.CrossingEvent.window;
+
+                                       // Win32 sends a WM_MOUSEMOVE after mouse enter
+                                       XEvent motionEvent = new XEvent ();
+                                       motionEvent.type = XEventName.MotionNotify;
+                                       motionEvent.MotionEvent.display = DisplayHandle;
+                                       motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
+                                       motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
+                                       motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
+                                       hwnd.Queue.EnqueueLocked (motionEvent);
                                        break;
                                }
 
@@ -3954,6 +4058,14 @@ namespace System.Windows.Forms {
                                        if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
                                                goto ProcessNextMessage;
                                        }
+
+                                       // Reset the cursor explicitly on X11.
+                                       // X11 remembers the last set cursor for the window and in cases where 
+                                       // the control won't get a WM_SETCURSOR X11 will restore the last 
+                                       // known cursor, which we don't want.
+                                       // 
+                                       SetCursor (hwnd.client_window, IntPtr.Zero);
+
                                        msg.message=Msg.WM_MOUSELEAVE;
                                        HoverState.Timer.Enabled = false;
                                        HoverState.Window = IntPtr.Zero;
@@ -4005,16 +4117,28 @@ namespace System.Windows.Forms {
                                                #if DriverDebugExtra
                                                        Console.WriteLine("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}", hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
                                                #endif
-//                                             if ((hwnd.x != xevent.ConfigureEvent.x) || (hwnd.y != xevent.ConfigureEvent.y) || (hwnd.width != xevent.ConfigureEvent.width) || (hwnd.height != xevent.ConfigureEvent.height)) {
-                                                       lock (hwnd.configure_lock) {
-                                                               SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
-                                                               hwnd.configure_pending = false;
-                                                       }
 
+                                               lock (hwnd.configure_lock) {
+                                                       Form form = Control.FromHandle (hwnd.client_window) as Form;
+                                                       if (form != null && !hwnd.resizing_or_moving) {
+                                                               if (hwnd.x != form.Bounds.X || hwnd.y != form.Bounds.Y) {
+                                                                       SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_MOVE, IntPtr.Zero);
+                                                                       hwnd.resizing_or_moving = true;
+                                                               } else if (hwnd.width != form.Bounds.Width || hwnd.height != form.Bounds.Height) {
+                                                                       SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_SIZE, IntPtr.Zero);
+                                                                       hwnd.resizing_or_moving = true;
+                                                               }
+                                                               if (hwnd.resizing_or_moving)
+                                                                       SendMessage (form.Handle, Msg.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
+                                                       }
+       
+                                                       SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
+                                                       hwnd.configure_pending = false;
+       
                                                        // We need to adjust our client window to track the resize of whole_window
                                                        if (hwnd.whole_window != hwnd.client_window)
                                                                PerformNCCalc(hwnd);
-//                                             }
+                                               }
                                        }
                                        goto ProcessNextMessage;
                                }
@@ -4041,8 +4165,8 @@ namespace System.Windows.Forms {
                                                }
                                                goto ProcessNextMessage;
                                        }
-                                       Keyboard.FocusIn(FocusWindow);
                                        SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
+                                       Keyboard.FocusIn (FocusWindow);
                                        goto ProcessNextMessage;
                                }
 
@@ -4051,12 +4175,12 @@ namespace System.Windows.Forms {
                                        if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
                                                goto ProcessNextMessage;
                                        }
-                                       Keyboard.FocusOut(FocusWindow);
 
                                        while (Keyboard.ResetKeyState(FocusWindow, ref msg)) {
                                                SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam);
                                        }
 
+                                       Keyboard.FocusOut(hwnd.client_window);
                                        SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
                                        goto ProcessNextMessage;
                                }
@@ -4223,6 +4347,7 @@ namespace System.Windows.Forms {
 
                                        if  (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) {
                                                if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) {
+                                                       SendMessage (msg.hwnd, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_CLOSE, IntPtr.Zero);
                                                        msg.message = Msg.WM_CLOSE;
                                                        return true;
                                                }
@@ -4243,6 +4368,16 @@ namespace System.Windows.Forms {
                        return true;
                }
 
+               private HitTest NCHitTest (Hwnd hwnd, int x, int y)
+               {
+                       // The hit test is sent in screen coordinates
+                       IntPtr dummy;
+                       int screen_x, screen_y;
+                       XTranslateCoordinates (DisplayHandle, hwnd.WholeWindow, RootWindow, x, y, out screen_x, out screen_y, out dummy);
+                       return (HitTest) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, 
+                                                              (IntPtr) (screen_y << 16 | screen_x & 0xFFFF));
+               }
+
                internal override bool GetText(IntPtr handle, out string text) {
 
                        lock (XlibLock) {
@@ -4402,7 +4537,7 @@ namespace System.Windows.Forms {
                                XGrabPointer(DisplayHandle, hwnd.client_window, false, 
                                        EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
                                        EventMask.ButtonReleaseMask | EventMask.PointerMotionMask | 
-                                       EventMask.LeaveWindowMask,
+                                       EventMask.PointerMotionHintMask | EventMask.LeaveWindowMask,
                                        GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
                        }
                }
@@ -4455,7 +4590,7 @@ namespace System.Windows.Forms {
 
                        hwnd = Hwnd.ObjectFromHandle(handle);
 
-                       AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
+                       AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
                }
 
                internal override bool IsEnabled(IntPtr handle) {
@@ -4473,7 +4608,12 @@ namespace System.Windows.Forms {
 
                        if (queue == null) {
                                // This isn't really an error, MS doesn't start the timer if
-                               // it has no assosciated queue
+                               // it has no assosciated queue. In this case, remove the timer
+                               // from the list of unattached timers (if it was enabled).
+                               lock (unattached_timer_list) {
+                                       if (unattached_timer_list.Contains (timer))
+                                               unattached_timer_list.Remove (timer);
+                               }
                                return;
                        }
                        queue.timer_list.Remove (timer);
@@ -4501,6 +4641,7 @@ namespace System.Windows.Forms {
                                XChangeActivePointerGrab (DisplayHandle,
                                                EventMask.ButtonMotionMask |
                                                EventMask.PointerMotionMask |
+                                               EventMask.PointerMotionHintMask |
                                                EventMask.ButtonPressMask |
                                                EventMask.ButtonReleaseMask,
                                                cursor, IntPtr.Zero);
@@ -4510,12 +4651,23 @@ namespace System.Windows.Forms {
                        OverrideCursorHandle = cursor;
                }
 
-               internal override PaintEventArgs PaintEventStart(IntPtr handle, bool client) {
+               internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) {
                        PaintEventArgs  paint_event;
                        Hwnd            hwnd;
-
-                       hwnd = Hwnd.ObjectFromHandle(handle);
-
+                       Hwnd            paint_hwnd;
+                       
+                       // 
+                       // handle  (and paint_hwnd) refers to the window that is should be painted.
+                       // msg.HWnd (and hwnd) refers to the window that got the paint message.
+                       // 
+                       
+                       hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
+                       if (msg.HWnd == handle) {
+                               paint_hwnd = hwnd;
+                       } else {
+                               paint_hwnd = Hwnd.ObjectFromHandle (handle);
+                       }
+       
                        if (Caret.Visible == true) {
                                Caret.Paused = true;
                                HideCaret();
@@ -4524,7 +4676,7 @@ namespace System.Windows.Forms {
                        Graphics dc;
 
                        if (client) {
-                               dc = Graphics.FromHwnd (hwnd.client_window);
+                               dc = Graphics.FromHwnd (paint_hwnd.client_window);
 
                                Region clip_region = new Region ();
                                clip_region.MakeEmpty();
@@ -4548,7 +4700,7 @@ namespace System.Windows.Forms {
 
                                return paint_event;
                        } else {
-                               dc = Graphics.FromHwnd (hwnd.whole_window);
+                               dc = Graphics.FromHwnd (paint_hwnd.whole_window);
 
                                if (!hwnd.nc_invalid.IsEmpty) {
                                        dc.SetClip (hwnd.nc_invalid);
@@ -4567,10 +4719,10 @@ namespace System.Windows.Forms {
                        }
                }
 
-               internal override void PaintEventEnd(IntPtr handle, bool client) {
+               internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) {
                        Hwnd    hwnd;
 
-                       hwnd = Hwnd.ObjectFromHandle(handle);
+                       hwnd = Hwnd.ObjectFromHandle (msg.HWnd);
 
                        Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
                        dc.Flush();
@@ -4637,13 +4789,21 @@ namespace System.Windows.Forms {
                        xevent.ClientMessageEvent.ptr3 = wparam;
                        xevent.ClientMessageEvent.ptr4 = lparam;
 
-                       hwnd.Queue.EnqueueLocked (xevent);
+                       if (hwnd != null)
+                               hwnd.Queue.EnqueueLocked (xevent);
+                       else
+                               ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent);
 
                        return true;
                }
 
                internal override void PostQuitMessage(int exitCode) {
-                       PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+                       ApplicationContext ctx = Application.MWFThread.Current.Context;
+                       Form f = ctx != null ? ctx.MainForm : null;
+                       if (f != null)
+                               PostMessage (Application.MWFThread.Current.Context.MainForm.window.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+                       else
+                               PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
                        XFlush(DisplayHandle);
                }
 
@@ -4718,6 +4878,33 @@ namespace System.Windows.Forms {
                        y = dest_y_return;
                }
 
+               bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg)
+               {
+                       return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) &&
+                               arg == xevent.GraphicsExposeEvent.drawable;
+               }
+
+               delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg);
+
+               void ProcessGraphicsExpose (Hwnd hwnd)
+               {
+                       XEvent xevent = new XEvent ();
+                       IntPtr handle = Hwnd.HandleFromObject (hwnd);
+                       EventPredicate predicate = GraphicsExposePredicate;
+
+                       for (;;) {
+                               XIfEvent (Display, ref xevent, predicate, handle);
+                               if (xevent.type != XEventName.GraphicsExpose)
+                                       break;
+
+                               AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y,
+                                               xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height);
+
+                               if (xevent.GraphicsExposeEvent.count == 0)
+                                       break;
+                       }
+               }
+
                internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
                        Hwnd            hwnd;
                        IntPtr          gc;
@@ -4756,48 +4943,23 @@ namespace System.Windows.Forms {
 
                        gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
 
-                       int src_x, src_y;
-                       int dest_x, dest_y;
-                       int width, height;
+                       Rectangle visible_rect = GetTotalVisibleArea (hwnd.client_window);
+                       visible_rect.Intersect (area);
 
-                       if (YAmount > 0) {
-                               src_y = area.Y;
-                               height = area.Height - YAmount;
-                               dest_y = area.Y + YAmount;
-                       }
-                       else {
-                               src_y = area.Y - YAmount;
-                               height = area.Height + YAmount;
-                               dest_y = area.Y;
-                       }
+                       Rectangle dest_rect = visible_rect;
+                       dest_rect.Y += YAmount;
+                       dest_rect.X += XAmount;
+                       dest_rect.Intersect (area);
 
-                       if (XAmount > 0) {
-                               src_x = area.X;
-                               width = area.Width - XAmount;
-                               dest_x = area.X + XAmount;
-                       }
-                       else {
-                               src_x = area.X - XAmount;
-                               width = area.Width + XAmount;
-                               dest_x = area.X;
-                       }
+                       Point src = new Point (dest_rect.X - XAmount, dest_rect.Y - YAmount);
+                       XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src.X, src.Y, 
+                                       dest_rect.Width, dest_rect.Height, dest_rect.X, dest_rect.Y);
 
-                       XCopyArea(DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src_x, src_y, width, height, dest_x, dest_y);
+                       Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount);
+                       AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height);
 
-                       // Generate an expose for the area exposed by the horizontal scroll
-                       // We don't use AddExpose since we're 
-                       if (XAmount > 0) {
-                               AddExpose(hwnd, true, area.X, area.Y, XAmount, area.Height);
-                       } else if (XAmount < 0) {
-                               AddExpose(hwnd, true, XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
-                       }
+                       ProcessGraphicsExpose (hwnd);
 
-                       // Generate an expose for the area exposed by the vertical scroll
-                       if (YAmount > 0) {
-                               AddExpose(hwnd, true, area.X, area.Y, area.Width, YAmount);
-                       } else if (YAmount < 0) {
-                               AddExpose(hwnd, true, area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
-                       }
                        XFreeGC(DisplayHandle, gc);
                }
 
@@ -4813,6 +4975,48 @@ namespace System.Windows.Forms {
                        ScrollWindow(handle, rect, XAmount, YAmount, with_children);
                }
 
+               Rectangle GetDirtyArea (Rectangle total_area, Rectangle valid_area, int XAmount, int YAmount)
+               {
+                       Rectangle dirty_area = total_area;
+
+                       if (YAmount > 0)
+                               dirty_area.Height -= valid_area.Height;
+                       else if (YAmount < 0) {
+                               dirty_area.Height -= valid_area.Height;
+                               dirty_area.Y += valid_area.Height;
+                       }
+
+                       if (XAmount > 0)
+                               dirty_area.Width -= valid_area.Width;
+                       else if (XAmount < 0) {
+                               dirty_area.Width -= valid_area.Width;
+                               dirty_area.X += valid_area.Width;
+                       }
+
+                       return dirty_area;
+               }
+
+               Rectangle GetTotalVisibleArea (IntPtr handle)
+               {
+                       Control c = Control.FromHandle (handle);
+
+                       Rectangle visible_area = c.ClientRectangle;
+                       visible_area.Location = c.PointToScreen (Point.Empty);
+
+                       for (Control parent = c.Parent; parent != null; parent = parent.Parent) {
+                               if (!parent.IsHandleCreated || !parent.Visible)
+                                       return visible_area; // Non visible, not need to finish computations
+
+                               Rectangle r = parent.ClientRectangle;
+                               r.Location = parent.PointToScreen (Point.Empty);
+
+                               visible_area.Intersect (r);
+                       }
+
+                       visible_area.Location = c.PointToClient (visible_area.Location);
+                       return visible_area;
+               }
+
                internal override void SendAsyncMethod (AsyncMethodData method) {
                        Hwnd    hwnd;
                        XEvent  xevent = new XEvent ();
@@ -4907,9 +5111,13 @@ namespace System.Windows.Forms {
 
                internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
                        Form form = Control.FromHandle (handle) as Form;
-                       if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow ||
-                                       border_style == FormBorderStyle.SizableToolWindow)) {
-                               form.window_manager = new ToolWindowManager (form);
+                       if (form != null && form.window_manager == null) {
+                               CreateParams cp = form.GetCreateParams ();
+                               if (border_style == FormBorderStyle.FixedToolWindow ||
+                                    border_style == FormBorderStyle.SizableToolWindow || 
+                                    cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
+                                       form.window_manager = new ToolWindowManager (form);
+                               }
                        }
                        
                        RequestNCRecalc(handle);
@@ -4923,6 +5131,8 @@ namespace System.Windows.Forms {
                                Caret.X = x;
                                Caret.Y = y;
 
+                               Keyboard.SetCaretPos (Caret, handle, x, y);
+
                                if (Caret.Visible == true) {
                                        ShowCaret();
                                        Caret.Timer.Start();
@@ -5081,6 +5291,10 @@ namespace System.Windows.Forms {
                                return;
                        }
 
+                       // Win32 doesn't do anything if disabled
+                       if (!hwnd.enabled)
+                               return;
+
                        prev_focus_window = FocusWindow;
                        FocusWindow = hwnd.client_window;
 
@@ -5088,6 +5302,7 @@ namespace System.Windows.Forms {
                                SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
                        }
                        SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
+                       Keyboard.FocusIn (FocusWindow);
 
                        //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
                }
@@ -5148,7 +5363,9 @@ namespace System.Windows.Forms {
 
                        if (queue == null) {
                                // This isn't really an error, MS doesn't start the timer if
-                               // it has no assosciated queue
+                               // it has no assosciated queue at this stage (it will be
+                               // enabled when a window is activated).
+                               unattached_timer_list.Add (timer);
                                return;
                        }
                        queue.timer_list.Add (timer);
@@ -5250,12 +5467,15 @@ namespace System.Windows.Forms {
                                return;
                        }
 
+                       min.Width = Math.Max (min.Width, SystemInformation.MinimumWindowSize.Width);
+                       min.Height = Math.Max (min.Height, SystemInformation.MinimumWindowSize.Height);
+                       
                        hints = new XSizeHints();
 
                        XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
                        if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
                                if (cp != null)
-                                       min = TranslateWindowSizeToXWindowSize (cp);
+                                       min = TranslateWindowSizeToXWindowSize (cp, min);
                                hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
                                hints.min_width = min.Width;
                                hints.min_height = min.Height;
@@ -5263,7 +5483,7 @@ namespace System.Windows.Forms {
 
                        if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
                                if (cp != null)
-                                       max = TranslateWindowSizeToXWindowSize (cp);
+                                       max = TranslateWindowSizeToXWindowSize (cp, max);
                                hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
                                hints.max_width = max.Width;
                                hints.max_height = max.Height;
@@ -5339,8 +5559,8 @@ namespace System.Windows.Forms {
 
                                lock (XlibLock) {
                                        Control ctrl = Control.FromHandle (handle);
-                                       Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams ());
-                                       XMoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
+                                       Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams (), new Size (width, height));
+                                       MoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
                                        PerformNCCalc(hwnd);
                                }
                        }
@@ -5516,18 +5736,19 @@ namespace System.Windows.Forms {
 
                                // Oh boy.
                                if (hwnd.client_window != hwnd.whole_window) {
+                                       Keyboard.DestroyICForWindow (hwnd.client_window);
                                        XDestroyWindow(DisplayHandle, hwnd.client_window);
                                        hwnd.client_window = hwnd.whole_window;
+                               }       
 
-                                       /* by virtue of the way the tests are ordered when determining if it's PAINT
-                                          or NCPAINT, client_window == whole_window will always be PAINT.  So, if we're
-                                          waiting on an nc_expose, drop it and remove the hwnd from the list (unless
-                                          there's a pending expose). */
-                                       if (hwnd.nc_expose_pending) {
-                                               hwnd.nc_expose_pending = false;
-                                               if (!hwnd.expose_pending)
-                                                       hwnd.Queue.Paint.Remove (hwnd);
-                                       }
+                               /* by virtue of the way the tests are ordered when determining if it's PAINT
+                                  or NCPAINT, client_window == whole_window will always be PAINT.  So, if we're
+                                  waiting on an nc_expose, drop it and remove the hwnd from the list (unless
+                                  there's a pending expose). */
+                               if (hwnd.nc_expose_pending) {
+                                       hwnd.nc_expose_pending = false;
+                                       if (!hwnd.expose_pending)
+                                               hwnd.Queue.Paint.Remove (hwnd);
                                }
 
                                size_hints = new XSizeHints();
@@ -5579,6 +5800,7 @@ namespace System.Windows.Forms {
                        if (control != null && tt != null) {
                                tt.SetToolTip(control, tip);
                                tt.Active = true;
+                               SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
                                return true;
                        } else {
                                return false;
@@ -5587,29 +5809,7 @@ namespace System.Windows.Forms {
 
                internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
 
-#if GTKSOCKET_SUPPORTS_REPARENTING
-                       Hwnd    hwnd;
-
-                       hwnd = Hwnd.ObjectFromHandle(handle);
-
-                       /* in the XEMBED spec, it mentions 3 ways for a client window to break the protocol with the embedder.
-                        * 1. The embedder can unmap the window and reparent to the root window (we should probably handle this...)
-                        * 2. The client can reparent its window out of the embedder window.
-                        * 3. The client can destroy its window.
-                        *
-                        * this call to SetParent is case 2, but in
-                        * the spec it also mentions that gtk doesn't
-                        * support this at present.  Looking at HEAD
-                        * gtksocket-x11.c jives with this statement.
-                        *
-                        * so we can't reparent.  we have to destroy.
-                        */
-                       SetParent(hwnd.whole_window, FosterParent);
-#else
-                       Control control = Control.FromHandle(handle);
-                       if (control is NotifyIcon.NotifyIconWindow)
-                               ((NotifyIcon.NotifyIconWindow)control).InternalRecreateHandle ();
-#endif
+                       SetVisible (handle, false, false);
 
                        // The caller can now re-dock it later...
                        if (tt != null) {
@@ -5772,7 +5972,14 @@ namespace System.Windows.Forms {
                [DllImport ("libX11", EntryPoint="XReparentWindow")]
                internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
                [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
-               internal extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+               private extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+
+               internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height)
+               {
+                       int ret = XMoveResizeWindow (display, window, x, y, width, height);
+                       Keyboard.MoveCurrentCaretPos ();
+                       return ret;
+               }
 
                [DllImport ("libX11", EntryPoint="XResizeWindow")]
                internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
@@ -6042,6 +6249,9 @@ namespace System.Windows.Forms {
 
                [DllImport ("libX11")]
                internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
+
+               [DllImport ("libX11")]
+               internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);
                #endregion
        }
 }