diff options
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs')
-rw-r--r-- | mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs | 4444 |
1 files changed, 4444 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs new file mode 100644 index 00000000000..149841ccbf7 --- /dev/null +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs @@ -0,0 +1,4444 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// NOTE: +// This driver understands the following environment variables: (Set the var to enable feature) +// +// MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered; +// by default a message is displayed but execution continues +// +// MONO_XSYNC = perform all X11 commands synchronous; this is slower but +// helps in debugging errors +// + +// NOT COMPLETE + +// define to log Window handles and relationships to stdout +#undef DriverDebug + +// Extra detailed debug +#undef DriverDebugExtra + +using System; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +// Only do the poll when building with mono for now +#if __MonoCS__ +using Mono.Unix.Native; +#endif + +/// X11 Version +namespace System.Windows.Forms { + internal class XplatUIX11 : XplatUIDriver { + #region Local Variables + // General + static volatile XplatUIX11 Instance; + private static int RefCount; + private static object XlibLock; // Our locking object + private static bool ThemesEnabled; + + // General X11 + private static IntPtr DisplayHandle; // X11 handle to display + private static int ScreenNo; // Screen number used + private static IntPtr DefaultColormap; // Colormap for screen + private static IntPtr CustomVisual; // Visual for window creation + private static IntPtr CustomColormap; // Colormap for window creation + private static IntPtr RootWindow; // Handle of the root window for the screen/display + private static IntPtr FosterParent; // Container to hold child windows until their parent exists + private static XErrorHandler ErrorHandler; // Error handler delegate + private static bool ErrorExceptions; // Throw exceptions on X errors + private static bool PostQuitState; // True if we've got an pending exit + + // Clipboard + private static IntPtr ClipMagic = new IntPtr(27051977); + private static ClipboardStruct Clipboard; // Our clipboard + + // Communication + private static IntPtr PostAtom; // PostMessage atom + private static IntPtr AsyncAtom; // Support for async messages + + // Message Loop + private static XEventQueue MessageQueue; // Holds our queued up events + #if __MonoCS__ // + private static Pollfd[] pollfds; // For watching the X11 socket + #endif // + private static X11Keyboard Keyboard; // + private static X11Dnd Dnd; + private static Socket listen; // + private static Socket wake; // + private static Socket wake_receive; // + private static byte[] network_buffer; // + + + // Focus tracking + private static IntPtr ActiveWindow; // Handle of the active window + private static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any) + + // Modality support + private static Stack ModalWindows; // Stack of our modal windows + + // Systray + private static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window + + // Cursors + private static IntPtr LastCursorWindow; // The last window we set the cursor on + private static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow + private static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors + + // Caret + private static CaretStruct Caret; // + + // Support for Window Styles + private static IntPtr[] NetAtoms; // All atoms we know + + // mouse hover message generation + private static HoverStruct HoverState; // + + // double click message generation + private static ClickStruct ClickPending; // + + // Support for mouse grab + private static GrabStruct Grab; // + + // State + private static Point MousePosition; // Last position of mouse, in screen coords + internal static MouseButtons MouseState; // Last state of mouse buttons + + // Timers + private static ArrayList TimerList; // Holds SWF.Timers + + // 'Constants' + private static int DoubleClickInterval; // msec; max interval between clicks to count as double click + + const EventMask SelectInputMask = EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask | + EventMask.KeyPressMask | + EventMask.KeyReleaseMask | + EventMask.EnterWindowMask | + EventMask.LeaveWindowMask | + EventMask.ExposureMask | + EventMask.FocusChangeMask | + EventMask.PointerMotionMask | + EventMask.VisibilityChangeMask | + EventMask.SubstructureNotifyMask | + EventMask.StructureNotifyMask; + + static readonly object lockobj = new object (); + + #endregion // Local Variables + #region Constructors + private XplatUIX11() { + // Handle singleton stuff first + RefCount = 0; + + // Now regular initialization + XlibLock = new object (); + MessageQueue = new XEventQueue (); + TimerList = new ArrayList (); + XInitThreads(); + + ErrorExceptions = false; + + // X11 Initialization + SetDisplay(XOpenDisplay(IntPtr.Zero)); + X11DesktopColors.Initialize(); + + // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does) + ErrorHandler = new XErrorHandler(HandleError); + XSetErrorHandler(ErrorHandler); + } + #endregion // Constructors + + #region Singleton Specific Code + public static XplatUIX11 GetInstance() { + lock (lockobj) { + if (Instance == null) { + Instance=new XplatUIX11(); + } + RefCount++; + } + return Instance; + } + + public int Reference { + get { + return RefCount; + } + } + #endregion + + #region Internal Properties + internal static IntPtr Display { + get { + return DisplayHandle; + } + + set { + XplatUIX11.GetInstance().SetDisplay(value); + } + } + + internal static int Screen { + get { + return ScreenNo; + } + + set { + ScreenNo = value; + } + } + + internal static IntPtr RootWindowHandle { + get { + return RootWindow; + } + + set { + RootWindow = value; + } + } + + internal static IntPtr Visual { + get { + return CustomVisual; + } + + set { + CustomVisual = value; + } + } + + internal static IntPtr ColorMap { + get { + return CustomColormap; + } + + set { + CustomColormap = value; + } + } + #endregion + + #region XExceptionClass + internal class XException : ApplicationException { + IntPtr Display; + IntPtr ResourceID; + IntPtr Serial; + XRequest RequestCode; + byte ErrorCode; + byte MinorCode; + + public XException(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) { + this.Display = Display; + this.ResourceID = ResourceID; + this.Serial = Serial; + this.RequestCode = RequestCode; + this.ErrorCode = ErrorCode; + this.MinorCode = MinorCode; + } + + public override string Message { + get { + return GetMessage(Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode); + } + } + + public static string GetMessage(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) { + StringBuilder sb; + string x_error_text; + string error; + + sb = new StringBuilder(160); + XGetErrorText(Display, ErrorCode, sb, sb.Capacity); + x_error_text = sb.ToString(); + + error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:x}\n Serial: {4}", x_error_text, RequestCode, RequestCode, ResourceID.ToInt32(), Serial); + return error; + } + } + #endregion // XExceptionClass + + #region Internal Methods + internal void SetDisplay(IntPtr display_handle) { + if (display_handle != IntPtr.Zero) { + Hwnd hwnd; + + if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) { + hwnd = Hwnd.ObjectFromHandle(FosterParent); + XDestroyWindow(DisplayHandle, FosterParent); + hwnd.Dispose(); + } + + if (DisplayHandle != IntPtr.Zero) { + XCloseDisplay(DisplayHandle); + } + + DisplayHandle=display_handle; + + // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has + // been hacked to do this for us. + Graphics.FromHdcInternal (DisplayHandle); + + // Debugging support + if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { + XSynchronize(DisplayHandle, true); + } + + if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { + ErrorExceptions = true; + } + + // Generic X11 setup + ScreenNo = XDefaultScreen(DisplayHandle); + RootWindow = XRootWindow(DisplayHandle, ScreenNo); + DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo); + + // Create the foster parent + FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero); + if (FosterParent==IntPtr.Zero) { + Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent"); + } + + hwnd = new Hwnd(); + hwnd.WholeWindow = FosterParent; + hwnd.ClientWindow = FosterParent; + + // For sleeping on the X11 socket + listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0); + listen.Bind(ep); + listen.Listen(1); + + // To wake up when a timer is ready + network_buffer = new byte[10]; + + wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + wake.Connect(listen.LocalEndPoint); + wake_receive = listen.Accept(); + + #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_receive.Handle.ToInt32 (); + pollfds [1].events = PollEvents.POLLIN; + #endif + + Keyboard = new X11Keyboard(DisplayHandle); + Dnd = new X11Dnd (DisplayHandle); + + PostQuitState = false; + + DoubleClickInterval = 500; + + HoverState.Interval = 500; + HoverState.Timer = new Timer(); + HoverState.Timer.Enabled = false; + HoverState.Timer.Interval = HoverState.Interval; + HoverState.Timer.Tick +=new EventHandler(MouseHover); + HoverState.X = -1; + HoverState.Y = -1; + + ActiveWindow = IntPtr.Zero; + FocusWindow = IntPtr.Zero; + ModalWindows = new Stack(3); + + MouseState = MouseButtons.None; + MousePosition = new Point(0, 0); + + Caret.Timer = new Timer(); + Caret.Timer.Interval = 500; // FIXME - where should this number come from? + Caret.Timer.Tick += new EventHandler(CaretCallback); + + SetupAtoms(); + + // Grab atom changes off the root window to catch certain WM events + XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int)EventMask.PropertyChangeMask)); + + // Handle any upcoming errors + ErrorHandler = new XErrorHandler(HandleError); + XSetErrorHandler(ErrorHandler); + } else { + throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check you DISPLAY environment variable)"); + } + } + + internal static void Where() { + Console.WriteLine("Here: {0}\n", WhereString()); + } + + internal static string WhereString() { + StackTrace stack; + StackFrame frame; + string newline; + string unknown; + StringBuilder sb; + MethodBase method; + + newline = String.Format("{0}\t {1} ", Environment.NewLine, Locale.GetText("at")); + unknown = Locale.GetText("<unknown method>"); + sb = new StringBuilder(); + stack = new StackTrace(true); + + for (int i = 0; i < stack.FrameCount; i++) { + frame = stack.GetFrame(i); + sb.Append(newline); + + method = frame.GetMethod(); + if (method != null) { + #if not + sb.AppendFormat(frame.ToString()); + #endif + if (frame.GetFileLineNumber() != 0) { + sb.AppendFormat("{0}.{1} () [{2}:{3}]", method.DeclaringType.FullName, method.Name, Path.GetFileName(frame.GetFileName()), frame.GetFileLineNumber()); + } else { + sb.AppendFormat("{0}.{1} ()", method.DeclaringType.FullName, method.Name); + } + } else { + sb.Append(unknown); + } + } + return sb.ToString(); + } + #endregion // Internal Methods + + #region Private Methods + private static void SetupAtoms() { + NetAtoms = new IntPtr[(int)NA.LAST_NET_ATOM]; + + NetAtoms[(int)NA.WM_PROTOCOLS] = XInternAtom(DisplayHandle, "WM_PROTOCOLS", false); + NetAtoms[(int)NA.WM_DELETE_WINDOW] = XInternAtom(DisplayHandle, "WM_DELETE_WINDOW", false); + NetAtoms[(int)NA.WM_TAKE_FOCUS] = XInternAtom(DisplayHandle, "WM_TAKE_FOCUS", false); + + NetAtoms[(int)NA._NET_SUPPORTED] = XInternAtom(DisplayHandle, "_NET_SUPPORTED", false); + NetAtoms[(int)NA._NET_CLIENT_LIST] = XInternAtom(DisplayHandle, "_NET_CLIENT_LIST", false); + NetAtoms[(int)NA._NET_NUMBER_OF_DESKTOPS] = XInternAtom(DisplayHandle, "_NET_NUMBER_OF_DESKTOPS", false); + NetAtoms[(int)NA._NET_DESKTOP_GEOMETRY] = XInternAtom(DisplayHandle, "_NET_DESKTOP_GEOMETRY", false); + NetAtoms[(int)NA._NET_DESKTOP_VIEWPORT] = XInternAtom(DisplayHandle, "_NET_DESKTOP_VIEWPORT", false); + NetAtoms[(int)NA._NET_CURRENT_DESKTOP] = XInternAtom(DisplayHandle, "_NET_CURRENT_DESKTOP", false); + NetAtoms[(int)NA._NET_DESKTOP_NAMES] = XInternAtom(DisplayHandle, "_NET_DESKTOP_NAMES", false); + NetAtoms[(int)NA._NET_ACTIVE_WINDOW] = XInternAtom(DisplayHandle, "_NET_ACTIVE_WINDOW", false); + NetAtoms[(int)NA._NET_WORKAREA] = XInternAtom(DisplayHandle, "_NET_WORKAREA", false); + NetAtoms[(int)NA._NET_SUPPORTING_WM_CHECK] = XInternAtom(DisplayHandle, "_NET_SUPPORTING_WM_CHECK", false); + NetAtoms[(int)NA._NET_VIRTUAL_ROOTS] = XInternAtom(DisplayHandle, "_NET_VIRTUAL_ROOTS", false); + NetAtoms[(int)NA._NET_DESKTOP_LAYOUT] = XInternAtom(DisplayHandle, "_NET_DESKTOP_LAYOUT", false); + NetAtoms[(int)NA._NET_SHOWING_DESKTOP] = XInternAtom(DisplayHandle, "_NET_SHOWING_DESKTOP", false); + + NetAtoms[(int)NA._NET_CLOSE_WINDOW] = XInternAtom(DisplayHandle, "_NET_CLOSE_WINDOW", false); + NetAtoms[(int)NA._NET_MOVERESIZE_WINDOW] = XInternAtom(DisplayHandle, "_NET_MOVERESIZE_WINDOW", false); + NetAtoms[(int)NA._NET_WM_MOVERESIZE] = XInternAtom(DisplayHandle, "_NET_WM_MOVERESIZE", false); + NetAtoms[(int)NA._NET_RESTACK_WINDOW] = XInternAtom(DisplayHandle, "_NET_RESTACK_WINDOW", false); + NetAtoms[(int)NA._NET_REQUEST_FRAME_EXTENTS] = XInternAtom(DisplayHandle, "_NET_REQUEST_FRAME_EXTENTS", false); + + NetAtoms[(int)NA._NET_WM_NAME] = XInternAtom(DisplayHandle, "_NET_WM_NAME", false); + NetAtoms[(int)NA._NET_WM_VISIBLE_NAME] = XInternAtom(DisplayHandle, "_NET_WM_VISIBLE_NAME", false); + NetAtoms[(int)NA._NET_WM_ICON_NAME] = XInternAtom(DisplayHandle, "_NET_WM_ICON_NAME", false); + NetAtoms[(int)NA._NET_WM_VISIBLE_ICON_NAME] = XInternAtom(DisplayHandle, "_NET_WM_VISIBLE_ICON_NAME", false); + NetAtoms[(int)NA._NET_WM_DESKTOP] = XInternAtom(DisplayHandle, "_NET_WM_DESKTOP", false); + NetAtoms[(int)NA._NET_WM_WINDOW_TYPE] = XInternAtom(DisplayHandle, "_NET_WM_WINDOW_TYPE", false); + NetAtoms[(int)NA._NET_WM_STATE] = XInternAtom(DisplayHandle, "_NET_WM_STATE", false); + NetAtoms[(int)NA._NET_WM_ALLOWED_ACTIONS] = XInternAtom(DisplayHandle, "_NET_WM_ALLOWED_ACTIONS", false); + NetAtoms[(int)NA._NET_WM_STRUT] = XInternAtom(DisplayHandle, "_NET_WM_STRUT", false); + NetAtoms[(int)NA._NET_WM_STRUT_PARTIAL] = XInternAtom(DisplayHandle, "_NET_WM_STRUT_PARTIAL", false); + NetAtoms[(int)NA._NET_WM_ICON_GEOMETRY] = XInternAtom(DisplayHandle, "_NET_WM_ICON_GEOMETRY", false); + NetAtoms[(int)NA._NET_WM_ICON] = XInternAtom(DisplayHandle, "_NET_WM_ICON", false); + NetAtoms[(int)NA._NET_WM_PID] = XInternAtom(DisplayHandle, "_NET_WM_PID", false); + NetAtoms[(int)NA._NET_WM_HANDLED_ICONS] = XInternAtom(DisplayHandle, "_NET_WM_HANDLED_ICONS", false); + NetAtoms[(int)NA._NET_WM_USER_TIME] = XInternAtom(DisplayHandle, "_NET_WM_USER_TIME", false); + NetAtoms[(int)NA._NET_FRAME_EXTENTS] = XInternAtom(DisplayHandle, "_NET_FRAME_EXTENTS", false); + + NetAtoms[(int)NA._NET_WM_PING] = XInternAtom(DisplayHandle, "_NET_WM_PING", false); + NetAtoms[(int)NA._NET_WM_SYNC_REQUEST] = XInternAtom(DisplayHandle, "_NET_WM_SYNC_REQUEST", false); + + NetAtoms[(int)NA._NET_SYSTEM_TRAY_S] = XInternAtom(DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString(), false); + NetAtoms[(int)NA._NET_SYSTEM_TRAY_OPCODE] = XInternAtom(DisplayHandle, "_NET_SYSTEM_TRAY_OPCODE", false); + NetAtoms[(int)NA._NET_SYSTEM_TRAY_ORIENTATION] = XInternAtom(DisplayHandle, "_NET_SYSTEM_TRAY_ORIENTATION", false); + + NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ] = XInternAtom(DisplayHandle, "_NET_WM_STATE_MAXIMIZED_HORZ", false); + NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT] = XInternAtom(DisplayHandle, "_NET_WM_STATE_MAXIMIZED_VERT", false); + NetAtoms[(int)NA._NET_WM_STATE_HIDDEN] = XInternAtom(DisplayHandle, "_NET_WM_STATE_HIDDEN", false); + + NetAtoms[(int)NA._XEMBED] = XInternAtom(DisplayHandle, "_XEMBED", false); + NetAtoms[(int)NA._XEMBED_INFO] = XInternAtom(DisplayHandle, "_XEMBED_INFO", false); + + NetAtoms[(int)NA._MOTIF_WM_HINTS] = XInternAtom(DisplayHandle, "_MOTIF_WM_HINTS", false); + + NetAtoms[(int)NA._NET_WM_STATE_NO_TASKBAR] = XInternAtom(DisplayHandle, "_NET_WM_STATE_NO_TASKBAR", false); + NetAtoms[(int)NA._NET_WM_STATE_ABOVE] = XInternAtom(DisplayHandle, "_NET_WM_STATE_ABOVE", false); + NetAtoms[(int)NA._NET_WM_STATE_MODAL] = XInternAtom(DisplayHandle, "_NET_WM_STATE_MODAL", false); + NetAtoms[(int)NA._NET_WM_CONTEXT_HELP] = XInternAtom(DisplayHandle, "_NET_WM_CONTEXT_HELP", false); + NetAtoms[(int)NA._NET_WM_WINDOW_OPACITY] = XInternAtom(DisplayHandle, "_NET_WM_WINDOW_OPACITY", false); + + // Clipboard support + NetAtoms[(int)NA.CLIPBOARD] = XInternAtom (DisplayHandle, "CLIPBOARD", false); + NetAtoms[(int)NA.DIB] = (IntPtr)Atom.XA_PIXMAP; + NetAtoms[(int)NA.OEMTEXT] = XInternAtom(DisplayHandle, "COMPOUND_TEXT", false); + NetAtoms[(int)NA.UNICODETEXT] = XInternAtom(DisplayHandle, "UTF8_STRING", false); + NetAtoms[(int)NA.TARGETS] = XInternAtom(DisplayHandle, "TARGETS", false); + + // Special Atoms + AsyncAtom = XInternAtom(DisplayHandle, "_SWF_AsyncAtom", false); + PostAtom = XInternAtom (DisplayHandle, "_SWF_PostMessageAtom", false); + HoverState.Atom = XInternAtom(DisplayHandle, "_SWF_HoverAtom", false); + } + + private void GetSystrayManagerWindow() { + XGrabServer(DisplayHandle); + SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, NetAtoms[(int)NA._NET_SYSTEM_TRAY_S]); + XUngrabServer(DisplayHandle); + XFlush(DisplayHandle); + } + + private void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) { + XEvent xev; + + xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + XSendEvent(DisplayHandle, RootWindow, false, new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev); + } + + private void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) { + XEvent xev; + + xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + XSendEvent(DisplayHandle, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev); + } + + private void DeriveStyles(IntPtr handle, int Style, int ExStyle, out FormBorderStyle border_style, out TitleStyle title_style, out int caption_height, out int tool_caption_height) { + + // Only MDI windows get caption_heights + caption_height = 0; + tool_caption_height = 19; + + if ((Style & (int) WindowStyles.WS_CHILD) != 0) { + if ((Style & (int) WindowStyles.WS_BORDER) == 0) { + border_style = FormBorderStyle.None; + } else if ((ExStyle & (int) WindowStyles.WS_EX_CLIENTEDGE) != 0) { + border_style = FormBorderStyle.Fixed3D; + } else { + border_style = FormBorderStyle.FixedSingle; + } + title_style = TitleStyle.None; + + if ((ExStyle & (int) WindowStyles.WS_EX_MDICHILD) != 0) { + caption_height = 26; + + if ((Style & (int)WindowStyles.WS_CAPTION) != 0) { + if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + if ((Style & (int) WindowStyles.WS_OVERLAPPEDWINDOW) != 0 || + (ExStyle & (int) WindowStyles.WS_EX_TOOLWINDOW) != 0) { + border_style = (FormBorderStyle) 0xFFFF; + } else { + border_style = FormBorderStyle.None; + } + } + + } else { + title_style = TitleStyle.None; + if ((Style & (int)WindowStyles.WS_CAPTION) != 0) { + if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + border_style = FormBorderStyle.None; + + if ((Style & (int)WindowStyles.WS_THICKFRAME) != 0) { + if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + border_style = FormBorderStyle.SizableToolWindow; + } else { + border_style = FormBorderStyle.Sizable; + } + } else { + if ((ExStyle & (int)WindowStyles.WS_EX_CLIENTEDGE) != 0) { + border_style = FormBorderStyle.Fixed3D; + } else if ((ExStyle & (int)WindowStyles.WS_EX_DLGMODALFRAME) != 0) { + border_style = FormBorderStyle.FixedDialog; + } else if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + border_style = FormBorderStyle.FixedToolWindow; + } else if ((Style & (int)WindowStyles.WS_BORDER) != 0) { + border_style = FormBorderStyle.Sizable; + } else { + border_style = FormBorderStyle.None; + } + } + } + } + + private void SetHwndStyles(Hwnd hwnd, CreateParams cp) { + DeriveStyles(hwnd.Handle, cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height); + } + + private void SetWMStyles(Hwnd hwnd, CreateParams cp) { + MotifWmHints mwmHints; + MotifFunctions functions; + MotifDecorations decorations; + int atom_count; + Rectangle client_rect; + + mwmHints = new MotifWmHints(); + functions = 0; + decorations = 0; + + mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations); + mwmHints.functions = (IntPtr)0; + mwmHints.decorations = (IntPtr)0; + + if ((cp.Style & (int)WindowStyles.WS_CAPTION) != 0) { + functions |= MotifFunctions.Move; + decorations |= MotifDecorations.Title | MotifDecorations.Menu; + } + + if ((cp.Style & ((int)WindowStyles.WS_THICKFRAME)) != 0) { + functions |= MotifFunctions.Move | MotifFunctions.Resize; + decorations |= MotifDecorations.Border | MotifDecorations.ResizeH; + } + if ((cp.Style & ((int)WindowStyles.WS_MINIMIZEBOX)) != 0) { + functions |= MotifFunctions.Minimize; + decorations |= MotifDecorations.Minimize; + } + + if ((cp.Style & ((int)WindowStyles.WS_MAXIMIZEBOX)) != 0) { + functions |= MotifFunctions.Maximize; + decorations |= MotifDecorations.Maximize; + } + + if ((cp.Style & ((int)WindowStyles.WS_SYSMENU)) != 0) { + functions |= MotifFunctions.Close; + } + + if ((cp.ExStyle & ((int)WindowStyles.WS_EX_DLGMODALFRAME)) != 0) { + decorations |= MotifDecorations.Border; + } + + if ((cp.Style & ((int)WindowStyles.WS_DLGFRAME)) != 0) { + decorations |= MotifDecorations.Border; + } + + if ((cp.Style & ((int)WindowStyles.WS_BORDER)) != 0) { + decorations |= MotifDecorations.Border; + } + + if ((cp.ExStyle & ((int)WindowStyles.WS_EX_TOOLWINDOW)) != 0) { + functions = 0; + decorations = 0; + } + + if ((functions & MotifFunctions.Resize) == 0) { + XplatUI.SetWindowMinMax(hwnd.Handle, new Rectangle(cp.X, cp.Y, cp.Width, cp.Height), new Size(cp.Width, cp.Height), new Size(cp.Width, cp.Height)); + } + + mwmHints.functions = (IntPtr)functions; + mwmHints.decorations = (IntPtr)decorations; + + client_rect = hwnd.ClientRect; + lock (XlibLock) { + XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._MOTIF_WM_HINTS], NetAtoms[(int)NA._MOTIF_WM_HINTS], 32, PropertyMode.Replace, ref mwmHints, 5); + + if (((cp.Style & (int)WindowStyles.WS_POPUP) != 0) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) { + XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd.parent.whole_window); + } + XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height); + + int[] atoms = new int[8]; + atom_count = 0; + + if ((cp.ExStyle & ((int)WindowStyles.WS_EX_TOOLWINDOW)) != 0) { + atoms[atom_count++] = NetAtoms[(int)NA._NET_WM_STATE_NO_TASKBAR].ToInt32(); + } + XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count); + + atom_count = 0; + IntPtr[] atom_ptrs = new IntPtr[2]; + + atom_ptrs[atom_count++] = NetAtoms[(int)NA.WM_DELETE_WINDOW]; + if ((cp.ExStyle & (int)WindowStyles.WS_EX_CONTEXTHELP) != 0) { + atom_ptrs[atom_count++] = NetAtoms[(int)NA._NET_WM_CONTEXT_HELP]; + } + + XSetWMProtocols(DisplayHandle, hwnd.whole_window, atom_ptrs, atom_count); + } + } + + private void SetIcon(Hwnd hwnd, Icon icon) { + Bitmap bitmap; + int size; + uint[] data; + int index; + + bitmap = icon.ToBitmap(); + index = 0; + size = bitmap.Width * bitmap.Height + 2; + data = new uint[size]; + + data[index++] = (uint)bitmap.Width; + data[index++] = (uint)bitmap.Height; + + for (int y = 0; y < bitmap.Height; y++) { + for (int x = 0; x < bitmap.Width; x++) { + data[index++] = (uint)bitmap.GetPixel(x, y).ToArgb(); + } + } + XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._NET_WM_ICON], (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, data, size); + } + + private IntPtr ImageToPixmap(Image image) { + return IntPtr.Zero; + } + + private void WakeupMain () { + wake.Send (new byte [] { 0xFF }); + } + + private void TranslatePropertyToClipboard(IntPtr property) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + Clipboard.Item = null; + + XGetWindowProperty(DisplayHandle, FosterParent, property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems > 0) { + if (property == (IntPtr)Atom.XA_STRING) { + Clipboard.Item = Marshal.PtrToStringAnsi(prop); + } else if (property == (IntPtr)Atom.XA_BITMAP) { + // FIXME - convert bitmap to image + } else if (property == (IntPtr)Atom.XA_PIXMAP) { + // FIXME - convert pixmap to image + } else if (property == NetAtoms[(int)NA.OEMTEXT]) { + Clipboard.Item = Marshal.PtrToStringAnsi(prop); + } else if (property == NetAtoms[(int)NA.UNICODETEXT]) { + Clipboard.Item = Marshal.PtrToStringAnsi(prop); + } + + XFree(prop); + } + } + + private void AddExpose (XEvent xevent) { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window); + + // Don't waste time + if (hwnd == null) { + return; + } + + if (xevent.AnyEvent.window == hwnd.client_window) { + hwnd.AddInvalidArea(xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + if (!hwnd.expose_pending) { + MessageQueue.Enqueue(xevent); + hwnd.expose_pending = true; + } + } else { + hwnd.AddNcInvalidArea (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + + if (!hwnd.nc_expose_pending) { + MessageQueue.Enqueue(xevent); + hwnd.nc_expose_pending = true; + } + } + } + + private void InvalidateWholeWindow(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + InvalidateWholeWindow(handle, new Rectangle(0, 0, hwnd.Width, hwnd.Height)); + } + + private void InvalidateWholeWindow(IntPtr handle, Rectangle rectangle) { + Hwnd hwnd; + XEvent xevent; + + hwnd = Hwnd.ObjectFromHandle(handle); + + + xevent = new XEvent (); + xevent.type = XEventName.Expose; + xevent.ExposeEvent.display = DisplayHandle; + xevent.ExposeEvent.window = hwnd.whole_window; + + xevent.ExposeEvent.x = rectangle.X; + xevent.ExposeEvent.y = rectangle.Y; + xevent.ExposeEvent.width = rectangle.Width; + xevent.ExposeEvent.height = rectangle.Height; + + AddExpose (xevent); + } + + private void WholeToScreen(IntPtr handle, ref int x, ref int y) { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + private void AbsoluteGeometry(IntPtr window, out int ret_x, out int ret_y, out int width, out int height) { + IntPtr root; + IntPtr win; + IntPtr parent; + IntPtr children; + int x; + int y; + int w; + int h; + int absX; + int absY; + int b; + int d; + int nchildren; + + absX = 0; + absY = 0; + win = window; + width = 0; + height = 0; + do { + XGetGeometry(DisplayHandle, win, out root, out x, out y, out w, out h, out b, out d); + if (win == window) { + width = w; + height = h; + } + absX += x; + absY += y; + if (XQueryTree(DisplayHandle, win, out root, out parent, out children, out nchildren) == 0) { + break; + } + + if (children != IntPtr.Zero) { + XFree(children); + } + win = parent; + } while (win != root); + + ret_x = absX; + ret_y = absY; + +//Console.WriteLine("Absolute pos for window {0} = {1},{2} {3}x{4}", XplatUI.Window(window), ret_x, ret_y, width, height); + } + + private void FrameExtents(IntPtr window, out int left, out int top) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + XGetWindowProperty(DisplayHandle, window, NetAtoms[(int)NA._NET_FRAME_EXTENTS], IntPtr.Zero, new IntPtr (16), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems == 4) && (prop != IntPtr.Zero)) { + left = Marshal.ReadInt32(prop, 0); + //right = Marshal.ReadInt32(prop, 4); + top = Marshal.ReadInt32(prop, 8); + //bottom = Marshal.ReadInt32(prop, 12); + } else { + left = 0; + top = 0; + } + + if (prop != IntPtr.Zero) { + XFree(prop); + } + return; + } + + private void AddConfigureNotify (XEvent xevent) { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window); + + // Don't waste time + if (hwnd == null) { + return; + } + + if (xevent.ConfigureEvent.window == hwnd.whole_window) { + if (!hwnd.reparented) { + hwnd.x = xevent.ConfigureEvent.x; + hwnd.y = xevent.ConfigureEvent.y; + } else { + // This sucks ass, part 1 + // Every WM does the ConfigureEvents of toplevel windows different, so there's + // no standard way of getting our adjustment. + // The code below is needed for KDE and FVWM, the 'whacky_wm' part is for metacity + // Several other WMs do their decorations different yet again and we fail to deal + // with that, since I couldn't find any frigging commonality between them. + // The only sane WM seems to be KDE + + if (!xevent.ConfigureEvent.send_event) { + IntPtr dummy_ptr; + + XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, -xevent.ConfigureEvent.x, -xevent.ConfigureEvent.y, out hwnd.x, out hwnd.y, out dummy_ptr); + } else { + // This is a synthetic event, coordinates are in root space + hwnd.x = xevent.ConfigureEvent.x; + hwnd.y = xevent.ConfigureEvent.y; + if (hwnd.whacky_wm) { + int frame_left; + int frame_top; + + FrameExtents(hwnd.whole_window, out frame_left, out frame_top); + hwnd.x -= frame_left; + hwnd.y -= frame_top; + } + } + } + hwnd.width = xevent.ConfigureEvent.width; + hwnd.height = xevent.ConfigureEvent.height; + + if (!hwnd.configure_pending) { + MessageQueue.Enqueue(xevent); + hwnd.configure_pending = true; + } + } + // We drop configure events for Client windows + } + + private void ShowCaret() { + if ((Caret.gc == IntPtr.Zero) || Caret.On) { + return; + } + Caret.On = true; + + lock (XlibLock) { + XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + } + + private void HideCaret() { + if ((Caret.gc == IntPtr.Zero) || !Caret.On) { + return; + } + Caret.On = false; + + lock (XlibLock) { + XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + } + + private int NextTimeout (DateTime now) { + int timeout = Int32.MaxValue; + lock (TimerList) { + foreach (Timer timer in TimerList) { + 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 (TimerList) { + int count; + + count = TimerList.Count; + + if (count == 0) { + return; + } + + for (int i = 0; i < TimerList.Count; i++) { + Timer timer; + + timer = (Timer) TimerList[i]; + + if (timer.Enabled && timer.Expires <= now) { + timer.Update (now); + timer.FireTick (); + } + } + } + } + + private void UpdateMessageQueue () { + DateTime now; + int pending; + + now = DateTime.Now; + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + + if (pending == 0) { + if (Idle != null) { + Idle (this, EventArgs.Empty); + } + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + + if (pending == 0) { + int timeout; + + timeout = NextTimeout (now); + if (timeout > 0) { + #if __MonoCS__ + Syscall.poll (pollfds, (uint) pollfds.Length, timeout); + // Clean out buffer, so we're not busy-looping on the same data + if (pollfds[1].revents != 0) { + wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None); + } + #endif + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + } + + CheckTimers (now); + + if (pending == 0) { + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + + while (pending > 0) { + XEvent xevent = new XEvent (); + + lock (XlibLock) { + XNextEvent (DisplayHandle, ref xevent); + } +//Console.WriteLine("Got x event {0}", xevent); + switch (xevent.type) { + case XEventName.Expose: + AddExpose (xevent); + break; + + case XEventName.SelectionClear: { + // Should we do something? + break; + } + + case XEventName.SelectionRequest: { + if (Dnd.HandleSelectionRequestEvent (ref xevent)) + break; + XEvent sel_event; + + sel_event = new XEvent(); + sel_event.SelectionEvent.type = XEventName.SelectionNotify; + sel_event.SelectionEvent.send_event = true; + sel_event.SelectionEvent.display = DisplayHandle; + sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection; + sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target; + sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor; + sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time; + sel_event.SelectionEvent.property = IntPtr.Zero; + + // Seems that some apps support asking for supported types + if (xevent.SelectionEvent.target == NetAtoms[(int)NA.TARGETS]) { + int[] atoms; + int atom_count; + + atoms = new int[5]; + atom_count = 0; + + if (Clipboard.Item is String) { + atoms[atom_count++] = (int)Atom.XA_STRING; + atoms[atom_count++] = (int)NetAtoms[(int)NA.OEMTEXT]; + atoms[atom_count++] = (int)NetAtoms[(int)NA.UNICODETEXT]; + } else if (Clipboard.Item is Image) { + atoms[atom_count++] = (int)Atom.XA_PIXMAP; + atoms[atom_count++] = (int)Atom.XA_BITMAP; + } else { + // FIXME - handle other types + } + + XChangeProperty(DisplayHandle, xevent.SelectionEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count); + } else if (Clipboard.Item is string) { + IntPtr buffer; + int buflen; + + buflen = 0; + + if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) { + Byte[] bytes; + + bytes = new ASCIIEncoding().GetBytes((string)Clipboard.Item); + buffer = Marshal.AllocHGlobal(bytes.Length); + buflen = bytes.Length; + + for (int i = 0; i < buflen; i++) { + Marshal.WriteByte(buffer, i, bytes[i]); + } + } else if (xevent.SelectionRequestEvent.target == NetAtoms[(int)NA.OEMTEXT]) { + // FIXME - this should encode into ISO2022 + buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item); + while (Marshal.ReadByte(buffer, buflen) != 0) { + buflen++; + } + } else if (xevent.SelectionRequestEvent.target == NetAtoms[(int)NA.UNICODETEXT]) { + buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item); + while (Marshal.ReadByte(buffer, buflen) != 0) { + buflen++; + } + } else { + buffer = IntPtr.Zero; + } + + if (buffer != IntPtr.Zero) { + XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen); + sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; + Marshal.FreeHGlobal(buffer); + } + } else if (Clipboard.Item is Image) { + if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) { + // FIXME - convert image and store as property + } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) { + // FIXME - convert image and store as property + } + } + + XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event); + break; + } + + case XEventName.SelectionNotify: { + if (Clipboard.Enumerating) { + Clipboard.Enumerating = false; + if (xevent.SelectionEvent.property != IntPtr.Zero) { + XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property); + if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) { + Clipboard.Formats.Add(xevent.SelectionEvent.property); + #if DriverDebugExtra + Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property); + #endif + } + } + } else if (Clipboard.Retrieving) { + Clipboard.Retrieving = false; + if (xevent.SelectionEvent.property != IntPtr.Zero) { + TranslatePropertyToClipboard(xevent.SelectionEvent.property); + } else { + Clipboard.Item = null; + } + } else { + Dnd.HandleSelectionNotifyEvent (ref xevent); + } + break; + } + + case XEventName.KeyPress: + case XEventName.KeyRelease: + case XEventName.ButtonPress: + case XEventName.ButtonRelease: + case XEventName.MotionNotify: + case XEventName.EnterNotify: + case XEventName.LeaveNotify: + case XEventName.CreateNotify: + case XEventName.DestroyNotify: + case XEventName.FocusIn: + case XEventName.FocusOut: + case XEventName.ClientMessage: + case XEventName.ReparentNotify: + MessageQueue.Enqueue (xevent); + break; + + case XEventName.ConfigureNotify: + AddConfigureNotify(xevent); + break; + + case XEventName.PropertyNotify: + if (xevent.PropertyEvent.atom == NetAtoms[(int)NA._NET_ACTIVE_WINDOW]) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr prev_active;; + + prev_active = ActiveWindow; + XGetWindowProperty(DisplayHandle, RootWindow, NetAtoms[(int)NA._NET_ACTIVE_WINDOW], IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop)); + XFree(prop); + + if (prev_active != ActiveWindow) { + if (prev_active != IntPtr.Zero) { + PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + } + if (ActiveWindow != IntPtr.Zero) { + PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); + } + } + if (ModalWindows.Count == 0) { + break; + } else { + // Modality handling, if we are modal and the new active window is one + // of ours but not the modal one, switch back to the modal window + + if (NativeWindow.FindWindow(ActiveWindow) != null) { + if (ActiveWindow != (IntPtr)ModalWindows.Peek()) { + Activate((IntPtr)ModalWindows.Peek()); + } + } + break; + } + } + } + break; + + } + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + } + + private IntPtr GetMousewParam(int Delta) { + int result = 0; + + if ((MouseState & MouseButtons.Left) != 0) { + result |= (int)MsgButtons.MK_LBUTTON; + } + + if ((MouseState & MouseButtons.Middle) != 0) { + result |= (int)MsgButtons.MK_MBUTTON; + } + + if ((MouseState & MouseButtons.Right) != 0) { + result |= (int)MsgButtons.MK_RBUTTON; + } + + Keys mods = ModifierKeys; + if ((mods & Keys.Control) != 0) { + result |= (int)MsgButtons.MK_CONTROL; + } + + if ((mods & Keys.Shift) != 0) { + result |= (int)MsgButtons.MK_SHIFT; + } + + result |= Delta << 16; + + return (IntPtr)result; + } + private IntPtr XGetParent(IntPtr handle) { + IntPtr Root; + IntPtr Parent; + IntPtr Children; + int ChildCount; + + lock (XlibLock) { + XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount); + } + + if (Children!=IntPtr.Zero) { + lock (XlibLock) { + XFree(Children); + } + } + return Parent; + } + + private int HandleError(IntPtr display, ref XErrorEvent error_event) { + if (ErrorExceptions) { + throw new XException(error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code); + } else { + Console.WriteLine("X11 Error encountered: {0}{1}\n", XException.GetMessage(error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code), WhereString()); + } + return 0; + } + + private void DestroyChildWindow(Control c) { + Hwnd hwnd; + int i; + Control[] controls; + + if (c != null) { + controls = c.child_controls.GetAllControls (); + + for (i = 0; i < controls.Length; i++) { + if (controls[i].IsHandleCreated) { + hwnd = Hwnd.ObjectFromHandle(controls[i].Handle); + SendMessage(controls[i].Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); + hwnd.Dispose(); + } + DestroyChildWindow(controls[i]); + } + } + } + + #endregion // Private Methods + + #region Callbacks + private void MouseHover(object sender, EventArgs e) { + if ((HoverState.X == MousePosition.X) && (HoverState.Y == MousePosition.Y)) { + XEvent xevent; + + HoverState.Timer.Enabled = false; + + if (HoverState.Window != IntPtr.Zero) { + xevent = new XEvent (); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + xevent.ClientMessageEvent.window = HoverState.Window; + xevent.ClientMessageEvent.message_type = HoverState.Atom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X); + + MessageQueue.EnqueueLocked (xevent); + + WakeupMain (); + } + } + } + + private void CaretCallback(object sender, EventArgs e) { + if (Caret.Paused) { + return; + } + Caret.On = !Caret.On; + + XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + #endregion // Callbacks + + #region Public Properties + + internal override int Caption { + get { + return 19; + } + } + + internal override Size CursorSize { + get { + int x; + int y; + + if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) { + return new Size(x, y); + } else { + return new Size(16, 16); + } + } + } + + internal override bool DragFullWindows { + get { + return true; + } + } + + internal override Size DragSize { + get { + return new Size(4, 4); + } + } + + internal override Size FrameBorderSize { + get { + throw new NotImplementedException(); + } + } + + internal override Size IconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) { + long current; + int largest; + + current = (long)list; + largest = 0; + + size = new XIconSize(); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType()); + current += Marshal.SizeOf(size); + + // Look for our preferred size + if (size.min_width == 32) { + XFree(list); + return new Size(32, 32); + } + + if (size.max_width == 32) { + XFree(list); + return new Size(32, 32); + } + + if (size.min_width < 32 && size.max_width > 32) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 32) { + XFree(list); + return new Size(32, 32); + } + } + } + + if (largest < size.max_width) { + largest = size.max_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size(largest, largest); + + } else { + return new Size(32, 32); + } + } + } + + internal override int KeyboardSpeed { + get{ + // + // A lot harder: need to do: + // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1 + // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8 + // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0 + // + // And from that we can tell the repetition rate + // + // Notice, the values must map to: + // [0, 31] which maps to 2.5 to 30 repetitions per second. + // + return 0; + } + } + + internal override int KeyboardDelay { + get { + // + // Return values must range from 0 to 4, 0 meaning 250ms, + // and 4 meaning 1000 ms. + // + return 1; // ie, 500 ms + } + } + + internal override Size MaxWindowTrackSize { + get { + return new Size (WorkingArea.Width, WorkingArea.Height); + } + } + + internal override Size MinimizedWindowSize { + get { + return new Size(1, 1); + } + } + + internal override Size MinimizedWindowSpacingSize { + get { + return new Size(1, 1); + } + } + + internal override Size MinimumWindowSize { + get { + return new Size(1, 1); + } + } + + internal override Size MinWindowTrackSize { + get { + return new Size(1, 1); + } + } + + internal override Keys ModifierKeys { + get { + return Keyboard.ModifierKeys; + } + } + + internal override Size SmallIconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) { + long current; + int smallest; + + current = (long)list; + smallest = 0; + + size = new XIconSize(); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType()); + current += Marshal.SizeOf(size); + + // Look for our preferred size + if (size.min_width == 16) { + XFree(list); + return new Size(16, 16); + } + + if (size.max_width == 16) { + XFree(list); + return new Size(16, 16); + } + + if (size.min_width < 16 && size.max_width > 16) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 16) { + XFree(list); + return new Size(16, 16); + } + } + } + + if (smallest == 0 || smallest > size.min_width) { + smallest = size.min_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size(smallest, smallest); + + } else { + return new Size(16, 16); + } + } + } + + internal override int MouseButtonCount { + get { + return 3; + } + } + + internal override bool MouseButtonsSwapped { + get { + return false; // FIXME - how to detect? + } + } + + internal override bool MouseWheelPresent { + get { + return true; // FIXME - how to detect? + } + } + + internal override Rectangle VirtualScreen { + get { + return WorkingArea; + } + } + + internal override Rectangle WorkingArea { + get { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + int width; + int height; + + XGetWindowProperty(DisplayHandle, RootWindow, NetAtoms[(int)NA._NET_DESKTOP_GEOMETRY], IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems == 2) && (prop != IntPtr.Zero) && IntPtr.Size == 4) { + width = Marshal.ReadInt32(prop, 0); + height = Marshal.ReadInt32(prop, 4); + + XFree(prop); + return new Rectangle(0, 0, width, height); + } else { + XWindowAttributes attributes=new XWindowAttributes(); + + lock (XlibLock) { + XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes); + } + + return new Rectangle(0, 0, attributes.width, attributes.height); + } + } + } + #endregion // Public properties + + #region Public Static Methods + internal override IntPtr InitializeDriver() { + lock (this) { + if (DisplayHandle==IntPtr.Zero) { + SetDisplay(XOpenDisplay(IntPtr.Zero)); + } + } + return IntPtr.Zero; + } + + internal override void ShutdownDriver(IntPtr token) { + lock (this) { + if (DisplayHandle!=IntPtr.Zero) { + XCloseDisplay(DisplayHandle); + DisplayHandle=IntPtr.Zero; + } + } + } + + internal override void EnableThemes() { + ThemesEnabled = true; + } + + + internal override void Activate(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) lock (XlibLock) { + SendNetWMMessage(hwnd.whole_window, NetAtoms[(int)NA._NET_ACTIVE_WINDOW], IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + //XRaiseWindow(DisplayHandle, handle); + } + return; + } + + internal override void AudibleAlert() { + XBell(DisplayHandle, 0); + return; + } + + + internal override void CaretVisible(IntPtr handle, bool visible) { + // Visible is cumulative; two hides require two shows before the caret is visible again + if (Caret.Hwnd == handle) { + if (visible) { + if (Caret.Visible < 1) { + Caret.Visible++; + Caret.On = false; + if (Caret.Visible == 1) { + ShowCaret(); + Caret.Timer.Start(); + } + } + } else { + Caret.Visible--; + if (Caret.Visible == 0) { + Caret.Timer.Stop(); + HideCaret(); + } + } + } + } + + internal override bool CalculateWindowRect(IntPtr handle, ref Rectangle ClientRect, int Style, int ExStyle, Menu menu, out Rectangle WindowRect) { + FormBorderStyle border_style; + TitleStyle title_style; + int caption_height; + int tool_caption_height; + + DeriveStyles(handle, Style, ExStyle, out border_style, out title_style, + out caption_height, out tool_caption_height); + + WindowRect = Hwnd.GetWindowRectangle(border_style, menu, title_style, + caption_height, tool_caption_height, + ClientRect); + + return true; + } + + internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates(DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override int[] ClipboardAvailableFormats(IntPtr handle) { + DataFormats.Format f; + int[] result; + + f = DataFormats.Format.List; + + if (XGetSelectionOwner(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD]) == IntPtr.Zero) { + return null; + } + + Clipboard.Formats = new ArrayList(); + + while (f != null) { + XConvertSelection(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], (IntPtr)f.Id, (IntPtr)f.Id, FosterParent, IntPtr.Zero); + + Clipboard.Enumerating = true; + while (Clipboard.Enumerating) { + UpdateMessageQueue(); + } + f = f.Next; + } + + result = new int[Clipboard.Formats.Count]; + + for (int i = 0; i < Clipboard.Formats.Count; i++) { + result[i] = (int)Clipboard.Formats[i]; + } + + Clipboard.Formats = null; + return result; + } + + internal override void ClipboardClose(IntPtr handle) { + if (handle != ClipMagic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + return; + } + + internal override int ClipboardGetID(IntPtr handle, string format) { + if (handle != ClipMagic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + + if (format == "Text" ) return (int)Atom.XA_STRING; + else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP; + //else if (format == "MetaFilePict" ) return 3; + //else if (format == "SymbolicLink" ) return 4; + //else if (format == "DataInterchangeFormat" ) return 5; + //else if (format == "Tiff" ) return 6; + else if (format == "OEMText" ) return XInternAtom(DisplayHandle, "COMPOUND_TEXT", false).ToInt32(); + else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP; + else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless + //else if (format == "PenData" ) return 10; + //else if (format == "RiffAudio" ) return 11; + //else if (format == "WaveAudio" ) return 12; + else if (format == "UnicodeText" ) return XInternAtom(DisplayHandle, "UTF8_STRING", false).ToInt32(); + //else if (format == "EnhancedMetafile" ) return 14; + //else if (format == "FileDrop" ) return 15; + //else if (format == "Locale" ) return 16; + + return XInternAtom(DisplayHandle, format, false).ToInt32(); + } + + internal override IntPtr ClipboardOpen() { + return ClipMagic; + } + + internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) { + XConvertSelection(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero); + + Clipboard.Retrieving = true; + while (Clipboard.Retrieving) { + UpdateMessageQueue(); + } + + return Clipboard.Item; + } + + internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter) { + Clipboard.Item = obj; + Clipboard.Type = type; + Clipboard.Converter = converter; + + if (obj != null) { + XSetSelectionOwner(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], FosterParent, IntPtr.Zero); + } else { + // Clearing the selection + XSetSelectionOwner(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], IntPtr.Zero, IntPtr.Zero); + } + } + + internal override void CreateCaret(IntPtr handle, int width, int height) { + XGCValues gc_values; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (Caret.Hwnd != IntPtr.Zero) { + DestroyCaret(Caret.Hwnd); + } + + Caret.Hwnd = handle; + Caret.Window = hwnd.client_window; + Caret.Width = width; + Caret.Height = height; + Caret.Visible = 0; + Caret.On = false; + + gc_values = new XGCValues(); + gc_values.line_width = width; + + Caret.gc = XCreateGC(DisplayHandle, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values); + if (Caret.gc == IntPtr.Zero) { + Caret.Hwnd = IntPtr.Zero; + return; + } + + XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert); + } + + internal override IntPtr CreateWindow(CreateParams cp) { + XSetWindowAttributes Attributes; + Hwnd hwnd; + int X; + int Y; + int Width; + int Height; + IntPtr ParentHandle; + IntPtr WholeWindow; + IntPtr ClientWindow; + Rectangle ClientRect; + SetWindowValuemask ValueMask; + + + hwnd = new Hwnd(); + + Attributes = new XSetWindowAttributes(); + X = cp.X; + Y = cp.Y; + Width = cp.Width; + Height = cp.Height; + + if (Width<1) Width=1; + if (Height<1) Height=1; + + if (cp.Parent != IntPtr.Zero) { + ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).client_window; + } else { + 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 ((cp.Style & (int)WindowStyles.WS_POPUP) != 0) { + ParentHandle=RootWindow; + } else { + // Default position on screen, if window manager doesn't place us somewhere else + if (X<1) X = 50; + if (Y<1) Y = 50; + ParentHandle=RootWindow; + } + } + + ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; + + Attributes.bit_gravity = Gravity.NorthWestGravity; + Attributes.win_gravity = Gravity.NorthWestGravity; + + // Save what's under the toolwindow + if ((cp.ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + Attributes.save_under = true; + ValueMask |= SetWindowValuemask.SaveUnder; + } + + + // If we're a popup without caption we override the WM + if ((cp.Style & ((int)WindowStyles.WS_POPUP)) != 0) { + if ((cp.Style & (int)WindowStyles.WS_CAPTION) == 0) { + Attributes.override_redirect = true; + ValueMask |= SetWindowValuemask.OverrideRedirect; + } + } + + hwnd.x = X; + hwnd.y = Y; + hwnd.width = Width; + hwnd.height = Height; + hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent); + + if ((cp.Style & ((int)WindowStyles.WS_DISABLED)) != 0) { + hwnd.enabled = false; + } + + ClientRect = hwnd.ClientRect; + ClientWindow = IntPtr.Zero; + + lock (XlibLock) { + WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, Width, Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes); + if (WholeWindow != IntPtr.Zero) { + ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder); + + if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) { + ValueMask = SetWindowValuemask.ColorMap; + Attributes.colormap = CustomColormap; + } + ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes); + } + } + + if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) { + throw new Exception("Could not create X11 windows"); + } + + hwnd.WholeWindow = WholeWindow; + hwnd.ClientWindow = ClientWindow; + + #if DriverDebug + Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0); + #endif + + lock (XlibLock) { + XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)SelectInputMask)); + XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)SelectInputMask)); + + if ((cp.Style & (int)WindowStyles.WS_VISIBLE) != 0) { + XMapWindow(DisplayHandle, hwnd.whole_window); + XMapWindow(DisplayHandle, hwnd.client_window); + hwnd.visible = true; + } + } + + if ((cp.ExStyle & (int) WindowStyles.WS_EX_TOPMOST) != 0) { + Console.WriteLine ("Setting transient: " + XSetTransientForHint (DisplayHandle, hwnd.whole_window, RootWindow)); + } + + SetWMStyles(hwnd, cp); + + if ((cp.Style & (int)WindowStyles.WS_MINIMIZE) != 0) { + SetWindowState(hwnd.Handle, FormWindowState.Minimized); + } else if ((cp.Style & (int)WindowStyles.WS_MAXIMIZE) != 0) { + SetWindowState(hwnd.Handle, FormWindowState.Maximized); + } + + // for now make all windows dnd enabled + Dnd.SetAllowDrop (hwnd, true); + + // Set caption/window title + Text(hwnd.Handle, cp.Caption); + + return hwnd.Handle; + } + + internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) { + CreateParams create_params = new CreateParams(); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName=XplatUI.DefaultClassName; + create_params.ClassStyle = 0; + create_params.ExStyle=0; + create_params.Parent=IntPtr.Zero; + create_params.Param=0; + + return CreateWindow(create_params); + } + + internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) { + IntPtr cursor; + Bitmap cursor_bitmap; + Bitmap cursor_mask; + Byte[] cursor_bits; + Byte[] mask_bits; + Color c_pixel; + Color m_pixel; + int width; + int height; + IntPtr cursor_pixmap; + IntPtr mask_pixmap; + XColor fg; + XColor bg; + bool and; + bool xor; + + if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) { + return IntPtr.Zero; + } + + // Win32 only allows creation cursors of a certain size + if ((bitmap.Width != width) || (bitmap.Width != height)) { + cursor_bitmap = new Bitmap(bitmap, new Size(width, height)); + cursor_mask = new Bitmap(mask, new Size(width, height)); + } else { + cursor_bitmap = bitmap; + cursor_mask = mask; + } + + width = cursor_bitmap.Width; + height = cursor_bitmap.Height; + + cursor_bits = new Byte[(width / 8) * height]; + mask_bits = new Byte[(width / 8) * height]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + c_pixel = cursor_bitmap.GetPixel(x, y); + m_pixel = cursor_mask.GetPixel(x, y); + + and = c_pixel == cursor_pixel; + xor = m_pixel == mask_pixel; + + if (!and && !xor) { + // Black + // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0 + mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + } else if (and && !xor) { + // White + cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); +#if notneeded + } else if (and && !xor) { + // Screen + } else if (and && xor) { + // Inverse Screen + + // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same + // we want both to be 0 so nothing to be done + //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); + //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8)); +#endif + } + } + } + + cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + fg = new XColor(); + bg = new XColor(); + + fg.pixel = XWhitePixel(DisplayHandle, ScreenNo); + fg.red = (ushort)65535; + fg.green = (ushort)65535; + fg.blue = (ushort)65535; + + bg.pixel = XBlackPixel(DisplayHandle, ScreenNo); + + cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot); + + XFreePixmap(DisplayHandle, cursor_pixmap); + XFreePixmap(DisplayHandle, mask_pixmap); + + return cursor; + } + + internal override IntPtr DefineStdCursor(StdCursor id) { + CursorFontShape shape; + IntPtr cursor; + + // FIXME - define missing shapes + + switch (id) { + case StdCursor.AppStarting: { + shape = CursorFontShape.XC_watch; + break; + } + + case StdCursor.Arrow: { + return IntPtr.Zero; + } + + case StdCursor.Cross: { + shape = CursorFontShape.XC_crosshair; + break; + } + + case StdCursor.Default: { + return IntPtr.Zero; + } + + case StdCursor.Hand: { + shape = CursorFontShape.XC_hand1; + break; + } + + case StdCursor.Help: { + shape = CursorFontShape.XC_question_arrow; + break; + } + + case StdCursor.HSplit: { + shape = CursorFontShape.XC_sb_v_double_arrow; + break; + } + + case StdCursor.IBeam: { + shape = CursorFontShape.XC_xterm; + break; + } + + case StdCursor.No: { + shape = CursorFontShape.XC_circle; + break; + } + + case StdCursor.NoMove2D: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.NoMoveHoriz: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.NoMoveVert: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanEast: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanNE: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanNorth: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanNW: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanSE: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanSouth: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanSW: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanWest: { + shape = CursorFontShape.XC_sizing; + break; + } + + case StdCursor.SizeAll: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.SizeNESW: { + shape = CursorFontShape.XC_top_right_corner; + break; + } + + case StdCursor.SizeNS: { + shape = CursorFontShape.XC_sb_v_double_arrow; + break; + } + + case StdCursor.SizeNWSE: { + shape = CursorFontShape.XC_top_left_corner; + break; + } + + case StdCursor.SizeWE: { + shape = CursorFontShape.XC_sb_h_double_arrow; + break; + } + + case StdCursor.UpArrow: { + shape = CursorFontShape.XC_center_ptr; + break; + } + + case StdCursor.VSplit: { + shape = CursorFontShape.XC_sb_h_double_arrow; + break; + } + + case StdCursor.WaitCursor: { + shape = CursorFontShape.XC_watch; + break; + } + + default: { + return IntPtr.Zero; + } + } + + lock (XlibLock) { + cursor = XCreateFontCursor(DisplayHandle, shape); + } + return cursor; + } + + internal override IntPtr DefWndProc(ref Message msg) { + switch ((Msg)msg.Msg) { + case Msg.WM_SETCURSOR: { + Hwnd hwnd; + // Pass to parent window first + hwnd = Hwnd.GetObjectFromWindow(msg.HWnd); + while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) { + hwnd = hwnd.parent; + NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam); + } + + if (msg.Result == IntPtr.Zero) { + IntPtr handle; + + switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) { + case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break; + case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTERROR: if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) { + AudibleAlert(); + } + handle = Cursors.Default.handle; + break; + + case HitTest.HTHELP: handle = Cursors.Help.handle; break; + case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break; + case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break; + + #if SameAsDefault + case HitTest.HTGROWBOX: + case HitTest.HTSIZE: + case HitTest.HTZOOM: + case HitTest.HTVSCROLL: + case HitTest.HTSYSMENU: + case HitTest.HTREDUCE: + case HitTest.HTNOWHERE: + case HitTest.HTMAXBUTTON: + case HitTest.HTMINBUTTON: + case HitTest.HTMENU: + case HitTest.HSCROLL: + case HitTest.HTBOTTOM: + case HitTest.HTCAPTION: + case HitTest.HTCLIENT: + case HitTest.HTCLOSE: + #endif + default: handle = Cursors.Default.handle; break; + } + SetCursor(msg.HWnd, handle); + } + return (IntPtr)1; + } + } + return IntPtr.Zero; + } + + internal override void DestroyCaret(IntPtr handle) { + if (Caret.Hwnd == handle) { + if (Caret.Visible == 1) { + Caret.Timer.Stop(); + HideCaret(); + } + if (Caret.gc != IntPtr.Zero) { + XFreeGC(DisplayHandle, Caret.gc); + Caret.gc = IntPtr.Zero; + } + Caret.Hwnd = IntPtr.Zero; + Caret.Visible = 0; + Caret.On = false; + } + } + + internal override void DestroyCursor(IntPtr cursor) { + lock (XlibLock) { + XFreeCursor(DisplayHandle, cursor); + } + } + + internal override void DestroyWindow(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + #if DriverDebug + Console.WriteLine("window {0:X} already destroyed", handle.ToInt32()); + #endif + return; + } + + #if DriverDebug + Console.WriteLine("Destroying window {0:X}", handle.ToInt32()); + #endif + + // Make sure if the caret is in the window, that we destroy the caret, too + if (Caret.Hwnd == hwnd.client_window) { + DestroyCaret(handle); + } + + // Mark our children as gone as well + DestroyChildWindow(Control.ControlNativeWindow.ControlFromHandle(handle)); + + // Send destroy message + SendMessage(handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); + + lock (XlibLock) { + if (hwnd.client_window != IntPtr.Zero) { + XDestroyWindow(DisplayHandle, hwnd.client_window); + } + + if ((hwnd.whole_window != IntPtr.Zero) && (hwnd.whole_window != hwnd.client_window)) { + XDestroyWindow(DisplayHandle, hwnd.whole_window); + } + } + hwnd.Dispose(); + } + + internal override IntPtr DispatchMessage(ref MSG msg) { + return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) { + Hwnd hwnd; + XGCValues gc_values; + IntPtr gc; + + hwnd = Hwnd.ObjectFromHandle(handle); + + gc_values = new XGCValues(); + + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + gc_values.line_width = line_width; + gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo); + + // This logic will give us true rubber bands: (libsx, SANE_XOR) + //mask = foreground ^ background; + //XSetForeground(DisplayHandle, gc, 0xffffffff); + //XSetBackground(DisplayHandle, gc, background); + //XSetFunction(DisplayHandle, gc, GXxor); + //XSetPlaneMask(DisplayHandle, gc, mask); + + + gc = XCreateGC(DisplayHandle, hwnd.client_window, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values); + uint foreground; + uint background; + + Control control; + control = Control.FromHandle(handle); + + XColor xcolor = new XColor(); + + xcolor.red = (ushort)(control.ForeColor.R * 257); + xcolor.green = (ushort)(control.ForeColor.G * 257); + xcolor.blue = (ushort)(control.ForeColor.B * 257); + XAllocColor(DisplayHandle, DefaultColormap, ref xcolor); + foreground = (uint)xcolor.pixel.ToInt32(); + + xcolor.red = (ushort)(control.BackColor.R * 257); + xcolor.green = (ushort)(control.BackColor.G * 257); + xcolor.blue = (ushort)(control.BackColor.B * 257); + XAllocColor(DisplayHandle, DefaultColormap, ref xcolor); + background = (uint)xcolor.pixel.ToInt32(); + + uint mask = foreground ^ background; + + XSetForeground(DisplayHandle, gc, (UIntPtr)0xffffffff); + XSetBackground(DisplayHandle, gc, (UIntPtr)background); + XSetFunction(DisplayHandle, gc, GXFunction.GXxor); + XSetPlaneMask(DisplayHandle, gc, (IntPtr)mask); + + if ((rect.Width > 0) && (rect.Height > 0)) { + XDrawRectangle(DisplayHandle, hwnd.client_window, gc, rect.Left, rect.Top, rect.Width, rect.Height); + } else { + if (rect.Width > 0) { + XDrawLine(DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.Right, rect.Y); + } else { + XDrawLine(DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.X, rect.Bottom); + } + } + XFreeGC(DisplayHandle, gc); + } + + internal override void DoEvents() { + MSG msg = new MSG (); + + if (OverrideCursorHandle != IntPtr.Zero) { + OverrideCursorHandle = IntPtr.Zero; + } + + while (PeekMessage(ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + } + + internal override void EnableWindow(IntPtr handle, bool Enable) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null) { + hwnd.Enabled = Enable; + } + } + + internal override void EndLoop(Thread thread) { + // This is where we one day will shut down the loop for the thread + } + + + internal override IntPtr GetActive() { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr active = IntPtr.Zero; + + XGetWindowProperty(DisplayHandle, RootWindow, NetAtoms[(int)NA._NET_ACTIVE_WINDOW], IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + active = (IntPtr)Marshal.ReadInt32(prop); + XFree(prop); + } + + if (active != IntPtr.Zero) { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow(active); + if (hwnd != null) { + active = hwnd.Handle; + } else { + active = IntPtr.Zero; + } + } + return active; + } + + internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) { + throw new NotImplementedException (); + } + + internal override void GetDisplaySize(out Size size) { + XWindowAttributes attributes=new XWindowAttributes(); + + lock (XlibLock) { + // FIXME - use _NET_WM messages instead? + XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes); + } + + size = new Size(attributes.width, attributes.height); + } + + internal override SizeF GetAutoScaleSize(Font font) { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; + + g = Graphics.FromHwnd(FosterParent); + + width = (float) (g.MeasureString (magic_string, font).Width / magic_number); + return new SizeF(width, font.Height); + } + + internal override IntPtr GetParent(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null && hwnd.parent != null) { + return hwnd.parent.Handle; + } + return IntPtr.Zero; + } + + internal override void GetCursorPos(IntPtr handle, out int x, out int y) { + IntPtr use_handle; + IntPtr root; + IntPtr child; + int root_x; + int root_y; + int win_x; + int win_y; + int keys_buttons; + + if (handle != IntPtr.Zero) { + use_handle = Hwnd.ObjectFromHandle(handle).client_window; + } else { + use_handle = RootWindow; + } + + lock (XlibLock) { + XQueryPointer(DisplayHandle, use_handle, 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; + } + } + + internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) { + return GetFontMetrics(g.GetHdc(), font.ToHfont(), out ascent, out descent); + } + + internal override Point GetMenuOrigin(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + return hwnd.MenuOrigin; + } + return Point.Empty; + } + + internal override bool GetMessage(ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) { + XEvent xevent; + bool client; + Hwnd hwnd; + + ProcessNextMessage: + + if (MessageQueue.Count > 0) { + xevent = (XEvent) MessageQueue.Dequeue (); + } else { + UpdateMessageQueue (); + + if (MessageQueue.Count > 0) { + xevent = (XEvent) MessageQueue.Dequeue (); + } else { + if (!PostQuitState) { + msg.hwnd= IntPtr.Zero; + msg.message = Msg.WM_ENTERIDLE; + return true; + } + + // We reset ourselves so GetMessage can be called again + PostQuitState = false; + + return false; + } + } + + // FIXME - handle filtering + + hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window); + + // Handle messages for windows that are already or are about to be destroyed + if (hwnd == null) { + #if DriverDebug + Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32()); + #endif + goto ProcessNextMessage; + } + + if (hwnd.client_window == xevent.AnyEvent.window) { + client = true; + //Console.WriteLine("Client message, sending to window {0:X}", msg.hwnd.ToInt32()); + } else { + client = false; + //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32()); + } + + msg.hwnd = hwnd.Handle; + + // + // 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: { + Keyboard.KeyEvent (FocusWindow, xevent, ref msg); + break; + } + + case XEventName.KeyRelease: { + Keyboard.KeyEvent (FocusWindow, xevent, ref msg); + break; + } + + case XEventName.ButtonPress: { + switch(xevent.ButtonEvent.button) { + case 1: { + MouseState |= MouseButtons.Left; + if (client) { + msg.message = Msg.WM_LBUTTONDOWN; + } else { + msg.message = Msg.WM_NCLBUTTONDOWN; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down + msg.wParam=GetMousewParam(0); + break; + } + + case 2: { + MouseState |= MouseButtons.Middle; + if (client) { + msg.message = Msg.WM_MBUTTONDOWN; + } else { + msg.message = Msg.WM_NCMBUTTONDOWN; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam=GetMousewParam(0); + break; + } + + case 3: { + MouseState |= MouseButtons.Right; + if (client) { + msg.message = Msg.WM_RBUTTONDOWN; + } else { + msg.message = Msg.WM_NCRBUTTONDOWN; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + 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); + MousePosition.X = xevent.ButtonEvent.x; + MousePosition.Y = xevent.ButtonEvent.y; + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } + + if (!ClickPending.Pending) { + ClickPending.Pending = true; + ClickPending.Hwnd = msg.hwnd; + ClickPending.Message = msg.message; + ClickPending.wParam = msg.wParam; + ClickPending.lParam = msg.lParam; + ClickPending.Time = (long)xevent.ButtonEvent.time; + } else { + if ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message)) { + // Looks like a genuine double click, clicked twice on the same spot with the same keys + switch(xevent.ButtonEvent.button) { + case 1: { + msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK; + break; + } + + case 2: { + msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK; + break; + } + + case 3: { + msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK; + break; + } + } + } + ClickPending.Pending = false; + } + + break; + } + + case XEventName.ButtonRelease: { + Dnd.HandleButtonRelease (ref xevent); + switch(xevent.ButtonEvent.button) { + case 1: { + MouseState &= ~MouseButtons.Left; + if (client) { + msg.message = Msg.WM_LBUTTONUP; + } else { + msg.message = Msg.WM_NCLBUTTONUP; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam=GetMousewParam(0); + break; + } + + case 2: { + MouseState &= ~MouseButtons.Middle; + if (client) { + msg.message = Msg.WM_MBUTTONUP; + } else { + msg.message = Msg.WM_NCMBUTTONUP; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam=GetMousewParam(0); + break; + } + + case 3: { + MouseState &= ~MouseButtons.Right; + if (client) { + msg.message = Msg.WM_RBUTTONUP; + } else { + msg.message = Msg.WM_NCRBUTTONUP; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam=GetMousewParam(0); + break; + } + + case 4: { + goto ProcessNextMessage; + } + + case 5: { + goto ProcessNextMessage; + } + } + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } + + msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); + MousePosition.X = xevent.ButtonEvent.x; + MousePosition.Y = xevent.ButtonEvent.y; + break; + } + + case XEventName.MotionNotify: { + if (client) { + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); + #endif + + if (Dnd.HandleMotionNotify (ref xevent)) + goto ProcessNextMessage; + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } else { + NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT); + } + + msg.message = Msg.WM_MOUSEMOVE; + msg.wParam = GetMousewParam(0); + msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF); + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + HoverState.X = MousePosition.X = xevent.MotionEvent.x; + HoverState.Y = MousePosition.Y = xevent.MotionEvent.y; + + break; + } else { + HitTest ht; + IntPtr dummy; + int screen_x; + int screen_y; + + #if DriverDebugExtra + Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); + #endif + msg.message = Msg.WM_NCMOUSEMOVE; + + if (!hwnd.Enabled) { + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + // The hit test is sent in screen coordinates + XTranslateCoordinates (DisplayHandle, hwnd.client_window, RootWindow, + xevent.MotionEvent.x, xevent.MotionEvent.y, + out screen_x, out screen_y, out dummy); + + msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF); + ht = (HitTest)NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, + IntPtr.Zero, msg.lParam).ToInt32 (); + NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht); + + MousePosition.X = xevent.MotionEvent.x; + MousePosition.Y = xevent.MotionEvent.y; + } + + break; + } + + case XEventName.EnterNotify: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) { + goto ProcessNextMessage; + } + msg.message = Msg.WM_MOUSE_ENTER; + HoverState.Timer.Enabled = true; + HoverState.Window = xevent.CrossingEvent.window; + break; + } + + case XEventName.LeaveNotify: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) { + goto ProcessNextMessage; + } + msg.message=Msg.WM_MOUSE_LEAVE; + HoverState.Timer.Enabled = false; + HoverState.Window = IntPtr.Zero; + break; + } + + #if later + case XEventName.CreateNotify: { + if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { + msg.message = WM_CREATE; + // Set up CreateStruct + } else { + goto ProcessNextMessage; + } + break; + } + #endif + + + case XEventName.ReparentNotify: { + if (hwnd.parent == null) { // Toplevel + if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) { + // We need to adjust x/y + // This sucks ass, part 2 + // Every WM does the reparenting of toplevel windows different, so there's + // no standard way of getting our adjustment considering frames/decorations + // The code below is needed for metacity. KDE doesn't works just fine without this + int dummy_int; + IntPtr dummy_ptr; + int new_x; + int new_y; + int frame_left; + int frame_top; + + hwnd.Reparented = true; + + XGetGeometry(DisplayHandle, XGetParent(hwnd.whole_window), out dummy_ptr, out new_x, out new_y, out dummy_int, out dummy_int, out dummy_int, out dummy_int); + FrameExtents(hwnd.whole_window, out frame_left, out frame_top); + if ((frame_left != 0) && (frame_top != 0) && (new_x != frame_left) && (new_y != frame_top)) { + hwnd.x = new_x; + hwnd.y = new_y; + hwnd.whacky_wm = true; + } + + msg.message = Msg.WM_WINDOWPOSCHANGED; + if (hwnd.opacity != 0xffffffff) { + uint opacity; + + opacity = hwnd.opacity; + XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), NetAtoms[(int)NA._NET_WM_WINDOW_OPACITY], (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1); + } + } else { + hwnd.Reparented = false; + goto ProcessNextMessage; + } + } + break; + } + + case XEventName.ConfigureNotify: { + if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + IntPtr ptr; + Rectangle rect; + + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}", hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); + #endif + msg.message = Msg.WM_WINDOWPOSCHANGED; + hwnd.configure_pending = false; + + // We need to adjust our client window to track the resize of whole_window + rect = hwnd.DefaultClientRect; + + ncp = new XplatUIWin32.NCCALCSIZE_PARAMS(); + ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp)); + + ncp.rgrc1.left = rect.Left; + ncp.rgrc1.top = rect.Top; + ncp.rgrc1.right = rect.Right; + ncp.rgrc1.bottom = rect.Bottom; + + Marshal.StructureToPtr(ncp, ptr, true); + NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr); + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS)); + Marshal.FreeHGlobal(ptr); + + // FIXME - debug this with Menus, need to set hwnd.ClientRect + + rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top); + + XMoveResizeWindow(DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height); + } else { + goto ProcessNextMessage; + } + + msg.lParam=IntPtr.Zero; // FIXME - Generate LPWINDOWPOS structure and pass on + break; + } + + case XEventName.FocusIn: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + msg.message=Msg.WM_SETFOCUS; + msg.wParam=IntPtr.Zero; + break; + } + + case XEventName.FocusOut: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + msg.message=Msg.WM_KILLFOCUS; + msg.wParam=IntPtr.Zero; + break; + } + + case XEventName.Expose: { + if (PostQuitState) { + goto ProcessNextMessage; + } + + + if (client) { + if (!hwnd.expose_pending) { + goto ProcessNextMessage; + } + } else { + if (!hwnd.nc_expose_pending) { + goto ProcessNextMessage; + } + + switch (hwnd.border_style) { + case FormBorderStyle.Fixed3D: { + Graphics g; + + g = Graphics.FromHwnd(hwnd.whole_window); + ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height)); + g.Dispose(); + break; + } + + case FormBorderStyle.FixedSingle: { + Graphics g; + + g = Graphics.FromHwnd(hwnd.whole_window); + ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid); + g.Dispose(); + break; + } + } + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + #endif + + Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + Region region = new Region (rect); + IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed + msg.message = Msg.WM_NCPAINT; + msg.wParam = hrgn; + hwnd.nc_expose_pending = false; + break; + } + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + #endif + if (Caret.Visible == 1) { + Caret.Paused = true; + HideCaret(); + } + + if (Caret.Visible == 1) { + ShowCaret(); + Caret.Paused = false; + } + msg.message = Msg.WM_PAINT; + break; + } + + case XEventName.DestroyNotify: { + + // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children + hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window); + + // We may get multiple for the same window, act only one the first (when Hwnd still knows about it) + if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) { + msg.hwnd = hwnd.client_window; + msg.message=Msg.WM_DESTROY; + hwnd.Dispose(); + + #if DriverDebug + Console.WriteLine("Got DestroyNotify on Window {0:X}", msg.hwnd.ToInt32()); + #endif + } else { + goto ProcessNextMessage; + } + + break; + } + + case XEventName.ClientMessage: { + if (Dnd.HandleClientMessage (ref xevent)) { + goto ProcessNextMessage; + } + + if (xevent.ClientMessageEvent.message_type == AsyncAtom) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1); + break; + } + + if (xevent.ClientMessageEvent.message_type == HoverState.Atom) { + msg.message = Msg.WM_MOUSEHOVER; + msg.wParam = GetMousewParam(0); + msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1); + break; + } + + if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) { + msg.hwnd = xevent.ClientMessageEvent.ptr1; + msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 (); + msg.wParam = xevent.ClientMessageEvent.ptr3; + msg.lParam = xevent.ClientMessageEvent.ptr4; + break; + } + + #if dontcare + if (xevent.ClientMessageEvent.message_type == NetAtoms[(int)NA._XEMBED]) { + Console.WriteLine("GOT EMBED MESSAGE {0:X}", xevent.ClientMessageEvent.ptr2.ToInt32()); + break; + } + #endif + + if (xevent.ClientMessageEvent.message_type == NetAtoms[(int)NA.WM_PROTOCOLS]) { + if (xevent.ClientMessageEvent.ptr1 == NetAtoms[(int)NA.WM_DELETE_WINDOW]) { + msg.message = Msg.WM_CLOSE; + Graphics.FromHdcInternal (IntPtr.Zero); + break; + } + + // We should not get this, but I'll leave the code in case we need it in the future + if (xevent.ClientMessageEvent.ptr1 == NetAtoms[(int)NA.WM_TAKE_FOCUS]) { + goto ProcessNextMessage; + } + } + break; + } + + case XEventName.TimerNotify: { + xevent.TimerNotifyEvent.handler (this, EventArgs.Empty); + break; + } + + default: { + goto ProcessNextMessage; + } + } + + return true; + } + + internal override bool GetText(IntPtr handle, out string text) { + IntPtr textptr; + + textptr = IntPtr.Zero; + + lock (XlibLock) { + // FIXME - use _NET properties + XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr); + } + if (textptr != IntPtr.Zero) { + text = Marshal.PtrToStringAnsi(textptr); + XFree(textptr); + return true; + } else { + text = ""; + return false; + } + } + + internal override void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) { + Hwnd hwnd; + Rectangle rect; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + x = hwnd.x; + y = hwnd.y; + width = hwnd.width; + height = hwnd.height; + + rect = Hwnd.GetClientRectangle(hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height); + + client_width = rect.Width; + client_height = rect.Height; + + return; + } + + // Should we throw an exception or fail silently? + // throw new ArgumentException("Called with an invalid window handle", "handle"); + + x = 0; + y = 0; + width = 0; + height = 0; + client_width = 0; + client_height = 0; + } + + internal override FormWindowState GetWindowState(IntPtr handle) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr atom; + int maximized; + bool minimized; + XWindowAttributes attributes; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + maximized = 0; + minimized = false; + XGetWindowProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + for (int i = 0; i < (long)nitems; i++) { + atom = (IntPtr)Marshal.ReadInt32(prop, i * 4); + if ((atom == NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ]) || (atom == NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT])) { + maximized++; + } else if (atom == NetAtoms[(int)NA._NET_WM_STATE_HIDDEN]) { + minimized = true; + } + } + XFree(prop); + } + + if (minimized) { + return FormWindowState.Minimized; + } else if (maximized == 2) { + return FormWindowState.Maximized; + } + + attributes = new XWindowAttributes(); + XGetWindowAttributes(DisplayHandle, handle, ref attributes); + if (attributes.map_state == MapState.IsUnmapped) { + throw new NotSupportedException("Cannot retrieve the state of an unmapped window"); + } + + + return FormWindowState.Normal; + } + + internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) { + handle = Grab.Hwnd; + GrabConfined = Grab.Confined; + GrabArea = Grab.Area; + } + + internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) { + Hwnd hwnd; + IntPtr confine_to_window; + + confine_to_window = IntPtr.Zero; + + if (confine_to_handle != IntPtr.Zero) { + XWindowAttributes attributes = new XWindowAttributes(); + + hwnd = Hwnd.ObjectFromHandle(confine_to_handle); + + lock (XlibLock) { + XGetWindowAttributes(DisplayHandle, hwnd.client_window, 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; + confine_to_window = hwnd.client_window; + } + + Grab.Hwnd = handle; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XGrabPointer(DisplayHandle, hwnd.client_window, false, + EventMask.ButtonPressMask | EventMask.ButtonMotionMask | + EventMask.ButtonReleaseMask | EventMask.PointerMotionMask, + GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero); + } + } + + internal override void UngrabWindow(IntPtr hwnd) { + lock (XlibLock) { + XUngrabPointer(DisplayHandle, IntPtr.Zero); + XFlush(DisplayHandle); + } + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + } + + internal override void HandleException(Exception e) { + StackTrace st = new StackTrace(e, true); + Console.WriteLine("Exception '{0}'", e.Message+st.ToString()); + Console.WriteLine("{0}{1}", e.Message, st.ToString()); + } + + internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) { + Hwnd hwnd; + XEvent xevent; + + hwnd = Hwnd.ObjectFromHandle(handle); + + + xevent = new XEvent (); + xevent.type = XEventName.Expose; + xevent.ExposeEvent.display = DisplayHandle; + xevent.ExposeEvent.window = hwnd.client_window; + + if (clear) { + xevent.ExposeEvent.x = hwnd.X; + xevent.ExposeEvent.y = hwnd.Y; + xevent.ExposeEvent.width = hwnd.Width; + xevent.ExposeEvent.height = hwnd.Height; + } else { + xevent.ExposeEvent.x = rc.X; + xevent.ExposeEvent.y = rc.Y; + xevent.ExposeEvent.width = rc.Width; + xevent.ExposeEvent.height = rc.Height; + } + + AddExpose (xevent); + } + + internal override bool IsEnabled(IntPtr handle) { + return Hwnd.ObjectFromHandle(handle).Enabled; + } + + internal override bool IsVisible(IntPtr handle) { + return Hwnd.ObjectFromHandle(handle).visible; + } + + internal override void KillTimer(Timer timer) { + lock (TimerList) { + TimerList.Remove(timer); + } + } + + internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void OverrideCursor(IntPtr cursor) { + OverrideCursorHandle = cursor; + } + + internal override PaintEventArgs PaintEventStart(IntPtr handle, bool client) { + PaintEventArgs paint_event; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (Caret.Visible == 1) { + Caret.Paused = true; + HideCaret(); + } + + if (client) { + hwnd.client_dc = Graphics.FromHwnd (hwnd.client_window); + hwnd.client_dc.SetClip(hwnd.invalid); + paint_event = new PaintEventArgs(hwnd.client_dc, hwnd.invalid); + hwnd.expose_pending = false; + + return paint_event; + } else { + hwnd.non_client_dc = Graphics.FromHwnd (hwnd.whole_window); + hwnd.non_client_dc.SetClip (hwnd.nc_invalid); + paint_event = new PaintEventArgs(hwnd.non_client_dc, hwnd.nc_invalid); + hwnd.nc_expose_pending = false; + + return paint_event; + } + } + + internal override void PaintEventEnd(IntPtr handle, bool client) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (client) { + hwnd.ClearInvalidArea(); + + hwnd.client_dc.Flush(); + hwnd.client_dc.Dispose(); + hwnd.client_dc = null; + } else { + hwnd.ClearNcInvalidArea (); + + hwnd.non_client_dc.Flush (); + hwnd.non_client_dc.Dispose (); + hwnd.non_client_dc = null; + } + + + + if (Caret.Visible == 1) { + ShowCaret(); + Caret.Paused = false; + } + } + + internal override bool PeekMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) { + bool pending; + + // FIXME - imlement filtering + + if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) { + throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag + } + + pending = false; + if (MessageQueue.Count > 0) { + pending = true; + } else { + // Only call UpdateMessageQueue if real events are pending + // otherwise we go to sleep on the socket + if (XPending(DisplayHandle) != 0) { + UpdateMessageQueue(); + pending = true; + } + } + + CheckTimers(DateTime.Now); + + if (!pending) { + return false; + } + return GetMessage(ref msg, hWnd, wFilterMin, wFilterMax); + } + + // FIXME - I think this should just enqueue directly + internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) { + XEvent xevent = new XEvent (); + Hwnd hwnd = Hwnd.ObjectFromHandle(handle); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + + if (hwnd != null) { + xevent.ClientMessageEvent.window = hwnd.whole_window; + } else { + xevent.ClientMessageEvent.window = IntPtr.Zero; + } + + xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = handle; + xevent.ClientMessageEvent.ptr2 = (IntPtr) message; + xevent.ClientMessageEvent.ptr3 = wparam; + xevent.ClientMessageEvent.ptr4 = lparam; + + MessageQueue.Enqueue (xevent); + + return true; + } + + internal override void PostQuitMessage(int exitCode) { + XFlush(DisplayHandle); + PostQuitState = true; + + // Remove our display handle from S.D + Graphics.FromHdcInternal (IntPtr.Zero); + } + + internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) { + Hwnd hwnd; + IntPtr gc; + XGCValues gc_values; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd.invalid != Rectangle.Empty) { + // BIG FAT WARNING. This only works with how we use this function right now + // where we basically still scroll the whole window, but work around areas + // that are covered by our children + + hwnd.invalid.X += XAmount; + hwnd.invalid.Y += YAmount; + + if (hwnd.invalid.X < 0) { + hwnd.invalid.Width += hwnd.invalid.X; + hwnd.invalid.X =0; + } + + if (hwnd.invalid.Y < 0) { + hwnd.invalid.Height += hwnd.invalid.Y; + hwnd.invalid.Y =0; + } + } + + gc_values = new XGCValues(); + + if (with_children) { + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + } + + gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values); + + XCopyArea(DisplayHandle, hwnd.client_window, hwnd.client_window, gc, area.X - XAmount, area.Y - YAmount, area.Width, area.Height, area.X, area.Y); + + // Generate an expose for the area exposed by the horizontal scroll + if (XAmount > 0) { + hwnd.AddInvalidArea (area.X, area.Y, XAmount, area.Height); + } else if (XAmount < 0) { + hwnd.AddInvalidArea (XAmount + area.X + area.Width, area.Y, -XAmount, area.Height); + } + + // Generate an expose for the area exposed by the vertical scroll + if (YAmount > 0) { + hwnd.AddInvalidArea (area.X, area.Y, area.Width, YAmount); + } else if (YAmount < 0) { + hwnd.AddInvalidArea (area.X, YAmount + area.Y + area.Height, area.Width, -YAmount); + } + XFreeGC(DisplayHandle, gc); + + UpdateWindow(handle); + } + + internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow(handle); + + ScrollWindow(handle, hwnd.ClientRect, XAmount, YAmount, with_children); + } + + internal override void SendAsyncMethod (AsyncMethodData method) { + XEvent xevent = new XEvent (); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + xevent.ClientMessageEvent.window = FosterParent; + xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method); + + MessageQueue.EnqueueLocked (xevent); + + WakeupMain (); + } + + internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) { + return NativeWindow.WndProc(hwnd, message, wParam, lParam); + } + + internal override void SetAllowDrop (IntPtr handle, bool value) + { + // We allow drop on all windows + } + + internal override DragDropEffects StartDrag (IntPtr handle, object data, + DragDropEffects allowed_effects) + { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ")."); + + return Dnd.StartDrag (hwnd.client_window, data, allowed_effects); + } + + internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + hwnd.border_style = border_style; + + XMoveResizeWindow(DisplayHandle, hwnd.client_window, hwnd.ClientRect.X, hwnd.ClientRect.Y, hwnd.ClientRect.Width, hwnd.ClientRect.Height); + + InvalidateWholeWindow(handle); + } + + internal override void SetCaretPos(IntPtr handle, int x, int y) { + if (Caret.Hwnd == handle) { + Caret.Timer.Stop(); + HideCaret(); + + Caret.X = x; + Caret.Y = y; + + if (Caret.Visible == 1) { + ShowCaret(); + Caret.Timer.Start(); + } + } + } + + internal override void SetCursor(IntPtr handle, IntPtr cursor) { + Hwnd hwnd; + + if (OverrideCursorHandle == IntPtr.Zero) { + if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) { + return; + } + + LastCursorHandle = cursor; + LastCursorWindow = handle; + + hwnd = Hwnd.ObjectFromHandle(handle); + lock (XlibLock) { + if (cursor != IntPtr.Zero) { + XDefineCursor(DisplayHandle, hwnd.whole_window, cursor); + } else { + XUndefineCursor(DisplayHandle, hwnd.whole_window); + } + } + return; + } + + hwnd = Hwnd.ObjectFromHandle(handle); + lock (XlibLock) { + XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle); + } + } + + internal override void SetCursorPos(IntPtr handle, int x, int y) { + if (handle == IntPtr.Zero) { + lock (XlibLock) { + XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x, y); + } + return; + } else { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + lock (XlibLock) { + XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y); + } + return; + } + } + + internal override void SetFocus(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (FocusWindow != IntPtr.Zero) { + PostMessage(FocusWindow, Msg.WM_KILLFOCUS, hwnd.client_window, IntPtr.Zero); + } + PostMessage(hwnd.client_window, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero); + FocusWindow = hwnd.client_window; + + //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero); + } + + internal override void SetIcon(IntPtr handle, Icon icon) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null) { + SetIcon(hwnd, icon); + } + } + + internal override void SetMenu(IntPtr handle, Menu menu) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.menu = menu; + + // FIXME - do we need to trigger some resize? + } + + internal override void SetModal(IntPtr handle, bool Modal) { + if (Modal) { + ModalWindows.Push(handle); + } else { + if (ModalWindows.Contains(handle)) { + ModalWindows.Pop(); + } + if (ModalWindows.Count > 0) { + Activate((IntPtr)ModalWindows.Peek()); + } + } + } + + internal override IntPtr SetParent(IntPtr handle, IntPtr parent) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.parent = Hwnd.ObjectFromHandle(parent); + + lock (XlibLock) { + #if DriverDebug + Console.WriteLine("Parent for window {0:X} / {1:X} = {2:X} (Handle:{3:X})", hwnd.ClientWindow.ToInt32(), hwnd.WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0, parent.ToInt32()); + #endif + XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent.client_window, hwnd.x, hwnd.y); + } + + return IntPtr.Zero; + } + + internal override void SetTimer (Timer timer) { + lock (TimerList) { + TimerList.Add(timer); + } + WakeupMain (); + } + + internal override bool SetTopmost(IntPtr handle, IntPtr handle_owner, bool enabled) { + Hwnd hwnd; + Hwnd hwnd_owner; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (handle_owner != IntPtr.Zero) { + hwnd_owner = Hwnd.ObjectFromHandle(handle_owner); + } else { + hwnd_owner = null; + } + + if (enabled) { + lock (XlibLock) { + if (hwnd_owner != null) { + XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window); + } else { + XSetTransientForHint(DisplayHandle, hwnd.whole_window, FosterParent); + } + } + } else { + lock (XlibLock) { + XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR); + } + } + return true; + } + + internal override bool SetVisible(IntPtr handle, bool visible) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.visible = visible; + + lock (XlibLock) { + if (visible) { + if (Control.FromHandle(handle) is Form) { + FormWindowState s; + + s = ((Form)Control.FromHandle(handle)).WindowState; + + XMapWindow(DisplayHandle, hwnd.whole_window); + XMapWindow(DisplayHandle, hwnd.client_window); + + switch(s) { + case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break; + case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break; + } + } else { + XMapWindow(DisplayHandle, hwnd.whole_window); + XMapWindow(DisplayHandle, hwnd.client_window); + } + } else { + XUnmapWindow(DisplayHandle, hwnd.whole_window); + } + } + return true; + } + + internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) { + Hwnd hwnd; + XSizeHints hints; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd == null) { + return; + } + + hints = new XSizeHints(); + + if (min != Size.Empty) { + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize); + hints.min_width = min.Width; + hints.min_height = min.Height; + } + + if (max != Size.Empty) { + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize); + hints.max_width = max.Width; + hints.max_height = max.Height; + } + + XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints); + + if (maximized != Rectangle.Empty) { + hints.flags = (IntPtr)XSizeHintsFlags.PPosition; + hints.x = maximized.X; + hints.y = maximized.Y; + hints.width = maximized.Width; + hints.height = maximized.Height; + + // Metacity does not seem to follow this constraint for maximized (zoomed) windows + XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints); + } + } + + + internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) { + Hwnd hwnd; + Rectangle client_rect; + + hwnd = Hwnd.ObjectFromHandle(handle); + + // X requires a sanity check for width & height; otherwise it dies + if (hwnd.zero_sized && width > 0 && height > 0) { + if (hwnd.visible) { + XMapWindow(DisplayHandle, hwnd.whole_window); + } + hwnd.zero_sized = false; + } + + if (width < 1) { + hwnd.zero_sized = true; + XUnmapWindow(DisplayHandle, hwnd.whole_window); + } + + if (height < 1) { + hwnd.zero_sized = true; + XUnmapWindow(DisplayHandle, hwnd.whole_window); + } + + client_rect = Hwnd.GetClientRectangle(hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height); + + // Save a server roundtrip (and prevent a feedback loop) + if ((hwnd.x == x) && (hwnd.y == y) && + (hwnd.width == width) && (hwnd.height == height) && + (hwnd.ClientRect == client_rect)) { + return; + } + + if (!hwnd.zero_sized) { + lock (XlibLock) { + XMoveResizeWindow(DisplayHandle, hwnd.whole_window, x, y, width, height); + XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height); + } + } + + // Prevent an old queued ConfigureNotify from setting our width with outdated data, set it now + hwnd.width = width; + hwnd.height = height; + } + + internal override void SetWindowState(IntPtr handle, FormWindowState state) { + FormWindowState current_state; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + current_state = GetWindowState(handle); + + if (current_state == state) { + return; + } + + switch(state) { + case FormWindowState.Normal: { + lock (XlibLock) { + if (current_state == FormWindowState.Minimized) { + XMapWindow(DisplayHandle, hwnd.whole_window); + XMapWindow(DisplayHandle, hwnd.client_window); + } else if (current_state == FormWindowState.Maximized) { + SendNetWMMessage(hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT]); + } + } + Activate(handle); + return; + } + + case FormWindowState.Minimized: { + lock (XlibLock) { + if (current_state == FormWindowState.Maximized) { + SendNetWMMessage(hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT]); + } + XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo); + } + return; + } + + case FormWindowState.Maximized: { + lock (XlibLock) { + if (current_state == FormWindowState.Minimized) { + XMapWindow(DisplayHandle, hwnd.whole_window); + XMapWindow(DisplayHandle, hwnd.client_window); + } + + SendNetWMMessage(hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], (IntPtr)1 /* Add */, NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT]); + } + Activate(handle); + return; + } + } + } + + internal override void SetWindowStyle(IntPtr handle, CreateParams cp) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + SetHwndStyles(hwnd, cp); + SetWMStyles(hwnd, cp); + } + + internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) { + Hwnd hwnd; + uint opacity; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + hwnd.opacity = (uint)(0xffffffff * transparency); + opacity = hwnd.opacity; + + if (hwnd.reparented) { + XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), NetAtoms[(int)NA._NET_WM_WINDOW_OPACITY], (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1); + } + } + + internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) { + Hwnd hwnd = Hwnd.ObjectFromHandle(handle); + + if (top) { + lock (XlibLock) { + XRaiseWindow(DisplayHandle, hwnd.whole_window); + } + return true; + } else if (!bottom) { + Hwnd after_hwnd = null; + + if (after_handle != IntPtr.Zero) { + after_hwnd = Hwnd.ObjectFromHandle(after_handle); + } + + XWindowChanges values = new XWindowChanges(); + + if (after_hwnd == null) { + throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order"); + } + values.sibling = after_hwnd.whole_window; + values.stack_mode = StackMode.Below; + + lock (XlibLock) { + XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values); + } + } else { + // Bottom + lock (XlibLock) { + XLowerWindow(DisplayHandle, hwnd.whole_window); + } + return true; + } + return false; + } + + internal override void ShowCursor(bool show) { + ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor + } + + internal override void StartLoop(Thread thread) { + // Future place for prepping a new queue for this specific thread + } + + internal override bool SupportsTransparency() { + // We need to check if the x compositing manager is running + return true; + } + + internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) { + GetSystrayManagerWindow(); + + if (SystrayMgrWindow != IntPtr.Zero) { + XSizeHints size_hints; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + #if DriverDebug + Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32()); + #endif + + XUnmapWindow(DisplayHandle, hwnd.whole_window); + XUnmapWindow(DisplayHandle, hwnd.client_window); + + // Oh boy. + XDestroyWindow(DisplayHandle, hwnd.client_window); + hwnd.client_window = hwnd.whole_window; + + size_hints = new XSizeHints(); + + size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize); + size_hints.min_width = icon.Width; + size_hints.min_height = icon.Height; + + size_hints.max_width = icon.Width; + size_hints.max_height = icon.Height; + + size_hints.base_width = icon.Width; + size_hints.base_height = icon.Height; + XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints); + + int[] atoms = new int[2]; + atoms [0] = 1; // Version 1 + atoms [1] = 0; // We're not mapped + + // This line cost me 3 days... + XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._XEMBED_INFO], NetAtoms[(int)NA._XEMBED_INFO], 32, PropertyMode.Replace, atoms, 2); + + // Need to pick some reasonable defaults + tt = new ToolTip(); + tt.AutomaticDelay = 100; + tt.InitialDelay = 250; + tt.ReshowDelay = 250; + tt.ShowAlways = true; + + if ((tip != null) && (tip != string.Empty)) { + tt.SetToolTip(Control.FromHandle(handle), tip); + tt.Active = true; + } else { + tt.Active = false; + } + + // Make sure the window exists + XSync(DisplayHandle, hwnd.whole_window); + + SendNetClientMessage(SystrayMgrWindow, NetAtoms[(int)NA._NET_SYSTEM_TRAY_OPCODE], IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window); + return true; + } + tt = null; + return false; + } + + internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) { + Control control; + + control = Control.FromHandle(handle); + if (control != null && tt != null) { + tt.SetToolTip(control, tip); + tt.Active = true; + return true; + } else { + return false; + } + } + + internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + XUnmapWindow(DisplayHandle, hwnd.whole_window); + SetParent(hwnd.whole_window, FosterParent); + + // The caller can now re-dock it later... + if (tt != null) { + tt.Dispose(); + tt = null; + } + } + + internal override bool Text(IntPtr handle, string text) { + lock (XlibLock) { + // FIXME - use _NET properties + XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text); + } + return true; + } + + internal override bool TranslateMessage(ref MSG msg) { + return Keyboard.TranslateMessage (ref msg); + } + + internal override void UpdateWindow(IntPtr handle) { + XEvent xevent; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (!hwnd.visible || hwnd.expose_pending) { + return; + } + +#if not + SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); +#else + xevent = new XEvent(); + xevent.type = XEventName.Expose; + xevent.ExposeEvent.display = DisplayHandle; + xevent.ExposeEvent.window = hwnd.client_window; + + MessageQueue.Enqueue(xevent); + hwnd.expose_pending = true; +#endif + } + #endregion // Public Static Methods + + #region Events + internal override event EventHandler Idle; + #endregion // Events + + #region X11 Imports + [DllImport ("libX11", EntryPoint="XOpenDisplay")] + internal extern static IntPtr XOpenDisplay(IntPtr display); + [DllImport ("libX11", EntryPoint="XCloseDisplay")] + internal extern static int XCloseDisplay(IntPtr display); + [DllImport ("libX11", EntryPoint="XSynchronize")] + internal extern static IntPtr XSynchronize(IntPtr display, bool onoff); + + [DllImport ("libX11", EntryPoint="XCreateWindow")] + internal extern static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes); + [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")] + internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background); + [DllImport ("libX11", EntryPoint="XMapWindow")] + internal extern static int XMapWindow(IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XUnmapWindow")] + internal extern static int XUnmapWindow(IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XMapSubwindows")] + internal extern static int XMapSubindows(IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XUnmapSubwindows")] + internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XRootWindow")] + internal extern static IntPtr XRootWindow(IntPtr display, int screen_number); + [DllImport ("libX11", EntryPoint="XNextEvent")] + internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent); + [DllImport ("libX11")] + internal extern static int XConnectionNumber (IntPtr diplay); + [DllImport ("libX11")] + internal extern static int XPending (IntPtr diplay); + [DllImport ("libX11", EntryPoint="XSelectInput")] + internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask); + + [DllImport ("libX11", EntryPoint="XDestroyWindow")] + internal extern static int XDestroyWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XReparentWindow")] + internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y); + [DllImport ("libX11", EntryPoint="XMoveResizeWindow")] + internal extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height); + + [DllImport ("libX11", EntryPoint="XResizeWindow")] + internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height); + + [DllImport ("libX11", EntryPoint="XGetWindowAttributes")] + internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes); + + [DllImport ("libX11", EntryPoint="XFlush")] + internal extern static int XFlush(IntPtr display); + + [DllImport ("libX11", EntryPoint="XSetWMName")] + internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop); + + [DllImport ("libX11", EntryPoint="XStoreName")] + internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name); + + [DllImport ("libX11", EntryPoint="XFetchName")] + internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name); + + [DllImport ("libX11", EntryPoint="XSendEvent")] + internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event); + + [DllImport ("libX11", EntryPoint="XQueryTree")] + internal extern static int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return); + + [DllImport ("libX11", EntryPoint="XFree")] + internal extern static int XFree(IntPtr data); + + [DllImport ("libX11", EntryPoint="XRaiseWindow")] + internal extern static int XRaiseWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XLowerWindow")] + internal extern static uint XLowerWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XConfigureWindow")] + internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values); + + [DllImport ("libX11", EntryPoint="XInternAtom")] + internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists); + + [DllImport ("libX11", EntryPoint="XSetWMProtocols")] + internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count); + + [DllImport ("libX11", 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, IntPtr cursor, IntPtr timestamp); + + [DllImport ("libX11", EntryPoint="XUngrabPointer")] + internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp); + + [DllImport ("libX11", 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", 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", 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", EntryPoint="XGetGeometry")] + internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth); + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport ("libX11", 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", EntryPoint="XClearWindow")] + internal extern static int XClearWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XClearArea")] + internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures); + + // Colormaps + [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")] + internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display); + + [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")] + internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen); + + [DllImport ("libX11", EntryPoint="XDefaultVisual")] + internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefaultDepth")] + internal extern static uint XDefaultDepth(IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefaultScreen")] + internal extern static int XDefaultScreen(IntPtr display); + + [DllImport ("libX11", EntryPoint="XDefaultColormap")] + internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XLookupColor")] + internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color); + + [DllImport ("libX11", EntryPoint="XAllocColor")] + internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def); + + [DllImport ("libX11", EntryPoint="XSetTransientForHint")] + internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length); + + [DllImport ("libX11", EntryPoint="XDeleteProperty")] + internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property); + + [DllImport ("gdiplus", EntryPoint="GetFontMetrics")] + internal extern static bool GetFontMetrics(IntPtr graphicsObject, IntPtr nativeObject, out int ascent, out int descent); + + // Drawing + [DllImport ("libX11", EntryPoint="XCreateGC")] + internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values); + + [DllImport ("libX11", EntryPoint="XFreeGC")] + internal extern static int XFreeGC(IntPtr display, IntPtr gc); + + [DllImport ("libX11", EntryPoint="XSetFunction")] + internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function); + + [DllImport ("libX11", EntryPoint="XDrawLine")] + internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2); + + [DllImport ("libX11", EntryPoint="XDrawRectangle")] + internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + + [DllImport ("libX11", EntryPoint="XSetWindowBackground")] + internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background); + + [DllImport ("libX11", EntryPoint="XCopyArea")] + internal extern static int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y); + + [DllImport ("libX11", EntryPoint="XGetWindowProperty")] + internal extern static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop); + + [DllImport ("libX11", EntryPoint="XSetInputFocus")] + internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time); + + [DllImport ("libX11", EntryPoint="XIconifyWindow")] + internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefineCursor")] + internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor); + + [DllImport ("libX11", EntryPoint="XUndefineCursor")] + internal extern static int XUndefineCursor(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XFreeCursor")] + internal extern static int XFreeCursor(IntPtr display, IntPtr cursor); + + [DllImport ("libX11", EntryPoint="XCreateFontCursor")] + internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape); + + [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")] + internal extern static IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot); + + [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")] + internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth); + + [DllImport ("libX11", EntryPoint="XFreePixmap")] + internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap); + + [DllImport ("libX11", EntryPoint="XQueryBestCursor")] + internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height); + + [DllImport ("libX11", EntryPoint="XWhitePixel")] + internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no); + + [DllImport ("libX11", EntryPoint="XBlackPixel")] + internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no); + + [DllImport ("libX11", EntryPoint="XGrabServer")] + internal extern static void XGrabServer(IntPtr display); + + [DllImport ("libX11", EntryPoint="XUngrabServer")] + internal extern static void XUngrabServer(IntPtr display); + + [DllImport ("libX11", EntryPoint="XSetWMNormalHints")] + internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport ("libX11", EntryPoint="XSetZoomHints")] + internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport ("libX11", EntryPoint="XSetWMHints")] + internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints); + + [DllImport ("libX11", EntryPoint="XSync")] + internal extern static void XSync(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XGetIconSizes")] + internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count); + + [DllImport ("libX11", EntryPoint="XSetErrorHandler")] + internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler); + + [DllImport ("libX11", EntryPoint="XGetErrorText")] + internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length); + + [DllImport ("libX11", EntryPoint="XInitThreads")] + internal extern static int XInitThreads(); + + [DllImport ("libX11", EntryPoint="XConvertSelection")] + internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time); + + [DllImport ("libX11", EntryPoint="XGetSelectionOwner")] + internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection); + + [DllImport ("libX11", EntryPoint="XSetSelectionOwner")] + internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time); + + [DllImport ("libX11", EntryPoint="XSetPlaneMask")] + internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask); + + [DllImport ("libX11", EntryPoint="XSetForeground")] + internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground); + + [DllImport ("libX11", EntryPoint="XSetBackground")] + internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background); + + [DllImport ("libX11", EntryPoint="XBell")] + internal extern static int XBell(IntPtr display, int percent); + + [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")] + internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time); + #endregion + } +} |