Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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.cs4226
1 files changed, 4226 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..d655d87b345
--- /dev/null
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs
@@ -0,0 +1,4226 @@
+// 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 N = 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 int PostAtom; // PostMessage atom
+ private static int 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 int[] 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 = 0;
+ RootWindow = XRootWindow(DisplayHandle, ScreenNo);
+ DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
+
+ // Create the foster parent
+ FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 4, 0, 0);
+ 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, 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 int[(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._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] = (int)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, 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, 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_OVERLAPPEDWINDOW) == 0) {
+ if ((Style & (int) WindowStyles.WS_BORDER) != 0) {
+ border_style = FormBorderStyle.FixedSingle;
+ } else if ((ExStyle & (int) WindowStyles.WS_EX_CLIENTEDGE) != 0) {
+ border_style = FormBorderStyle.Fixed3D;
+ } else {
+ border_style = FormBorderStyle.None;
+ }
+ title_style = TitleStyle.None;
+ } else {
+ bool is_mdi = false;
+
+ if ((ExStyle & (int) WindowStyles.WS_EX_MDICHILD) != 0) {
+ caption_height = 26;
+ is_mdi = true;
+ }
+
+ 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;
+ }
+ }
+
+ if (!is_mdi) {
+ border_style = FormBorderStyle.None;
+ if ((ExStyle & (int)WindowStyles.WS_EX_WINDOWEDGE) != 0) {
+ if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
+ if ((Style & (int)WindowStyles.WS_THICKFRAME) != 0) {
+ border_style = FormBorderStyle.SizableToolWindow;
+ } else {
+ border_style = FormBorderStyle.FixedToolWindow;
+ }
+ } else if ((ExStyle & (int)WindowStyles.WS_EX_DLGMODALFRAME) != 0) {
+ border_style = FormBorderStyle.FixedDialog;
+ } else if ((ExStyle & (int)WindowStyles.WS_THICKFRAME) != 0) {
+ border_style = FormBorderStyle.Sizable;
+ } else {
+ border_style = FormBorderStyle.FixedSingle;
+ }
+ } else {
+ border_style = FormBorderStyle.Fixed3D;
+ }
+ } else {
+ if ((Style & (int) WindowStyles.WS_OVERLAPPEDWINDOW) != 0 ||
+ (ExStyle & (int) WindowStyles.WS_EX_TOOLWINDOW) != 0)
+ border_style = (FormBorderStyle) 0xFFFF;
+ 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;
+ uint[] atoms;
+ 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;
+ }
+
+ 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);
+
+ atoms = new uint[8];
+ atom_count = 0;
+
+ if ((cp.ExStyle & ((int)WindowStyles.WS_EX_TOOLWINDOW)) != 0) {
+ atoms[atom_count++] = (uint)NetAtoms[(int)NA._NET_WM_STATE_NO_TASKBAR];
+ }
+
+ XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
+
+ atom_count = 0;
+ atoms[atom_count++] = (uint)NetAtoms[(int)NA.WM_DELETE_WINDOW];
+ if ((cp.ExStyle & (int)WindowStyles.WS_EX_CONTEXTHELP) != 0) {
+ atoms[atom_count++] = (uint)NetAtoms[(int)NA._NET_WM_CONTEXT_HELP];
+ }
+
+ XSetWMProtocols(DisplayHandle, hwnd.whole_window, atoms, 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], 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(int property) {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+
+ Clipboard.Item = null;
+
+ XGetWindowProperty(DisplayHandle, FosterParent, property, 0, 0x7fffffff, true, Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+
+ if (nitems > 0) {
+ if (property == (int)Atom.XA_STRING) {
+ Clipboard.Item = Marshal.PtrToStringAnsi(prop);
+ } else if (property == (int)Atom.XA_BITMAP) {
+ // FIXME - convert bitmap to image
+ } else if (property == (int)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 || !hwnd.visible) { // Can'd check visible; we might loose expose for whole_windows
+ 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 {
+ 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 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 {
+ int dummy_int;
+ IntPtr dummy_ptr;
+
+ XGetGeometry(DisplayHandle, XGetParent(hwnd.whole_window), out dummy_ptr, out hwnd.x, out hwnd.y, out dummy_int, out dummy_int, out dummy_int, out dummy_int);
+ }
+
+ 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 = 0;
+
+ // Seems that some apps support asking for supported types
+ if (xevent.SelectionEvent.target == NetAtoms[(int)NA.TARGETS]) {
+ uint[] atoms;
+ int atom_count;
+
+ atoms = new uint[5];
+ atom_count = 0;
+
+ if (Clipboard.Item is String) {
+ atoms[atom_count++] = (uint)Atom.XA_STRING;
+ atoms[atom_count++] = (uint)NetAtoms[(int)NA.OEMTEXT];
+ atoms[atom_count++] = (uint)NetAtoms[(int)NA.UNICODETEXT];
+ } else if (Clipboard.Item is Image) {
+ atoms[atom_count++] = (uint)Atom.XA_PIXMAP;
+ atoms[atom_count++] = (uint)Atom.XA_BITMAP;
+ } else {
+ // FIXME - handle other types
+ }
+
+ XChangeProperty(DisplayHandle, xevent.SelectionEvent.requestor, xevent.SelectionRequestEvent.property, 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 == (int)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, xevent.SelectionRequestEvent.property, 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 == (int)Atom.XA_PIXMAP) {
+ // FIXME - convert image and store as property
+ } else if (xevent.SelectionEvent.target == (int)Atom.XA_PIXMAP) {
+ // FIXME - convert image and store as property
+ }
+ }
+
+ XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, EventMask.NoEventMask, ref sel_event);
+ break;
+ }
+
+ case XEventName.SelectionNotify: {
+ if (Clipboard.Enumerating) {
+ Clipboard.Enumerating = false;
+ if (xevent.SelectionEvent.property != 0) {
+ XDeleteProperty(DisplayHandle, FosterParent, 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 != 0) {
+ 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]) {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr prev_active;;
+
+ prev_active = ActiveWindow;
+ XGetWindowProperty(DisplayHandle, RootWindow, NetAtoms[(int)NA._NET_ACTIVE_WINDOW], 0, 1, false, Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((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++) {
+ hwnd = Hwnd.ObjectFromHandle(controls[i].Handle);
+
+ if (hwnd != null) {
+ hwnd.destroy_pending = true;
+ }
+ 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 = (IntPtr)HoverState.Window;
+ xevent.ClientMessageEvent.message_type = (IntPtr)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 25;
+ }
+ }
+
+ 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 {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ int width;
+ int height;
+
+ XGetWindowProperty(DisplayHandle, RootWindow, NetAtoms[(int)NA._NET_DESKTOP_GEOMETRY], 0, 256, false, Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((nitems == 2) && (prop != IntPtr.Zero)) {
+ 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, (IntPtr)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], f.Id, 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);
+ 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);
+ //else if (format == "EnhancedMetafile" ) return 14;
+ //else if (format == "FileDrop" ) return 15;
+ //else if (format == "Locale" ) return 16;
+
+ return XInternAtom(DisplayHandle, format, false);
+ }
+
+ internal override IntPtr ClipboardOpen() {
+ return ClipMagic;
+ }
+
+ internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) {
+ XConvertSelection(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], type, 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, 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, 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, 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, SelectInputMask);
+ XSelectInput(DisplayHandle, hwnd.client_window, SelectInputMask);
+
+ if ((cp.Style & (int)WindowStyles.WS_VISIBLE) != 0) {
+ XMapWindow(DisplayHandle, hwnd.whole_window);
+ XMapWindow(DisplayHandle, hwnd.client_window);
+ hwnd.visible = true;
+ }
+ }
+
+ SetWMStyles(hwnd, cp);
+
+ // 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) {
+ 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);
+ }
+
+ // The window is a goner, don't send it stuff like WM_PAINT anymore
+ hwnd.destroy_pending = true;
+
+ // Mark our children as gone as well
+ DestroyChildWindow(Control.ControlNativeWindow.ControlFromHandle(handle));
+
+ 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);
+ }
+ }
+ }
+
+ 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, 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, 0xffffffff);
+ XSetBackground(DisplayHandle, gc, background);
+ XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
+ XSetPlaneMask(DisplayHandle, gc, 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() {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr active = IntPtr.Zero;
+
+ XGetWindowProperty(DisplayHandle, RootWindow, NetAtoms[(int)NA._NET_ACTIVE_WINDOW], 0, 1, false, Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((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 Graphics GetMenuDC(IntPtr handle, IntPtr ncpaint_region) {
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ return Graphics.FromHwnd(hwnd.whole_window);
+ }
+
+ 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 || hwnd.destroy_pending) {
+ // We need to let the DestroyNotify go through so that the owning control can learn about it, too
+ if (hwnd == null || xevent.type != XEventName.DestroyNotify) {
+ #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 {
+ #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;
+ 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);
+ }
+
+ #if notyet
+ // Not sure we need this...
+ HitTest ht;
+ ht = NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam);
+ #endif
+
+ 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) {
+ // We need to adjust x/y
+ int dummy_int;
+ IntPtr dummy_ptr;
+
+ hwnd.Reparented = true;
+
+ XGetGeometry(DisplayHandle, XGetParent(hwnd.whole_window), out dummy_ptr, out hwnd.x, out hwnd.y, out dummy_int, out dummy_int, out dummy_int, out dummy_int);
+ 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], 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 == (IntPtr)AsyncAtom) {
+ XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
+ break;
+ }
+
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)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 == (IntPtr)NetAtoms[(int)NA._XEMBED]) {
+ Console.WriteLine("GOT EMBED MESSAGE {0:X}", xevent.ClientMessageEvent.ptr2.ToInt32());
+ break;
+ }
+ #endif
+
+ if (xevent.ClientMessageEvent.message_type == (IntPtr)NetAtoms[(int)NA.WM_PROTOCOLS]) {
+ if (xevent.ClientMessageEvent.ptr1 == (IntPtr)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 == (IntPtr)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) {
+ Atom actual_atom;
+ int actual_format;
+ int nitems;
+ int bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ IntPtr atom;
+ int maximized;
+ XWindowAttributes attributes;
+ Hwnd hwnd;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ maximized = 0;
+ XGetWindowProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], 0, 256, false, Atom.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
+ if ((nitems > 0) && (prop != IntPtr.Zero)) {
+ for (int i = 0; i < nitems; i++) {
+ atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
+ if ((atom == (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ]) || (atom == (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT])) {
+ maximized++;
+ }
+ }
+ XFree(prop);
+ }
+
+ if (maximized == 2) {
+ return FormWindowState.Maximized;
+ }
+
+
+ attributes = new XWindowAttributes();
+ XGetWindowAttributes(DisplayHandle, handle, ref attributes);
+ if (attributes.map_state == MapState.IsUnmapped) {
+ return FormWindowState.Minimized;
+ }
+
+ 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, 0, 0);
+ }
+ }
+
+ internal override void UngrabWindow(IntPtr hwnd) {
+ lock (XlibLock) {
+ XUngrabPointer(DisplayHandle, 0);
+ 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.client_dc = Graphics.FromHwnd (hwnd.whole_window);
+ paint_event = new PaintEventArgs(hwnd.client_dc, new Rectangle(0, 0, hwnd.width, hwnd.height));
+ 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;
+
+ 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 ReleaseMenuDC(IntPtr handle, Graphics dc) {
+ dc.Dispose();
+ }
+
+ 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, 0, 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, (int)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) {
+ XMapWindow(DisplayHandle, hwnd.whole_window);
+ XMapWindow(DisplayHandle, hwnd.client_window);
+ } else {
+ XUnmapWindow(DisplayHandle, hwnd.whole_window);
+ }
+ }
+ return true;
+ }
+
+ 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, (IntPtr)(uint)NetAtoms[(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)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, (IntPtr)NetAtoms[(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT]);
+ }
+ XIconifyWindow(DisplayHandle, hwnd.whole_window, 0);
+ }
+ 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, (IntPtr)NetAtoms[(int)NA._NET_WM_STATE], (IntPtr)1 /* Add */, (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)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], 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) {
+ uint[] atoms;
+ 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);
+
+ atoms = new uint[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, (IntPtr)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) {
+ if (!hwnd.visible || hwnd.destroy_pending) {
+ return;
+ }
+
+ SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+#if not
+#if true
+ xevent = new XEvent();
+ xevent.type = XEventName.Expose;
+ xevent.ExposeEvent.display = DisplayHandle;
+ xevent.ExposeEvent.window = hwnd.client_window;
+
+ MessageQueue.Enqueue(xevent);
+ hwnd.expose_pending = true;
+#else
+ // This would force an immediate paint (SendMessage, instead of PostMessage)
+ if (!hwnd.visible) {
+ return;
+ }
+
+ if (!hwnd.expose_pending) {
+ xevent = new XEvent();
+ xevent.type = XEventName.Expose;
+ xevent.ExposeEvent.display = DisplayHandle;
+ xevent.ExposeEvent.window = hwnd.client_window;
+
+ MessageQueue.Enqueue(xevent);
+ hwnd.expose_pending = true;
+ }
+ NativeWindow.WndProc(hwnd.client_window, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
+#endif
+#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, SetWindowValuemask 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, int border, int 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")]
+ internal extern static bool XCheckWindowEvent (IntPtr display, IntPtr window, EventMask mask, ref XEvent xevent);
+ [DllImport ("libX11")]
+ internal extern static bool XCheckMaskEvent (IntPtr display, EventMask mask, ref XEvent xevent);
+ [DllImport ("libX11", EntryPoint="XSelectInput")]
+ internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, EventMask 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, EventMask 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 int XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
+
+ [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
+ internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, uint[] 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, uint cursor, uint timestamp);
+
+ [DllImport ("libX11", EntryPoint="XUngrabPointer")]
+ internal extern static int XUngrabPointer(IntPtr display, uint 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="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, int property, int type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, uint[] atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, ref uint value, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, uint[] atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, IntPtr atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty")]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, IntPtr atoms, int nelements);
+
+ [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
+ internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, int type, int format, PropertyMode mode, string text, int text_length);
+
+ [DllImport ("libX11", EntryPoint="XDeleteProperty")]
+ internal extern static int XDeleteProperty(IntPtr display, IntPtr window, int 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, GCFunction 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="XGetAtomName")]
+ internal extern static string XGetAtomName(IntPtr display, int atom);
+
+ [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
+ internal extern static int XGetWindowProperty(IntPtr display, IntPtr window, int atom, int long_offset, int long_length, bool delete, Atom req_type, out Atom actual_type, out int actual_format, out int nitems, out int 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="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, int selection, int target, int property, IntPtr requestor, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
+ internal extern static IntPtr XGetSelectionOwner(IntPtr display, int selection);
+
+ [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
+ internal extern static int XSetSelectionOwner(IntPtr display, int selection, IntPtr owner, IntPtr time);
+
+ [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
+ internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, uint mask);
+
+ [DllImport ("libX11", EntryPoint="XSetForeground")]
+ internal extern static int XSetForeground(IntPtr display, IntPtr gc, uint foreground);
+
+ [DllImport ("libX11", EntryPoint="XSetBackground")]
+ internal extern static int XSetBackground(IntPtr display, IntPtr gc, uint background);
+
+ [DllImport ("libX11", EntryPoint="XBell")]
+ internal extern static int XBell(IntPtr display, int percent);
+ #endregion
+ }
+}