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
44 #undef DriverDebugParent
45 #undef DriverDebugCreate
46 #undef DriverDebugDestroy
47 #undef DriverDebugThreads
48 #undef DriverDebugXEmbed
51 using System.ComponentModel;
52 using System.Collections;
53 using System.Diagnostics;
55 using System.Drawing.Drawing2D;
56 using System.Drawing.Imaging;
59 using System.Net.Sockets;
60 using System.Reflection;
61 using System.Runtime.InteropServices;
63 using System.Threading;
65 // Only do the poll when building with mono for now
67 using Mono.Unix.Native;
71 namespace System.Windows.Forms {
72 internal class XplatUIX11 : XplatUIDriver {
73 #region Local Variables
75 static volatile XplatUIX11 Instance;
76 private static int RefCount;
77 private static object XlibLock; // Our locking object
78 private static bool themes_enabled;
81 private static IntPtr DisplayHandle; // X11 handle to display
82 private static int ScreenNo; // Screen number used
83 private static IntPtr DefaultColormap; // Colormap for screen
84 private static IntPtr CustomVisual; // Visual for window creation
85 private static IntPtr CustomColormap; // Colormap for window creation
86 private static IntPtr RootWindow; // Handle of the root window for the screen/display
87 private static IntPtr FosterParent; // Container to hold child windows until their parent exists
88 private static XErrorHandler ErrorHandler; // Error handler delegate
89 private static bool ErrorExceptions; // Throw exceptions on X errors
90 private int render_major_opcode;
91 private int render_first_event;
92 private int render_first_error;
95 private static IntPtr ClipMagic;
96 private static ClipboardStruct Clipboard; // Our clipboard
99 private static IntPtr PostAtom; // PostMessage atom
100 private static IntPtr AsyncAtom; // Support for async messages
103 private static Hashtable MessageQueues; // Holds our thread-specific XEventQueues
104 private static ArrayList unattached_timer_list; // holds timers that are enabled but not attached to a window.
106 private static Pollfd[] pollfds; // For watching the X11 socket
107 private static bool wake_waiting;
108 private static object wake_waiting_lock = new object ();
110 private static X11Keyboard Keyboard; //
111 private static X11Dnd Dnd;
112 private static Socket listen; //
113 private static Socket wake; //
114 private static Socket wake_receive; //
115 private static byte[] network_buffer; //
116 private static bool detectable_key_auto_repeat;
119 private static IntPtr ActiveWindow; // Handle of the active window
120 private static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any)
123 private static Stack ModalWindows; // Stack of our modal windows
126 private static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window
129 private static IntPtr LastCursorWindow; // The last window we set the cursor on
130 private static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
131 private static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
134 private static CaretStruct Caret; //
136 // Last window containing the pointer
137 private static IntPtr LastPointerWindow; // The last window containing the pointer
140 private static IntPtr WM_PROTOCOLS;
141 private static IntPtr WM_DELETE_WINDOW;
142 private static IntPtr WM_TAKE_FOCUS;
143 //private static IntPtr _NET_SUPPORTED;
144 //private static IntPtr _NET_CLIENT_LIST;
145 //private static IntPtr _NET_NUMBER_OF_DESKTOPS;
146 private static IntPtr _NET_DESKTOP_GEOMETRY;
147 //private static IntPtr _NET_DESKTOP_VIEWPORT;
148 private static IntPtr _NET_CURRENT_DESKTOP;
149 //private static IntPtr _NET_DESKTOP_NAMES;
150 private static IntPtr _NET_ACTIVE_WINDOW;
151 private static IntPtr _NET_WORKAREA;
152 //private static IntPtr _NET_SUPPORTING_WM_CHECK;
153 //private static IntPtr _NET_VIRTUAL_ROOTS;
154 //private static IntPtr _NET_DESKTOP_LAYOUT;
155 //private static IntPtr _NET_SHOWING_DESKTOP;
156 //private static IntPtr _NET_CLOSE_WINDOW;
157 //private static IntPtr _NET_MOVERESIZE_WINDOW;
158 //private static IntPtr _NET_WM_MOVERESIZE;
159 //private static IntPtr _NET_RESTACK_WINDOW;
160 //private static IntPtr _NET_REQUEST_FRAME_EXTENTS;
161 private static IntPtr _NET_WM_NAME;
162 //private static IntPtr _NET_WM_VISIBLE_NAME;
163 //private static IntPtr _NET_WM_ICON_NAME;
164 //private static IntPtr _NET_WM_VISIBLE_ICON_NAME;
165 //private static IntPtr _NET_WM_DESKTOP;
166 private static IntPtr _NET_WM_WINDOW_TYPE;
167 private static IntPtr _NET_WM_STATE;
168 //private static IntPtr _NET_WM_ALLOWED_ACTIONS;
169 //private static IntPtr _NET_WM_STRUT;
170 //private static IntPtr _NET_WM_STRUT_PARTIAL;
171 //private static IntPtr _NET_WM_ICON_GEOMETRY;
172 private static IntPtr _NET_WM_ICON;
173 //private static IntPtr _NET_WM_PID;
174 //private static IntPtr _NET_WM_HANDLED_ICONS;
175 private static IntPtr _NET_WM_USER_TIME;
176 private static IntPtr _NET_FRAME_EXTENTS;
177 //private static IntPtr _NET_WM_PING;
178 //private static IntPtr _NET_WM_SYNC_REQUEST;
179 private static IntPtr _NET_SYSTEM_TRAY_S;
180 //private static IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
181 private static IntPtr _NET_SYSTEM_TRAY_OPCODE;
182 private static IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
183 private static IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
184 private static IntPtr _XEMBED;
185 private static IntPtr _XEMBED_INFO;
186 private static IntPtr _MOTIF_WM_HINTS;
187 private static IntPtr _NET_WM_STATE_SKIP_TASKBAR;
188 private static IntPtr _NET_WM_STATE_ABOVE;
189 private static IntPtr _NET_WM_STATE_MODAL;
190 private static IntPtr _NET_WM_STATE_HIDDEN;
191 private static IntPtr _NET_WM_CONTEXT_HELP;
192 private static IntPtr _NET_WM_WINDOW_OPACITY;
193 //private static IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
194 //private static IntPtr _NET_WM_WINDOW_TYPE_DOCK;
195 //private static IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
196 //private static IntPtr _NET_WM_WINDOW_TYPE_MENU;
197 private static IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
198 //private static IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
199 private static IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
200 private static IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
201 private static IntPtr CLIPBOARD;
202 private static IntPtr PRIMARY;
203 //private static IntPtr DIB;
204 private static IntPtr OEMTEXT;
205 private static IntPtr UNICODETEXT;
206 private static IntPtr TARGETS;
208 // mouse hover message generation
209 private static HoverStruct HoverState; //
211 // double click message generation
212 private static ClickStruct ClickPending; //
214 // Support for mouse grab
215 private static GrabStruct Grab; //
218 Point mouse_position; // Last position of mouse, in screen coords
219 internal static MouseButtons MouseState; // Last state of mouse buttons
222 private static int DoubleClickInterval; // msec; max interval between clicks to count as double click
224 const EventMask SelectInputMask = (EventMask.ButtonPressMask |
225 EventMask.ButtonReleaseMask |
226 EventMask.KeyPressMask |
227 EventMask.KeyReleaseMask |
228 EventMask.EnterWindowMask |
229 EventMask.LeaveWindowMask |
230 EventMask.ExposureMask |
231 EventMask.FocusChangeMask |
232 EventMask.PointerMotionMask |
233 EventMask.PointerMotionHintMask |
234 EventMask.SubstructureNotifyMask);
236 static readonly object lockobj = new object ();
238 #endregion // Local Variables
240 private XplatUIX11() {
241 // Handle singleton stuff first
244 // Now regular initialization
245 XlibLock = new object ();
246 X11Keyboard.XlibLock = XlibLock;
247 MessageQueues = Hashtable.Synchronized (new Hashtable(7));
248 unattached_timer_list = ArrayList.Synchronized (new ArrayList (3));
251 ErrorExceptions = false;
253 // X11 Initialization
254 SetDisplay(XOpenDisplay(IntPtr.Zero));
255 X11DesktopColors.Initialize();
258 // Disable keyboard autorepeat
260 XkbSetDetectableAutoRepeat (DisplayHandle, true, IntPtr.Zero);
261 detectable_key_auto_repeat = true;
263 Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually.");
264 detectable_key_auto_repeat = false;
267 // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does)
268 ErrorHandler = new XErrorHandler(HandleError);
269 XSetErrorHandler(ErrorHandler);
273 // Remove our display handle from S.D
274 Graphics.FromHdcInternal (IntPtr.Zero);
277 #endregion // Constructors
279 #region Singleton Specific Code
280 public static XplatUIX11 GetInstance() {
282 if (Instance == null) {
283 Instance=new XplatUIX11();
290 public int Reference {
297 #region Internal Properties
298 internal static IntPtr Display {
300 return DisplayHandle;
304 XplatUIX11.GetInstance().SetDisplay(value);
308 internal static int Screen {
318 internal static IntPtr RootWindowHandle {
328 internal static IntPtr Visual {
334 CustomVisual = value;
338 internal static IntPtr ColorMap {
340 return CustomColormap;
344 CustomColormap = value;
349 #region XExceptionClass
350 internal class XException : ApplicationException {
354 XRequest RequestCode;
358 public XException(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
359 this.Display = Display;
360 this.ResourceID = ResourceID;
361 this.Serial = Serial;
362 this.RequestCode = RequestCode;
363 this.ErrorCode = ErrorCode;
364 this.MinorCode = MinorCode;
367 public override string Message {
369 return GetMessage(Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode);
373 public static string GetMessage(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
382 sb = new StringBuilder(160);
383 XGetErrorText(Display, ErrorCode, sb, sb.Capacity);
384 x_error_text = sb.ToString();
385 hwnd = Hwnd.ObjectFromHandle(ResourceID);
387 hwnd_text = hwnd.ToString();
388 c = Control.FromHandle(hwnd.Handle);
390 control_text = c.ToString();
392 control_text = String.Format("<handle {0:X} non-existant>", hwnd.Handle);
395 hwnd_text = "<null>";
396 control_text = "<null>";
400 error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:X}\n Serial: {4}\n Hwnd: {5}\n Control: {6}", x_error_text, RequestCode, MinorCode, ResourceID.ToInt32(), Serial, hwnd_text, control_text);
404 #endregion // XExceptionClass
406 #region Internal Methods
407 internal void SetDisplay(IntPtr display_handle) {
408 if (display_handle != IntPtr.Zero) {
411 if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) {
412 hwnd = Hwnd.ObjectFromHandle(FosterParent);
413 XDestroyWindow(DisplayHandle, FosterParent);
417 if (DisplayHandle != IntPtr.Zero) {
418 XCloseDisplay(DisplayHandle);
421 DisplayHandle=display_handle;
423 // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has
424 // been hacked to do this for us.
425 Graphics.FromHdcInternal (DisplayHandle);
427 // query for the render extension so
428 // we can ignore the spurious
429 // BadPicture errors that are
430 // generated by cairo/render.
431 XQueryExtension (DisplayHandle, "RENDER",
432 ref render_major_opcode, ref render_first_event, ref render_first_error);
435 if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
436 XSynchronize(DisplayHandle, true);
439 if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
440 ErrorExceptions = true;
444 ScreenNo = XDefaultScreen(DisplayHandle);
445 RootWindow = XRootWindow(DisplayHandle, ScreenNo);
446 DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
448 // Create the foster parent
449 // it is important that border_width is kept in synch with the other XCreateWindow calls
450 FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 0, UIntPtr.Zero, UIntPtr.Zero);
451 if (FosterParent==IntPtr.Zero) {
452 Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
456 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
457 hwnd.WholeWindow = FosterParent;
458 hwnd.ClientWindow = FosterParent;
460 // Create a HWND for RootWIndow as well, so our queue doesn't eat the events
462 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
463 hwnd.whole_window = RootWindow;
464 hwnd.ClientWindow = RootWindow;
466 // For sleeping on the X11 socket
467 listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
468 IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0);
472 // To wake up when a timer is ready
473 network_buffer = new byte[10];
475 wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
476 wake.Connect(listen.LocalEndPoint);
477 wake_receive = listen.Accept();
480 pollfds = new Pollfd [2];
481 pollfds [0] = new Pollfd ();
482 pollfds [0].fd = XConnectionNumber (DisplayHandle);
483 pollfds [0].events = PollEvents.POLLIN;
485 pollfds [1] = new Pollfd ();
486 pollfds [1].fd = wake_receive.Handle.ToInt32 ();
487 pollfds [1].events = PollEvents.POLLIN;
490 Keyboard = new X11Keyboard(DisplayHandle, FosterParent);
491 Dnd = new X11Dnd (DisplayHandle, Keyboard);
493 DoubleClickInterval = 500;
495 HoverState.Interval = 500;
496 HoverState.Timer = new Timer();
497 HoverState.Timer.Enabled = false;
498 HoverState.Timer.Interval = HoverState.Interval;
499 HoverState.Timer.Tick += new EventHandler(MouseHover);
500 HoverState.Size = new Size(4, 4);
504 ActiveWindow = IntPtr.Zero;
505 FocusWindow = IntPtr.Zero;
506 ModalWindows = new Stack(3);
508 MouseState = MouseButtons.None;
509 mouse_position = new Point(0, 0);
511 Caret.Timer = new Timer();
512 Caret.Timer.Interval = 500; // FIXME - where should this number come from?
513 Caret.Timer.Tick += new EventHandler(CaretCallback);
517 // Grab atom changes off the root window to catch certain WM events
518 XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int) (EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
520 // Handle any upcoming errors
521 ErrorHandler = new XErrorHandler(HandleError);
522 XSetErrorHandler(ErrorHandler);
524 throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check you DISPLAY environment variable)");
527 #endregion // Internal Methods
529 #region Private Methods
530 private int unixtime() {
531 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
533 return (int) t.TotalSeconds;
536 private static void SetupAtoms() {
537 // make sure this array stays in sync with the statements below
538 string [] atom_names = new string[] {
543 //"_NET_CLIENT_LIST",
544 //"_NET_NUMBER_OF_DESKTOPS",
545 "_NET_DESKTOP_GEOMETRY",
546 //"_NET_DESKTOP_VIEWPORT",
547 "_NET_CURRENT_DESKTOP",
548 //"_NET_DESKTOP_NAMES",
549 "_NET_ACTIVE_WINDOW",
551 //"_NET_SUPPORTING_WM_CHECK",
552 //"_NET_VIRTUAL_ROOTS",
553 //"_NET_DESKTOP_LAYOUT",
554 //"_NET_SHOWING_DESKTOP",
555 //"_NET_CLOSE_WINDOW",
556 //"_NET_MOVERESIZE_WINDOW",
557 //"_NET_WM_MOVERESIZE",
558 //"_NET_RESTACK_WINDOW",
559 //"_NET_REQUEST_FRAME_EXTENTS",
561 //"_NET_WM_VISIBLE_NAME",
562 //"_NET_WM_ICON_NAME",
563 //"_NET_WM_VISIBLE_ICON_NAME",
565 "_NET_WM_WINDOW_TYPE",
567 //"_NET_WM_ALLOWED_ACTIONS",
569 //"_NET_WM_STRUT_PARTIAL",
570 //"_NET_WM_ICON_GEOMETRY",
573 //"_NET_WM_HANDLED_ICONS",
575 "_NET_FRAME_EXTENTS",
577 //"_NET_WM_SYNC_REQUEST",
578 "_NET_SYSTEM_TRAY_OPCODE",
579 //"_NET_SYSTEM_TRAY_ORIENTATION",
580 "_NET_WM_STATE_MAXIMIZED_HORZ",
581 "_NET_WM_STATE_MAXIMIZED_VERT",
582 "_NET_WM_STATE_HIDDEN",
586 "_NET_WM_STATE_SKIP_TASKBAR",
587 "_NET_WM_STATE_ABOVE",
588 "_NET_WM_STATE_MODAL",
589 "_NET_WM_CONTEXT_HELP",
590 "_NET_WM_WINDOW_OPACITY",
591 //"_NET_WM_WINDOW_TYPE_DESKTOP",
592 //"_NET_WM_WINDOW_TYPE_DOCK",
593 //"_NET_WM_WINDOW_TYPE_TOOLBAR",
594 //"_NET_WM_WINDOW_TYPE_MENU",
595 "_NET_WM_WINDOW_TYPE_UTILITY",
596 "_NET_WM_WINDOW_TYPE_DIALOG",
597 //"_NET_WM_WINDOW_TYPE_SPLASH",
598 "_NET_WM_WINDOW_TYPE_NORMAL",
605 "_SWF_PostMessageAtom",
608 IntPtr[] atoms = new IntPtr [atom_names.Length];;
610 XInternAtoms (DisplayHandle, atom_names, atom_names.Length, false, atoms);
613 WM_PROTOCOLS = atoms [off++];
614 WM_DELETE_WINDOW = atoms [off++];
615 WM_TAKE_FOCUS = atoms [off++];
616 //_NET_SUPPORTED = atoms [off++];
617 //_NET_CLIENT_LIST = atoms [off++];
618 //_NET_NUMBER_OF_DESKTOPS = atoms [off++];
619 _NET_DESKTOP_GEOMETRY = atoms [off++];
620 //_NET_DESKTOP_VIEWPORT = atoms [off++];
621 _NET_CURRENT_DESKTOP = atoms [off++];
622 //_NET_DESKTOP_NAMES = atoms [off++];
623 _NET_ACTIVE_WINDOW = atoms [off++];
624 _NET_WORKAREA = atoms [off++];
625 //_NET_SUPPORTING_WM_CHECK = atoms [off++];
626 //_NET_VIRTUAL_ROOTS = atoms [off++];
627 //_NET_DESKTOP_LAYOUT = atoms [off++];
628 //_NET_SHOWING_DESKTOP = atoms [off++];
629 //_NET_CLOSE_WINDOW = atoms [off++];
630 //_NET_MOVERESIZE_WINDOW = atoms [off++];
631 //_NET_WM_MOVERESIZE = atoms [off++];
632 //_NET_RESTACK_WINDOW = atoms [off++];
633 //_NET_REQUEST_FRAME_EXTENTS = atoms [off++];
634 _NET_WM_NAME = atoms [off++];
635 //_NET_WM_VISIBLE_NAME = atoms [off++];
636 //_NET_WM_ICON_NAME = atoms [off++];
637 //_NET_WM_VISIBLE_ICON_NAME = atoms [off++];
638 //_NET_WM_DESKTOP = atoms [off++];
639 _NET_WM_WINDOW_TYPE = atoms [off++];
640 _NET_WM_STATE = atoms [off++];
641 //_NET_WM_ALLOWED_ACTIONS = atoms [off++];
642 //_NET_WM_STRUT = atoms [off++];
643 //_NET_WM_STRUT_PARTIAL = atoms [off++];
644 //_NET_WM_ICON_GEOMETRY = atoms [off++];
645 _NET_WM_ICON = atoms [off++];
646 //_NET_WM_PID = atoms [off++];
647 //_NET_WM_HANDLED_ICONS = atoms [off++];
648 _NET_WM_USER_TIME = atoms [off++];
649 _NET_FRAME_EXTENTS = atoms [off++];
650 //_NET_WM_PING = atoms [off++];
651 //_NET_WM_SYNC_REQUEST = atoms [off++];
652 _NET_SYSTEM_TRAY_OPCODE = atoms [off++];
653 //_NET_SYSTEM_TRAY_ORIENTATION = atoms [off++];
654 _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++];
655 _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++];
656 _NET_WM_STATE_HIDDEN = atoms [off++];
657 _XEMBED = atoms [off++];
658 _XEMBED_INFO = atoms [off++];
659 _MOTIF_WM_HINTS = atoms [off++];
660 _NET_WM_STATE_SKIP_TASKBAR = atoms [off++];
661 _NET_WM_STATE_ABOVE = atoms [off++];
662 _NET_WM_STATE_MODAL = atoms [off++];
663 _NET_WM_CONTEXT_HELP = atoms [off++];
664 _NET_WM_WINDOW_OPACITY = atoms [off++];
665 //_NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++];
666 //_NET_WM_WINDOW_TYPE_DOCK = atoms [off++];
667 //_NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++];
668 //_NET_WM_WINDOW_TYPE_MENU = atoms [off++];
669 _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++];
670 _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++];
671 //_NET_WM_WINDOW_TYPE_SPLASH = atoms [off++];
672 _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++];
673 CLIPBOARD = atoms [off++];
674 PRIMARY = atoms [off++];
675 OEMTEXT = atoms [off++];
676 UNICODETEXT = atoms [off++];
677 TARGETS = atoms [off++];
678 AsyncAtom = atoms [off++];
679 PostAtom = atoms [off++];
680 HoverState.Atom = atoms [off++];
682 //DIB = (IntPtr)Atom.XA_PIXMAP;
683 _NET_SYSTEM_TRAY_S = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString(), false);
686 private void GetSystrayManagerWindow() {
687 XGrabServer(DisplayHandle);
688 SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, _NET_SYSTEM_TRAY_S);
689 XUngrabServer(DisplayHandle);
690 XFlush(DisplayHandle);
693 private void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
697 xev.ClientMessageEvent.type = XEventName.ClientMessage;
698 xev.ClientMessageEvent.send_event = true;
699 xev.ClientMessageEvent.window = window;
700 xev.ClientMessageEvent.message_type = message_type;
701 xev.ClientMessageEvent.format = 32;
702 xev.ClientMessageEvent.ptr1 = l0;
703 xev.ClientMessageEvent.ptr2 = l1;
704 xev.ClientMessageEvent.ptr3 = l2;
705 XSendEvent(DisplayHandle, RootWindow, false, new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
708 private void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
712 xev.ClientMessageEvent.type = XEventName.ClientMessage;
713 xev.ClientMessageEvent.send_event = true;
714 xev.ClientMessageEvent.window = window;
715 xev.ClientMessageEvent.message_type = message_type;
716 xev.ClientMessageEvent.format = 32;
717 xev.ClientMessageEvent.ptr1 = l0;
718 xev.ClientMessageEvent.ptr2 = l1;
719 xev.ClientMessageEvent.ptr3 = l2;
720 XSendEvent(DisplayHandle, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev);
723 // For WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN
724 // WM_CREATE and WM_DESTROY causes
725 void SendParentNotify(IntPtr child, Msg cause, int x, int y)
729 if (child == IntPtr.Zero) {
733 hwnd = Hwnd.GetObjectFromWindow (child);
739 if (hwnd.Handle == IntPtr.Zero) {
743 if (ExStyleSet ((int) hwnd.initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY)) {
747 if (hwnd.Parent == null) {
751 if (hwnd.Parent.Handle == IntPtr.Zero) {
755 if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) {
756 SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Control.MakeParam((int)cause, 0), child);
758 SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Control.MakeParam((int)cause, 0), Control.MakeParam(x, y));
761 SendParentNotify (hwnd.Parent.Handle, cause, x, y);
764 bool StyleSet (int s, WindowStyles ws)
766 return (s & (int)ws) == (int)ws;
769 bool ExStyleSet (int ex, WindowExStyles exws)
771 return (ex & (int)exws) == (int)exws;
774 internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd)
776 return TranslateClientRectangleToXClientRectangle (hwnd, Control.FromHandle (hwnd.Handle));
779 internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd, Control ctrl)
782 * If this is a form with no window manager, X is handling all the border and caption painting
783 * so remove that from the area (since the area we set of the window here is the part of the window
784 * we're painting in only)
786 Rectangle rect = hwnd.ClientRect;
787 Form form = ctrl as Form;
788 CreateParams cp = null;
791 cp = form.GetCreateParams ();
793 if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
794 Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
795 Rectangle xrect = rect;
797 xrect.Y -= borders.top;
798 xrect.X -= borders.left;
799 xrect.Width += borders.left + borders.right;
800 xrect.Height += borders.top + borders.bottom;
805 if (rect.Width < 1 || rect.Height < 1) {
815 internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp)
817 return TranslateWindowSizeToXWindowSize (cp, new Size (cp.Width, cp.Height));
820 internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp, Size size)
823 * If this is a form with no window manager, X is handling all the border and caption painting
824 * so remove that from the area (since the area we set of the window here is the part of the window
825 * we're painting in only)
827 Form form = cp.control as Form;
828 if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
829 Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
832 xrect.Width -= borders.left + borders.right;
833 xrect.Height -= borders.top + borders.bottom;
837 if (size.Height == 0)
844 internal static Size TranslateXWindowSizeToWindowSize (CreateParams cp, int xWidth, int xHeight)
847 * If this is a form with no window manager, X is handling all the border and caption painting
848 * so remove that from the area (since the area we set of the window here is the part of the window
849 * we're painting in only)
851 Size rect = new Size (xWidth, xHeight);
852 Form form = cp.control as Form;
853 if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
854 Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
857 xrect.Width += borders.left + borders.right;
858 xrect.Height += borders.top + borders.bottom;
865 internal static Point GetTopLevelWindowLocation (Hwnd hwnd)
871 XTranslateCoordinates (DisplayHandle, hwnd.whole_window, RootWindow, 0, 0, out x, out y, out dummy);
872 frame = FrameExtents (hwnd.whole_window);
877 return new Point (x, y);
880 private void DeriveStyles(int Style, int ExStyle, out FormBorderStyle border_style, out bool border_static, out TitleStyle title_style, out int caption_height, out int tool_caption_height) {
883 tool_caption_height = 19;
884 border_static = false;
886 if (StyleSet (Style, WindowStyles.WS_CHILD)) {
887 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) {
888 border_style = FormBorderStyle.Fixed3D;
889 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
890 border_style = FormBorderStyle.Fixed3D;
891 border_static = true;
892 } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) {
893 border_style = FormBorderStyle.None;
895 border_style = FormBorderStyle.FixedSingle;
897 title_style = TitleStyle.None;
899 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
901 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
902 title_style = TitleStyle.Tool;
904 title_style = TitleStyle.Normal;
908 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) {
911 if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) ||
912 ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
913 border_style = (FormBorderStyle) 0xFFFF;
915 border_style = FormBorderStyle.None;
920 title_style = TitleStyle.None;
921 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
922 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
923 title_style = TitleStyle.Tool;
925 title_style = TitleStyle.Normal;
929 border_style = FormBorderStyle.None;
931 if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) {
932 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
933 border_style = FormBorderStyle.SizableToolWindow;
935 border_style = FormBorderStyle.Sizable;
938 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
939 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) {
940 border_style = FormBorderStyle.Fixed3D;
941 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
942 border_style = FormBorderStyle.Fixed3D;
943 border_static = true;
944 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
945 border_style = FormBorderStyle.FixedDialog;
946 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
947 border_style = FormBorderStyle.FixedToolWindow;
948 } else if (StyleSet (Style, WindowStyles.WS_BORDER)) {
949 border_style = FormBorderStyle.FixedSingle;
952 if (StyleSet (Style, WindowStyles.WS_BORDER)) {
953 border_style = FormBorderStyle.FixedSingle;
960 private void SetHwndStyles(Hwnd hwnd, CreateParams cp) {
961 DeriveStyles(cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.border_static, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height);
964 private void SetWMStyles(Hwnd hwnd, CreateParams cp) {
965 MotifWmHints mwmHints;
966 MotifFunctions functions;
967 MotifDecorations decorations;
970 Rectangle client_rect;
973 bool hide_from_taskbar;
974 IntPtr transient_for_parent;
976 // Windows we manage ourselves don't need WM window styles.
977 if (cp.HasWindowManager && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
982 mwmHints = new MotifWmHints();
985 window_type = _NET_WM_WINDOW_TYPE_NORMAL;
986 transient_for_parent = IntPtr.Zero;
988 mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
989 mwmHints.functions = (IntPtr)0;
990 mwmHints.decorations = (IntPtr)0;
992 form = cp.control as Form;
994 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
995 /* tool windows get no window manager
999 /* just because the window doesn't get any decorations doesn't
1000 mean we should disable the functions. for instance, without
1001 MotifFunctions.Maximize, changing the windowstate to Maximized
1002 is ignored by metacity. */
1003 functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
1004 } else if (form != null && form.FormBorderStyle == FormBorderStyle.None) {
1005 functions |= MotifFunctions.All;
1007 if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
1008 functions |= MotifFunctions.Move;
1009 decorations |= MotifDecorations.Title | MotifDecorations.Menu;
1012 if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) {
1013 functions |= MotifFunctions.Move | MotifFunctions.Resize;
1014 decorations |= MotifDecorations.Border | MotifDecorations.ResizeH;
1017 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) {
1018 functions |= MotifFunctions.Minimize;
1019 decorations |= MotifDecorations.Minimize;
1022 if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) {
1023 functions |= MotifFunctions.Maximize;
1024 decorations |= MotifDecorations.Maximize;
1027 if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) {
1028 functions |= MotifFunctions.Resize;
1029 decorations |= MotifDecorations.ResizeH;
1032 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
1033 decorations |= MotifDecorations.Border;
1036 if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) {
1037 decorations |= MotifDecorations.Border;
1040 if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) {
1041 decorations |= MotifDecorations.Border;
1044 if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) {
1045 functions |= MotifFunctions.Close;
1048 functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close);
1049 decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize);
1050 if (cp.Caption == "") {
1051 functions &= ~MotifFunctions.Move;
1052 decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH);
1057 if ((functions & MotifFunctions.Resize) == 0) {
1058 hwnd.fixed_size = true;
1059 Rectangle fixed_rectangle = new Rectangle (cp.X, cp.Y, cp.Width, cp.Height);
1060 SetWindowMinMax(hwnd.Handle, fixed_rectangle, fixed_rectangle.Size, fixed_rectangle.Size, cp);
1062 hwnd.fixed_size = false;
1065 mwmHints.functions = (IntPtr)functions;
1066 mwmHints.decorations = (IntPtr)decorations;
1069 Console.WriteLine ("SetWMStyles ({0}, {1}) functions = {2}, decorations = {3}", hwnd, cp, functions, decorations);
1072 if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
1073 // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
1074 // and get those windows in front of their parents
1075 window_type = _NET_WM_WINDOW_TYPE_UTILITY;
1076 } else if (form != null && form.Modal) {
1077 window_type = _NET_WM_WINDOW_TYPE_DIALOG;
1079 window_type = _NET_WM_WINDOW_TYPE_NORMAL;
1082 if (!cp.IsSet (WindowExStyles.WS_EX_APPWINDOW)) {
1083 hide_from_taskbar = true;
1084 } else if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW) && form != null && form.Parent != null && !form.ShowInTaskbar) {
1085 hide_from_taskbar = true;
1087 hide_from_taskbar = false;
1090 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
1091 if (form != null && !hwnd.reparented) {
1092 if (form.Owner != null && form.Owner.Handle != IntPtr.Zero) {
1093 Hwnd owner_hwnd = Hwnd.ObjectFromHandle (form.Owner.Handle);
1094 if (owner_hwnd != null)
1095 transient_for_parent = owner_hwnd.whole_window;
1099 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
1100 transient_for_parent = hwnd.parent.whole_window;
1103 FormWindowState current_state = GetWindowState (hwnd.Handle);
1104 if (current_state == (FormWindowState)(-1))
1105 current_state = FormWindowState.Normal;
1107 client_rect = TranslateClientRectangleToXClientRectangle (hwnd);
1112 atoms [0] = window_type.ToInt32 ();
1113 XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
1115 XChangeProperty(DisplayHandle, hwnd.whole_window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref mwmHints, 5);
1117 if (transient_for_parent != IntPtr.Zero) {
1118 XSetTransientForHint (DisplayHandle, hwnd.whole_window, transient_for_parent);
1121 MoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
1123 if (hide_from_taskbar) {
1124 /* this line keeps the window from showing up in gnome's taskbar */
1125 atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
1127 /* we need to add these atoms in the
1128 * event we're maximized, since we're
1129 * replacing the existing
1130 * _NET_WM_STATE here. If we don't
1131 * add them, future calls to
1132 * GetWindowState will return Normal
1133 * for a window which is maximized. */
1134 if (current_state == FormWindowState.Maximized) {
1135 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_HORZ.ToInt32();
1136 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_VERT.ToInt32();
1139 if (form != null && form.Modal) {
1140 atoms[atom_count++] = _NET_WM_STATE_MODAL.ToInt32 ();
1143 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
1146 IntPtr[] atom_ptrs = new IntPtr[2];
1147 atom_ptrs[atom_count++] = WM_DELETE_WINDOW;
1148 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP)) {
1149 atom_ptrs[atom_count++] = _NET_WM_CONTEXT_HELP;
1152 XSetWMProtocols(DisplayHandle, hwnd.whole_window, atom_ptrs, atom_count);
1156 private void SetIcon(Hwnd hwnd, Icon icon)
1161 // This really needs to do whatever it
1162 // takes to remove the window manager
1163 // menu, not just delete the ICON
1164 // property. This will cause metacity
1165 // to use the "no icon set" icon, and
1166 // we'll still have an icon.
1167 XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_ICON);
1175 bitmap = icon.ToBitmap();
1177 size = bitmap.Width * bitmap.Height + 2;
1178 data = new IntPtr[size];
1180 data[index++] = (IntPtr)bitmap.Width;
1181 data[index++] = (IntPtr)bitmap.Height;
1183 for (int y = 0; y < bitmap.Height; y++) {
1184 for (int x = 0; x < bitmap.Width; x++) {
1185 data[index++] = (IntPtr)bitmap.GetPixel (x, y).ToArgb ();
1189 XChangeProperty (DisplayHandle, hwnd.whole_window,
1190 _NET_WM_ICON, (IntPtr)Atom.XA_CARDINAL, 32,
1191 PropertyMode.Replace, data, size);
1195 private void WakeupMain () {
1196 wake.Send (new byte [] { 0xFF });
1199 private XEventQueue ThreadQueue(Thread thread) {
1202 queue = (XEventQueue)MessageQueues[thread];
1203 if (queue == null) {
1204 queue = new XEventQueue(thread);
1205 MessageQueues[thread] = queue;
1211 private void TranslatePropertyToClipboard(IntPtr property) {
1216 IntPtr prop = IntPtr.Zero;
1218 Clipboard.Item = null;
1220 XGetWindowProperty(DisplayHandle, FosterParent, property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1222 if ((long)nitems > 0) {
1223 if (property == (IntPtr)Atom.XA_STRING) {
1224 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1225 } else if (property == (IntPtr)Atom.XA_BITMAP) {
1226 // FIXME - convert bitmap to image
1227 } else if (property == (IntPtr)Atom.XA_PIXMAP) {
1228 // FIXME - convert pixmap to image
1229 } else if (property == OEMTEXT) {
1230 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1231 } else if (property == UNICODETEXT) {
1232 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1239 private void AddExpose (Hwnd hwnd, bool client, int x, int y, int width, int height) {
1241 if ((hwnd == null) || (x > hwnd.Width) || (y > hwnd.Height) || ((x + width) < 0) || ((y + height) < 0)) {
1245 // Keep the invalid area as small as needed
1246 if ((x + width) > hwnd.width) {
1247 width = hwnd.width - x;
1250 if ((y + height) > hwnd.height) {
1251 height = hwnd.height - y;
1255 hwnd.AddInvalidArea(x, y, width, height);
1256 if (!hwnd.expose_pending) {
1257 if (!hwnd.nc_expose_pending) {
1258 hwnd.Queue.Paint.Enqueue(hwnd);
1260 hwnd.expose_pending = true;
1263 hwnd.AddNcInvalidArea (x, y, width, height);
1265 if (!hwnd.nc_expose_pending) {
1266 if (!hwnd.expose_pending) {
1267 hwnd.Queue.Paint.Enqueue(hwnd);
1269 hwnd.nc_expose_pending = true;
1274 private static Hwnd.Borders FrameExtents (IntPtr window)
1280 IntPtr prop = IntPtr.Zero;
1281 Hwnd.Borders rect = new Hwnd.Borders ();
1283 XGetWindowProperty (DisplayHandle, window, _NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1284 if (prop != IntPtr.Zero) {
1285 if (nitems.ToInt32 () == 4) {
1286 rect.left = Marshal.ReadInt32 (prop, 0);
1287 rect.right = Marshal.ReadInt32 (prop, IntPtr.Size);
1288 rect.top = Marshal.ReadInt32 (prop, 2 * IntPtr.Size);
1289 rect.bottom = Marshal.ReadInt32 (prop, 3 * IntPtr.Size);
1297 private void AddConfigureNotify (XEvent xevent) {
1300 hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window);
1303 if (hwnd == null || hwnd.zombie) {
1306 if ((xevent.ConfigureEvent.window == hwnd.whole_window)/* && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)*/) {
1307 if (hwnd.parent == null) {
1308 // The location given by the event is not reliable between different wm's,
1309 // so use an alternative way of getting it.
1310 Point location = GetTopLevelWindowLocation (hwnd);
1311 hwnd.x = location.X;
1312 hwnd.y = location.Y;
1315 // XXX this sucks. this isn't thread safe
1316 Control ctrl = Control.FromHandle (hwnd.Handle);
1317 Size TranslatedSize;
1319 TranslatedSize = TranslateXWindowSizeToWindowSize (ctrl.GetCreateParams (), xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
1321 TranslatedSize = new Size (xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
1323 hwnd.width = TranslatedSize.Width;
1324 hwnd.height = TranslatedSize.Height;
1325 hwnd.ClientRect = Rectangle.Empty;
1328 Console.WriteLine ("AddConfigureNotify (hwnd.Handle = {1}, final hwnd.rect = {0}, reported rect={2})", new Rectangle (hwnd.x, hwnd.y, hwnd.width, hwnd.height), hwnd.Handle, new Rectangle (xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.width));
1330 lock (hwnd.configure_lock) {
1331 if (!hwnd.configure_pending) {
1332 hwnd.Queue.EnqueueLocked (xevent);
1333 hwnd.configure_pending = true;
1337 // We drop configure events for Client windows
1340 private void ShowCaret() {
1341 if ((Caret.gc == IntPtr.Zero) || Caret.On) {
1347 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1351 private void HideCaret() {
1352 if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
1358 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1362 private int NextTimeout (ArrayList timers, DateTime now) {
1365 foreach (Timer timer in timers) {
1366 int next = (int) (timer.Expires - now).TotalMilliseconds;
1368 return 0; // Have a timer that has already expired
1371 if (next < timeout) {
1375 if (timeout < Timer.Minimum) {
1376 timeout = Timer.Minimum;
1384 private void CheckTimers (ArrayList timers, DateTime now) {
1387 count = timers.Count;
1392 for (int i = 0; i < timers.Count; i++) {
1395 timer = (Timer) timers [i];
1397 if (timer.Enabled && timer.Expires <= now && !timer.Busy) {
1406 private void WaitForHwndMessage (Hwnd hwnd, Msg message) {
1407 MSG msg = new MSG ();
1410 queue = ThreadQueue(Thread.CurrentThread);
1412 queue.DispatchIdle = false;
1416 if (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
1417 if ((Msg)msg.message == Msg.WM_QUIT) {
1418 PostQuitMessage (0);
1422 if (msg.hwnd == hwnd.Handle) {
1423 if ((Msg)msg.message == message)
1425 else if ((Msg)msg.message == Msg.WM_DESTROY)
1429 TranslateMessage (ref msg);
1430 DispatchMessage (ref msg);
1435 queue.DispatchIdle = true;
1439 private void MapWindow(Hwnd hwnd, WindowType windows) {
1441 Form f = Control.FromHandle(hwnd.Handle) as Form;
1443 if (f.WindowState == FormWindowState.Normal) {
1444 f.waiting_showwindow = true;
1445 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
1449 // it's possible that our Hwnd is no
1450 // longer valid after making that
1451 // SendMessage call, so check here.
1455 if ((windows & WindowType.Whole) != 0) {
1456 XMapWindow(DisplayHandle, hwnd.whole_window);
1458 if ((windows & WindowType.Client) != 0) {
1459 XMapWindow(DisplayHandle, hwnd.client_window);
1464 if (f != null && f.waiting_showwindow)
1465 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1469 private void UnmapWindow(Hwnd hwnd, WindowType windows) {
1472 if (Control.FromHandle(hwnd.Handle) is Form) {
1473 f = Control.FromHandle(hwnd.Handle) as Form;
1474 if (f.WindowState == FormWindowState.Normal) {
1475 f.waiting_showwindow = true;
1476 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
1480 // it's possible that our Hwnd is no
1481 // longer valid after making that
1482 // SendMessage call, so check here.
1483 // FIXME: it is likely wrong, as it has already sent WM_SHOWWINDOW
1487 if ((windows & WindowType.Client) != 0) {
1488 XUnmapWindow(DisplayHandle, hwnd.client_window);
1490 if ((windows & WindowType.Whole) != 0) {
1491 XUnmapWindow(DisplayHandle, hwnd.whole_window);
1494 hwnd.mapped = false;
1496 if (f != null && f.waiting_showwindow)
1497 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1501 private void UpdateMessageQueue (XEventQueue queue) {
1506 now = DateTime.UtcNow;
1509 pending = XPending (DisplayHandle);
1513 if ((queue == null || queue.DispatchIdle) && Idle != null) {
1514 Idle (this, EventArgs.Empty);
1518 pending = XPending (DisplayHandle);
1525 if (queue != null) {
1526 if (queue.Paint.Count > 0)
1529 timeout = NextTimeout (queue.timer_list, now);
1534 int length = pollfds.Length - 1;
1535 lock (wake_waiting_lock) {
1536 if (wake_waiting == false) {
1538 wake_waiting = true;
1542 Syscall.poll (pollfds, (uint)length, timeout);
1543 // Clean out buffer, so we're not busy-looping on the same data
1544 if (length == pollfds.Length) {
1545 if (pollfds[1].revents != 0)
1546 wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
1547 lock (wake_waiting_lock) {
1548 wake_waiting = false;
1553 pending = XPending (DisplayHandle);
1559 CheckTimers (queue.timer_list, now);
1562 XEvent xevent = new XEvent ();
1565 if (XPending (DisplayHandle) == 0)
1568 XNextEvent (DisplayHandle, ref xevent);
1570 if (xevent.AnyEvent.type == XEventName.KeyPress ||
1571 xevent.AnyEvent.type == XEventName.KeyRelease) {
1572 // PreFilter() handles "shift key state updates.
1573 Keyboard.PreFilter (xevent);
1574 if (XFilterEvent (ref xevent, Keyboard.ClientWindow)) {
1575 // probably here we could raise WM_IME_KEYDOWN and
1576 // WM_IME_KEYUP, but I'm not sure it is worthy.
1580 else if (XFilterEvent (ref xevent, IntPtr.Zero))
1584 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
1589 Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
1591 switch (xevent.type) {
1592 case XEventName.Expose:
1593 AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
1596 case XEventName.SelectionClear: {
1597 // Should we do something?
1601 case XEventName.SelectionRequest: {
1602 if (Dnd.HandleSelectionRequestEvent (ref xevent))
1606 sel_event = new XEvent();
1607 sel_event.SelectionEvent.type = XEventName.SelectionNotify;
1608 sel_event.SelectionEvent.send_event = true;
1609 sel_event.SelectionEvent.display = DisplayHandle;
1610 sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
1611 sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
1612 sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
1613 sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
1614 sel_event.SelectionEvent.property = IntPtr.Zero;
1616 // Seems that some apps support asking for supported types
1617 if (xevent.SelectionEvent.target == TARGETS) {
1624 if (Clipboard.Item is String) {
1625 atoms[atom_count++] = (int)Atom.XA_STRING;
1626 atoms[atom_count++] = (int)OEMTEXT;
1627 atoms[atom_count++] = (int)UNICODETEXT;
1628 } else if (Clipboard.Item is Image) {
1629 atoms[atom_count++] = (int)Atom.XA_PIXMAP;
1630 atoms[atom_count++] = (int)Atom.XA_BITMAP;
1632 // FIXME - handle other types
1635 XChangeProperty(DisplayHandle, xevent.SelectionEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
1636 } else if (Clipboard.Item is string) {
1642 if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) {
1645 bytes = new ASCIIEncoding().GetBytes((string)Clipboard.Item);
1646 buffer = Marshal.AllocHGlobal(bytes.Length);
1647 buflen = bytes.Length;
1649 for (int i = 0; i < buflen; i++) {
1650 Marshal.WriteByte(buffer, i, bytes[i]);
1652 } else if (xevent.SelectionRequestEvent.target == OEMTEXT) {
1653 // FIXME - this should encode into ISO2022
1654 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1655 while (Marshal.ReadByte(buffer, buflen) != 0) {
1658 } else if (xevent.SelectionRequestEvent.target == UNICODETEXT) {
1659 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1660 while (Marshal.ReadByte(buffer, buflen) != 0) {
1664 buffer = IntPtr.Zero;
1667 if (buffer != IntPtr.Zero) {
1668 XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
1669 sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
1670 Marshal.FreeHGlobal(buffer);
1672 } else if (Clipboard.Item is Image) {
1673 if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1674 // FIXME - convert image and store as property
1675 } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1676 // FIXME - convert image and store as property
1680 XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event);
1684 case XEventName.SelectionNotify: {
1685 if (Clipboard.Enumerating) {
1686 Clipboard.Enumerating = false;
1687 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1688 XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property);
1689 if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) {
1690 Clipboard.Formats.Add(xevent.SelectionEvent.property);
1691 #if DriverDebugExtra
1692 Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
1696 } else if (Clipboard.Retrieving) {
1697 Clipboard.Retrieving = false;
1698 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1699 TranslatePropertyToClipboard(xevent.SelectionEvent.property);
1701 Clipboard.Item = null;
1704 Dnd.HandleSelectionNotifyEvent (ref xevent);
1709 case XEventName.KeyRelease:
1710 if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) {
1711 XEvent nextevent = new XEvent ();
1713 XPeekEvent (DisplayHandle, ref nextevent);
1715 if (nextevent.type == XEventName.KeyPress &&
1716 nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
1717 nextevent.KeyEvent.time == xevent.KeyEvent.time) {
1721 goto case XEventName.KeyPress;
1723 case XEventName.MotionNotify: {
1726 /* we can't do motion compression across threads, so just punt if we don't match up */
1727 if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) {
1728 peek = hwnd.Queue.Peek();
1729 if (peek.AnyEvent.type == XEventName.MotionNotify) {
1733 goto case XEventName.KeyPress;
1736 case XEventName.KeyPress:
1737 hwnd.Queue.EnqueueLocked (xevent);
1738 /* Process KeyPresses immediately. Otherwise multiple Compose messages as a result of a
1739 * single physical keypress are not processed correctly */
1741 case XEventName.ButtonPress:
1742 case XEventName.ButtonRelease:
1743 case XEventName.EnterNotify:
1744 case XEventName.LeaveNotify:
1745 case XEventName.CreateNotify:
1746 case XEventName.DestroyNotify:
1747 case XEventName.FocusIn:
1748 case XEventName.FocusOut:
1749 case XEventName.ClientMessage:
1750 case XEventName.ReparentNotify:
1751 case XEventName.MapNotify:
1752 case XEventName.UnmapNotify:
1753 hwnd.Queue.EnqueueLocked (xevent);
1756 case XEventName.ConfigureNotify:
1757 AddConfigureNotify(xevent);
1760 case XEventName.PropertyNotify:
1762 Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
1764 if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) {
1769 IntPtr prop = IntPtr.Zero;
1772 prev_active = ActiveWindow;
1773 XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
1774 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
1775 ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop));
1778 if (prev_active != ActiveWindow) {
1779 if (prev_active != IntPtr.Zero) {
1780 PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1782 if (ActiveWindow != IntPtr.Zero) {
1783 PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
1786 if (ModalWindows.Count == 0) {
1789 // Modality handling, if we are modal and the new active window is one
1790 // of ours but not the modal one, switch back to the modal window
1792 if (NativeWindow.FromHandle(ActiveWindow) != null) {
1793 if (ActiveWindow != (IntPtr)ModalWindows.Peek()) {
1794 Activate((IntPtr)ModalWindows.Peek());
1801 else if (xevent.PropertyEvent.atom == _NET_WM_STATE) {
1802 // invalidate our cache - we'll query again the next time someone does GetWindowState.
1803 hwnd.cached_window_state = (FormWindowState)(-1);
1804 PostMessage (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
1812 private IntPtr GetMousewParam(int Delta) {
1815 if ((MouseState & MouseButtons.Left) != 0) {
1816 result |= (int)MsgButtons.MK_LBUTTON;
1819 if ((MouseState & MouseButtons.Middle) != 0) {
1820 result |= (int)MsgButtons.MK_MBUTTON;
1823 if ((MouseState & MouseButtons.Right) != 0) {
1824 result |= (int)MsgButtons.MK_RBUTTON;
1827 Keys mods = ModifierKeys;
1828 if ((mods & Keys.Control) != 0) {
1829 result |= (int)MsgButtons.MK_CONTROL;
1832 if ((mods & Keys.Shift) != 0) {
1833 result |= (int)MsgButtons.MK_SHIFT;
1836 result |= Delta << 16;
1838 return (IntPtr)result;
1840 private IntPtr XGetParent(IntPtr handle) {
1847 XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount);
1850 if (Children!=IntPtr.Zero) {
1858 private int HandleError (IntPtr display, ref XErrorEvent error_event)
1860 // we need to workaround a problem with the
1861 // ordering of destruction of Drawables and
1862 // Pictures that exists between cairo and
1863 // RENDER on the server.
1864 if (error_event.request_code == (XRequest)render_major_opcode
1865 && error_event.minor_code == 7 /* X_RenderFreePicture from render.h */
1866 && error_event.error_code == render_first_error + 1 /* BadPicture from render.h */) {
1870 if (ErrorExceptions) {
1871 XUngrabPointer (display, IntPtr.Zero);
1872 throw new XException (error_event.display, error_event.resourceid,
1873 error_event.serial, error_event.error_code,
1874 error_event.request_code, error_event.minor_code);
1876 Console.WriteLine("X11 Error encountered: {0}{1}\n",
1877 XException.GetMessage (error_event.display, error_event.resourceid,
1878 error_event.serial, error_event.error_code,
1879 error_event.request_code, error_event.minor_code),
1880 Environment.StackTrace);
1885 private void AccumulateDestroyedHandles (Control c, ArrayList list)
1888 Control[] controls = c.Controls.GetAllControls ();
1890 if (c.IsHandleCreated && !c.IsDisposed) {
1891 Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle);
1893 #if DriverDebug || DriverDebugDestroy
1894 Console.WriteLine (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
1895 Console.WriteLine (" + parent X window is {0:X}", XGetParent (hwnd.whole_window).ToInt32());
1899 CleanupCachedWindows (hwnd);
1902 for (int i = 0; i < controls.Length; i ++) {
1903 AccumulateDestroyedHandles (controls[i], list);
1909 void CleanupCachedWindows (Hwnd hwnd)
1911 if (ActiveWindow == hwnd.Handle) {
1912 SendMessage(hwnd.client_window, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1913 ActiveWindow = IntPtr.Zero;
1916 if (FocusWindow == hwnd.Handle) {
1917 SendMessage(hwnd.client_window, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
1918 FocusWindow = IntPtr.Zero;
1921 if (Grab.Hwnd == hwnd.Handle) {
1922 Grab.Hwnd = IntPtr.Zero;
1923 Grab.Confined = false;
1926 DestroyCaret (hwnd.Handle);
1929 private void PerformNCCalc(Hwnd hwnd) {
1930 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
1934 rect = new Rectangle (0, 0, hwnd.Width, hwnd.Height);
1936 ncp = new XplatUIWin32.NCCALCSIZE_PARAMS();
1937 ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp));
1939 ncp.rgrc1.left = rect.Left;
1940 ncp.rgrc1.top = rect.Top;
1941 ncp.rgrc1.right = rect.Right;
1942 ncp.rgrc1.bottom = rect.Bottom;
1944 Marshal.StructureToPtr(ncp, ptr, true);
1945 NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr);
1946 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
1947 Marshal.FreeHGlobal(ptr);
1950 rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
1951 hwnd.ClientRect = rect;
1953 rect = TranslateClientRectangleToXClientRectangle (hwnd);
1956 MoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
1959 AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
1961 #endregion // Private Methods
1964 private void MouseHover(object sender, EventArgs e) {
1968 HoverState.Timer.Enabled = false;
1970 if (HoverState.Window != IntPtr.Zero) {
1971 hwnd = Hwnd.GetObjectFromWindow(HoverState.Window);
1973 xevent = new XEvent ();
1975 xevent.type = XEventName.ClientMessage;
1976 xevent.ClientMessageEvent.display = DisplayHandle;
1977 xevent.ClientMessageEvent.window = HoverState.Window;
1978 xevent.ClientMessageEvent.message_type = HoverState.Atom;
1979 xevent.ClientMessageEvent.format = 32;
1980 xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
1982 hwnd.Queue.EnqueueLocked (xevent);
1989 private void CaretCallback(object sender, EventArgs e) {
1993 Caret.On = !Caret.On;
1995 XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1997 #endregion // Callbacks
1999 #region Public Properties
2001 internal override int CaptionHeight {
2007 internal override Size CursorSize {
2012 if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) {
2013 return new Size(x, y);
2015 return new Size(16, 16);
2020 internal override bool DragFullWindows {
2026 internal override Size DragSize {
2028 return new Size(4, 4);
2032 internal override Size FrameBorderSize {
2034 return new Size (4, 4);
2038 internal override Size IconSize {
2044 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
2048 current = (long)list;
2051 size = new XIconSize();
2053 for (int i = 0; i < count; i++) {
2054 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
2055 current += Marshal.SizeOf(size);
2057 // Look for our preferred size
2058 if (size.min_width == 32) {
2060 return new Size(32, 32);
2063 if (size.max_width == 32) {
2065 return new Size(32, 32);
2068 if (size.min_width < 32 && size.max_width > 32) {
2071 // check if we can fit one
2073 while (x < size.max_width) {
2074 x += size.width_inc;
2077 return new Size(32, 32);
2082 if (largest < size.max_width) {
2083 largest = size.max_width;
2087 // We didn't find a match or we wouldn't be here
2088 return new Size(largest, largest);
2091 return new Size(32, 32);
2096 internal override int KeyboardSpeed {
2099 // A lot harder: need to do:
2100 // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
2101 // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
2102 // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
2104 // And from that we can tell the repetition rate
2106 // Notice, the values must map to:
2107 // [0, 31] which maps to 2.5 to 30 repetitions per second.
2113 internal override int KeyboardDelay {
2116 // Return values must range from 0 to 4, 0 meaning 250ms,
2117 // and 4 meaning 1000 ms.
2119 return 1; // ie, 500 ms
2123 internal override Size MaxWindowTrackSize {
2125 return new Size (WorkingArea.Width, WorkingArea.Height);
2129 internal override bool MenuAccessKeysUnderlined {
2135 internal override Size MinimizedWindowSpacingSize {
2137 return new Size(1, 1);
2141 internal override Size MinimumWindowSize {
2143 return new Size(110, 22);
2147 internal override Size MinimumFixedToolWindowSize {
2148 get { return new Size (27, 22); }
2151 internal override Size MinimumSizeableToolWindowSize {
2152 get { return new Size (37, 22); }
2155 internal override Size MinimumNoBorderWindowSize {
2156 get { return new Size (2, 2); }
2159 internal override Keys ModifierKeys {
2161 return Keyboard.ModifierKeys;
2165 internal override Size SmallIconSize {
2171 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
2175 current = (long)list;
2178 size = new XIconSize();
2180 for (int i = 0; i < count; i++) {
2181 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
2182 current += Marshal.SizeOf(size);
2184 // Look for our preferred size
2185 if (size.min_width == 16) {
2187 return new Size(16, 16);
2190 if (size.max_width == 16) {
2192 return new Size(16, 16);
2195 if (size.min_width < 16 && size.max_width > 16) {
2198 // check if we can fit one
2200 while (x < size.max_width) {
2201 x += size.width_inc;
2204 return new Size(16, 16);
2209 if (smallest == 0 || smallest > size.min_width) {
2210 smallest = size.min_width;
2214 // We didn't find a match or we wouldn't be here
2215 return new Size(smallest, smallest);
2218 return new Size(16, 16);
2223 internal override int MouseButtonCount {
2229 internal override bool MouseButtonsSwapped {
2231 return false; // FIXME - how to detect?
2235 internal override Point MousePosition {
2237 return mouse_position;
2241 internal override Size MouseHoverSize {
2243 return new Size (1, 1);
2247 internal override int MouseHoverTime {
2249 return HoverState.Interval;
2255 internal override bool MouseWheelPresent {
2257 return true; // FIXME - how to detect?
2261 internal override Rectangle VirtualScreen {
2267 IntPtr prop = IntPtr.Zero;
2271 XGetWindowProperty(DisplayHandle, RootWindow, _NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
2272 if ((long)nitems < 2)
2275 width = Marshal.ReadIntPtr(prop, 0).ToInt32();
2276 height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
2280 return new Rectangle(0, 0, width, height);
2283 XWindowAttributes attributes=new XWindowAttributes();
2286 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2289 return new Rectangle(0, 0, attributes.width, attributes.height);
2293 internal override Rectangle WorkingArea {
2299 IntPtr prop = IntPtr.Zero;
2302 int current_desktop;
2306 XGetWindowProperty(DisplayHandle, RootWindow, _NET_CURRENT_DESKTOP, IntPtr.Zero, new IntPtr(1), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
2307 if ((long)nitems < 1) {
2311 current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
2314 XGetWindowProperty(DisplayHandle, RootWindow, _NET_WORKAREA, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
2315 if ((long)nitems < 4 * current_desktop) {
2319 x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
2320 y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
2321 width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
2322 height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
2325 return new Rectangle(x, y, width, height);
2328 XWindowAttributes attributes=new XWindowAttributes();
2331 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2334 return new Rectangle(0, 0, attributes.width, attributes.height);
2338 internal override bool ThemesEnabled {
2340 return XplatUIX11.themes_enabled;
2345 #endregion // Public properties
2347 #region Public Static Methods
2348 internal override void RaiseIdle (EventArgs e)
2354 internal override IntPtr InitializeDriver() {
2356 if (DisplayHandle==IntPtr.Zero) {
2357 SetDisplay(XOpenDisplay(IntPtr.Zero));
2363 internal override void ShutdownDriver(IntPtr token) {
2365 if (DisplayHandle!=IntPtr.Zero) {
2366 XCloseDisplay(DisplayHandle);
2367 DisplayHandle=IntPtr.Zero;
2372 internal override void EnableThemes() {
2373 themes_enabled = true;
2377 internal override void Activate(IntPtr handle) {
2380 hwnd = Hwnd.ObjectFromHandle(handle);
2384 if (true /* the window manager supports NET_ACTIVE_WINDOW */) {
2385 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
2386 XEventQueue q = null;
2387 lock (unattached_timer_list) {
2388 foreach (Timer t in unattached_timer_list) {
2390 q= (XEventQueue) MessageQueues [Thread.CurrentThread];
2391 t.thread = q.Thread;
2392 q.timer_list.Add (t);
2394 unattached_timer_list.Clear ();
2398 // XRaiseWindow(DisplayHandle, handle);
2404 internal override void AudibleAlert() {
2405 XBell(DisplayHandle, 0);
2410 internal override void CaretVisible(IntPtr handle, bool visible) {
2411 if (Caret.Hwnd == handle) {
2413 if (!Caret.Visible) {
2414 Caret.Visible = true;
2416 Caret.Timer.Start();
2419 Caret.Visible = false;
2426 internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) {
2427 WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect);
2431 internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) {
2437 hwnd = Hwnd.ObjectFromHandle(handle);
2440 XTranslateCoordinates(DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
2447 internal override int[] ClipboardAvailableFormats(IntPtr handle) {
2448 DataFormats.Format f;
2451 f = DataFormats.Format.List;
2453 if (XGetSelectionOwner(DisplayHandle, CLIPBOARD) == IntPtr.Zero) {
2457 Clipboard.Formats = new ArrayList();
2460 XConvertSelection(DisplayHandle, CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent, IntPtr.Zero);
2462 Clipboard.Enumerating = true;
2463 while (Clipboard.Enumerating) {
2464 UpdateMessageQueue(null);
2469 result = new int[Clipboard.Formats.Count];
2471 for (int i = 0; i < Clipboard.Formats.Count; i++) {
2472 result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
2475 Clipboard.Formats = null;
2479 internal override void ClipboardClose(IntPtr handle) {
2480 if (handle != ClipMagic) {
2481 throw new ArgumentException("handle is not a valid clipboard handle");
2486 internal override int ClipboardGetID(IntPtr handle, string format) {
2487 if (handle != ClipMagic) {
2488 throw new ArgumentException("handle is not a valid clipboard handle");
2491 if (format == "Text" ) return (int)Atom.XA_STRING;
2492 else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP;
2493 //else if (format == "MetaFilePict" ) return 3;
2494 //else if (format == "SymbolicLink" ) return 4;
2495 //else if (format == "DataInterchangeFormat" ) return 5;
2496 //else if (format == "Tiff" ) return 6;
2497 else if (format == "OEMText" ) return OEMTEXT.ToInt32();
2498 else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP;
2499 else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless
2500 //else if (format == "PenData" ) return 10;
2501 //else if (format == "RiffAudio" ) return 11;
2502 //else if (format == "WaveAudio" ) return 12;
2503 else if (format == "UnicodeText" ) return UNICODETEXT.ToInt32();
2504 //else if (format == "EnhancedMetafile" ) return 14;
2505 //else if (format == "FileDrop" ) return 15;
2506 //else if (format == "Locale" ) return 16;
2508 return XInternAtom(DisplayHandle, format, false).ToInt32();
2511 internal override IntPtr ClipboardOpen(bool primary_selection) {
2512 if (!primary_selection)
2513 ClipMagic = CLIPBOARD;
2515 ClipMagic = PRIMARY;
2519 internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) {
2520 XConvertSelection(DisplayHandle, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
2522 Clipboard.Retrieving = true;
2523 while (Clipboard.Retrieving) {
2524 UpdateMessageQueue(null);
2527 return Clipboard.Item;
2530 internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter) {
2531 Clipboard.Item = obj;
2532 Clipboard.Type = type;
2533 Clipboard.Converter = converter;
2536 XSetSelectionOwner(DisplayHandle, CLIPBOARD, FosterParent, IntPtr.Zero);
2538 // Clearing the selection
2539 XSetSelectionOwner(DisplayHandle, CLIPBOARD, IntPtr.Zero, IntPtr.Zero);
2543 internal override void CreateCaret (IntPtr handle, int width, int height)
2545 XGCValues gc_values;
2548 hwnd = Hwnd.ObjectFromHandle(handle);
2550 if (Caret.Hwnd != IntPtr.Zero) {
2551 DestroyCaret(Caret.Hwnd);
2554 Caret.Hwnd = handle;
2555 Caret.Window = hwnd.client_window;
2556 Caret.Width = width;
2557 Caret.Height = height;
2558 Caret.Visible = false;
2561 gc_values = new XGCValues();
2562 gc_values.line_width = width;
2564 Caret.gc = XCreateGC(DisplayHandle, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
2565 if (Caret.gc == IntPtr.Zero) {
2566 Caret.Hwnd = IntPtr.Zero;
2570 XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert);
2573 internal override IntPtr CreateWindow (CreateParams cp)
2575 XSetWindowAttributes Attributes;
2577 Hwnd parent_hwnd = null;
2582 IntPtr ParentHandle;
2584 IntPtr ClientWindow;
2585 SetWindowValuemask ValueMask;
2590 Attributes = new XSetWindowAttributes();
2596 if (Width<1) Width=1;
2597 if (Height<1) Height=1;
2599 if (cp.Parent != IntPtr.Zero) {
2600 parent_hwnd = Hwnd.ObjectFromHandle(cp.Parent);
2601 ParentHandle = parent_hwnd.client_window;
2603 if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2604 // We need to use our foster parent window until this poor child gets it's parent assigned
2605 ParentHandle=FosterParent;
2607 ParentHandle=RootWindow;
2611 // Set the default location location for forms.
2613 if (cp.control is Form) {
2614 next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd);
2618 ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
2620 Attributes.bit_gravity = Gravity.NorthWestGravity;
2621 Attributes.win_gravity = Gravity.NorthWestGravity;
2623 // Save what's under the toolwindow
2624 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
2625 Attributes.save_under = true;
2626 ValueMask |= SetWindowValuemask.SaveUnder;
2630 // If we're a popup without caption we override the WM
2631 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
2632 Attributes.override_redirect = true;
2633 ValueMask |= SetWindowValuemask.OverrideRedirect;
2639 hwnd.height = Height;
2640 hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent);
2641 hwnd.initial_style = cp.WindowStyle;
2642 hwnd.initial_ex_style = cp.WindowExStyle;
2644 if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) {
2645 hwnd.enabled = false;
2648 ClientWindow = IntPtr.Zero;
2650 Size XWindowSize = TranslateWindowSizeToXWindowSize (cp);
2651 Rectangle XClientRect = TranslateClientRectangleToXClientRectangle (hwnd, cp.control);
2654 WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, XWindowSize.Width, XWindowSize.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes);
2655 if (WholeWindow != IntPtr.Zero) {
2656 ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
2658 if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) {
2659 ValueMask = SetWindowValuemask.ColorMap;
2660 Attributes.colormap = CustomColormap;
2662 ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, XClientRect.X, XClientRect.Y, XClientRect.Width, XClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes);
2666 if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) {
2667 throw new Exception("Could not create X11 windows");
2670 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
2671 hwnd.WholeWindow = WholeWindow;
2672 hwnd.ClientWindow = ClientWindow;
2674 #if DriverDebug || DriverDebugCreate
2675 Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle);
2678 if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2679 if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
2682 hints = new XSizeHints();
2685 hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition);
2686 XSetWMNormalHints(DisplayHandle, WholeWindow, ref hints);
2691 XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
2692 if (hwnd.whole_window != hwnd.client_window)
2693 XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | Keyboard.KeyEventMask)));
2696 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
2698 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
2699 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
2701 XSetTransientForHint (DisplayHandle, hwnd.whole_window, RootWindow);
2704 SetWMStyles(hwnd, cp);
2706 // set the group leader
2707 XWMHints wm_hints = new XWMHints ();
2709 wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint);
2710 wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
2711 wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState;
2713 if (ParentHandle != RootWindow) {
2714 wm_hints.window_group = hwnd.whole_window;
2716 wm_hints.window_group = ParentHandle;
2720 XSetWMHints(DisplayHandle, hwnd.whole_window, ref wm_hints );
2723 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) {
2724 SetWindowState(hwnd.Handle, FormWindowState.Minimized);
2725 } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) {
2726 SetWindowState(hwnd.Handle, FormWindowState.Maximized);
2729 // for now make all windows dnd enabled
2730 Dnd.SetAllowDrop (hwnd, true);
2732 // Set caption/window title
2733 Text(hwnd.Handle, cp.Caption);
2735 SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */);
2736 SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue);
2738 if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) {
2739 hwnd.visible = true;
2740 MapWindow(hwnd, WindowType.Both);
2741 if (!(Control.FromHandle(hwnd.Handle) is Form))
2742 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
2748 internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) {
2749 CreateParams create_params = new CreateParams();
2751 create_params.Caption = "";
2752 create_params.X = X;
2753 create_params.Y = Y;
2754 create_params.Width = Width;
2755 create_params.Height = Height;
2757 create_params.ClassName=XplatUI.DefaultClassName;
2758 create_params.ClassStyle = 0;
2759 create_params.ExStyle=0;
2760 create_params.Parent=IntPtr.Zero;
2761 create_params.Param=0;
2763 return CreateWindow(create_params);
2766 internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
2768 Bitmap cursor_bitmap;
2776 IntPtr cursor_pixmap;
2783 if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) {
2787 // Win32 only allows creation cursors of a certain size
2788 if ((bitmap.Width != width) || (bitmap.Width != height)) {
2789 cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
2790 cursor_mask = new Bitmap(mask, new Size(width, height));
2792 cursor_bitmap = bitmap;
2796 width = cursor_bitmap.Width;
2797 height = cursor_bitmap.Height;
2799 cursor_bits = new Byte[(width / 8) * height];
2800 mask_bits = new Byte[(width / 8) * height];
2802 for (int y = 0; y < height; y++) {
2803 for (int x = 0; x < width; x++) {
2804 c_pixel = cursor_bitmap.GetPixel(x, y);
2805 m_pixel = cursor_mask.GetPixel(x, y);
2807 and = c_pixel == cursor_pixel;
2808 xor = m_pixel == mask_pixel;
2812 // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
2813 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2814 } else if (and && !xor) {
2816 cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2817 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2819 } else if (and && !xor) {
2821 } else if (and && xor) {
2824 // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
2825 // we want both to be 0 so nothing to be done
2826 //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
2827 //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
2833 cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2834 mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2838 fg.pixel = XWhitePixel(DisplayHandle, ScreenNo);
2839 fg.red = (ushort)65535;
2840 fg.green = (ushort)65535;
2841 fg.blue = (ushort)65535;
2843 bg.pixel = XBlackPixel(DisplayHandle, ScreenNo);
2845 cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
2847 XFreePixmap(DisplayHandle, cursor_pixmap);
2848 XFreePixmap(DisplayHandle, mask_pixmap);
2853 internal override Bitmap DefineStdCursorBitmap (StdCursor id) {
2854 CursorFontShape shape;
2861 shape = StdCursorToFontShape (id);
2862 name = shape.ToString ().Replace ("XC_", string.Empty);
2863 size = XcursorGetDefaultSize (DisplayHandle);
2864 theme = XcursorGetTheme (DisplayHandle);
2865 IntPtr images_ptr = XcursorLibraryLoadImages (name, theme, size);
2867 Console.WriteLine ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr);
2870 if (images_ptr == IntPtr.Zero) {
2874 XcursorImages images = (XcursorImages) Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
2876 Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
2879 if (images.nimage > 0) {
2880 // We only care about the first image.
2881 XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
2884 Console.WriteLine ("DefineStdCursorBitmap, loaded image <size={0}, height={1}, width={2}, xhot={3}, yhot={4}, pixels={5}", image.size, image.height, image.width, image.xhot, image.yhot, image.pixels);
2887 if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
2888 int [] pixels = new int [image.width * image.height];
2889 Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
2890 bmp = new Bitmap (image.width, image.height);
2891 for (int w = 0; w < image.width; w++) {
2892 for (int h = 0; h < image.height; h++) {
2893 bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
2899 XcursorImagesDestroy (images_ptr);
2901 } catch (DllNotFoundException ex) {
2902 Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
2910 internal override IntPtr DefineStdCursor(StdCursor id) {
2911 CursorFontShape shape;
2914 shape = StdCursorToFontShape (id);
2917 cursor = XCreateFontCursor(DisplayHandle, shape);
2922 internal static CursorFontShape StdCursorToFontShape (StdCursor id) {
2923 CursorFontShape shape;
2924 // FIXME - define missing shapes
2927 case StdCursor.AppStarting: {
2928 shape = CursorFontShape.XC_watch;
2932 case StdCursor.Arrow: {
2933 shape = CursorFontShape.XC_top_left_arrow;
2937 case StdCursor.Cross: {
2938 shape = CursorFontShape.XC_crosshair;
2942 case StdCursor.Default: {
2943 shape = CursorFontShape.XC_top_left_arrow;
2947 case StdCursor.Hand: {
2948 shape = CursorFontShape.XC_hand1;
2952 case StdCursor.Help: {
2953 shape = CursorFontShape.XC_question_arrow;
2957 case StdCursor.HSplit: {
2958 shape = CursorFontShape.XC_sb_v_double_arrow;
2962 case StdCursor.IBeam: {
2963 shape = CursorFontShape.XC_xterm;
2967 case StdCursor.No: {
2968 shape = CursorFontShape.XC_circle;
2972 case StdCursor.NoMove2D: {
2973 shape = CursorFontShape.XC_fleur;
2977 case StdCursor.NoMoveHoriz: {
2978 shape = CursorFontShape.XC_fleur;
2982 case StdCursor.NoMoveVert: {
2983 shape = CursorFontShape.XC_fleur;
2987 case StdCursor.PanEast: {
2988 shape = CursorFontShape.XC_fleur;
2992 case StdCursor.PanNE: {
2993 shape = CursorFontShape.XC_fleur;
2997 case StdCursor.PanNorth: {
2998 shape = CursorFontShape.XC_fleur;
3002 case StdCursor.PanNW: {
3003 shape = CursorFontShape.XC_fleur;
3007 case StdCursor.PanSE: {
3008 shape = CursorFontShape.XC_fleur;
3012 case StdCursor.PanSouth: {
3013 shape = CursorFontShape.XC_fleur;
3017 case StdCursor.PanSW: {
3018 shape = CursorFontShape.XC_fleur;
3022 case StdCursor.PanWest: {
3023 shape = CursorFontShape.XC_sizing;
3027 case StdCursor.SizeAll: {
3028 shape = CursorFontShape.XC_fleur;
3032 case StdCursor.SizeNESW: {
3033 shape = CursorFontShape.XC_top_right_corner;
3037 case StdCursor.SizeNS: {
3038 shape = CursorFontShape.XC_sb_v_double_arrow;
3042 case StdCursor.SizeNWSE: {
3043 shape = CursorFontShape.XC_top_left_corner;
3047 case StdCursor.SizeWE: {
3048 shape = CursorFontShape.XC_sb_h_double_arrow;
3052 case StdCursor.UpArrow: {
3053 shape = CursorFontShape.XC_center_ptr;
3057 case StdCursor.VSplit: {
3058 shape = CursorFontShape.XC_sb_h_double_arrow;
3062 case StdCursor.WaitCursor: {
3063 shape = CursorFontShape.XC_watch;
3068 shape = (CursorFontShape) 0;
3076 internal override IntPtr DefWndProc(ref Message msg) {
3077 switch ((Msg)msg.Msg) {
3079 case Msg.WM_IME_COMPOSITION:
3080 string s = Keyboard.GetCompositionString ();
3081 foreach (char c in s)
3082 SendMessage (msg.HWnd, Msg.WM_IME_CHAR, (IntPtr) c, msg.LParam);
3085 case Msg.WM_IME_CHAR:
3086 // On Windows API it sends two WM_CHAR messages for each byte, but
3087 // I wonder if it is worthy to emulate it (also no idea how to
3088 // reconstruct those bytes into chars).
3089 SendMessage (msg.HWnd, Msg.WM_CHAR, msg.WParam, msg.LParam);
3092 case Msg.WM_PAINT: {
3095 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3097 hwnd.expose_pending = false;
3103 case Msg.WM_NCPAINT: {
3106 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3108 hwnd.nc_expose_pending = false;
3114 case Msg.WM_NCCALCSIZE: {
3117 if (msg.WParam == (IntPtr)1) {
3118 hwnd = Hwnd.GetObjectFromWindow (msg.HWnd);
3120 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
3121 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (msg.LParam, typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
3123 // Add all the stuff X is supposed to draw.
3124 Control ctrl = Control.FromHandle (hwnd.Handle);
3127 Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null);
3129 ncp.rgrc1.top += rect.top;
3130 ncp.rgrc1.bottom -= rect.bottom;
3131 ncp.rgrc1.left += rect.left;
3132 ncp.rgrc1.right -= rect.right;
3134 Marshal.StructureToPtr (ncp, msg.LParam, true);
3141 case Msg.WM_CONTEXTMENU: {
3144 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3146 if ((hwnd != null) && (hwnd.parent != null)) {
3147 SendMessage(hwnd.parent.client_window, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam);
3152 case Msg.WM_MOUSEWHEEL: {
3155 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3157 if ((hwnd != null) && (hwnd.parent != null)) {
3158 SendMessage(hwnd.parent.client_window, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam);
3159 if (msg.Result == IntPtr.Zero) {
3166 case Msg.WM_SETCURSOR: {
3169 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3171 break; // not sure how this happens, but it does
3173 // Pass to parent window first
3174 while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) {
3176 msg.Result = NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam);
3179 if (msg.Result == IntPtr.Zero) {
3182 switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) {
3183 case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break;
3184 case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break;
3185 case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break;
3186 case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break;
3187 case HitTest.HTERROR: if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) {
3190 handle = Cursors.Default.handle;
3193 case HitTest.HTHELP: handle = Cursors.Help.handle; break;
3194 case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break;
3195 case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break;
3196 case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break;
3197 case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break;
3198 case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break;
3201 case HitTest.HTGROWBOX:
3202 case HitTest.HTSIZE:
3203 case HitTest.HTZOOM:
3204 case HitTest.HTVSCROLL:
3205 case HitTest.HTSYSMENU:
3206 case HitTest.HTREDUCE:
3207 case HitTest.HTNOWHERE:
3208 case HitTest.HTMAXBUTTON:
3209 case HitTest.HTMINBUTTON:
3210 case HitTest.HTMENU:
3211 case HitTest.HSCROLL:
3212 case HitTest.HTBOTTOM:
3213 case HitTest.HTCAPTION:
3214 case HitTest.HTCLIENT:
3215 case HitTest.HTCLOSE:
3217 default: handle = Cursors.Default.handle; break;
3219 SetCursor(msg.HWnd, handle);
3227 internal override void DestroyCaret(IntPtr handle) {
3228 if (Caret.Hwnd == handle) {
3229 if (Caret.Visible) {
3233 if (Caret.gc != IntPtr.Zero) {
3234 XFreeGC(DisplayHandle, Caret.gc);
3235 Caret.gc = IntPtr.Zero;
3237 Caret.Hwnd = IntPtr.Zero;
3238 Caret.Visible = false;
3243 internal override void DestroyCursor(IntPtr cursor) {
3245 XFreeCursor(DisplayHandle, cursor);
3249 internal override void DestroyWindow(IntPtr handle) {
3252 hwnd = Hwnd.ObjectFromHandle(handle);
3255 #if DriverDebug || DriverDebugDestroy
3256 Console.WriteLine("window {0:X} already destroyed", handle.ToInt32());
3261 #if DriverDebug || DriverDebugDestroy
3262 Console.WriteLine("Destroying window {0}", XplatUI.Window(hwnd.client_window));
3265 SendParentNotify (hwnd.Handle, Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
3267 CleanupCachedWindows (hwnd);
3269 ArrayList windows = new ArrayList ();
3271 AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
3274 foreach (Hwnd h in windows) {
3275 SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
3280 if (hwnd.whole_window != IntPtr.Zero) {
3281 #if DriverDebug || DriverDebugDestroy
3282 Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32());
3284 Keyboard.DestroyICForWindow (hwnd.whole_window);
3285 XDestroyWindow(DisplayHandle, hwnd.whole_window);
3287 else if (hwnd.client_window != IntPtr.Zero) {
3288 #if DriverDebug || DriverDebugDestroy
3289 Console.WriteLine ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32());
3291 Keyboard.DestroyICForWindow (hwnd.client_window);
3292 XDestroyWindow(DisplayHandle, hwnd.client_window);
3298 internal override IntPtr DispatchMessage(ref MSG msg) {
3299 return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
3302 IntPtr GetReversibleScreenGC (Color backColor)
3304 XGCValues gc_values;
3308 XColor xcolor = new XColor();
3309 xcolor.red = (ushort)(backColor.R * 257);
3310 xcolor.green = (ushort)(backColor.G * 257);
3311 xcolor.blue = (ushort)(backColor.B * 257);
3312 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3313 pixel = (uint)xcolor.pixel.ToInt32();
3316 gc_values = new XGCValues();
3318 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
3319 gc_values.foreground = (IntPtr)pixel;
3321 gc = XCreateGC(DisplayHandle, RootWindow, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
3322 XSetForeground(DisplayHandle, gc, (UIntPtr)pixel);
3323 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
3328 IntPtr GetReversibleControlGC (Control control, int line_width)
3330 XGCValues gc_values;
3333 gc_values = new XGCValues();
3335 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
3336 gc_values.line_width = line_width;
3337 gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo);
3339 // This logic will give us true rubber bands: (libsx, SANE_XOR)
3340 //mask = foreground ^ background;
3341 //XSetForeground(DisplayHandle, gc, 0xffffffff);
3342 //XSetBackground(DisplayHandle, gc, background);
3343 //XSetFunction(DisplayHandle, gc, GXxor);
3344 //XSetPlaneMask(DisplayHandle, gc, mask);
3347 gc = XCreateGC(DisplayHandle, control.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values);
3351 XColor xcolor = new XColor();
3353 xcolor.red = (ushort)(control.ForeColor.R * 257);
3354 xcolor.green = (ushort)(control.ForeColor.G * 257);
3355 xcolor.blue = (ushort)(control.ForeColor.B * 257);
3356 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3357 foreground = (uint)xcolor.pixel.ToInt32();
3359 xcolor.red = (ushort)(control.BackColor.R * 257);
3360 xcolor.green = (ushort)(control.BackColor.G * 257);
3361 xcolor.blue = (ushort)(control.BackColor.B * 257);
3362 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3363 background = (uint)xcolor.pixel.ToInt32();
3365 uint mask = foreground ^ background;
3367 XSetForeground(DisplayHandle, gc, (UIntPtr)0xffffffff);
3368 XSetBackground(DisplayHandle, gc, (UIntPtr)background);
3369 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
3370 XSetPlaneMask(DisplayHandle, gc, (IntPtr)mask);
3375 internal override void DrawReversibleLine(Point start, Point end, Color backColor)
3377 if (backColor.GetBrightness() < 0.5)
3378 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
3380 IntPtr gc = GetReversibleScreenGC (backColor);
3382 XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y);
3384 XFreeGC(DisplayHandle, gc);
3387 internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
3389 if (backColor.GetBrightness() < 0.5)
3390 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
3392 IntPtr gc = GetReversibleScreenGC (backColor);
3394 if (rectangle.Width < 0) {
3395 rectangle.X += rectangle.Width;
3396 rectangle.Width = -rectangle.Width;
3398 if (rectangle.Height < 0) {
3399 rectangle.Y += rectangle.Height;
3400 rectangle.Height = -rectangle.Height;
3404 GCLineStyle line_style = GCLineStyle.LineSolid;
3405 GCCapStyle cap_style = GCCapStyle.CapButt;
3406 GCJoinStyle join_style = GCJoinStyle.JoinMiter;
3409 case FrameStyle.Dashed:
3410 line_style = GCLineStyle.LineOnOffDash;
3412 case FrameStyle.Thick:
3417 XSetLineAttributes (DisplayHandle, gc, line_width, line_style, cap_style, join_style);
3419 XDrawRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3421 XFreeGC(DisplayHandle, gc);
3424 internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
3426 if (backColor.GetBrightness() < 0.5)
3427 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
3429 IntPtr gc = GetReversibleScreenGC (backColor);
3431 if (rectangle.Width < 0) {
3432 rectangle.X += rectangle.Width;
3433 rectangle.Width = -rectangle.Width;
3435 if (rectangle.Height < 0) {
3436 rectangle.Y += rectangle.Height;
3437 rectangle.Height = -rectangle.Height;
3439 XFillRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3441 XFreeGC(DisplayHandle, gc);
3444 internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width)
3447 Control control = Control.FromHandle(handle);
3449 gc = GetReversibleControlGC (control, line_width);
3451 if ((rect.Width > 0) && (rect.Height > 0)) {
3452 XDrawRectangle(DisplayHandle, control.Handle, gc, rect.Left, rect.Top, rect.Width, rect.Height);
3454 if (rect.Width > 0) {
3455 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.Right, rect.Y);
3457 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.X, rect.Bottom);
3460 XFreeGC(DisplayHandle, gc);
3463 internal override void DoEvents() {
3464 MSG msg = new MSG ();
3467 if (OverrideCursorHandle != IntPtr.Zero) {
3468 OverrideCursorHandle = IntPtr.Zero;
3471 queue = ThreadQueue(Thread.CurrentThread);
3473 queue.DispatchIdle = false;
3475 while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
3476 TranslateMessage (ref msg);
3477 DispatchMessage (ref msg);
3480 queue.DispatchIdle = true;
3483 internal override void EnableWindow(IntPtr handle, bool Enable) {
3486 hwnd = Hwnd.ObjectFromHandle(handle);
3488 hwnd.Enabled = Enable;
3492 internal override void EndLoop(Thread thread) {
3493 // This is where we one day will shut down the loop for the thread
3496 internal override IntPtr GetActive() {
3501 IntPtr prop = IntPtr.Zero;
3502 IntPtr active = IntPtr.Zero;
3504 XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
3505 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
3506 active = (IntPtr)Marshal.ReadInt32(prop);
3510 if (active != IntPtr.Zero) {
3513 hwnd = Hwnd.GetObjectFromWindow(active);
3515 active = hwnd.Handle;
3517 active = IntPtr.Zero;
3523 internal override Region GetClipRegion(IntPtr handle) {
3526 hwnd = Hwnd.ObjectFromHandle(handle);
3528 return hwnd.UserClip;
3534 internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) {
3541 internal override void GetDisplaySize(out Size size) {
3542 XWindowAttributes attributes=new XWindowAttributes();
3545 // FIXME - use _NET_WM messages instead?
3546 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
3549 size = new Size(attributes.width, attributes.height);
3552 internal override SizeF GetAutoScaleSize(Font font) {
3555 string magic_string = "The quick brown fox jumped over the lazy dog.";
3556 double magic_number = 44.549996948242189;
3558 g = Graphics.FromHwnd(FosterParent);
3560 width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
3561 return new SizeF(width, font.Height);
3564 internal override IntPtr GetParent(IntPtr handle) {
3567 hwnd = Hwnd.ObjectFromHandle(handle);
3568 if (hwnd != null && hwnd.parent != null) {
3569 return hwnd.parent.Handle;
3574 // This is a nop on win32 and x11
3575 internal override IntPtr GetPreviousWindow(IntPtr handle) {
3579 internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
3589 if (handle != IntPtr.Zero) {
3590 use_handle = Hwnd.ObjectFromHandle(handle).client_window;
3592 use_handle = RootWindow;
3596 QueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
3599 if (handle != IntPtr.Zero) {
3608 internal override IntPtr GetFocus() {
3613 internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) {
3614 FontFamily ff = font.FontFamily;
3615 ascent = ff.GetCellAscent (font.Style);
3616 descent = ff.GetCellDescent (font.Style);
3620 internal override Point GetMenuOrigin(IntPtr handle) {
3623 hwnd = Hwnd.ObjectFromHandle(handle);
3626 return hwnd.MenuOrigin;
3631 [MonoTODO("Implement filtering")]
3632 internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) {
3639 if (((XEventQueue)queue_id).Count > 0) {
3640 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3642 UpdateMessageQueue ((XEventQueue)queue_id);
3644 if (((XEventQueue)queue_id).Count > 0) {
3645 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3646 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
3647 xevent = ((XEventQueue)queue_id).Paint.Dequeue();
3649 msg.hwnd= IntPtr.Zero;
3650 msg.message = Msg.WM_ENTERIDLE;
3655 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
3657 // Handle messages for windows that are already or are about to be destroyed.
3659 // we need a special block for this because unless we remove the hwnd from the paint
3660 // queue it will always stay there (since we don't handle the expose), and we'll
3661 // effectively loop infinitely trying to repaint a non-existant window.
3662 if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
3663 hwnd.expose_pending = hwnd.nc_expose_pending = false;
3664 hwnd.Queue.Paint.Remove (hwnd);
3665 goto ProcessNextMessage;
3668 // We need to make sure we only allow DestroyNotify events through for zombie
3669 // hwnds, since much of the event handling code makes requests using the hwnd's
3670 // client_window, and that'll result in BadWindow errors if there's some lag
3671 // between the XDestroyWindow call and the DestroyNotify event.
3672 if (hwnd == null || hwnd.zombie && xevent.AnyEvent.type != XEventName.ClientMessage) {
3673 #if DriverDebug || DriverDebugDestroy
3674 Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
3676 goto ProcessNextMessage;
3679 if (hwnd.client_window == xevent.AnyEvent.window) {
3681 //Console.WriteLine("Client message {1}, sending to window {0:X}", msg.hwnd.ToInt32(), xevent.type);
3684 //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32());
3687 msg.hwnd = hwnd.Handle;
3689 // Windows sends WM_ENTERSIZEMOVE when a form resize/move operation starts and WM_EXITSIZEMOVE
3690 // when it is done. The problem in X11 is that there is no concept of start-end of a moving/sizing.
3691 // Configure events ("this window has resized/moved") are sent for each step of the resize. We send a
3692 // WM_ENTERSIZEMOVE when we get the first Configure event. The problem is the WM_EXITSIZEMOVE.
3694 // - There is no way for us to know which is the last Configure event. We can't traverse the events
3695 // queue, because the next configure event might not be pending yet.
3696 // - We can't get ButtonPress/Release events for the window decorations, because they are not part
3697 // of the window(s) we manage.
3698 // - We can't rely on the mouse state to change to "up" before the last Configure event. It doesn't.
3700 // We are almost 100% guaranteed to get another event (e.g Expose or other), but we can't know for sure
3701 // which, so we have here to check if the mouse buttons state is "up" and send the WM_EXITSIZEMOVE
3703 if (hwnd.resizing_or_moving) {
3704 int root_x, root_y, win_x, win_y, keys_buttons;
3706 XQueryPointer (DisplayHandle, hwnd.Handle, out root, out child, out root_x, out root_y,
3707 out win_x, out win_y, out keys_buttons);
3708 if ((keys_buttons & (int)MouseKeyMasks.Button1Mask) == 0 &&
3709 (keys_buttons & (int)MouseKeyMasks.Button2Mask) == 0 &&
3710 (keys_buttons & (int)MouseKeyMasks.Button3Mask) == 0) {
3711 hwnd.resizing_or_moving = false;
3712 SendMessage (hwnd.Handle, Msg.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
3717 // If you add a new event to this switch make sure to add it in
3718 // UpdateMessage also unless it is not coming through the X event system.
3720 switch(xevent.type) {
3721 case XEventName.KeyPress: {
3722 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3726 case XEventName.KeyRelease: {
3727 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3731 case XEventName.ButtonPress: {
3732 switch(xevent.ButtonEvent.button) {
3734 MouseState |= MouseButtons.Left;
3736 msg.message = Msg.WM_LBUTTONDOWN;
3737 msg.wParam = GetMousewParam (0);
3739 msg.message = Msg.WM_NCLBUTTONDOWN;
3740 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3741 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3747 MouseState |= MouseButtons.Middle;
3749 msg.message = Msg.WM_MBUTTONDOWN;
3750 msg.wParam = GetMousewParam (0);
3752 msg.message = Msg.WM_NCMBUTTONDOWN;
3753 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3754 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3760 MouseState |= MouseButtons.Right;
3762 msg.message = Msg.WM_RBUTTONDOWN;
3763 msg.wParam = GetMousewParam (0);
3765 msg.message = Msg.WM_NCRBUTTONDOWN;
3766 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3767 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3773 msg.hwnd = FocusWindow;
3774 msg.message=Msg.WM_MOUSEWHEEL;
3775 msg.wParam=GetMousewParam(120);
3780 msg.hwnd = FocusWindow;
3781 msg.message=Msg.WM_MOUSEWHEEL;
3782 msg.wParam=GetMousewParam(-120);
3788 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3789 mouse_position.X = xevent.ButtonEvent.x;
3790 mouse_position.Y = xevent.ButtonEvent.y;
3792 if (!hwnd.Enabled) {
3795 msg.hwnd = hwnd.EnabledHwnd;
3796 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);
3797 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3800 if (Grab.Hwnd != IntPtr.Zero) {
3801 msg.hwnd = Grab.Hwnd;
3804 if (ClickPending.Pending && ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
3805 // Looks like a genuine double click, clicked twice on the same spot with the same keys
3806 switch(xevent.ButtonEvent.button) {
3808 msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
3813 msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
3818 msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
3822 ClickPending.Pending = false;
3824 ClickPending.Pending = true;
3825 ClickPending.Hwnd = msg.hwnd;
3826 ClickPending.Message = msg.message;
3827 ClickPending.wParam = msg.wParam;
3828 ClickPending.lParam = msg.lParam;
3829 ClickPending.Time = (long)xevent.ButtonEvent.time;
3832 if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
3833 SendParentNotify(msg.hwnd, msg.message, mouse_position.X, mouse_position.Y);
3839 case XEventName.ButtonRelease: {
3840 switch(xevent.ButtonEvent.button) {
3843 msg.message = Msg.WM_LBUTTONUP;
3845 msg.message = Msg.WM_NCLBUTTONUP;
3846 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3847 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3849 MouseState &= ~MouseButtons.Left;
3850 msg.wParam = GetMousewParam (0);
3856 msg.message = Msg.WM_MBUTTONUP;
3858 msg.message = Msg.WM_NCMBUTTONUP;
3859 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3860 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3862 MouseState &= ~MouseButtons.Middle;
3863 msg.wParam = GetMousewParam (0);
3869 msg.message = Msg.WM_RBUTTONUP;
3871 msg.message = Msg.WM_NCRBUTTONUP;
3872 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3873 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3875 MouseState &= ~MouseButtons.Right;
3876 msg.wParam = GetMousewParam (0);
3881 goto ProcessNextMessage;
3885 goto ProcessNextMessage;
3889 if (!hwnd.Enabled) {
3892 msg.hwnd = hwnd.EnabledHwnd;
3893 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);
3894 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3897 if (Grab.Hwnd != IntPtr.Zero) {
3898 msg.hwnd = Grab.Hwnd;
3901 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3902 mouse_position.X = xevent.ButtonEvent.x;
3903 mouse_position.Y = xevent.ButtonEvent.y;
3905 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
3906 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
3907 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
3908 if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
3909 XEvent motionEvent = new XEvent ();
3910 motionEvent.type = XEventName.MotionNotify;
3911 motionEvent.MotionEvent.display = DisplayHandle;
3912 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
3913 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
3914 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
3915 hwnd.Queue.EnqueueLocked (motionEvent);
3920 case XEventName.MotionNotify: {
3922 #if DriverDebugExtra
3923 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);
3926 if (Grab.Hwnd != IntPtr.Zero) {
3927 msg.hwnd = Grab.Hwnd;
3930 NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
3934 if (xevent.MotionEvent.is_hint != 0)
3938 XQueryPointer (DisplayHandle, xevent.AnyEvent.window,
3939 out root, out child,
3940 out xevent.MotionEvent.x_root,
3941 out xevent.MotionEvent.y_root,
3942 out xevent.MotionEvent.x,
3943 out xevent.MotionEvent.y, out mask);
3946 msg.message = Msg.WM_MOUSEMOVE;
3947 msg.wParam = GetMousewParam(0);
3948 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
3950 if (!hwnd.Enabled) {
3953 msg.hwnd = hwnd.EnabledHwnd;
3954 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);
3955 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3958 mouse_position.X = xevent.MotionEvent.x;
3959 mouse_position.Y = xevent.MotionEvent.y;
3961 if ((HoverState.Timer.Enabled) &&
3962 (((mouse_position.X + HoverState.Size.Width) < HoverState.X) ||
3963 ((mouse_position.X - HoverState.Size.Width) > HoverState.X) ||
3964 ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) ||
3965 ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) {
3966 HoverState.Timer.Stop();
3967 HoverState.Timer.Start();
3968 HoverState.X = mouse_position.X;
3969 HoverState.Y = mouse_position.Y;
3977 #if DriverDebugExtra
3978 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);
3980 msg.message = Msg.WM_NCMOUSEMOVE;
3982 if (!hwnd.Enabled) {
3983 msg.hwnd = hwnd.EnabledHwnd;
3984 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);
3985 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3988 ht = NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3989 NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
3991 mouse_position.X = xevent.MotionEvent.x;
3992 mouse_position.Y = xevent.MotionEvent.y;
3998 case XEventName.EnterNotify: {
3999 if (!hwnd.Enabled) {
4000 goto ProcessNextMessage;
4002 if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || xevent.AnyEvent.window != hwnd.client_window) {
4003 goto ProcessNextMessage;
4005 if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) { // Pseudo motion caused by grabbing
4006 if (LastPointerWindow == xevent.AnyEvent.window)
4007 goto ProcessNextMessage;
4009 if (LastPointerWindow != IntPtr.Zero) {
4010 Point enter_loc = new Point (xevent.ButtonEvent.x, xevent.ButtonEvent.y);
4012 // We need this due to EnterNotify being fired on all the parent controls
4013 // of the Control being grabbed, and obviously in that scenario we are not
4014 // actuallty entering them
4015 Control ctrl = Control.FromHandle (hwnd.client_window);
4016 foreach (Control child_control in ctrl.Controls)
4017 if (child_control.Bounds.Contains (enter_loc))
4018 goto ProcessNextMessage;
4020 // A MouseLeave/LeaveNotify event is sent to the previous window
4021 // until the mouse is ungrabbed, not when actually leaving its bounds
4022 int x = xevent.CrossingEvent.x_root;
4023 int y = xevent.CrossingEvent.y_root;
4024 ScreenToClient (LastPointerWindow, ref x, ref y);
4026 XEvent leaveEvent = new XEvent ();
4027 leaveEvent.type = XEventName.LeaveNotify;
4028 leaveEvent.CrossingEvent.display = DisplayHandle;
4029 leaveEvent.CrossingEvent.window = LastPointerWindow;
4030 leaveEvent.CrossingEvent.x = x;
4031 leaveEvent.CrossingEvent.y = y;
4032 leaveEvent.CrossingEvent.mode = NotifyMode.NotifyNormal;
4033 Hwnd last_pointer_hwnd = Hwnd.ObjectFromHandle (LastPointerWindow);
4034 last_pointer_hwnd.Queue.EnqueueLocked (leaveEvent);
4038 LastPointerWindow = xevent.AnyEvent.window;
4040 msg.message = Msg.WM_MOUSE_ENTER;
4041 HoverState.X = xevent.CrossingEvent.x;
4042 HoverState.Y = xevent.CrossingEvent.y;
4043 HoverState.Timer.Enabled = true;
4044 HoverState.Window = xevent.CrossingEvent.window;
4046 // Win32 sends a WM_MOUSEMOVE after mouse enter
4047 XEvent motionEvent = new XEvent ();
4048 motionEvent.type = XEventName.MotionNotify;
4049 motionEvent.MotionEvent.display = DisplayHandle;
4050 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
4051 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
4052 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
4053 hwnd.Queue.EnqueueLocked (motionEvent);
4057 case XEventName.LeaveNotify: {
4058 if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) {
4059 WindowUngrabbed (hwnd.Handle);
4060 goto ProcessNextMessage;
4062 if (!hwnd.Enabled) {
4063 goto ProcessNextMessage;
4065 if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
4066 goto ProcessNextMessage;
4068 // If a grab is taking place, ignore it - we handle it in EnterNotify
4069 if (Grab.Hwnd != IntPtr.Zero)
4070 goto ProcessNextMessage;
4072 // Reset the cursor explicitly on X11.
4073 // X11 remembers the last set cursor for the window and in cases where
4074 // the control won't get a WM_SETCURSOR X11 will restore the last
4075 // known cursor, which we don't want.
4077 SetCursor (hwnd.client_window, IntPtr.Zero);
4079 msg.message=Msg.WM_MOUSELEAVE;
4080 HoverState.Timer.Enabled = false;
4081 HoverState.Window = IntPtr.Zero;
4086 case XEventName.CreateNotify: {
4087 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
4088 msg.message = WM_CREATE;
4089 // Set up CreateStruct
4091 goto ProcessNextMessage;
4098 case XEventName.ReparentNotify: {
4099 if (hwnd.parent == null) { // Toplevel
4100 if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) {
4101 hwnd.Reparented = true;
4103 // The location given by the event is not reliable between different wm's,
4104 // so use an alternative way of getting it.
4105 Point location = GetTopLevelWindowLocation (hwnd);
4106 hwnd.X = location.X;
4107 hwnd.Y = location.Y;
4109 if (hwnd.opacity != 0xffffffff) {
4112 opacity = (IntPtr)(Int32)hwnd.opacity;
4113 XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
4115 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
4116 goto ProcessNextMessage;
4118 hwnd.Reparented = false;
4119 goto ProcessNextMessage;
4122 goto ProcessNextMessage;
4125 case XEventName.ConfigureNotify: {
4126 if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4127 #if DriverDebugExtra
4128 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);
4131 lock (hwnd.configure_lock) {
4132 Form form = Control.FromHandle (hwnd.client_window) as Form;
4133 if (form != null && !hwnd.resizing_or_moving) {
4134 if (hwnd.x != form.Bounds.X || hwnd.y != form.Bounds.Y) {
4135 SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_MOVE, IntPtr.Zero);
4136 hwnd.resizing_or_moving = true;
4137 } else if (hwnd.width != form.Bounds.Width || hwnd.height != form.Bounds.Height) {
4138 SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_SIZE, IntPtr.Zero);
4139 hwnd.resizing_or_moving = true;
4141 if (hwnd.resizing_or_moving)
4142 SendMessage (form.Handle, Msg.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
4145 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4146 hwnd.configure_pending = false;
4148 // We need to adjust our client window to track the resize of whole_window
4149 if (hwnd.whole_window != hwnd.client_window)
4150 PerformNCCalc(hwnd);
4153 goto ProcessNextMessage;
4156 case XEventName.FocusIn: {
4157 // We received focus. We use X11 focus only to know if the app window does or does not have focus
4158 // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
4159 // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
4160 // about it having focus again
4161 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4162 goto ProcessNextMessage;
4165 if (FocusWindow == IntPtr.Zero) {
4166 Control c = Control.FromHandle (hwnd.client_window);
4168 goto ProcessNextMessage;
4169 Form form = c.FindForm ();
4171 goto ProcessNextMessage;
4172 if (ActiveWindow != form.Handle) {
4173 ActiveWindow = form.Handle;
4174 SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
4176 goto ProcessNextMessage;
4178 SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
4179 Keyboard.FocusIn (FocusWindow);
4180 goto ProcessNextMessage;
4183 case XEventName.FocusOut: {
4184 // Se the comment for our FocusIn handler
4185 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4186 goto ProcessNextMessage;
4189 while (Keyboard.ResetKeyState(FocusWindow, ref msg)) {
4190 SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam);
4193 Keyboard.FocusOut(hwnd.client_window);
4194 SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
4195 goto ProcessNextMessage;
4198 case XEventName.MapNotify: {
4199 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4201 msg.message = Msg.WM_SHOWWINDOW;
4202 msg.wParam = (IntPtr) 1;
4203 // XXX we're missing the lParam..
4206 goto ProcessNextMessage;
4209 case XEventName.UnmapNotify: {
4210 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4211 hwnd.mapped = false;
4212 msg.message = Msg.WM_SHOWWINDOW;
4213 msg.wParam = (IntPtr) 0;
4214 // XXX we're missing the lParam..
4217 goto ProcessNextMessage;
4220 case XEventName.Expose: {
4223 hwnd.expose_pending = false;
4225 hwnd.nc_expose_pending = false;
4227 goto ProcessNextMessage;
4231 if (!hwnd.expose_pending) {
4232 goto ProcessNextMessage;
4235 if (!hwnd.nc_expose_pending) {
4236 goto ProcessNextMessage;
4239 switch (hwnd.border_style) {
4240 case FormBorderStyle.Fixed3D: {
4243 g = Graphics.FromHwnd(hwnd.whole_window);
4244 if (hwnd.border_static)
4245 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter);
4247 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken);
4252 case FormBorderStyle.FixedSingle: {
4255 g = Graphics.FromHwnd(hwnd.whole_window);
4256 ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
4261 #if DriverDebugExtra
4262 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);
4265 Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
4266 Region region = new Region (rect);
4267 IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
4268 msg.message = Msg.WM_NCPAINT;
4269 msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
4270 msg.refobject = region;
4273 #if DriverDebugExtra
4274 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);
4276 if (Caret.Visible == true) {
4277 Caret.Paused = true;
4281 if (Caret.Visible == true) {
4283 Caret.Paused = false;
4285 msg.message = Msg.WM_PAINT;
4289 case XEventName.DestroyNotify: {
4291 // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
4292 hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
4294 // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
4295 if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) {
4296 CleanupCachedWindows (hwnd);
4298 #if DriverDebugDestroy
4299 Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window));
4302 msg.hwnd = hwnd.client_window;
4303 msg.message=Msg.WM_DESTROY;
4306 goto ProcessNextMessage;
4312 case XEventName.ClientMessage: {
4313 if (Dnd.HandleClientMessage (ref xevent)) {
4314 goto ProcessNextMessage;
4317 if (xevent.ClientMessageEvent.message_type == AsyncAtom) {
4318 XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
4319 goto ProcessNextMessage;
4322 if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
4323 msg.message = Msg.WM_MOUSEHOVER;
4324 msg.wParam = GetMousewParam(0);
4325 msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
4329 if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
4330 msg.hwnd = xevent.ClientMessageEvent.ptr1;
4331 msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
4332 msg.wParam = xevent.ClientMessageEvent.ptr3;
4333 msg.lParam = xevent.ClientMessageEvent.ptr4;
4334 if (msg.message == (Msg)Msg.WM_QUIT)
4340 if (xevent.ClientMessageEvent.message_type == _XEMBED) {
4341 #if DriverDebugXEmbed
4342 Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
4345 if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
4346 XSizeHints hints = new XSizeHints();
4349 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
4351 hwnd.width = hints.max_width;
4352 hwnd.height = hints.max_height;
4353 hwnd.ClientRect = Rectangle.Empty;
4354 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4358 if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) {
4359 if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) {
4360 SendMessage (msg.hwnd, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_CLOSE, IntPtr.Zero);
4361 msg.message = Msg.WM_CLOSE;
4365 // We should not get this, but I'll leave the code in case we need it in the future
4366 if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) {
4367 goto ProcessNextMessage;
4370 goto ProcessNextMessage;
4374 goto ProcessNextMessage;
4381 private HitTest NCHitTest (Hwnd hwnd, int x, int y)
4383 // The hit test is sent in screen coordinates
4385 int screen_x, screen_y;
4386 XTranslateCoordinates (DisplayHandle, hwnd.WholeWindow, RootWindow, x, y, out screen_x, out screen_y, out dummy);
4387 return (HitTest) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero,
4388 (IntPtr) (screen_y << 16 | screen_x & 0xFFFF));
4391 internal override bool GetText(IntPtr handle, out string text) {
4398 IntPtr prop = IntPtr.Zero;
4400 XGetWindowProperty(DisplayHandle, handle,
4401 _NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
4402 UNICODETEXT, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
4404 if ((long)nitems > 0 && prop != IntPtr.Zero) {
4405 text = Marshal.PtrToStringUni (prop, (int)nitems);
4410 // fallback on the non-_NET property
4413 textptr = IntPtr.Zero;
4415 XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr);
4416 if (textptr != IntPtr.Zero) {
4417 text = Marshal.PtrToStringAnsi(textptr);
4428 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) {
4431 hwnd = Hwnd.ObjectFromHandle(handle);
4437 height = hwnd.height;
4439 PerformNCCalc(hwnd);
4441 client_width = hwnd.ClientRect.Width;
4442 client_height = hwnd.ClientRect.Height;
4447 // Should we throw an exception or fail silently?
4448 // throw new ArgumentException("Called with an invalid window handle", "handle");
4458 internal override FormWindowState GetWindowState(IntPtr handle) {
4461 hwnd = Hwnd.ObjectFromHandle(handle);
4463 if (hwnd.cached_window_state == (FormWindowState)(-1))
4464 hwnd.cached_window_state = UpdateWindowState (handle);
4466 return hwnd.cached_window_state;
4469 private FormWindowState UpdateWindowState (IntPtr handle) {
4474 IntPtr prop = IntPtr.Zero;
4478 XWindowAttributes attributes;
4481 hwnd = Hwnd.ObjectFromHandle(handle);
4485 XGetWindowProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
4486 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
4487 for (int i = 0; i < (long)nitems; i++) {
4488 atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
4489 if ((atom == _NET_WM_STATE_MAXIMIZED_HORZ) || (atom == _NET_WM_STATE_MAXIMIZED_VERT)) {
4491 } else if (atom == _NET_WM_STATE_HIDDEN) {
4499 return FormWindowState.Minimized;
4500 } else if (maximized == 2) {
4501 return FormWindowState.Maximized;
4504 attributes = new XWindowAttributes();
4505 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4506 if (attributes.map_state == MapState.IsUnmapped) {
4507 return (FormWindowState)(-1);
4511 return FormWindowState.Normal;
4514 internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) {
4516 GrabConfined = Grab.Confined;
4517 GrabArea = Grab.Area;
4520 internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) {
4522 IntPtr confine_to_window;
4524 confine_to_window = IntPtr.Zero;
4526 if (confine_to_handle != IntPtr.Zero) {
4527 XWindowAttributes attributes = new XWindowAttributes();
4529 hwnd = Hwnd.ObjectFromHandle(confine_to_handle);
4532 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4534 Grab.Area.X = attributes.x;
4535 Grab.Area.Y = attributes.y;
4536 Grab.Area.Width = attributes.width;
4537 Grab.Area.Height = attributes.height;
4538 Grab.Confined = true;
4539 confine_to_window = hwnd.client_window;
4544 hwnd = Hwnd.ObjectFromHandle(handle);
4547 XGrabPointer(DisplayHandle, hwnd.client_window, false,
4548 EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
4549 EventMask.ButtonReleaseMask | EventMask.PointerMotionMask |
4550 EventMask.PointerMotionHintMask | EventMask.LeaveWindowMask,
4551 GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
4555 internal override void UngrabWindow(IntPtr hwnd) {
4557 XUngrabPointer(DisplayHandle, IntPtr.Zero);
4558 XFlush(DisplayHandle);
4560 WindowUngrabbed (hwnd);
4563 private void WindowUngrabbed (IntPtr hwnd) {
4564 bool was_grabbed = Grab.Hwnd != IntPtr.Zero;
4566 Grab.Hwnd = IntPtr.Zero;
4567 Grab.Confined = false;
4570 // lparam should be the handle to the window gaining the mouse capture,
4571 // but X doesn't seem to give us that information.
4572 // Also only generate WM_CAPTURECHANGED if the window actually was grabbed.
4573 // X will send a NotifyUngrab, but since it comes late sometimes we're
4574 // calling WindowUngrabbed directly from UngrabWindow in order to send
4575 // this WM right away.
4576 SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero);
4580 internal override void HandleException(Exception e) {
4581 StackTrace st = new StackTrace(e, true);
4582 Console.WriteLine("Exception '{0}'", e.Message+st.ToString());
4583 Console.WriteLine("{0}{1}", e.Message, st.ToString());
4586 internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
4589 hwnd = Hwnd.ObjectFromHandle(handle);
4592 AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height);
4594 AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height);
4598 internal override void InvalidateNC (IntPtr handle) {
4601 hwnd = Hwnd.ObjectFromHandle(handle);
4603 AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
4606 internal override bool IsEnabled(IntPtr handle) {
4607 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4608 return (hwnd != null && hwnd.Enabled);
4611 internal override bool IsVisible(IntPtr handle) {
4612 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4613 return (hwnd != null && hwnd.visible);
4616 internal override void KillTimer(Timer timer) {
4617 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
4619 if (queue == null) {
4620 // This isn't really an error, MS doesn't start the timer if
4621 // it has no assosciated queue. In this case, remove the timer
4622 // from the list of unattached timers (if it was enabled).
4623 lock (unattached_timer_list) {
4624 if (unattached_timer_list.Contains (timer))
4625 unattached_timer_list.Remove (timer);
4629 queue.timer_list.Remove (timer);
4632 internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) {
4638 hwnd = Hwnd.ObjectFromHandle(handle);
4641 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
4648 internal override void OverrideCursor(IntPtr cursor)
4650 if (Grab.Hwnd != IntPtr.Zero) {
4651 XChangeActivePointerGrab (DisplayHandle,
4652 EventMask.ButtonMotionMask |
4653 EventMask.PointerMotionMask |
4654 EventMask.PointerMotionHintMask |
4655 EventMask.ButtonPressMask |
4656 EventMask.ButtonReleaseMask,
4657 cursor, IntPtr.Zero);
4661 OverrideCursorHandle = cursor;
4664 internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) {
4665 PaintEventArgs paint_event;
4670 // handle (and paint_hwnd) refers to the window that is should be painted.
4671 // msg.HWnd (and hwnd) refers to the window that got the paint message.
4674 hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
4675 if (msg.HWnd == handle) {
4678 paint_hwnd = Hwnd.ObjectFromHandle (handle);
4681 if (Caret.Visible == true) {
4682 Caret.Paused = true;
4689 dc = Graphics.FromHwnd (paint_hwnd.client_window);
4691 Region clip_region = new Region ();
4692 clip_region.MakeEmpty();
4694 foreach (Rectangle r in hwnd.ClipRectangles) {
4695 clip_region.Union (r);
4698 if (hwnd.UserClip != null) {
4699 clip_region.Intersect(hwnd.UserClip);
4702 dc.Clip = clip_region;
4703 paint_event = new PaintEventArgs(dc, hwnd.Invalid);
4704 hwnd.expose_pending = false;
4706 hwnd.ClearInvalidArea();
4708 hwnd.drawing_stack.Push (paint_event);
4709 hwnd.drawing_stack.Push (dc);
4713 dc = Graphics.FromHwnd (paint_hwnd.whole_window);
4715 if (!hwnd.nc_invalid.IsEmpty) {
4716 dc.SetClip (hwnd.nc_invalid);
4717 paint_event = new PaintEventArgs(dc, hwnd.nc_invalid);
4719 paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height));
4721 hwnd.nc_expose_pending = false;
4723 hwnd.ClearNcInvalidArea ();
4725 hwnd.drawing_stack.Push (paint_event);
4726 hwnd.drawing_stack.Push (dc);
4732 internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) {
4735 hwnd = Hwnd.ObjectFromHandle (msg.HWnd);
4737 Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
4741 PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop();
4742 pe.SetGraphics (null);
4745 if (Caret.Visible == true) {
4747 Caret.Paused = false;
4751 [MonoTODO("Implement filtering and PM_NOREMOVE")]
4752 internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
4753 XEventQueue queue = (XEventQueue) queue_id;
4756 if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
4757 throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
4761 if (queue.Count > 0) {
4764 // Only call UpdateMessageQueue if real events are pending
4765 // otherwise we go to sleep on the socket
4766 if (XPending(DisplayHandle) != 0) {
4767 UpdateMessageQueue((XEventQueue)queue_id);
4769 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
4774 CheckTimers(queue.timer_list, DateTime.UtcNow);
4779 return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
4782 internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) {
4783 XEvent xevent = new XEvent ();
4784 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
4786 xevent.type = XEventName.ClientMessage;
4787 xevent.ClientMessageEvent.display = DisplayHandle;
4790 xevent.ClientMessageEvent.window = hwnd.whole_window;
4792 xevent.ClientMessageEvent.window = IntPtr.Zero;
4795 xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
4796 xevent.ClientMessageEvent.format = 32;
4797 xevent.ClientMessageEvent.ptr1 = handle;
4798 xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
4799 xevent.ClientMessageEvent.ptr3 = wparam;
4800 xevent.ClientMessageEvent.ptr4 = lparam;
4803 hwnd.Queue.EnqueueLocked (xevent);
4805 ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent);
4810 internal override void PostQuitMessage(int exitCode) {
4811 ApplicationContext ctx = Application.MWFThread.Current.Context;
4812 Form f = ctx != null ? ctx.MainForm : null;
4814 PostMessage (Application.MWFThread.Current.Context.MainForm.window.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4816 PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4817 XFlush(DisplayHandle);
4820 internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave)
4825 internal override void RequestNCRecalc(IntPtr handle) {
4828 hwnd = Hwnd.ObjectFromHandle(handle);
4834 PerformNCCalc(hwnd);
4835 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4836 InvalidateNC(handle);
4839 internal override void ResetMouseHover(IntPtr handle) {
4842 hwnd = Hwnd.ObjectFromHandle(handle);
4847 HoverState.Timer.Enabled = true;
4848 HoverState.X = mouse_position.X;
4849 HoverState.Y = mouse_position.Y;
4850 HoverState.Window = handle;
4854 internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) {
4860 hwnd = Hwnd.ObjectFromHandle(handle);
4863 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
4870 internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) {
4876 hwnd = Hwnd.ObjectFromHandle(handle);
4879 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
4882 Form form = Control.FromHandle (handle) as Form;
4883 if (form != null && form.window_manager != null) {
4884 dest_y_return -= form.window_manager.TitleBarHeight;
4891 bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg)
4893 return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) &&
4894 arg == xevent.GraphicsExposeEvent.drawable;
4897 delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg);
4899 void ProcessGraphicsExpose (Hwnd hwnd)
4901 XEvent xevent = new XEvent ();
4902 IntPtr handle = Hwnd.HandleFromObject (hwnd);
4903 EventPredicate predicate = GraphicsExposePredicate;
4906 XIfEvent (Display, ref xevent, predicate, handle);
4907 if (xevent.type != XEventName.GraphicsExpose)
4910 AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y,
4911 xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height);
4913 if (xevent.GraphicsExposeEvent.count == 0)
4918 internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
4921 XGCValues gc_values;
4923 hwnd = Hwnd.ObjectFromHandle(handle);
4925 Rectangle r = Rectangle.Intersect (hwnd.Invalid, area);
4927 /* We have an invalid area in the window we're scrolling.
4928 Adjust our stored invalid rectangle to to match the scrolled amount */
4943 if (area.Contains (hwnd.Invalid))
4944 hwnd.ClearInvalidArea ();
4945 hwnd.AddInvalidArea(r);
4948 gc_values = new XGCValues();
4950 if (with_children) {
4951 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
4954 gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
4956 Rectangle visible_rect = GetTotalVisibleArea (hwnd.client_window);
4957 visible_rect.Intersect (area);
4959 Rectangle dest_rect = visible_rect;
4960 dest_rect.Y += YAmount;
4961 dest_rect.X += XAmount;
4962 dest_rect.Intersect (area);
4964 Point src = new Point (dest_rect.X - XAmount, dest_rect.Y - YAmount);
4965 XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src.X, src.Y,
4966 dest_rect.Width, dest_rect.Height, dest_rect.X, dest_rect.Y);
4968 Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount);
4969 AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height);
4971 ProcessGraphicsExpose (hwnd);
4973 XFreeGC(DisplayHandle, gc);
4976 internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) {
4980 hwnd = Hwnd.GetObjectFromWindow(handle);
4982 rect = hwnd.ClientRect;
4985 ScrollWindow(handle, rect, XAmount, YAmount, with_children);
4988 Rectangle GetDirtyArea (Rectangle total_area, Rectangle valid_area, int XAmount, int YAmount)
4990 Rectangle dirty_area = total_area;
4993 dirty_area.Height -= valid_area.Height;
4994 else if (YAmount < 0) {
4995 dirty_area.Height -= valid_area.Height;
4996 dirty_area.Y += valid_area.Height;
5000 dirty_area.Width -= valid_area.Width;
5001 else if (XAmount < 0) {
5002 dirty_area.Width -= valid_area.Width;
5003 dirty_area.X += valid_area.Width;
5009 Rectangle GetTotalVisibleArea (IntPtr handle)
5011 Control c = Control.FromHandle (handle);
5013 Rectangle visible_area = c.ClientRectangle;
5014 visible_area.Location = c.PointToScreen (Point.Empty);
5016 for (Control parent = c.Parent; parent != null; parent = parent.Parent) {
5017 if (!parent.IsHandleCreated || !parent.Visible)
5018 return visible_area; // Non visible, not need to finish computations
5020 Rectangle r = parent.ClientRectangle;
5021 r.Location = parent.PointToScreen (Point.Empty);
5023 visible_area.Intersect (r);
5026 visible_area.Location = c.PointToClient (visible_area.Location);
5027 return visible_area;
5030 internal override void SendAsyncMethod (AsyncMethodData method) {
5032 XEvent xevent = new XEvent ();
5034 hwnd = Hwnd.ObjectFromHandle(method.Handle);
5036 xevent.type = XEventName.ClientMessage;
5037 xevent.ClientMessageEvent.display = DisplayHandle;
5038 xevent.ClientMessageEvent.window = method.Handle;
5039 xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
5040 xevent.ClientMessageEvent.format = 32;
5041 xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
5043 hwnd.Queue.EnqueueLocked (xevent);
5048 delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
5050 internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
5053 h = Hwnd.ObjectFromHandle(hwnd);
5055 if (h != null && h.queue != ThreadQueue (Thread.CurrentThread)) {
5056 AsyncMethodResult result;
5057 AsyncMethodData data;
5059 result = new AsyncMethodResult ();
5060 data = new AsyncMethodData ();
5063 data.Method = new WndProcDelegate (NativeWindow.WndProc);
5064 data.Args = new object[] { hwnd, message, wParam, lParam };
5065 data.Result = result;
5067 SendAsyncMethod (data);
5068 #if DriverDebug || DriverDebugThreads
5069 Console.WriteLine ("Sending {0} message across.", message);
5074 return NativeWindow.WndProc(hwnd, message, wParam, lParam);
5077 internal override int SendInput(IntPtr handle, Queue keys) {
5078 if (handle == IntPtr.Zero)
5081 int count = keys.Count;
5082 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5084 while (keys.Count > 0) {
5086 MSG msg = (MSG)keys.Dequeue();
5088 XEvent xevent = new XEvent ();
5090 xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
5091 xevent.KeyEvent.display = DisplayHandle;
5094 xevent.KeyEvent.window = hwnd.whole_window;
5096 xevent.KeyEvent.window = IntPtr.Zero;
5099 xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
5101 hwnd.Queue.EnqueueLocked (xevent);
5106 internal override void SetAllowDrop (IntPtr handle, bool value)
5108 // We allow drop on all windows
5111 internal override DragDropEffects StartDrag (IntPtr handle, object data,
5112 DragDropEffects allowed_effects)
5114 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
5117 throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
5119 return Dnd.StartDrag (hwnd.client_window, data, allowed_effects);
5122 internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
5123 Form form = Control.FromHandle (handle) as Form;
5124 if (form != null && form.window_manager == null) {
5125 CreateParams cp = form.GetCreateParams ();
5126 if (border_style == FormBorderStyle.FixedToolWindow ||
5127 border_style == FormBorderStyle.SizableToolWindow ||
5128 cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
5129 form.window_manager = new ToolWindowManager (form);
5133 RequestNCRecalc(handle);
5136 internal override void SetCaretPos(IntPtr handle, int x, int y) {
5137 if (Caret.Hwnd == handle) {
5144 Keyboard.SetCaretPos (Caret, handle, x, y);
5146 if (Caret.Visible == true) {
5148 Caret.Timer.Start();
5153 internal override void SetClipRegion(IntPtr handle, Region region) {
5156 hwnd = Hwnd.ObjectFromHandle(handle);
5161 hwnd.UserClip = region;
5164 internal override void SetCursor(IntPtr handle, IntPtr cursor) {
5167 if (OverrideCursorHandle == IntPtr.Zero) {
5168 if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
5172 LastCursorHandle = cursor;
5173 LastCursorWindow = handle;
5175 hwnd = Hwnd.ObjectFromHandle(handle);
5177 if (cursor != IntPtr.Zero) {
5178 XDefineCursor(DisplayHandle, hwnd.whole_window, cursor);
5180 XUndefineCursor(DisplayHandle, hwnd.whole_window);
5182 XFlush(DisplayHandle);
5187 hwnd = Hwnd.ObjectFromHandle(handle);
5189 XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
5193 private void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child,
5194 out int root_x, out int root_y, out int child_x, out int child_y,
5197 /* this code was written with the help of
5198 glance at gdk. I never would have realized we
5199 needed a loop in order to traverse down in the
5200 hierarchy. I would have assumed you'd get the
5201 most deeply nested child and have to do
5202 XQueryTree to move back up the hierarchy..
5203 stupid me, of course. */
5206 XGrabServer (display);
5208 XQueryPointer(display, w, out root, out c,
5209 out root_x, out root_y, out child_x, out child_y,
5215 IntPtr child_last = IntPtr.Zero;
5216 while (c != IntPtr.Zero) {
5218 XQueryPointer(display, c, out root, out c,
5219 out root_x, out root_y, out child_x, out child_y,
5222 XUngrabServer (display);
5228 internal override void SetCursorPos(IntPtr handle, int x, int y) {
5229 if (handle == IntPtr.Zero) {
5232 int root_x, root_y, child_x, child_y, mask;
5235 * QueryPointer before warping
5236 * because if the warp is on
5237 * the RootWindow, the x/y are
5238 * relative to the current
5241 QueryPointer (DisplayHandle, RootWindow,
5244 out root_x, out root_y,
5245 out child_x, out child_y,
5248 XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
5250 XFlush (DisplayHandle);
5252 /* then we need to a
5253 * QueryPointer after warping
5254 * to manually generate a
5255 * motion event for the window
5258 QueryPointer (DisplayHandle, RootWindow,
5261 out root_x, out root_y,
5262 out child_x, out child_y,
5265 Hwnd child_hwnd = Hwnd.ObjectFromHandle(child);
5266 if (child_hwnd == null) {
5270 XEvent xevent = new XEvent ();
5272 xevent.type = XEventName.MotionNotify;
5273 xevent.MotionEvent.display = DisplayHandle;
5274 xevent.MotionEvent.window = child_hwnd.client_window;
5275 xevent.MotionEvent.root = RootWindow;
5276 xevent.MotionEvent.x = child_x;
5277 xevent.MotionEvent.y = child_y;
5278 xevent.MotionEvent.x_root = root_x;
5279 xevent.MotionEvent.y_root = root_y;
5280 xevent.MotionEvent.state = mask;
5282 child_hwnd.Queue.EnqueueLocked (xevent);
5287 hwnd = Hwnd.ObjectFromHandle(handle);
5289 XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
5294 internal override void SetFocus(IntPtr handle) {
5296 IntPtr prev_focus_window;
5298 hwnd = Hwnd.ObjectFromHandle(handle);
5300 if (hwnd.client_window == FocusWindow) {
5304 // Win32 doesn't do anything if disabled
5308 prev_focus_window = FocusWindow;
5309 FocusWindow = hwnd.client_window;
5311 if (prev_focus_window != IntPtr.Zero) {
5312 SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
5314 SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
5315 Keyboard.FocusIn (FocusWindow);
5317 //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
5320 internal override void SetIcon(IntPtr handle, Icon icon) {
5323 hwnd = Hwnd.ObjectFromHandle(handle);
5325 SetIcon(hwnd, icon);
5329 internal override void SetMenu(IntPtr handle, Menu menu) {
5332 hwnd = Hwnd.ObjectFromHandle(handle);
5335 RequestNCRecalc(handle);
5338 internal override void SetModal(IntPtr handle, bool Modal) {
5340 ModalWindows.Push(handle);
5342 if (ModalWindows.Contains(handle)) {
5345 if (ModalWindows.Count > 0) {
5346 Activate((IntPtr)ModalWindows.Peek());
5350 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
5351 Control ctrl = Control.FromHandle (handle);
5352 SetWMStyles (hwnd, ctrl.GetCreateParams ());
5355 internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
5358 hwnd = Hwnd.ObjectFromHandle(handle);
5359 hwnd.parent = Hwnd.ObjectFromHandle(parent);
5362 #if DriverDebug || DriverDebugParent
5363 Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(hwnd.Handle), XplatUI.Window(hwnd.parent != null ? hwnd.parent.Handle : IntPtr.Zero));
5365 XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent == null ? FosterParent : hwnd.parent.client_window, hwnd.x, hwnd.y);
5371 internal override void SetTimer (Timer timer) {
5372 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
5374 if (queue == null) {
5375 // This isn't really an error, MS doesn't start the timer if
5376 // it has no assosciated queue at this stage (it will be
5377 // enabled when a window is activated).
5378 unattached_timer_list.Add (timer);
5381 queue.timer_list.Add (timer);
5385 internal override bool SetTopmost(IntPtr handle, bool enabled) {
5387 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5391 int[] atoms = new int[8];
5392 atoms[0] = _NET_WM_STATE_ABOVE.ToInt32();
5393 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5397 XDeleteProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE);
5403 internal override bool SetOwner(IntPtr handle, IntPtr handle_owner) {
5407 hwnd = Hwnd.ObjectFromHandle(handle);
5409 if (handle_owner != IntPtr.Zero) {
5410 hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
5416 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
5417 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5419 if (hwnd_owner != null) {
5420 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
5422 XSetTransientForHint(DisplayHandle, hwnd.whole_window, RootWindow);
5427 XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR);
5433 internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
5437 hwnd = Hwnd.ObjectFromHandle(handle);
5438 hwnd.visible = visible;
5442 MapWindow(hwnd, WindowType.Both);
5444 if (Control.FromHandle(handle) is Form) {
5447 s = ((Form)Control.FromHandle(handle)).WindowState;
5450 case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break;
5451 case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break;
5455 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5458 UnmapWindow(hwnd, WindowType.Both);
5464 internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
5465 Control ctrl = Control.FromHandle (handle);
5466 SetWindowMinMax (handle, maximized, min, max, ctrl != null ? ctrl.GetCreateParams () : null);
5469 internal void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp)
5475 hwnd = Hwnd.ObjectFromHandle(handle);
5480 min.Width = Math.Max (min.Width, SystemInformation.MinimumWindowSize.Width);
5481 min.Height = Math.Max (min.Height, SystemInformation.MinimumWindowSize.Height);
5483 hints = new XSizeHints();
5485 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
5486 if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
5488 min = TranslateWindowSizeToXWindowSize (cp, min);
5489 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
5490 hints.min_width = min.Width;
5491 hints.min_height = min.Height;
5494 if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
5496 max = TranslateWindowSizeToXWindowSize (cp, max);
5497 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
5498 hints.max_width = max.Width;
5499 hints.max_height = max.Height;
5502 if (hints.flags != IntPtr.Zero) {
5503 // The Metacity team has decided that they won't care about this when clicking the maximize icon,
5504 // they will maximize the window to fill the screen/parent no matter what.
5505 // http://bugzilla.ximian.com/show_bug.cgi?id=80021
5506 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints);
5509 if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
5511 maximized.Size = TranslateWindowSizeToXWindowSize (cp);
5512 hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
5513 hints.x = maximized.X;
5514 hints.y = maximized.Y;
5515 hints.width = maximized.Width;
5516 hints.height = maximized.Height;
5518 // Metacity does not seem to follow this constraint for maximized (zoomed) windows
5519 XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints);
5524 internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
5527 hwnd = Hwnd.ObjectFromHandle(handle);
5533 // Win32 automatically changes negative width/height to 0.
5539 // X requires a sanity check for width & height; otherwise it dies
5540 if (hwnd.zero_sized && width > 0 && height > 0) {
5542 MapWindow(hwnd, WindowType.Whole);
5544 hwnd.zero_sized = false;
5547 if ((width < 1) || (height < 1)) {
5548 hwnd.zero_sized = true;
5549 UnmapWindow(hwnd, WindowType.Whole);
5552 // Save a server roundtrip (and prevent a feedback loop)
5553 if ((hwnd.x == x) && (hwnd.y == y) &&
5554 (hwnd.width == width) && (hwnd.height == height)) {
5558 if (!hwnd.zero_sized) {
5563 hwnd.height = height;
5564 SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5566 if (hwnd.fixed_size) {
5567 SetWindowMinMax(handle, Rectangle.Empty, new Size(width, height), new Size(width, height));
5571 Control ctrl = Control.FromHandle (handle);
5572 Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams (), new Size (width, height));
5573 MoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
5574 PerformNCCalc(hwnd);
5578 // Update our position/size immediately, so
5579 // that future calls to SetWindowPos aren't
5580 // kept from calling XMoveResizeWindow (by the
5581 // "Save a server roundtrip" block above).
5585 hwnd.height = height;
5586 hwnd.ClientRect = Rectangle.Empty;
5589 internal override void SetWindowState(IntPtr handle, FormWindowState state) {
5590 FormWindowState current_state;
5593 hwnd = Hwnd.ObjectFromHandle(handle);
5595 current_state = GetWindowState(handle);
5597 if (current_state == state) {
5602 case FormWindowState.Normal: {
5604 if (current_state == FormWindowState.Minimized) {
5605 MapWindow(hwnd, WindowType.Both);
5606 } else if (current_state == FormWindowState.Maximized) {
5607 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5614 case FormWindowState.Minimized: {
5616 if (current_state == FormWindowState.Maximized) {
5617 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5619 XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo);
5624 case FormWindowState.Maximized: {
5626 if (current_state == FormWindowState.Minimized) {
5627 MapWindow(hwnd, WindowType.Both);
5630 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)1 /* Add */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5638 internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
5641 hwnd = Hwnd.ObjectFromHandle(handle);
5642 SetHwndStyles(hwnd, cp);
5643 SetWMStyles(hwnd, cp);
5646 internal override double GetWindowTransparency(IntPtr handle)
5651 internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) {
5655 hwnd = Hwnd.ObjectFromHandle(handle);
5661 hwnd.opacity = (uint)(0xffffffff * transparency);
5662 opacity = (IntPtr)((int)hwnd.opacity);
5664 IntPtr w = hwnd.whole_window;
5665 if (hwnd.reparented)
5666 w = XGetParent (hwnd.whole_window);
5667 XChangeProperty(DisplayHandle, w, _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
5670 internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) {
5671 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5679 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5682 } else if (!bottom) {
5683 Hwnd after_hwnd = null;
5685 if (after_handle != IntPtr.Zero) {
5686 after_hwnd = Hwnd.ObjectFromHandle(after_handle);
5689 XWindowChanges values = new XWindowChanges();
5691 if (after_hwnd == null) {
5692 // Work around metacity 'issues'
5696 atoms[0] = unixtime();
5697 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_USER_TIME, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, atoms, 1);
5699 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5700 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
5702 //throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order");
5705 values.sibling = after_hwnd.whole_window;
5706 values.stack_mode = StackMode.Below;
5709 XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
5714 XLowerWindow(DisplayHandle, hwnd.whole_window);
5721 internal override void ShowCursor(bool show) {
5722 ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
5725 internal override object StartLoop(Thread thread) {
5726 XEventQueue q = ThreadQueue(thread);
5730 internal override TransparencySupport SupportsTransparency() {
5731 // We need to check if the x compositing manager is running
5732 return TransparencySupport.Set;
5735 internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) {
5736 GetSystrayManagerWindow();
5738 if (SystrayMgrWindow != IntPtr.Zero) {
5739 XSizeHints size_hints;
5742 hwnd = Hwnd.ObjectFromHandle(handle);
5744 Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
5748 if (hwnd.client_window != hwnd.whole_window) {
5749 Keyboard.DestroyICForWindow (hwnd.client_window);
5750 XDestroyWindow(DisplayHandle, hwnd.client_window);
5751 hwnd.client_window = hwnd.whole_window;
5754 /* by virtue of the way the tests are ordered when determining if it's PAINT
5755 or NCPAINT, client_window == whole_window will always be PAINT. So, if we're
5756 waiting on an nc_expose, drop it and remove the hwnd from the list (unless
5757 there's a pending expose). */
5758 if (hwnd.nc_expose_pending) {
5759 hwnd.nc_expose_pending = false;
5760 if (!hwnd.expose_pending)
5761 hwnd.Queue.Paint.Remove (hwnd);
5764 size_hints = new XSizeHints();
5766 size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
5768 size_hints.min_width = 24;
5769 size_hints.min_height = 24;
5770 size_hints.max_width = 24;
5771 size_hints.max_height = 24;
5772 size_hints.base_width = 24;
5773 size_hints.base_height = 24;
5775 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints);
5777 int[] atoms = new int[2];
5778 atoms [0] = 1; // Version 1
5779 atoms [1] = 1; // we want to be mapped
5781 // This line cost me 3 days...
5782 XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2);
5784 // Need to pick some reasonable defaults
5786 tt.AutomaticDelay = 350;
5787 tt.InitialDelay = 250;
5788 tt.ReshowDelay = 250;
5789 tt.ShowAlways = true;
5791 if ((tip != null) && (tip != string.Empty)) {
5792 tt.SetToolTip(Control.FromHandle(handle), tip);
5798 SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
5806 internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) {
5809 control = Control.FromHandle(handle);
5810 if (control != null && tt != null) {
5811 tt.SetToolTip(control, tip);
5813 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5820 internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
5822 SetVisible (handle, false, false);
5824 // The caller can now re-dock it later...
5832 internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
5834 ThemeEngine.Current.ShowBalloonWindow (handle, timeout, title, text, icon);
5835 SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW);
5839 internal override bool Text(IntPtr handle, string text) {
5842 hwnd = Hwnd.ObjectFromHandle(handle);
5845 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_NAME, UNICODETEXT, 8,
5846 PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
5848 // XXX this has problems with UTF8.
5849 // we need to either use the actual
5850 // text if it's latin-1, or convert it
5851 // to compound text if it's in a
5852 // different charset.
5853 XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text);
5858 internal override bool TranslateMessage(ref MSG msg) {
5859 return Keyboard.TranslateMessage (ref msg);
5862 internal override void UpdateWindow(IntPtr handle) {
5865 hwnd = Hwnd.ObjectFromHandle(handle);
5867 if (!hwnd.visible || !hwnd.expose_pending || !hwnd.Mapped) {
5871 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5872 hwnd.Queue.Paint.Remove(hwnd);
5875 internal override void CreateOffscreenDrawable (IntPtr handle,
5876 int width, int height,
5877 out object offscreen_drawable)
5880 int x_out, y_out, width_out, height_out, border_width_out, depth_out;
5882 XGetGeometry (DisplayHandle, handle,
5884 out x_out, out y_out,
5885 out width_out, out height_out,
5886 out border_width_out, out depth_out);
5888 IntPtr pixmap = XCreatePixmap (DisplayHandle, handle, width, height, depth_out);
5890 offscreen_drawable = pixmap;
5894 internal override void DestroyOffscreenDrawable (object offscreen_drawable)
5896 XFreePixmap (DisplayHandle, (IntPtr)offscreen_drawable);
5899 internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
5901 return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
5904 internal override void BlitFromOffscreen (IntPtr dest_handle,
5906 object offscreen_drawable,
5907 Graphics offscreen_dc,
5910 XGCValues gc_values;
5913 gc_values = new XGCValues();
5915 gc = XCreateGC (DisplayHandle, dest_handle, IntPtr.Zero, ref gc_values);
5917 XCopyArea (DisplayHandle, (IntPtr)offscreen_drawable, dest_handle,
5918 gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
5920 XFreeGC (DisplayHandle, gc);
5923 #endregion // Public Static Methods
5926 internal override event EventHandler Idle;
5927 #endregion // Events
5929 #region Xcursor imports
5930 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")]
5931 internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name);
5933 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")]
5934 internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size);
5936 [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")]
5937 internal extern static void XcursorImagesDestroy (IntPtr images);
5939 [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")]
5940 internal extern static int XcursorGetDefaultSize (IntPtr display);
5942 [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")]
5943 internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image);
5945 [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")]
5946 internal extern static IntPtr XcursorGetTheme (IntPtr display);
5949 [DllImport ("libX11", EntryPoint="XOpenDisplay")]
5950 internal extern static IntPtr XOpenDisplay(IntPtr display);
5951 [DllImport ("libX11", EntryPoint="XCloseDisplay")]
5952 internal extern static int XCloseDisplay(IntPtr display);
5953 [DllImport ("libX11", EntryPoint="XSynchronize")]
5954 internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
5956 [DllImport ("libX11", EntryPoint="XCreateWindow")]
5957 internal extern static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes);
5958 [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
5959 internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
5960 [DllImport ("libX11", EntryPoint="XMapWindow")]
5961 internal extern static int XMapWindow(IntPtr display, IntPtr window);
5962 [DllImport ("libX11", EntryPoint="XUnmapWindow")]
5963 internal extern static int XUnmapWindow(IntPtr display, IntPtr window);
5964 [DllImport ("libX11", EntryPoint="XMapSubwindows")]
5965 internal extern static int XMapSubindows(IntPtr display, IntPtr window);
5966 [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
5967 internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
5968 [DllImport ("libX11", EntryPoint="XRootWindow")]
5969 internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
5970 [DllImport ("libX11", EntryPoint="XNextEvent")]
5971 internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
5972 [DllImport ("libX11")]
5973 internal extern static int XConnectionNumber (IntPtr diplay);
5974 [DllImport ("libX11")]
5975 internal extern static int XPending (IntPtr diplay);
5976 [DllImport ("libX11", EntryPoint="XSelectInput")]
5977 internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
5979 [DllImport ("libX11", EntryPoint="XDestroyWindow")]
5980 internal extern static int XDestroyWindow(IntPtr display, IntPtr window);
5982 [DllImport ("libX11", EntryPoint="XReparentWindow")]
5983 internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
5984 [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
5985 private extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
5987 internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height)
5989 int ret = XMoveResizeWindow (display, window, x, y, width, height);
5990 Keyboard.MoveCurrentCaretPos ();
5994 [DllImport ("libX11", EntryPoint="XResizeWindow")]
5995 internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
5997 [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
5998 internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
6000 [DllImport ("libX11", EntryPoint="XFlush")]
6001 internal extern static int XFlush(IntPtr display);
6003 [DllImport ("libX11", EntryPoint="XSetWMName")]
6004 internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
6006 [DllImport ("libX11", EntryPoint="XStoreName")]
6007 internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
6009 [DllImport ("libX11", EntryPoint="XFetchName")]
6010 internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
6012 [DllImport ("libX11", EntryPoint="XSendEvent")]
6013 internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
6015 [DllImport ("libX11", EntryPoint="XQueryTree")]
6016 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);
6018 [DllImport ("libX11", EntryPoint="XFree")]
6019 internal extern static int XFree(IntPtr data);
6021 [DllImport ("libX11", EntryPoint="XRaiseWindow")]
6022 internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
6024 [DllImport ("libX11", EntryPoint="XLowerWindow")]
6025 internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
6027 [DllImport ("libX11", EntryPoint="XConfigureWindow")]
6028 internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
6030 [DllImport ("libX11", EntryPoint="XInternAtom")]
6031 internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
6033 [DllImport ("libX11", EntryPoint="XInternAtoms")]
6034 internal extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
6036 [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
6037 internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
6039 [DllImport ("libX11", EntryPoint="XGrabPointer")]
6040 internal extern static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp);
6042 [DllImport ("libX11", EntryPoint="XUngrabPointer")]
6043 internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp);
6045 [DllImport ("libX11", EntryPoint="XQueryPointer")]
6046 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);
6048 [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
6049 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);
6051 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6052 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);
6054 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6055 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);
6057 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6058 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);
6060 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6061 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);
6063 [DllImport ("libX11", EntryPoint="XWarpPointer")]
6064 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);
6066 [DllImport ("libX11", EntryPoint="XClearWindow")]
6067 internal extern static int XClearWindow(IntPtr display, IntPtr window);
6069 [DllImport ("libX11", EntryPoint="XClearArea")]
6070 internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
6073 [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
6074 internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
6076 [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
6077 internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
6079 [DllImport ("libX11", EntryPoint="XDefaultVisual")]
6080 internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
6082 [DllImport ("libX11", EntryPoint="XDefaultDepth")]
6083 internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
6085 [DllImport ("libX11", EntryPoint="XDefaultScreen")]
6086 internal extern static int XDefaultScreen(IntPtr display);
6088 [DllImport ("libX11", EntryPoint="XDefaultColormap")]
6089 internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
6091 [DllImport ("libX11", EntryPoint="XLookupColor")]
6092 internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
6094 [DllImport ("libX11", EntryPoint="XAllocColor")]
6095 internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
6097 [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
6098 internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
6100 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6101 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
6103 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6104 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
6106 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6107 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
6109 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6110 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
6112 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6113 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
6115 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6116 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
6118 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6119 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
6121 [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
6122 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
6124 [DllImport ("libX11", EntryPoint="XDeleteProperty")]
6125 internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
6128 [DllImport ("libX11", EntryPoint="XCreateGC")]
6129 internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
6131 [DllImport ("libX11", EntryPoint="XFreeGC")]
6132 internal extern static int XFreeGC(IntPtr display, IntPtr gc);
6134 [DllImport ("libX11", EntryPoint="XSetFunction")]
6135 internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
6137 [DllImport ("libX11", EntryPoint="XSetLineAttributes")]
6138 internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
6140 [DllImport ("libX11", EntryPoint="XDrawLine")]
6141 internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
6143 [DllImport ("libX11", EntryPoint="XDrawRectangle")]
6144 internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
6146 [DllImport ("libX11", EntryPoint="XFillRectangle")]
6147 internal extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
6149 [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
6150 internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
6152 [DllImport ("libX11", EntryPoint="XCopyArea")]
6153 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);
6155 [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
6156 internal extern static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop);
6158 [DllImport ("libX11", EntryPoint="XSetInputFocus")]
6159 internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
6161 [DllImport ("libX11", EntryPoint="XIconifyWindow")]
6162 internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
6164 [DllImport ("libX11", EntryPoint="XDefineCursor")]
6165 internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
6167 [DllImport ("libX11", EntryPoint="XUndefineCursor")]
6168 internal extern static int XUndefineCursor(IntPtr display, IntPtr window);
6170 [DllImport ("libX11", EntryPoint="XFreeCursor")]
6171 internal extern static int XFreeCursor(IntPtr display, IntPtr cursor);
6173 [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
6174 internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
6176 [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
6177 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);
6179 [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
6180 internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
6182 [DllImport ("libX11", EntryPoint="XCreatePixmap")]
6183 internal extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
6185 [DllImport ("libX11", EntryPoint="XFreePixmap")]
6186 internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
6188 [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
6189 internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
6191 [DllImport ("libX11", EntryPoint="XQueryExtension")]
6192 internal extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
6194 [DllImport ("libX11", EntryPoint="XWhitePixel")]
6195 internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
6197 [DllImport ("libX11", EntryPoint="XBlackPixel")]
6198 internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
6200 [DllImport ("libX11", EntryPoint="XGrabServer")]
6201 internal extern static void XGrabServer(IntPtr display);
6203 [DllImport ("libX11", EntryPoint="XUngrabServer")]
6204 internal extern static void XUngrabServer(IntPtr display);
6206 [DllImport ("libX11", EntryPoint="XGetWMNormalHints")]
6207 internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
6209 [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
6210 internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
6212 [DllImport ("libX11", EntryPoint="XSetZoomHints")]
6213 internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
6215 [DllImport ("libX11", EntryPoint="XSetWMHints")]
6216 internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
6218 [DllImport ("libX11", EntryPoint="XGetIconSizes")]
6219 internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
6221 [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
6222 internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
6224 [DllImport ("libX11", EntryPoint="XGetErrorText")]
6225 internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
6227 [DllImport ("libX11", EntryPoint="XInitThreads")]
6228 internal extern static int XInitThreads();
6230 [DllImport ("libX11", EntryPoint="XConvertSelection")]
6231 internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
6233 [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
6234 internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
6236 [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
6237 internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
6239 [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
6240 internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
6242 [DllImport ("libX11", EntryPoint="XSetForeground")]
6243 internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
6245 [DllImport ("libX11", EntryPoint="XSetBackground")]
6246 internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
6248 [DllImport ("libX11", EntryPoint="XBell")]
6249 internal extern static int XBell(IntPtr display, int percent);
6251 [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")]
6252 internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
6254 [DllImport ("libX11", EntryPoint="XFilterEvent")]
6255 internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
6257 [DllImport ("libX11")]
6258 internal extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
6260 [DllImport ("libX11")]
6261 internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
6263 [DllImport ("libX11")]
6264 internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);