// Peter Bartok pbartok@novell.com
//
//
-// $Revision: 1.12 $
-// $Modtime: $
-// $Log: XplatUIX11.cs,v $
-// Revision 1.12 2004/08/09 19:48:08 pbartok
-// - Fixed default sizing for child windows
-//
-// Revision 1.11 2004/08/09 18:56:55 pbartok
-// - Added generation of WM_DESTROY message
-// - Added handling of window manager induced shutdown
-//
-// Revision 1.10 2004/08/09 16:05:16 jackson
-// These properties are handled by the theme now.
-//
-// Revision 1.9 2004/08/08 21:08:10 jordi
-// fixes keyboard crash
-//
-// Revision 1.8 2004/08/06 23:46:56 pbartok
-// - Implemented GetParent
-//
-// Revision 1.7 2004/08/06 23:17:44 pbartok
-// - Fixed Refresh and Invalidate
-//
-// Revision 1.6 2004/08/06 21:30:56 pbartok
-// - Fixed recursive loop when resizing
-// - Improved/fixed redrawing on expose messages
-//
-// Revision 1.5 2004/08/06 15:53:39 jordi
-// X11 keyboard navigation
-//
-// Revision 1.4 2004/08/06 14:02:33 pbartok
-// - Fixed reparenting
-// - Fixed window border creation
-//
-// Revision 1.3 2004/08/05 21:38:02 pbartok
-// - Attempted fix for reparenting problems
-//
-// Revision 1.2 2004/08/04 20:11:24 pbartok
-// - Added Invalidate handling
-//
-// Revision 1.1 2004/07/09 05:21:25 pbartok
-// - Initial check-in
-//
-//
// NOT COMPLETE
using System;
+using System.Threading;
using System.Drawing;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
+using System.Net;
+using System.Net.Sockets;
+
+// Only do the poll when building with mono for now
+#if __MonoCS__
+using Mono.Posix;
+#endif
/// X11 Version
namespace System.Windows.Forms {
- public class XplatUIX11 : XplatUIDriver {
+ internal class XplatUIX11 : XplatUIDriver {
#region Local Variables
private static XplatUIX11 instance;
private static int ref_count;
+ private static bool themes_enabled;
private static IntPtr DisplayHandle; // X11 handle to display
+ private static int screen_num; // Screen number used
+ private static IntPtr root_window; // Handle of the root window for the screen/display
private static IntPtr FosterParent; // Container to hold child windows until their parent exists
private static int wm_protocols; // X Atom
private static int wm_delete_window; // X Atom
+ private static IntPtr async_method;
+ private static uint default_colormap; // X Colormap ID
internal static Keys key_state;
internal static MouseButtons mouse_state;
internal static Point mouse_position;
- internal static Rectangle paint_area;
+ internal static bool grab_confined; // Is the current grab (if any) confined to grab_area?
+ internal static IntPtr grab_hwnd; // The window that is grabbed
+ internal static Rectangle grab_area; // The area the current grab is confined to
internal static bool is_visible;
+
+ private static Hashtable handle_data;
+ private Queue message_queue;
+
+ private ArrayList timer_list;
+ private Thread timer_thread;
+ private AutoResetEvent timer_wait;
+ private Socket listen;
+ private Socket wake;
+
+#if __MonoCS__
+ private pollfd [] pollfds;
+#endif
+
+ private object xlib_lock = new object ();
+
+ private static readonly EventMask SelectInputMask = EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask |
+ EventMask.KeyPressMask |
+ EventMask.KeyReleaseMask |
+ EventMask.EnterWindowMask |
+ EventMask.LeaveWindowMask |
+ EventMask.ExposureMask |
+ EventMask.PointerMotionMask |
+ EventMask.VisibilityChangeMask |
+ EventMask.StructureNotifyMask;
+
#endregion // Local Variables
internal override Keys ModifierKeys {
}
#region Constructor & Destructor
+ // This is always called from a locked context
private XplatUIX11() {
// Handle singleton stuff first
ref_count=0;
+ message_queue = new Queue ();
+ timer_list = new ArrayList ();
+
// Now regular initialization
- DisplayHandle=XOpenDisplay(IntPtr.Zero);
- key_state=Keys.None;
- mouse_state=MouseButtons.None;
- mouse_position=Point.Empty;
- paint_area=new Rectangle(0, 0, 0, 0);
+ SetDisplay(XOpenDisplay(IntPtr.Zero));
- // Create the foster parent
- FosterParent=XCreateSimpleWindow(DisplayHandle, XRootWindow(DisplayHandle, 0), 0, 0, 1, 1, 4, 0, 0);
- if (FosterParent==IntPtr.Zero) {
- Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
- }
+ listen = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
+ IPEndPoint ep = new IPEndPoint (IPAddress.Loopback, 0);
+ listen.Bind (ep);
+ listen.Listen (1);
+
+ wake = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
+ wake.Connect (listen.LocalEndPoint);
- // Prepare for shutdown
- wm_protocols=XInternAtom(DisplayHandle, "WM_PROTOCOLS", false);
- wm_delete_window=XInternAtom(DisplayHandle, "WM_DELETE_WINDOW", false);
+#if __MonoCS__
+ pollfds = new pollfd [2];
+ pollfds [0] = new pollfd ();
+ pollfds [0].fd = XConnectionNumber (DisplayHandle);
+ pollfds [0].events = PollEvents.POLLIN;
+
+ pollfds [1] = new pollfd ();
+ pollfds [1].fd = wake.Handle.ToInt32 ();
+ pollfds [1].events = PollEvents.POLLIN;
+#endif
}
~XplatUIX11() {
- if (DisplayHandle!=IntPtr.Zero) {
- XCloseDisplay(DisplayHandle);
- DisplayHandle=IntPtr.Zero;
+ lock (this) {
+ if (DisplayHandle!=IntPtr.Zero) {
+ XCloseDisplay(DisplayHandle);
+ DisplayHandle=IntPtr.Zero;
+ }
}
}
#endregion // Constructor & Destructor
#region Singleton Specific Code
public static XplatUIX11 GetInstance() {
- if (instance==null) {
- instance=new XplatUIX11();
+ lock (typeof (XplatUIX11)) {
+ if (instance==null) {
+ instance=new XplatUIX11();
+ }
+ ref_count++;
}
- ref_count++;
return instance;
}
}
#endregion
+ internal override event EventHandler Idle;
+
#region Public Static Methods
- internal override IntPtr InitializeDriver() {\r
- if (DisplayHandle==IntPtr.Zero) {
- DisplayHandle=XOpenDisplay(IntPtr.Zero);
- key_state=Keys.None;
- mouse_state=MouseButtons.None;
- mouse_position=Point.Empty;
+ internal override IntPtr InitializeDriver() {
+ lock (this) {
+ if (DisplayHandle==IntPtr.Zero) {
+ DisplayHandle=XOpenDisplay(IntPtr.Zero);
+ key_state=Keys.None;
+ mouse_state=MouseButtons.None;
+ mouse_position=Point.Empty;
+ }
}
+ return IntPtr.Zero;
+ }
+
+ internal static void SetDisplay(IntPtr display_handle) {
+ if (display_handle != IntPtr.Zero) {
+ IntPtr Screen;
+
+ if (FosterParent != IntPtr.Zero) {
+ XDestroyWindow(DisplayHandle, FosterParent);
+ }
+ if (DisplayHandle != IntPtr.Zero) {
+ XCloseDisplay(DisplayHandle);
+ }
- return IntPtr.Zero;\r
- }\r
+ DisplayHandle=display_handle;
+
+ // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has
+ // been hacked to do this for us.
+ Graphics.FromHdcInternal (DisplayHandle);
+
+ // Create a few things
+ key_state = Keys.None;
+ mouse_state = MouseButtons.None;
+ mouse_position = Point.Empty;
+ Screen = XDefaultScreenOfDisplay(DisplayHandle);
+ //screen_num = XScreenNumberOfScreen(DisplayHandle, Screen);
+ screen_num = 0;
+ root_window = XRootWindow(display_handle, screen_num);
+ default_colormap = XDefaultColormap(display_handle, screen_num);
+
+ // Create the foster parent
+ FosterParent=XCreateSimpleWindow(display_handle, root_window, 0, 0, 1, 1, 4, 0, 0);
+ if (FosterParent==IntPtr.Zero) {
+ Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
+ }
+ // Prepare for shutdown
+ wm_protocols=XInternAtom(display_handle, "WM_PROTOCOLS", false);
+ wm_delete_window=XInternAtom(display_handle, "WM_DELETE_WINDOW", false);
- internal override void ShutdownDriver(IntPtr token) {\r
- if (DisplayHandle!=IntPtr.Zero) {
- XCloseDisplay(DisplayHandle);
- DisplayHandle=IntPtr.Zero;
+ handle_data = new Hashtable ();
+ }
+ }
+
+ internal override void ShutdownDriver(IntPtr token) {
+ lock (this) {
+ if (DisplayHandle!=IntPtr.Zero) {
+ XCloseDisplay(DisplayHandle);
+ DisplayHandle=IntPtr.Zero;
+ }
}
- }\r
+ }
internal void Version() {
Console.WriteLine("XplatUIX11.Exit");
}
+ internal override void GetDisplaySize(out Size size) {
+ XWindowAttributes attributes=new XWindowAttributes();
+
+ lock (xlib_lock) {
+ XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
+ }
+
+ size = new Size(attributes.width, attributes.height);
+ }
+
+ internal override void EnableThemes() {
+ themes_enabled=true;
+ }
+
internal override IntPtr CreateWindow(CreateParams cp) {
- IntPtr WindowHandle;
- IntPtr ParentHandle;
- int X;
- int Y;
- int Width;
- int Height;
- int BorderWidth;
- int protocols;
+ IntPtr WindowHandle;
+ IntPtr ParentHandle;
+ int X;
+ int Y;
+ int Width;
+ int Height;
+ int BorderWidth;
+ int protocols;
ParentHandle=cp.Parent;
if (Width<1) Width=1;
if (Height<1) Height=1;
- if (ParentHandle==IntPtr.Zero) {
- if ((cp.Style & (int)WindowStyles.WS_CHILD)!=0) {
- // We need to use our foster parent window until this poor child gets it's parent assigned
- ParentHandle=FosterParent;
- } else {
- if (X<1) X=50;
- if (Y<1) Y=50;
- BorderWidth=4;
- ParentHandle=XRootWindow(DisplayHandle, 0);
- }
- }
- WindowHandle=XCreateSimpleWindow(DisplayHandle, ParentHandle, X, Y, Width, Height, BorderWidth, 0, 0);
- XMapWindow(DisplayHandle, WindowHandle);
+ lock (xlib_lock) {
+ if (ParentHandle==IntPtr.Zero) {
+ if ((cp.Style & (int)WindowStyles.WS_CHILD)!=0) {
+ // We need to use our foster parent window until
+ // this poor child gets it's parent assigned
+ ParentHandle=FosterParent;
+ } else {
+ if (X<1) X=50;
+ if (Y<1) Y=50;
+ BorderWidth=4;
+ ParentHandle=XRootWindow(DisplayHandle, 0);
+ }
+ }
- XSelectInput(DisplayHandle, WindowHandle,
- EventMask.ButtonPressMask |
- EventMask.ButtonReleaseMask |
- EventMask.KeyPressMask |
- EventMask.KeyReleaseMask |
- EventMask.EnterWindowMask |
- EventMask.LeaveWindowMask |
- EventMask.ExposureMask |
- EventMask.PointerMotionMask |
- EventMask.ResizeRedirectMask |
- EventMask.VisibilityChangeMask |
- EventMask.StructureNotifyMask);
- XSetWindowBackground(DisplayHandle, WindowHandle, (uint)this.BackColor.ToArgb());
- is_visible=true;
+ WindowHandle=XCreateSimpleWindow(DisplayHandle, ParentHandle, X, Y, Width, Height, BorderWidth, 0, 0);
+ XMapWindow(DisplayHandle, WindowHandle);
- protocols=wm_delete_window;
- XSetWMProtocols(DisplayHandle, WindowHandle, ref protocols, 1);
+ XSelectInput(DisplayHandle, WindowHandle, SelectInputMask);
+ is_visible=true;
+ protocols=wm_delete_window;
+ XSetWMProtocols(DisplayHandle, WindowHandle, ref protocols, 1);
+ }
return(WindowHandle);
}
}
internal override void DestroyWindow(IntPtr handle) {
- XDestroyWindow(DisplayHandle, handle);
- return;
+ lock (this) {
+ HandleData data = (HandleData) handle_data [handle];
+ if (data != null) {
+ data.Dispose ();
+ handle_data [handle] = null;
+ }
+ XDestroyWindow(DisplayHandle, handle);
+ }
}
internal override void RefreshWindow(IntPtr handle) {
- XWindowAttributes attributes=new XWindowAttributes();
- XEvent xevent = new XEvent();
+ XEvent xevent = new XEvent();
+ IntPtr root;
+ int border_width;
+ int depth;
+ int x;
+ int y;
+ int width;
+ int height;
+
+ lock (xlib_lock) {
+
+ // We need info about our window to generate the expose
+ XGetGeometry(DisplayHandle, handle, out root, out x, out y,
+ out width, out height, out border_width, out depth);
+
+ xevent.type=XEventName.Expose;
+ xevent.ExposeEvent.display=DisplayHandle;
+ xevent.ExposeEvent.window=handle;
+ xevent.ExposeEvent.x=0;
+ xevent.ExposeEvent.y=0;
+ xevent.ExposeEvent.width=width;
+ xevent.ExposeEvent.height=height;
+
+ XSendEvent(DisplayHandle, handle, false, EventMask.ExposureMask, ref xevent);
+ XFlush(DisplayHandle);
+ }
+ }
+
+ internal override void SetWindowBackground(IntPtr handle, Color color) {
+ XColor xcolor;
- // We need info about our window to generate the expose
- XGetWindowAttributes(DisplayHandle, handle, ref attributes);
+ xcolor = new XColor();
- xevent.type=XEventName.Expose;
- xevent.ExposeEvent.display=DisplayHandle;
- xevent.ExposeEvent.window=handle;
- xevent.ExposeEvent.x=0;
- xevent.ExposeEvent.y=0;
- xevent.ExposeEvent.width=attributes.width;
- xevent.ExposeEvent.height=attributes.height;
+ xcolor.red = (ushort)(color.R * 257);
+ xcolor.green = (ushort)(color.G * 257);
+ xcolor.blue = (ushort)(color.B * 257);
+ XAllocColor(DisplayHandle, default_colormap, ref xcolor);
- XSendEvent(DisplayHandle, handle, false, EventMask.ExposureMask, ref xevent);
- XFlush(DisplayHandle);
+ lock (xlib_lock) {
+ XSetWindowBackground(DisplayHandle, handle, xcolor.pixel);
+ XClearWindow(DisplayHandle, handle);
+ }
}
[MonoTODO("Add support for internal table of windows/DCs for looking up paint area and cleanup")]
internal override PaintEventArgs PaintEventStart(IntPtr handle) {
PaintEventArgs paint_event;
- Rectangle update_area;
- // FIXME: Assign proper values
- update_area = new Rectangle();
- paint_event = new PaintEventArgs(Graphics.FromHwnd(handle), update_area);
+ HandleData data = (HandleData) handle_data [handle];
+ if (data == null) {
+ throw new Exception ("null data on paint event start: " + handle);
- return paint_event;
- }
+ }
- internal override void PaintEventEnd(IntPtr handle) {\r
- // FIXME: Lookup in the internal list how to clean\r
- ;\r
- }\r
+ data.DeviceContext = Graphics.FromHwnd (handle);
+ paint_event = new PaintEventArgs((Graphics)data.DeviceContext, data.InvalidArea);
- internal override void SetWindowPos(IntPtr handle, Rectangle rc) {
- SetWindowPos(handle, rc.X, rc.Y, rc.Width, rc.Height);
- return;
+ return paint_event;
}
- internal override bool MoveWindow(IntPtr hWnd, int x, int y, int width, int height) {
- XMoveResizeWindow(DisplayHandle, hWnd, x, y, width, height);
- return true;
+ internal override void PaintEventEnd(IntPtr handle) {
+ HandleData data = (HandleData) handle_data [handle];
+ if (data == null)
+ throw new Exception ("null data on PaintEventEnd");
+ data.ClearInvalidArea ();
+ Graphics g = (Graphics) data.DeviceContext;
+ g.Flush ();
+ g.Dispose ();
}
internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
- XMoveResizeWindow(DisplayHandle, handle, x, y, width, height);
- return;
- }
+ // X requires a sanity check for width & height; otherwise it dies
+ if (width < 1) {
+ width = 1;
+ }
- internal override void Activate(IntPtr handle) {
- // Not sure this is the right method, but we don't use ICs either...
- XRaiseWindow(DisplayHandle, handle);
+ if (height < 1) {
+ height = 1;
+ }
+ lock (xlib_lock) {
+ XMoveResizeWindow(DisplayHandle, handle, x, y, width, height);
+ }
return;
}
- internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
- XEvent xevent = new XEvent();
+ internal override void GetWindowPos(IntPtr handle, out int x, out int y, out int width, out int height, out int client_width, out int client_height) {
+ IntPtr root;
+ int border_width;
+ int depth;
- xevent.type=XEventName.Expose;
- xevent.ExposeEvent.display=DisplayHandle;
- xevent.ExposeEvent.window=handle;
- xevent.ExposeEvent.count=0;
+ lock (xlib_lock) {
+
+ XGetGeometry(DisplayHandle, handle, out root, out x,
+ out y, out width, out height, out border_width, out depth);
+ }
- if (clear) {
- // Need to clear the whole window, so we force a redraw for the whole window
- XWindowAttributes attributes=new XWindowAttributes();
+ client_width = width;
+ client_height = height;
+ return;
+ }
- // We need info about our window to generate the expose
- XGetWindowAttributes(DisplayHandle, handle, ref attributes);
+ internal override void Activate(IntPtr handle) {
- xevent.ExposeEvent.x=0;
- xevent.ExposeEvent.y=0;
- xevent.ExposeEvent.width=attributes.width;
- xevent.ExposeEvent.height=attributes.height;
- } else {
- xevent.ExposeEvent.x=rc.Left;
- xevent.ExposeEvent.y=rc.Top;
- xevent.ExposeEvent.width=rc.Width;
- xevent.ExposeEvent.height=rc.Height;
+ lock (xlib_lock) {
+ // Not sure this is the right method, but we don't use ICs either...
+ XRaiseWindow(DisplayHandle, handle);
}
-
- XSendEvent(DisplayHandle, handle, false, EventMask.ExposureMask, ref xevent);
- // Flush is not needed, invalidate does not guarantee an immediate effect
- //XFlush(DisplayHandle);
return;
}
+ internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
+ // FIXME - we're not properly interpreting the clear flag, we're assuming it's always true
+ lock (xlib_lock) {
+ XClearArea(DisplayHandle, handle, rc.Left, rc.Top, (uint)rc.Width, (uint)rc.Height, true);
+ }
+ }
+
internal override IntPtr DefWndProc(ref Message msg) {
#if not
switch (msg.Msg) {
string keys;
int len;
msg.wParam = IntPtr.Zero;
-
- len = XLookupString(ref xevent, buffer, 24, out keysym, IntPtr.Zero);
+
+ lock (xlib_lock) {
+ len = XLookupString(ref xevent, buffer, 24, out keysym, IntPtr.Zero);
+ }
+
+ if ((keysym==XKeySym.XK_Control_L) || (keysym==XKeySym.XK_Control_R)) {
+ if (xevent.type==XEventName.KeyPress) {
+ key_state |= Keys.Control;
+ } else {
+ key_state &= ~Keys.Control;
+ }
+ }
+
+ if ((keysym==XKeySym.XK_Shift_L) || (keysym==XKeySym.XK_Shift_R)) {
+ if (xevent.type==XEventName.KeyPress) {
+ key_state |= Keys.Shift;
+ } else {
+ key_state &= ~Keys.Shift;
+ }
+ }
if (len>0) /* String is not zero terminated*/
Marshal.WriteByte (buffer, len, 0);
}
}
- if (msg.wParam == IntPtr.Zero) {
+ if ((msg.wParam == IntPtr.Zero) && (keys.Length>0)) {
char[] keychars;
keychars=keys.ToCharArray(0, 1);
msg.wParam=(IntPtr)keychars[0];
msg.lParam = (IntPtr) 1;
}
+ private IntPtr GetMousewParam(int Delta) {
+ int result = 0;
+
+ if ((mouse_state & MouseButtons.Left) != 0) {
+ result |= (int)MsgButtons.MK_LBUTTON;
+ }
+
+ if ((mouse_state & MouseButtons.Middle) != 0) {
+ result |= (int)MsgButtons.MK_MBUTTON;
+ }
+
+ if ((mouse_state & MouseButtons.Right) != 0) {
+ result |= (int)MsgButtons.MK_RBUTTON;
+ }
+
+ if ((key_state & Keys.Control) != 0) {
+ result |= (int)MsgButtons.MK_CONTROL;
+ }
+
+ if ((key_state & Keys.Shift) != 0) {
+ result |= (int)MsgButtons.MK_SHIFT;
+ }
+
+ result |= Delta << 16;
+
+ return (IntPtr)result;
+ }
+
+ private int NextTimeout (DateTime now)
+ {
+ int timeout = Int32.MaxValue;
+ lock (timer_list) {
+ foreach (Timer timer in timer_list) {
+ int next = (int) (timer.Expires - now).TotalMilliseconds;
+ if (next < 0)
+ return 0; // Have a timer that has already expired
+ if (next < timeout)
+ timeout = next;
+ }
+ }
+ if (timeout < Timer.Minimum)
+ timeout = Timer.Minimum;
+ return timeout;
+ }
+
+ private void CheckTimers (DateTime now)
+ {
+ lock (timer_list) {
+ int count = timer_list.Count;
+ if (count == 0)
+ return;
+ for (int i = 0; i < count; i++) {
+ Timer timer = (Timer) timer_list [i];
+ if (timer.Enabled && timer.Expires <= now) {
+ timer.FireTick ();
+ timer.Update (now);
+ }
+ }
+ }
+ }
+
+ private void UpdateMessageQueue ()
+ {
+ DateTime now = DateTime.Now;
+
+ int pending;
+ lock (xlib_lock) {
+ pending = XPending (DisplayHandle);
+ }
+ if (pending == 0) {
+ if (Idle != null) {
+ Idle (this, EventArgs.Empty);
+ }
+ lock (xlib_lock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+
+ if (pending == 0) {
+ int timeout = NextTimeout (now);
+ if (timeout > 0) {
+#if __MonoCS__
+ Syscall.poll (pollfds, pollfds.Length, timeout);
+#endif
+ pending = XPending (DisplayHandle);
+ }
+ }
+
+ CheckTimers (now);
+
+ if (pending == 0) {
+ lock (xlib_lock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+
+ while (pending > 0) {
+ XEvent xevent = new XEvent ();
+
+ lock (xlib_lock) {
+ XNextEvent (DisplayHandle, ref xevent);
+ }
+
+ switch (xevent.type) {
+ case XEventName.Expose:
+ HandleData data = (HandleData) handle_data [xevent.AnyEvent.window];
+ if (data == null) {
+ data = new HandleData ();
+ handle_data [xevent.AnyEvent.window] = data;
+ }
+
+ data.AddToInvalidArea (xevent.ExposeEvent.x, xevent.ExposeEvent.y,
+ xevent.ExposeEvent.width, xevent.ExposeEvent.height);
+
+ if (!data.HasExpose) {
+ lock (message_queue) {
+ message_queue.Enqueue (xevent);
+ }
+ data.HasExpose = true;
+ }
+ break;
+ case XEventName.KeyPress:
+ case XEventName.KeyRelease:
+ case XEventName.ButtonPress:
+ case XEventName.ButtonRelease:
+ case XEventName.MotionNotify:
+ case XEventName.EnterNotify:
+ case XEventName.LeaveNotify:
+ case XEventName.ConfigureNotify:
+ case XEventName.DestroyNotify:
+ case XEventName.ClientMessage:
+ lock (message_queue) {
+ message_queue.Enqueue (xevent);
+ }
+ break;
+ }
+
+ lock (xlib_lock) {
+ pending = XPending (DisplayHandle);
+ }
+ }
+ }
+
internal override bool GetMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax) {
- XEvent xevent = new XEvent();
+ XEvent xevent;
+
+ if (message_queue.Count > 0) {
+ xevent = (XEvent) message_queue.Dequeue ();
+ } else {
+ UpdateMessageQueue ();
+ if (message_queue.Count > 0) {
+ xevent = (XEvent) message_queue.Dequeue ();
+ } else {
+ msg.hwnd= IntPtr.Zero;
+ msg.message = Msg.WM_ENTERIDLE;
+ return true;
+ }
+ }
- XNextEvent(DisplayHandle, ref xevent);
msg.hwnd=xevent.AnyEvent.window;
+ //
+ // If you add a new event to this switch make sure to add it in
+ // UpdateMessage also unless it is not coming through the X event system.
+ //
switch(xevent.type) {
case XEventName.KeyPress: {
msg.message = Msg.WM_KEYDOWN;
}
case XEventName.ButtonPress: {
- msg.message=Msg.WM_LBUTTONDOWN;
+ switch(xevent.ButtonEvent.button) {
+ case 1: {
+ mouse_state |= MouseButtons.Left;
+ msg.message=Msg.WM_LBUTTONDOWN;
+ msg.wParam=GetMousewParam(0);
+ break;
+ }
+
+ case 2: {
+ mouse_state |= MouseButtons.Middle;
+ msg.message=Msg.WM_MBUTTONDOWN;
+ msg.wParam=GetMousewParam(0);
+ break;
+ }
+
+ case 3: {
+ mouse_state |= MouseButtons.Right;
+ msg.message=Msg.WM_RBUTTONDOWN;
+ msg.wParam=GetMousewParam(0);
+ break;
+ }
+
+ case 4: {
+ msg.message=Msg.WM_MOUSEWHEEL;
+ msg.wParam=GetMousewParam(120);
+ break;
+ }
+
+ case 5: {
+ msg.message=Msg.WM_MOUSEWHEEL;
+ msg.wParam=GetMousewParam(-120);
+ break;
+ }
+
+ }
+
msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ mouse_position.X=xevent.ButtonEvent.x;
+ mouse_position.Y=xevent.ButtonEvent.y;
break;
}
case XEventName.ButtonRelease: {
- msg.message=Msg.WM_LBUTTONUP;
+ switch(xevent.ButtonEvent.button) {
+ case 1: {
+ mouse_state &= ~MouseButtons.Left;
+ msg.message=Msg.WM_LBUTTONUP;
+ msg.wParam=GetMousewParam(0);
+ break;
+ }
+
+ case 2: {
+ mouse_state &= ~MouseButtons.Middle;
+ msg.message=Msg.WM_MBUTTONUP;
+ msg.wParam=GetMousewParam(0);
+ break;
+ }
+
+ case 3: {
+ mouse_state &= ~MouseButtons.Right;
+ msg.message=Msg.WM_RBUTTONUP;
+ msg.wParam=GetMousewParam(0);
+ break;
+ }
+
+ case 4: {
+ return true;
+ }
+
+ case 5: {
+ return true;
+ }
+ }
+
msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ mouse_position.X=xevent.ButtonEvent.x;
+ mouse_position.Y=xevent.ButtonEvent.y;
break;
}
case XEventName.MotionNotify: {
msg.message=Msg.WM_MOUSEMOVE;
- msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
+ msg.wParam=GetMousewParam(0);
+ msg.lParam=(IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x);
+ mouse_position.X=xevent.MotionEvent.x;
+ mouse_position.Y=xevent.MotionEvent.y;
+ break;
+ }
+
+ case XEventName.EnterNotify: {
+ if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
+ return true;
+ }
+ msg.message=Msg.WM_MOUSE_ENTER;
+ break;
+ }
+
+ case XEventName.LeaveNotify: {
+ if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
+ return true;
+ }
+ msg.message=Msg.WM_MOUSE_LEAVE;
+ break;
+ }
+
+ case XEventName.ConfigureNotify: {
+ msg.message=Msg.WM_WINDOWPOSCHANGED;
+ msg.wParam=IntPtr.Zero;
+ msg.lParam=IntPtr.Zero;
+
break;
}
case XEventName.Expose: {
- // We might be able to do some optimizations by using count and combining regions
msg.message=Msg.WM_PAINT;
- paint_area.X=xevent.ExposeEvent.x;
- paint_area.Y=xevent.ExposeEvent.y;
- paint_area.Width=xevent.ExposeEvent.width;
- paint_area.Height=xevent.ExposeEvent.height;
+ msg.wParam=IntPtr.Zero;
+ msg.lParam=IntPtr.Zero;
break;
}
}
case XEventName.ClientMessage: {
- if (xevent.ClientMessageEvent.l0==wm_delete_window) {
+ if (xevent.ClientMessageEvent.message_type == async_method) {
+ GCHandle handle = (GCHandle)xevent.ClientMessageEvent.ptr1;
+ AsyncMethodData data = (AsyncMethodData) handle.Target;
+ AsyncMethodResult result = data.Result.Target as AsyncMethodResult;
+ object ret = data.Method.DynamicInvoke (data.Args);
+ if (result != null)
+ result.Complete (ret);
+ handle.Free ();
+ } else {
msg.message=Msg.WM_QUIT;
msg.wParam=IntPtr.Zero;
msg.lParam=IntPtr.Zero;
return false;
}
- return true;
break;
}
+
+ case XEventName.TimerNotify: {
+ xevent.TimerNotifyEvent.handler (this, EventArgs.Empty);
+ break;
+ }
+
+ default: {
+ msg.message = Msg.WM_NULL;
+ break;
+ }
}
NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
internal override bool TranslateMessage(ref MSG msg) {
-// Console.WriteLine("XplatUIX11 TranslateMessage");
return true;
}
internal override bool DispatchMessage(ref MSG msg) {
-// Console.WriteLine("XplatUIX11 DispatchMessage");
return true;
}
+ internal override bool SetZOrder(IntPtr hWnd, IntPtr AfterhWnd, bool Top, bool Bottom) {
+ if (Top) {
+ XRaiseWindow(DisplayHandle, hWnd);
+ return true;
+ } else if (!Bottom) {
+ XWindowChanges values = new XWindowChanges();
+
+ values.sibling = AfterhWnd;
+ values.stack_mode = StackMode.Below;
+ XConfigureWindow(DisplayHandle, hWnd, ChangeWindowFlags.CWStackMode, ref values);
+ } else {
+ XLowerWindow(DisplayHandle, hWnd);
+ return true;
+ }
+ return false;
+ }
+
+
internal override bool Text(IntPtr handle, string text) {
#if notdef
XTextProperty property = new XTextProperty();
property.encoding=
XSetWMName(DisplayHandle, handle, ref property);
#else
- XStoreName(DisplayHandle, handle, text);
+ lock (xlib_lock) {
+ XStoreName(DisplayHandle, handle, text);
+ }
#endif
return true;
}
- internal override bool SetVisible(IntPtr handle, bool visible) {
- if (visible) {
- XMapWindow(DisplayHandle, handle);
- is_visible=true;
+ internal override bool GetText(IntPtr handle, out string text) {
+ IntPtr textptr;
+
+ textptr = IntPtr.Zero;
+
+ lock (xlib_lock) {
+ XFetchName(DisplayHandle, handle, ref textptr);
+ }
+ if (textptr != IntPtr.Zero) {
+ text = Marshal.PtrToStringAnsi(textptr);
+ XFree(textptr);
+ return true;
} else {
- XUnmapWindow(DisplayHandle, handle);
- is_visible=false;
+ text = "";
+ return false;
+ }
+ }
+
+ internal override bool SetVisible(IntPtr handle, bool visible) {
+ lock (xlib_lock) {
+ if (visible) {
+ XMapWindow(DisplayHandle, handle);
+ is_visible=true;
+ } else {
+ XUnmapWindow(DisplayHandle, handle);
+ is_visible=false;
+ }
}
-// Console.WriteLine("Setting window visibility: {0}", visible);
return true;
}
internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
XWindowAttributes attributes=new XWindowAttributes();
- XGetWindowAttributes(DisplayHandle, handle, ref attributes);
- XReparentWindow(DisplayHandle, handle, parent, attributes.x, attributes.y);
+ lock (xlib_lock) {
+ XGetWindowAttributes(DisplayHandle, handle, ref attributes);
+ XReparentWindow(DisplayHandle, handle, parent, attributes.x, attributes.y);
+ }
return IntPtr.Zero;
}
Children=IntPtr.Zero;
ChildCount=0;
- XQueryTree(DisplayHandle, handle, ref Root, ref Parent, ref Children, ref ChildCount);
+ lock (xlib_lock) {
+ XQueryTree(DisplayHandle, handle, ref Root, ref Parent, ref Children, ref ChildCount);
+ }
if (Children!=IntPtr.Zero) {
- XFree(Children);
+ lock (xlib_lock) {
+ XFree(Children);
+ }
}
return Parent;
}
-\r
- internal override void GrabWindow(IntPtr hWnd) {
-// Win32SetCapture(hWnd);
+
+ internal override void GrabWindow(IntPtr hWnd, IntPtr confine_hwnd) {
+ if (confine_hwnd != IntPtr.Zero) {
+ XWindowAttributes attributes = new XWindowAttributes();
+
+ lock (xlib_lock) {
+ XGetWindowAttributes(DisplayHandle, confine_hwnd, ref attributes);
+ }
+ grab_area.X = attributes.x;
+ grab_area.Y = attributes.y;
+ grab_area.Width = attributes.width;
+ grab_area.Height = attributes.height;
+ grab_confined = true;
+ }
+ grab_hwnd = hWnd;
+ lock (xlib_lock) {
+ XGrabPointer(DisplayHandle, hWnd, false,
+ EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
+ EventMask.ButtonReleaseMask | EventMask.PointerMotionMask,
+ GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_hwnd, 0, 0);
+ }
+ }
+
+ internal override void GrabInfo(out IntPtr hWnd, out bool GrabConfined, out Rectangle GrabArea) {
+ hWnd = grab_hwnd;
+ GrabConfined = grab_confined;
+ GrabArea = grab_area;
}
internal override void ReleaseWindow(IntPtr hWnd) {
-// Win32ReleaseCapture();
+ lock (xlib_lock) {
+ XUngrabPointer(DisplayHandle, 0);
+ grab_hwnd = IntPtr.Zero;
+ grab_confined = false;
+ }
}
- // Santa's little helper
- static void Where() {
- Console.WriteLine("Here: {0}", new StackTrace().ToString());
+ internal override bool CalculateWindowRect(IntPtr hWnd, ref Rectangle ClientRect, int Style, bool HasMenu, out Rectangle WindowRect) {
+ WindowRect = new Rectangle(ClientRect.Left, ClientRect.Top, ClientRect.Width, ClientRect.Height);
+ return true;
}
- internal override void Run() {
- XEvent xevent = new XEvent();
+ internal override void SetCursorPos(IntPtr handle, int x, int y) {
+ lock (xlib_lock) {
+ XWarpPointer(DisplayHandle, IntPtr.Zero, (handle!=IntPtr.Zero) ? handle : IntPtr.Zero, 0, 0, 0, 0, x, y);
+ }
+ }
- //Console.WriteLine("Size of XEvent: {0}", Marshal.SizeOf(typeof(XEvent)));
- //Where();
- //XNextEvent(DisplayHandle, ref xevent);
- //Where();
-
- while (true==true) {
- XNextEvent(DisplayHandle, ref xevent);
-
- switch(xevent.type) {
- case XEventName.KeyPress: {
- IntPtr buffer = Marshal.AllocHGlobal(24);
- XKeySym keysym;
- string keys;
- int len;
-
- len=XLookupString(ref xevent, buffer, 24, out keysym, IntPtr.Zero);
- if (len>0) {
- keys=Marshal.PtrToStringAuto(buffer);
- Console.WriteLine("Got char {0}", keys);
- } else {
- Console.WriteLine("Got special key {0}", keysym);
- }
- Marshal.FreeHGlobal(buffer);
- break;
- }
+ internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
+ IntPtr root;
+ IntPtr child;
+ int root_x;
+ int root_y;
+ int win_x;
+ int win_y;
+ int keys_buttons;
+
+ lock (xlib_lock) {
+ XQueryPointer(DisplayHandle, (handle!=IntPtr.Zero) ? handle : root_window,
+ out root, out child, out root_x, out root_y,
+ out win_x, out win_y, out keys_buttons);
+ }
+
+ if (handle != IntPtr.Zero) {
+ x = win_x;
+ y = win_y;
+ } else {
+ x = root_x;
+ y = root_y;
+ }
+ }
- case XEventName.Expose: {
- Rectangle r = new Rectangle(xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
- Graphics g = Graphics.FromHwnd (xevent.ExposeEvent.window );
- Font f = new Font("Bitstream Vera Sans Mono", 20);
- SolidBrush b = new SolidBrush(Color.Red);
- Rectangle r2 = new Rectangle(0, 0, 300, 300);
+ internal override void ScreenToClient(IntPtr handle, ref int x, ref int y)
+ {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
- g.FillRectangle(SystemBrushes.Window, r2);
- g.DrawString("TestString", f, b, 0, 0);
+ lock (xlib_lock) {
+ XTranslateCoordinates (DisplayHandle, root_window,
+ handle, x, y, out dest_x_return, out dest_y_return, out child);
+ }
-// Console.WriteLine("XplatUI.Run(): Exposed {0}", r);
- break;
- }
+ x = dest_x_return;
+ y = dest_y_return;
+ }
- case XEventName.ButtonPress: {
- Console.WriteLine("XplatUI.Run(): leaving loop");
- return;
- }
+ internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) {
+ int dest_x_return;
+ int dest_y_return;
+ IntPtr child;
- default: {
- Console.WriteLine("Received event {0}", xevent.type);
- break;
- }
- }
+ lock (xlib_lock) {
+ XTranslateCoordinates (DisplayHandle, handle, root_window,
+ x, y, out dest_x_return, out dest_y_return, out child);
}
+
+ x = dest_x_return;
+ y = dest_y_return;
+ }
+
+ internal override void SendAsyncMethod (AsyncMethodData method)
+ {
+ XEvent xevent = new XEvent ();
+
+ xevent.type = XEventName.ClientMessage;
+ xevent.ClientMessageEvent.display = DisplayHandle;
+ xevent.ClientMessageEvent.window = IntPtr.Zero;
+ xevent.ClientMessageEvent.message_type = async_method;
+ xevent.ClientMessageEvent.format = 32;
+ xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
+
+ lock (message_queue) {
+ message_queue.Enqueue (xevent);
+ }
+
+ WakeupMain ();
+ }
+
+ private void WakeupMain ()
+ {
+ wake.BeginSend (new byte [] { 0xFF }, 0, 1, SocketFlags.None, null, null);
+ }
+
+ internal override void SetTimer (Timer timer)
+ {
+ lock (timer_list) {
+ timer_list.Add (timer);
+ }
+ WakeupMain ();
+ }
+
+ internal override void KillTimer (Timer timer)
+ {
+ lock (timer_list) {
+ timer_list.Remove (timer);
+ }
+ }
+
+ // Santa's little helper
+ static void Where()
+ {
+ Console.WriteLine("Here: {0}", new StackTrace().ToString());
}
#endregion // Public Static Methods
internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
[DllImport ("libX11.so", EntryPoint="XNextEvent")]
internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
+ [DllImport ("libX11.so")]
+ internal extern static int XConnectionNumber (IntPtr diplay);
+ [DllImport ("libX11.so")]
+ internal extern static int XPending (IntPtr diplay);
+ [DllImport ("libX11.so")]
+ internal extern static bool XCheckWindowEvent (IntPtr display, IntPtr window, EventMask mask, ref XEvent xevent);
+ [DllImport ("libX11.so")]
+ internal extern static bool XCheckMaskEvent (IntPtr display, EventMask mask, ref XEvent xevent);
[DllImport ("libX11.so", EntryPoint="XSelectInput")]
internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, EventMask mask);
[DllImport ("libX11.so", EntryPoint="XLookupString")]
[DllImport ("libX11.so", EntryPoint="XMoveResizeWindow")]
internal extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+ [DllImport ("libX11.so", EntryPoint="XResizeWindow")]
+ internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
+
[DllImport ("libX11.so", EntryPoint="XGetWindowAttributes")]
internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
[DllImport ("libX11.so", EntryPoint="XStoreName")]
internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
+ [DllImport ("libX11.so", EntryPoint="XFetchName")]
+ internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
+
[DllImport ("libX11.so", EntryPoint="XSendEvent")]
internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, EventMask event_mask, ref XEvent send_event);
[DllImport ("libX11.so", EntryPoint="XRaiseWindow")]
internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
+ [DllImport ("libX11.so", EntryPoint="XLowerWindow")]
+ internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11.so", EntryPoint="XConfigureWindow")]
+ internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
+
[DllImport ("libX11.so", EntryPoint="XInternAtom")]
internal extern static int XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
[DllImport ("libX11.so", EntryPoint="XSetWMProtocols")]
internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, ref int protocols, int count);
-// [DllImport ("libX11.so", EntryPoint="XSetWMProtocols")]
-// internal extern static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, uint event_mask, int pointer_mode, int keyboard_mode, IntPtr confine_to, XplatUICursor cursor, uint timestamp);
+ [DllImport ("libX11.so", EntryPoint="XGrabPointer")]
+ internal extern static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, uint cursor, uint timestamp);
+
+ [DllImport ("libX11.so", EntryPoint="XUngrabPointer")]
+ internal extern static int XUngrabPointer(IntPtr display, uint timestamp);
+
+ [DllImport ("libX11.so", EntryPoint="XQueryPointer")]
+ internal extern static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons);
+
+ [DllImport ("libX11.so", EntryPoint="XTranslateCoordinates")]
+ internal extern static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return);
+
+ [DllImport ("libX11.so", EntryPoint="XGetGeometry")]
+ internal extern static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth);
+
+ [DllImport ("libX11.so", EntryPoint="XWarpPointer")]
+ internal extern static uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y);
+
+ [DllImport ("libX11.so", EntryPoint="XClearWindow")]
+ internal extern static int XClearWindow(IntPtr display, IntPtr window);
+
+ [DllImport ("libX11.so", EntryPoint="XClearArea")]
+ internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, uint width, uint height, bool exposures);
+
+ // Colormaps
+ [DllImport ("libX11.so", EntryPoint="XDefaultScreenOfDisplay")]
+ internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
+
+ [DllImport ("libX11.so", EntryPoint="XScreenNumberOfScreen")]
+ internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
+
+ [DllImport ("libX11.so", EntryPoint="XDefaultVisual")]
+ internal extern static uint XDefaultVisual(IntPtr display, int screen_number);
+
+ [DllImport ("libX11.so", EntryPoint="XDefaultDepth")]
+ internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
+
+ [DllImport ("libX11.so", EntryPoint="XDefaultColormap")]
+ internal extern static uint XDefaultColormap(IntPtr display, int screen_number);
+
+ [DllImport ("libX11.so", EntryPoint="XLookupColor")]
+ internal extern static int XLookupColor(IntPtr display, uint Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
+
+ [DllImport ("libX11.so", EntryPoint="XAllocColor")]
+ internal extern static int XAllocColor(IntPtr display, uint Colormap, ref XColor colorcell_def);
+
// Drawing
[DllImport ("libX11.so", EntryPoint="XCreateGC")]