Merge pull request #1612 from esdrubal/socketsh
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms.X11Internal / X11Display.cs
1 // a copy of this software and associated documentation files (the
2 // "Software"), to deal in the Software without restriction, including
3 // without limitation the rights to use, copy, modify, merge, publish,
4 // distribute, sublicense, and/or sell copies of the Software, and to
5 // permit persons to whom the Software is furnished to do so, subject to
6 // the following conditions:
7 // 
8 // The above copyright notice and this permission notice shall be
9 // included in all copies or substantial portions of the Software.
10 // 
11 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
15 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
16 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
17 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 //
19 // Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
20 //
21 //
22
23 using System;
24 using System.Collections;
25 using System.Diagnostics;
26 using System.Drawing;
27 using System.Drawing.Drawing2D;
28 using System.Drawing.Imaging;
29 using System.IO;
30 using System.Net;
31 using System.Net.Sockets;
32 using System.Reflection;
33 using System.Runtime.InteropServices;
34 using System.Text;
35 using System.Threading;
36 using System.Windows.Forms;
37 // Only do the poll when building with mono for now
38 #if __MonoCS__
39 using Mono.Unix.Native;
40 #endif
41
42 namespace System.Windows.Forms.X11Internal {
43
44         internal class X11Display {
45
46                 IntPtr display; /* our X handle */
47
48                 // XXX internal because X11Hwnd needs them
49                 internal IntPtr CustomVisual;    // Visual for window creation
50                 internal IntPtr CustomColormap;  // Colormap for window creation
51
52                 X11Keyboard Keyboard;
53                 internal X11Dnd Dnd; // XXX X11Hwnd needs it to enable Dnd
54                 bool detectable_key_auto_repeat;
55
56                 X11Atoms atoms;
57                 X11RootHwnd root_hwnd;
58                 X11Hwnd foster_hwnd;
59
60                 // Clipboard
61                 IntPtr          ClipMagic;
62                 ClipboardStruct Clipboard; // Our clipboard
63
64                 // Focus tracking
65                 internal X11Hwnd ActiveWindow;
66                 X11Hwnd FocusWindow;
67
68                 // Modality support
69                 Stack ModalWindows; // Stack of our modal windows
70
71                 // Caret
72                 CaretStruct Caret;
73
74                 // mouse hover message generation
75                 // XXX internal because X11Atoms needs to access it..
76                 internal HoverStruct HoverState;
77
78                 // double click message generation
79                 ClickStruct ClickPending;
80                 int DoubleClickInterval; // msec; max interval between clicks to count as double click
81
82                 // Support for mouse grab
83                 GrabStruct Grab;
84
85                 // Cursors
86                 IntPtr LastCursorWindow; // The last window we set the cursor on
87                 IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
88                 IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
89
90                 // State
91                 Point MousePosition;     // Last position of mouse, in screen coords
92                 MouseButtons MouseState; // Last state of mouse buttons
93
94                 XErrorHandler   ErrorHandler;           // Error handler delegate
95                 bool            ErrorExceptions;        // Throw exceptions on X errors
96
97                 Thread event_thread; // the background thread that just watches our X socket
98
99 #if __MonoCS__
100                 Pollfd[] pollfds;
101 #endif
102
103                 public X11Display (IntPtr display)
104                 {
105                         if (display == IntPtr.Zero) {
106                                 throw new ArgumentNullException("Display",
107                                                         "Could not open display (X-Server required. Check your DISPLAY environment variable)");
108                         }
109
110                         this.display = display;
111
112                         // Debugging support
113                         if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
114                                 Xlib.XSynchronize (display, true);
115                         }
116
117                         if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
118                                 ErrorExceptions = true;
119                         }
120
121                         atoms = new X11Atoms (this);
122
123                         DoubleClickInterval = 500;
124
125                         HoverState.Interval = 500;
126                         HoverState.Timer = new Timer();
127                         HoverState.Timer.Enabled = false;
128                         HoverState.Timer.Interval = HoverState.Interval;
129                         HoverState.Timer.Tick += new EventHandler(MouseHover);
130                         HoverState.Size = new Size(4, 4);
131                         HoverState.X = -1;
132                         HoverState.Y = -1;
133
134                         ActiveWindow = null;
135                         FocusWindow = null;
136                         ModalWindows = new Stack(3);
137
138                         MouseState = MouseButtons.None;
139                         MousePosition = new Point(0, 0);
140
141                         Caret.Timer = new Timer();
142                         Caret.Timer.Interval = 500;             // FIXME - where should this number come from?
143                         Caret.Timer.Tick += new EventHandler(CaretCallback);
144
145                         // XXX multiscreen work here
146                         root_hwnd = new X11RootHwnd (this, Xlib.XRootWindow (display, DefaultScreen));
147
148                         // XXX do we need a per-screen foster parent?
149                         // Create the foster parent
150                         foster_hwnd = new X11Hwnd (this,
151                                                    Xlib.XCreateSimpleWindow (display, root_hwnd.WholeWindow,
152                                                                              0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero));
153
154 #if __MonoCS__
155                         pollfds = new Pollfd [1];
156                         pollfds [0] = new Pollfd ();
157                         pollfds [0].fd = Xlib.XConnectionNumber (display);
158                         pollfds [0].events = PollEvents.POLLIN;
159 #endif
160
161                         Keyboard = new X11Keyboard(display, foster_hwnd.Handle);
162                         Dnd = new X11Dnd (display, Keyboard);
163
164                         ErrorExceptions = false;
165
166                         // Handle any upcoming errors
167                         ErrorHandler = new XErrorHandler (HandleError);
168                         Xlib.XSetErrorHandler (ErrorHandler);
169
170                         X11DesktopColors.Initialize(); // XXX we need to figure out how to make this display specific?
171
172                         // Disable keyboard autorepeat
173                         try {
174                                 Xlib.XkbSetDetectableAutoRepeat (display, true, IntPtr.Zero);
175                                 detectable_key_auto_repeat = true;
176                         } catch {
177                                 Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually.");
178                                 detectable_key_auto_repeat = false;
179                         }
180
181                         // we re-set our error handler here, X11DesktopColor stuff might have stolen it (gtk does)
182                         Xlib.XSetErrorHandler (ErrorHandler);
183
184                         // create our event thread (just sits on the X socket waiting for events)
185                         event_thread = new Thread (new ThreadStart (XEventThread));
186                         event_thread.IsBackground = true;
187                         event_thread.Start ();
188                 }
189
190                 #region Callbacks
191                 private void MouseHover(object sender, EventArgs e)
192                 {
193                         HoverState.Timer.Enabled = false;
194
195                         if (HoverState.Window != IntPtr.Zero) {
196                                 X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (HoverState.Window);
197                                 if (hwnd != null) {
198                                         XEvent xevent = new XEvent ();
199
200                                         xevent.type = XEventName.ClientMessage;
201                                         xevent.ClientMessageEvent.display = display;
202                                         xevent.ClientMessageEvent.window = HoverState.Window;
203                                         xevent.ClientMessageEvent.message_type = HoverState.Atom;
204                                         xevent.ClientMessageEvent.format = 32;
205                                         xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
206
207                                         hwnd.Queue.Enqueue (xevent);
208                                 }
209                         }
210                 }
211
212                 private void CaretCallback (object sender, EventArgs e)
213                 {
214                         if (Caret.Paused) {
215                                 return;
216                         }
217                         Caret.On = !Caret.On;
218
219                         Xlib.XDrawLine (display, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
220                 }
221
222                 internal string WhereString ()
223                 {
224                         StackTrace      stack;
225                         StackFrame      frame;
226                         string          newline;
227                         string          unknown;
228                         StringBuilder   sb;
229                         MethodBase      method;
230
231                         newline = String.Format("{0}\t {1} ", Environment.NewLine, Locale.GetText("at"));
232                         unknown = Locale.GetText("<unknown method>");
233                         sb = new StringBuilder();
234                         stack = new StackTrace(true);
235
236                         for (int i = 0; i < stack.FrameCount; i++) {
237                                 frame = stack.GetFrame (i);
238                                 sb.Append(newline);
239
240                                 method = frame.GetMethod();
241                                 if (method != null) {
242                                         if (frame.GetFileLineNumber() != 0)
243                                                 sb.AppendFormat ("{0}.{1} () [{2}:{3}]",
244                                                                  method.DeclaringType.FullName, method.Name,
245                                                                  Path.GetFileName(frame.GetFileName()), frame.GetFileLineNumber());
246                                         else
247                                                 sb.AppendFormat ("{0}.{1} ()", method.DeclaringType.FullName, method.Name);
248                                 } else { 
249                                         sb.Append(unknown);
250                                 }
251                         }
252                         return sb.ToString();
253                 }
254
255                 private int HandleError (IntPtr display, ref XErrorEvent error_event)
256                 {
257                         if (ErrorExceptions)
258                                 throw new X11Exception (error_event.display, error_event.resourceid,
259                                                         error_event.serial, error_event.error_code,
260                                                         error_event.request_code, error_event.minor_code);
261                         else
262                                 Console.WriteLine ("X11 Error encountered: {0}{1}\n",
263                                                    X11Exception.GetMessage(error_event.display, error_event.resourceid,
264                                                                            error_event.serial, error_event.error_code,
265                                                                            error_event.request_code, error_event.minor_code),
266                                                    WhereString());
267                         return 0;
268                 }
269                 #endregion      // Callbacks
270
271                 private void ShowCaret()
272                 {
273                         if ((Caret.gc == IntPtr.Zero) || Caret.On) {
274                                 return;
275                         }
276                         Caret.On = true;
277
278                         Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
279                 }
280
281                 private void HideCaret()
282                 {
283                         if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
284                                 return;
285                         }
286                         Caret.On = false;
287
288                         Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
289                 }
290
291                 public void CaretVisible (IntPtr handle, bool visible)
292                 {
293                         if (Caret.Hwnd == handle) {
294                                 if (visible) {
295                                         if (!Caret.Visible) {
296                                                 Caret.Visible = true;
297                                                 ShowCaret();
298                                                 Caret.Timer.Start();
299                                         }
300                                 } else {
301                                         Caret.Visible = false;
302                                         Caret.Timer.Stop();
303                                         HideCaret();
304                                 }
305                         }
306                 }
307
308                 public void AudibleAlert ()
309                 {
310                         Xlib.XBell (display, 0);
311                 }
312
313                 public void Flush ()
314                 {
315                         Xlib.XFlush (display);
316                 }
317
318                 public void Close ()
319                 {
320                         // XXX shut down the event_thread
321                         Xlib.XCloseDisplay (display);
322                 }
323
324                 public IntPtr XGetParent(IntPtr handle)
325                 {
326                         IntPtr  Root;
327                         IntPtr  Parent;
328                         IntPtr  Children;
329                         int     ChildCount;
330
331                         Xlib.XQueryTree (display, handle, out Root, out Parent, out Children, out ChildCount);
332
333                         if (Children!=IntPtr.Zero) {
334                                 Xlib.XFree(Children);
335                         }
336
337                         return Parent;
338                 }
339
340                 public bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt)
341                 {
342                         IntPtr SystrayMgrWindow;
343
344                         Xlib.XGrabServer (display);
345                         SystrayMgrWindow = Xlib.XGetSelectionOwner (display, Atoms._NET_SYSTEM_TRAY_S);
346                         Xlib.XUngrabServer (display);
347
348                         if (SystrayMgrWindow != IntPtr.Zero) {
349                                 XSizeHints size_hints;
350                                 X11Hwnd hwnd;
351
352                                 hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
353 #if DriverDebug
354                                 Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}",
355                                                   hwnd.WholeWindow.ToInt32(), hwnd.ClientWindow.ToInt32());
356 #endif
357
358                                 // Oh boy.
359                                 if (hwnd.ClientWindow != hwnd.WholeWindow) {
360                                         Xlib.XDestroyWindow (display, hwnd.ClientWindow);
361                                         hwnd.ClientWindow = hwnd.WholeWindow;
362
363                                         try {
364                                                 hwnd.Queue.Lock ();
365
366                                                 /* by virtue of the way the tests are ordered when determining if it's PAINT
367                                                    or NCPAINT, ClientWindow == WholeWindow will always be PAINT.  So, if we're
368                                                    waiting on an nc_expose, drop it and remove the hwnd from the list (unless
369                                                    there's a pending expose). */
370                                                 hwnd.PendingNCExpose = false;
371                                         }
372                                         finally {
373                                                 hwnd.Queue.Unlock ();
374                                         }
375                                 }
376
377                                 size_hints = new XSizeHints();
378
379                                 size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
380
381                                 size_hints.min_width = 24;
382                                 size_hints.min_height = 24;
383                                 size_hints.max_width = 24;
384                                 size_hints.max_height = 24;
385                                 size_hints.base_width = 24;
386                                 size_hints.base_height = 24;
387
388                                 Xlib.XSetWMNormalHints (display, hwnd.WholeWindow, ref size_hints);
389
390                                 int[] atoms = new int[2];
391                                 atoms [0] = 1;                  // Version 1
392                                 atoms [1] = 1;                  // we want to be mapped
393
394                                 // This line cost me 3 days...
395                                 Xlib.XChangeProperty (display,
396                                                       hwnd.WholeWindow, Atoms._XEMBED_INFO, Atoms._XEMBED_INFO, 32,
397                                                       PropertyMode.Replace, atoms, 2);
398
399                                 // Need to pick some reasonable defaults
400                                 tt = new ToolTip();
401                                 tt.AutomaticDelay = 100;
402                                 tt.InitialDelay = 250;
403                                 tt.ReshowDelay = 250;
404                                 tt.ShowAlways = true;
405
406                                 if ((tip != null) && (tip != string.Empty)) {
407                                         tt.SetToolTip(Control.FromHandle(handle), tip);
408                                         tt.Active = true;
409                                 } else {
410                                         tt.Active = false;
411                                 }
412
413                                 SendNetClientMessage (SystrayMgrWindow,
414                                                       Atoms._NET_SYSTEM_TRAY_OPCODE,
415                                                       IntPtr.Zero,
416                                                       (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK,
417                                                       hwnd.WholeWindow);
418
419                                 return true;
420                         }
421
422                         tt = null;
423                         return false;
424                 }
425
426                 public bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt)
427                 {
428                         Control control;
429
430                         control = Control.FromHandle(handle);
431                         if (control != null && tt != null) {
432                                 tt.SetToolTip(control, tip);
433                                 tt.Active = true;
434                                 return true;
435                         } else {
436                                 return false;
437                         }
438                 }
439
440                 public void SystrayRemove(IntPtr handle, ref ToolTip tt)
441                 {
442 #if GTKSOCKET_SUPPORTS_REPARENTING
443                         X11Hwnd hwnd;
444
445                         hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
446
447                         /* in the XEMBED spec, it mentions 3 ways for a client window to break the protocol with the embedder.
448                          * 1. The embedder can unmap the window and reparent to the root window (we should probably handle this...)
449                          * 2. The client can reparent its window out of the embedder window.
450                          * 3. The client can destroy its window.
451                          *
452                          * this call to SetParent is case 2, but in
453                          * the spec it also mentions that gtk doesn't
454                          * support this at present.  Looking at HEAD
455                          * gtksocket-x11.c jives with this statement.
456                          *
457                          * so we can't reparent.  we have to destroy.
458                          */
459                         SetParent(hwnd.WholeWindow, FosterParent);
460 #else
461                         Control control = Control.FromHandle(handle);
462                         if (control is NotifyIcon.NotifyIconWindow)
463                                 ((NotifyIcon.NotifyIconWindow)control).InternalRecreateHandle ();
464 #endif
465
466                         // The caller can now re-dock it later...
467                         if (tt != null) {
468                                 tt.Dispose();
469                                 tt = null;
470                         }
471                 }
472
473                 public void ResetMouseHover (X11Hwnd hovering)
474                 {
475                         HoverState.Timer.Enabled = hovering != null;
476                         HoverState.X = MousePosition.X;
477                         HoverState.Y = MousePosition.Y;
478                         HoverState.Window = hovering == null ? IntPtr.Zero : hovering.Handle;
479                 }
480
481                 public void ShowCursor (bool show)
482                 {
483                         ;       // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
484                 }
485
486                 public void SetModal (X11Hwnd hwnd, bool Modal)
487                 {
488                         if (Modal) {
489                                 ModalWindows.Push(hwnd);
490                         } else {
491                                 // XXX do we need to pop until the
492                                 // hwnd is off the stack?  or just the
493                                 // most recently pushed hwnd?
494                                 if (ModalWindows.Contains(hwnd)) {
495                                         ModalWindows.Pop();
496                                 }
497
498                                 if (ModalWindows.Count > 0) {
499                                         X11Hwnd top_hwnd = (X11Hwnd)ModalWindows.Peek();
500                                         top_hwnd.Activate();
501                                 }
502                         }
503                 }
504
505                 public TransparencySupport SupportsTransparency ()
506                 {
507                         // compiz adds _NET_WM_WINDOW_OPACITY to _NET_SUPPORTED on the root window, check for that
508                         return ((IList)root_hwnd._NET_SUPPORTED).Contains (Atoms._NET_WM_WINDOW_OPACITY) ? TransparencySupport.GetSet : TransparencySupport.None;
509                 }
510
511                 public void SendAsyncMethod (AsyncMethodData method)
512                 {
513                         X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(method.Handle);
514                         XEvent xevent = new XEvent ();
515
516                         xevent.type = XEventName.ClientMessage;
517                         xevent.ClientMessageEvent.display = display;
518                         xevent.ClientMessageEvent.window = method.Handle;
519                         xevent.ClientMessageEvent.message_type = Atoms.AsyncAtom;
520                         xevent.ClientMessageEvent.format = 32;
521                         xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
522
523                         hwnd.Queue.Enqueue (xevent);
524                 }
525
526                 delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
527
528                 public IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam)
529                 {
530                         X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
531                         if (hwnd == null)
532                                 return IntPtr.Zero;
533
534                         if (hwnd.Queue.Thread != Thread.CurrentThread) {
535                                 AsyncMethodResult       result;
536                                 AsyncMethodData         data;
537
538                                 result = new AsyncMethodResult ();
539                                 data = new AsyncMethodData ();
540
541                                 data.Handle = hwnd.Handle;
542                                 data.Method = new WndProcDelegate (NativeWindow.WndProc);
543                                 data.Args = new object[] { hwnd.Handle, message, wParam, lParam };
544                                 data.Result = result;
545                                 
546                                 SendAsyncMethod (data);
547 #if DriverDebug || DriverDebugThreads
548                                 Console.WriteLine ("Sending {0} message across.", message);
549 #endif
550
551                                 return IntPtr.Zero;
552                         }
553                         else {
554                                 return NativeWindow.WndProc (hwnd.Handle, message, wParam, lParam);
555                         }
556                 }
557
558                 public int SendInput (IntPtr handle, Queue keys) {
559                         if (handle == IntPtr.Zero)
560                                 return 0;
561
562                         int count = keys.Count;
563                         Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
564
565                         while (keys.Count > 0) {
566                         
567                                 MSG msg = (MSG)keys.Dequeue();
568
569                                 XEvent xevent = new XEvent ();
570
571                                 xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
572                                 xevent.KeyEvent.display = display;
573
574                                 if (hwnd != null) {
575                                         xevent.KeyEvent.window = hwnd.whole_window;
576                                 } else {
577                                         xevent.KeyEvent.window = IntPtr.Zero;
578                                 }
579
580                                 xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
581
582                                 hwnd.Queue.EnqueueLocked (xevent);
583                         }
584                         return count;
585                 }
586
587                 // FIXME - I think this should just enqueue directly
588                 public bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam)
589                 {
590                         XEvent xevent = new XEvent ();
591                         X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
592
593                         xevent.type = XEventName.ClientMessage;
594                         xevent.ClientMessageEvent.display = display;
595
596                         if (hwnd != null) {
597                                 xevent.ClientMessageEvent.window = hwnd.WholeWindow;
598                         } else {
599                                 xevent.ClientMessageEvent.window = IntPtr.Zero;
600                         }
601
602                         xevent.ClientMessageEvent.message_type = Atoms.PostAtom;
603                         xevent.ClientMessageEvent.format = 32;
604                         xevent.ClientMessageEvent.ptr1 = handle;
605                         xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
606                         xevent.ClientMessageEvent.ptr3 = wparam;
607                         xevent.ClientMessageEvent.ptr4 = lparam;
608
609                         hwnd.Queue.Enqueue (xevent);
610
611                         return true;
612                 }
613
614                 public void SendNetWMMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
615                 {
616                         XEvent  xev;
617
618                         xev = new XEvent();
619                         xev.ClientMessageEvent.type = XEventName.ClientMessage;
620                         xev.ClientMessageEvent.send_event = true;
621                         xev.ClientMessageEvent.window = window;
622                         xev.ClientMessageEvent.message_type = message_type;
623                         xev.ClientMessageEvent.format = 32;
624                         xev.ClientMessageEvent.ptr1 = l0;
625                         xev.ClientMessageEvent.ptr2 = l1;
626                         xev.ClientMessageEvent.ptr3 = l2;
627
628                         Xlib.XSendEvent (display, root_hwnd.Handle, false,
629                                          new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
630                 }
631
632                 public void SendNetClientMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
633                 {
634                         XEvent  xev;
635
636                         xev = new XEvent();
637                         xev.ClientMessageEvent.type = XEventName.ClientMessage;
638                         xev.ClientMessageEvent.send_event = true;
639                         xev.ClientMessageEvent.window = window;
640                         xev.ClientMessageEvent.message_type = message_type;
641                         xev.ClientMessageEvent.format = 32;
642                         xev.ClientMessageEvent.ptr1 = l0;
643                         xev.ClientMessageEvent.ptr2 = l1;
644                         xev.ClientMessageEvent.ptr3 = l2;
645
646                         Xlib.XSendEvent (display, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev);
647                 }
648
649                 public bool TranslateMessage (ref MSG msg)
650                 {
651                         return Keyboard.TranslateMessage (ref msg);
652                 }
653
654                 public IntPtr DispatchMessage (ref MSG msg)
655                 {
656                         return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
657                 }
658
659                 private void QueryPointer (IntPtr w, out IntPtr root, out IntPtr child,
660                                            out int root_x, out int root_y, out int child_x, out int child_y,
661                                            out int mask)
662                 {
663                         /* this code was written with the help of
664                            glance at gdk.  I never would have realized we
665                            needed a loop in order to traverse down in the
666                            hierarchy.  I would have assumed you'd get the
667                            most deeply nested child and have to do
668                            XQueryTree to move back up the hierarchy..
669                            stupid me, of course. */
670                         IntPtr c;
671
672                         //                      Xlib.XGrabServer (display);
673
674                         Xlib.XQueryPointer (display, w, out root, out c,
675                                             out root_x, out root_y, out child_x, out child_y,
676                                             out mask);
677
678                         if (root != w)
679                                 c = root;
680
681                         IntPtr child_last = IntPtr.Zero;
682                         while (c != IntPtr.Zero) {
683                                 child_last = c;
684                                 Xlib.XQueryPointer (display, c, out root, out c,
685                                                     out root_x, out root_y, out child_x, out child_y,
686                                                     out mask);
687                         }
688
689                         //                      Xlib.XUngrabServer (display);
690
691                         child = child_last;
692                 }
693
694                 public void SetCursorPos (int x, int y)
695                 {
696                         IntPtr root, child;
697                         int root_x, root_y, child_x, child_y, mask;
698
699                         /* we need to do a
700                          * QueryPointer before warping
701                          * because if the warp is on
702                          * the RootWindow, the x/y are
703                          * relative to the current
704                          * mouse position
705                          */
706                         QueryPointer (RootWindow.Handle,
707                                       out root,
708                                       out child,
709                                       out root_x, out root_y,
710                                       out child_x, out child_y,
711                                       out mask);
712
713                         Xlib.XWarpPointer (display, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
714
715                         Xlib.XFlush (display);
716
717                         /* then we need to a
718                          * QueryPointer after warping
719                          * to manually generate a
720                          * motion event for the window
721                          * we move into.
722                          */
723                         QueryPointer (RootWindow.Handle,
724                                       out root,
725                                       out child,
726                                       out root_x, out root_y,
727                                       out child_x, out child_y,
728                                       out mask);
729
730                         X11Hwnd child_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(child);
731                         if (child_hwnd == null)
732                                 return;
733
734                         XEvent xevent = new XEvent ();
735
736                         xevent.type = XEventName.MotionNotify;
737                         xevent.MotionEvent.display = display;
738                         xevent.MotionEvent.window = child_hwnd.Handle;
739                         xevent.MotionEvent.root = RootWindow.Handle;
740                         xevent.MotionEvent.x = child_x;
741                         xevent.MotionEvent.y = child_y;
742                         xevent.MotionEvent.x_root = root_x;
743                         xevent.MotionEvent.y_root = root_y;
744                         xevent.MotionEvent.state = mask;
745
746                         child_hwnd.Queue.Enqueue (xevent);
747                 }
748
749                 public void SetFocus (X11Hwnd new_focus)
750                 {
751                         if (new_focus == FocusWindow)
752                                 return;
753
754                         X11Hwnd prev_focus = FocusWindow;
755                         FocusWindow = new_focus;
756
757                         if (prev_focus != null)
758                                 SendMessage (prev_focus.Handle, Msg.WM_KILLFOCUS,
759                                              FocusWindow == null ? IntPtr.Zero : FocusWindow.Handle, IntPtr.Zero);
760                         if (FocusWindow != null)
761                                 SendMessage (FocusWindow.Handle, Msg.WM_SETFOCUS,
762                                              prev_focus == null ? IntPtr.Zero : prev_focus.Handle, IntPtr.Zero);
763
764                         //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).ClientWindow, RevertTo.None, IntPtr.Zero);
765                 }
766
767                 public IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
768                 {
769                         IntPtr  cursor;
770                         Bitmap  cursor_bitmap;
771                         Bitmap  cursor_mask;
772                         Byte[]  cursor_bits;
773                         Byte[]  mask_bits;
774                         Color   c_pixel;
775                         Color   m_pixel;
776                         int     width;
777                         int     height;
778                         IntPtr  cursor_pixmap;
779                         IntPtr  mask_pixmap;
780                         XColor  fg;
781                         XColor  bg;
782                         bool    and;
783                         bool    xor;
784
785                         if (Xlib.XQueryBestCursor (display, RootWindow.Handle, bitmap.Width, bitmap.Height, out width, out height) == 0) {
786                                 return IntPtr.Zero;
787                         }
788
789                         // Win32 only allows creation cursors of a certain size
790                         if ((bitmap.Width != width) || (bitmap.Width != height)) {
791                                 cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
792                                 cursor_mask = new Bitmap(mask, new Size(width, height));
793                         } else {
794                                 cursor_bitmap = bitmap;
795                                 cursor_mask = mask;
796                         }
797
798                         width = cursor_bitmap.Width;
799                         height = cursor_bitmap.Height;
800
801                         cursor_bits = new Byte[(width / 8) * height];
802                         mask_bits = new Byte[(width / 8) * height];
803
804                         for (int y = 0; y < height; y++) {
805                                 for (int x = 0; x < width; x++) {
806                                         c_pixel = cursor_bitmap.GetPixel(x, y);
807                                         m_pixel = cursor_mask.GetPixel(x, y);
808
809                                         and = c_pixel == cursor_pixel;
810                                         xor = m_pixel == mask_pixel;
811
812                                         if (!and && !xor) {
813                                                 // Black
814                                                 // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));       // The bit already is 0
815                                                 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
816                                         } else if (and && !xor) {
817                                                 // White
818                                                 cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
819                                                 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
820 #if notneeded
821                                         } else if (and && !xor) {
822                                                 // Screen
823                                         } else if (and && xor) {
824                                                 // Inverse Screen
825
826                                                 // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
827                                                 // we want both to be 0 so nothing to be done
828                                                 //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
829                                                 //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
830 #endif
831                                         }
832                                 }
833                         }
834
835                         cursor_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle,
836                                                                           cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
837                         mask_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle,
838                                                                         mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
839                         fg = new XColor();
840                         bg = new XColor();
841
842                         fg.pixel = Xlib.XWhitePixel (display, DefaultScreen);
843                         fg.red = (ushort)65535;
844                         fg.green = (ushort)65535;
845                         fg.blue = (ushort)65535;
846
847                         bg.pixel = Xlib.XBlackPixel (display, DefaultScreen);
848
849                         cursor = Xlib.XCreatePixmapCursor (display, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
850
851                         Xlib.XFreePixmap (display, cursor_pixmap);
852                         Xlib.XFreePixmap (display, mask_pixmap);
853
854                         return cursor;
855                 }
856                 
857                 public Bitmap DefineStdCursorBitmap (StdCursor id)
858                 {
859                         CursorFontShape shape;
860                         string name;
861                         IntPtr theme;
862                         int size;
863                         Bitmap bmp = null;
864
865                         try {
866                                 shape = XplatUIX11.StdCursorToFontShape (id);
867                                 name = shape.ToString ().Replace ("XC_", string.Empty);
868                                 size = XplatUIX11.XcursorGetDefaultSize (Handle);
869                                 theme = XplatUIX11.XcursorGetTheme (Handle);
870                                 IntPtr images_ptr = XplatUIX11.XcursorLibraryLoadImages (name, theme, size);
871 #if debug
872                                 Console.WriteLine ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr);
873 #endif
874
875                                 if (images_ptr == IntPtr.Zero) {
876                                         return null;
877                                 }
878
879                                 XcursorImages images = (XcursorImages)Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
880 #if debug
881                                 Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
882 #endif
883
884                                 if (images.nimage > 0) {
885                                         // We only care about the first image.
886                                         XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
887
888 #if debug
889                                         Console.WriteLine ("DefineStdCursorBitmap, loaded image <size={0}, height={1}, width={2}, xhot={3}, yhot={4}, pixels={5}", image.size, image.height, image.width, image.xhot, image.yhot, image.pixels);
890 #endif
891                                         // A sanity check
892                                         if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
893                                                 int [] pixels = new int [image.width * image.height];
894                                                 Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
895                                                 bmp = new Bitmap (image.width, image.height);
896                                                 for (int w = 0; w < image.width; w++) {
897                                                         for (int h = 0; h < image.height; h++) {
898                                                                 bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
899                                                         }
900                                                 }
901                                         }
902                                 }
903
904                                 XplatUIX11.XcursorImagesDestroy (images_ptr);
905
906                         } catch (DllNotFoundException ex) {
907                                 Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
908                                 return null;
909                         }
910
911                         return bmp;
912                 }
913                 
914                 public IntPtr DefineStdCursor (StdCursor id)
915                 {
916                         CursorFontShape shape;
917
918                         // FIXME - define missing shapes
919
920                         switch (id) {
921                         case StdCursor.AppStarting:
922                                 shape = CursorFontShape.XC_watch;
923                                 break;
924
925                         case StdCursor.Arrow:
926                                 shape = CursorFontShape.XC_top_left_arrow;
927                                 break;
928
929                         case StdCursor.Cross:
930                                 shape = CursorFontShape.XC_crosshair;
931                                 break;
932
933                         case StdCursor.Default:
934                                 shape = CursorFontShape.XC_top_left_arrow;
935                                 break;
936
937                         case StdCursor.Hand:
938                                 shape = CursorFontShape.XC_hand1;
939                                 break;
940
941                         case StdCursor.Help:
942                                 shape = CursorFontShape.XC_question_arrow;
943                                 break;
944                         
945                         case StdCursor.HSplit:
946                                 shape = CursorFontShape.XC_sb_v_double_arrow; 
947                                 break;
948
949                         case StdCursor.IBeam:
950                                 shape = CursorFontShape.XC_xterm; 
951                                 break;
952
953                         case StdCursor.No:
954                                 shape = CursorFontShape.XC_circle; 
955                                 break;
956
957                         case StdCursor.NoMove2D:
958                                 shape = CursorFontShape.XC_fleur; 
959                                 break;
960
961                         case StdCursor.NoMoveHoriz:
962                                 shape = CursorFontShape.XC_fleur; 
963                                 break;
964
965                         case StdCursor.NoMoveVert:
966                                 shape = CursorFontShape.XC_fleur; 
967                                 break;
968
969                         case StdCursor.PanEast:
970                                 shape = CursorFontShape.XC_fleur; 
971                                 break;
972
973                         case StdCursor.PanNE:
974                                 shape = CursorFontShape.XC_fleur; 
975                                 break;
976
977                         case StdCursor.PanNorth:
978                                 shape = CursorFontShape.XC_fleur; 
979                                 break;
980
981                         case StdCursor.PanNW:
982                                 shape = CursorFontShape.XC_fleur; 
983                                 break;
984
985                         case StdCursor.PanSE:
986                                 shape = CursorFontShape.XC_fleur; 
987                                 break;
988
989                         case StdCursor.PanSouth:
990                                 shape = CursorFontShape.XC_fleur; 
991                                 break;
992
993                         case StdCursor.PanSW:
994                                 shape = CursorFontShape.XC_fleur; 
995                                 break;
996
997                         case StdCursor.PanWest:
998                                 shape = CursorFontShape.XC_sizing; 
999                                 break;
1000
1001                         case StdCursor.SizeAll:
1002                                 shape = CursorFontShape.XC_fleur; 
1003                                 break;
1004
1005                         case StdCursor.SizeNESW:
1006                                 shape = CursorFontShape.XC_top_right_corner; 
1007                                 break;
1008
1009                         case StdCursor.SizeNS:
1010                                 shape = CursorFontShape.XC_sb_v_double_arrow;
1011                                 break;
1012
1013                         case StdCursor.SizeNWSE:
1014                                 shape = CursorFontShape.XC_top_left_corner; 
1015                                 break;
1016
1017                         case StdCursor.SizeWE:
1018                                 shape = CursorFontShape.XC_sb_h_double_arrow; 
1019                                 break;
1020
1021                         case StdCursor.UpArrow:
1022                                 shape = CursorFontShape.XC_center_ptr; 
1023                                 break;
1024
1025                         case StdCursor.VSplit:
1026                                 shape = CursorFontShape.XC_sb_h_double_arrow;
1027                                 break;
1028
1029                         case StdCursor.WaitCursor:
1030                                 shape = CursorFontShape.XC_watch; 
1031                                 break;
1032
1033                         default:
1034                                 return IntPtr.Zero;
1035                         }
1036
1037                         return Xlib.XCreateFontCursor (display, shape);
1038                 }
1039
1040                 // XXX this should take an X11Hwnd.
1041                 public void CreateCaret (IntPtr handle, int width, int height)
1042                 {
1043                         XGCValues gc_values;
1044                         X11Hwnd hwnd;
1045
1046                         hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
1047
1048                         if (Caret.Hwnd != IntPtr.Zero)
1049                                 DestroyCaret(Caret.Hwnd);
1050
1051                         Caret.Hwnd = handle;
1052                         Caret.Window = hwnd.ClientWindow;
1053                         Caret.Width = width;
1054                         Caret.Height = height;
1055                         Caret.Visible = false;
1056                         Caret.On = false;
1057
1058                         gc_values = new XGCValues();
1059                         gc_values.line_width = width;
1060
1061                         Caret.gc = Xlib.XCreateGC (display, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
1062                         if (Caret.gc == IntPtr.Zero) {
1063                                 Caret.Hwnd = IntPtr.Zero;
1064                                 return;
1065                         }
1066
1067                         Xlib.XSetFunction (display, Caret.gc, GXFunction.GXinvert);
1068                 }
1069
1070
1071                 // XXX this should take an X11Hwnd.
1072                 public void DestroyCaret (IntPtr handle)
1073                 {
1074                         if (Caret.Hwnd == handle) {
1075                                 if (Caret.Visible == true) {
1076                                         Caret.Timer.Stop ();
1077                                 }
1078                                 if (Caret.gc != IntPtr.Zero) {
1079                                         Xlib.XFreeGC (display, Caret.gc);
1080                                         Caret.gc = IntPtr.Zero;
1081                                 }
1082                                 Caret.Hwnd = IntPtr.Zero;
1083                                 Caret.Visible = false;
1084                                 Caret.On = false;
1085                         }
1086                 }
1087
1088                 public void SetCaretPos (IntPtr handle, int x, int y)
1089                 {
1090                         if (Caret.Hwnd == handle) {
1091                                 Caret.Timer.Stop();
1092                                 HideCaret();
1093
1094                                 Caret.X = x;
1095                                 Caret.Y = y;
1096
1097                                 if (Caret.Visible == true) {
1098                                         ShowCaret();
1099                                         Caret.Timer.Start();
1100                                 }
1101                         }
1102                 }
1103
1104                 public void DestroyCursor (IntPtr cursor)
1105                 {
1106                         Xlib.XFreeCursor (display, cursor);
1107                 }
1108
1109                 private void AccumulateDestroyedHandles (Control c, ArrayList list)
1110                 {
1111                         if (c != null) {
1112                                 Control[] controls = c.Controls.GetAllControls ();
1113
1114                                 if (c.IsHandleCreated && !c.IsDisposed) {
1115                                         X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(c.Handle);
1116
1117 #if DriverDebug || DriverDebugDestroy
1118                                         Console.WriteLine (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
1119                                         Console.WriteLine (" + parent X window is {0:X}", XGetParent (hwnd.WholeWindow).ToInt32());
1120 #endif
1121
1122                                         list.Add (hwnd);
1123                                         CleanupCachedWindows (hwnd);
1124                                         hwnd.zombie = true;
1125                                 }
1126
1127                                 for (int  i = 0; i < controls.Length; i ++) {
1128                                         AccumulateDestroyedHandles (controls[i], list);
1129                                 }
1130                         }
1131                         
1132                 }
1133
1134                 void CleanupCachedWindows (X11Hwnd hwnd)
1135                 {
1136                         if (ActiveWindow == hwnd) {
1137                                 SendMessage (hwnd.ClientWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1138                                 ActiveWindow = null;
1139                         }
1140
1141                         if (FocusWindow == hwnd) {
1142                                 SendMessage (hwnd.ClientWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
1143                                 FocusWindow = null;
1144                         }
1145
1146                         if (Grab.Hwnd == hwnd.Handle) {
1147                                 Grab.Hwnd = IntPtr.Zero;
1148                                 Grab.Confined = false;
1149                         }
1150
1151                         DestroyCaret (hwnd.Handle);
1152                 }
1153
1154
1155                 public void DestroyWindow (X11Hwnd hwnd)
1156                 {
1157                         CleanupCachedWindows (hwnd);
1158
1159                         hwnd.SendParentNotify (Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
1160
1161                         ArrayList windows = new ArrayList ();
1162
1163                         AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
1164
1165                         hwnd.DestroyWindow ();
1166
1167                         foreach (X11Hwnd h in windows) {
1168                                 SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
1169                         }
1170                 }
1171
1172                 public X11Hwnd GetActiveWindow ()
1173                 {
1174                         IntPtr  actual_atom;
1175                         int     actual_format;
1176                         IntPtr  nitems;
1177                         IntPtr  bytes_after;
1178                         IntPtr  prop = IntPtr.Zero;
1179                         IntPtr  active = IntPtr.Zero;
1180
1181                         Xlib.XGetWindowProperty (display, RootWindow.Handle,
1182                                                  Atoms._NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false,
1183                                                  Atoms.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1184
1185                         if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
1186                                 active = (IntPtr)Marshal.ReadInt32(prop);
1187                                 Xlib.XFree(prop);
1188                         }
1189
1190                         return (X11Hwnd)Hwnd.GetObjectFromWindow(active);
1191                 }
1192
1193                 public void SetActiveWindow (X11Hwnd new_active_window)
1194                 {
1195                         if (new_active_window != ActiveWindow) {
1196                                 if (ActiveWindow != null)
1197                                         PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE,
1198                                                      (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1199
1200                                 ActiveWindow = new_active_window;
1201
1202                                 if (ActiveWindow != null)
1203                                         PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE,
1204                                                      (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
1205                         }
1206
1207                         if (ModalWindows.Count > 0) {
1208                                 // Modality handling, if we are modal and the new active window is one
1209                                 // of ours but not the modal one, switch back to the modal window
1210
1211                                 if (ActiveWindow != null &&
1212                                     NativeWindow.FromHandle (ActiveWindow.Handle) != null) {
1213                                         if (ActiveWindow != (X11Hwnd)ModalWindows.Peek())
1214                                                 ((X11Hwnd)ModalWindows.Peek()).Activate ();
1215                                 }
1216                         }
1217                 }
1218
1219                 public void GetDisplaySize (out Size size)
1220                 {
1221                         XWindowAttributes attributes = new XWindowAttributes();
1222
1223                         // FIXME - use _NET_WM messages instead?
1224                         Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
1225
1226                         size = new Size(attributes.width, attributes.height);
1227                 }
1228
1229                 // XXX this method doesn't really fit well anywhere in the backend
1230                 public SizeF GetAutoScaleSize (Font font)
1231                 {
1232                         Graphics        g;
1233                         float           width;
1234                         string          magic_string = "The quick brown fox jumped over the lazy dog.";
1235                         double          magic_number = 44.549996948242189; // XXX my god, where did this number come from?
1236
1237                         g = Graphics.FromHwnd (FosterParent.Handle);
1238
1239                         width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
1240                         return new SizeF(width, font.Height);
1241                 }
1242
1243                 public void GetCursorPos (X11Hwnd hwnd, out int x, out int y)
1244                 {
1245                         IntPtr  use_handle;
1246                         IntPtr  root;
1247                         IntPtr  child;
1248                         int     root_x;
1249                         int     root_y;
1250                         int     win_x;
1251                         int     win_y;
1252                         int     keys_buttons;
1253
1254                         if (hwnd != null)
1255                                 use_handle = hwnd.Handle;
1256                         else
1257                                 use_handle = RootWindow.Handle;
1258
1259                         QueryPointer (use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
1260
1261                         if (hwnd != null) {
1262                                 x = win_x;
1263                                 y = win_y;
1264                         } else {
1265                                 x = root_x;
1266                                 y = root_y;
1267                         }
1268                 }
1269
1270                 public IntPtr GetFocus ()
1271                 {
1272                         return FocusWindow.Handle;
1273                 }
1274
1275                 public IntPtr GetMousewParam (int Delta)
1276                 {
1277                         int     result = 0;
1278
1279                         if ((MouseState & MouseButtons.Left) != 0) {
1280                                 result |= (int)MsgButtons.MK_LBUTTON;
1281                         }
1282
1283                         if ((MouseState & MouseButtons.Middle) != 0) {
1284                                 result |= (int)MsgButtons.MK_MBUTTON;
1285                         }
1286
1287                         if ((MouseState & MouseButtons.Right) != 0) {
1288                                 result |= (int)MsgButtons.MK_RBUTTON;
1289                         }
1290
1291                         Keys mods = ModifierKeys;
1292                         if ((mods & Keys.Control) != 0) {
1293                                 result |= (int)MsgButtons.MK_CONTROL;
1294                         }
1295
1296                         if ((mods & Keys.Shift) != 0) {
1297                                 result |= (int)MsgButtons.MK_SHIFT;
1298                         }
1299
1300                         result |= Delta << 16;
1301
1302                         return (IntPtr)result;
1303                 }
1304
1305                 public void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea)
1306                 {
1307                         handle = Grab.Hwnd;
1308                         GrabConfined = Grab.Confined;
1309                         GrabArea = Grab.Area;
1310                 }
1311
1312                 public void GrabWindow (X11Hwnd hwnd, X11Hwnd confine_to)
1313                 {
1314                         IntPtr  confine_to_window;
1315
1316                         confine_to_window = IntPtr.Zero;
1317
1318                         if (confine_to != null) {
1319                                 Console.WriteLine (Environment.StackTrace);
1320
1321                                 XWindowAttributes attributes = new XWindowAttributes();
1322
1323                                 Xlib.XGetWindowAttributes (display, confine_to.ClientWindow, ref attributes);
1324
1325                                 Grab.Area.X = attributes.x;
1326                                 Grab.Area.Y = attributes.y;
1327                                 Grab.Area.Width = attributes.width;
1328                                 Grab.Area.Height = attributes.height;
1329                                 Grab.Confined = true;
1330                                 confine_to_window = confine_to.ClientWindow;
1331                         }
1332
1333                         Grab.Hwnd = hwnd.ClientWindow;
1334
1335                         Xlib.XGrabPointer (display, hwnd.ClientWindow, false, 
1336                                            EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
1337                                            EventMask.ButtonReleaseMask | EventMask.PointerMotionMask,
1338                                            GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
1339                 }
1340
1341                 public void UngrabWindow (X11Hwnd hwnd)
1342                 {
1343                         Xlib.XUngrabPointer (display, IntPtr.Zero);
1344                         Xlib.XFlush (display);
1345
1346                         // XXX make sure hwnd is what should have the grab and throw if not
1347                         Grab.Hwnd = IntPtr.Zero;
1348                         Grab.Confined = false;
1349                 }
1350
1351 #if notyet
1352                 private void TranslatePropertyToClipboard (IntPtr property)
1353                 {
1354                         IntPtr actual_atom;
1355                         int actual_format;
1356                         IntPtr nitems;
1357                         IntPtr bytes_after;
1358                         IntPtr prop = IntPtr.Zero;
1359
1360                         Clipboard.Item = null;
1361
1362                         Xlib.XGetWindowProperty (display, FosterParent.Handle,
1363                                                  property, IntPtr.Zero, new IntPtr (0x7fffffff), true,
1364                                                  Atoms.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1365
1366                         if ((long)nitems > 0) {
1367                                 if (property == Atoms.XA_STRING) {
1368                                         Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1369                                 } else if (property == Atoms.XA_BITMAP) {
1370                                         // FIXME - convert bitmap to image
1371                                 } else if (property == Atoms.XA_PIXMAP) {
1372                                         // FIXME - convert pixmap to image
1373                                 } else if (property == Atoms.OEMTEXT) {
1374                                         Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1375                                 } else if (property == Atoms.UNICODETEXT) {
1376                                         Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1377                                 }
1378
1379                                 Xlib.XFree(prop);
1380                         }
1381                 }
1382 #endif
1383
1384                 // XXX should we be using @handle instead of Atoms.CLIPBOARD here?
1385                 public int[] ClipboardAvailableFormats (IntPtr handle)
1386                 {
1387                         // XXX deal with the updatemessagequeue stuff
1388 #if true
1389                         return new int[0];
1390 #else
1391                         DataFormats.Format f;
1392                         int[] result;
1393
1394                         f = DataFormats.Format.List;
1395
1396                         if (Xlib.XGetSelectionOwner (display, Atoms.CLIPBOARD) == IntPtr.Zero) {
1397                                 return null;
1398                         }
1399
1400                         Clipboard.Formats = new ArrayList();
1401
1402                         while (f != null) {
1403                                 Xlib.XConvertSelection (display, Atoms.CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent.Handle, IntPtr.Zero);
1404
1405                                 Clipboard.Enumerating = true;
1406                                 while (Clipboard.Enumerating) {
1407                                         UpdateMessageQueue(null);
1408                                 }
1409                                 f = f.Next;
1410                         }
1411
1412                         result = new int[Clipboard.Formats.Count];
1413
1414                         for (int i = 0; i < Clipboard.Formats.Count; i++) {
1415                                 result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
1416                         }
1417
1418                         Clipboard.Formats = null;
1419                         return result;
1420 #endif
1421                 }
1422
1423                 public void ClipboardClose (IntPtr handle)
1424                 {
1425                         if (handle != ClipMagic) {
1426                                 throw new ArgumentException("handle is not a valid clipboard handle");
1427                         }
1428                         return;
1429                 }
1430
1431                 public int ClipboardGetID (IntPtr handle, string format)
1432                 {
1433                         if (handle != ClipMagic) {
1434                                 throw new ArgumentException("handle is not a valid clipboard handle");
1435                         }
1436
1437                         if (format == "Text" ) return Atoms.XA_STRING.ToInt32();
1438                         else if (format == "Bitmap" ) return Atoms.XA_BITMAP.ToInt32();
1439                         //else if (format == "MetaFilePict" ) return 3;
1440                         //else if (format == "SymbolicLink" ) return 4;
1441                         //else if (format == "DataInterchangeFormat" ) return 5;
1442                         //else if (format == "Tiff" ) return 6;
1443                         else if (format == "OEMText" ) return Atoms.OEMTEXT.ToInt32();
1444                         else if (format == "DeviceIndependentBitmap" ) return Atoms.XA_PIXMAP.ToInt32();
1445                         else if (format == "Palette" ) return Atoms.XA_COLORMAP.ToInt32();      // Useless
1446                         //else if (format == "PenData" ) return 10;
1447                         //else if (format == "RiffAudio" ) return 11;
1448                         //else if (format == "WaveAudio" ) return 12;
1449                         else if (format == "UnicodeText" ) return Atoms.UNICODETEXT.ToInt32();
1450                         //else if (format == "EnhancedMetafile" ) return 14;
1451                         //else if (format == "FileDrop" ) return 15;
1452                         //else if (format == "Locale" ) return 16;
1453
1454                         return Xlib.XInternAtom (display, format, false).ToInt32();
1455                 }
1456
1457                 public IntPtr ClipboardOpen (bool primary_selection)
1458                 {
1459                         if (!primary_selection)
1460                                 ClipMagic = Atoms.CLIPBOARD;
1461                         else
1462                                 ClipMagic = Atoms.PRIMARY;
1463
1464                         return ClipMagic;
1465                 }
1466
1467                 // XXX @converter?
1468                 public object ClipboardRetrieve (IntPtr handle, int type, XplatUI.ClipboardToObject converter)
1469                 {
1470                         // XXX deal with the UpdateMessageQueue stuff
1471 #if true
1472                         return null;
1473 #else
1474                         Xlib.XConvertSelection (display, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
1475
1476                         Clipboard.Retrieving = true;
1477                         while (Clipboard.Retrieving) {
1478                                 UpdateMessageQueue(null);
1479                         }
1480
1481                         return Clipboard.Item;
1482 #endif
1483                 }
1484
1485                 public void ClipboardStore (IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter)
1486                 {
1487                         Clipboard.Item = obj;
1488                         Clipboard.Type = type;
1489                         Clipboard.Converter = converter;
1490
1491                         if (obj != null) {
1492                                 Xlib.XSetSelectionOwner (display, Atoms.CLIPBOARD, FosterParent.Handle, IntPtr.Zero);
1493                         } else {
1494                                 // Clearing the selection
1495                                 Xlib.XSetSelectionOwner (display, Atoms.CLIPBOARD, IntPtr.Zero, IntPtr.Zero);
1496                         }
1497                 }
1498
1499
1500                 public PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client)
1501                 {
1502                         X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
1503
1504                         if (Caret.Visible == true) {
1505                                 Caret.Paused = true;
1506                                 HideCaret();
1507                         }
1508
1509                         return hwnd.PaintEventStart (ref m, client);
1510                 }
1511
1512                 public void PaintEventEnd (ref Message m, IntPtr handle, bool client)
1513                 {
1514                         X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
1515
1516                         hwnd.PaintEventEnd (ref m, client);
1517
1518                         if (Caret.Visible == true) {
1519                                 ShowCaret();
1520                                 Caret.Paused = false;
1521                         }
1522                 }
1523
1524                 public void SetCursor (IntPtr handle, IntPtr cursor)
1525                 {
1526                         Hwnd    hwnd;
1527
1528                         if (OverrideCursorHandle == IntPtr.Zero) {
1529                                 if ((LastCursorWindow == handle) && (LastCursorHandle == cursor))
1530                                         return;
1531
1532                                 LastCursorHandle = cursor;
1533                                 LastCursorWindow = handle;
1534
1535                                 hwnd = Hwnd.ObjectFromHandle(handle);
1536                                 if (cursor != IntPtr.Zero)
1537                                         Xlib.XDefineCursor (display, hwnd.whole_window, cursor);
1538                                 else
1539                                         Xlib.XUndefineCursor (display, hwnd.whole_window);
1540                                 Xlib.XFlush (display);
1541                         }
1542                         else {
1543                                 hwnd = Hwnd.ObjectFromHandle(handle);
1544                                 Xlib.XDefineCursor (display, hwnd.whole_window, OverrideCursorHandle);
1545                         }
1546                 }
1547
1548                 public DragDropEffects StartDrag (IntPtr handle, object data,
1549                                                   DragDropEffects allowed_effects)
1550                 {
1551                         X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle);
1552
1553                         if (hwnd == null)
1554                                 throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
1555
1556                         return Dnd.StartDrag (hwnd.ClientWindow, data, allowed_effects);
1557                 }
1558
1559                 public X11Atoms Atoms {
1560                         get { return atoms; }
1561                 }
1562
1563                 public int CurrentTimestamp {
1564                         get {
1565                                 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
1566
1567                                 return (int) t.TotalSeconds;
1568                         }
1569                 }
1570
1571                 public Size CursorSize {
1572                         get {
1573                                 int     x;
1574                                 int     y;
1575
1576                                 if (Xlib.XQueryBestCursor (display, RootWindow.Handle, 32, 32, out x, out y) != 0) {
1577                                         return new Size (x, y);
1578                                 } else {
1579                                         return new Size (16, 16);
1580                                 }
1581                         }
1582                 } 
1583
1584                 public IntPtr Handle {
1585                         get { return display; }
1586                 }
1587
1588                 public Size IconSize {
1589                         get {
1590                                 IntPtr          list;
1591                                 XIconSize       size;
1592                                 int             count;
1593
1594                                 if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) {
1595                                         long            current;
1596                                         int             largest;
1597
1598                                         current = (long)list;
1599                                         largest = 0;
1600
1601                                         size = new XIconSize();
1602
1603                                         for (int i = 0; i < count; i++) {
1604                                                 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
1605                                                 current += Marshal.SizeOf(size);
1606
1607                                                 // Look for our preferred size
1608                                                 if (size.min_width == 32) {
1609                                                         Xlib.XFree(list);
1610                                                         return new Size(32, 32);
1611                                                 }
1612
1613                                                 if (size.max_width == 32) {
1614                                                         Xlib.XFree(list);
1615                                                         return new Size(32, 32);
1616                                                 }
1617
1618                                                 if (size.min_width < 32 && size.max_width > 32) {
1619                                                         int     x;
1620
1621                                                         // check if we can fit one
1622                                                         x = size.min_width;
1623                                                         while (x < size.max_width) {
1624                                                                 x += size.width_inc;
1625                                                                 if (x == 32) {
1626                                                                         Xlib.XFree(list);
1627                                                                         return new Size(32, 32);
1628                                                                 }
1629                                                         }
1630                                                 }
1631
1632                                                 if (largest < size.max_width) {
1633                                                         largest = size.max_width;
1634                                                 }
1635                                         }
1636
1637                                         // We didn't find a match or we wouldn't be here
1638                                         return new Size(largest, largest);
1639
1640                                 } else {
1641                                         return new Size(32, 32);
1642                                 }
1643                         }
1644                 } 
1645
1646                 public int KeyboardSpeed {
1647                         get {
1648                                 //
1649                                 // A lot harder: need to do:
1650                                 // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58)       = 1
1651                                 // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58)        = 0x080517a8
1652                                 // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58)                   = 0
1653                                 //
1654                                 // And from that we can tell the repetition rate
1655                                 //
1656                                 // Notice, the values must map to:
1657                                 //   [0, 31] which maps to 2.5 to 30 repetitions per second.
1658                                 //
1659                                 return 0;
1660                         }
1661                 }
1662
1663                 public int KeyboardDelay {
1664                         get {
1665                                 //
1666                                 // Return values must range from 0 to 4, 0 meaning 250ms,
1667                                 // and 4 meaning 1000 ms.
1668                                 //
1669                                 return 1; // ie, 500 ms
1670                         }
1671                 } 
1672
1673                 public int DefaultScreen {
1674                         get { return Xlib.XDefaultScreen (display); }
1675                 }
1676
1677                 public IntPtr DefaultColormap {
1678                         // XXX multiscreen
1679                         get { return Xlib.XDefaultColormap (display, DefaultScreen); }
1680                 }
1681
1682                 public Keys ModifierKeys {
1683                         get { return Keyboard.ModifierKeys; }
1684                 }
1685
1686                 public IntPtr OverrideCursor {
1687                         get { return OverrideCursorHandle; }
1688                         set {
1689                                 if (Grab.Hwnd != IntPtr.Zero) {
1690                                         Xlib.XChangeActivePointerGrab (display,
1691                                                                        EventMask.ButtonMotionMask |
1692                                                                        EventMask.PointerMotionMask |
1693                                                                        EventMask.ButtonPressMask |
1694                                                                        EventMask.ButtonReleaseMask,
1695                                                                        value, IntPtr.Zero);
1696                                         return;
1697                                 }
1698
1699                                 OverrideCursorHandle = value;
1700                         }
1701                 }
1702
1703                 public X11RootHwnd RootWindow {
1704                         get { return root_hwnd; }
1705                 }
1706
1707                 public Size SmallIconSize {
1708                         get {
1709                                 IntPtr          list;
1710                                 XIconSize       size;
1711                                 int             count;
1712
1713                                 if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) {
1714                                         long            current;
1715                                         int             smallest;
1716
1717                                         current = (long)list;
1718                                         smallest = 0;
1719
1720                                         size = new XIconSize();
1721
1722                                         for (int i = 0; i < count; i++) {
1723                                                 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
1724                                                 current += Marshal.SizeOf(size);
1725
1726                                                 // Look for our preferred size
1727                                                 if (size.min_width == 16) {
1728                                                         Xlib.XFree(list);
1729                                                         return new Size(16, 16);
1730                                                 }
1731
1732                                                 if (size.max_width == 16) {
1733                                                         Xlib.XFree(list);
1734                                                         return new Size(16, 16);
1735                                                 }
1736
1737                                                 if (size.min_width < 16 && size.max_width > 16) {
1738                                                         int     x;
1739
1740                                                         // check if we can fit one
1741                                                         x = size.min_width;
1742                                                         while (x < size.max_width) {
1743                                                                 x += size.width_inc;
1744                                                                 if (x == 16) {
1745                                                                         Xlib.XFree(list);
1746                                                                         return new Size(16, 16);
1747                                                                 }
1748                                                         }
1749                                                 }
1750
1751                                                 if (smallest == 0 || smallest > size.min_width) {
1752                                                         smallest = size.min_width;
1753                                                 }
1754                                         }
1755
1756                                         // We didn't find a match or we wouldn't be here
1757                                         return new Size(smallest, smallest);
1758
1759                                 } else {
1760                                         return new Size(16, 16);
1761                                 }
1762                         }
1763                 } 
1764
1765                 public X11Hwnd FosterParent {
1766                         get { return foster_hwnd; }
1767                 }
1768
1769                 public int MouseHoverTime {
1770                         get { return HoverState.Interval; }
1771                 }
1772
1773                 public Rectangle VirtualScreen {
1774                         get {
1775                                 IntPtr actual_atom;
1776                                 int actual_format;
1777                                 IntPtr nitems;
1778                                 IntPtr bytes_after;
1779                                 IntPtr prop = IntPtr.Zero;
1780                                 int width;
1781                                 int height;
1782
1783                                 Xlib.XGetWindowProperty (display, RootWindow.Handle,
1784                                                          Atoms._NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL,
1785                                                          out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1786
1787                                 if ((long)nitems < 2)
1788                                         goto failsafe;
1789
1790                                 width = Marshal.ReadIntPtr(prop, 0).ToInt32();
1791                                 height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
1792                                 Xlib.XFree(prop);
1793
1794                                 return new Rectangle(0, 0, width, height);
1795
1796                         failsafe:
1797                                 XWindowAttributes attributes = new XWindowAttributes();
1798
1799                                 Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
1800
1801                                 return new Rectangle(0, 0, attributes.width, attributes.height);
1802                         }
1803                 }
1804
1805                 public Rectangle WorkingArea {
1806                         get {
1807                                 IntPtr actual_atom;
1808                                 int actual_format;
1809                                 IntPtr nitems;
1810                                 IntPtr bytes_after;
1811                                 IntPtr prop = IntPtr.Zero;
1812                                 int width;
1813                                 int height;
1814                                 int current_desktop;
1815                                 int x;
1816                                 int y;
1817
1818                                 Xlib.XGetWindowProperty (display, RootWindow.Handle, 
1819                                                          Atoms._NET_CURRENT_DESKTOP, IntPtr.Zero, new IntPtr(1), false, Atoms.XA_CARDINAL,
1820                                                          out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1821
1822                                 if ((long)nitems < 1) {
1823                                         goto failsafe;
1824                                 }
1825
1826                                 current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
1827                                 Xlib.XFree(prop);
1828
1829                                 Xlib.XGetWindowProperty (display, RootWindow.Handle,
1830                                                          Atoms._NET_WORKAREA, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL,
1831                                                          out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1832
1833                                 if ((long)nitems < 4 * current_desktop) {
1834                                         goto failsafe;
1835                                 }
1836
1837                                 x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
1838                                 y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
1839                                 width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
1840                                 height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
1841                                 Xlib.XFree(prop);
1842
1843                                 return new Rectangle(x, y, width, height);
1844
1845                         failsafe:
1846                                 XWindowAttributes attributes = new XWindowAttributes();
1847
1848                                 Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
1849
1850                                 return new Rectangle(0, 0, attributes.width, attributes.height);
1851                         }
1852                 }
1853
1854                 private void XEventThread ()
1855                 {
1856                         while (true) {
1857 #if __MonoCS__
1858                                 Syscall.poll (pollfds, 1U, -1);
1859
1860                                 while (Xlib.XPending (display) > 0) {
1861 #endif
1862                                         XEvent xevent = new XEvent ();
1863                                         Xlib.XNextEvent (display, ref xevent);
1864
1865                                         // this is kind of a gross place to put this, but we don't know about the
1866                                         // key repeat state in X11ThreadQueue, nor to we want the queue code calling
1867                                         // XPeekEvent.
1868                                         if (!detectable_key_auto_repeat &&
1869                                             xevent.type == XEventName.KeyRelease &&
1870                                             Xlib.XPending (display) > 0) {
1871
1872                                                 XEvent nextevent = new XEvent ();
1873                                                 Xlib.XPeekEvent (display, ref nextevent);
1874
1875                                                 if (nextevent.type == XEventName.KeyPress &&
1876                                                     nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
1877                                                     nextevent.KeyEvent.time == xevent.KeyEvent.time) {
1878                                                         continue;
1879                                                 }
1880                                         }
1881
1882                                         X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
1883                                         if (hwnd != null)
1884                                                 hwnd.Queue.Enqueue (xevent);
1885 #if __MonoCS__
1886                                 }
1887 #endif
1888                         }
1889                 }
1890
1891                 private void RedirectMsgToEnabledAncestor (X11Hwnd hwnd, MSG msg, IntPtr window,
1892                                                            ref int event_x, ref int event_y)
1893                 {
1894                         int x, y;
1895
1896                         IntPtr dummy;
1897                         msg.hwnd = hwnd.EnabledHwnd;
1898                         Xlib.XTranslateCoordinates (display, window,
1899                                                     Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow,
1900                                                     event_x, event_y,
1901                                                     out x, out y, out dummy);
1902                         event_x = x;
1903                         event_y = y;
1904                         msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
1905                 }
1906
1907
1908                 // This is called from the thread owning the corresponding X11ThreadQueue
1909                 [MonoTODO("Implement filtering")]
1910                 public bool GetMessage (object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax)
1911                 {
1912                         X11ThreadQueue queue = (X11ThreadQueue)queue_id;
1913                         XEvent xevent;
1914                         bool client;
1915                         bool got_xevent = false;
1916
1917                         X11Hwnd hwnd;
1918
1919                 ProcessNextMessage:
1920                         do {
1921                                 got_xevent = queue.Dequeue (out xevent);
1922
1923                                 if (!got_xevent) {
1924 #if spew
1925                                         Console.WriteLine (">");
1926                                         Console.Out.Flush ();
1927 #endif
1928                                         break;
1929                                 }
1930
1931 #if spew
1932                                 Console.Write ("-");
1933                                 Console.Out.Flush ();
1934 #endif
1935
1936                                 hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
1937
1938                                 // Handle messages for windows that are already or are about to be destroyed.
1939
1940                                 // we need a special block for this because unless we remove the hwnd from the paint
1941                                 // queue it will always stay there (since we don't handle the expose), and we'll
1942                                 // effectively loop infinitely trying to repaint a non-existant window.
1943                                 if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
1944                                         hwnd.PendingExpose = hwnd.PendingNCExpose = false;
1945                                         goto ProcessNextMessage;
1946                                 }
1947
1948                                 // We need to make sure we only allow DestroyNotify events through for zombie
1949                                 // hwnds, since much of the event handling code makes requests using the hwnd's
1950                                 // ClientWindow, and that'll result in BadWindow errors if there's some lag
1951                                 // between the XDestroyWindow call and the DestroyNotify event.
1952                                 if (hwnd == null || hwnd.zombie) {
1953 #if DriverDebug || DriverDebugDestroy
1954                                         Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}",
1955                                                           xevent.type, xevent.AnyEvent.window.ToInt32());
1956 #endif
1957                                         goto ProcessNextMessage;
1958                                 }
1959
1960                                 client = hwnd.ClientWindow == xevent.AnyEvent.window;
1961
1962                                 msg.hwnd = hwnd.Handle;
1963
1964                                 switch (xevent.type) {
1965                                 case XEventName.KeyPress:
1966                                         Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg);
1967                                         return true;
1968
1969                                 case XEventName.KeyRelease:
1970                                         Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg);
1971                                         return true;
1972
1973                                 case XEventName.ButtonPress: {
1974                                         switch(xevent.ButtonEvent.button) {
1975                                         case 1:
1976                                                 MouseState |= MouseButtons.Left;
1977                                                 if (client) {
1978                                                         msg.message = Msg.WM_LBUTTONDOWN;
1979                                                 } else {
1980                                                         msg.message = Msg.WM_NCLBUTTONDOWN;
1981                                                         hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
1982                                                 }
1983                                                 // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
1984                                                 msg.wParam=GetMousewParam(0);
1985                                                 break;
1986
1987                                         case 2:
1988                                                 MouseState |= MouseButtons.Middle;
1989                                                 if (client) {
1990                                                         msg.message = Msg.WM_MBUTTONDOWN;
1991                                                 } else {
1992                                                         msg.message = Msg.WM_NCMBUTTONDOWN;
1993                                                         hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
1994                                                 }
1995                                                 msg.wParam=GetMousewParam(0);
1996                                                 break;
1997
1998                                         case 3:
1999                                                 MouseState |= MouseButtons.Right;
2000                                                 if (client) {
2001                                                         msg.message = Msg.WM_RBUTTONDOWN;
2002                                                 } else {
2003                                                         msg.message = Msg.WM_NCRBUTTONDOWN;
2004                                                         hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2005                                                 }
2006                                                 msg.wParam=GetMousewParam(0);
2007                                                 break;
2008
2009                                         case 4:
2010                                                 msg.hwnd = FocusWindow.Handle;
2011                                                 msg.message=Msg.WM_MOUSEWHEEL;
2012                                                 msg.wParam=GetMousewParam(120);
2013                                                 break;
2014
2015                                         case 5:
2016                                                 msg.hwnd = FocusWindow.Handle;
2017                                                 msg.message=Msg.WM_MOUSEWHEEL;
2018                                                 msg.wParam=GetMousewParam(-120);
2019                                                 break;
2020                                         }
2021
2022                                         msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
2023                                         MousePosition.X = xevent.ButtonEvent.x;
2024                                         MousePosition.Y = xevent.ButtonEvent.y;
2025
2026                                         if (!hwnd.Enabled) {
2027                                                 RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
2028                                                                               ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2029                                         }
2030
2031                                         if (Grab.Hwnd != IntPtr.Zero)
2032                                                 msg.hwnd = Grab.Hwnd;
2033
2034                                         if (ClickPending.Pending &&
2035                                             ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) &&
2036                                              (msg.wParam == ClickPending.wParam) &&
2037                                              (msg.lParam == ClickPending.lParam) &&
2038                                              (msg.message == ClickPending.Message))) {
2039                                                 // Looks like a genuine double click, clicked twice on the same spot with the same keys
2040                                                 switch(xevent.ButtonEvent.button) {
2041                                                 case 1:
2042                                                         msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
2043                                                         break;
2044
2045                                                 case 2:
2046                                                         msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
2047                                                         break;
2048
2049                                                 case 3:
2050                                                         msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
2051                                                         break;
2052                                                 }
2053
2054                                                 ClickPending.Pending = false;
2055
2056                                         }
2057                                         else {
2058                                                 ClickPending.Pending = true;
2059                                                 ClickPending.Hwnd = msg.hwnd;
2060                                                 ClickPending.Message = msg.message;
2061                                                 ClickPending.wParam = msg.wParam;
2062                                                 ClickPending.lParam = msg.lParam;
2063                                                 ClickPending.Time = (long)xevent.ButtonEvent.time;
2064                                         }
2065
2066                                         if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
2067                                                 hwnd.SendParentNotify (msg.message, MousePosition.X, MousePosition.Y);
2068
2069                                                 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
2070                                                 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after 
2071                                                 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
2072                                                 XEvent motionEvent = new XEvent ();
2073                                                 motionEvent.type = XEventName.MotionNotify;
2074                                                 motionEvent.MotionEvent.display = display;
2075                                                 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
2076                                                 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
2077                                                 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
2078                                                 hwnd.Queue.Enqueue (motionEvent);
2079                                         }
2080
2081                                         return true;
2082                                 }
2083
2084                                 case XEventName.ButtonRelease:
2085                                         switch(xevent.ButtonEvent.button) {
2086                                         case 1:
2087                                                 if (client) {
2088                                                         msg.message = Msg.WM_LBUTTONUP;
2089                                                 } else {
2090                                                         msg.message = Msg.WM_NCLBUTTONUP;
2091                                                         hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2092                                                 }
2093                                                 MouseState &= ~MouseButtons.Left;
2094                                                 msg.wParam=GetMousewParam(0);
2095                                                 break;
2096
2097                                         case 2:
2098                                                 if (client) {
2099                                                         msg.message = Msg.WM_MBUTTONUP;
2100                                                 } else {
2101                                                         msg.message = Msg.WM_NCMBUTTONUP;
2102                                                         hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2103                                                 }
2104                                                 MouseState &= ~MouseButtons.Middle;
2105                                                 msg.wParam=GetMousewParam(0);
2106                                                 break;
2107
2108                                         case 3:
2109                                                 if (client) {
2110                                                         msg.message = Msg.WM_RBUTTONUP;
2111                                                 } else {
2112                                                         msg.message = Msg.WM_NCRBUTTONUP;
2113                                                         hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2114                                                 }
2115                                                 MouseState &= ~MouseButtons.Right;
2116                                                 msg.wParam=GetMousewParam(0);
2117                                                 break;
2118
2119                                         case 4:
2120                                                 goto ProcessNextMessage;
2121
2122                                         case 5:
2123                                                 goto ProcessNextMessage;
2124                                         }
2125
2126                                         if (!hwnd.Enabled) {
2127                                                 RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
2128                                                                               ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2129                                         }
2130
2131                                         if (Grab.Hwnd != IntPtr.Zero)
2132                                                 msg.hwnd = Grab.Hwnd;
2133
2134                                         msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
2135                                         MousePosition.X = xevent.ButtonEvent.x;
2136                                         MousePosition.Y = xevent.ButtonEvent.y;
2137
2138                                                 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
2139                                                 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after 
2140                                                 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
2141                                         if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
2142                                                 XEvent motionEvent = new XEvent ();
2143                                                 motionEvent.type = XEventName.MotionNotify;
2144                                                 motionEvent.MotionEvent.display = display;
2145                                                 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
2146                                                 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
2147                                                 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
2148                                                 hwnd.Queue.Enqueue (motionEvent);
2149                                         }
2150                                         return true;
2151
2152                                 case XEventName.MotionNotify:
2153                                         /* XXX move the compression stuff here */
2154
2155                                         if (client) {
2156 #if DriverDebugExtra
2157                                                 Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}",
2158                                                                   client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(),
2159                                                                   xevent.MotionEvent.x, xevent.MotionEvent.y);
2160 #endif
2161
2162                                                 if (Grab.Hwnd != IntPtr.Zero)
2163                                                         msg.hwnd = Grab.Hwnd;
2164                                                 else
2165                                                         NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
2166
2167                                                 msg.message = Msg.WM_MOUSEMOVE;
2168                                                 msg.wParam = GetMousewParam(0);
2169                                                 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
2170
2171                                                 if (!hwnd.Enabled) {
2172                                                         RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
2173                                                                                       ref xevent.MotionEvent.x, ref xevent.MotionEvent.y);
2174                                                 }
2175
2176                                                 MousePosition.X = xevent.MotionEvent.x;
2177                                                 MousePosition.Y = xevent.MotionEvent.y;
2178
2179                                                 if ((HoverState.Timer.Enabled) &&
2180                                                     (((MousePosition.X + HoverState.Size.Width) < HoverState.X) ||
2181                                                      ((MousePosition.X - HoverState.Size.Width) > HoverState.X) ||
2182                                                      ((MousePosition.Y + HoverState.Size.Height) < HoverState.Y) ||
2183                                                      ((MousePosition.Y - HoverState.Size.Height) > HoverState.Y))) {
2184
2185                                                         HoverState.Timer.Stop();
2186                                                         HoverState.Timer.Start();
2187                                                         HoverState.X = MousePosition.X;
2188                                                         HoverState.Y = MousePosition.Y;
2189                                                 }
2190                                         }
2191                                         else {
2192                                                 HitTest ht;
2193                                                 IntPtr dummy;
2194                                                 int screen_x;
2195                                                 int screen_y;
2196
2197                                                 #if DriverDebugExtra
2198                                                 Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}",
2199                                                                   client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(),
2200                                                                   xevent.MotionEvent.x, xevent.MotionEvent.y);
2201                                                 #endif
2202                                                 msg.message = Msg.WM_NCMOUSEMOVE;
2203
2204                                                 if (!hwnd.Enabled) {
2205                                                         RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
2206                                                                                       ref xevent.MotionEvent.x, ref xevent.MotionEvent.y);
2207                                                 }
2208
2209                                                 // The hit test is sent in screen coordinates
2210                                                 Xlib.XTranslateCoordinates (display, xevent.AnyEvent.window, RootWindow.Handle,
2211                                                                             xevent.MotionEvent.x, xevent.MotionEvent.y,
2212                                                                             out screen_x, out screen_y, out dummy);
2213
2214                                                 msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF);
2215                                                 ht = (HitTest)NativeWindow.WndProc (hwnd.ClientWindow, Msg.WM_NCHITTEST,
2216                                                                                     IntPtr.Zero, msg.lParam).ToInt32 ();
2217                                                 NativeWindow.WndProc(hwnd.ClientWindow, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
2218
2219                                                 MousePosition.X = xevent.MotionEvent.x;
2220                                                 MousePosition.Y = xevent.MotionEvent.y;
2221                                         }
2222
2223                                         return true;
2224
2225                                 case XEventName.EnterNotify:
2226                                         if (!hwnd.Enabled)
2227                                                 goto ProcessNextMessage;
2228
2229                                         if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal)
2230                                                 goto ProcessNextMessage;
2231
2232                                         msg.message = Msg.WM_MOUSE_ENTER;
2233                                         HoverState.X = xevent.CrossingEvent.x;
2234                                         HoverState.Y = xevent.CrossingEvent.y;
2235                                         HoverState.Timer.Enabled = true;
2236                                         HoverState.Window = xevent.CrossingEvent.window;
2237
2238                                         return true;
2239
2240                                 case XEventName.LeaveNotify:
2241                                         if (!hwnd.Enabled)
2242                                                 goto ProcessNextMessage;
2243
2244                                         if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) ||
2245                                             (xevent.CrossingEvent.window != hwnd.ClientWindow))
2246                                                 goto ProcessNextMessage;
2247
2248                                         msg.message=Msg.WM_MOUSELEAVE;
2249                                         HoverState.Timer.Enabled = false;
2250                                         HoverState.Window = IntPtr.Zero;
2251
2252                                         return true;
2253
2254                                 case XEventName.ReparentNotify:
2255                                         if (hwnd.parent == null) {      // Toplevel
2256                                                 if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.WholeWindow)) {
2257                                                         // We need to adjust x/y
2258                                                         // This sucks ass, part 2
2259                                                         // Every WM does the reparenting of toplevel windows different, so there's
2260                                                         // no standard way of getting our adjustment considering frames/decorations
2261                                                         // The code below is needed for metacity. KDE doesn't works just fine without this
2262                                                         int     dummy_int;
2263                                                         IntPtr  dummy_ptr;
2264                                                         int     new_x;
2265                                                         int     new_y;
2266                                                         int     frame_left;
2267                                                         int     frame_top;
2268
2269                                                         hwnd.Reparented = true;
2270
2271                                                         Xlib.XGetGeometry(display, XGetParent(hwnd.WholeWindow),
2272                                                                           out dummy_ptr, out new_x, out new_y,
2273                                                                           out dummy_int, out dummy_int, out dummy_int, out dummy_int);
2274                                                         hwnd.FrameExtents(out frame_left, out frame_top);
2275                                                         if ((frame_left != 0) && (frame_top != 0) && (new_x != frame_left) && (new_y != frame_top)) {
2276                                                                 hwnd.x = new_x;
2277                                                                 hwnd.y = new_y;
2278                                                                 hwnd.whacky_wm = true;
2279                                                         }
2280
2281                                                         if (hwnd.opacity != 0xffffffff) {
2282                                                                 IntPtr opacity;
2283
2284                                                                 opacity = (IntPtr)(Int32)hwnd.opacity;
2285                                                                 Xlib.XChangeProperty (display, XGetParent(hwnd.WholeWindow),
2286                                                                                       Atoms._NET_WM_WINDOW_OPACITY, Atoms.XA_CARDINAL, 32,
2287                                                                                       PropertyMode.Replace, ref opacity, 1);
2288                                                         }
2289                                                         SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
2290                                                         goto ProcessNextMessage;
2291                                                 } else {
2292                                                         hwnd.Reparented = false;
2293                                                         goto ProcessNextMessage;
2294                                                 }
2295                                         }
2296                                         goto ProcessNextMessage;
2297
2298                                 case XEventName.ConfigureNotify:
2299                                         hwnd.HandleConfigureNotify (xevent);
2300                                         goto ProcessNextMessage;
2301
2302                                 case XEventName.MapNotify: {
2303                                         if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
2304                                                 hwnd.Mapped = true;
2305                                                 msg.message = Msg.WM_SHOWWINDOW;
2306                                                 msg.wParam = (IntPtr) 1;
2307                                                 // XXX we're missing the lParam..
2308                                                 break;
2309                                         }
2310                                         goto ProcessNextMessage;
2311                                 }
2312
2313                                 case XEventName.UnmapNotify: {
2314                                         if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
2315                                                 hwnd.Mapped = false;
2316                                                 msg.message = Msg.WM_SHOWWINDOW;
2317                                                 msg.wParam = (IntPtr) 0;
2318                                                 // XXX we're missing the lParam..
2319                                                 break;
2320                                         }
2321                                         goto ProcessNextMessage;
2322                                 }
2323
2324                                 case XEventName.FocusIn:
2325                                         // We received focus. We use X11 focus only to know if the app window does or does not have focus
2326                                         // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
2327                                         // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know 
2328                                         // about it having focus again
2329                                         if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear)
2330                                                 goto ProcessNextMessage;
2331
2332                                         if (FocusWindow == null) {
2333                                                 Control c = Control.FromHandle (hwnd.ClientWindow);
2334                                                 if (c == null)
2335                                                         goto ProcessNextMessage;
2336                                                 Form form = c.FindForm ();
2337                                                 if (form == null)
2338                                                         goto ProcessNextMessage;
2339                                                 X11Hwnd new_active = (X11Hwnd)Hwnd.ObjectFromHandle (form.Handle);
2340                                                 if (ActiveWindow != new_active) {
2341                                                         ActiveWindow = new_active;
2342                                                         SendMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
2343                                                 }
2344                                                 goto ProcessNextMessage;
2345                                         }
2346                                         Keyboard.FocusIn(FocusWindow.Handle);
2347                                         SendMessage(FocusWindow.Handle, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
2348                                         goto ProcessNextMessage;
2349
2350                                 case XEventName.FocusOut:
2351                                         // Se the comment for our FocusIn handler
2352                                         if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear)
2353                                                 goto ProcessNextMessage;
2354
2355                                         if (FocusWindow == null)
2356                                                 goto ProcessNextMessage;
2357
2358                                         Keyboard.FocusOut(FocusWindow.Handle);
2359
2360                                         while (Keyboard.ResetKeyState(FocusWindow.Handle, ref msg))
2361                                                 SendMessage(FocusWindow.Handle, msg.message, msg.wParam, msg.lParam);
2362
2363                                         SendMessage(FocusWindow.Handle, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
2364                                         goto ProcessNextMessage;
2365
2366                                 case XEventName.Expose:
2367                                         if (!hwnd.Mapped) {
2368                                                 hwnd.PendingExpose = hwnd.PendingNCExpose = false;
2369                                                 continue;
2370                                         }
2371
2372                                         msg.hwnd = hwnd.Handle;
2373
2374                                         if (client) {
2375 #if DriverDebugExtra
2376                                                 Console.WriteLine("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}",
2377                                                                   hwnd.client_window.ToInt32(),
2378                                                                   xevent.ExposeEvent.x, xevent.ExposeEvent.y,
2379                                                                   xevent.ExposeEvent.width, xevent.ExposeEvent.height);
2380 #endif
2381                                                 msg.message = Msg.WM_PAINT;
2382                                         }
2383                                         else {
2384                                                 Graphics g;
2385
2386                                                 switch (hwnd.border_style) {
2387                                                 case FormBorderStyle.Fixed3D:
2388                                                         g = Graphics.FromHwnd(hwnd.WholeWindow);
2389                                                         ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height),
2390                                                                                   Border3DStyle.Sunken);
2391                                                         g.Dispose();
2392                                                         break;
2393
2394                                                 case FormBorderStyle.FixedSingle:
2395                                                         g = Graphics.FromHwnd(hwnd.WholeWindow);
2396                                                         ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height),
2397                                                                                 Color.Black, ButtonBorderStyle.Solid);
2398                                                         g.Dispose();
2399                                                 break;
2400                                                 }
2401 #if DriverDebugExtra
2402                                                 Console.WriteLine("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}",
2403                                                                   hwnd.ClientWindow.ToInt32(),
2404                                                                   xevent.ExposeEvent.x, xevent.ExposeEvent.y,
2405                                                                   xevent.ExposeEvent.width, xevent.ExposeEvent.height);
2406 #endif
2407
2408                                                 Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y,
2409                                                                                 xevent.ExposeEvent.width, xevent.ExposeEvent.height);
2410                                                 Region region = new Region (rect);
2411                                                 IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
2412                                                 msg.message = Msg.WM_NCPAINT;
2413                                                 msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
2414                                                 msg.refobject = region;
2415                                         }
2416
2417                                         return true;
2418                                                 
2419                                 case XEventName.DestroyNotify:
2420
2421                                         // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
2422                                         hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
2423
2424                                         // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
2425                                         if ((hwnd != null) && (hwnd.ClientWindow == xevent.DestroyWindowEvent.window)) {
2426                                                 CleanupCachedWindows (hwnd);
2427
2428                                                 #if DriverDebugDestroy
2429                                                 Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.ClientWindow));
2430                                                 #endif
2431
2432                                                 msg.hwnd = hwnd.ClientWindow;
2433                                                 msg.message=Msg.WM_DESTROY;
2434                                                 hwnd.Dispose();
2435                                         }
2436                                         else
2437                                                 goto ProcessNextMessage;
2438
2439                                         return true;
2440
2441                                 case XEventName.ClientMessage:
2442                                         if (Dnd.HandleClientMessage (ref xevent))
2443                                                 goto ProcessNextMessage;
2444
2445                                         if (xevent.ClientMessageEvent.message_type == Atoms.AsyncAtom) {
2446                                                 XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
2447                                                 goto ProcessNextMessage;
2448                                         }
2449
2450                                         if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
2451                                                 msg.message = Msg.WM_MOUSEHOVER;
2452                                                 msg.wParam = GetMousewParam(0);
2453                                                 msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
2454                                                 return true;
2455                                         }
2456
2457                                         if (xevent.ClientMessageEvent.message_type == Atoms.PostAtom) {
2458                                                 msg.hwnd = xevent.ClientMessageEvent.ptr1;
2459                                                 msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
2460                                                 msg.wParam = xevent.ClientMessageEvent.ptr3;
2461                                                 msg.lParam = xevent.ClientMessageEvent.ptr4;
2462
2463                                                 // if we posted a WM_QUIT message, make sure we return
2464                                                 // false here as well.
2465                                                 if (msg.message == (Msg)Msg.WM_QUIT)
2466                                                         return false;
2467                                                 else
2468                                                         return true;
2469                                         }
2470
2471                                         if (xevent.ClientMessageEvent.message_type == Atoms._XEMBED) {
2472 #if DriverDebugXEmbed
2473                                                 Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}",
2474                                                                   xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
2475 #endif
2476
2477                                                 if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
2478                                                         XSizeHints hints = new XSizeHints();
2479                                                         IntPtr dummy;
2480
2481                                                         Xlib.XGetWMNormalHints (display, hwnd.WholeWindow, ref hints, out dummy);
2482
2483                                                         hwnd.width = hints.max_width;
2484                                                         hwnd.height = hints.max_height;
2485                                                         hwnd.ClientRect = Rectangle.Empty;
2486                                                         SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
2487                                                 }
2488                                         }
2489
2490                                         if (xevent.ClientMessageEvent.message_type == Atoms.WM_PROTOCOLS) {
2491                                                 if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_DELETE_WINDOW) {
2492                                                         msg.message = Msg.WM_CLOSE;
2493                                                         return true;
2494                                                 }
2495
2496                                                 // We should not get this, but I'll leave the code in case we need it in the future
2497                                                 if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_TAKE_FOCUS) {
2498                                                         goto ProcessNextMessage;
2499                                                 }
2500                                         }
2501
2502                                         goto ProcessNextMessage;
2503
2504                                 case XEventName.PropertyNotify:
2505                                         // The Hwnd's themselves handle this
2506                                         hwnd.PropertyChanged (xevent);
2507                                         goto ProcessNextMessage;
2508                                 }
2509                         } while (true);
2510
2511                         msg.hwnd= IntPtr.Zero;
2512                         msg.message = Msg.WM_ENTERIDLE;
2513                         return true;
2514                 }
2515
2516                 [MonoTODO("Implement filtering and PM_NOREMOVE")]
2517                 public bool PeekMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
2518                 {
2519                         X11ThreadQueue queue = (X11ThreadQueue) queue_id;
2520                         bool    pending;
2521
2522                         if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
2523                                 throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet");    // FIXME - Implement PM_NOREMOVE flag
2524                         }
2525
2526                         try {
2527                                 queue.Lock ();
2528                                 pending = false;
2529                                 if (queue.CountUnlocked > 0)
2530                                         pending = true;
2531                         }
2532                         catch {
2533                                 return false;
2534                         }
2535                         finally {
2536                                 queue.Unlock ();
2537                         }
2538
2539                         queue.CheckTimers ();
2540
2541                         if (!pending)
2542                                 return false;
2543
2544                         return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
2545                 }
2546
2547                 public void DoEvents (X11ThreadQueue queue)
2548                 {
2549                         MSG     msg = new MSG ();
2550
2551                         if (OverrideCursorHandle != IntPtr.Zero)
2552                                 OverrideCursorHandle = IntPtr.Zero;
2553
2554                         queue.DispatchIdle = false;
2555
2556                         while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
2557                                 TranslateMessage (ref msg);
2558                                 DispatchMessage (ref msg);
2559                         }
2560
2561                         queue.DispatchIdle = true;
2562                 }
2563
2564                 // double buffering support
2565                 public void CreateOffscreenDrawable (IntPtr handle,
2566                                                      int width, int height,
2567                                                      out object offscreen_drawable)
2568                 {
2569                         IntPtr root_out;
2570                         int x_out, y_out, width_out, height_out, border_width_out, depth_out;
2571
2572                         Xlib.XGetGeometry (display, handle,
2573                                            out root_out,
2574                                            out x_out, out y_out,
2575                                            out width_out, out height_out,
2576                                            out border_width_out, out depth_out);
2577
2578                         IntPtr pixmap = Xlib.XCreatePixmap (display, handle, width, height, depth_out);
2579
2580                         offscreen_drawable = pixmap;
2581                 }
2582
2583                 public void DestroyOffscreenDrawable (object offscreen_drawable)
2584                 {
2585                         Xlib.XFreePixmap (display, (IntPtr)offscreen_drawable);
2586                 }
2587
2588                 public Graphics GetOffscreenGraphics (object offscreen_drawable)
2589                 {
2590                         return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
2591                 }
2592
2593                 public void BlitFromOffscreen (IntPtr dest_handle,
2594                                                Graphics dest_dc,
2595                                                object offscreen_drawable,
2596                                                Graphics offscreen_dc,
2597                                                Rectangle r)
2598                 {
2599                         XGCValues gc_values;
2600                         IntPtr gc;
2601
2602                         gc_values = new XGCValues();
2603
2604                         gc = Xlib.XCreateGC (display, dest_handle, IntPtr.Zero, ref gc_values);
2605
2606                         Xlib.XCopyArea (display, (IntPtr)offscreen_drawable, dest_handle,
2607                                         gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
2608
2609                         Xlib.XFreeGC (display, gc);
2610                 }
2611
2612
2613                 // reversible screen-level drawing
2614                 IntPtr GetReversibleScreenGC (Color backColor)
2615                 {
2616                         XGCValues       gc_values;
2617                         IntPtr          gc;
2618                         uint pixel;
2619
2620                         XColor xcolor = new XColor();
2621                         xcolor.red = (ushort)(backColor.R * 257);
2622                         xcolor.green = (ushort)(backColor.G * 257);
2623                         xcolor.blue = (ushort)(backColor.B * 257);
2624                         Xlib.XAllocColor (display, DefaultColormap, ref xcolor);
2625                         pixel = (uint)xcolor.pixel.ToInt32();
2626
2627
2628                         gc_values = new XGCValues();
2629
2630                         gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
2631                         gc_values.foreground = (IntPtr)pixel;
2632
2633                         gc = Xlib.XCreateGC (display, RootWindow.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
2634                         Xlib.XSetForeground (display, gc, (UIntPtr)pixel);
2635                         Xlib.XSetFunction (display,   gc, GXFunction.GXxor);
2636
2637                         return gc;
2638                 }
2639
2640                 public void DrawReversibleLine (Point start, Point end, Color backColor)
2641                 {
2642                         if (backColor.GetBrightness() < 0.5)
2643                                 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
2644
2645                         IntPtr gc = GetReversibleScreenGC (backColor);
2646
2647                         Xlib.XDrawLine (display, RootWindow.Handle, gc, start.X, start.Y, end.X, end.Y);
2648
2649                         Xlib.XFreeGC (display, gc);
2650                 }
2651
2652                 public void FillReversibleRectangle (Rectangle rectangle, Color backColor)
2653                 {
2654                         if (backColor.GetBrightness() < 0.5)
2655                                 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
2656
2657                         IntPtr gc = GetReversibleScreenGC (backColor);
2658
2659                         if (rectangle.Width < 0) {
2660                                 rectangle.X += rectangle.Width;
2661                                 rectangle.Width = -rectangle.Width;
2662                         }
2663                         if (rectangle.Height < 0) {
2664                                 rectangle.Y += rectangle.Height;
2665                                 rectangle.Height = -rectangle.Height;
2666                         }
2667
2668                         Xlib.XFillRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
2669
2670                         Xlib.XFreeGC (display, gc);
2671                 }
2672
2673                 public void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
2674                 {
2675                         if (backColor.GetBrightness() < 0.5)
2676                                 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
2677
2678                         IntPtr gc = GetReversibleScreenGC (backColor);
2679
2680                         if (rectangle.Width < 0) {
2681                                 rectangle.X += rectangle.Width;
2682                                 rectangle.Width = -rectangle.Width;
2683                         }
2684                         if (rectangle.Height < 0) {
2685                                 rectangle.Y += rectangle.Height;
2686                                 rectangle.Height = -rectangle.Height;
2687                         }
2688
2689                         int line_width = 1;
2690                         GCLineStyle line_style = GCLineStyle.LineSolid;
2691                         GCCapStyle cap_style = GCCapStyle.CapButt;
2692                         GCJoinStyle join_style = GCJoinStyle.JoinMiter;
2693
2694                         switch (style) {
2695                         case FrameStyle.Dashed:
2696                                 line_style = GCLineStyle.LineOnOffDash;
2697                                 break;
2698                         case FrameStyle.Thick:
2699                                 line_width = 2;
2700                                 break;
2701                         }
2702
2703                         Xlib.XSetLineAttributes (display, gc, line_width, line_style, cap_style, join_style);
2704
2705                         Xlib.XDrawRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
2706
2707                         Xlib.XFreeGC (display, gc);
2708                 }
2709         }
2710 }