Mark tests as not working under TARGET_JVM
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms.X11Internal / X11Hwnd.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
21 //
22 //
23
24 using System;
25 using System.Collections;
26 using System.Drawing;
27 using System.Runtime.InteropServices;
28 using System.Text;
29 using System.Threading;
30 using System.Windows.Forms;
31
32 namespace System.Windows.Forms.X11Internal {
33
34         internal class X11Hwnd : Hwnd
35         {
36                 X11Display display;
37
38                 bool refetch_window_type = true;
39                 bool refetch_window_opacity = true;
40
41                 IntPtr[] wm_state = new IntPtr[0];
42                 IntPtr[] window_type = new IntPtr[0];
43                 double trans = 1.0;
44
45                 string text;
46                 new X11ThreadQueue queue;
47
48                 const EventMask SelectInputMask = (EventMask.ButtonPressMask | 
49                                                    EventMask.ButtonReleaseMask | 
50                                                    EventMask.KeyPressMask | 
51                                                    EventMask.KeyReleaseMask | 
52                                                    EventMask.EnterWindowMask | 
53                                                    EventMask.LeaveWindowMask |
54                                                    EventMask.ExposureMask |
55                                                    EventMask.FocusChangeMask |
56                                                    EventMask.PointerMotionMask | 
57                                                    EventMask.SubstructureNotifyMask);
58
59                 public X11Hwnd (X11Display display)
60                 {
61                         this.display = display;
62                         Queue = XplatUIX11_new.GetInstance().ThreadQueue(Thread.CurrentThread);
63                 }
64
65                 public X11Hwnd (X11Display display, IntPtr handle) : this (display)
66                 {
67                         if (handle == IntPtr.Zero)
68                                 throw new ArgumentNullException ("handle");
69                         WholeWindow = ClientWindow = handle;
70                 }
71
72                 // XXX this needs to be here so we don't have to
73                 // change Hwnd.  once we land, remove this and make
74                 // Hwnd.Queue virtual or abstract
75                 public new X11ThreadQueue Queue {
76                         get { return queue; }
77                         set { queue = value; }
78                 }
79
80                 public virtual void CreateWindow (CreateParams cp)
81                 {
82                         if (WholeWindow != IntPtr.Zero || ClientWindow != IntPtr.Zero)
83                                 throw new Exception ("createwindow called a second time on live X11Hwnd");
84
85                         XSetWindowAttributes    Attributes;
86                         int                     x;
87                         int                     y;
88                         int                     width;
89                         int                     height;
90                         IntPtr                  ParentHandle;
91                         SetWindowValuemask      ValueMask;
92
93                         Attributes = new XSetWindowAttributes();
94                         x = cp.X;
95                         y = cp.Y;
96                         width = cp.Width;
97                         height = cp.Height;
98
99                         /* Figure out our parent handle */
100                         if (cp.Parent != IntPtr.Zero)
101                                 // the parent handle is specified in the CreateParams
102                                 ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).ClientWindow;
103                         else if (StyleSet (cp.Style, WindowStyles.WS_CHILD))
104                                 // a child control with an unassigned parent gets created under the FosterParent
105                                 ParentHandle = display.FosterParent.Handle;
106                         else
107                                 // for all other cases, the parent is the root window
108                                 ParentHandle = display.RootWindow.Handle;
109
110                         ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
111
112                         Attributes.bit_gravity = Gravity.NorthWestGravity;
113                         Attributes.win_gravity = Gravity.NorthWestGravity;
114
115                         // Save what's under the toolwindow
116                         if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
117                                 Attributes.save_under = true;
118                                 ValueMask |= SetWindowValuemask.SaveUnder;
119                         }
120
121                         // If we're a popup without caption we override the WM
122                         if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
123                                 Attributes.override_redirect = true;
124                                 ValueMask |= SetWindowValuemask.OverrideRedirect;
125                         }
126
127                         // Default position on screen, if window manager doesn't place us somewhere else
128                         if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)
129                             && !StyleSet (cp.Style, WindowStyles.WS_POPUP)) {
130                                 if (x<0) x = 50;
131                                 if (y<0) y = 50;
132                         }
133                         // minimum width/height
134                         if (width<1) width=1;
135                         if (height<1) height=1;
136
137                         X = x;
138                         Y = y;
139                         Width = width;
140                         Height = height;
141                         Parent = Hwnd.ObjectFromHandle (cp.Parent);
142
143                         Enabled = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
144
145                         ClientWindow = IntPtr.Zero;
146
147                         WholeWindow = Xlib.XCreateWindow (display.Handle, ParentHandle,
148                                                           X, Y, Width, Height, 0,
149                                                           (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput,
150                                                           IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes);
151                         if (WholeWindow == IntPtr.Zero)
152                                 throw new Exception ("Coult not create X11 nc window");
153
154                         ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
155
156                         if (display.CustomVisual != IntPtr.Zero && display.CustomColormap != IntPtr.Zero) {
157                                 ValueMask |= SetWindowValuemask.ColorMap;
158                                 Attributes.colormap = display.CustomColormap;
159                         }
160
161                         ClientWindow = Xlib.XCreateWindow (display.Handle, WholeWindow,
162                                                            ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0,
163                                                            (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput,
164                                                            display.CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes);
165
166                         if (ClientWindow == IntPtr.Zero)
167                                 throw new Exception("Could not create X11 client window");
168
169 #if DriverDebug || DriverDebugCreate
170                         Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), Parent != null ? Parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle);
171 #endif
172
173                         if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
174                                 if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
175                                         XSizeHints      hints;
176
177                                         hints = new XSizeHints();
178                                         hints.x = X;
179                                         hints.y = Y;
180                                         hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition);
181                                         Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints);
182                                 }
183                         }
184
185                         Xlib.XSelectInput (display.Handle, WholeWindow, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask)));
186                         if (WholeWindow != ClientWindow)
187                                 Xlib.XSelectInput (display.Handle, ClientWindow, new IntPtr ((int)SelectInputMask));
188
189                         if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) {
190                                 Map ();
191                                 Visible = true;
192                         }
193
194                         if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
195                                 WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL;
196                                 Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.Handle);
197                         }
198
199                         SetWMStyles (cp);
200                         
201                         // set the group leader
202                         XWMHints wm_hints = new XWMHints ();
203                         
204                         wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint);
205                         wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
206                         wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState;
207                         wm_hints.window_group = ParentHandle == display.RootWindow.Handle ? ParentHandle : WholeWindow;
208                         
209                         Xlib.XSetWMHints (display.Handle, WholeWindow, ref wm_hints );
210
211                         if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE))
212                                 SetWindowState (FormWindowState.Minimized);
213                         else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE))
214                                 SetWindowState (FormWindowState.Maximized);
215
216                         // for now make all windows dnd enabled
217                         display.Dnd.SetAllowDrop (this, true);
218
219                         // Set caption/window title
220                         Text = cp.Caption;
221                 }
222
223                 public virtual void DestroyWindow ()
224                 {
225                         if (WholeWindow != IntPtr.Zero) {
226 #if DriverDebug || DriverDebugDestroy
227                                 Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", WholeWindow.ToInt32());
228 #endif
229                                 Xlib.XDestroyWindow (display.Handle, WholeWindow);
230                         }
231                         else if (ClientWindow != IntPtr.Zero) {
232 #if DriverDebug || DriverDebugDestroy
233                                 Console.WriteLine ("XDestroyWindow (client_window = {0:X})", ClientWindow.ToInt32());
234 #endif
235                                 Xlib.XDestroyWindow (display.Handle, ClientWindow);
236                         }
237                 }
238
239                 public void Activate ()
240                 {
241                         if (((IList)display.RootWindow._NET_SUPPORTED).Contains (display.Atoms._NET_ACTIVE_WINDOW)) {
242                                 display.SendNetWMMessage (WholeWindow, display.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
243                         }
244                         else {
245                                 Xlib.XRaiseWindow (display.Handle, WholeWindow);
246                         }
247                 }
248
249                 public void Update ()
250                 {
251                         try {
252                                 Queue.Lock ();
253                                 if (!Visible || !PendingExpose || !Mapped)
254                                         return;
255
256                                 // XXX this SendMessage call should probably not be inside the lock
257                                 display.SendMessage (ClientWindow, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
258                                 
259                                 PendingExpose = false;
260                         }
261                         finally {
262                                 Queue.Unlock ();
263                         }
264                 }
265
266                 public void MenuToScreen (ref int x, ref int y)
267                 {
268                         int     dest_x_return;
269                         int     dest_y_return;
270                         IntPtr  child;
271
272                         Xlib.XTranslateCoordinates (display.Handle,
273                                                     WholeWindow, display.RootWindow.Handle,
274                                                     x, y, out dest_x_return, out dest_y_return, out child);
275
276                         x = dest_x_return;
277                         y = dest_y_return;
278                 }
279
280                 public virtual void PropertyChanged (XEvent xevent)
281                 {
282                         if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_WINDOW_TYPE) {
283                                 // we need to recache our WINDOW_TYPE on the next query
284                                 refetch_window_type = true;
285                                 window_type = null;
286                         }
287                         else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_STATE) {
288                                 // we need to recache our WM_STATE on the next query
289                         }
290                         else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_NAME) {
291                                 // update our Text property
292                         }
293                         else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_WINDOW_OPACITY) {
294                                 // we need to recache our _NET_WM_WINDOW_OPACITY on the next query.
295                                 refetch_window_opacity = true;
296                         }
297                         // else we don't care about it
298
299                 }
300
301                 public void SetIcon (Icon icon)
302                 {
303                         if (icon == null) {
304                                 Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms._NET_WM_ICON);
305                         }
306                         else {
307                                 Bitmap          bitmap;
308                                 int             size;
309                                 IntPtr[]        data;
310                                 int             index;
311
312                                 bitmap = icon.ToBitmap();
313                                 index = 0;
314                                 size = bitmap.Width * bitmap.Height + 2;
315                                 data = new IntPtr[size];
316
317                                 data[index++] = (IntPtr)bitmap.Width;
318                                 data[index++] = (IntPtr)bitmap.Height;
319
320                                 for (int y = 0; y < bitmap.Height; y++) {
321                                         for (int x = 0; x < bitmap.Width; x++) {
322                                                 data[index++] = (IntPtr)bitmap.GetPixel(x, y).ToArgb();
323                                         }
324                                 }
325
326                                 Xlib.XChangeProperty (display.Handle, WholeWindow,
327                                                       display.Atoms._NET_WM_ICON, display.Atoms.XA_CARDINAL, 32,
328                                                       PropertyMode.Replace, data, size);
329                         }
330                 }
331
332                 public double GetWindowTransparency ()
333                 {
334                         if (refetch_window_opacity) {
335                                 trans = 1.0;
336
337                                 IntPtr actual_atom;
338                                 int actual_format;
339                                 IntPtr nitems;
340                                 IntPtr bytes_after;
341                                 IntPtr prop = IntPtr.Zero;
342
343                                 IntPtr w = WholeWindow;
344                                 if (reparented)
345                                         w = display.XGetParent (WholeWindow);
346
347                                 Xlib.XGetWindowProperty (display.Handle, w,
348                                                          display.Atoms._NET_WM_WINDOW_OPACITY, IntPtr.Zero, new IntPtr (16), false,
349                                                          display.Atoms.XA_CARDINAL,
350                                                          out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
351                                 
352                                 if (((long)nitems == 1) && (prop != IntPtr.Zero)) {
353                                         uint x11_opacity = (uint)Marshal.ReadInt32(prop, 0);
354                                         trans = ((double)x11_opacity) / (uint)0xffffffff;
355                                 }
356
357                                 if (prop != IntPtr.Zero) {
358                                         Xlib.XFree(prop);
359                                 }
360                         }
361
362                         return trans;
363                 }
364
365                 public void SetWindowTransparency (double transparency, Color key)
366                 {
367                         IntPtr  x11_opacity;
368
369                         opacity = (uint)(0xffffffff * transparency);
370                         x11_opacity = (IntPtr)((int)opacity);
371
372                         IntPtr w = WholeWindow;
373                         if (reparented)
374                                 w = display.XGetParent (WholeWindow);
375                         Xlib.XChangeProperty (display.Handle, w,
376                                               display.Atoms._NET_WM_WINDOW_OPACITY, display.Atoms.XA_CARDINAL, 32,
377                                               PropertyMode.Replace, ref x11_opacity, 1);
378                 }
379
380                 public IntPtr DefWndProc (ref Message msg)
381                 {
382                         switch ((Msg)msg.Msg) {
383                         case Msg.WM_PAINT:
384                                 Queue.Lock ();
385                                 PendingExpose = false;
386                                 Queue.Unlock ();
387                                 return IntPtr.Zero;
388
389                         case Msg.WM_NCPAINT:
390                                 Queue.Lock ();
391                                 PendingNCExpose = false;
392                                 Queue.Unlock ();
393                                 return IntPtr.Zero;
394
395                         case Msg.WM_CONTEXTMENU:
396                                 if (Parent != null)
397                                         display.SendMessage (Parent.ClientWindow, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam);
398                                 return IntPtr.Zero;
399
400                         case Msg.WM_MOUSEWHEEL:
401                                 if (Parent != null) {
402                                         display.SendMessage (Parent.ClientWindow, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam);
403                                         if (msg.Result == IntPtr.Zero)
404                                                 return IntPtr.Zero;
405                                 }
406                                 return IntPtr.Zero;
407
408                         case Msg.WM_SETCURSOR:
409                                 X11Hwnd parent = (X11Hwnd)Parent;
410                                 // Pass to parent window first
411                                 while ((parent != null) && (msg.Result == IntPtr.Zero)) {
412                                         msg.Result = NativeWindow.WndProc (parent.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam);
413                                         parent = (X11Hwnd)Parent;
414                                 }
415
416                                 if (msg.Result == IntPtr.Zero) {
417                                         IntPtr handle;
418
419                                         switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) {
420                                         case HitTest.HTBOTTOM:          handle = Cursors.SizeNS.handle; break;
421                                         case HitTest.HTBORDER:          handle = Cursors.SizeNS.handle; break;
422                                         case HitTest.HTBOTTOMLEFT:      handle = Cursors.SizeNESW.handle; break;
423                                         case HitTest.HTBOTTOMRIGHT:     handle = Cursors.SizeNWSE.handle; break;
424                                         case HitTest.HTERROR:
425                                                 if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN)
426                                                         display.AudibleAlert();
427                                                 handle = Cursors.Default.handle;
428                                                 break;
429
430                                         case HitTest.HTHELP:            handle = Cursors.Help.handle; break;
431                                         case HitTest.HTLEFT:            handle = Cursors.SizeWE.handle; break;
432                                         case HitTest.HTRIGHT:           handle = Cursors.SizeWE.handle; break;
433                                         case HitTest.HTTOP:             handle = Cursors.SizeNS.handle; break;
434                                         case HitTest.HTTOPLEFT:         handle = Cursors.SizeNWSE.handle; break;
435                                         case HitTest.HTTOPRIGHT:        handle = Cursors.SizeNESW.handle; break;
436
437 #if SameAsDefault
438                                         case HitTest.HTGROWBOX:
439                                         case HitTest.HTSIZE:
440                                         case HitTest.HTZOOM:
441                                         case HitTest.HTVSCROLL:
442                                         case HitTest.HTSYSMENU:
443                                         case HitTest.HTREDUCE:
444                                         case HitTest.HTNOWHERE:
445                                         case HitTest.HTMAXBUTTON:
446                                         case HitTest.HTMINBUTTON:
447                                         case HitTest.HTMENU:
448                                         case HitTest.HSCROLL:
449                                         case HitTest.HTBOTTOM:
450                                         case HitTest.HTCAPTION:
451                                         case HitTest.HTCLIENT:
452                                         case HitTest.HTCLOSE:
453 #endif
454                                         default: handle = Cursors.Default.handle; break;
455                                         }
456
457                                         display.SetCursor (msg.HWnd, handle);
458                                 }
459                                 return (IntPtr)1;
460
461                         default:
462                                 return IntPtr.Zero;
463                         }
464                 }
465
466
467                 public void AddExpose (bool client, int x, int y, int width, int height)
468                 {
469                         // Don't waste time
470                         if ((x > Width) || (y > Height) || ((x + width) <= 0) || ((y + height) <= 0))
471                                 return;
472
473                         // Keep the invalid area as small as needed
474                         if ((x + width) > Width)
475                                 width = Width - x;
476
477                         if ((y + height) > Height)
478                                 height = Height - y;
479
480                         if (client) {
481                                 AddInvalidArea(x, y, width, height);
482                                 PendingExpose = true;
483                         }
484                         else {
485                                 AddNcInvalidArea (x, y, width, height);
486                                 PendingNCExpose = true;
487                         }
488                 }
489
490                 public void AddConfigureNotify (XEvent xevent)
491                 {
492                         // We drop configure events for Client windows
493                         if ((xevent.ConfigureEvent.window != WholeWindow) || (xevent.ConfigureEvent.window != xevent.ConfigureEvent.xevent))
494                                 return;
495
496                         if (!reparented) {
497                                 X = xevent.ConfigureEvent.x;
498                                 Y = xevent.ConfigureEvent.y;
499                         } else {
500                                 // This sucks ass, part 1
501                                 // Every WM does the ConfigureEvents of toplevel windows different, so there's
502                                 // no standard way of getting our adjustment. 
503                                 // The code below is needed for KDE and FVWM, the 'whacky_wm' part is for metacity
504                                 // Several other WMs do their decorations different yet again and we fail to deal 
505                                 // with that, since I couldn't find any frigging commonality between them.
506                                 // The only sane WM seems to be KDE
507
508                                 if (!xevent.ConfigureEvent.send_event) {
509                                         IntPtr  dummy_ptr;
510
511                                         int trans_x;
512                                         int trans_y;
513
514                                         Xlib.XTranslateCoordinates (display.Handle, WholeWindow, display.RootWindow.Handle,
515                                                                     -xevent.ConfigureEvent.x, -xevent.ConfigureEvent.y,
516                                                                     out trans_x, out trans_y, out dummy_ptr);
517
518                                         X = trans_x;
519                                         Y = trans_y;
520                                 } else {
521                                         // This is a synthetic event, coordinates are in root space
522                                         X = xevent.ConfigureEvent.x;
523                                         Y = xevent.ConfigureEvent.y;
524                                         if (whacky_wm) {
525                                                 int frame_left;
526                                                 int frame_top;
527
528                                                 FrameExtents (out frame_left, out frame_top);
529                                                 X -= frame_left;
530                                                 Y -= frame_top;
531                                         }
532                                 }
533                         }
534
535                         Width = xevent.ConfigureEvent.width;
536                         Height = xevent.ConfigureEvent.height;
537                         ClientRect = Rectangle.Empty;
538
539                         if (!configure_pending) {
540                                 Queue.AddConfigure (this);
541                                 configure_pending = true;
542                         }
543                 }
544
545                 public void HandleConfigureNotify (XEvent xevent)
546                 {
547                         configure_pending = false;
548
549                         display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
550
551                         // We need to adjust our client window to track the resize of whole_window
552                         if (WholeWindow != ClientWindow)
553                                 PerformNCCalc ();
554                 }
555
556                 public void Invalidate (Rectangle rc, bool clear)
557                 {
558                         if (clear) {
559                                 AddExpose (true, X, Y, Width, Height);
560                         } else {
561                                 AddExpose (true, rc.X, rc.Y, rc.Width, rc.Height);
562                         }
563                 }
564
565                 public void InvalidateNC ()
566                 {
567                         AddExpose (false, 0, 0, Width, Height);
568                 }
569
570                 // XXX this assumes the queue lock is held
571                 public bool PendingNCExpose {
572                         get { return nc_expose_pending; }
573                         set {
574                                 if (nc_expose_pending == value)
575                                         return;
576                                 nc_expose_pending = value;
577
578                                 if (nc_expose_pending && !expose_pending)
579                                         Queue.AddPaint (this);
580                                 else if (!nc_expose_pending && !expose_pending)
581                                         Queue.RemovePaint (this);
582                         }
583                 }
584
585                 // XXX this assumes the queue lock is held
586                 public bool PendingExpose {
587                         get { return expose_pending; }
588                         set {
589                                 if (expose_pending == value)
590                                         return;
591                                 expose_pending = value;
592
593                                 if (expose_pending && !nc_expose_pending)
594                                         Queue.AddPaint (this);
595                                 else if (!expose_pending && !nc_expose_pending)
596                                         Queue.RemovePaint (this);
597                         }
598                 }
599
600                 public PaintEventArgs PaintEventStart (bool client)
601                 {
602                         PaintEventArgs paint_event;
603                         Graphics dc;
604
605                         if (client) {
606                                 dc = Graphics.FromHwnd (ClientWindow);
607
608                                 Region clip_region = new Region ();
609                                 clip_region.MakeEmpty();
610
611                                 foreach (Rectangle r in ClipRectangles)
612                                         clip_region.Union (r);
613
614                                 if (UserClip != null)
615                                         clip_region.Intersect(UserClip);
616
617                                 dc.Clip = clip_region;
618                                 paint_event = new PaintEventArgs(dc, Invalid);
619                                 PendingExpose = false;
620
621                                 ClearInvalidArea();
622
623                                 drawing_stack.Push (paint_event);
624                                 drawing_stack.Push (dc);
625
626                                 return paint_event;
627                         }
628                         else {
629                                 dc = Graphics.FromHwnd (WholeWindow);
630
631                                 if (!nc_invalid.IsEmpty) {
632                                         dc.SetClip (nc_invalid);
633                                         paint_event = new PaintEventArgs(dc, nc_invalid);
634                                 }
635                                 else {
636                                         paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, width, height));
637                                 }
638                                 PendingNCExpose = false;
639
640                                 ClearNcInvalidArea ();
641
642                                 drawing_stack.Push (paint_event);
643                                 drawing_stack.Push (dc);
644
645                                 return paint_event;
646                         }
647                 }
648
649                 public void PaintEventEnd (bool client)
650                 {
651                         Graphics dc = (Graphics)drawing_stack.Pop ();
652                         dc.Flush();
653                         dc.Dispose();
654                         
655                         PaintEventArgs pe = (PaintEventArgs)drawing_stack.Pop();
656                         pe.SetGraphics (null);
657                         pe.Dispose ();
658                 }
659
660                 public void DrawReversibleRectangle (Rectangle rect, int line_width)
661                 {
662                         XGCValues       gc_values;
663                         IntPtr          gc;
664
665                         gc_values = new XGCValues ();
666
667                         gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
668                         gc_values.line_width = line_width;
669
670                         // XXX multiscreen support
671                         gc_values.foreground = Xlib.XBlackPixel (display.Handle, display.DefaultScreen);
672
673                         // This logic will give us true rubber bands: (libsx, SANE_XOR)
674                         //mask = foreground ^ background; 
675                         //XSetForeground(DisplayHandle, gc, 0xffffffff);
676                         //XSetBackground(DisplayHandle, gc, background);
677                         //XSetFunction(DisplayHandle,   gc, GXxor);
678                         //XSetPlaneMask(DisplayHandle,  gc, mask);
679
680
681                         gc = Xlib.XCreateGC (display.Handle, ClientWindow,
682                                              new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values);
683                         uint foreground;
684                         uint background;
685
686                         Control control;
687                         control = Control.FromHandle(Handle);
688
689                         XColor xcolor = new XColor();
690
691                         xcolor.red = (ushort)(control.ForeColor.R * 257);
692                         xcolor.green = (ushort)(control.ForeColor.G * 257);
693                         xcolor.blue = (ushort)(control.ForeColor.B * 257);
694                         Xlib.XAllocColor (display.Handle, display.DefaultColormap, ref xcolor);
695                         foreground = (uint)xcolor.pixel.ToInt32();
696
697                         xcolor.red = (ushort)(control.BackColor.R * 257);
698                         xcolor.green = (ushort)(control.BackColor.G * 257);
699                         xcolor.blue = (ushort)(control.BackColor.B * 257);
700                         Xlib.XAllocColor (display.Handle, display.DefaultColormap, ref xcolor);
701                         background = (uint)xcolor.pixel.ToInt32();
702
703                         uint mask = foreground ^ background; 
704
705                         Xlib.XSetForeground (display.Handle, gc, (UIntPtr)0xffffffff);
706                         Xlib.XSetBackground (display.Handle, gc, (UIntPtr)background);
707                         Xlib.XSetFunction (display.Handle,   gc, GXFunction.GXxor);
708                         Xlib.XSetPlaneMask (display.Handle,  gc, (IntPtr)mask);
709
710                         if ((rect.Width > 0) && (rect.Height > 0))
711                                 Xlib.XDrawRectangle (display.Handle, ClientWindow, gc, rect.Left, rect.Top, rect.Width, rect.Height);
712                         else if (rect.Width > 0)
713                                 Xlib.XDrawLine (display.Handle, ClientWindow, gc, rect.X, rect.Y, rect.Right, rect.Y);
714                         else
715                                 Xlib.XDrawLine (display.Handle, ClientWindow, gc, rect.X, rect.Y, rect.X, rect.Bottom);
716
717                         Xlib.XFreeGC (display.Handle, gc);
718                 }
719
720                 public void Map ()
721                 {
722                         // FIXME why do we set this here and also in the MapNotify event handling?
723                         mapped = true;
724                         Xlib.XMapWindow (display.Handle, WholeWindow);
725                         if (WholeWindow != ClientWindow)
726                                 Xlib.XMapWindow (display.Handle, ClientWindow);
727                 }
728
729                 public void Unmap ()
730                 {
731                         // FIXME why do we set this here and also in the UnmapNotify event handling?
732                         mapped = false;
733                         Xlib.XUnmapWindow (display.Handle, WholeWindow);
734                 }
735
736                 public void PerformNCCalc ()
737                 {
738                         XplatUIWin32.NCCALCSIZE_PARAMS  ncp;
739                         IntPtr                          ptr;
740                         Rectangle                       rect;
741
742                         rect = DefaultClientRect;
743
744                         ncp = new XplatUIWin32.NCCALCSIZE_PARAMS ();
745                         ptr = Marshal.AllocHGlobal (Marshal.SizeOf(ncp));
746
747                         ncp.rgrc1.left = rect.Left;
748                         ncp.rgrc1.top = rect.Top;
749                         ncp.rgrc1.right = rect.Right;
750                         ncp.rgrc1.bottom = rect.Bottom;
751
752                         Marshal.StructureToPtr (ncp, ptr, true);
753                         NativeWindow.WndProc (ClientWindow, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr);
754                         ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
755                         Marshal.FreeHGlobal(ptr);
756
757                         // FIXME - debug this with Menus
758
759                         rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
760                         ClientRect = rect;
761
762                         if (Visible) {
763                                 if ((rect.Width < 1) || (rect.Height < 1))
764                                         Xlib.XMoveResizeWindow (display.Handle, ClientWindow, -5, -5, 1, 1);
765                                 else
766                                         Xlib.XMoveResizeWindow (display.Handle, ClientWindow, rect.X, rect.Y, rect.Width, rect.Height);
767                         }
768
769                         InvalidateNC ();
770                 }
771
772                 public void RequestNCRecalc ()
773                 {
774                         PerformNCCalc ();
775                         display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
776                         InvalidateNC ();
777                 }
778
779                 [MonoTODO]
780                 public void RequestAdditionalWM_NCMessages (bool hover, bool leave)
781                 {
782                         // Missing messages won't crash anything so just don't generate them for the moment.
783                         // throw new NotImplementedException( );
784                 }
785                 
786                 public void FrameExtents (out int left, out int top)
787                 {
788                         IntPtr actual_atom;
789                         int actual_format;
790                         IntPtr nitems;
791                         IntPtr bytes_after;
792                         IntPtr prop = IntPtr.Zero;
793
794                         Xlib.XGetWindowProperty (display.Handle, WholeWindow,
795                                                  display.Atoms._NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false,
796                                                  display.Atoms.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
797                         if (((long)nitems == 4) && (prop != IntPtr.Zero)) {
798                                 left = Marshal.ReadIntPtr(prop, 0).ToInt32();
799                                 //right = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
800                                 top = Marshal.ReadIntPtr(prop, IntPtr.Size * 2).ToInt32();
801                                 //bottom = Marshal.ReadIntPtr(prop, IntPtr.Size * 3).ToInt32();
802                         } else {
803                                 left = 0;
804                                 top = 0;
805                         }
806
807                         if (prop != IntPtr.Zero) {
808                                 Xlib.XFree(prop);
809                         }
810                 }
811
812                 static bool StyleSet (int s, WindowStyles ws)
813                 {
814                         return (s & (int)ws) == (int)ws;
815                 }
816
817                 static bool ExStyleSet (int ex, WindowExStyles exws)
818                 {
819                         return (ex & (int)exws) == (int)exws;
820                 }
821
822                 // XXX this should be a static method on Hwnd so other backends can use it
823                 public static void DeriveStyles(int Style, int ExStyle, out FormBorderStyle border_style, out bool border_static, 
824                                 out TitleStyle title_style, out int caption_height, out int tool_caption_height)
825                 {
826
827                         // Only MDI windows get caption_heights
828                         caption_height = 0;
829                         tool_caption_height = 19;
830                         border_static = false;
831
832                         if (StyleSet (Style, WindowStyles.WS_CHILD)) {
833                                 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) {
834                                         border_style = FormBorderStyle.Fixed3D;
835                                 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
836                                         border_style = FormBorderStyle.Fixed3D;
837                                         border_static = true;
838                                 } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) {
839                                         border_style = FormBorderStyle.None;
840                                 } else {
841                                         border_style = FormBorderStyle.FixedSingle;
842                                 }
843                                 title_style = TitleStyle.None;
844
845                                 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) {
846                                         caption_height = 26;
847
848                                         if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
849                                                 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
850                                                         title_style = TitleStyle.Tool;
851                                                 else
852                                                         title_style = TitleStyle.Normal;
853                                         }
854
855                                         if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) ||
856                                             ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
857                                                 border_style = (FormBorderStyle) 0xFFFF;
858                                         else
859                                                 border_style = FormBorderStyle.None;
860                                 }
861                         }
862                         else {
863                                 title_style = TitleStyle.None;
864                                 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
865                                         if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
866                                                 title_style = TitleStyle.Tool;
867                                         else
868                                                 title_style = TitleStyle.Normal;
869                                 }
870
871                                 border_style = FormBorderStyle.None;
872
873                                 if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) {
874                                         if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
875                                                 border_style = FormBorderStyle.SizableToolWindow;
876                                         else
877                                                 border_style = FormBorderStyle.Sizable;
878                                 } else {
879                                         if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
880                                                 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE))
881                                                         border_style = FormBorderStyle.Fixed3D;
882                                                 else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
883                                                         border_style = FormBorderStyle.Fixed3D;
884                                                         border_static = true;
885                                                 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME))
886                                                         border_style = FormBorderStyle.FixedDialog;
887                                                 else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
888                                                         border_style = FormBorderStyle.FixedToolWindow;
889                                                 else if (StyleSet (Style, WindowStyles.WS_BORDER))
890                                                         border_style = FormBorderStyle.FixedSingle;
891                                         } else if (StyleSet (Style, WindowStyles.WS_BORDER))
892                                                 border_style = FormBorderStyle.FixedSingle;
893                                 }
894                         }
895                 }
896
897                 public void SetHwndStyles (CreateParams cp)
898                 {
899                         DeriveStyles(cp.Style, cp.ExStyle, out this.border_style, out this.border_static, out this.title_style, out this.caption_height, out this.tool_caption_height);
900                 }
901
902                 public void SetWMStyles (CreateParams cp)
903                 {
904                         MotifWmHints mwmHints;
905                         MotifFunctions functions;
906                         MotifDecorations decorations;
907                         IntPtr[] atoms;
908                         int atom_count;
909                         Rectangle client_rect;
910
911                         // Child windows don't need WM window styles
912                         if (StyleSet (cp.Style, WindowStyles.WS_CHILDWINDOW))
913                                 return;
914
915                         atoms = new IntPtr[8];
916                         mwmHints = new MotifWmHints();
917                         functions = 0;
918                         decorations = 0;
919
920                         mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
921                         mwmHints.functions = (IntPtr)0;
922                         mwmHints.decorations = (IntPtr)0;
923
924                         if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)
925                             || !StyleSet (cp.Style, WindowStyles.WS_CAPTION | WindowStyles.WS_BORDER | WindowStyles.WS_DLGFRAME)) {
926                                 /* tool windows get no window manager
927                                    decorations, and neither do windows
928                                    which lack CAPTION/BORDER/DLGFRAME
929                                    styles.
930                                 */
931
932                                 /* just because the window doesn't get any decorations doesn't
933                                    mean we should disable the functions.  for instance, without
934                                    MotifFunctions.Maximize, changing the windowstate to Maximized
935                                    is ignored by metacity. */
936                                 functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
937                         }
938                         else {
939                                 if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
940                                         functions |= MotifFunctions.Move;
941                                         decorations |= MotifDecorations.Title | MotifDecorations.Menu;
942                                 }
943
944                                 if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) {
945                                         functions |= MotifFunctions.Move | MotifFunctions.Resize;
946                                         decorations |= MotifDecorations.Border | MotifDecorations.ResizeH;
947                                 }
948
949                                 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) {
950                                         functions |= MotifFunctions.Minimize;
951                                         decorations |= MotifDecorations.Minimize;
952                                 }
953
954                                 if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) {
955                                         functions |= MotifFunctions.Maximize;
956                                         decorations |= MotifDecorations.Maximize;
957                                 }
958
959                                 if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) {
960                                         functions |= MotifFunctions.Resize;
961                                         decorations |= MotifDecorations.ResizeH;
962                                 }
963
964                                 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
965                                         decorations |= MotifDecorations.Border;
966                                 }
967
968                                 if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) {
969                                         decorations |= MotifDecorations.Border;
970                                 }
971                         
972                                 if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) {
973                                         decorations |= MotifDecorations.Border;
974                                 }
975
976                                 if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) {
977                                         functions |= MotifFunctions.Close;
978                                 }
979                                 else {
980                                         functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close);
981                                         decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize);
982                                         if (cp.Caption == "") {
983                                                 functions &= ~MotifFunctions.Move;
984                                                 decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH);
985                                         }
986                                 }
987                         }
988
989                         if ((functions & MotifFunctions.Resize) == 0) {
990                                 fixed_size = true;
991                                 SetMinMax (new Rectangle(cp.X, cp.Y, cp.Width, cp.Height), new Size(cp.Width, cp.Height), new Size(cp.Width, cp.Height));
992                         } else {
993                                 fixed_size = false;
994                         }
995
996                         mwmHints.functions = (IntPtr)functions;
997                         mwmHints.decorations = (IntPtr)decorations;
998
999                         FormWindowState current_state = GetWindowState ();
1000                         if (current_state == (FormWindowState)(-1))
1001                                 current_state = FormWindowState.Normal;
1002
1003                         client_rect = ClientRect;
1004
1005                         atom_count = 0;
1006
1007                         // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
1008                         // and get those windows in front of their parents
1009                         if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
1010                                 WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_UTILITY;
1011
1012                                 Form f = Control.FromHandle(Handle) as Form;
1013                                 if (f != null && !reparented) {
1014                                         if (f.Owner != null && f.Owner.Handle != IntPtr.Zero) {
1015                                                 Hwnd owner_hwnd = Hwnd.ObjectFromHandle(f.Owner.Handle);
1016                                                 if (owner_hwnd != null)
1017                                                         Xlib.XSetTransientForHint (display.Handle, WholeWindow,
1018                                                                                    owner_hwnd.WholeWindow);
1019                                         }
1020                                 }
1021                         }
1022                                 
1023                         Xlib.XChangeProperty (display.Handle, WholeWindow,
1024                                               display.Atoms._MOTIF_WM_HINTS, display.Atoms._MOTIF_WM_HINTS, 32,
1025                                               PropertyMode.Replace, ref mwmHints, 5);
1026
1027                         if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (parent != null) && (parent.WholeWindow != IntPtr.Zero)) {
1028                                 WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL;
1029                                 Xlib.XSetTransientForHint(display.Handle, WholeWindow, parent.WholeWindow);
1030                         } else if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_APPWINDOW)) {
1031                                 /* this line keeps the window from showing up in gnome's taskbar */
1032                                 atoms[atom_count++] = display.Atoms._NET_WM_STATE_SKIP_TASKBAR;
1033                         }
1034                         if ((client_rect.Width < 1) || (client_rect.Height < 1)) {
1035                                 Xlib.XMoveResizeWindow (display.Handle, ClientWindow, -5, -5, 1, 1);
1036                         } else {
1037                                 Xlib.XMoveResizeWindow (display.Handle, ClientWindow, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
1038                         }
1039
1040                         if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW))
1041                                 atoms[atom_count++] = display.Atoms._NET_WM_STATE_SKIP_TASKBAR;
1042
1043                         /* we need to add these atoms in the
1044                          * event we're maximized, since we're
1045                          * replacing the existing
1046                          * _NET_WM_STATE here.  If we don't
1047                          * add them, future calls to
1048                          * GetWindowState will return Normal
1049                          * for a window which is maximized. */
1050                         if (current_state == FormWindowState.Maximized) {
1051                                 atoms[atom_count++] = display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ;
1052                                 atoms[atom_count++] = display.Atoms._NET_WM_STATE_MAXIMIZED_VERT;
1053                         }
1054
1055                         Set_WM_STATE (atoms, atom_count);
1056
1057                         atom_count = 0;
1058                         atoms[atom_count++] = display.Atoms.WM_DELETE_WINDOW;
1059                         if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP))
1060                                 atoms[atom_count++] = display.Atoms._NET_WM_CONTEXT_HELP;
1061
1062                         Xlib.XSetWMProtocols (display.Handle, WholeWindow, atoms, atom_count);
1063                 }
1064
1065                 public void ClientToScreen (ref int x, ref int y)
1066                 {
1067                         int     dest_x_return;
1068                         int     dest_y_return;
1069                         IntPtr  child;
1070
1071                         Xlib.XTranslateCoordinates (display.Handle,
1072                                                     ClientWindow, display.RootWindow.Handle,
1073                                                     x, y, out dest_x_return, out dest_y_return, out child);
1074
1075                         x = dest_x_return;
1076                         y = dest_y_return;
1077                 }
1078
1079                 public void ScreenToClient (ref int x, ref int y)
1080                 {
1081                         int     dest_x_return;
1082                         int     dest_y_return;
1083                         IntPtr  child;
1084
1085                         Xlib.XTranslateCoordinates (display.Handle,
1086                                                     display.RootWindow.Handle, ClientWindow,
1087                                                     x, y, out dest_x_return, out dest_y_return, out child);
1088
1089                         x = dest_x_return;
1090                         y = dest_y_return;
1091                 }
1092
1093
1094                 public void ScreenToMenu (ref int x, ref int y)
1095                 {
1096                         int     dest_x_return;
1097                         int     dest_y_return;
1098                         IntPtr  child;
1099
1100                         Xlib.XTranslateCoordinates (display.Handle,
1101                                                     display.RootWindow.Handle, WholeWindow,
1102                                                     x, y, out dest_x_return, out dest_y_return, out child);
1103
1104                         x = dest_x_return;
1105                         y = dest_y_return;
1106                 }
1107
1108                 public void ScrollWindow (Rectangle area, int XAmount, int YAmount, bool with_children)
1109                 {
1110                         IntPtr          gc;
1111                         XGCValues       gc_values;
1112
1113                         Rectangle r = Rectangle.Intersect (Invalid, area);
1114                         if (!r.IsEmpty) {
1115                                 /* We have an invalid area in the window we're scrolling. 
1116                                    Adjust our stored invalid rectangle to to match the scrolled amount */
1117
1118                                 r.X += XAmount;
1119                                 r.Y += YAmount;
1120
1121                                 if (r.X < 0) {
1122                                         r.Width += r.X;
1123                                         r.X =0;
1124                                 }
1125
1126                                 if (r.Y < 0) {
1127                                         r.Height += r.Y;
1128                                         r.Y =0;
1129                                 }
1130
1131                                 if (area.Contains (Invalid))
1132                                         ClearInvalidArea();
1133                                 AddInvalidArea(r);
1134                         }
1135
1136                         gc_values = new XGCValues();
1137
1138                         gc_values.graphics_exposures = false;
1139                         if (with_children)
1140                                 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
1141
1142                         gc = Xlib.XCreateGC (display.Handle, ClientWindow, IntPtr.Zero, ref gc_values);
1143
1144                         int src_x, src_y;
1145                         int dest_x, dest_y;
1146                         int width, height;
1147
1148                         if (YAmount > 0) {
1149                                 src_y = area.Y;
1150                                 height = area.Height - YAmount;
1151                                 dest_y = area.Y + YAmount;
1152                         }
1153                         else {
1154                                 src_y = area.Y - YAmount;
1155                                 height = area.Height + YAmount;
1156                                 dest_y = area.Y;
1157                         }
1158
1159                         if (XAmount > 0) {
1160                                 src_x = area.X;
1161                                 width = area.Width - XAmount;
1162                                 dest_x = area.X + XAmount;
1163                         }
1164                         else {
1165                                 src_x = area.X - XAmount;
1166                                 width = area.Width + XAmount;
1167                                 dest_x = area.X;
1168                         }
1169
1170                         Xlib.XCopyArea (display.Handle, ClientWindow, ClientWindow, gc, src_x, src_y, width, height, dest_x, dest_y);
1171
1172                         // Generate an expose for the area exposed by the horizontal scroll
1173                         // We don't use AddExpose since we're 
1174                         if (XAmount > 0) {
1175                                 AddExpose (true, area.X, area.Y, XAmount, area.Height);
1176                         } else if (XAmount < 0) {
1177                                 AddExpose (true, XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
1178                         }
1179
1180                         // Generate an expose for the area exposed by the vertical scroll
1181                         if (YAmount > 0) {
1182                                 AddExpose (true, area.X, area.Y, area.Width, YAmount);
1183                         } else if (YAmount < 0) {
1184                                 AddExpose (true, area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
1185                         }
1186
1187                         Xlib.XFreeGC (display.Handle, gc);
1188                 }
1189
1190
1191                 public void SetBorderStyle (FormBorderStyle border_style)
1192                 {
1193                         Form form = Control.FromHandle (Handle) as Form;
1194                         if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow ||
1195                                                                             border_style == FormBorderStyle.SizableToolWindow)) {
1196                                 form.window_manager = new ToolWindowManager (form);
1197                         }
1198                         
1199                         BorderStyle = border_style;
1200                         RequestNCRecalc ();
1201                 }
1202
1203                 // XXX this should probably be in Hwnd
1204                 public void SetClipRegion (Region region)
1205                 {
1206                         UserClip = region;
1207                         Invalidate (new Rectangle(0, 0, Width, Height), false);
1208                 }
1209
1210                 // XXX this should probably be in Hwnd
1211                 public Region GetClipRegion ()
1212                 {
1213                         return UserClip;
1214                 }
1215
1216                 public void SetMenu (Menu menu)
1217                 {
1218                         Menu = menu;
1219
1220                         RequestNCRecalc ();
1221                 }
1222
1223                 public void SetMinMax (Rectangle maximized, Size min, Size max)
1224                 {
1225                         XSizeHints      hints;
1226                         IntPtr          dummy;
1227
1228                         hints = new XSizeHints();
1229
1230                         Xlib.XGetWMNormalHints (display.Handle, WholeWindow, ref hints, out dummy);
1231                         if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
1232                                 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
1233                                 hints.min_width = min.Width;
1234                                 hints.min_height = min.Height;
1235                         }
1236
1237                         if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
1238                                 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
1239                                 hints.max_width = max.Width;
1240                                 hints.max_height = max.Height;
1241                         }
1242
1243                         if (hints.flags != IntPtr.Zero)
1244                                 Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints);
1245
1246                         if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
1247                                 hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
1248                                 hints.x = maximized.X;
1249                                 hints.y = maximized.Y;
1250                                 hints.width = maximized.Width;
1251                                 hints.height = maximized.Height;
1252
1253                                 // Metacity does not seem to follow this constraint for maximized (zoomed) windows
1254                                 Xlib.XSetZoomHints (display.Handle, WholeWindow, ref hints);
1255                         }
1256                 }
1257
1258                 public void GetPosition (bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height)
1259                 {
1260                         x = X;
1261                         y = Y;
1262                         width = Width;
1263                         height = Height;
1264
1265                         PerformNCCalc ();
1266
1267                         client_width = ClientRect.Width;
1268                         client_height = ClientRect.Height;
1269                 }
1270
1271                 public void SetPosition (int x, int y, int width, int height)
1272                 {
1273                         // Win32 automatically changes negative width/height to 0.
1274                         if (width < 0)
1275                                 width = 0;
1276                         if (height < 0)
1277                                 height = 0;
1278
1279                         // X requires a sanity check for width & height; otherwise it dies
1280                         if (zero_sized && width > 0 && height > 0) {
1281                                 if (Visible) {
1282                                         Map ();
1283                                 }
1284                                 zero_sized = false;
1285                         }
1286
1287                         if ((width < 1) || (height < 1)) {
1288                                 zero_sized = true;
1289                                 Unmap ();
1290                         }
1291
1292                         // Save a server roundtrip (and prevent a feedback loop)
1293                         if ((X == x) && (Y == y) && 
1294                                 (Width == width) && (Height == height)) {
1295                                 return;
1296                         }
1297
1298                         if (!zero_sized) {
1299                                 //Hack?
1300                                 X = x;
1301                                 Y = y;
1302                                 Width = width;
1303                                 Height = height;
1304                                 display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
1305
1306                                 if (fixed_size) {
1307                                         SetMinMax (Rectangle.Empty, new Size(width, height), new Size(width, height));
1308                                 }
1309
1310                                 Xlib.XMoveResizeWindow (display.Handle, WholeWindow, x, y, width, height);
1311                                 PerformNCCalc ();
1312                         }
1313
1314                         // Update our position/size immediately, so
1315                         // that future calls to SetWindowPos aren't
1316                         // kept from calling XMoveResizeWindow (by the
1317                         // "Save a server roundtrip" block above).
1318                         X = x;
1319                         Y = y;
1320                         Width = width;
1321                         Height = height;
1322                         ClientRect = Rectangle.Empty;
1323                 }
1324
1325                 public void SetParent (X11Hwnd parent_hwnd)
1326                 {
1327                         Parent = parent_hwnd;
1328
1329 #if DriverDebug || DriverDebugParent
1330                         Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(Handle), XplatUI.Window(hwnd.parent != null ? parent_hwnd.Handle : IntPtr.Zero));
1331 #endif
1332                         Xlib.XReparentWindow (display.Handle, WholeWindow,
1333                                               parent_hwnd == null ? display.FosterParent.ClientWindow : parent_hwnd.ClientWindow,
1334                                               X, Y);
1335                 }
1336
1337                 public void SetCursorPos (int x, int y)
1338                 {
1339                         Xlib.XWarpPointer (display.Handle, IntPtr.Zero, ClientWindow, 0, 0, 0, 0, x, y);
1340                 }
1341                 
1342                 public bool SetTopmost (X11Hwnd owner, bool enabled)
1343                 {
1344                         if (enabled) {
1345                                 WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL;
1346                                 if (owner != null)
1347                                         Xlib.XSetTransientForHint (display.Handle, WholeWindow, owner.WholeWindow);
1348                                 else
1349                                         Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.WholeWindow);
1350                         }
1351                         else {
1352                                 Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms.XA_WM_TRANSIENT_FOR);
1353                         }
1354
1355                         return true;
1356                 }
1357
1358                 public bool SetVisible (bool visible, bool activate)
1359                 {
1360                         Visible = visible;
1361
1362                         if (visible) {
1363                                 if (Control.FromHandle (Handle) is Form) {
1364                                         FormWindowState s;
1365
1366                                         s = ((Form)Control.FromHandle(Handle)).WindowState;
1367
1368                                         Map ();
1369
1370                                         switch(s) {
1371                                         case FormWindowState.Minimized: SetWindowState (FormWindowState.Minimized); break;
1372                                         case FormWindowState.Maximized: SetWindowState (FormWindowState.Maximized); break;
1373                                         }
1374
1375                                 } else {
1376                                         Map ();
1377                                 }
1378
1379                                 display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
1380                         } else {
1381                                 Unmap ();
1382                         }
1383
1384                         return true;
1385                 }
1386
1387                 public FormWindowState GetWindowState ()
1388                 {
1389                         IntPtr                  actual_atom;
1390                         int                     actual_format;
1391                         IntPtr                  nitems;
1392                         IntPtr                  bytes_after;
1393                         IntPtr                  prop = IntPtr.Zero;
1394                         IntPtr                  atom;
1395                         int                     maximized;
1396                         bool                    minimized;
1397                         XWindowAttributes       attributes;
1398
1399                         maximized = 0;
1400                         minimized = false;
1401                         Xlib.XGetWindowProperty (display.Handle, WholeWindow,
1402                                                  display.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr (256), false,
1403                                                  display.Atoms.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1404
1405                         if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
1406                                 for (int i = 0; i < (long)nitems; i++) {
1407                                         // XXX 64 bit clean?
1408                                         atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
1409                                         if ((atom == display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ) || (atom == display.Atoms._NET_WM_STATE_MAXIMIZED_VERT))
1410                                                 maximized++;
1411                                         else if (atom == display.Atoms._NET_WM_STATE_HIDDEN)
1412                                                 minimized = true;
1413                                 }
1414                                 Xlib.XFree(prop);
1415                         }
1416
1417                         if (minimized)
1418                                 return FormWindowState.Minimized;
1419                         else if (maximized == 2)
1420                                 return FormWindowState.Maximized;
1421
1422                         attributes = new XWindowAttributes();
1423                         Xlib.XGetWindowAttributes (display.Handle, ClientWindow, ref attributes);
1424                         if (attributes.map_state == MapState.IsUnmapped)
1425                                 return (FormWindowState)(-1);
1426
1427                         return FormWindowState.Normal;
1428                 }
1429
1430
1431                 public void SetWindowState (FormWindowState state)
1432                 {
1433                         FormWindowState current_state;
1434
1435                         current_state = GetWindowState ();
1436
1437                         if (current_state == state)
1438                                 return;
1439
1440                         switch (state) {
1441                         case FormWindowState.Normal:
1442                                 if (current_state == FormWindowState.Minimized)
1443                                         Map ();
1444                                 else if (current_state == FormWindowState.Maximized)
1445                                         display.SendNetWMMessage (WholeWindow,
1446                                                                   display.Atoms._NET_WM_STATE, (IntPtr)2 /* toggle */,
1447                                                                   display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ,
1448                                                                   display.Atoms._NET_WM_STATE_MAXIMIZED_VERT);
1449                                 Activate ();
1450                                 break;
1451
1452                         case FormWindowState.Minimized:
1453                                 if (current_state == FormWindowState.Maximized)
1454                                         display.SendNetWMMessage (WholeWindow,
1455                                                                   display.Atoms._NET_WM_STATE, (IntPtr)2 /* toggle */,
1456                                                                   display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ,
1457                                                                   display.Atoms._NET_WM_STATE_MAXIMIZED_VERT);
1458
1459                                 // FIXME multiscreen support
1460                                 Xlib.XIconifyWindow (display.Handle, WholeWindow, display.DefaultScreen);
1461                                 break;
1462
1463                         case FormWindowState.Maximized:
1464                                 if (current_state == FormWindowState.Minimized)
1465                                         Map ();
1466
1467                                 display.SendNetWMMessage (WholeWindow,
1468                                                           display.Atoms._NET_WM_STATE, (IntPtr)1 /* Add */,
1469                                                           display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ,
1470                                                           display.Atoms._NET_WM_STATE_MAXIMIZED_VERT);
1471                                 Activate ();
1472                                 break;
1473                         }
1474                 }
1475
1476                 public bool SetZOrder (X11Hwnd after_hwnd, bool top, bool bottom)
1477                 {
1478                         if (top) {
1479                                 Xlib.XRaiseWindow (display.Handle, WholeWindow);
1480                                 return true;
1481                         }
1482                         else if (bottom) {
1483                                 Xlib.XLowerWindow (display.Handle, WholeWindow);
1484                                 return true;
1485                         }
1486                         else {
1487                                 if (after_hwnd == null) {
1488                                         Update_USER_TIME ();
1489                                         Xlib.XRaiseWindow (display.Handle, WholeWindow);
1490                                         display.SendNetWMMessage (WholeWindow, display.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
1491                                         return true;
1492                                 }
1493
1494                                 XWindowChanges values = new XWindowChanges();
1495                                 values.sibling = after_hwnd.WholeWindow;
1496                                 values.stack_mode = StackMode.Below;
1497
1498                                 Xlib.XConfigureWindow (display.Handle, WholeWindow, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
1499                         }
1500                         return false;
1501                 }
1502
1503                 public X11Display Display {
1504                         get { return display; }
1505                 }
1506
1507                 public string Text {
1508                         get { return text; }
1509                         set {
1510                                 if (value == null)
1511                                         value = "";
1512
1513                                 if (value == text)
1514                                         return;
1515
1516                                 text = value;
1517
1518                                 Xlib.XChangeProperty(display.Handle, WholeWindow,
1519                                                      display.Atoms._NET_WM_NAME, display.Atoms.UNICODETEXT, 8,
1520                                                      PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
1521
1522                                 // XXX this has problems with UTF8.
1523                                 // we need to either use the actual
1524                                 // text if it's latin-1, or convert it
1525                                 // to compound text if it's in a
1526                                 // different charset.
1527                                 Xlib.XStoreName(display.Handle, WholeWindow, text);
1528                         }
1529                 }
1530
1531                 public bool GetText (out string text)
1532                 {
1533                         IntPtr actual_atom;
1534                         int actual_format;
1535                         IntPtr nitems;
1536                         IntPtr bytes_after;
1537                         IntPtr prop = IntPtr.Zero;
1538
1539                         Xlib.XGetWindowProperty (display.Handle, WholeWindow,
1540                                                  display.Atoms._NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
1541                                                  display.Atoms.UNICODETEXT, out actual_atom, out actual_format,
1542                                                  out nitems, out bytes_after, ref prop);
1543
1544                         if ((long)nitems > 0 && prop != IntPtr.Zero) {
1545                                 text = Marshal.PtrToStringUni (prop, (int)nitems);
1546                                 Xlib.XFree (prop);
1547                                 return true;
1548                         }
1549                         else {
1550                                 // fallback on the non-_NET property
1551                                 IntPtr  textptr;
1552
1553                                 textptr = IntPtr.Zero;
1554
1555                                 Xlib.XFetchName (display.Handle, WholeWindow, ref textptr);
1556                                 if (textptr != IntPtr.Zero) {
1557                                         text = Marshal.PtrToStringAnsi(textptr);
1558                                         Xlib.XFree(textptr);
1559                                         return true;
1560                                 } else {
1561                                         text = "";
1562                                         return false;
1563                                 }
1564                         }
1565                 }
1566
1567                 public IntPtr WINDOW_TYPE {
1568                         get {
1569                                 if (refetch_window_type) {
1570                                         window_type = GetAtomListProperty (display.Atoms._NET_WM_WINDOW_TYPE);
1571                                         refetch_window_type = false;
1572                                 }
1573
1574                                 return window_type.Length > 0 ? window_type[0] : IntPtr.Zero;
1575                         }
1576                         set {
1577                                 Set_WINDOW_TYPE (new IntPtr[] {value}, 1);
1578                         }
1579                 }
1580
1581                 public void Set_WINDOW_TYPE (IntPtr[] value, int count)
1582                 {
1583                         if (refetch_window_type) {
1584                                 window_type = GetAtomListProperty (display.Atoms._NET_WM_WINDOW_TYPE);
1585                                 refetch_window_type = false;
1586                         }
1587
1588                         if (ArrayDifferent (window_type, value)) {
1589                                 window_type = value;
1590                                 Xlib.XChangeProperty (display.Handle, WholeWindow,
1591                                                       display.Atoms._NET_WM_WINDOW_TYPE, display.Atoms.XA_ATOM, 32,
1592                                                       PropertyMode.Replace, window_type, window_type.Length);
1593                         }
1594                 }
1595
1596                 public void Set_WM_STATE (IntPtr[] value, int count)
1597                 {
1598                         if (ArrayDifferent (wm_state, value)) {
1599                                 wm_state = value;
1600                                 Xlib.XChangeProperty (display.Handle, WholeWindow,
1601                                                       display.Atoms._NET_WM_STATE, display.Atoms.XA_ATOM, 32,
1602                                                       PropertyMode.Replace, wm_state, wm_state.Length);
1603                         }
1604                 }
1605
1606                 public void Update_USER_TIME ()
1607                 {
1608                         int[] args;
1609
1610                         args = new int[2];
1611                         args[0] = display.CurrentTimestamp;
1612                         Xlib.XChangeProperty (display.Handle, WholeWindow,
1613                                               display.Atoms._NET_WM_USER_TIME, display.Atoms.XA_CARDINAL, 32,
1614                                               PropertyMode.Replace, args, 1);
1615                 }
1616
1617                 public IntPtr[] GetAtomListProperty (IntPtr atom)
1618                 {
1619                         IntPtr  actual_atom;
1620                         int     actual_format;
1621                         IntPtr  nitems;
1622                         IntPtr  bytes_after;
1623                         IntPtr  prop = IntPtr.Zero;
1624
1625                         Xlib.XGetWindowProperty (display.Handle, WholeWindow,
1626                                                  atom, IntPtr.Zero, new IntPtr (Int32.MaxValue), false,
1627                                                  display.Atoms.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1628
1629                         if (actual_atom != display.Atoms.XA_ATOM ||
1630                             (long)nitems == 0 ||
1631                             prop == IntPtr.Zero) {
1632                                 return new IntPtr[0];
1633                         }
1634
1635                         IntPtr[] values = new IntPtr[(long)nitems];
1636                         int ofs = 0;
1637
1638                         for (int i = 0; i < values.Length; i ++) {
1639                                 values[i] = Marshal.ReadIntPtr (prop, ofs);  ofs += IntPtr.Size;
1640                         }
1641
1642                         Xlib.XFree (prop);
1643
1644                         return values;
1645                 }
1646
1647                 bool ArrayDifferent (IntPtr[] a, IntPtr[] b)
1648                 {
1649                         if (a.Length != b.Length)
1650                                 return true;
1651
1652                         for (int i = 0; i < a.Length; i ++) {
1653                                 if (a[i] != b[i])
1654                                         return true;
1655                         }
1656
1657                         return false;
1658                 }
1659         }
1660 }