Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms.X11Internal / X11Display.cs
index ef2250d3a9a5d3b65868f9787a21d9795c404036..43b39dcd4fc9a9d78ccc3fd62494fcc426ea1d42 100644 (file)
@@ -853,7 +853,64 @@ namespace System.Windows.Forms.X11Internal {
 
                        return cursor;
                }
+               
+               public Bitmap DefineStdCursorBitmap (StdCursor id)
+               {
+                       CursorFontShape shape;
+                       string name;
+                       IntPtr theme;
+                       int size;
+                       Bitmap bmp = null;
+
+                       try {
+                               shape = XplatUIX11.StdCursorToFontShape (id);
+                               name = shape.ToString ().Replace ("XC_", string.Empty);
+                               size = XplatUIX11.XcursorGetDefaultSize (Handle);
+                               theme = XplatUIX11.XcursorGetTheme (Handle);
+                               IntPtr images_ptr = XplatUIX11.XcursorLibraryLoadImages (name, theme, size);
+#if debug
+                               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);
+#endif
+
+                               if (images_ptr == IntPtr.Zero) {
+                                       return null;
+                               }
 
+                               XcursorImages images = (XcursorImages)Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
+#if debug
+                               Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
+#endif
+
+                               if (images.nimage > 0) {
+                                       // We only care about the first image.
+                                       XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
+
+#if debug
+                                       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);
+#endif
+                                       // A sanity check
+                                       if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
+                                               int [] pixels = new int [image.width * image.height];
+                                               Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
+                                               bmp = new Bitmap (image.width, image.height);
+                                               for (int w = 0; w < image.width; w++) {
+                                                       for (int h = 0; h < image.height; h++) {
+                                                               bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               XplatUIX11.XcursorImagesDestroy (images_ptr);
+
+                       } catch (DllNotFoundException ex) {
+                               Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
+                               return null;
+                       }
+
+                       return bmp;
+               }
+               
                public IntPtr DefineStdCursor (StdCursor id)
                {
                        CursorFontShape shape;
@@ -1099,6 +1156,8 @@ namespace System.Windows.Forms.X11Internal {
                {
                        CleanupCachedWindows (hwnd);
 
+                       hwnd.SendParentNotify (Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
+
                        ArrayList windows = new ArrayList ();
 
                        AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
@@ -1150,7 +1209,7 @@ namespace System.Windows.Forms.X11Internal {
                                // of ours but not the modal one, switch back to the modal window
 
                                if (ActiveWindow != null &&
-                                   NativeWindow.FindWindow (ActiveWindow.Handle) != null) {
+                                   NativeWindow.FromHandle (ActiveWindow.Handle) != null) {
                                        if (ActiveWindow != (X11Hwnd)ModalWindows.Peek())
                                                ((X11Hwnd)ModalWindows.Peek()).Activate ();
                                }
@@ -1438,7 +1497,7 @@ namespace System.Windows.Forms.X11Internal {
                }
 
 
-               public PaintEventArgs PaintEventStart (IntPtr handle, bool client)
+               public PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client)
                {
                        X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
 
@@ -1447,14 +1506,14 @@ namespace System.Windows.Forms.X11Internal {
                                HideCaret();
                        }
 
-                       return hwnd.PaintEventStart (client);
+                       return hwnd.PaintEventStart (ref m, client);
                }
 
-               public void PaintEventEnd (IntPtr handle, bool client)
+               public void PaintEventEnd (ref Message m, IntPtr handle, bool client)
                {
                        X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
 
-                       hwnd.PaintEventEnd (client);
+                       hwnd.PaintEventEnd (ref m, client);
 
                        if (Caret.Visible == true) {
                                ShowCaret();
@@ -1711,6 +1770,38 @@ namespace System.Windows.Forms.X11Internal {
                        get { return HoverState.Interval; }
                }
 
+               public Rectangle VirtualScreen {
+                       get {
+                               IntPtr actual_atom;
+                               int actual_format;
+                               IntPtr nitems;
+                               IntPtr bytes_after;
+                               IntPtr prop = IntPtr.Zero;
+                               int width;
+                               int height;
+
+                               Xlib.XGetWindowProperty (display, RootWindow.Handle,
+                                                        Atoms._NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL,
+                                                        out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+                               if ((long)nitems < 2)
+                                       goto failsafe;
+
+                               width = Marshal.ReadIntPtr(prop, 0).ToInt32();
+                               height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
+                               Xlib.XFree(prop);
+
+                               return new Rectangle(0, 0, width, height);
+
+                       failsafe:
+                               XWindowAttributes attributes = new XWindowAttributes();
+
+                               Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
+
+                               return new Rectangle(0, 0, attributes.width, attributes.height);
+                       }
+               }
+
                public Rectangle WorkingArea {
                        get {
                                IntPtr actual_atom;
@@ -1872,8 +1963,6 @@ namespace System.Windows.Forms.X11Internal {
 
                                switch (xevent.type) {
                                case XEventName.KeyPress:
-                                       if (Dnd.InDrag ())
-                                               Dnd.HandleKeyPress (ref xevent);
                                        Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg);
                                        return true;
 
@@ -1974,16 +2063,25 @@ namespace System.Windows.Forms.X11Internal {
                                                ClickPending.Time = (long)xevent.ButtonEvent.time;
                                        }
 
+                                       if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
+                                               hwnd.SendParentNotify (msg.message, MousePosition.X, MousePosition.Y);
+
+                                               // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
+                                               // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after 
+                                               // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
+                                               XEvent motionEvent = new XEvent ();
+                                               motionEvent.type = XEventName.MotionNotify;
+                                               motionEvent.MotionEvent.display = display;
+                                               motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
+                                               motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
+                                               motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
+                                               hwnd.Queue.Enqueue (motionEvent);
+                                       }
+
                                        return true;
                                }
 
                                case XEventName.ButtonRelease:
-                                       if (Dnd.InDrag()) {
-                                               if (Dnd.HandleButtonRelease (ref xevent))
-                                                       return true;
-                                               // Don't return here, so that the BUTTONUP message can get through
-                                       }
-
                                        switch(xevent.ButtonEvent.button) {
                                        case 1:
                                                if (client) {
@@ -2036,6 +2134,19 @@ namespace System.Windows.Forms.X11Internal {
                                        msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
                                        MousePosition.X = xevent.ButtonEvent.x;
                                        MousePosition.Y = xevent.ButtonEvent.y;
+
+                                               // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
+                                               // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after 
+                                               // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
+                                       if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
+                                               XEvent motionEvent = new XEvent ();
+                                               motionEvent.type = XEventName.MotionNotify;
+                                               motionEvent.MotionEvent.display = display;
+                                               motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
+                                               motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
+                                               motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
+                                               hwnd.Queue.Enqueue (motionEvent);
+                                       }
                                        return true;
 
                                case XEventName.MotionNotify:
@@ -2048,9 +2159,6 @@ namespace System.Windows.Forms.X11Internal {
                                                                  xevent.MotionEvent.x, xevent.MotionEvent.y);
 #endif
 
-                                               if (Dnd.HandleMotionNotify (ref xevent))
-                                                       goto ProcessNextMessage;
-
                                                if (Grab.Hwnd != IntPtr.Zero)
                                                        msg.hwnd = Grab.Hwnd;
                                                else
@@ -2137,7 +2245,7 @@ namespace System.Windows.Forms.X11Internal {
                                            (xevent.CrossingEvent.window != hwnd.ClientWindow))
                                                goto ProcessNextMessage;
 
-                                       msg.message=Msg.WM_MOUSE_LEAVE;
+                                       msg.message=Msg.WM_MOUSELEAVE;
                                        HoverState.Timer.Enabled = false;
                                        HoverState.Window = IntPtr.Zero;
 
@@ -2191,6 +2299,28 @@ namespace System.Windows.Forms.X11Internal {
                                        hwnd.HandleConfigureNotify (xevent);
                                        goto ProcessNextMessage;
 
+                               case XEventName.MapNotify: {
+                                       if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+                                               hwnd.Mapped = true;
+                                               msg.message = Msg.WM_SHOWWINDOW;
+                                               msg.wParam = (IntPtr) 1;
+                                               // XXX we're missing the lParam..
+                                               break;
+                                       }
+                                       goto ProcessNextMessage;
+                               }
+
+                               case XEventName.UnmapNotify: {
+                                       if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
+                                               hwnd.Mapped = false;
+                                               msg.message = Msg.WM_SHOWWINDOW;
+                                               msg.wParam = (IntPtr) 0;
+                                               // XXX we're missing the lParam..
+                                               break;
+                                       }
+                                       goto ProcessNextMessage;
+                               }
+
                                case XEventName.FocusIn:
                                        // We received focus. We use X11 focus only to know if the app window does or does not have focus
                                        // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
@@ -2234,7 +2364,7 @@ namespace System.Windows.Forms.X11Internal {
                                        goto ProcessNextMessage;
 
                                case XEventName.Expose:
-                                       if (queue.PostQuitState || !hwnd.Mapped) {
+                                       if (!hwnd.Mapped) {
                                                hwnd.PendingExpose = hwnd.PendingNCExpose = false;
                                                continue;
                                        }
@@ -2329,7 +2459,13 @@ namespace System.Windows.Forms.X11Internal {
                                                msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
                                                msg.wParam = xevent.ClientMessageEvent.ptr3;
                                                msg.lParam = xevent.ClientMessageEvent.ptr4;
-                                               return true;
+
+                                               // if we posted a WM_QUIT message, make sure we return
+                                               // false here as well.
+                                               if (msg.message == (Msg)Msg.WM_QUIT)
+                                                       return false;
+                                               else
+                                                       return true;
                                        }
 
                                        if (xevent.ClientMessageEvent.message_type == Atoms._XEMBED) {
@@ -2362,6 +2498,7 @@ namespace System.Windows.Forms.X11Internal {
                                                        goto ProcessNextMessage;
                                                }
                                        }
+
                                        goto ProcessNextMessage;
 
                                case XEventName.PropertyNotify:
@@ -2371,23 +2508,9 @@ namespace System.Windows.Forms.X11Internal {
                                }
                        } while (true);
 
-#if notyet
-                       // XXX need to figure out how to post
-                       // WM_ENTERIDLE only in specific conditions
-                       // (we've handled some input events)
-                       if (!queue.PostQuitState) {
-                               msg.hwnd= IntPtr.Zero;
-                               msg.message = Msg.WM_ENTERIDLE;
-                               return true;
-                       }
-#else
-                       goto ProcessNextMessage;
-#endif
-
-                       // We reset ourselves so GetMessage can be called again
-                       queue.PostQuitState = false;
-
-                       return false;
+                       msg.hwnd= IntPtr.Zero;
+                       msg.message = Msg.WM_ENTERIDLE;
+                       return true;
                }
 
                [MonoTODO("Implement filtering and PM_NOREMOVE")]
@@ -2516,6 +2639,9 @@ namespace System.Windows.Forms.X11Internal {
 
                public void DrawReversibleLine (Point start, Point end, Color backColor)
                {
+                       if (backColor.GetBrightness() < 0.5)
+                               backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
                        IntPtr gc = GetReversibleScreenGC (backColor);
 
                        Xlib.XDrawLine (display, RootWindow.Handle, gc, start.X, start.Y, end.X, end.Y);
@@ -2525,6 +2651,9 @@ namespace System.Windows.Forms.X11Internal {
 
                public void FillReversibleRectangle (Rectangle rectangle, Color backColor)
                {
+                       if (backColor.GetBrightness() < 0.5)
+                               backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
                        IntPtr gc = GetReversibleScreenGC (backColor);
 
                        if (rectangle.Width < 0) {
@@ -2543,6 +2672,9 @@ namespace System.Windows.Forms.X11Internal {
 
                public void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
                {
+                       if (backColor.GetBrightness() < 0.5)
+                               backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
                        IntPtr gc = GetReversibleScreenGC (backColor);
 
                        if (rectangle.Width < 0) {