1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2006 Novell, Inc.
23 // Peter Bartok pbartok@novell.com
28 // This driver understands the following environment variables: (Set the var to enable feature)
30 // MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered;
31 // by default a message is displayed but execution continues
33 // MONO_XSYNC = perform all X11 commands synchronous; this is slower but
34 // helps in debugging errors
39 // define to log Window handles and relationships to stdout
42 // Extra detailed debug
43 #undef DriverDebugExtra
46 using System.ComponentModel;
47 using System.Collections;
48 using System.Diagnostics;
50 using System.Drawing.Drawing2D;
51 using System.Drawing.Imaging;
55 using System.Net.Sockets;
56 using System.Reflection;
57 using System.Runtime.InteropServices;
59 using System.Threading;
61 // Only do the poll when building with mono for now
63 using Mono.Unix.Native;
67 namespace System.Windows.Forms {
68 internal class XplatUIX11 : XplatUIDriver {
69 #region Local Variables
71 static volatile XplatUIX11 Instance;
72 private static int RefCount;
73 private static object XlibLock; // Our locking object
74 private static bool ThemesEnabled;
77 private static IntPtr DisplayHandle; // X11 handle to display
78 private static int ScreenNo; // Screen number used
79 private static IntPtr DefaultColormap; // Colormap for screen
80 private static IntPtr CustomVisual; // Visual for window creation
81 private static IntPtr CustomColormap; // Colormap for window creation
82 private static IntPtr RootWindow; // Handle of the root window for the screen/display
83 private static IntPtr FosterParent; // Container to hold child windows until their parent exists
84 private static XErrorHandler ErrorHandler; // Error handler delegate
85 private static bool ErrorExceptions; // Throw exceptions on X errors
86 private static bool PostQuitState; // True if we've got an pending exit
89 private static IntPtr ClipMagic = new IntPtr(27051977);
90 private static ClipboardStruct Clipboard; // Our clipboard
93 private static int PostAtom; // PostMessage atom
94 private static int AsyncAtom; // Support for async messages
97 private static XEventQueue MessageQueue; // Holds our queued up events
99 private static Pollfd[] pollfds; // For watching the X11 socket
101 private static X11Keyboard Keyboard; //
102 private static X11Dnd Dnd;
103 private static Socket listen; //
104 private static Socket wake; //
105 private static Socket wake_receive; //
106 private static byte[] network_buffer; //
110 private static IntPtr ActiveWindow; // Handle of the active window
111 private static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any)
114 private static Stack ModalWindows; // Stack of our modal windows
117 private static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window
120 private static IntPtr LastCursorWindow; // The last window we set the cursor on
121 private static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
122 private static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
125 private static CaretStruct Caret; //
127 // Support for Window Styles
128 private static int[] NetAtoms; // All atoms we know
130 // mouse hover message generation
131 private static HoverStruct HoverState; //
133 // double click message generation
134 private static ClickStruct ClickPending; //
136 // Support for mouse grab
137 private static GrabStruct Grab; //
140 private static Point MousePosition; // Last position of mouse, in screen coords
141 internal static MouseButtons MouseState; // Last state of mouse buttons
144 private static ArrayList TimerList; // Holds SWF.Timers
147 private static int DoubleClickInterval; // msec; max interval between clicks to count as double click
149 const EventMask SelectInputMask = EventMask.ButtonPressMask |
150 EventMask.ButtonReleaseMask |
151 EventMask.KeyPressMask |
152 EventMask.KeyReleaseMask |
153 EventMask.EnterWindowMask |
154 EventMask.LeaveWindowMask |
155 EventMask.ExposureMask |
156 EventMask.FocusChangeMask |
157 EventMask.PointerMotionMask |
158 EventMask.VisibilityChangeMask |
159 EventMask.SubstructureNotifyMask |
160 EventMask.StructureNotifyMask;
162 static readonly object lockobj = new object ();
164 #endregion // Local Variables
166 private XplatUIX11() {
167 // Handle singleton stuff first
170 // Now regular initialization
171 XlibLock = new object ();
172 MessageQueue = new XEventQueue ();
173 TimerList = new ArrayList ();
176 ErrorExceptions = false;
178 // X11 Initialization
179 SetDisplay(XOpenDisplay(IntPtr.Zero));
180 X11DesktopColors.Initialize();
182 // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does)
183 ErrorHandler = new XErrorHandler(HandleError);
184 XSetErrorHandler(ErrorHandler);
186 #endregion // Constructors
188 #region Singleton Specific Code
189 public static XplatUIX11 GetInstance() {
191 if (Instance == null) {
192 Instance=new XplatUIX11();
199 public int Reference {
206 #region Internal Properties
207 internal static IntPtr Display {
209 return DisplayHandle;
213 XplatUIX11.GetInstance().SetDisplay(value);
217 internal static int Screen {
227 internal static IntPtr RootWindowHandle {
237 internal static IntPtr Visual {
243 CustomVisual = value;
247 internal static IntPtr ColorMap {
249 return CustomColormap;
253 CustomColormap = value;
258 #region XExceptionClass
259 internal class XException : ApplicationException {
263 XRequest RequestCode;
267 public XException(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
268 this.Display = Display;
269 this.ResourceID = ResourceID;
270 this.Serial = Serial;
271 this.RequestCode = RequestCode;
272 this.ErrorCode = ErrorCode;
273 this.MinorCode = MinorCode;
276 public override string Message {
278 return GetMessage(Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode);
282 public static string GetMessage(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
287 sb = new StringBuilder(160);
288 XGetErrorText(Display, ErrorCode, sb, sb.Capacity);
289 x_error_text = sb.ToString();
291 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);
295 #endregion // XExceptionClass
297 #region Internal Methods
298 internal void SetDisplay(IntPtr display_handle) {
299 if (display_handle != IntPtr.Zero) {
302 if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) {
303 hwnd = Hwnd.ObjectFromHandle(FosterParent);
304 XDestroyWindow(DisplayHandle, FosterParent);
308 if (DisplayHandle != IntPtr.Zero) {
309 XCloseDisplay(DisplayHandle);
312 DisplayHandle=display_handle;
314 // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has
315 // been hacked to do this for us.
316 Graphics.FromHdcInternal (DisplayHandle);
319 if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
320 XSynchronize(DisplayHandle, true);
323 if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
324 ErrorExceptions = true;
329 RootWindow = XRootWindow(DisplayHandle, ScreenNo);
330 DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
332 // Create the foster parent
333 FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 4, 0, 0);
334 if (FosterParent==IntPtr.Zero) {
335 Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
339 hwnd.WholeWindow = FosterParent;
340 hwnd.ClientWindow = FosterParent;
342 // For sleeping on the X11 socket
343 listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
344 IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0);
348 // To wake up when a timer is ready
349 network_buffer = new byte[10];
351 wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
352 wake.Connect(listen.LocalEndPoint);
353 wake_receive = listen.Accept();
356 pollfds = new Pollfd [2];
357 pollfds [0] = new Pollfd ();
358 pollfds [0].fd = XConnectionNumber (DisplayHandle);
359 pollfds [0].events = PollEvents.POLLIN;
361 pollfds [1] = new Pollfd ();
362 pollfds [1].fd = wake_receive.Handle.ToInt32 ();
363 pollfds [1].events = PollEvents.POLLIN;
366 Keyboard = new X11Keyboard(DisplayHandle);
367 Dnd = new X11Dnd (DisplayHandle);
369 PostQuitState = false;
371 DoubleClickInterval = 500;
373 HoverState.Interval = 500;
374 HoverState.Timer = new Timer();
375 HoverState.Timer.Enabled = false;
376 HoverState.Timer.Interval = HoverState.Interval;
377 HoverState.Timer.Tick +=new EventHandler(MouseHover);
381 ActiveWindow = IntPtr.Zero;
382 FocusWindow = IntPtr.Zero;
383 ModalWindows = new Stack(3);
385 MouseState = MouseButtons.None;
386 MousePosition = new Point(0, 0);
388 Caret.Timer = new Timer();
389 Caret.Timer.Interval = 500; // FIXME - where should this number come from?
390 Caret.Timer.Tick += new EventHandler(CaretCallback);
394 // Grab atom changes off the root window to catch certain WM events
395 XSelectInput(DisplayHandle, RootWindow, EventMask.PropertyChangeMask);
397 // Handle any upcoming errors
398 ErrorHandler = new XErrorHandler(HandleError);
399 XSetErrorHandler(ErrorHandler);
401 throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check you DISPLAY environment variable)");
405 internal static void Where() {
406 Console.WriteLine("Here: {0}\n", WhereString());
409 internal static string WhereString() {
417 newline = String.Format("{0}\t {1} ", Environment.NewLine, Locale.GetText("at"));
418 unknown = Locale.GetText("<unknown method>");
419 sb = new StringBuilder();
420 stack = new StackTrace(true);
422 for (int i = 0; i < stack.FrameCount; i++) {
423 frame = stack.GetFrame(i);
426 method = frame.GetMethod();
427 if (method != null) {
429 sb.AppendFormat(frame.ToString());
431 if (frame.GetFileLineNumber() != 0) {
432 sb.AppendFormat("{0}.{1} () [{2}:{3}]", method.DeclaringType.FullName, method.Name, Path.GetFileName(frame.GetFileName()), frame.GetFileLineNumber());
434 sb.AppendFormat("{0}.{1} ()", method.DeclaringType.FullName, method.Name);
440 return sb.ToString();
442 #endregion // Internal Methods
444 #region Private Methods
445 private static void SetupAtoms() {
446 NetAtoms = new int[(int)NA.LAST_NET_ATOM];
448 NetAtoms[(int)NA.WM_PROTOCOLS] = XInternAtom(DisplayHandle, "WM_PROTOCOLS", false);
449 NetAtoms[(int)NA.WM_DELETE_WINDOW] = XInternAtom(DisplayHandle, "WM_DELETE_WINDOW", false);
450 NetAtoms[(int)NA.WM_TAKE_FOCUS] = XInternAtom(DisplayHandle, "WM_TAKE_FOCUS", false);
452 NetAtoms[(int)NA._NET_SUPPORTED] = XInternAtom(DisplayHandle, "_NET_SUPPORTED", false);
453 NetAtoms[(int)NA._NET_CLIENT_LIST] = XInternAtom(DisplayHandle, "_NET_CLIENT_LIST", false);
454 NetAtoms[(int)NA._NET_NUMBER_OF_DESKTOPS] = XInternAtom(DisplayHandle, "_NET_NUMBER_OF_DESKTOPS", false);
455 NetAtoms[(int)NA._NET_DESKTOP_GEOMETRY] = XInternAtom(DisplayHandle, "_NET_DESKTOP_GEOMETRY", false);
456 NetAtoms[(int)NA._NET_DESKTOP_VIEWPORT] = XInternAtom(DisplayHandle, "_NET_DESKTOP_VIEWPORT", false);
457 NetAtoms[(int)NA._NET_CURRENT_DESKTOP] = XInternAtom(DisplayHandle, "_NET_CURRENT_DESKTOP", false);
458 NetAtoms[(int)NA._NET_DESKTOP_NAMES] = XInternAtom(DisplayHandle, "_NET_DESKTOP_NAMES", false);
459 NetAtoms[(int)NA._NET_ACTIVE_WINDOW] = XInternAtom(DisplayHandle, "_NET_ACTIVE_WINDOW", false);
460 NetAtoms[(int)NA._NET_WORKAREA] = XInternAtom(DisplayHandle, "_NET_WORKAREA", false);
461 NetAtoms[(int)NA._NET_SUPPORTING_WM_CHECK] = XInternAtom(DisplayHandle, "_NET_SUPPORTING_WM_CHECK", false);
462 NetAtoms[(int)NA._NET_VIRTUAL_ROOTS] = XInternAtom(DisplayHandle, "_NET_VIRTUAL_ROOTS", false);
463 NetAtoms[(int)NA._NET_DESKTOP_LAYOUT] = XInternAtom(DisplayHandle, "_NET_DESKTOP_LAYOUT", false);
464 NetAtoms[(int)NA._NET_SHOWING_DESKTOP] = XInternAtom(DisplayHandle, "_NET_SHOWING_DESKTOP", false);
466 NetAtoms[(int)NA._NET_CLOSE_WINDOW] = XInternAtom(DisplayHandle, "_NET_CLOSE_WINDOW", false);
467 NetAtoms[(int)NA._NET_MOVERESIZE_WINDOW] = XInternAtom(DisplayHandle, "_NET_MOVERESIZE_WINDOW", false);
468 NetAtoms[(int)NA._NET_WM_MOVERESIZE] = XInternAtom(DisplayHandle, "_NET_WM_MOVERESIZE", false);
469 NetAtoms[(int)NA._NET_RESTACK_WINDOW] = XInternAtom(DisplayHandle, "_NET_RESTACK_WINDOW", false);
470 NetAtoms[(int)NA._NET_REQUEST_FRAME_EXTENTS] = XInternAtom(DisplayHandle, "_NET_REQUEST_FRAME_EXTENTS", false);
472 NetAtoms[(int)NA._NET_WM_NAME] = XInternAtom(DisplayHandle, "_NET_WM_NAME", false);
473 NetAtoms[(int)NA._NET_WM_VISIBLE_NAME] = XInternAtom(DisplayHandle, "_NET_WM_VISIBLE_NAME", false);
474 NetAtoms[(int)NA._NET_WM_ICON_NAME] = XInternAtom(DisplayHandle, "_NET_WM_ICON_NAME", false);
475 NetAtoms[(int)NA._NET_WM_VISIBLE_ICON_NAME] = XInternAtom(DisplayHandle, "_NET_WM_VISIBLE_ICON_NAME", false);
476 NetAtoms[(int)NA._NET_WM_DESKTOP] = XInternAtom(DisplayHandle, "_NET_WM_DESKTOP", false);
477 NetAtoms[(int)NA._NET_WM_WINDOW_TYPE] = XInternAtom(DisplayHandle, "_NET_WM_WINDOW_TYPE", false);
478 NetAtoms[(int)NA._NET_WM_STATE] = XInternAtom(DisplayHandle, "_NET_WM_STATE", false);
479 NetAtoms[(int)NA._NET_WM_ALLOWED_ACTIONS] = XInternAtom(DisplayHandle, "_NET_WM_ALLOWED_ACTIONS", false);
480 NetAtoms[(int)NA._NET_WM_STRUT] = XInternAtom(DisplayHandle, "_NET_WM_STRUT", false);
481 NetAtoms[(int)NA._NET_WM_STRUT_PARTIAL] = XInternAtom(DisplayHandle, "_NET_WM_STRUT_PARTIAL", false);
482 NetAtoms[(int)NA._NET_WM_ICON_GEOMETRY] = XInternAtom(DisplayHandle, "_NET_WM_ICON_GEOMETRY", false);
483 NetAtoms[(int)NA._NET_WM_ICON] = XInternAtom(DisplayHandle, "_NET_WM_ICON", false);
484 NetAtoms[(int)NA._NET_WM_PID] = XInternAtom(DisplayHandle, "_NET_WM_PID", false);
485 NetAtoms[(int)NA._NET_WM_HANDLED_ICONS] = XInternAtom(DisplayHandle, "_NET_WM_HANDLED_ICONS", false);
486 NetAtoms[(int)NA._NET_WM_USER_TIME] = XInternAtom(DisplayHandle, "_NET_WM_USER_TIME", false);
487 NetAtoms[(int)NA._NET_FRAME_EXTENTS] = XInternAtom(DisplayHandle, "_NET_FRAME_EXTENTS", false);
489 NetAtoms[(int)NA._NET_WM_PING] = XInternAtom(DisplayHandle, "_NET_WM_PING", false);
490 NetAtoms[(int)NA._NET_WM_SYNC_REQUEST] = XInternAtom(DisplayHandle, "_NET_WM_SYNC_REQUEST", false);
492 NetAtoms[(int)NA._NET_SYSTEM_TRAY_S] = XInternAtom(DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString(), false);
493 NetAtoms[(int)NA._NET_SYSTEM_TRAY_OPCODE] = XInternAtom(DisplayHandle, "_NET_SYSTEM_TRAY_OPCODE", false);
494 NetAtoms[(int)NA._NET_SYSTEM_TRAY_ORIENTATION] = XInternAtom(DisplayHandle, "_NET_SYSTEM_TRAY_ORIENTATION", false);
496 NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ] = XInternAtom(DisplayHandle, "_NET_WM_STATE_MAXIMIZED_HORZ", false);
497 NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT] = XInternAtom(DisplayHandle, "_NET_WM_STATE_MAXIMIZED_VERT", false);
498 NetAtoms[(int)NA._NET_WM_STATE_HIDDEN] = XInternAtom(DisplayHandle, "_NET_WM_STATE_HIDDEN", false);
500 NetAtoms[(int)NA._XEMBED] = XInternAtom(DisplayHandle, "_XEMBED", false);
501 NetAtoms[(int)NA._XEMBED_INFO] = XInternAtom(DisplayHandle, "_XEMBED_INFO", false);
503 NetAtoms[(int)NA._MOTIF_WM_HINTS] = XInternAtom(DisplayHandle, "_MOTIF_WM_HINTS", false);
505 NetAtoms[(int)NA._NET_WM_STATE_NO_TASKBAR] = XInternAtom(DisplayHandle, "_NET_WM_STATE_NO_TASKBAR", false);
506 NetAtoms[(int)NA._NET_WM_STATE_ABOVE] = XInternAtom(DisplayHandle, "_NET_WM_STATE_ABOVE", false);
507 NetAtoms[(int)NA._NET_WM_STATE_MODAL] = XInternAtom(DisplayHandle, "_NET_WM_STATE_MODAL", false);
508 NetAtoms[(int)NA._NET_WM_CONTEXT_HELP] = XInternAtom(DisplayHandle, "_NET_WM_CONTEXT_HELP", false);
509 NetAtoms[(int)NA._NET_WM_WINDOW_OPACITY] = XInternAtom(DisplayHandle, "_NET_WM_WINDOW_OPACITY", false);
512 NetAtoms[(int)NA.CLIPBOARD] = XInternAtom (DisplayHandle, "CLIPBOARD", false);
513 NetAtoms[(int)NA.DIB] = (int)Atom.XA_PIXMAP;
514 NetAtoms[(int)NA.OEMTEXT] = XInternAtom(DisplayHandle, "COMPOUND_TEXT", false);
515 NetAtoms[(int)NA.UNICODETEXT] = XInternAtom(DisplayHandle, "UTF8_STRING", false);
516 NetAtoms[(int)NA.TARGETS] = XInternAtom(DisplayHandle, "TARGETS", false);
519 AsyncAtom = XInternAtom(DisplayHandle, "_SWF_AsyncAtom", false);
520 PostAtom = XInternAtom (DisplayHandle, "_SWF_PostMessageAtom", false);
521 HoverState.Atom = XInternAtom(DisplayHandle, "_SWF_HoverAtom", false);
524 private void GetSystrayManagerWindow() {
525 XGrabServer(DisplayHandle);
526 SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, NetAtoms[(int)NA._NET_SYSTEM_TRAY_S]);
527 XUngrabServer(DisplayHandle);
528 XFlush(DisplayHandle);
531 private void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
535 xev.ClientMessageEvent.type = XEventName.ClientMessage;
536 xev.ClientMessageEvent.send_event = true;
537 xev.ClientMessageEvent.window = window;
538 xev.ClientMessageEvent.message_type = message_type;
539 xev.ClientMessageEvent.format = 32;
540 xev.ClientMessageEvent.ptr1 = l0;
541 xev.ClientMessageEvent.ptr2 = l1;
542 xev.ClientMessageEvent.ptr3 = l2;
543 XSendEvent(DisplayHandle, RootWindow, false, EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask, ref xev);
546 private void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
550 xev.ClientMessageEvent.type = XEventName.ClientMessage;
551 xev.ClientMessageEvent.send_event = true;
552 xev.ClientMessageEvent.window = window;
553 xev.ClientMessageEvent.message_type = message_type;
554 xev.ClientMessageEvent.format = 32;
555 xev.ClientMessageEvent.ptr1 = l0;
556 xev.ClientMessageEvent.ptr2 = l1;
557 xev.ClientMessageEvent.ptr3 = l2;
558 XSendEvent(DisplayHandle, window, false, EventMask.NoEventMask, ref xev);
561 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) {
563 // Only MDI windows get caption_heights
565 tool_caption_height = 19;
567 if ((Style & (int) WindowStyles.WS_CHILD) != 0) {
568 if ((Style & (int) WindowStyles.WS_BORDER) == 0) {
569 border_style = FormBorderStyle.None;
570 } else if ((ExStyle & (int) WindowStyles.WS_EX_CLIENTEDGE) != 0) {
571 border_style = FormBorderStyle.Fixed3D;
573 border_style = FormBorderStyle.FixedSingle;
575 title_style = TitleStyle.None;
579 if ((ExStyle & (int) WindowStyles.WS_EX_MDICHILD) != 0) {
584 title_style = TitleStyle.None;
585 if ((Style & (int)WindowStyles.WS_CAPTION) != 0) {
586 if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
587 title_style = TitleStyle.Tool;
589 title_style = TitleStyle.Normal;
594 border_style = FormBorderStyle.None;
596 if ((Style & (int)WindowStyles.WS_THICKFRAME) != 0) {
597 if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
598 border_style = FormBorderStyle.SizableToolWindow;
600 border_style = FormBorderStyle.Sizable;
603 if ((ExStyle & (int)WindowStyles.WS_EX_CLIENTEDGE) != 0) {
604 border_style = FormBorderStyle.Fixed3D;
605 } else if ((ExStyle & (int)WindowStyles.WS_EX_DLGMODALFRAME) != 0) {
606 border_style = FormBorderStyle.FixedDialog;
607 } else if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
608 border_style = FormBorderStyle.FixedToolWindow;
609 } else if ((Style & (int)WindowStyles.WS_BORDER) != 0) {
610 border_style = FormBorderStyle.Sizable;
612 border_style = FormBorderStyle.None;
616 if ((Style & (int) WindowStyles.WS_OVERLAPPEDWINDOW) != 0 ||
617 (ExStyle & (int) WindowStyles.WS_EX_TOOLWINDOW) != 0) {
618 border_style = (FormBorderStyle) 0xFFFF;
620 border_style = FormBorderStyle.None;
626 private void SetHwndStyles(Hwnd hwnd, CreateParams cp) {
627 DeriveStyles(hwnd.Handle, cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height);
630 private void SetWMStyles(Hwnd hwnd, CreateParams cp) {
631 MotifWmHints mwmHints;
632 MotifFunctions functions;
633 MotifDecorations decorations;
636 Rectangle client_rect;
638 mwmHints = new MotifWmHints();
642 mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
643 mwmHints.functions = (IntPtr)0;
644 mwmHints.decorations = (IntPtr)0;
646 if ((cp.Style & (int)WindowStyles.WS_CAPTION) != 0) {
647 functions |= MotifFunctions.Move;
648 decorations |= MotifDecorations.Title | MotifDecorations.Menu;
651 if ((cp.Style & ((int)WindowStyles.WS_THICKFRAME)) != 0) {
652 functions |= MotifFunctions.Move | MotifFunctions.Resize;
653 decorations |= MotifDecorations.Border | MotifDecorations.ResizeH;
655 if ((cp.Style & ((int)WindowStyles.WS_MINIMIZEBOX)) != 0) {
656 functions |= MotifFunctions.Minimize;
657 decorations |= MotifDecorations.Minimize;
660 if ((cp.Style & ((int)WindowStyles.WS_MAXIMIZEBOX)) != 0) {
661 functions |= MotifFunctions.Maximize;
662 decorations |= MotifDecorations.Maximize;
665 if ((cp.Style & ((int)WindowStyles.WS_SYSMENU)) != 0) {
666 functions |= MotifFunctions.Close;
669 if ((cp.ExStyle & ((int)WindowStyles.WS_EX_DLGMODALFRAME)) != 0) {
670 decorations |= MotifDecorations.Border;
673 if ((cp.Style & ((int)WindowStyles.WS_DLGFRAME)) != 0) {
674 decorations |= MotifDecorations.Border;
677 if ((cp.Style & ((int)WindowStyles.WS_BORDER)) != 0) {
678 decorations |= MotifDecorations.Border;
681 if ((cp.ExStyle & ((int)WindowStyles.WS_EX_TOOLWINDOW)) != 0) {
686 mwmHints.functions = (IntPtr)functions;
687 mwmHints.decorations = (IntPtr)decorations;
689 client_rect = hwnd.ClientRect;
691 XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._MOTIF_WM_HINTS], NetAtoms[(int)NA._MOTIF_WM_HINTS], 32, PropertyMode.Replace, ref mwmHints, 5);
693 if (((cp.Style & (int)WindowStyles.WS_POPUP) != 0) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
694 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd.parent.whole_window);
696 XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
701 if ((cp.ExStyle & ((int)WindowStyles.WS_EX_TOOLWINDOW)) != 0) {
702 atoms[atom_count++] = (uint)NetAtoms[(int)NA._NET_WM_STATE_NO_TASKBAR];
705 XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._NET_WM_STATE], Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
708 atoms[atom_count++] = (uint)NetAtoms[(int)NA.WM_DELETE_WINDOW];
709 if ((cp.ExStyle & (int)WindowStyles.WS_EX_CONTEXTHELP) != 0) {
710 atoms[atom_count++] = (uint)NetAtoms[(int)NA._NET_WM_CONTEXT_HELP];
713 XSetWMProtocols(DisplayHandle, hwnd.whole_window, atoms, atom_count);
717 private void SetIcon(Hwnd hwnd, Icon icon) {
723 bitmap = icon.ToBitmap();
725 size = bitmap.Width * bitmap.Height + 2;
726 data = new uint[size];
728 data[index++] = (uint)bitmap.Width;
729 data[index++] = (uint)bitmap.Height;
731 for (int y = 0; y < bitmap.Height; y++) {
732 for (int x = 0; x < bitmap.Width; x++) {
733 data[index++] = (uint)bitmap.GetPixel(x, y).ToArgb();
736 XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._NET_WM_ICON], Atom.XA_CARDINAL, 32, PropertyMode.Replace, data, size);
739 private IntPtr ImageToPixmap(Image image) {
743 private void WakeupMain () {
744 wake.Send (new byte [] { 0xFF });
747 private void TranslatePropertyToClipboard(int property) {
752 IntPtr prop = IntPtr.Zero;
754 Clipboard.Item = null;
756 XGetWindowProperty(DisplayHandle, FosterParent, property, 0, 0x7fffffff, true, Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
759 if (property == (int)Atom.XA_STRING) {
760 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
761 } else if (property == (int)Atom.XA_BITMAP) {
762 // FIXME - convert bitmap to image
763 } else if (property == (int)Atom.XA_PIXMAP) {
764 // FIXME - convert pixmap to image
765 } else if (property == NetAtoms[(int)NA.OEMTEXT]) {
766 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
767 } else if (property == NetAtoms[(int)NA.UNICODETEXT]) {
768 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
775 private void AddExpose (XEvent xevent) {
778 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
785 if (xevent.AnyEvent.window == hwnd.client_window) {
786 hwnd.AddInvalidArea(xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
787 if (!hwnd.expose_pending) {
788 MessageQueue.Enqueue(xevent);
789 hwnd.expose_pending = true;
792 if (!hwnd.nc_expose_pending) {
793 MessageQueue.Enqueue(xevent);
794 hwnd.nc_expose_pending = true;
799 private void InvalidateWholeWindow(IntPtr handle) {
802 hwnd = Hwnd.ObjectFromHandle(handle);
804 InvalidateWholeWindow(handle, new Rectangle(0, 0, hwnd.Width, hwnd.Height));
807 private void InvalidateWholeWindow(IntPtr handle, Rectangle rectangle) {
811 hwnd = Hwnd.ObjectFromHandle(handle);
814 xevent = new XEvent ();
815 xevent.type = XEventName.Expose;
816 xevent.ExposeEvent.display = DisplayHandle;
817 xevent.ExposeEvent.window = hwnd.whole_window;
819 xevent.ExposeEvent.x = rectangle.X;
820 xevent.ExposeEvent.y = rectangle.Y;
821 xevent.ExposeEvent.width = rectangle.Width;
822 xevent.ExposeEvent.height = rectangle.Height;
827 private void WholeToScreen(IntPtr handle, ref int x, ref int y) {
833 hwnd = Hwnd.ObjectFromHandle(handle);
836 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
843 private void AddConfigureNotify (XEvent xevent) {
846 hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window);
853 if (xevent.ConfigureEvent.window == hwnd.whole_window) {
854 if (!hwnd.reparented) {
855 hwnd.x = xevent.ConfigureEvent.x;
856 hwnd.y = xevent.ConfigureEvent.y;
861 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);
864 hwnd.width = xevent.ConfigureEvent.width;
865 hwnd.height = xevent.ConfigureEvent.height;
867 if (!hwnd.configure_pending) {
868 MessageQueue.Enqueue(xevent);
869 hwnd.configure_pending = true;
872 // We drop configure events for Client windows
875 private void ShowCaret() {
876 if ((Caret.gc == IntPtr.Zero) || Caret.On) {
882 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
886 private void HideCaret() {
887 if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
893 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
897 private int NextTimeout (DateTime now) {
898 int timeout = Int32.MaxValue;
900 foreach (Timer timer in TimerList) {
901 int next = (int) (timer.Expires - now).TotalMilliseconds;
903 return 0; // Have a timer that has already expired
906 if (next < timeout) {
911 if (timeout < Timer.Minimum) {
912 timeout = Timer.Minimum;
918 private void CheckTimers (DateTime now) {
922 count = TimerList.Count;
928 for (int i = 0; i < TimerList.Count; i++) {
931 timer = (Timer) TimerList[i];
933 if (timer.Enabled && timer.Expires <= now) {
941 private void UpdateMessageQueue () {
948 pending = XPending (DisplayHandle);
953 Idle (this, EventArgs.Empty);
957 pending = XPending (DisplayHandle);
964 timeout = NextTimeout (now);
967 Syscall.poll (pollfds, (uint) pollfds.Length, timeout);
968 // Clean out buffer, so we're not busy-looping on the same data
969 if (pollfds[1].revents != 0) {
970 wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
974 pending = XPending (DisplayHandle);
983 pending = XPending (DisplayHandle);
987 while (pending > 0) {
988 XEvent xevent = new XEvent ();
991 XNextEvent (DisplayHandle, ref xevent);
993 //Console.WriteLine("Got x event {0}", xevent);
994 switch (xevent.type) {
995 case XEventName.Expose:
999 case XEventName.SelectionClear: {
1000 // Should we do something?
1004 case XEventName.SelectionRequest: {
1005 if (Dnd.HandleSelectionRequestEvent (ref xevent))
1009 sel_event = new XEvent();
1010 sel_event.SelectionEvent.type = XEventName.SelectionNotify;
1011 sel_event.SelectionEvent.send_event = true;
1012 sel_event.SelectionEvent.display = DisplayHandle;
1013 sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
1014 sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
1015 sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
1016 sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
1017 sel_event.SelectionEvent.property = 0;
1019 // Seems that some apps support asking for supported types
1020 if (xevent.SelectionEvent.target == NetAtoms[(int)NA.TARGETS]) {
1024 atoms = new uint[5];
1027 if (Clipboard.Item is String) {
1028 atoms[atom_count++] = (uint)Atom.XA_STRING;
1029 atoms[atom_count++] = (uint)NetAtoms[(int)NA.OEMTEXT];
1030 atoms[atom_count++] = (uint)NetAtoms[(int)NA.UNICODETEXT];
1031 } else if (Clipboard.Item is Image) {
1032 atoms[atom_count++] = (uint)Atom.XA_PIXMAP;
1033 atoms[atom_count++] = (uint)Atom.XA_BITMAP;
1035 // FIXME - handle other types
1038 XChangeProperty(DisplayHandle, xevent.SelectionEvent.requestor, xevent.SelectionRequestEvent.property, xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
1039 } else if (Clipboard.Item is string) {
1045 if (xevent.SelectionRequestEvent.target == (int)Atom.XA_STRING) {
1048 bytes = new ASCIIEncoding().GetBytes((string)Clipboard.Item);
1049 buffer = Marshal.AllocHGlobal(bytes.Length);
1050 buflen = bytes.Length;
1052 for (int i = 0; i < buflen; i++) {
1053 Marshal.WriteByte(buffer, i, bytes[i]);
1055 } else if (xevent.SelectionRequestEvent.target == NetAtoms[(int)NA.OEMTEXT]) {
1056 // FIXME - this should encode into ISO2022
1057 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1058 while (Marshal.ReadByte(buffer, buflen) != 0) {
1061 } else if (xevent.SelectionRequestEvent.target == NetAtoms[(int)NA.UNICODETEXT]) {
1062 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1063 while (Marshal.ReadByte(buffer, buflen) != 0) {
1067 buffer = IntPtr.Zero;
1070 if (buffer != IntPtr.Zero) {
1071 XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, xevent.SelectionRequestEvent.property, xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
1072 sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
1073 Marshal.FreeHGlobal(buffer);
1075 } else if (Clipboard.Item is Image) {
1076 if (xevent.SelectionEvent.target == (int)Atom.XA_PIXMAP) {
1077 // FIXME - convert image and store as property
1078 } else if (xevent.SelectionEvent.target == (int)Atom.XA_PIXMAP) {
1079 // FIXME - convert image and store as property
1083 XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, EventMask.NoEventMask, ref sel_event);
1087 case XEventName.SelectionNotify: {
1088 if (Clipboard.Enumerating) {
1089 Clipboard.Enumerating = false;
1090 if (xevent.SelectionEvent.property != 0) {
1091 XDeleteProperty(DisplayHandle, FosterParent, xevent.SelectionEvent.property);
1092 if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) {
1093 Clipboard.Formats.Add(xevent.SelectionEvent.property);
1094 #if DriverDebugExtra
1095 Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
1099 } else if (Clipboard.Retrieving) {
1100 Clipboard.Retrieving = false;
1101 if (xevent.SelectionEvent.property != 0) {
1102 TranslatePropertyToClipboard(xevent.SelectionEvent.property);
1104 Clipboard.Item = null;
1107 Dnd.HandleSelectionNotifyEvent (ref xevent);
1112 case XEventName.KeyPress:
1113 case XEventName.KeyRelease:
1114 case XEventName.ButtonPress:
1115 case XEventName.ButtonRelease:
1116 case XEventName.MotionNotify:
1117 case XEventName.EnterNotify:
1118 case XEventName.LeaveNotify:
1119 case XEventName.CreateNotify:
1120 case XEventName.DestroyNotify:
1121 case XEventName.FocusIn:
1122 case XEventName.FocusOut:
1123 case XEventName.ClientMessage:
1124 case XEventName.ReparentNotify:
1125 MessageQueue.Enqueue (xevent);
1128 case XEventName.ConfigureNotify:
1129 AddConfigureNotify(xevent);
1132 case XEventName.PropertyNotify:
1133 if (xevent.PropertyEvent.atom == NetAtoms[(int)NA._NET_ACTIVE_WINDOW]) {
1138 IntPtr prop = IntPtr.Zero;
1139 IntPtr prev_active;;
1141 prev_active = ActiveWindow;
1142 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);
1143 if ((nitems > 0) && (prop != IntPtr.Zero)) {
1144 ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop));
1147 if (prev_active != ActiveWindow) {
1148 if (prev_active != IntPtr.Zero) {
1149 PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1151 if (ActiveWindow != IntPtr.Zero) {
1152 PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
1155 if (ModalWindows.Count == 0) {
1158 // Modality handling, if we are modal and the new active window is one
1159 // of ours but not the modal one, switch back to the modal window
1161 if (NativeWindow.FindWindow(ActiveWindow) != null) {
1162 if (ActiveWindow != (IntPtr)ModalWindows.Peek()) {
1163 Activate((IntPtr)ModalWindows.Peek());
1175 pending = XPending (DisplayHandle);
1180 private IntPtr GetMousewParam(int Delta) {
1183 if ((MouseState & MouseButtons.Left) != 0) {
1184 result |= (int)MsgButtons.MK_LBUTTON;
1187 if ((MouseState & MouseButtons.Middle) != 0) {
1188 result |= (int)MsgButtons.MK_MBUTTON;
1191 if ((MouseState & MouseButtons.Right) != 0) {
1192 result |= (int)MsgButtons.MK_RBUTTON;
1195 Keys mods = ModifierKeys;
1196 if ((mods & Keys.Control) != 0) {
1197 result |= (int)MsgButtons.MK_CONTROL;
1200 if ((mods & Keys.Shift) != 0) {
1201 result |= (int)MsgButtons.MK_SHIFT;
1204 result |= Delta << 16;
1206 return (IntPtr)result;
1208 private IntPtr XGetParent(IntPtr handle) {
1215 XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount);
1218 if (Children!=IntPtr.Zero) {
1226 private int HandleError(IntPtr display, ref XErrorEvent error_event) {
1227 if (ErrorExceptions) {
1228 throw new XException(error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code);
1230 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());
1235 private void DestroyChildWindow(Control c) {
1241 controls = c.child_controls.GetAllControls ();
1243 for (i = 0; i < controls.Length; i++) {
1244 if (controls[i].IsHandleCreated) {
1245 hwnd = Hwnd.ObjectFromHandle(controls[i].Handle);
1246 SendMessage(controls[i].Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
1249 DestroyChildWindow(controls[i]);
1254 #endregion // Private Methods
1257 private void MouseHover(object sender, EventArgs e) {
1258 if ((HoverState.X == MousePosition.X) && (HoverState.Y == MousePosition.Y)) {
1261 HoverState.Timer.Enabled = false;
1263 if (HoverState.Window != IntPtr.Zero) {
1264 xevent = new XEvent ();
1266 xevent.type = XEventName.ClientMessage;
1267 xevent.ClientMessageEvent.display = DisplayHandle;
1268 xevent.ClientMessageEvent.window = (IntPtr)HoverState.Window;
1269 xevent.ClientMessageEvent.message_type = (IntPtr)HoverState.Atom;
1270 xevent.ClientMessageEvent.format = 32;
1271 xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
1273 MessageQueue.EnqueueLocked (xevent);
1280 private void CaretCallback(object sender, EventArgs e) {
1284 Caret.On = !Caret.On;
1286 XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1288 #endregion // Callbacks
1290 #region Public Properties
1292 internal override int Caption {
1298 internal override Size CursorSize {
1303 if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) {
1304 return new Size(x, y);
1306 return new Size(16, 16);
1311 internal override bool DragFullWindows {
1317 internal override Size DragSize {
1319 return new Size(4, 4);
1323 internal override Size FrameBorderSize {
1325 throw new NotImplementedException();
1329 internal override Size IconSize {
1335 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
1339 current = (long)list;
1342 size = new XIconSize();
1344 for (int i = 0; i < count; i++) {
1345 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
1346 current += Marshal.SizeOf(size);
1348 // Look for our preferred size
1349 if (size.min_width == 32) {
1351 return new Size(32, 32);
1354 if (size.max_width == 32) {
1356 return new Size(32, 32);
1359 if (size.min_width < 32 && size.max_width > 32) {
1362 // check if we can fit one
1364 while (x < size.max_width) {
1365 x += size.width_inc;
1368 return new Size(32, 32);
1373 if (largest < size.max_width) {
1374 largest = size.max_width;
1378 // We didn't find a match or we wouldn't be here
1379 return new Size(largest, largest);
1382 return new Size(32, 32);
1387 internal override int KeyboardSpeed {
1390 // A lot harder: need to do:
1391 // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
1392 // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
1393 // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
1395 // And from that we can tell the repetition rate
1397 // Notice, the values must map to:
1398 // [0, 31] which maps to 2.5 to 30 repetitions per second.
1404 internal override int KeyboardDelay {
1407 // Return values must range from 0 to 4, 0 meaning 250ms,
1408 // and 4 meaning 1000 ms.
1410 return 1; // ie, 500 ms
1414 internal override Size MaxWindowTrackSize {
1416 return new Size (WorkingArea.Width, WorkingArea.Height);
1420 internal override Size MinimizedWindowSize {
1422 return new Size(1, 1);
1426 internal override Size MinimizedWindowSpacingSize {
1428 return new Size(1, 1);
1432 internal override Size MinimumWindowSize {
1434 return new Size(1, 1);
1438 internal override Size MinWindowTrackSize {
1440 return new Size(1, 1);
1444 internal override Keys ModifierKeys {
1446 return Keyboard.ModifierKeys;
1450 internal override Size SmallIconSize {
1456 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
1460 current = (long)list;
1463 size = new XIconSize();
1465 for (int i = 0; i < count; i++) {
1466 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
1467 current += Marshal.SizeOf(size);
1469 // Look for our preferred size
1470 if (size.min_width == 16) {
1472 return new Size(16, 16);
1475 if (size.max_width == 16) {
1477 return new Size(16, 16);
1480 if (size.min_width < 16 && size.max_width > 16) {
1483 // check if we can fit one
1485 while (x < size.max_width) {
1486 x += size.width_inc;
1489 return new Size(16, 16);
1494 if (smallest == 0 || smallest > size.min_width) {
1495 smallest = size.min_width;
1499 // We didn't find a match or we wouldn't be here
1500 return new Size(smallest, smallest);
1503 return new Size(16, 16);
1508 internal override int MouseButtonCount {
1514 internal override bool MouseButtonsSwapped {
1516 return false; // FIXME - how to detect?
1520 internal override bool MouseWheelPresent {
1522 return true; // FIXME - how to detect?
1526 internal override Rectangle VirtualScreen {
1532 internal override Rectangle WorkingArea {
1538 IntPtr prop = IntPtr.Zero;
1542 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);
1543 if ((nitems == 2) && (prop != IntPtr.Zero)) {
1544 width = Marshal.ReadInt32(prop, 0);
1545 height = Marshal.ReadInt32(prop, 4);
1548 return new Rectangle(0, 0, width, height);
1550 XWindowAttributes attributes=new XWindowAttributes();
1553 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
1556 return new Rectangle(0, 0, attributes.width, attributes.height);
1560 #endregion // Public properties
1562 #region Public Static Methods
1563 internal override IntPtr InitializeDriver() {
1565 if (DisplayHandle==IntPtr.Zero) {
1566 SetDisplay(XOpenDisplay(IntPtr.Zero));
1572 internal override void ShutdownDriver(IntPtr token) {
1574 if (DisplayHandle!=IntPtr.Zero) {
1575 XCloseDisplay(DisplayHandle);
1576 DisplayHandle=IntPtr.Zero;
1581 internal override void EnableThemes() {
1582 ThemesEnabled = true;
1586 internal override void Activate(IntPtr handle) {
1589 hwnd = Hwnd.ObjectFromHandle(handle);
1591 if (hwnd != null) lock (XlibLock) {
1592 SendNetWMMessage(hwnd.whole_window, (IntPtr)NetAtoms[(int)NA._NET_ACTIVE_WINDOW], IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
1593 //XRaiseWindow(DisplayHandle, handle);
1598 internal override void AudibleAlert() {
1599 XBell(DisplayHandle, 0);
1604 internal override void CaretVisible(IntPtr handle, bool visible) {
1605 // Visible is cumulative; two hides require two shows before the caret is visible again
1606 if (Caret.Hwnd == handle) {
1608 if (Caret.Visible < 1) {
1611 if (Caret.Visible == 1) {
1613 Caret.Timer.Start();
1618 if (Caret.Visible == 0) {
1626 internal override bool CalculateWindowRect(IntPtr handle, ref Rectangle ClientRect, int Style, int ExStyle, Menu menu, out Rectangle WindowRect) {
1627 FormBorderStyle border_style;
1628 TitleStyle title_style;
1630 int tool_caption_height;
1632 DeriveStyles(handle, Style, ExStyle, out border_style, out title_style,
1633 out caption_height, out tool_caption_height);
1635 WindowRect = Hwnd.GetWindowRectangle(border_style, menu, title_style,
1636 caption_height, tool_caption_height,
1642 internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) {
1648 hwnd = Hwnd.ObjectFromHandle(handle);
1651 XTranslateCoordinates(DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
1658 internal override int[] ClipboardAvailableFormats(IntPtr handle) {
1659 DataFormats.Format f;
1662 f = DataFormats.Format.List;
1664 if (XGetSelectionOwner(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD]) == IntPtr.Zero) {
1668 Clipboard.Formats = new ArrayList();
1671 XConvertSelection(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], f.Id, f.Id, FosterParent, IntPtr.Zero);
1673 Clipboard.Enumerating = true;
1674 while (Clipboard.Enumerating) {
1675 UpdateMessageQueue();
1680 result = new int[Clipboard.Formats.Count];
1682 for (int i = 0; i < Clipboard.Formats.Count; i++) {
1683 result[i] = (int)Clipboard.Formats[i];
1686 Clipboard.Formats = null;
1690 internal override void ClipboardClose(IntPtr handle) {
1691 if (handle != ClipMagic) {
1692 throw new ArgumentException("handle is not a valid clipboard handle");
1697 internal override int ClipboardGetID(IntPtr handle, string format) {
1698 if (handle != ClipMagic) {
1699 throw new ArgumentException("handle is not a valid clipboard handle");
1702 if (format == "Text" ) return (int)Atom.XA_STRING;
1703 else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP;
1704 //else if (format == "MetaFilePict" ) return 3;
1705 //else if (format == "SymbolicLink" ) return 4;
1706 //else if (format == "DataInterchangeFormat" ) return 5;
1707 //else if (format == "Tiff" ) return 6;
1708 else if (format == "OEMText" ) return XInternAtom(DisplayHandle, "COMPOUND_TEXT", false);
1709 else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP;
1710 else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless
1711 //else if (format == "PenData" ) return 10;
1712 //else if (format == "RiffAudio" ) return 11;
1713 //else if (format == "WaveAudio" ) return 12;
1714 else if (format == "UnicodeText" ) return XInternAtom(DisplayHandle, "UTF8_STRING", false);
1715 //else if (format == "EnhancedMetafile" ) return 14;
1716 //else if (format == "FileDrop" ) return 15;
1717 //else if (format == "Locale" ) return 16;
1719 return XInternAtom(DisplayHandle, format, false);
1722 internal override IntPtr ClipboardOpen() {
1726 internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) {
1727 XConvertSelection(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], type, type, FosterParent, IntPtr.Zero);
1729 Clipboard.Retrieving = true;
1730 while (Clipboard.Retrieving) {
1731 UpdateMessageQueue();
1734 return Clipboard.Item;
1737 internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter) {
1738 Clipboard.Item = obj;
1739 Clipboard.Type = type;
1740 Clipboard.Converter = converter;
1743 XSetSelectionOwner(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], FosterParent, IntPtr.Zero);
1745 // Clearing the selection
1746 XSetSelectionOwner(DisplayHandle, NetAtoms[(int)NA.CLIPBOARD], IntPtr.Zero, IntPtr.Zero);
1750 internal override void CreateCaret(IntPtr handle, int width, int height) {
1751 XGCValues gc_values;
1754 hwnd = Hwnd.ObjectFromHandle(handle);
1756 if (Caret.Hwnd != IntPtr.Zero) {
1757 DestroyCaret(Caret.Hwnd);
1760 Caret.Hwnd = handle;
1761 Caret.Window = hwnd.client_window;
1762 Caret.Width = width;
1763 Caret.Height = height;
1767 gc_values = new XGCValues();
1768 gc_values.line_width = width;
1770 Caret.gc = XCreateGC(DisplayHandle, Caret.Window, GCFunction.GCLineWidth, ref gc_values);
1771 if (Caret.gc == IntPtr.Zero) {
1772 Caret.Hwnd = IntPtr.Zero;
1776 XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert);
1779 internal override IntPtr CreateWindow(CreateParams cp) {
1780 XSetWindowAttributes Attributes;
1786 IntPtr ParentHandle;
1788 IntPtr ClientWindow;
1789 Rectangle ClientRect;
1790 SetWindowValuemask ValueMask;
1795 Attributes = new XSetWindowAttributes();
1801 if (Width<1) Width=1;
1802 if (Height<1) Height=1;
1804 if (cp.Parent != IntPtr.Zero) {
1805 ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).client_window;
1807 if ((cp.Style & (int)WindowStyles.WS_CHILD) != 0) {
1808 // We need to use our foster parent window until this poor child gets it's parent assigned
1809 ParentHandle=FosterParent;
1810 } else if ((cp.Style & (int)WindowStyles.WS_POPUP) != 0) {
1811 ParentHandle=RootWindow;
1813 // Default position on screen, if window manager doesn't place us somewhere else
1816 ParentHandle=RootWindow;
1820 ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
1822 Attributes.bit_gravity = Gravity.NorthWestGravity;
1823 Attributes.win_gravity = Gravity.NorthWestGravity;
1825 // Save what's under the toolwindow
1826 if ((cp.ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) {
1827 Attributes.save_under = true;
1828 ValueMask |= SetWindowValuemask.SaveUnder;
1832 // If we're a popup without caption we override the WM
1833 if ((cp.Style & ((int)WindowStyles.WS_POPUP)) != 0) {
1834 if ((cp.Style & (int)WindowStyles.WS_CAPTION) == 0) {
1835 Attributes.override_redirect = true;
1836 ValueMask |= SetWindowValuemask.OverrideRedirect;
1843 hwnd.height = Height;
1844 hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent);
1846 if ((cp.Style & ((int)WindowStyles.WS_DISABLED)) != 0) {
1847 hwnd.enabled = false;
1850 ClientRect = hwnd.ClientRect;
1851 ClientWindow = IntPtr.Zero;
1854 WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, Width, Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, ValueMask, ref Attributes);
1855 if (WholeWindow != IntPtr.Zero) {
1856 ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
1858 if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) {
1859 ValueMask = SetWindowValuemask.ColorMap;
1860 Attributes.colormap = CustomColormap;
1862 ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, ValueMask, ref Attributes);
1866 if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) {
1867 throw new Exception("Could not create X11 windows");
1870 hwnd.WholeWindow = WholeWindow;
1871 hwnd.ClientWindow = ClientWindow;
1874 Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0);
1878 XSelectInput(DisplayHandle, hwnd.whole_window, SelectInputMask);
1879 XSelectInput(DisplayHandle, hwnd.client_window, SelectInputMask);
1881 if ((cp.Style & (int)WindowStyles.WS_VISIBLE) != 0) {
1882 XMapWindow(DisplayHandle, hwnd.whole_window);
1883 XMapWindow(DisplayHandle, hwnd.client_window);
1884 hwnd.visible = true;
1888 SetWMStyles(hwnd, cp);
1890 if ((cp.Style & (int)WindowStyles.WS_MINIMIZE) != 0) {
1891 SetWindowState(hwnd.Handle, FormWindowState.Minimized);
1892 } else if ((cp.Style & (int)WindowStyles.WS_MAXIMIZE) != 0) {
1893 SetWindowState(hwnd.Handle, FormWindowState.Maximized);
1896 // for now make all windows dnd enabled
1897 Dnd.SetAllowDrop (hwnd, true);
1899 // Set caption/window title
1900 Text(hwnd.Handle, cp.Caption);
1905 internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) {
1906 CreateParams create_params = new CreateParams();
1908 create_params.Caption = "";
1909 create_params.X = X;
1910 create_params.Y = Y;
1911 create_params.Width = Width;
1912 create_params.Height = Height;
1914 create_params.ClassName=XplatUI.DefaultClassName;
1915 create_params.ClassStyle = 0;
1916 create_params.ExStyle=0;
1917 create_params.Parent=IntPtr.Zero;
1918 create_params.Param=0;
1920 return CreateWindow(create_params);
1923 internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
1925 Bitmap cursor_bitmap;
1933 IntPtr cursor_pixmap;
1940 if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) {
1944 // Win32 only allows creation cursors of a certain size
1945 if ((bitmap.Width != width) || (bitmap.Width != height)) {
1946 cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
1947 cursor_mask = new Bitmap(mask, new Size(width, height));
1949 cursor_bitmap = bitmap;
1953 width = cursor_bitmap.Width;
1954 height = cursor_bitmap.Height;
1956 cursor_bits = new Byte[(width / 8) * height];
1957 mask_bits = new Byte[(width / 8) * height];
1959 for (int y = 0; y < height; y++) {
1960 for (int x = 0; x < width; x++) {
1961 c_pixel = cursor_bitmap.GetPixel(x, y);
1962 m_pixel = cursor_mask.GetPixel(x, y);
1964 and = c_pixel == cursor_pixel;
1965 xor = m_pixel == mask_pixel;
1969 // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
1970 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
1971 } else if (and && !xor) {
1973 cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
1974 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
1976 } else if (and && !xor) {
1978 } else if (and && xor) {
1981 // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
1982 // we want both to be 0 so nothing to be done
1983 //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
1984 //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
1990 cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
1991 mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
1995 fg.pixel = XWhitePixel(DisplayHandle, ScreenNo);
1996 fg.red = (ushort)65535;
1997 fg.green = (ushort)65535;
1998 fg.blue = (ushort)65535;
2000 bg.pixel = XBlackPixel(DisplayHandle, ScreenNo);
2002 cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
2004 XFreePixmap(DisplayHandle, cursor_pixmap);
2005 XFreePixmap(DisplayHandle, mask_pixmap);
2010 internal override IntPtr DefineStdCursor(StdCursor id) {
2011 CursorFontShape shape;
2014 // FIXME - define missing shapes
2017 case StdCursor.AppStarting: {
2018 shape = CursorFontShape.XC_watch;
2022 case StdCursor.Arrow: {
2026 case StdCursor.Cross: {
2027 shape = CursorFontShape.XC_crosshair;
2031 case StdCursor.Default: {
2035 case StdCursor.Hand: {
2036 shape = CursorFontShape.XC_hand1;
2040 case StdCursor.Help: {
2041 shape = CursorFontShape.XC_question_arrow;
2045 case StdCursor.HSplit: {
2046 shape = CursorFontShape.XC_sb_v_double_arrow;
2050 case StdCursor.IBeam: {
2051 shape = CursorFontShape.XC_xterm;
2055 case StdCursor.No: {
2056 shape = CursorFontShape.XC_circle;
2060 case StdCursor.NoMove2D: {
2061 shape = CursorFontShape.XC_fleur;
2065 case StdCursor.NoMoveHoriz: {
2066 shape = CursorFontShape.XC_fleur;
2070 case StdCursor.NoMoveVert: {
2071 shape = CursorFontShape.XC_fleur;
2075 case StdCursor.PanEast: {
2076 shape = CursorFontShape.XC_fleur;
2080 case StdCursor.PanNE: {
2081 shape = CursorFontShape.XC_fleur;
2085 case StdCursor.PanNorth: {
2086 shape = CursorFontShape.XC_fleur;
2090 case StdCursor.PanNW: {
2091 shape = CursorFontShape.XC_fleur;
2095 case StdCursor.PanSE: {
2096 shape = CursorFontShape.XC_fleur;
2100 case StdCursor.PanSouth: {
2101 shape = CursorFontShape.XC_fleur;
2105 case StdCursor.PanSW: {
2106 shape = CursorFontShape.XC_fleur;
2110 case StdCursor.PanWest: {
2111 shape = CursorFontShape.XC_sizing;
2115 case StdCursor.SizeAll: {
2116 shape = CursorFontShape.XC_fleur;
2120 case StdCursor.SizeNESW: {
2121 shape = CursorFontShape.XC_top_right_corner;
2125 case StdCursor.SizeNS: {
2126 shape = CursorFontShape.XC_sb_v_double_arrow;
2130 case StdCursor.SizeNWSE: {
2131 shape = CursorFontShape.XC_top_left_corner;
2135 case StdCursor.SizeWE: {
2136 shape = CursorFontShape.XC_sb_h_double_arrow;
2140 case StdCursor.UpArrow: {
2141 shape = CursorFontShape.XC_center_ptr;
2145 case StdCursor.VSplit: {
2146 shape = CursorFontShape.XC_sb_h_double_arrow;
2150 case StdCursor.WaitCursor: {
2151 shape = CursorFontShape.XC_watch;
2161 cursor = XCreateFontCursor(DisplayHandle, shape);
2166 internal override IntPtr DefWndProc(ref Message msg) {
2170 internal override void DestroyCaret(IntPtr handle) {
2171 if (Caret.Hwnd == handle) {
2172 if (Caret.Visible == 1) {
2176 if (Caret.gc != IntPtr.Zero) {
2177 XFreeGC(DisplayHandle, Caret.gc);
2178 Caret.gc = IntPtr.Zero;
2180 Caret.Hwnd = IntPtr.Zero;
2186 internal override void DestroyCursor(IntPtr cursor) {
2188 XFreeCursor(DisplayHandle, cursor);
2192 internal override void DestroyWindow(IntPtr handle) {
2195 hwnd = Hwnd.ObjectFromHandle(handle);
2199 Console.WriteLine("window {0:X} already destroyed", handle.ToInt32());
2205 Console.WriteLine("Destroying window {0:X}", handle.ToInt32());
2208 // Make sure if the caret is in the window, that we destroy the caret, too
2209 if (Caret.Hwnd == hwnd.client_window) {
2210 DestroyCaret(handle);
2213 // Mark our children as gone as well
2214 DestroyChildWindow(Control.ControlNativeWindow.ControlFromHandle(handle));
2216 // Send destroy message
2217 SendMessage(handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
2220 if (hwnd.client_window != IntPtr.Zero) {
2221 XDestroyWindow(DisplayHandle, hwnd.client_window);
2224 if ((hwnd.whole_window != IntPtr.Zero) && (hwnd.whole_window != hwnd.client_window)) {
2225 XDestroyWindow(DisplayHandle, hwnd.whole_window);
2231 internal override IntPtr DispatchMessage(ref MSG msg) {
2232 return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
2235 internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) {
2237 XGCValues gc_values;
2240 hwnd = Hwnd.ObjectFromHandle(handle);
2242 gc_values = new XGCValues();
2244 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
2245 gc_values.line_width = line_width;
2246 gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo);
2248 // This logic will give us true rubber bands: (libsx, SANE_XOR)
2249 //mask = foreground ^ background;
2250 //XSetForeground(DisplayHandle, gc, 0xffffffff);
2251 //XSetBackground(DisplayHandle, gc, background);
2252 //XSetFunction(DisplayHandle, gc, GXxor);
2253 //XSetPlaneMask(DisplayHandle, gc, mask);
2256 gc = XCreateGC(DisplayHandle, hwnd.client_window, GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground, ref gc_values);
2261 control = Control.FromHandle(handle);
2263 XColor xcolor = new XColor();
2265 xcolor.red = (ushort)(control.ForeColor.R * 257);
2266 xcolor.green = (ushort)(control.ForeColor.G * 257);
2267 xcolor.blue = (ushort)(control.ForeColor.B * 257);
2268 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
2269 foreground = (uint)xcolor.pixel.ToInt32();
2271 xcolor.red = (ushort)(control.BackColor.R * 257);
2272 xcolor.green = (ushort)(control.BackColor.G * 257);
2273 xcolor.blue = (ushort)(control.BackColor.B * 257);
2274 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
2275 background = (uint)xcolor.pixel.ToInt32();
2277 uint mask = foreground ^ background;
2279 XSetForeground(DisplayHandle, gc, 0xffffffff);
2280 XSetBackground(DisplayHandle, gc, background);
2281 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
2282 XSetPlaneMask(DisplayHandle, gc, mask);
2284 if ((rect.Width > 0) && (rect.Height > 0)) {
2285 XDrawRectangle(DisplayHandle, hwnd.client_window, gc, rect.Left, rect.Top, rect.Width, rect.Height);
2287 if (rect.Width > 0) {
2288 XDrawLine(DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.Right, rect.Y);
2290 XDrawLine(DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.X, rect.Bottom);
2293 XFreeGC(DisplayHandle, gc);
2296 internal override void DoEvents() {
2297 MSG msg = new MSG ();
2299 if (OverrideCursorHandle != IntPtr.Zero) {
2300 OverrideCursorHandle = IntPtr.Zero;
2303 while (PeekMessage(ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
2304 TranslateMessage (ref msg);
2305 DispatchMessage (ref msg);
2309 internal override void EnableWindow(IntPtr handle, bool Enable) {
2312 hwnd = Hwnd.ObjectFromHandle(handle);
2314 hwnd.Enabled = Enable;
2318 internal override void EndLoop(Thread thread) {
2319 // This is where we one day will shut down the loop for the thread
2323 internal override IntPtr GetActive() {
2328 IntPtr prop = IntPtr.Zero;
2329 IntPtr active = IntPtr.Zero;
2331 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);
2332 if ((nitems > 0) && (prop != IntPtr.Zero)) {
2333 active = (IntPtr)Marshal.ReadInt32(prop);
2337 if (active != IntPtr.Zero) {
2340 hwnd = Hwnd.GetObjectFromWindow(active);
2342 active = hwnd.Handle;
2344 active = IntPtr.Zero;
2350 internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) {
2351 throw new NotImplementedException ();
2354 internal override void GetDisplaySize(out Size size) {
2355 XWindowAttributes attributes=new XWindowAttributes();
2358 // FIXME - use _NET_WM messages instead?
2359 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2362 size = new Size(attributes.width, attributes.height);
2365 internal override SizeF GetAutoScaleSize(Font font) {
2368 string magic_string = "The quick brown fox jumped over the lazy dog.";
2369 double magic_number = 44.549996948242189;
2371 g = Graphics.FromHwnd(FosterParent);
2373 width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
2374 return new SizeF(width, font.Height);
2377 internal override IntPtr GetParent(IntPtr handle) {
2380 hwnd = Hwnd.ObjectFromHandle(handle);
2381 if (hwnd != null && hwnd.parent != null) {
2382 return hwnd.parent.Handle;
2387 internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
2397 if (handle != IntPtr.Zero) {
2398 use_handle = Hwnd.ObjectFromHandle(handle).client_window;
2400 use_handle = RootWindow;
2404 XQueryPointer(DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
2407 if (handle != IntPtr.Zero) {
2416 internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) {
2417 return GetFontMetrics(g.GetHdc(), font.ToHfont(), out ascent, out descent);
2420 internal override Point GetMenuOrigin(IntPtr handle) {
2423 hwnd = Hwnd.ObjectFromHandle(handle);
2426 return hwnd.MenuOrigin;
2431 internal override bool GetMessage(ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) {
2438 if (MessageQueue.Count > 0) {
2439 xevent = (XEvent) MessageQueue.Dequeue ();
2441 UpdateMessageQueue ();
2443 if (MessageQueue.Count > 0) {
2444 xevent = (XEvent) MessageQueue.Dequeue ();
2446 if (!PostQuitState) {
2447 msg.hwnd= IntPtr.Zero;
2448 msg.message = Msg.WM_ENTERIDLE;
2452 // We reset ourselves so GetMessage can be called again
2453 PostQuitState = false;
2459 // FIXME - handle filtering
2461 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
2463 // Handle messages for windows that are already or are about to be destroyed
2466 Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
2468 goto ProcessNextMessage;
2471 if (hwnd.client_window == xevent.AnyEvent.window) {
2473 //Console.WriteLine("Client message, sending to window {0:X}", msg.hwnd.ToInt32());
2476 //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32());
2479 msg.hwnd = hwnd.Handle;
2482 // If you add a new event to this switch make sure to add it in
2483 // UpdateMessage also unless it is not coming through the X event system.
2485 switch(xevent.type) {
2486 case XEventName.KeyPress: {
2487 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
2491 case XEventName.KeyRelease: {
2492 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
2496 case XEventName.ButtonPress: {
2497 switch(xevent.ButtonEvent.button) {
2499 MouseState |= MouseButtons.Left;
2501 msg.message = Msg.WM_LBUTTONDOWN;
2503 msg.message = Msg.WM_NCLBUTTONDOWN;
2504 WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2506 // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
2507 msg.wParam=GetMousewParam(0);
2512 MouseState |= MouseButtons.Middle;
2514 msg.message = Msg.WM_MBUTTONDOWN;
2516 msg.message = Msg.WM_NCMBUTTONDOWN;
2517 WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2519 msg.wParam=GetMousewParam(0);
2524 MouseState |= MouseButtons.Right;
2526 msg.message = Msg.WM_RBUTTONDOWN;
2528 msg.message = Msg.WM_NCRBUTTONDOWN;
2529 WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2531 msg.wParam=GetMousewParam(0);
2536 msg.message=Msg.WM_MOUSEWHEEL;
2537 msg.wParam=GetMousewParam(120);
2542 msg.message=Msg.WM_MOUSEWHEEL;
2543 msg.wParam=GetMousewParam(-120);
2549 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
2550 MousePosition.X = xevent.ButtonEvent.x;
2551 MousePosition.Y = xevent.ButtonEvent.y;
2553 if (!hwnd.Enabled) {
2556 msg.hwnd = hwnd.EnabledHwnd;
2557 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);
2558 msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
2561 if (Grab.Hwnd != IntPtr.Zero) {
2562 msg.hwnd = Grab.Hwnd;
2565 if (!ClickPending.Pending) {
2566 ClickPending.Pending = true;
2567 ClickPending.Hwnd = msg.hwnd;
2568 ClickPending.Message = msg.message;
2569 ClickPending.wParam = msg.wParam;
2570 ClickPending.lParam = msg.lParam;
2571 ClickPending.Time = (long)xevent.ButtonEvent.time;
2573 if ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message)) {
2574 // Looks like a genuine double click, clicked twice on the same spot with the same keys
2575 switch(xevent.ButtonEvent.button) {
2577 msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
2582 msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
2587 msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
2592 ClickPending.Pending = false;
2598 case XEventName.ButtonRelease: {
2599 Dnd.HandleButtonRelease (ref xevent);
2600 switch(xevent.ButtonEvent.button) {
2602 MouseState &= ~MouseButtons.Left;
2604 msg.message = Msg.WM_LBUTTONUP;
2606 msg.message = Msg.WM_NCLBUTTONUP;
2607 WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2609 msg.wParam=GetMousewParam(0);
2614 MouseState &= ~MouseButtons.Middle;
2616 msg.message = Msg.WM_MBUTTONUP;
2618 msg.message = Msg.WM_NCMBUTTONUP;
2619 WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2621 msg.wParam=GetMousewParam(0);
2626 MouseState &= ~MouseButtons.Right;
2628 msg.message = Msg.WM_RBUTTONUP;
2630 msg.message = Msg.WM_NCRBUTTONUP;
2631 WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
2633 msg.wParam=GetMousewParam(0);
2638 goto ProcessNextMessage;
2642 goto ProcessNextMessage;
2646 if (!hwnd.Enabled) {
2649 msg.hwnd = hwnd.EnabledHwnd;
2650 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);
2651 msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
2654 if (Grab.Hwnd != IntPtr.Zero) {
2655 msg.hwnd = Grab.Hwnd;
2658 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
2659 MousePosition.X = xevent.ButtonEvent.x;
2660 MousePosition.Y = xevent.ButtonEvent.y;
2664 case XEventName.MotionNotify: {
2666 #if DriverDebugExtra
2667 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);
2670 if (Dnd.HandleMotionNotify (ref xevent))
2671 goto ProcessNextMessage;
2672 if (Grab.Hwnd != IntPtr.Zero) {
2673 msg.hwnd = Grab.Hwnd;
2675 NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
2678 msg.message = Msg.WM_MOUSEMOVE;
2679 msg.wParam = GetMousewParam(0);
2680 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
2682 if (!hwnd.Enabled) {
2685 msg.hwnd = hwnd.EnabledHwnd;
2686 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);
2687 msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
2690 HoverState.X = MousePosition.X = xevent.MotionEvent.x;
2691 HoverState.Y = MousePosition.Y = xevent.MotionEvent.y;
2695 #if DriverDebugExtra
2696 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);
2698 msg.message = Msg.WM_NCMOUSEMOVE;
2699 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
2701 if (!hwnd.Enabled) {
2704 msg.hwnd = hwnd.EnabledHwnd;
2705 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);
2706 msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
2710 // Not sure we need this...
2712 ht = NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam);
2715 MousePosition.X = xevent.MotionEvent.x;
2716 MousePosition.Y = xevent.MotionEvent.y;
2722 case XEventName.EnterNotify: {
2723 if (!hwnd.Enabled) {
2724 goto ProcessNextMessage;
2726 if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
2727 goto ProcessNextMessage;
2729 msg.message = Msg.WM_MOUSE_ENTER;
2730 HoverState.Timer.Enabled = true;
2731 HoverState.Window = xevent.CrossingEvent.window;
2735 case XEventName.LeaveNotify: {
2736 if (!hwnd.Enabled) {
2737 goto ProcessNextMessage;
2739 if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
2740 goto ProcessNextMessage;
2742 msg.message=Msg.WM_MOUSE_LEAVE;
2743 HoverState.Timer.Enabled = false;
2744 HoverState.Window = IntPtr.Zero;
2749 case XEventName.CreateNotify: {
2750 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
2751 msg.message = WM_CREATE;
2752 // Set up CreateStruct
2754 goto ProcessNextMessage;
2761 case XEventName.ReparentNotify: {
2762 if (hwnd.parent == null) { // Toplevel
2763 if (xevent.ReparentEvent.parent != IntPtr.Zero) {
2764 // We need to adjust x/y
2768 hwnd.Reparented = true;
2770 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);
2771 msg.message = Msg.WM_WINDOWPOSCHANGED;
2772 if (hwnd.opacity != 0xffffffff) {
2775 opacity = hwnd.opacity;
2776 XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), NetAtoms[(int)NA._NET_WM_WINDOW_OPACITY], Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
2779 hwnd.Reparented = false;
2780 goto ProcessNextMessage;
2786 case XEventName.ConfigureNotify: {
2787 if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
2788 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
2792 #if DriverDebugExtra
2793 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);
2795 msg.message = Msg.WM_WINDOWPOSCHANGED;
2796 hwnd.configure_pending = false;
2798 // We need to adjust our client window to track the resize of whole_window
2799 rect = hwnd.DefaultClientRect;
2801 ncp = new XplatUIWin32.NCCALCSIZE_PARAMS();
2802 ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp));
2804 ncp.rgrc1.left = rect.Left;
2805 ncp.rgrc1.top = rect.Top;
2806 ncp.rgrc1.right = rect.Right;
2807 ncp.rgrc1.bottom = rect.Bottom;
2809 Marshal.StructureToPtr(ncp, ptr, true);
2810 NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr);
2811 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
2812 Marshal.FreeHGlobal(ptr);
2814 // FIXME - debug this with Menus, need to set hwnd.ClientRect
2816 rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
2818 XMoveResizeWindow(DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
2820 goto ProcessNextMessage;
2823 msg.lParam=IntPtr.Zero; // FIXME - Generate LPWINDOWPOS structure and pass on
2827 case XEventName.FocusIn: {
2828 if (!hwnd.Enabled) {
2829 goto ProcessNextMessage;
2831 msg.message=Msg.WM_SETFOCUS;
2832 msg.wParam=IntPtr.Zero;
2836 case XEventName.FocusOut: {
2837 if (!hwnd.Enabled) {
2838 goto ProcessNextMessage;
2840 msg.message=Msg.WM_KILLFOCUS;
2841 msg.wParam=IntPtr.Zero;
2845 case XEventName.Expose: {
2846 if (PostQuitState) {
2847 goto ProcessNextMessage;
2852 if (!hwnd.expose_pending) {
2853 goto ProcessNextMessage;
2856 if (!hwnd.nc_expose_pending) {
2857 goto ProcessNextMessage;
2860 switch (hwnd.border_style) {
2861 case FormBorderStyle.Fixed3D: {
2864 g = Graphics.FromHwnd(hwnd.whole_window);
2865 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height));
2870 case FormBorderStyle.FixedSingle: {
2873 g = Graphics.FromHwnd(hwnd.whole_window);
2874 ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
2879 #if DriverDebugExtra
2880 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);
2883 Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
2884 Region region = new Region (rect);
2885 IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
2886 msg.message = Msg.WM_NCPAINT;
2888 hwnd.nc_expose_pending = false;
2891 #if DriverDebugExtra
2892 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);
2894 if (Caret.Visible == 1) {
2895 Caret.Paused = true;
2899 if (Caret.Visible == 1) {
2901 Caret.Paused = false;
2903 msg.message = Msg.WM_PAINT;
2907 case XEventName.DestroyNotify: {
2909 // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
2910 hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
2912 // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
2913 if (hwnd.client_window == xevent.DestroyWindowEvent.window) {
2914 msg.hwnd = hwnd.client_window;
2915 msg.message=Msg.WM_DESTROY;
2919 Console.WriteLine("Got DestroyNotify on Window {0:X}", msg.hwnd.ToInt32());
2922 goto ProcessNextMessage;
2928 case XEventName.ClientMessage: {
2929 if (Dnd.HandleClientMessage (ref xevent)) {
2930 goto ProcessNextMessage;
2933 if (xevent.ClientMessageEvent.message_type == (IntPtr)AsyncAtom) {
2934 XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
2938 if (xevent.ClientMessageEvent.message_type == (IntPtr)HoverState.Atom) {
2939 msg.message = Msg.WM_MOUSEHOVER;
2940 msg.wParam = GetMousewParam(0);
2941 msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
2945 if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
2946 msg.hwnd = xevent.ClientMessageEvent.ptr1;
2947 msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
2948 msg.wParam = xevent.ClientMessageEvent.ptr3;
2949 msg.lParam = xevent.ClientMessageEvent.ptr4;
2954 if (xevent.ClientMessageEvent.message_type == (IntPtr)NetAtoms[(int)NA._XEMBED]) {
2955 Console.WriteLine("GOT EMBED MESSAGE {0:X}", xevent.ClientMessageEvent.ptr2.ToInt32());
2960 if (xevent.ClientMessageEvent.message_type == (IntPtr)NetAtoms[(int)NA.WM_PROTOCOLS]) {
2961 if (xevent.ClientMessageEvent.ptr1 == (IntPtr)NetAtoms[(int)NA.WM_DELETE_WINDOW]) {
2962 msg.message = Msg.WM_CLOSE;
2963 Graphics.FromHdcInternal (IntPtr.Zero);
2967 // We should not get this, but I'll leave the code in case we need it in the future
2968 if (xevent.ClientMessageEvent.ptr1 == (IntPtr)NetAtoms[(int)NA.WM_TAKE_FOCUS]) {
2969 goto ProcessNextMessage;
2975 case XEventName.TimerNotify: {
2976 xevent.TimerNotifyEvent.handler (this, EventArgs.Empty);
2981 goto ProcessNextMessage;
2988 internal override bool GetText(IntPtr handle, out string text) {
2991 textptr = IntPtr.Zero;
2994 // FIXME - use _NET properties
2995 XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr);
2997 if (textptr != IntPtr.Zero) {
2998 text = Marshal.PtrToStringAnsi(textptr);
3007 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) {
3011 hwnd = Hwnd.ObjectFromHandle(handle);
3017 height = hwnd.height;
3019 rect = Hwnd.GetClientRectangle(hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height);
3021 client_width = rect.Width;
3022 client_height = rect.Height;
3027 // Should we throw an exception or fail silently?
3028 // throw new ArgumentException("Called with an invalid window handle", "handle");
3038 internal override FormWindowState GetWindowState(IntPtr handle) {
3043 IntPtr prop = IntPtr.Zero;
3047 XWindowAttributes attributes;
3050 hwnd = Hwnd.ObjectFromHandle(handle);
3054 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);
3055 if ((nitems > 0) && (prop != IntPtr.Zero)) {
3056 for (int i = 0; i < nitems; i++) {
3057 atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
3058 if ((atom == (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_HORZ]) || (atom == (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_MAXIMIZED_VERT])) {
3060 } else if (atom == (IntPtr)NetAtoms[(int)NA._NET_WM_STATE_HIDDEN]) {
3068 return FormWindowState.Minimized;
3069 } else if (maximized == 2) {
3070 return FormWindowState.Maximized;
3073 attributes = new XWindowAttributes();
3074 XGetWindowAttributes(DisplayHandle, handle, ref attributes);
3075 if (attributes.map_state == MapState.IsUnmapped) {
3076 throw new NotSupportedException("Cannot retrieve the state of an unmapped window");
3080 return FormWindowState.Normal;
3083 internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) {
3085 GrabConfined = Grab.Confined;
3086 GrabArea = Grab.Area;
3089 internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) {
3091 IntPtr confine_to_window;
3093 confine_to_window = IntPtr.Zero;
3095 if (confine_to_handle != IntPtr.Zero) {
3096 XWindowAttributes attributes = new XWindowAttributes();
3098 hwnd = Hwnd.ObjectFromHandle(confine_to_handle);
3101 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
3103 Grab.Area.X = attributes.x;
3104 Grab.Area.Y = attributes.y;
3105 Grab.Area.Width = attributes.width;
3106 Grab.Area.Height = attributes.height;
3107 Grab.Confined = true;
3108 confine_to_window = hwnd.client_window;
3113 hwnd = Hwnd.ObjectFromHandle(handle);
3116 XGrabPointer(DisplayHandle, hwnd.client_window, false,
3117 EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
3118 EventMask.ButtonReleaseMask | EventMask.PointerMotionMask,
3119 GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, 0, 0);
3123 internal override void UngrabWindow(IntPtr hwnd) {
3125 XUngrabPointer(DisplayHandle, 0);
3126 XFlush(DisplayHandle);
3128 Grab.Hwnd = IntPtr.Zero;
3129 Grab.Confined = false;
3132 internal override void HandleException(Exception e) {
3133 StackTrace st = new StackTrace(e, true);
3134 Console.WriteLine("Exception '{0}'", e.Message+st.ToString());
3135 Console.WriteLine("{0}{1}", e.Message, st.ToString());
3138 internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
3142 hwnd = Hwnd.ObjectFromHandle(handle);
3145 xevent = new XEvent ();
3146 xevent.type = XEventName.Expose;
3147 xevent.ExposeEvent.display = DisplayHandle;
3148 xevent.ExposeEvent.window = hwnd.client_window;
3151 xevent.ExposeEvent.x = hwnd.X;
3152 xevent.ExposeEvent.y = hwnd.Y;
3153 xevent.ExposeEvent.width = hwnd.Width;
3154 xevent.ExposeEvent.height = hwnd.Height;
3156 xevent.ExposeEvent.x = rc.X;
3157 xevent.ExposeEvent.y = rc.Y;
3158 xevent.ExposeEvent.width = rc.Width;
3159 xevent.ExposeEvent.height = rc.Height;
3165 internal override bool IsEnabled(IntPtr handle) {
3166 return Hwnd.ObjectFromHandle(handle).Enabled;
3169 internal override bool IsVisible(IntPtr handle) {
3170 return Hwnd.ObjectFromHandle(handle).visible;
3173 internal override void KillTimer(Timer timer) {
3175 TimerList.Remove(timer);
3179 internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) {
3185 hwnd = Hwnd.ObjectFromHandle(handle);
3188 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
3195 internal override void OverrideCursor(IntPtr cursor) {
3196 OverrideCursorHandle = cursor;
3199 internal override PaintEventArgs PaintEventStart(IntPtr handle, bool client) {
3200 PaintEventArgs paint_event;
3203 hwnd = Hwnd.ObjectFromHandle(handle);
3205 if (Caret.Visible == 1) {
3206 Caret.Paused = true;
3211 hwnd.client_dc = Graphics.FromHwnd (hwnd.client_window);
3212 hwnd.client_dc.SetClip(hwnd.invalid);
3213 paint_event = new PaintEventArgs(hwnd.client_dc, hwnd.invalid);
3214 hwnd.expose_pending = false;
3218 hwnd.client_dc = Graphics.FromHwnd (hwnd.whole_window);
3219 paint_event = new PaintEventArgs(hwnd.client_dc, new Rectangle(0, 0, hwnd.width, hwnd.height));
3220 hwnd.nc_expose_pending = false;
3226 internal override void PaintEventEnd(IntPtr handle, bool client) {
3229 hwnd = Hwnd.ObjectFromHandle(handle);
3232 hwnd.ClearInvalidArea();
3235 hwnd.client_dc.Flush();
3236 hwnd.client_dc.Dispose();
3237 hwnd.client_dc = null;
3239 if (Caret.Visible == 1) {
3241 Caret.Paused = false;
3245 internal override bool PeekMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
3248 // FIXME - imlement filtering
3250 if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
3251 throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
3255 if (MessageQueue.Count > 0) {
3258 // Only call UpdateMessageQueue if real events are pending
3259 // otherwise we go to sleep on the socket
3260 if (XPending(DisplayHandle) != 0) {
3261 UpdateMessageQueue();
3266 CheckTimers(DateTime.Now);
3271 return GetMessage(ref msg, hWnd, wFilterMin, wFilterMax);
3274 // FIXME - I think this should just enqueue directly
3275 internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) {
3276 XEvent xevent = new XEvent ();
3277 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
3279 xevent.type = XEventName.ClientMessage;
3280 xevent.ClientMessageEvent.display = DisplayHandle;
3283 xevent.ClientMessageEvent.window = hwnd.whole_window;
3285 xevent.ClientMessageEvent.window = IntPtr.Zero;
3288 xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
3289 xevent.ClientMessageEvent.format = 32;
3290 xevent.ClientMessageEvent.ptr1 = handle;
3291 xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
3292 xevent.ClientMessageEvent.ptr3 = wparam;
3293 xevent.ClientMessageEvent.ptr4 = lparam;
3295 MessageQueue.Enqueue (xevent);
3300 internal override void PostQuitMessage(int exitCode) {
3301 XFlush(DisplayHandle);
3302 PostQuitState = true;
3304 // Remove our display handle from S.D
3305 Graphics.FromHdcInternal (IntPtr.Zero);
3308 internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) {
3314 hwnd = Hwnd.ObjectFromHandle(handle);
3317 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
3324 internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) {
3330 hwnd = Hwnd.ObjectFromHandle(handle);
3333 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
3340 internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
3343 XGCValues gc_values;
3345 hwnd = Hwnd.ObjectFromHandle(handle);
3347 if (hwnd.invalid != Rectangle.Empty) {
3348 // BIG FAT WARNING. This only works with how we use this function right now
3349 // where we basically still scroll the whole window, but work around areas
3350 // that are covered by our children
3352 hwnd.invalid.X += XAmount;
3353 hwnd.invalid.Y += YAmount;
3355 if (hwnd.invalid.X < 0) {
3356 hwnd.invalid.Width += hwnd.invalid.X;
3360 if (hwnd.invalid.Y < 0) {
3361 hwnd.invalid.Height += hwnd.invalid.Y;
3366 gc_values = new XGCValues();
3368 if (with_children) {
3369 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
3372 gc = XCreateGC(DisplayHandle, hwnd.client_window, 0, ref gc_values);
3374 XCopyArea(DisplayHandle, hwnd.client_window, hwnd.client_window, gc, area.X - XAmount, area.Y - YAmount, area.Width, area.Height, area.X, area.Y);
3376 // Generate an expose for the area exposed by the horizontal scroll
3378 hwnd.AddInvalidArea (area.X, area.Y, XAmount, area.Height);
3379 } else if (XAmount < 0) {
3380 hwnd.AddInvalidArea (XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
3383 // Generate an expose for the area exposed by the vertical scroll
3385 hwnd.AddInvalidArea (area.X, area.Y, area.Width, YAmount);
3386 } else if (YAmount < 0) {
3387 hwnd.AddInvalidArea (area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
3389 XFreeGC(DisplayHandle, gc);
3391 UpdateWindow(handle);
3394 internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) {
3397 hwnd = Hwnd.GetObjectFromWindow(handle);
3399 ScrollWindow(handle, hwnd.ClientRect, XAmount, YAmount, with_children);
3402 internal override void SendAsyncMethod (AsyncMethodData method) {
3403 XEvent xevent = new XEvent ();
3405 xevent.type = XEventName.ClientMessage;
3406 xevent.ClientMessageEvent.display = DisplayHandle;
3407 xevent.ClientMessageEvent.window = FosterParent;
3408 xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
3409 xevent.ClientMessageEvent.format = 32;
3410 xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
3412 MessageQueue.EnqueueLocked (xevent);
3417 internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) {
3418 return NativeWindow.WndProc(hwnd, message, wParam, lParam);
3421 internal override void SetAllowDrop (IntPtr handle, bool value)
3423 // We allow drop on all windows
3426 internal override DragDropEffects StartDrag (IntPtr handle, object data,
3427 DragDropEffects allowed_effects)
3429 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
3432 throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
3434 return Dnd.StartDrag (hwnd.client_window, data, allowed_effects);
3437 internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
3440 hwnd = Hwnd.ObjectFromHandle(handle);
3442 hwnd.border_style = border_style;
3444 XMoveResizeWindow(DisplayHandle, hwnd.client_window, hwnd.ClientRect.X, hwnd.ClientRect.Y, hwnd.ClientRect.Width, hwnd.ClientRect.Height);
3446 InvalidateWholeWindow(handle);
3449 internal override void SetCaretPos(IntPtr handle, int x, int y) {
3450 if (Caret.Hwnd == handle) {
3457 if (Caret.Visible == 1) {
3459 Caret.Timer.Start();
3464 internal override void SetCursor(IntPtr handle, IntPtr cursor) {
3467 if (OverrideCursorHandle == IntPtr.Zero) {
3468 if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
3472 LastCursorHandle = cursor;
3473 LastCursorWindow = handle;
3475 hwnd = Hwnd.ObjectFromHandle(handle);
3477 if (cursor != IntPtr.Zero) {
3478 XDefineCursor(DisplayHandle, hwnd.whole_window, cursor);
3480 XUndefineCursor(DisplayHandle, hwnd.whole_window);
3486 hwnd = Hwnd.ObjectFromHandle(handle);
3488 XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
3492 internal override void SetCursorPos(IntPtr handle, int x, int y) {
3493 if (handle == IntPtr.Zero) {
3495 XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x, y);
3501 hwnd = Hwnd.ObjectFromHandle(handle);
3503 XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
3509 internal override void SetFocus(IntPtr handle) {
3512 hwnd = Hwnd.ObjectFromHandle(handle);
3514 if (FocusWindow != IntPtr.Zero) {
3515 PostMessage(FocusWindow, Msg.WM_KILLFOCUS, hwnd.client_window, IntPtr.Zero);
3517 PostMessage(hwnd.client_window, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero);
3518 FocusWindow = hwnd.client_window;
3520 //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
3523 internal override void SetIcon(IntPtr handle, Icon icon) {
3526 hwnd = Hwnd.ObjectFromHandle(handle);
3528 SetIcon(hwnd, icon);
3532 internal override void SetMenu(IntPtr handle, Menu menu) {
3535 hwnd = Hwnd.ObjectFromHandle(handle);
3538 // FIXME - do we need to trigger some resize?
3541 internal override void SetModal(IntPtr handle, bool Modal) {
3543 ModalWindows.Push(handle);
3545 if (ModalWindows.Contains(handle)) {
3548 if (ModalWindows.Count > 0) {
3549 Activate((IntPtr)ModalWindows.Peek());
3554 internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
3557 hwnd = Hwnd.ObjectFromHandle(handle);
3558 hwnd.parent = Hwnd.ObjectFromHandle(parent);
3562 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());
3564 XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent.client_window, hwnd.x, hwnd.y);
3570 internal override void SetTimer (Timer timer) {
3572 TimerList.Add(timer);
3577 internal override bool SetTopmost(IntPtr handle, IntPtr handle_owner, bool enabled) {
3581 hwnd = Hwnd.ObjectFromHandle(handle);
3583 if (handle_owner != IntPtr.Zero) {
3584 hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
3591 if (hwnd_owner != null) {
3592 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
3594 XSetTransientForHint(DisplayHandle, hwnd.whole_window, FosterParent);
3599 XDeleteProperty(DisplayHandle, hwnd.whole_window, (int)Atom.XA_WM_TRANSIENT_FOR);
3605 internal override bool SetVisible(IntPtr handle, bool visible) {
3608 hwnd = Hwnd.ObjectFromHandle(handle);
3609 hwnd.visible = visible;
3613 if (Control.FromHandle(handle) is Form) {
3616 s = ((Form)Control.FromHandle(handle)).WindowState;
3618 XMapWindow(DisplayHandle, hwnd.whole_window);
3619 XMapWindow(DisplayHandle, hwnd.client_window);
3622 case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break;
3623 case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break;
3626 XMapWindow(DisplayHandle, hwnd.whole_window);
3627 XMapWindow(DisplayHandle, hwnd.client_window);
3630 XUnmapWindow(DisplayHandle, hwnd.whole_window);
3636 internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
3640 hwnd = Hwnd.ObjectFromHandle(handle);
3645 hints = new XSizeHints();
3647 if (min != Size.Empty) {
3648 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
3649 hints.min_width = min.Width;
3650 hints.min_height = min.Height;
3653 if (max != Size.Empty) {
3654 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
3655 hints.max_width = max.Width;
3656 hints.max_height = max.Height;
3659 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints);
3661 if (maximized != Rectangle.Empty) {
3662 hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
3663 hints.x = maximized.X;
3664 hints.y = maximized.Y;
3665 hints.width = maximized.Width;
3666 hints.height = maximized.Height;
3668 // Metacity does not seem to follow this constraint for maximized (zoomed) windows
3669 XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints);
3674 internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
3676 Rectangle client_rect;
3678 hwnd = Hwnd.ObjectFromHandle(handle);
3680 // X requires a sanity check for width & height; otherwise it dies
3681 if (hwnd.zero_sized && width > 0 && height > 0) {
3683 XMapWindow(DisplayHandle, hwnd.whole_window);
3685 hwnd.zero_sized = false;
3689 hwnd.zero_sized = true;
3690 XUnmapWindow(DisplayHandle, hwnd.whole_window);
3694 hwnd.zero_sized = true;
3695 XUnmapWindow(DisplayHandle, hwnd.whole_window);
3698 client_rect = Hwnd.GetClientRectangle(hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height);
3700 // Save a server roundtrip (and prevent a feedback loop)
3701 if ((hwnd.x == x) && (hwnd.y == y) &&
3702 (hwnd.width == width) && (hwnd.height == height) &&
3703 (hwnd.ClientRect == client_rect)) {
3707 if (!hwnd.zero_sized) {
3709 XMoveResizeWindow(DisplayHandle, hwnd.whole_window, x, y, width, height);
3710 XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
3714 // Prevent an old queued ConfigureNotify from setting our width with outdated data, set it now
3716 hwnd.height = height;
3719 internal override void SetWindowState(IntPtr handle, FormWindowState state) {
3720 FormWindowState current_state;
3723 hwnd = Hwnd.ObjectFromHandle(handle);
3725 current_state = GetWindowState(handle);
3727 if (current_state == state) {
3732 case FormWindowState.Normal: {
3734 if (current_state == FormWindowState.Minimized) {
3735 XMapWindow(DisplayHandle, hwnd.whole_window);
3736 XMapWindow(DisplayHandle, hwnd.client_window);
3737 } else if (current_state == FormWindowState.Maximized) {
3738 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]);
3745 case FormWindowState.Minimized: {
3747 if (current_state == FormWindowState.Maximized) {
3748 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]);
3750 XIconifyWindow(DisplayHandle, hwnd.whole_window, 0);
3755 case FormWindowState.Maximized: {
3757 if (current_state == FormWindowState.Minimized) {
3758 XMapWindow(DisplayHandle, hwnd.whole_window);
3759 XMapWindow(DisplayHandle, hwnd.client_window);
3762 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]);
3770 internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
3773 hwnd = Hwnd.ObjectFromHandle(handle);
3774 SetHwndStyles(hwnd, cp);
3775 SetWMStyles(hwnd, cp);
3778 internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) {
3782 hwnd = Hwnd.ObjectFromHandle(handle);
3788 hwnd.opacity = (uint)(0xffffffff * transparency);
3789 opacity = hwnd.opacity;
3791 if (hwnd.reparented) {
3792 XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), NetAtoms[(int)NA._NET_WM_WINDOW_OPACITY], Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
3796 internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) {
3797 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
3801 XRaiseWindow(DisplayHandle, hwnd.whole_window);
3804 } else if (!bottom) {
3805 Hwnd after_hwnd = null;
3807 if (after_handle != IntPtr.Zero) {
3808 after_hwnd = Hwnd.ObjectFromHandle(after_handle);
3811 XWindowChanges values = new XWindowChanges();
3813 if (after_hwnd == null) {
3814 throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order");
3816 values.sibling = after_hwnd.whole_window;
3817 values.stack_mode = StackMode.Below;
3820 XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
3825 XLowerWindow(DisplayHandle, hwnd.whole_window);
3832 internal override void ShowCursor(bool show) {
3833 ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
3836 internal override void StartLoop(Thread thread) {
3837 // Future place for prepping a new queue for this specific thread
3840 internal override bool SupportsTransparency() {
3841 // We need to check if the x compositing manager is running
3845 internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) {
3846 GetSystrayManagerWindow();
3848 if (SystrayMgrWindow != IntPtr.Zero) {
3850 XSizeHints size_hints;
3853 hwnd = Hwnd.ObjectFromHandle(handle);
3855 Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
3858 XUnmapWindow(DisplayHandle, hwnd.whole_window);
3859 XUnmapWindow(DisplayHandle, hwnd.client_window);
3862 XDestroyWindow(DisplayHandle, hwnd.client_window);
3863 hwnd.client_window = hwnd.whole_window;
3865 size_hints = new XSizeHints();
3867 size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
3868 size_hints.min_width = icon.Width;
3869 size_hints.min_height = icon.Height;
3871 size_hints.max_width = icon.Width;
3872 size_hints.max_height = icon.Height;
3874 size_hints.base_width = icon.Width;
3875 size_hints.base_height = icon.Height;
3876 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints);
3878 atoms = new uint[2];
3879 atoms[0] = 1; // Version 1
3880 atoms[1] = 0; // We're not mapped
3882 // This line cost me 3 days...
3883 XChangeProperty(DisplayHandle, hwnd.whole_window, NetAtoms[(int)NA._XEMBED_INFO], NetAtoms[(int)NA._XEMBED_INFO], 32, PropertyMode.Replace, atoms, 2);
3885 // Need to pick some reasonable defaults
3887 tt.AutomaticDelay = 100;
3888 tt.InitialDelay = 250;
3889 tt.ReshowDelay = 250;
3890 tt.ShowAlways = true;
3892 if ((tip != null) && (tip != string.Empty)) {
3893 tt.SetToolTip(Control.FromHandle(handle), tip);
3899 // Make sure the window exists
3900 XSync(DisplayHandle, hwnd.whole_window);
3902 SendNetClientMessage(SystrayMgrWindow, (IntPtr)NetAtoms[(int)NA._NET_SYSTEM_TRAY_OPCODE], IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
3909 internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) {
3912 control = Control.FromHandle(handle);
3913 if (control != null && tt != null) {
3914 tt.SetToolTip(control, tip);
3922 internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
3925 hwnd = Hwnd.ObjectFromHandle(handle);
3927 XUnmapWindow(DisplayHandle, hwnd.whole_window);
3928 SetParent(hwnd.whole_window, FosterParent);
3930 // The caller can now re-dock it later...
3937 internal override bool Text(IntPtr handle, string text) {
3939 // FIXME - use _NET properties
3940 XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text);
3945 internal override bool TranslateMessage(ref MSG msg) {
3946 return Keyboard.TranslateMessage (ref msg);
3949 internal override void UpdateWindow(IntPtr handle) {
3953 hwnd = Hwnd.ObjectFromHandle(handle);
3955 if (!hwnd.visible || hwnd.expose_pending) {
3960 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
3962 xevent = new XEvent();
3963 xevent.type = XEventName.Expose;
3964 xevent.ExposeEvent.display = DisplayHandle;
3965 xevent.ExposeEvent.window = hwnd.client_window;
3967 MessageQueue.Enqueue(xevent);
3968 hwnd.expose_pending = true;
3971 #endregion // Public Static Methods
3974 internal override event EventHandler Idle;
3975 #endregion // Events
3978 [DllImport ("libX11", EntryPoint="XOpenDisplay")]
3979 internal extern static IntPtr XOpenDisplay(IntPtr display);
3980 [DllImport ("libX11", EntryPoint="XCloseDisplay")]
3981 internal extern static int XCloseDisplay(IntPtr display);
3982 [DllImport ("libX11", EntryPoint="XSynchronize")]
3983 internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
3985 [DllImport ("libX11", EntryPoint="XCreateWindow")]
3986 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);
3987 [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
3988 internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int border, int background);
3989 [DllImport ("libX11", EntryPoint="XMapWindow")]
3990 internal extern static int XMapWindow(IntPtr display, IntPtr window);
3991 [DllImport ("libX11", EntryPoint="XUnmapWindow")]
3992 internal extern static int XUnmapWindow(IntPtr display, IntPtr window);
3993 [DllImport ("libX11", EntryPoint="XMapSubwindows")]
3994 internal extern static int XMapSubindows(IntPtr display, IntPtr window);
3995 [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
3996 internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
3997 [DllImport ("libX11", EntryPoint="XRootWindow")]
3998 internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
3999 [DllImport ("libX11", EntryPoint="XNextEvent")]
4000 internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
4001 [DllImport ("libX11")]
4002 internal extern static int XConnectionNumber (IntPtr diplay);
4003 [DllImport ("libX11")]
4004 internal extern static int XPending (IntPtr diplay);
4005 [DllImport ("libX11")]
4006 internal extern static bool XCheckWindowEvent (IntPtr display, IntPtr window, EventMask mask, ref XEvent xevent);
4007 [DllImport ("libX11")]
4008 internal extern static bool XCheckMaskEvent (IntPtr display, EventMask mask, ref XEvent xevent);
4009 [DllImport ("libX11", EntryPoint="XSelectInput")]
4010 internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, EventMask mask);
4012 [DllImport ("libX11", EntryPoint="XDestroyWindow")]
4013 internal extern static int XDestroyWindow(IntPtr display, IntPtr window);
4015 [DllImport ("libX11", EntryPoint="XReparentWindow")]
4016 internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
4017 [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
4018 internal extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
4020 [DllImport ("libX11", EntryPoint="XResizeWindow")]
4021 internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
4023 [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
4024 internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
4026 [DllImport ("libX11", EntryPoint="XFlush")]
4027 internal extern static int XFlush(IntPtr display);
4029 [DllImport ("libX11", EntryPoint="XSetWMName")]
4030 internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
4032 [DllImport ("libX11", EntryPoint="XStoreName")]
4033 internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
4035 [DllImport ("libX11", EntryPoint="XFetchName")]
4036 internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
4038 [DllImport ("libX11", EntryPoint="XSendEvent")]
4039 internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, EventMask event_mask, ref XEvent send_event);
4041 [DllImport ("libX11", EntryPoint="XQueryTree")]
4042 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);
4044 [DllImport ("libX11", EntryPoint="XFree")]
4045 internal extern static int XFree(IntPtr data);
4047 [DllImport ("libX11", EntryPoint="XRaiseWindow")]
4048 internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
4050 [DllImport ("libX11", EntryPoint="XLowerWindow")]
4051 internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
4053 [DllImport ("libX11", EntryPoint="XConfigureWindow")]
4054 internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
4056 [DllImport ("libX11", EntryPoint="XInternAtom")]
4057 internal extern static int XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
4059 [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
4060 internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, uint[] protocols, int count);
4062 [DllImport ("libX11", EntryPoint="XGrabPointer")]
4063 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);
4065 [DllImport ("libX11", EntryPoint="XUngrabPointer")]
4066 internal extern static int XUngrabPointer(IntPtr display, uint timestamp);
4068 [DllImport ("libX11", EntryPoint="XQueryPointer")]
4069 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);
4071 [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
4072 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);
4074 [DllImport ("libX11", EntryPoint="XGetGeometry")]
4075 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);
4077 [DllImport ("libX11", EntryPoint="XGetGeometry")]
4078 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);
4080 [DllImport ("libX11", EntryPoint="XGetGeometry")]
4081 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);
4083 [DllImport ("libX11", EntryPoint="XGetGeometry")]
4084 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);
4086 [DllImport ("libX11", EntryPoint="XWarpPointer")]
4087 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);
4089 [DllImport ("libX11", EntryPoint="XClearWindow")]
4090 internal extern static int XClearWindow(IntPtr display, IntPtr window);
4092 [DllImport ("libX11", EntryPoint="XClearArea")]
4093 internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
4096 [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
4097 internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
4099 [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
4100 internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
4102 [DllImport ("libX11", EntryPoint="XDefaultVisual")]
4103 internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
4105 [DllImport ("libX11", EntryPoint="XDefaultDepth")]
4106 internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
4108 [DllImport ("libX11", EntryPoint="XDefaultColormap")]
4109 internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
4111 [DllImport ("libX11", EntryPoint="XLookupColor")]
4112 internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
4114 [DllImport ("libX11", EntryPoint="XAllocColor")]
4115 internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
4117 [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
4118 internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
4120 [DllImport ("libX11", EntryPoint="XChangeProperty")]
4121 internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, int type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
4123 [DllImport ("libX11", EntryPoint="XChangeProperty")]
4124 internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, uint[] atoms, int nelements);
4126 [DllImport ("libX11", EntryPoint="XChangeProperty")]
4127 internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, ref uint value, int nelements);
4129 [DllImport ("libX11", EntryPoint="XChangeProperty")]
4130 internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, uint[] atoms, int nelements);
4132 [DllImport ("libX11", EntryPoint="XChangeProperty")]
4133 internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, IntPtr atoms, int nelements);
4135 [DllImport ("libX11", EntryPoint="XChangeProperty")]
4136 internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, IntPtr atoms, int nelements);
4138 [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
4139 internal extern static int XChangeProperty(IntPtr display, IntPtr window, int property, int type, int format, PropertyMode mode, string text, int text_length);
4141 [DllImport ("libX11", EntryPoint="XDeleteProperty")]
4142 internal extern static int XDeleteProperty(IntPtr display, IntPtr window, int property);
4144 [DllImport ("gdiplus", EntryPoint="GetFontMetrics")]
4145 internal extern static bool GetFontMetrics(IntPtr graphicsObject, IntPtr nativeObject, out int ascent, out int descent);
4148 [DllImport ("libX11", EntryPoint="XCreateGC")]
4149 internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, GCFunction valuemask, ref XGCValues values);
4151 [DllImport ("libX11", EntryPoint="XFreeGC")]
4152 internal extern static int XFreeGC(IntPtr display, IntPtr gc);
4154 [DllImport ("libX11", EntryPoint="XSetFunction")]
4155 internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
4157 [DllImport ("libX11", EntryPoint="XDrawLine")]
4158 internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
4160 [DllImport ("libX11", EntryPoint="XDrawRectangle")]
4161 internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
4163 [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
4164 internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
4166 [DllImport ("libX11", EntryPoint="XCopyArea")]
4167 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);
4169 [DllImport ("libX11", EntryPoint="XGetAtomName")]
4170 internal extern static string XGetAtomName(IntPtr display, int atom);
4172 [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
4173 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);
4175 [DllImport ("libX11", EntryPoint="XSetInputFocus")]
4176 internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
4178 [DllImport ("libX11", EntryPoint="XIconifyWindow")]
4179 internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
4181 [DllImport ("libX11", EntryPoint="XDefineCursor")]
4182 internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
4184 [DllImport ("libX11", EntryPoint="XUndefineCursor")]
4185 internal extern static int XUndefineCursor(IntPtr display, IntPtr window);
4187 [DllImport ("libX11", EntryPoint="XFreeCursor")]
4188 internal extern static int XFreeCursor(IntPtr display, IntPtr cursor);
4190 [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
4191 internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
4193 [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
4194 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);
4196 [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
4197 internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
4199 [DllImport ("libX11", EntryPoint="XFreePixmap")]
4200 internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
4202 [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
4203 internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
4205 [DllImport ("libX11", EntryPoint="XWhitePixel")]
4206 internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
4208 [DllImport ("libX11", EntryPoint="XBlackPixel")]
4209 internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
4211 [DllImport ("libX11", EntryPoint="XGrabServer")]
4212 internal extern static void XGrabServer(IntPtr display);
4214 [DllImport ("libX11", EntryPoint="XUngrabServer")]
4215 internal extern static void XUngrabServer(IntPtr display);
4217 [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
4218 internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
4220 [DllImport ("libX11", EntryPoint="XSetZoomHints")]
4221 internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
4223 [DllImport ("libX11", EntryPoint="XSetWMHints")]
4224 internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
4226 [DllImport ("libX11", EntryPoint="XSync")]
4227 internal extern static void XSync(IntPtr display, IntPtr window);
4229 [DllImport ("libX11", EntryPoint="XGetIconSizes")]
4230 internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
4232 [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
4233 internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
4235 [DllImport ("libX11", EntryPoint="XGetErrorText")]
4236 internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
4238 [DllImport ("libX11", EntryPoint="XInitThreads")]
4239 internal extern static int XInitThreads();
4241 [DllImport ("libX11", EntryPoint="XConvertSelection")]
4242 internal extern static int XConvertSelection(IntPtr display, int selection, int target, int property, IntPtr requestor, IntPtr time);
4244 [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
4245 internal extern static IntPtr XGetSelectionOwner(IntPtr display, int selection);
4247 [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
4248 internal extern static int XSetSelectionOwner(IntPtr display, int selection, IntPtr owner, IntPtr time);
4250 [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
4251 internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, uint mask);
4253 [DllImport ("libX11", EntryPoint="XSetForeground")]
4254 internal extern static int XSetForeground(IntPtr display, IntPtr gc, uint foreground);
4256 [DllImport ("libX11", EntryPoint="XSetBackground")]
4257 internal extern static int XSetBackground(IntPtr display, IntPtr gc, uint background);
4259 [DllImport ("libX11", EntryPoint="XBell")]
4260 internal extern static int XBell(IntPtr display, int percent);