X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FManaged.Windows.Forms%2FSystem.Windows.Forms.X11Internal%2FX11ThreadQueue.cs;h=cf07045de7b753f157749512ec9ae62043c460b8;hb=9f3ef8e4bac11601a2cf2670cbab337e6276103b;hp=6140f4fa787a2c223786054339677b6c7fa9477f;hpb=615f246d23d01e081e198899dea66607038637e8;p=mono.git diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms.X11Internal/X11ThreadQueue.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms.X11Internal/X11ThreadQueue.cs index 6140f4fa787..cf07045de7b 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms.X11Internal/X11ThreadQueue.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms.X11Internal/X11ThreadQueue.cs @@ -33,8 +33,9 @@ namespace System.Windows.Forms.X11Internal { internal class X11ThreadQueue { - XQueue xqueue; + XEventQueue xqueue; PaintQueue paint_queue; + ConfigureQueue configure_queue; ArrayList timer_list; Thread thread; bool quit_posted; @@ -42,13 +43,14 @@ namespace System.Windows.Forms.X11Internal { bool need_dispatch_idle = true; object lockobj = new object (); - static readonly int InitialXEventSize = 100; - static readonly int InitialPaintSize = 50; + static readonly int InitialXEventQueueSize = 128; + static readonly int InitialHwndQueueSize = 50; public X11ThreadQueue (Thread thread) { - xqueue = new XQueue (InitialXEventSize); - paint_queue = new PaintQueue(InitialPaintSize); + xqueue = new XEventQueue (InitialXEventQueueSize); + paint_queue = new PaintQueue (InitialHwndQueueSize); + configure_queue = new ConfigureQueue (InitialHwndQueueSize); timer_list = new ArrayList (); this.thread = thread; this.quit_posted = false; @@ -65,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); @@ -77,60 +98,112 @@ 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) { - xevent = paint_queue.Dequeue (); - return true; + 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 RemovePaint (Hwnd hwnd) { - lock (lockobj) { - paint_queue.Remove (hwnd); - } + paint_queue.Remove (hwnd); } public void AddPaint (Hwnd hwnd) { - lock (lockobj) { - Console.WriteLine ("adding paint event"); - paint_queue.Enqueue (hwnd); - // wake up any thread blocking in DequeueUnlocked - Monitor.PulseAll (lockobj); - } + paint_queue.Enqueue (hwnd); + } + + public void AddConfigure (Hwnd hwnd) + { + configure_queue.Enqueue (hwnd); + } + + public ConfigureQueue Configure { + get { return configure_queue; } + } + + public PaintQueue Paint { + get { return paint_queue; } } public void Lock () @@ -146,26 +219,24 @@ namespace System.Windows.Forms.X11Internal { private int NextTimeout () { int timeout = Int32.MaxValue; - DateTime now = DateTime.Now; + DateTime now = DateTime.UtcNow; foreach (Timer timer in timer_list) { int next = (int) (timer.Expires - now).TotalMilliseconds; - if (next < 0) { + if (next < 0) return 0; // Have a timer that has already expired - } - if (next < timeout) { + if (next < timeout) timeout = next; - } } + if (timeout < Timer.Minimum) { timeout = Timer.Minimum; } -#if false - if (timeout > 1000) - timeout = 1000; -#endif + if (timeout == Int32.MaxValue) + timeout = Timeout.Infinite; + return timeout; } @@ -236,12 +307,17 @@ namespace System.Windows.Forms.X11Internal { set { quit_posted = value; } } - public class PaintQueue { - - private ArrayList hwnds; - - public PaintQueue (int size) { - hwnds = new ArrayList(size); + public abstract class HwndEventQueue { + protected ArrayList hwnds; +#if DebugHwndEventQueue + protected ArrayList stacks; +#endif + public HwndEventQueue (int size) + { + hwnds = new ArrayList (size); +#if DebugHwndEventQueue + stacks = new ArrayList (size); +#endif } public int Count { @@ -250,67 +326,123 @@ 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 (!hwnd.expose_pending && !hwnd.nc_expose_pending) { - hwnds.Remove(hwnd); - } +#if DebugHwndEventQueue + int index = hwnds.IndexOf(hwnd); + if (index != -1) + stacks.RemoveAt(index); +#endif + hwnds.Remove(hwnd); } - public XEvent Peek () + protected abstract XEvent Peek (); + + public virtual XEvent Dequeue () { if (hwnds.Count == 0) throw new Exception ("Attempt to dequeue empty queue."); - Hwnd hwnd = (Hwnd)hwnds[0]; + return Peek (); + } + } + + + public class ConfigureQueue : HwndEventQueue + { + public ConfigureQueue (int size) : base (size) + { + } + + protected override XEvent Peek () + { + X11Hwnd hwnd = (X11Hwnd)hwnds[0]; XEvent xevent = new XEvent (); + xevent.AnyEvent.type = XEventName.ConfigureNotify; + + xevent.ConfigureEvent.window = hwnd.ClientWindow; + xevent.ConfigureEvent.x = hwnd.X; + xevent.ConfigureEvent.y = hwnd.Y; + xevent.ConfigureEvent.width = hwnd.Width; + xevent.ConfigureEvent.height = hwnd.Height; + + 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 + { + public PaintQueue (int size) : base (size) + { + } + + protected override XEvent Peek () + { + X11Hwnd hwnd = (X11Hwnd)hwnds[0]; + + XEvent xevent = new XEvent (); + xevent.AnyEvent.type = XEventName.Expose; - if (hwnd.expose_pending) { - xevent.ExposeEvent.window = hwnd.client_window; - return xevent; + if (hwnd.PendingExpose) { + xevent.ExposeEvent.window = hwnd.ClientWindow; } else { - xevent.ExposeEvent.window = hwnd.whole_window; + xevent.ExposeEvent.window = hwnd.WholeWindow; xevent.ExposeEvent.x = hwnd.nc_invalid.X; xevent.ExposeEvent.y = hwnd.nc_invalid.Y; xevent.ExposeEvent.width = hwnd.nc_invalid.Width; xevent.ExposeEvent.height = hwnd.nc_invalid.Height; - return xevent; } - } - - public XEvent Dequeue () - { - if (hwnds.Count == 0) - throw new Exception ("Attempt to dequeue empty queue."); - - // populate the xevent - XEvent xevent = Peek (); - - Hwnd hwnd = (Hwnd)hwnds[0]; - - // We only remove the event from the queue if we have one expose left since - // a single entry in our queue may be for both NC and Client exposed - if ( !(hwnd.nc_expose_pending && hwnd.expose_pending)) - hwnds.RemoveAt(0); return xevent; } + + // don't override Dequeue like ConfigureQueue does. } - private class XQueue { + /* a circular queue for holding X events for processing by GetMessage */ + private class XEventQueue { - private XEvent [] xevents; - private int head; - private int tail; - private int size; + XEvent[] xevents; + int head; + int tail; + int size; - public XQueue (int initial_size) + public XEventQueue (int initial_size) { + if (initial_size % 2 != 0) + throw new Exception ("XEventQueue must be a power of 2 size"); + xevents = new XEvent [initial_size]; } @@ -322,9 +454,9 @@ namespace System.Windows.Forms.X11Internal { { if (size == xevents.Length) Grow (); - + xevents [tail] = xevent; - tail = (tail + 1) % xevents.Length; + tail = (tail + 1) & (xevents.Length - 1); size++; } @@ -334,7 +466,7 @@ namespace System.Windows.Forms.X11Internal { throw new Exception ("Attempt to dequeue empty queue."); XEvent res = xevents [head]; - head = (head + 1) % xevents.Length; + head = (head + 1) & (xevents.Length - 1); size--; return res; } @@ -351,7 +483,15 @@ namespace System.Windows.Forms.X11Internal { { int newcap = (xevents.Length * 2); XEvent [] na = new XEvent [newcap]; - xevents.CopyTo (na, 0); + + if (head + size > xevents.Length) { + Array.Copy (xevents, head, na, 0, xevents.Length - head); + Array.Copy (xevents, 0, na, xevents.Length - head, head + size - xevents.Length); + } + else { + Array.Copy (xevents, head, na, 0, size); + } + xevents = na; head = 0; tail = head + size;