| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- // Copyright (c) 2004-2006 Novell, Inc.
- //
- // Authors:
- // Jackson Harper ([email protected])
- // Peter Dennis Bartok ([email protected])
- // Chris Toshok ([email protected])
- //
- using System;
- using System.Threading;
- using System.Collections;
- namespace System.Windows.Forms.X11Internal {
- internal class X11ThreadQueue {
- XEventQueue xqueue;
- PaintQueue paint_queue;
- ConfigureQueue configure_queue;
- ArrayList timer_list;
- Thread thread;
- bool quit_posted;
- bool dispatch_idle;
- bool need_dispatch_idle = true;
- object lockobj = new object ();
- static readonly int InitialXEventQueueSize = 128;
- static readonly int InitialHwndQueueSize = 50;
- public X11ThreadQueue (Thread thread)
- {
- 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;
- this.dispatch_idle = true;
- }
- public int CountUnlocked {
- get { return xqueue.Count + paint_queue.Count; }
- }
- public Thread Thread {
- get { return thread; }
- }
- 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);
- }
- public void Enqueue (XEvent xevent)
- {
- lock (lockobj) {
- EnqueueUnlocked (xevent);
- }
- }
- public bool Dequeue (out XEvent xevent)
- {
- StartOver:
- bool got_xevent = false;
- lock (lockobj) {
- if (xqueue.Count > 0) {
- got_xevent = true;
- xevent = xqueue.Dequeue ();
- }
- else
- xevent = new XEvent (); /* not strictly needed, but mcs complains */
- }
- 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;
- }
- lock (lockobj) {
- 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)
- {
- paint_queue.Remove (hwnd);
- }
- public void AddPaint (Hwnd hwnd)
- {
- 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 ()
- {
- Monitor.Enter (lockobj);
- }
- public void Unlock ()
- {
- Monitor.Exit (lockobj);
- }
- private int NextTimeout ()
- {
- int timeout = Int32.MaxValue;
- DateTime now = DateTime.UtcNow;
- foreach (Timer timer in timer_list) {
- int next = (int) (timer.Expires - now).TotalMilliseconds;
- if (next < 0)
- return 0; // Have a timer that has already expired
- if (next < timeout)
- timeout = next;
- }
- if (timeout < Timer.Minimum) {
- timeout = Timer.Minimum;
- }
- if (timeout == Int32.MaxValue)
- timeout = Timeout.Infinite;
- return timeout;
- }
- public void CheckTimers ()
- {
- int count;
- DateTime now = DateTime.UtcNow;
- count = timer_list.Count;
- if (count == 0)
- return;
- for (int i = 0; i < timer_list.Count; i++) {
- Timer timer;
- timer = (Timer) timer_list [i];
- if (timer.Enabled && timer.Expires <= now) {
- timer.Update (now);
- timer.FireTick ();
- }
- }
- }
- public void SetTimer (Timer timer)
- {
- lock (lockobj) {
- timer_list.Add (timer);
- // we need to wake up any thread waiting in DequeueUnlocked,
- // since it might need to wait for a different amount of time.
- Monitor.PulseAll (lockobj);
- }
- }
- public void KillTimer (Timer timer)
- {
- lock (lockobj) {
- timer_list.Remove (timer);
- // we need to wake up any thread waiting in DequeueUnlocked,
- // since it might need to wait for a different amount of time.
- Monitor.PulseAll (lockobj);
- }
- }
- public event EventHandler Idle;
- public void OnIdle (EventArgs e)
- {
- if (Idle != null)
- Idle (thread, e);
- }
- public bool NeedDispatchIdle {
- get { return need_dispatch_idle; }
- set { need_dispatch_idle = value; }
- }
- public bool DispatchIdle {
- get { return dispatch_idle; }
- set { dispatch_idle = value; }
- }
- public bool PostQuitState {
- get { return quit_posted; }
- set { quit_posted = value; }
- }
- 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 {
- get { return hwnds.Count; }
- }
- 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 virtual XEvent Dequeue ()
- {
- if (hwnds.Count == 0)
- throw new Exception ("Attempt to dequeue empty queue.");
- 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.PendingExpose) {
- xevent.ExposeEvent.window = hwnd.ClientWindow;
- } else {
- 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;
- }
- // don't override Dequeue like ConfigureQueue does.
- }
- /* a circular queue for holding X events for processing by GetMessage */
- private class XEventQueue {
- XEvent[] xevents;
- int head;
- int tail;
- int 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];
- }
- public int Count {
- get { return size; }
- }
- public void Enqueue (XEvent xevent)
- {
- if (size == xevents.Length)
- Grow ();
- xevents [tail] = xevent;
- tail = (tail + 1) & (xevents.Length - 1);
- size++;
- }
- public XEvent Dequeue ()
- {
- if (size < 1)
- throw new Exception ("Attempt to dequeue empty queue.");
- XEvent res = xevents [head];
- head = (head + 1) & (xevents.Length - 1);
- size--;
- return res;
- }
- public XEvent Peek()
- {
- if (size < 1)
- throw new Exception ("Attempt to peek at empty queue.");
- return xevents[head];
- }
- private void Grow ()
- {
- int newcap = (xevents.Length * 2);
- XEvent [] na = new XEvent [newcap];
- 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;
- }
- }
- }
- }
|