]> O.S.I.I.S - jp/crow.git/commitdiff
simplify mouse handling, try single threaded
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 27 Dec 2018 10:47:01 +0000 (11:47 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 27 Dec 2018 10:47:01 +0000 (11:47 +0100)
Crow/Templates/MenuItem.template
Crow/Templates/Spinner.template
Crow/src/ExtensionsMethods.cs
Crow/src/GraphicObjects/TemplatedGroup.cs
Crow/src/GraphicObjects/TreeView.cs
Crow/src/GraphicObjects/Widget.cs
Crow/src/Interface.cs

index d33216615f466a8a01ed8609afc8dc96c0ab49df..ae31c8622c9f5e5631c56dc52c8c00c58e75b1ba 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <HorizontalStack>
 <Popper Font="{./Font}" Caption="{./Caption}"  Background="{./Background}" PopDirection="{./PopDirection}"
-       Foreground = "{./Foreground}" CanPop="{./HasChildren}" MouseClick="./onMI_Click"
+       Foreground = "{./Foreground}" CanPop="{./HasChildren}"
        IsPopped="{²./IsOpened}" PopWidth="{./PopWidth}" PopHeight="{./PopHeight}">
        <Template>
                <CheckBox IsChecked="{²./IsPopped}" Caption="{./Caption}" Background="{./Background}" Foreground="{./Foreground}">
index 60d7ccf9eba299a8fcf6751ef4674cca6f0afb17..4d992da3661de368cf3363c58605ef0e776f1c00 100755 (executable)
@@ -6,7 +6,7 @@
                        Text="{²./Value}" TextAlignment="Right" Margin="0"/>
        </Border>
        <VerticalStack MinimumSize="13,13" Width="25%" Height="Stretched" Spacing="0" Margin="0">
-               <Shape Style="ArrowBut" Height="50%" MouseDown="./onUp" Path="M 5.5,0.5 L 10.5,6.5 L 0.5,6.5 Z"/>                       
-               <Shape Style="ArrowBut" Height="50%" MouseDown="./onDown" Path="M 0.5,0.5 L 10.5,0.5 L 5.5,6.5 Z"/>                     
+               <Shape Style="ArrowBut" Size="11,11" Height="50%" MouseDown="./onUp" Path="M 5.5,0.5 L 10.5,6.5 L 0.5,6.5 Z"/>                  
+               <Shape Style="ArrowBut" Size="11,11" Height="50%" MouseDown="./onDown" Path="M 0.5,0.5 L 10.5,0.5 L 5.5,6.5 Z"/>                        
        </VerticalStack>
 </HorizontalStack>
index ef464270f80f92d6719009ddb9e6f7af253ef7fd..da92fc9f327b01ec254e36cbfe404f41d7e0cf65 100644 (file)
@@ -190,17 +190,11 @@ namespace Crow
                }
                public static void Raise(this EventHandler handler, object sender, EventArgs e)
                {
-                       if(handler != null)
-                       {
-                               handler(sender, e);
-                       }
+                       handler?.Invoke (sender, e);
                }
                public static void Raise<T>(this EventHandler<T> handler, object sender, T e)
                {
-                       if(handler != null)
-                       {
-                               handler(sender, e);
-                       }
+                       handler?.Invoke (sender, e);
                }
                public static byte[] GetBytes(this string str)
                {
index daaedeb40144cfd3e51dd4abb20dfca804ab7272..0ee9a405f5a9b8f808d0e0f3353cc669b171ed03 100644 (file)
@@ -218,9 +218,10 @@ namespace Crow
                                if (data == null)
                                        return;
 
-                               loadingThread = new CrowThread (this, loading);
+                               /*loadingThread = new CrowThread (this, loading);
                                loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
-                               loadingThread.Start ();
+                               loadingThread.Start ();*/
+                               loading ();
 
                                NotifyValueChanged ("SelectedIndex", _selectedIndex);
                                NotifyValueChanged ("SelectedItem", SelectedItem);
@@ -394,8 +395,8 @@ namespace Crow
 
                        for (int i = 0; i < _data.Count; i++) {                         
                                loadItem (_data[i], page, _dataTest);
-                               if (loadingThread.cancelRequested)
-                                       break;
+//                             if (loadingThread.cancelRequested)
+//                                     break;
                        }
 
 //                     if (page == items)
@@ -455,7 +456,7 @@ namespace Crow
                                page.AddChild (g);
 //                             if (isPaged)
                                g.LogicalParent = this;
-                               g.MouseDown += itemClick;
+                               g.MouseClick += itemClick;
                        }
 
                        if (iTemp.Expand != null && g is Expandable) {
index 9ee8d2c5a7e605bd55a513b02be79b710be3dc7f..12910ac41c124d0e62592753fc82898b87892601 100644 (file)
@@ -65,8 +65,8 @@ namespace Crow
                internal override void itemClick (object sender, MouseButtonEventArgs e)
                {
                        Widget tmp = sender as Widget;
-                       if (!tmp.HasFocus)
-                               return;
+//                     if (!tmp.HasFocus)
+                               //return;
                        /*if (selectedItemContainer != null) {
                                selectedItemContainer.Foreground = Color.Transparent;
                                selectedItemContainer.Background = Color.Transparent;
index d6ea25801bfe3f8a891846ee41d7b21d0430d168..2ecaf28e0aa261ae8b9456e88b27e38ab9552a52 100644 (file)
@@ -282,12 +282,12 @@ namespace Crow
                Font font = "sans, 10";
                protected Measure width, height;
                int left, top;
-               double cornerRadius = 0;
-               int margin = 0;
-               bool focusable = false;
-               bool hasFocus = false;
-               bool isActive = false;
-               //bool isHover = false;
+               double cornerRadius;
+               int margin;
+               bool focusable ;
+               bool hasFocus;
+               bool isActive;
+               bool isHover;
                bool mouseRepeat;
                protected bool isVisible = true;
                bool isEnabled = true;
@@ -295,7 +295,7 @@ namespace Crow
                HorizontalAlignment horizontalAlignment = HorizontalAlignment.Center;
                Size maximumSize = "0,0";
                Size minimumSize = "0,0";
-               bool cacheEnabled = false;
+               bool cacheEnabled;
                bool clipToClientRect = true;
                Type dataSourceType;
                protected object dataSource;
@@ -440,7 +440,7 @@ namespace Crow
                /// <summary>Occurs when this object loose focus</summary>
                public event EventHandler Unfocused;
                /// <summary>Occurs when mouse is over</summary>
-               //public event EventHandler Hover;
+               public event EventHandler Hover;
                /// <summary>Occurs when this control is no longer the Hover one</summary>
                //public event EventHandler UnHover;
                /// <summary>Occurs when this object loose focus</summary>
@@ -472,6 +472,9 @@ namespace Crow
                public event EventHandler<DataSourceChangeEventArgs> LogicalParentChanged;
                #endregion
 
+               internal bool hasDoubleClick => MouseDoubleClick != null;
+               internal bool hasClick => MouseClick != null;
+
                #region public properties
                /// <summary>Random value placeholder</summary>
                [DesignCategory ("Divers")]
@@ -748,7 +751,7 @@ namespace Crow
                /// <summary>
                /// true if this control has the pointer hover
                /// </summary>
-               /*[XmlIgnore]public virtual bool IsHover {
+               [XmlIgnore]public virtual bool IsHover {
                        get { return isHover; }
                        set {
                                if (value == isHover)
@@ -757,13 +760,11 @@ namespace Crow
                                isHover = value;
 
                                if (isHover)
-                                       onHover (this, null);
-                               else
-                                       onUnHover (this, null);
+                                       Hover.Raise (this, null);
 
                                NotifyValueChanged ("IsHover", isHover);
                        }
-               }*/
+               }
                /// <summary>
                /// true if holding mouse button down should trigger multiple click events
                /// </summary>
@@ -1803,20 +1804,19 @@ namespace Crow
                        //to let other control behind have mouse entering
                        if (isDragged)
                                return;
-                       
-                       //bubble event to the top
-                       Widget p = focusParent;
-                       if (p != null)
-                               p.onMouseMove(sender,e);
 
-                       MouseMove.Raise (this, e);
+                       if (MouseMove == null)
+                               focusParent?.onMouseMove (sender, e);
+                       else
+                               MouseMove.Invoke (this, e);
+
                }
                public virtual void onMouseDown(object sender, MouseButtonEventArgs e){
-                       #if DEBUG_FOCUS
+#if DEBUG_FOCUS
                        Debug.WriteLine("MOUSE DOWN => " + this.ToString());
-                       #endif
+#endif
 
-                       if (focusable && !Interface.FocusOnHover) {
+                       /*if (focusable && !Interface.FocusOnHover) {
                                BubblingMouseButtonEventArg be = e as BubblingMouseButtonEventArg;
                                if (be.Focused == null) {
                                        be.Focused = this;
@@ -1824,20 +1824,18 @@ namespace Crow
                                        if (e.Button == MouseButton.Right && contextCommands != null)
                                                IFace.ShowContextMenu (this);                                   
                                }
-                       }
-                       //bubble event to the top
-                       Widget p = focusParent;
-                       if (p != null)
-                               p.onMouseDown(sender,e);
-
-                       MouseDown.Raise (this, e);
+                       }*/
+                       if (MouseDown == null)
+                               focusParent?.onMouseDown (sender, e);
+                       else
+                               MouseDown.Invoke (this, e);
                }
                public virtual void onMouseUp(object sender, MouseButtonEventArgs e){
                        #if DEBUG_FOCUS
                        Debug.WriteLine("MOUSE UP => " + this.ToString());
                        #endif
 
-                       if (IFace.DragAndDropOperation != null){
+                       /*if (IFace.DragAndDropOperation != null){
                                if (IFace.DragAndDropOperation.DragSource == this) {
                                        if (IFace.DragAndDropOperation.DropTarget != null)
                                                onDrop (this, IFace.DragAndDropOperation);
@@ -1845,50 +1843,38 @@ namespace Crow
                                                onEndDrag (this, IFace.DragAndDropOperation);
                                        IFace.DragAndDropOperation = null;
                                }
-                       }
-
-                       //bubble event to the top
-                       Widget p = focusParent;
-                       if (p != null)
-                               p.onMouseUp(sender,e);
+                       }*/
 
-                       MouseUp.Raise (this, e);
+                       if (MouseUp == null)
+                               focusParent?.onMouseUp (sender, e);
+                       else 
+                               MouseUp.Invoke (this, e);
                }
                public virtual void onMouseClick(object sender, MouseButtonEventArgs e){
 #if DEBUG_FOCUS
                        Debug.WriteLine("CLICK => " + this.ToString());
 #endif
-            if (MouseClick != null)
-            {
-                MouseClick.Raise(this, e);
-                return;
-            }
-                       Widget p = focusParent;
-                       if (p != null)
-                               p.onMouseClick(sender,e);                       
+            if (MouseClick == null)
+                               focusParent?.onMouseClick (sender, e);
+                       else
+                               MouseClick.Invoke(this, e);
                }
                public virtual void onMouseDoubleClick(object sender, MouseButtonEventArgs e){
 #if DEBUG_FOCUS
                        Debug.WriteLine("DOUBLE CLICK => " + this.ToString());
 #endif
-            if (MouseDoubleClick != null)
-            {
-                MouseDoubleClick.Raise(this, e);
-                return;
-            }
-            Widget p = focusParent;
-                       if (p != null)
-                               p.onMouseDoubleClick(sender,e);                 
+                       if (MouseDoubleClick == null)
+                               focusParent?.onMouseDoubleClick (sender, e);
+                       else
+                               MouseDoubleClick.Invoke (this, e);
                }
                public virtual void onMouseWheel(object sender, MouseWheelEventArgs e){
-            if (MouseWheelChanged != null)
-            {
-                MouseWheelChanged.Raise(this, e);
-                return;
-            }
-            Widget p = focusParent;
-                       if (p != null)
-                               p.onMouseWheel(sender,e);
+            if (MouseWheelChanged == null)
+                               focusParent?.onMouseWheel (sender, e);
+                       else
+                               MouseWheelChanged.Invoke(this, e);
+
+            
                }
                public virtual void onMouseEnter(object sender, MouseMoveEventArgs e)
                {
@@ -1925,8 +1911,6 @@ namespace Crow
                #endregion
 
                protected virtual void onFocused(object sender, EventArgs e){
-                       if (IFace.FocusedWidget != this)
-                               IFace.FocusedWidget = this;
                        #if DEBUG_FOCUS
                        Debug.WriteLine("Focused => " + this.ToString());
                        #endif
@@ -1938,6 +1922,7 @@ namespace Crow
                        #endif
                        Unfocused.Raise (this, e);
                }
+
                public virtual void onEnable(object sender, EventArgs e){
                        Enabled.Raise (this, e);
                }
@@ -1945,13 +1930,6 @@ namespace Crow
                        Disabled.Raise (this, e);
                }
                protected virtual void onParentChanged(object sender, DataSourceChangeEventArgs e) {
-//                     if (e.NewDataSource != null) {
-//                             if (width == Measure.Inherit)
-//                                     RegisterForLayouting (LayoutingType.Width);
-//                             if (height == Measure.Inherit)
-//                                     RegisterForLayouting (LayoutingType.Height);
-//                     }
-                       
                        ParentChanged.Raise (this, e);
                        if (logicalParent == null)
                                LogicalParentChanged.Raise (this, e);
index eb77adf89276d081191c68d25bdf48905577a6c2..7090eadd8492f90e74c11f96aaf1a7756a3f358e 100644 (file)
@@ -125,61 +125,28 @@ namespace Crow
                        //backend = new Crow.XLib.XLibBackend ();
                        backend.Init (this);
 
-                       initTooltip ();
-                       initContextMenus ();
+                       /*initTooltip ();
+                       initContextMenus ();*/
 
-                       running = true;
 
                        /*Thread t = new Thread (interfaceThread);
                        t.IsBackground = true;
                        t.Start ();*/
                }
                public void Run () {
+                       //load default main.crow if present
+                       try {
+                               Load ("#main.crow").DataSource = this;
+                       } catch {}
+
+                       running = true;
+
                        while (running) {
                                Update ();
                                ProcessEvents ();
                        }
                }
-               public void ProcessKeyPress (char c)
-               {
-                       if (_focusedWidget != null)
-                               _focusedWidget.onKeyPress (this, new KeyPressEventArgs(c));
-               }
-
-               public void ProcessKeyUp (Key key)
-               {
-                       if (_focusedWidget != null)
-                               _focusedWidget.onKeyUp (this, new KeyEventArgs(key, false));
-//                     if (keyboardRepeatThread != null) {
-//                             keyboardRepeatOn = false;
-//                             keyboardRepeatThread.Abort();
-//                             keyboardRepeatThread.Join ();
-//                     }
-               }
-               public void ProcessKeyDown (Key key)
-               {
-                       //Keyboard.SetKeyState((Crow.Key)Key,true);
-                       lastKeyDownEvt = new KeyEventArgs (key, true);
 
-                       if (_focusedWidget != null)
-                               _focusedWidget.onKeyDown (this, new KeyEventArgs (key, false));
-
-                       //                      keyboardRepeatThread = new Thread (keyboardRepeatThreadFunc);
-                       //                      keyboardRepeatThread.IsBackground = true;
-                       //                      keyboardRepeatThread.Start ();
-               }
-
-               public bool Shift {
-                       get { return backend.Shift; }
-               }
-
-               public bool Ctrl {
-                       get { return backend.Ctrl; }
-               }
-
-               public bool Alt {
-                       get { return backend.Alt; }
-               }
 
                void interfaceThread()
                {                       
@@ -223,7 +190,31 @@ namespace Crow
                #endregion
 
                public void ProcessEvents() {
+
+                       if (armedClick != null) {
+                               if (lastClickTime.ElapsedMilliseconds > DoubleClick) {
+                                       //cancel double click and 
+                                       armedClick.onMouseClick (armedClick, armedClickEventArgs);
+                                       armedClick = null;
+                               }
+                       }
+
+                       Widget w = _hoverWidget;  //previous hover widget 
+
                        backend.ProcessEvents ();
+
+                       if (!FocusOnHover || (w == _hoverWidget))
+                               return;
+
+                       w = _hoverWidget;
+                       while (w != null) {
+                               if (w.Focusable) {
+                                       FocusedWidget = _hoverWidget;
+                                       break;
+                               }
+                               w = w.focusParent;
+                       }               
+
                }
                public void Init () {
                        CultureInfo.DefaultThreadCurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
@@ -246,13 +237,13 @@ namespace Crow
                /// </summary>
                public static string CrowConfigRoot;
                /// <summary>If true, mouse focus is given when mouse is over control</summary>
-               public static bool FocusOnHover = false;
+               public static bool FocusOnHover = true;
                /// <summary> Threshold to catch borders for sizing </summary>
                public static int BorderThreshold = 5;
                /// <summary> delay before tooltip appear </summary>
                public static int ToolTipDelay = 500;
                /// <summary>Double click threshold in milisecond</summary>
-               public static int DoubleClick = 250;//max duration between two mouse_down evt for a dbl clk in milisec.
+               public static int DoubleClick = 240;//max duration between two mouse_down evt for a dbl clk in milisec.
                /// <summary> Time to wait in millisecond before starting repeat loop</summary>
                public static int DeviceRepeatDelay = 700;
                /// <summary> Time interval in millisecond between device event repeat</summary>
@@ -281,37 +272,10 @@ namespace Crow
                /// the ref of this one will be stored in GraphicObject.currentInterface
                /// </summary>
                protected static Interface CurrentInterface;
-               internal Stopwatch clickTimer = new Stopwatch();
-               Widget armedClickSender = null;
-               MouseButtonEventArgs armedClickEvtArgs = null;
-//             internal GraphicObject EligibleForDoubleClick {
-//                     get { return eligibleForDoubleClick; }
-//                     set {
-//                             eligibleForDoubleClick = value;
-//                             clickTimer.Restart ();
-//                     }
-//             }
-               internal void armeClick (Widget sender, MouseButtonEventArgs e){
-                       armedClickSender = sender;
-                       armedClickEvtArgs = e;
-                       clickTimer.Restart ();
-               }
-               #endregion
+               Stopwatch lastClickTime = new Stopwatch();
+               Widget armedClick;//store widget with double click on first click
+               MouseButtonEventArgs armedClickEventArgs;
 
-               #region Events
-               public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
-               public event EventHandler Quit;
-
-               public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
-               public event EventHandler<MouseButtonEventArgs> MouseButtonUp;
-               public event EventHandler<MouseButtonEventArgs> MouseButtonDown;
-               public event EventHandler<MouseButtonEventArgs> MouseClick;
-               public event EventHandler<MouseMoveEventArgs> MouseMove;
-               public event EventHandler<KeyEventArgs> KeyDown;
-               public event EventHandler<KeyEventArgs> KeyUp;
-               public event EventHandler<KeyPressEventArgs> KeyPress;
-               /*public event EventHandler<KeyEventArgs> KeyboardKeyDown;
-               public event EventHandler<KeyEventArgs> KeyboardKeyUp;*/
                #endregion
 
                /// <summary>Main Cairo surface</summary>
@@ -325,7 +289,7 @@ namespace Crow
                /// <summary>resulting bitmap limited to last redrawn part</summary>
                public byte[] dirtyBmp;
                /// <summary>True when host has to repaint Interface</summary>
-               public bool IsDirty = false;
+               public bool IsDirty;
                /// <summary>Coordinate of the dirty bmp on the original bmp</summary>
                public Rectangle DirtyRect;
                /// <summary>Locked for each layouting operation</summary>
@@ -576,7 +540,7 @@ namespace Crow
                #region focus
                Widget _activeWidget;   //button is pressed on widget
                Widget _hoverWidget;            //mouse is over
-               Widget _focusedWidget;  //has keyboard (or other perif) focus
+               Widget _focusedWidget;  //has keyboard (or other perif) focus
 
                /// <summary>Widget is focused and button is down or another perif action is occuring
                /// , it can not lose focus while Active</summary>
@@ -618,8 +582,8 @@ namespace Crow
                                if (_hoverWidget == value)
                                        return;
 
-                               //if (_hoverWidget != null)
-                               //      _hoverWidget.IsHover = false;
+                               if (_hoverWidget != null)
+                                       _hoverWidget.IsHover = false;
 
                                _hoverWidget = value;
 
@@ -684,29 +648,23 @@ namespace Crow
                /// Result: the Interface bitmap is drawn in memory (byte[] bmp) and a dirtyRect and bitmap are available
                /// </summary>
                public void Update(){
-                       if (armedClickSender != null && clickTimer.ElapsedMilliseconds >= Interface.DoubleClick) {
-                               armedClickSender.onMouseClick (armedClickSender, armedClickEvtArgs);                            
-                               armedClickSender = null;
-                       }
 
-                       if (mouseRepeatCount > 0) {
-                               int mc = mouseRepeatCount;
-                               mouseRepeatCount -= mc;
-                               if (_focusedWidget != null) {
-                                       mouseRepeatTriggeredAtLeastOnce = true;
-                                       for (int i = 0; i < mc; i++) {
-                                               _focusedWidget.onMouseDown (this, new BubblingMouseButtonEventArg(Mouse.X, Mouse.Y, MouseButton.Left, true));
-                                       }
-                               }
-                       }
-
-                       CrowThread[] tmpThreads;
+                       /*CrowThread[] tmpThreads;
                        lock (CrowThreads) {
                                tmpThreads = new CrowThread[CrowThreads.Count];
                                Array.Copy (CrowThreads.ToArray (), tmpThreads, CrowThreads.Count);
                        }
                        for (int i = 0; i < tmpThreads.Length; i++)
-                               tmpThreads [i].CheckState ();
+                               tmpThreads [i].CheckState ();*/
+                       if (mouseRepeatTimer.ElapsedMilliseconds > 0) {
+                               if (_hoverWidget != null && _hoverWidget.MouseRepeat) {
+                                       int repeatCount = (int)mouseRepeatTimer.ElapsedMilliseconds / DeviceRepeatInterval - mouseRepeatCount;
+                                       for (int i = 0; i < repeatCount; i++)
+                                               _hoverWidget.onMouseDown (_hoverWidget, lastMouseDownEvent);
+                                       mouseRepeatCount += repeatCount;
+                               }
+                       } else if (lastMouseDown.ElapsedMilliseconds > DeviceRepeatDelay) 
+                               mouseRepeatTimer.Start ();
 
                        if (!Monitor.TryEnter (UpdateMutex))
                                return;
@@ -1001,6 +959,9 @@ namespace Crow
                #region Mouse and Keyboard Handling
 
                public MouseState Mouse;
+               Stopwatch lastMouseDown = new Stopwatch (), mouseRepeatTimer = new Stopwatch ();
+               int mouseRepeatCount;
+               MouseButtonEventArgs lastMouseDownEvent;
 
                public MouseCursors MouseCursor {
                        set {
@@ -1012,10 +973,6 @@ namespace Crow
                /// <returns>true if mouse is in the interface</returns>
                public virtual bool ProcessMouseMove(int x, int y)
                {
-                       /*if (armedClickSender != null) {
-                               //armedClickSender.onMouseClick (armedClickSender, armedClickEvtArgs);
-                               armedClickSender = null;
-                       }*/
                        int deltaX = x - Mouse.X;
                        int deltaY = y - Mouse.Y;
                        Mouse.X = x;
@@ -1023,20 +980,25 @@ namespace Crow
                        MouseMoveEventArgs e = new MouseMoveEventArgs (x, y, deltaX, deltaY);
                        e.Mouse = Mouse;
 
+                       if (armedClick != null) {
+                               armedClick.onMouseClick (armedClick, armedClickEventArgs);
+                               armedClick = null;
+                       }
+
                        if (ActiveWidget != null && DragAndDropOperation == null) {
                                //TODO, ensure object is still in the graphic tree
                                //send move evt even if mouse move outside bounds
-                               ActiveWidget.onMouseMove (this, e);
+                               _activeWidget.onMouseMove (this, e);
                                return true;
                        }
 
                        if (DragAndDropOperation != null)//drag source cant have hover event, so move has to be handle here
                                DragAndDropOperation.DragSource.onMouseMove (this, e);                  
 
-                       if (HoverWidget != null) {
+                       if (_hoverWidget != null) {
                                resetTooltip ();
                                //check topmost graphicobject first
-                               Widget tmp = HoverWidget;
+                               Widget tmp = _hoverWidget;
                                Widget topc = null;
                                while (tmp is Widget) {
                                        topc = tmp;
@@ -1048,13 +1010,13 @@ namespace Crow
                                        while (i < idxhw) {
                                                if (!GraphicTree [i].isPopup) {
                                                        if (GraphicTree [i].MouseIsIn (e.Position)) {
-                                                               while (HoverWidget != null) {
-                                                                       HoverWidget.onMouseLeave (HoverWidget, e);
-                                                                       HoverWidget = HoverWidget.focusParent;
+                                                               while (_hoverWidget != null) {
+                                                                       _hoverWidget.onMouseLeave (_hoverWidget, e);
+                                                                       HoverWidget = _hoverWidget.focusParent;
                                                                }
 
                                                                GraphicTree [i].checkHoverWidget (e);
-                                                               HoverWidget.onMouseMove (this, e);
+                                                               _hoverWidget.onMouseMove (_hoverWidget, e);
                                                                return true;
                                                        }
                                                }
@@ -1062,21 +1024,21 @@ namespace Crow
                                        }
                                }
 
-                               if (HoverWidget.MouseIsIn (e.Position)) {
-                                       HoverWidget.checkHoverWidget (e);
-                                       HoverWidget.onMouseMove (this, e);
+                               if (_hoverWidget.MouseIsIn (e.Position)) {
+                                       _hoverWidget.checkHoverWidget (e);
+                                       _hoverWidget.onMouseMove (_hoverWidget, e);
                                        return true;
                                } else {
-                                       HoverWidget.onMouseLeave (HoverWidget, e);
+                                       _hoverWidget.onMouseLeave (_hoverWidget, e);
                                        //seek upward from last focused graph obj's
-                                       while (HoverWidget.focusParent != null) {
-                                               HoverWidget = HoverWidget.focusParent;
-                                               if (HoverWidget.MouseIsIn (e.Position)) {
-                                                       HoverWidget.checkHoverWidget (e);
-                                                       HoverWidget.onMouseMove (this, e);
+                                       while (_hoverWidget.focusParent != null) {
+                                               HoverWidget = _hoverWidget.focusParent;
+                                               if (_hoverWidget.MouseIsIn (e.Position)) {
+                                                       _hoverWidget.checkHoverWidget (e);
+                                                       _hoverWidget.onMouseMove (_hoverWidget, e);
                                                        return true;
                                                } else
-                                                       HoverWidget.onMouseLeave (HoverWidget, e);
+                                                       _hoverWidget.onMouseLeave (_hoverWidget, e);
                                        }
                                }
                        }
@@ -1089,7 +1051,7 @@ namespace Crow
                                                g.checkHoverWidget (e);
                                                if (g is Window)
                                                        PutOnTop (g);
-                                               HoverWidget.onMouseMove (this, e);
+                                               _hoverWidget.onMouseMove (_hoverWidget, e);
                                                return true;
                                        }
                                }
@@ -1105,20 +1067,37 @@ namespace Crow
                public bool ProcessMouseButtonUp(Crow.MouseButton button)
                {
                        Mouse.DisableBit ((int)button);
+                       lastMouseDown.Reset ();
+                       mouseRepeatTimer.Reset ();
+
                        MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
                        if (_activeWidget == null)
                                return false;
 
-                       if (mouseRepeatThread != null) {
-                               mouseRepeatOn = false;
-                               mouseRepeatThread.Cancel();
+                       _activeWidget.onMouseUp (_activeWidget, e);
+
+                       if (armedClick != null) {
+                               if (lastClickTime.ElapsedMilliseconds <= DoubleClick) {
+                                       armedClick.onMouseDoubleClick (armedClick, armedClickEventArgs);
+                                       ActiveWidget = null;
+                               } else
+                                       armedClick.onMouseClick (armedClick, armedClickEventArgs);
+                               armedClick = null;
                        }
-                       if (!mouseRepeatTriggeredAtLeastOnce) {
-                               if (_activeWidget.MouseIsIn (e.Position))
-                                       armeClick (_activeWidget, e);                           
+
+                       Widget target = _activeWidget;
+                       while (target != null) {
+                               if (target.hasDoubleClick) {
+                                       armedClick = _activeWidget;
+                                       armedClickEventArgs = e;
+                                       lastClickTime.Restart ();
+                                       break;
+                               } else if (target.hasClick) {
+                                       _activeWidget.onMouseClick (_activeWidget, e);
+                                       break;
+                               } else
+                                       target = target.focusParent;
                        }
-                       mouseRepeatTriggeredAtLeastOnce = false;
-                       _activeWidget.onMouseUp (_activeWidget, e);
 
 //                     GraphicObject lastActive = _activeWidget;
                        ActiveWidget = null;
@@ -1132,10 +1111,13 @@ namespace Crow
                /// </summary>
                /// <returns>return true, if interface handled the event, false otherwise.</returns>
                /// <param name="button">Button index</param>
-               public bool ProcessMouseButtonDown(Crow.MouseButton button)
+               public bool ProcessMouseButtonDown(MouseButton button)
                {
                        Mouse.EnableBit ((int)button);
-                       MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
+                       lastMouseDown.Start ();
+                       mouseRepeatCount = 0;
+
+                       lastMouseDownEvent = new MouseButtonEventArgs (button) { Mouse = Mouse };
 
                        if (HoverWidget == null)
                                return false;
@@ -1148,29 +1130,13 @@ namespace Crow
                                        break;
                                }
                        }
-                       if (hoverFocused == armedClickSender) {
-                               if (clickTimer.ElapsedMilliseconds < Interface.DoubleClick) {
-                                       armedClickSender.onMouseDoubleClick (armedClickSender, e);
-                                       armedClickSender = null;
-                                       return true;
-                               }
-                                       
-                       }
-                       if (armedClickSender!=null)
-                               armedClickSender.onMouseClick (armedClickSender, armedClickEvtArgs);                            
-                       armedClickSender = null;
-
-                       HoverWidget.onMouseDown(HoverWidget,new BubblingMouseButtonEventArg(e));
 
-                       if (FocusedWidget == null)
-                               return true;
+                       _hoverWidget.onMouseDown(_hoverWidget,lastMouseDownEvent);
 
-                       ActiveWidget = FocusedWidget;
+                       /*if (_focusedWidget == null)
+                               return true;*/
 
-                       if (!FocusedWidget.MouseRepeat)
-                               return true;
-                       mouseRepeatThread = new CrowThread (FocusedWidget, mouseRepeatThreadFunc);                      
-                       mouseRepeatThread.Start ();
+                       ActiveWidget = _hoverWidget;
                        return true;
                }
                /// <summary>
@@ -1189,6 +1155,46 @@ namespace Crow
                        return true;
                }
 
+               public void ProcessKeyPress (char c)
+               {
+                       if (_focusedWidget != null)
+                               _focusedWidget.onKeyPress (this, new KeyPressEventArgs (c));
+               }
+
+               public void ProcessKeyUp (Key key)
+               {
+                       if (_focusedWidget != null)
+                               _focusedWidget.onKeyUp (this, new KeyEventArgs (key, false));
+                       //                      if (keyboardRepeatThread != null) {
+                       //                              keyboardRepeatOn = false;
+                       //                              keyboardRepeatThread.Abort();
+                       //                              keyboardRepeatThread.Join ();
+                       //                      }
+               }
+               public void ProcessKeyDown (Key key)
+               {
+                       //Keyboard.SetKeyState((Crow.Key)Key,true);
+                       lastKeyDownEvt = new KeyEventArgs (key, true);
+
+                       if (_focusedWidget != null)
+                               _focusedWidget.onKeyDown (this, new KeyEventArgs (key, false));
+
+                       //                      keyboardRepeatThread = new Thread (keyboardRepeatThreadFunc);
+                       //                      keyboardRepeatThread.IsBackground = true;
+                       //                      keyboardRepeatThread.Start ();
+               }
+
+               public bool Shift {
+                       get { return backend.Shift; }
+               }
+
+               public bool Ctrl {
+                       get { return backend.Ctrl; }
+               }
+
+               public bool Alt {
+                       get { return backend.Alt; }
+               }
                public bool IsKeyDown (Key key) {
                        return false;
                }
@@ -1281,21 +1287,10 @@ namespace Crow
                #endregion
 
                #region Device Repeat Events
-               volatile bool mouseRepeatOn, keyboardRepeatOn, mouseRepeatTriggeredAtLeastOnce = false;
-               volatile int mouseRepeatCount, keyboardRepeatCount;
-               CrowThread mouseRepeatThread, keyboardRepeatThread;
+               volatile bool keyboardRepeatOn;
+               volatile int keyboardRepeatCount;
                KeyEventArgs lastKeyDownEvt;
-               void mouseRepeatThreadFunc()
-               {
-                       mouseRepeatOn = true;
-                       mouseRepeatTriggeredAtLeastOnce = false;
-                       Thread.Sleep (Interface.DeviceRepeatDelay);
-                       while (mouseRepeatOn&!mouseRepeatThread.cancelRequested) {
-                               mouseRepeatCount++;
-                               Thread.Sleep (Interface.DeviceRepeatInterval);
-                       }
-                       mouseRepeatCount = 0;
-               }
+
                void keyboardRepeatThreadFunc()
                {
                        keyboardRepeatOn = true;