diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d
index 13966928..97165a2b 100644
--- a/src/dlangui/platforms/common/platform.d
+++ b/src/dlangui/platforms/common/platform.d
@@ -113,7 +113,17 @@ class Window {
     protected Widget _mouseTrackingWidget;
     /// widget which tracks all events after processed ButtonDown
     protected Widget _mouseCaptureWidget;
+	protected ushort _mouseCaptureButtons;
     protected bool _mouseCaptureFocusedOut;
+	
+	protected bool dispatchCancel(MouseEvent event) {
+    	event.changeAction(MouseAction.Cancel);
+        bool res = _mouseCaptureWidget.onMouseEvent(event);
+		_mouseCaptureWidget = null;
+		_mouseCaptureFocusedOut = false;
+		return res;
+	}
+	
     /// dispatch mouse event to window content widgets
     bool dispatchMouseEvent(MouseEvent event) {
         // ignore events if there is no root
@@ -127,23 +137,29 @@ class Window {
             _mouseTrackingWidget = null;
 
         bool res = false;
+		ushort currentButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton);
         if (_mouseCaptureWidget !is null) {
             // try to forward message directly to active widget
             if (event.action == MouseAction.Move) {
                 if (!_mouseCaptureWidget.isPointInside(event.x, event.y)) {
+					if (currentButtons != _mouseCaptureButtons)
+						return dispatchCancel(event);
                     // point is no more inside of captured widget
                     if (!_mouseCaptureFocusedOut) {
                         // sending FocusOut message
                         event.changeAction(MouseAction.FocusOut);
                         _mouseCaptureFocusedOut = true;
+						_mouseCaptureButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton);
                         return _mouseCaptureWidget.onMouseEvent(event);
                     }
                     return true;
                 } else {
                     // point is inside widget
                     if (_mouseCaptureFocusedOut) {
-                        event.changeAction(MouseAction.FocusIn); // back in after focus out
                         _mouseCaptureFocusedOut = false;
+						if (currentButtons != _mouseCaptureButtons)
+							return dispatchCancel(event);
+                       	event.changeAction(MouseAction.FocusIn); // back in after focus out
                     }
                     return _mouseCaptureWidget.onMouseEvent(event);
                 }
@@ -152,6 +168,7 @@ class Window {
                     // sending FocusOut message
                     event.changeAction(MouseAction.FocusOut);
                     _mouseCaptureFocusedOut = true;
+					_mouseCaptureButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton);
                     return _mouseCaptureWidget.onMouseEvent(event);
                 }
                 return true;
diff --git a/src/dlangui/platforms/x11/x11app.d b/src/dlangui/platforms/x11/x11app.d
index 813749f2..b409bdf3 100644
--- a/src/dlangui/platforms/x11/x11app.d
+++ b/src/dlangui/platforms/x11/x11app.d
@@ -34,24 +34,6 @@ version(linux) {
 			Log.d("Destroying window");
 		}
 			
-		/// request window redraw
-		override void invalidate() {
-			
-			xcb_expose_event_t * event = cast(xcb_expose_event_t*)std.c.stdlib.malloc(xcb_expose_event_t.sizeof);
-		    event.response_type = XCB_EXPOSE; /* The type of the event, here it is XCB_EXPOSE */
-		    event.sequence = 0;
-		    event.window = _w;        /* The Id of the window that receives the event (in case */
-		                                    /* our application registered for events on several windows */
-		    event.x = 0;             /* The x coordinate of the top-left part of the window that needs to be redrawn */
-		    event.y = 0;             /* The y coordinate of the top-left part of the window that needs to be redrawn */
-		    event.width = cast(ushort)_dx;         /* The width of the part of the window that needs to be redrawn */
-		    event.height = cast(ushort)_dy;        /* The height of the part of the window that needs to be redrawn */
-		    event.count = 1;
-
-			xcb_void_cookie_t res = xcb_send_event(_xcbconnection, false, _w, XCB_EVENT_MASK_EXPOSURE, cast(char *)event);
-		  	xcb_flush(_xcbconnection);
-		}
-
 		bool create() {
 			uint mask;
 			uint values[2];
@@ -209,10 +191,32 @@ version(linux) {
 		}
 		
 		ColorDrawBuf _drawbuf;
+		bool _exposeSent;
 		void processExpose(xcb_expose_event_t * event) {
 			redraw();
+			_exposeSent = false;
 		}
-		
+
+		/// request window redraw
+		override void invalidate() {
+			if (_exposeSent)
+				return;
+			_exposeSent = true;
+			xcb_expose_event_t * event = cast(xcb_expose_event_t*)std.c.stdlib.malloc(xcb_expose_event_t.sizeof);
+		    event.response_type = XCB_EXPOSE; /* The type of the event, here it is XCB_EXPOSE */
+		    event.sequence = 0;
+		    event.window = _w;        /* The Id of the window that receives the event (in case */
+		                                    /* our application registered for events on several windows */
+		    event.x = 0;             /* The x coordinate of the top-left part of the window that needs to be redrawn */
+		    event.y = 0;             /* The y coordinate of the top-left part of the window that needs to be redrawn */
+		    event.width = cast(ushort)_dx;         /* The width of the part of the window that needs to be redrawn */
+		    event.height = cast(ushort)_dy;        /* The height of the part of the window that needs to be redrawn */
+		    event.count = 1;
+
+			xcb_void_cookie_t res = xcb_send_event(_xcbconnection, false, _w, XCB_EVENT_MASK_EXPOSURE, cast(char *)event);
+		  	xcb_flush(_xcbconnection);
+		}
+				
 		protected ButtonDetails _lbutton;
 		protected ButtonDetails _mbutton;
 		protected ButtonDetails _rbutton;
@@ -238,14 +242,20 @@ version(linux) {
 					case 1:
 						button = MouseButton.Left;
 		                pbuttonDetails = &_lbutton;
+						if (action == MouseAction.ButtonDown)
+							flags |= MouseFlag.LButton;
 						break;
 					case 2:
 						button = MouseButton.Middle;
 		                pbuttonDetails = &_mbutton;
+						if (action == MouseAction.ButtonDown)
+							flags |= MouseFlag.MButton;
 						break;
 					case 3:
 						button = MouseButton.Right;
 		                pbuttonDetails = &_rbutton;
+						if (action == MouseAction.ButtonDown)
+							flags |= MouseFlag.RButton;
 						break;
 					case 4:
 						if (action == MouseAction.ButtonUp)
@@ -464,8 +474,14 @@ version(linux) {
 			            }
 		            case XCB_LEAVE_NOTIFY: {
 		                xcb_leave_notify_event_t *leave = cast(xcb_leave_notify_event_t *)e;
-
-			                Log.d("XCB_LEAVE_NOTIFY ", leave.event, " at coords ", leave.event_x, ", ", leave.event_y);
+		                Log.d("XCB_LEAVE_NOTIFY ", leave.event, " at coords ", leave.event_x, ", ", leave.event_y);
+						XCBWindow window = getWindow(leave.event);
+						if (window !is null) {
+							//
+							window.processMouseEvent(MouseAction.Leave, 0, leave.state, leave.event_x, leave.event_y);
+						} else {
+							Log.w("Received message for unknown window", leave.event);
+						}
 		                break;
 		            }
 		            case XCB_KEY_PRESS: {
diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d
index 7819bc32..67c0e2d5 100644
--- a/src/dlangui/widgets/controls.d
+++ b/src/dlangui/widgets/controls.d
@@ -1,159 +1,159 @@
-module dlangui.widgets.controls;
-
-import dlangui.widgets.widget;
-
-/// static text widget
-class TextWidget : Widget {
-    this(string ID = null) {
-		super(ID);
-        styleId = "TEXT";
-    }
-    protected dstring _text;
-    /// get widget text
-    override @property dstring text() { return _text; }
-    /// set text to show
-    override @property Widget text(dstring s) { 
-        _text = s; 
-        requestLayout();
-		return this;
-    }
-
-    override void measure(int parentWidth, int parentHeight) { 
-        FontRef font = font();
-        Point sz = font.textSize(text);
-        measuredContent(parentWidth, parentHeight, sz.x, sz.y);
-    }
-
-    bool onClick() {
-        // override it
-        Log.d("Button.onClick ", id);
-        return false;
-    }
-
-    override void onDraw(DrawBuf buf) {
-        if (visibility != Visibility.Visible)
-            return;
-        super.onDraw(buf);
-        Rect rc = _pos;
-        applyMargins(rc);
-        ClipRectSaver(buf, rc);
-        applyPadding(rc);
-        FontRef font = font();
-        Point sz = font.textSize(text);
-        applyAlign(rc, sz);
-        font.drawText(buf, rc.left, rc.top, text, textColor);
-    }
-}
-
-/// image widget
-class ImageWidget : Widget {
-
-    protected string _drawableId;
-    protected DrawableRef _drawable;
-
-    this(string ID = null) {
-		super(ID);
-	}
-
-    /// get drawable image id
-    @property string drawableId() { return _drawableId; }
-    /// set drawable image id
-    @property ImageWidget drawableId(string id) { 
-        _drawableId = id; 
-        _drawable.clear();
-        requestLayout();
-        return this; 
-    }
-    /// get drawable
-    @property ref DrawableRef drawable() {
-        if (!_drawable.isNull)
-            return _drawable;
-        if (_drawableId !is null)
-            _drawable = drawableCache.get(_drawableId);
-        return _drawable;
-    }
-    /// set custom drawable (not one from resources)
-    @property ImageWidget drawable(DrawableRef img) {
-        _drawable = img;
-        _drawableId = null;
-        return this;
-    }
-
-    override void measure(int parentWidth, int parentHeight) { 
-        DrawableRef img = drawable;
-        int w = 0;
-        int h = 0;
-        if (!img.isNull) {
-            w = img.width;
-            h = img.height;
-        }
-        measuredContent(parentWidth, parentHeight, w, h);
-    }
-    override void onDraw(DrawBuf buf) {
-        if (visibility != Visibility.Visible)
-            return;
-        super.onDraw(buf);
-        Rect rc = _pos;
-        applyMargins(rc);
-        ClipRectSaver(buf, rc);
-        applyPadding(rc);
-        DrawableRef img = drawable;
-        if (!img.isNull) {
-            Point sz;
-            sz.x = img.width;
-            sz.y = img.height;
-            applyAlign(rc, sz);
-            img.drawTo(buf, rc);
-        }
-    }
-}
-
-class Button : Widget {
-    protected dstring _text;
-    override @property dstring text() { return _text; }
-    override @property Widget text(dstring s) { _text = s; requestLayout(); return this; }
-    this(string ID = null) {
-		super(ID);
-        styleId = "BUTTON";
-    }
-    override void measure(int parentWidth, int parentHeight) { 
-        FontRef font = font();
-        Point sz = font.textSize(text);
-        measuredContent(parentWidth, parentHeight, sz.x, sz.y);
-    }
-    override void onDraw(DrawBuf buf) {
-        super.onDraw(buf);
-        Rect rc = _pos;
-        applyMargins(rc);
-        buf.fillRect(_pos, backgroundColor);
-        applyPadding(rc);
-        ClipRectSaver(buf, rc);
-        FontRef font = font();
-        Point sz = font.textSize(text);
-        applyAlign(rc, sz);
-        font.drawText(buf, rc.left, rc.top, text, textColor);
-    }
-
-    override bool onMouseEvent(MouseEvent event) {
-        if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
-            setState(State.Pressed);
-            Log.d("Button state: ", state);
-            return true;
-        }
-        if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
-            resetState(State.Pressed);
-            Log.d("Button state: ", state);
-            return true;
-        }
-        if (event.action == MouseAction.FocusOut) {
-            resetState(State.Pressed);
-            return true;
-        }
-        if (event.action == MouseAction.FocusIn) {
-            setState(State.Pressed);
-            return true;
-        }
-        return false;
-    }
-
-}
+module dlangui.widgets.controls;
+
+import dlangui.widgets.widget;
+
+/// static text widget
+class TextWidget : Widget {
+    this(string ID = null) {
+		super(ID);
+        styleId = "TEXT";
+    }
+    protected dstring _text;
+    /// get widget text
+    override @property dstring text() { return _text; }
+    /// set text to show
+    override @property Widget text(dstring s) { 
+        _text = s; 
+        requestLayout();
+		return this;
+    }
+
+    override void measure(int parentWidth, int parentHeight) { 
+        FontRef font = font();
+        Point sz = font.textSize(text);
+        measuredContent(parentWidth, parentHeight, sz.x, sz.y);
+    }
+
+    bool onClick() {
+        // override it
+        Log.d("Button.onClick ", id);
+        return false;
+    }
+
+    override void onDraw(DrawBuf buf) {
+        if (visibility != Visibility.Visible)
+            return;
+        super.onDraw(buf);
+        Rect rc = _pos;
+        applyMargins(rc);
+        ClipRectSaver(buf, rc);
+        applyPadding(rc);
+        FontRef font = font();
+        Point sz = font.textSize(text);
+        applyAlign(rc, sz);
+        font.drawText(buf, rc.left, rc.top, text, textColor);
+    }
+}
+
+/// image widget
+class ImageWidget : Widget {
+
+    protected string _drawableId;
+    protected DrawableRef _drawable;
+
+    this(string ID = null) {
+		super(ID);
+	}
+
+    /// get drawable image id
+    @property string drawableId() { return _drawableId; }
+    /// set drawable image id
+    @property ImageWidget drawableId(string id) { 
+        _drawableId = id; 
+        _drawable.clear();
+        requestLayout();
+        return this; 
+    }
+    /// get drawable
+    @property ref DrawableRef drawable() {
+        if (!_drawable.isNull)
+            return _drawable;
+        if (_drawableId !is null)
+            _drawable = drawableCache.get(_drawableId);
+        return _drawable;
+    }
+    /// set custom drawable (not one from resources)
+    @property ImageWidget drawable(DrawableRef img) {
+        _drawable = img;
+        _drawableId = null;
+        return this;
+    }
+
+    override void measure(int parentWidth, int parentHeight) { 
+        DrawableRef img = drawable;
+        int w = 0;
+        int h = 0;
+        if (!img.isNull) {
+            w = img.width;
+            h = img.height;
+        }
+        measuredContent(parentWidth, parentHeight, w, h);
+    }
+    override void onDraw(DrawBuf buf) {
+        if (visibility != Visibility.Visible)
+            return;
+        super.onDraw(buf);
+        Rect rc = _pos;
+        applyMargins(rc);
+        ClipRectSaver(buf, rc);
+        applyPadding(rc);
+        DrawableRef img = drawable;
+        if (!img.isNull) {
+            Point sz;
+            sz.x = img.width;
+            sz.y = img.height;
+            applyAlign(rc, sz);
+            img.drawTo(buf, rc);
+        }
+    }
+}
+
+class Button : Widget {
+    protected dstring _text;
+    override @property dstring text() { return _text; }
+    override @property Widget text(dstring s) { _text = s; requestLayout(); return this; }
+    this(string ID = null) {
+		super(ID);
+        styleId = "BUTTON";
+    }
+    override void measure(int parentWidth, int parentHeight) { 
+        FontRef font = font();
+        Point sz = font.textSize(text);
+        measuredContent(parentWidth, parentHeight, sz.x, sz.y);
+    }
+    override void onDraw(DrawBuf buf) {
+        super.onDraw(buf);
+        Rect rc = _pos;
+        applyMargins(rc);
+        buf.fillRect(_pos, backgroundColor);
+        applyPadding(rc);
+        ClipRectSaver(buf, rc);
+        FontRef font = font();
+        Point sz = font.textSize(text);
+        applyAlign(rc, sz);
+        font.drawText(buf, rc.left, rc.top, text, textColor);
+    }
+
+    override bool onMouseEvent(MouseEvent event) {
+        if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
+            setState(State.Pressed);
+            Log.d("Button state: ", state);
+            return true;
+        }
+        if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
+            resetState(State.Pressed);
+            Log.d("Button state: ", state);
+            return true;
+        }
+        if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
+            resetState(State.Pressed);
+            return true;
+        }
+        if (event.action == MouseAction.FocusIn) {
+            setState(State.Pressed);
+            return true;
+        }
+        return false;
+    }
+
+}