#endif
Keyboard = new X11Keyboard(display, foster_hwnd.Handle);
- Dnd = new X11Dnd (display);
+ Dnd = new X11Dnd (display, Keyboard);
ErrorExceptions = false;
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;
{
CleanupCachedWindows (hwnd);
+ hwnd.SendParentNotify (Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
+
ArrayList windows = new ArrayList ();
AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
// 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 ();
}
}
- public PaintEventArgs PaintEventStart (IntPtr handle, bool client)
+ public PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client)
{
X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
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();
public IntPtr OverrideCursor {
get { return OverrideCursorHandle; }
- set { OverrideCursorHandle = value; }
+ set {
+ if (Grab.Hwnd != IntPtr.Zero) {
+ Xlib.XChangeActivePointerGrab (display,
+ EventMask.ButtonMotionMask |
+ EventMask.PointerMotionMask |
+ EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask,
+ value, IntPtr.Zero);
+ return;
+ }
+
+ OverrideCursorHandle = value;
+ }
}
public X11RootHwnd RootWindow {
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;
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()) {
- Dnd.HandleButtonRelease (ref xevent);
- // Don't return here, so that the BUTTONUP message can get through
- }
-
switch(xevent.ButtonEvent.button) {
case 1:
if (client) {
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:
xevent.MotionEvent.x, xevent.MotionEvent.y);
#endif
- if (Dnd.HandleMotionNotify (ref xevent))
- goto ProcessNextMessage;
-
if (Grab.Hwnd != IntPtr.Zero)
msg.hwnd = Grab.Hwnd;
else
(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;
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
goto ProcessNextMessage;
case XEventName.Expose:
- if (queue.PostQuitState || !hwnd.Mapped) {
+ if (!hwnd.Mapped) {
hwnd.PendingExpose = hwnd.PendingNCExpose = false;
continue;
}
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) {
goto ProcessNextMessage;
}
}
+
goto ProcessNextMessage;
case XEventName.PropertyNotify:
}
} 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")]
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);
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) {
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) {