Merge pull request #2218 from mono/assignProjectConfigurtionFix
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / XEventQueue.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2006 Novell, Inc.
21 //
22 // System.Windows.Forms.XEventQueue
23 //
24 // Authors:
25 //  Jackson Harper (jackson@ximian.com)
26 //  Peter Dennis Bartok (pbartok@novell.com)
27 //
28
29 using System;
30 using System.Threading;
31 using System.Collections;
32
33 namespace System.Windows.Forms {
34
35         internal class XEventQueue {
36
37                 private XQueue          xqueue;
38                 private XQueue          lqueue; // Events inserted from threads other then the main X thread
39                 private PaintQueue      paint;  // Paint-only queue
40                 internal ArrayList      timer_list;
41                 private Thread          thread;
42                 private bool            dispatch_idle;
43
44                 private static readonly int InitialXEventSize = 100;
45                 private static readonly int InitialLXEventSize = 10;
46                 private static readonly int InitialPaintSize = 50;
47
48                 public XEventQueue (Thread thread) {
49                         xqueue = new XQueue (InitialXEventSize);
50                         lqueue = new XQueue (InitialLXEventSize);
51                         paint = new PaintQueue(InitialPaintSize);
52                         timer_list = new ArrayList ();
53                         this.thread = thread;
54                         this.dispatch_idle = true;
55                 }
56
57                 public int Count {
58                         get {
59                                 lock (lqueue) {
60                                         return xqueue.Count + lqueue.Count;
61                                 }
62                         }
63                 }
64
65                 public PaintQueue Paint {
66                         get {
67                                 return paint;
68                         }
69                 }
70
71                 public Thread Thread {
72                         get {
73                                 return thread;
74                         }
75                 }
76
77                 public void Enqueue (XEvent xevent)
78                 {
79                         if (Thread.CurrentThread != thread) {
80                                 Console.WriteLine ("Hwnd.Queue.Enqueue called from a different thread without locking.");
81                                 Console.WriteLine (Environment.StackTrace);
82                         }
83
84                         xqueue.Enqueue (xevent);
85                 }
86
87                 public void EnqueueLocked (XEvent xevent)
88                 {
89                         lock (lqueue) {
90                                 lqueue.Enqueue (xevent);
91                         }
92                 }
93
94                 public XEvent Dequeue ()
95                 {
96                         if (Thread.CurrentThread != thread) {
97                                 Console.WriteLine ("Hwnd.Queue.Dequeue called from a different thread without locking.");
98                                 Console.WriteLine (Environment.StackTrace);
99                         }
100
101                         if (xqueue.Count == 0) {
102                                 lock (lqueue) {
103                                         return lqueue.Dequeue ();
104                                 }
105                         }
106                         return xqueue.Dequeue ();
107                 }
108
109                 public XEvent Peek()
110                 {
111                         if (Thread.CurrentThread != thread) {
112                                 Console.WriteLine ("Hwnd.Queue.Peek called from a different thread without locking.");
113                                 Console.WriteLine (Environment.StackTrace);
114                         }
115
116                         if (xqueue.Count == 0) {
117                                 lock (lqueue) {
118                                         return lqueue.Peek ();
119                                 }
120                         }                               
121                         return xqueue.Peek ();
122                 }
123
124                 public bool DispatchIdle {
125                         get {
126                                 return dispatch_idle;
127                         }
128                         set {
129                                 dispatch_idle = value;
130                         }
131                 }
132
133                 public class PaintQueue {
134
135                         private ArrayList       hwnds;
136                         private XEvent          xevent;
137                         
138                         public PaintQueue (int size) {
139                                 hwnds = new ArrayList (size);
140                                 xevent = new XEvent ();
141                                 xevent.AnyEvent.type = XEventName.Expose;
142                         }
143
144                         public int Count {
145                                 get {
146                                         lock (hwnds) {
147                                                 return hwnds.Count;
148                                         }
149                                 }
150                         }
151
152                         public void Enqueue (Hwnd hwnd) {
153                                 lock (hwnds) {
154                                         hwnds.Add (hwnd);
155                                 }
156                         }
157
158                         public void Remove(Hwnd hwnd) {
159                                 if (!hwnd.expose_pending && !hwnd.nc_expose_pending) {
160                                         lock (hwnds) {
161                                                 hwnds.Remove (hwnd);
162                                         }
163                                 }
164                         }
165
166                         public XEvent Dequeue () {
167                                 Hwnd            hwnd;
168                                 IEnumerator     next;
169
170                                 lock (hwnds) {
171                                         if (hwnds.Count == 0) {
172                                                 xevent.ExposeEvent.window = IntPtr.Zero;
173                                                 return xevent;
174                                         }
175
176                                         next = hwnds.GetEnumerator ();
177                                         next.MoveNext ();
178                                         hwnd = (Hwnd)next.Current;
179
180                                         // We only remove the event from the queue if we have one expose left since
181                                         // a single 'entry in our queue may be for both NC and Client exposed
182                                         if (!(hwnd.nc_expose_pending && hwnd.expose_pending)) {
183                                                 hwnds.Remove (hwnd);
184                                         }
185                                         if (hwnd.expose_pending) {
186                                                 xevent.ExposeEvent.window = hwnd.client_window;
187 #if not
188                                                 xevent.ExposeEvent.x = hwnd.invalid.X;
189                                                 xevent.ExposeEvent.y = hwnd.invalid.Y;
190                                                 xevent.ExposeEvent.width = hwnd.invalid.Width;
191                                                 xevent.ExposeEvent.height = hwnd.invalid.Height;
192 #endif
193                                                 return xevent;
194                                         } else {
195                                                 xevent.ExposeEvent.window = hwnd.whole_window;
196                                                 xevent.ExposeEvent.x = hwnd.nc_invalid.X;
197                                                 xevent.ExposeEvent.y = hwnd.nc_invalid.Y;
198                                                 xevent.ExposeEvent.width = hwnd.nc_invalid.Width;
199                                                 xevent.ExposeEvent.height = hwnd.nc_invalid.Height;
200                                                 return xevent;
201                                         }
202                                 }
203                         }
204                 }
205
206                 private class XQueue {
207
208                         private XEvent [] xevents;
209                         private int head;
210                         private int tail;
211                         private int size;
212                         
213                         public XQueue (int size)
214                         {
215                                 xevents = new XEvent [size];
216                         }
217
218                         public int Count {
219                                 get { return size; }
220                         }
221
222                         public void Enqueue (XEvent xevent)
223                         {
224                                 if (size == xevents.Length)
225                                         Grow ();
226                                 
227                                 xevents [tail] = xevent;
228                                 tail = (tail + 1) % xevents.Length;
229                                 size++;
230                         }
231
232                         public XEvent Dequeue ()
233                         {
234                                 if (size < 1)
235                                         throw new Exception ("Attempt to dequeue empty queue.");
236                                 XEvent res = xevents [head];
237                                 head = (head + 1) % xevents.Length;
238                                 size--;
239                                 return res;
240                         }
241
242                         public XEvent Peek() {
243                                 if (size < 1) {
244                                         throw new Exception ("Attempt to peek at empty queue");
245                                 }
246                                 return xevents[head];
247                         }
248
249                         private void Grow ()
250                         {
251                                 int newcap = (xevents.Length * 2);
252                                 XEvent [] na = new XEvent [newcap];
253                                 xevents.CopyTo (na, 0);
254                                 xevents = na;
255                                 head = 0;
256                                 tail = head + size;
257                         }
258                 }
259         }
260 }
261