Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms.X11Internal / X11ThreadQueue.cs
index 954b4f7b6bb924b4532249facb2937572664ce99..cf07045de7b753f157749512ec9ae62043c460b8 100644 (file)
@@ -67,6 +67,25 @@ namespace System.Windows.Forms.X11Internal {
 
                public void EnqueueUnlocked (XEvent xevent)
                {
+                       switch (xevent.type) {
+                       case XEventName.KeyPress:
+                       case XEventName.KeyRelease:
+                       case XEventName.ButtonPress:
+                       case XEventName.ButtonRelease:
+                               NeedDispatchIdle = true;
+                               break;
+                       case XEventName.MotionNotify:
+                               if (xqueue.Count > 0) {
+                                       XEvent peek = xqueue.Peek ();
+                                       if (peek.AnyEvent.type == XEventName.MotionNotify)
+                                               return; // we've already got a pending motion notify.
+                               }
+
+                               // otherwise fall through and enqueue
+                               // the event.
+                               break;
+                       }
+
                        xqueue.Enqueue (xevent);
                        // wake up any thread blocking in DequeueUnlocked
                        Monitor.PulseAll (lockobj);
@@ -79,70 +98,102 @@ namespace System.Windows.Forms.X11Internal {
                        }
                }
 
-               public bool DequeueUnlocked (out XEvent xevent)
+               public bool Dequeue (out XEvent xevent)
                {
-               try_again:
-                       if (xqueue.Count > 0) {
-                               xevent = xqueue.Dequeue ();
-                               return true;
-                       }
+               StartOver:
+                       bool got_xevent = false;
 
-                       if (paint_queue.Count > 0 || configure_queue.Count > 0) {
-                               xevent = new XEvent ();
-                               return false;
+                       lock (lockobj) {
+                               if (xqueue.Count > 0) {
+                                       got_xevent = true;
+                                       xevent = xqueue.Dequeue ();
+                               }
+                               else
+                                       xevent = new XEvent (); /* not strictly needed, but mcs complains */
                        }
 
-                       // both queues are empty.  go to sleep until NextTimeout
-                       // (or until there's an event to handle).
+                       if (got_xevent) {
+                               if (xevent.AnyEvent.type == XEventName.Expose) {
+#if spew
+                                       Console.Write ("E");
+                                       Console.Out.Flush ();
+#endif
+                                       X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
+                                       hwnd.AddExpose (xevent.AnyEvent.window == hwnd.ClientWindow,
+                                                       xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+                                                       xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+                                       goto StartOver;
+                               }
+                               else if (xevent.AnyEvent.type == XEventName.ConfigureNotify) {
+#if spew
+                                       Console.Write ("C");
+                                       Console.Out.Flush ();
+#endif
+                                       X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
+                                       hwnd.AddConfigureNotify (xevent);
+                                       goto StartOver;
+                               }
+                               else {
+#if spew
+                                       Console.Write ("X");
+                                       Console.Out.Flush ();
+#endif
+                                       /* it was an event we can deal with directly, return it */
+                                       return true;
+                               }
+                       }
+                       else {
+                               if (paint_queue.Count > 0) {
+                                       xevent = paint_queue.Dequeue ();
+#if spew
+                                       Console.Write ("e");
+                                       Console.Out.Flush ();
+#endif
+                                       return true;
+                               }
+                               else if (configure_queue.Count > 0) {
+                                       xevent = configure_queue.Dequeue ();
+#if spew
+                                       Console.Write ("c");
+                                       Console.Out.Flush ();
+#endif
+                                       return true;
+                               }
+                       }
 
                        if (dispatch_idle && need_dispatch_idle) {
                                OnIdle (EventArgs.Empty);
                                need_dispatch_idle = false;
                        }
 
-                       if (Monitor.Wait (lockobj, NextTimeout (), true)) {
-                               /* the lock was reaquired before timeout.
-                                  i.e. we have an event now */
-                               goto try_again;
-                       }
-                       else {
-                               xevent = new XEvent ();
-                               return false;
-                       }
-               }
-
-               public bool Dequeue (out XEvent xevent)
-               {
                        lock (lockobj) {
-                               return DequeueUnlocked (out xevent);
+                               if (CountUnlocked > 0)
+                                       goto StartOver;
+
+                               if (Monitor.Wait (lockobj, NextTimeout (), true)) {
+                                       // the lock was reaquired before the
+                                       // timeout.  meaning an event was
+                                       // enqueued by X11Display.XEventThread.
+                                       goto StartOver;
+                               }
+                               else {
+                                       CheckTimers ();
+                                       return false;
+                               }
                        }
                }
 
-               public void RemovePaintUnlocked (Hwnd hwnd)
-               {
-                       paint_queue.Remove (hwnd);
-               }
-
                public void RemovePaint (Hwnd hwnd)
                {
-                       lock (lockobj) {
-                               RemovePaintUnlocked (hwnd);
-                       }
-               }
-
-               public void AddPaintUnlocked (Hwnd hwnd)
-               {
-                       paint_queue.Enqueue (hwnd);
+                       paint_queue.Remove (hwnd);
                }
 
                public void AddPaint (Hwnd hwnd)
                {
-                       lock (lockobj) {
-                               AddPaintUnlocked (hwnd);
-                       }
+                       paint_queue.Enqueue (hwnd);
                }
 
-               public void AddConfigureUnlocked (Hwnd hwnd)
+               public void AddConfigure (Hwnd hwnd)
                {
                        configure_queue.Enqueue (hwnd);
                }
@@ -258,10 +309,15 @@ namespace System.Windows.Forms.X11Internal {
 
                public abstract class HwndEventQueue {
                        protected ArrayList hwnds;
-                       
+#if DebugHwndEventQueue
+                       protected ArrayList stacks;
+#endif
                        public HwndEventQueue (int size)
                        {
-                               hwnds = new ArrayList(size);
+                               hwnds = new ArrayList (size);
+#if DebugHwndEventQueue
+                               stacks = new ArrayList (size);
+#endif
                        }
 
                        public int Count {
@@ -271,31 +327,39 @@ namespace System.Windows.Forms.X11Internal {
                        public void Enqueue (Hwnd hwnd)
                        {
                                if (hwnds.Contains (hwnd)) {
+#if DebugHwndEventQueue
                                        Console.WriteLine ("hwnds can only appear in the queue once.");
                                        Console.WriteLine (Environment.StackTrace);
+                                       Console.WriteLine ("originally added here:");
+                                       Console.WriteLine (stacks[hwnds.IndexOf (hwnd)]);
+#endif
+
                                        return;
                                }
                                hwnds.Add(hwnd);
+#if DebugHwndEventQueue
+                               stacks.Add(Environment.StackTrace);
+#endif
                        }
 
                        public void Remove(Hwnd hwnd)
                        {
+#if DebugHwndEventQueue
+                               int index = hwnds.IndexOf(hwnd);
+                               if (index != -1)
+                                       stacks.RemoveAt(index);
+#endif
                                hwnds.Remove(hwnd);
                        }
 
                        protected abstract XEvent Peek ();
 
-                       public XEvent Dequeue ()
+                       public virtual XEvent Dequeue ()
                        {
                                if (hwnds.Count == 0)
                                        throw new Exception ("Attempt to dequeue empty queue.");
 
-                               // populate the xevent
-                               XEvent xevent = Peek ();
-
-                               hwnds.RemoveAt(0);
-
-                               return xevent;
+                               return Peek ();
                        }
                }
 
@@ -321,6 +385,19 @@ namespace System.Windows.Forms.X11Internal {
                                
                                return xevent;
                        }
+
+                       public override XEvent Dequeue ()
+                       {
+                               XEvent xev = base.Dequeue ();
+
+
+                               hwnds.RemoveAt(0);
+#if DebugHwndEventQueue
+                               stacks.RemoveAt(0);
+#endif
+
+                               return xev;
+                       }
                }
 
                public class PaintQueue : HwndEventQueue
@@ -349,6 +426,8 @@ namespace System.Windows.Forms.X11Internal {
 
                                return xevent;
                        }
+
+                       // don't override Dequeue like ConfigureQueue does.
                }
 
                /* a circular queue for holding X events for processing by GetMessage */