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);
3835 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
3836 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
3837 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
3838 XEvent motionEvent = new XEvent ();
3839 motionEvent.type = XEventName.MotionNotify;
3840 motionEvent.MotionEvent.display = DisplayHandle;
3841 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
3842 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
3843 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
3844 hwnd.Queue.EnqueueLocked (motionEvent);
3850 case XEventName.ButtonRelease: {
3851 switch(xevent.ButtonEvent.button) {
3854 msg.message = Msg.WM_LBUTTONUP;
3856 msg.message = Msg.WM_NCLBUTTONUP;
3857 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3858 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3860 MouseState &= ~MouseButtons.Left;
3861 msg.wParam = GetMousewParam (0);
3867 msg.message = Msg.WM_MBUTTONUP;
3869 msg.message = Msg.WM_NCMBUTTONUP;
3870 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3871 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3873 MouseState &= ~MouseButtons.Middle;
3874 msg.wParam = GetMousewParam (0);
3880 msg.message = Msg.WM_RBUTTONUP;
3882 msg.message = Msg.WM_NCRBUTTONUP;
3883 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3884 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3886 MouseState &= ~MouseButtons.Right;
3887 msg.wParam = GetMousewParam (0);
3892 goto ProcessNextMessage;
3896 goto ProcessNextMessage;
3900 if (!hwnd.Enabled) {
3903 msg.hwnd = hwnd.EnabledHwnd;
3904 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);
3905 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3908 if (Grab.Hwnd != IntPtr.Zero) {
3909 msg.hwnd = Grab.Hwnd;
3912 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3913 mouse_position.X = xevent.ButtonEvent.x;
3914 mouse_position.Y = xevent.ButtonEvent.y;
3916 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
3917 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
3918 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
3919 if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
3920 XEvent motionEvent = new XEvent ();
3921 motionEvent.type = XEventName.MotionNotify;
3922 motionEvent.MotionEvent.display = DisplayHandle;
3923 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
3924 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
3925 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
3926 hwnd.Queue.EnqueueLocked (motionEvent);
3931 case XEventName.MotionNotify: {
3933 #if DriverDebugExtra
3934 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);
3937 if (Grab.Hwnd != IntPtr.Zero) {
3938 msg.hwnd = Grab.Hwnd;
3941 NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
3945 if (xevent.MotionEvent.is_hint != 0)
3949 XQueryPointer (DisplayHandle, xevent.AnyEvent.window,
3950 out root, out child,
3951 out xevent.MotionEvent.x_root,
3952 out xevent.MotionEvent.y_root,
3953 out xevent.MotionEvent.x,
3954 out xevent.MotionEvent.y, out mask);
3957 msg.message = Msg.WM_MOUSEMOVE;
3958 msg.wParam = GetMousewParam(0);
3959 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
3961 if (!hwnd.Enabled) {
3964 msg.hwnd = hwnd.EnabledHwnd;
3965 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);
3966 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3969 mouse_position.X = xevent.MotionEvent.x;
3970 mouse_position.Y = xevent.MotionEvent.y;
3972 if ((HoverState.Timer.Enabled) &&
3973 (((mouse_position.X + HoverState.Size.Width) < HoverState.X) ||
3974 ((mouse_position.X - HoverState.Size.Width) > HoverState.X) ||
3975 ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) ||
3976 ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) {
3977 HoverState.Timer.Stop();
3978 HoverState.Timer.Start();
3979 HoverState.X = mouse_position.X;
3980 HoverState.Y = mouse_position.Y;
3990 #if DriverDebugExtra
3991 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);
3993 msg.message = Msg.WM_NCMOUSEMOVE;
3995 if (!hwnd.Enabled) {
3996 msg.hwnd = hwnd.EnabledHwnd;
3997 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);
3998 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
4001 ht = NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
4002 NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
4004 mouse_position.X = xevent.MotionEvent.x;
4005 mouse_position.Y = xevent.MotionEvent.y;
4011 case XEventName.EnterNotify: {
4012 if (!hwnd.Enabled) {
4013 goto ProcessNextMessage;
4015 if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || LastPointerWindow == xevent.CrossingEvent.window ||
4016 hwnd.client_window == IntPtr.Zero) {
4017 goto ProcessNextMessage;
4019 if (LastPointerWindow != IntPtr.Zero) {
4020 Point enter_loc = new Point (xevent.ButtonEvent.x, xevent.ButtonEvent.y);
4022 // We need this due to EnterNotify being fired on all the parent controls
4023 // of the Control being grabbed, and obviously in that scenario we are not
4024 // actuallty entering them
4025 Control ctrl = Control.FromHandle (hwnd.client_window);
4026 foreach (Control child_control in ctrl.Controls)
4027 if (child_control.Bounds.Contains (enter_loc))
4028 goto ProcessNextMessage;
4031 LastPointerWindow = xevent.AnyEvent.window;
4033 msg.message = Msg.WM_MOUSE_ENTER;
4034 HoverState.X = xevent.CrossingEvent.x;
4035 HoverState.Y = xevent.CrossingEvent.y;
4036 HoverState.Timer.Enabled = true;
4037 HoverState.Window = xevent.CrossingEvent.window;
4039 // Win32 sends a WM_MOUSEMOVE after mouse enter
4040 XEvent motionEvent = new XEvent ();
4041 motionEvent.type = XEventName.MotionNotify;
4042 motionEvent.MotionEvent.display = DisplayHandle;
4043 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
4044 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
4045 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
4046 hwnd.Queue.EnqueueLocked (motionEvent);
4050 case XEventName.LeaveNotify: {
4051 if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) {
4052 WindowUngrabbed (hwnd.Handle);
4053 goto ProcessNextMessage;
4055 if (!hwnd.Enabled) {
4056 goto ProcessNextMessage;
4058 if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
4059 goto ProcessNextMessage;
4062 // Reset the cursor explicitly on X11.
4063 // X11 remembers the last set cursor for the window and in cases where
4064 // the control won't get a WM_SETCURSOR X11 will restore the last
4065 // known cursor, which we don't want.
4067 SetCursor (hwnd.client_window, IntPtr.Zero);
4069 msg.message=Msg.WM_MOUSELEAVE;
4070 HoverState.Timer.Enabled = false;
4071 HoverState.Window = IntPtr.Zero;
4076 case XEventName.CreateNotify: {
4077 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
4078 msg.message = WM_CREATE;
4079 // Set up CreateStruct
4081 goto ProcessNextMessage;
4088 case XEventName.ReparentNotify: {
4089 if (hwnd.parent == null) { // Toplevel
4090 if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) {
4091 hwnd.Reparented = true;
4093 // The location given by the event is not reliable between different wm's,
4094 // so use an alternative way of getting it.
4095 Point location = GetTopLevelWindowLocation (hwnd);
4096 hwnd.X = location.X;
4097 hwnd.Y = location.Y;
4099 if (hwnd.opacity != 0xffffffff) {
4102 opacity = (IntPtr)(Int32)hwnd.opacity;
4103 XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
4105 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
4106 goto ProcessNextMessage;
4108 hwnd.Reparented = false;
4109 goto ProcessNextMessage;
4112 goto ProcessNextMessage;
4115 case XEventName.ConfigureNotify: {
4116 if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4117 #if DriverDebugExtra
4118 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);
4121 lock (hwnd.configure_lock) {
4122 Form form = Control.FromHandle (hwnd.client_window) as Form;
4123 if (form != null && !hwnd.resizing_or_moving) {
4124 if (hwnd.x != form.Bounds.X || hwnd.y != form.Bounds.Y) {
4125 SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_MOVE, IntPtr.Zero);
4126 hwnd.resizing_or_moving = true;
4127 } else if (hwnd.width != form.Bounds.Width || hwnd.height != form.Bounds.Height) {
4128 SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_SIZE, IntPtr.Zero);
4129 hwnd.resizing_or_moving = true;
4131 if (hwnd.resizing_or_moving)
4132 SendMessage (form.Handle, Msg.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
4135 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4136 hwnd.configure_pending = false;
4138 // We need to adjust our client window to track the resize of whole_window
4139 if (hwnd.whole_window != hwnd.client_window)
4140 PerformNCCalc(hwnd);
4143 goto ProcessNextMessage;
4146 case XEventName.FocusIn: {
4147 // We received focus. We use X11 focus only to know if the app window does or does not have focus
4148 // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
4149 // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
4150 // about it having focus again
4151 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4152 goto ProcessNextMessage;
4155 if (FocusWindow == IntPtr.Zero) {
4156 Control c = Control.FromHandle (hwnd.client_window);
4158 goto ProcessNextMessage;
4159 Form form = c.FindForm ();
4161 goto ProcessNextMessage;
4162 if (ActiveWindow != form.Handle) {
4163 ActiveWindow = form.Handle;
4164 SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
4166 goto ProcessNextMessage;
4168 SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
4169 Keyboard.FocusIn (FocusWindow);
4170 goto ProcessNextMessage;
4173 case XEventName.FocusOut: {
4174 // Se the comment for our FocusIn handler
4175 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4176 goto ProcessNextMessage;
4179 while (Keyboard.ResetKeyState(FocusWindow, ref msg)) {
4180 SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam);
4183 Keyboard.FocusOut(hwnd.client_window);
4184 SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
4185 goto ProcessNextMessage;
4188 case XEventName.MapNotify: {
4189 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4191 msg.message = Msg.WM_SHOWWINDOW;
4192 msg.wParam = (IntPtr) 1;
4193 // XXX we're missing the lParam..
4196 goto ProcessNextMessage;
4199 case XEventName.UnmapNotify: {
4200 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4201 hwnd.mapped = false;
4202 msg.message = Msg.WM_SHOWWINDOW;
4203 msg.wParam = (IntPtr) 0;
4204 // XXX we're missing the lParam..
4207 goto ProcessNextMessage;
4210 case XEventName.Expose: {
4213 hwnd.expose_pending = false;
4215 hwnd.nc_expose_pending = false;
4217 goto ProcessNextMessage;
4221 if (!hwnd.expose_pending) {
4222 goto ProcessNextMessage;
4225 if (!hwnd.nc_expose_pending) {
4226 goto ProcessNextMessage;
4229 switch (hwnd.border_style) {
4230 case FormBorderStyle.Fixed3D: {
4233 g = Graphics.FromHwnd(hwnd.whole_window);
4234 if (hwnd.border_static)
4235 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter);
4237 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken);
4242 case FormBorderStyle.FixedSingle: {
4245 g = Graphics.FromHwnd(hwnd.whole_window);
4246 ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
4251 #if DriverDebugExtra
4252 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);
4255 Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
4256 Region region = new Region (rect);
4257 IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
4258 msg.message = Msg.WM_NCPAINT;
4259 msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
4260 msg.refobject = region;
4263 #if DriverDebugExtra
4264 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);
4266 if (Caret.Visible == true) {
4267 Caret.Paused = true;
4271 if (Caret.Visible == true) {
4273 Caret.Paused = false;
4275 msg.message = Msg.WM_PAINT;
4279 case XEventName.DestroyNotify: {
4281 // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
4282 hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
4284 // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
4285 if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) {
4286 CleanupCachedWindows (hwnd);
4288 #if DriverDebugDestroy
4289 Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window));
4292 msg.hwnd = hwnd.client_window;
4293 msg.message=Msg.WM_DESTROY;
4296 goto ProcessNextMessage;
4302 case XEventName.ClientMessage: {
4303 if (Dnd.HandleClientMessage (ref xevent)) {
4304 goto ProcessNextMessage;
4307 if (xevent.ClientMessageEvent.message_type == AsyncAtom) {
4308 XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
4309 goto ProcessNextMessage;
4312 if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
4313 msg.message = Msg.WM_MOUSEHOVER;
4314 msg.wParam = GetMousewParam(0);
4315 msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
4319 if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
4320 msg.hwnd = xevent.ClientMessageEvent.ptr1;
4321 msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
4322 msg.wParam = xevent.ClientMessageEvent.ptr3;
4323 msg.lParam = xevent.ClientMessageEvent.ptr4;
4324 if (msg.message == (Msg)Msg.WM_QUIT)
4330 if (xevent.ClientMessageEvent.message_type == _XEMBED) {
4331 #if DriverDebugXEmbed
4332 Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
4335 if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
4336 XSizeHints hints = new XSizeHints();
4339 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
4341 hwnd.width = hints.max_width;
4342 hwnd.height = hints.max_height;
4343 hwnd.ClientRect = Rectangle.Empty;
4344 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4348 if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) {
4349 if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) {
4350 SendMessage (msg.hwnd, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_CLOSE, IntPtr.Zero);
4351 msg.message = Msg.WM_CLOSE;
4355 // We should not get this, but I'll leave the code in case we need it in the future
4356 if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) {
4357 goto ProcessNextMessage;
4360 goto ProcessNextMessage;
4364 goto ProcessNextMessage;
4371 private HitTest NCHitTest (Hwnd hwnd, int x, int y)
4373 // The hit test is sent in screen coordinates
4375 int screen_x, screen_y;
4376 XTranslateCoordinates (DisplayHandle, hwnd.WholeWindow, RootWindow, x, y, out screen_x, out screen_y, out dummy);
4377 return (HitTest) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero,
4378 (IntPtr) (screen_y << 16 | screen_x & 0xFFFF));
4381 internal override bool GetText(IntPtr handle, out string text) {
4388 IntPtr prop = IntPtr.Zero;
4390 XGetWindowProperty(DisplayHandle, handle,
4391 _NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
4392 UNICODETEXT, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
4394 if ((long)nitems > 0 && prop != IntPtr.Zero) {
4395 text = Marshal.PtrToStringUni (prop, (int)nitems);
4400 // fallback on the non-_NET property
4403 textptr = IntPtr.Zero;
4405 XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr);
4406 if (textptr != IntPtr.Zero) {
4407 text = Marshal.PtrToStringAnsi(textptr);
4418 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) {
4421 hwnd = Hwnd.ObjectFromHandle(handle);
4427 height = hwnd.height;
4429 PerformNCCalc(hwnd);
4431 client_width = hwnd.ClientRect.Width;
4432 client_height = hwnd.ClientRect.Height;
4437 // Should we throw an exception or fail silently?
4438 // throw new ArgumentException("Called with an invalid window handle", "handle");
4448 internal override FormWindowState GetWindowState(IntPtr handle) {
4451 hwnd = Hwnd.ObjectFromHandle(handle);
4453 if (hwnd.cached_window_state == (FormWindowState)(-1))
4454 hwnd.cached_window_state = UpdateWindowState (handle);
4456 return hwnd.cached_window_state;
4459 private FormWindowState UpdateWindowState (IntPtr handle) {
4464 IntPtr prop = IntPtr.Zero;
4468 XWindowAttributes attributes;
4471 hwnd = Hwnd.ObjectFromHandle(handle);
4475 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);
4476 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
4477 for (int i = 0; i < (long)nitems; i++) {
4478 atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
4479 if ((atom == _NET_WM_STATE_MAXIMIZED_HORZ) || (atom == _NET_WM_STATE_MAXIMIZED_VERT)) {
4481 } else if (atom == _NET_WM_STATE_HIDDEN) {
4489 return FormWindowState.Minimized;
4490 } else if (maximized == 2) {
4491 return FormWindowState.Maximized;
4494 attributes = new XWindowAttributes();
4495 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4496 if (attributes.map_state == MapState.IsUnmapped) {
4497 return (FormWindowState)(-1);
4501 return FormWindowState.Normal;
4504 internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) {
4506 GrabConfined = Grab.Confined;
4507 GrabArea = Grab.Area;
4510 internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) {
4512 IntPtr confine_to_window;
4514 confine_to_window = IntPtr.Zero;
4516 if (confine_to_handle != IntPtr.Zero) {
4517 XWindowAttributes attributes = new XWindowAttributes();
4519 hwnd = Hwnd.ObjectFromHandle(confine_to_handle);
4522 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4524 Grab.Area.X = attributes.x;
4525 Grab.Area.Y = attributes.y;
4526 Grab.Area.Width = attributes.width;
4527 Grab.Area.Height = attributes.height;
4528 Grab.Confined = true;
4529 confine_to_window = hwnd.client_window;
4534 hwnd = Hwnd.ObjectFromHandle(handle);
4537 XGrabPointer(DisplayHandle, hwnd.client_window, false,
4538 EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
4539 EventMask.ButtonReleaseMask | EventMask.PointerMotionMask |
4540 EventMask.PointerMotionHintMask | EventMask.LeaveWindowMask,
4541 GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
4545 internal override void UngrabWindow(IntPtr hwnd) {
4547 XUngrabPointer(DisplayHandle, IntPtr.Zero);
4548 XFlush(DisplayHandle);
4550 WindowUngrabbed (hwnd);
4553 private void WindowUngrabbed (IntPtr hwnd) {
4554 bool was_grabbed = Grab.Hwnd != IntPtr.Zero;
4556 Grab.Hwnd = IntPtr.Zero;
4557 Grab.Confined = false;
4560 // lparam should be the handle to the window gaining the mouse capture,
4561 // but X doesn't seem to give us that information.
4562 // Also only generate WM_CAPTURECHANGED if the window actually was grabbed.
4563 // X will send a NotifyUngrab, but since it comes late sometimes we're
4564 // calling WindowUngrabbed directly from UngrabWindow in order to send
4565 // this WM right away.
4566 SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero);
4570 internal override void HandleException(Exception e) {
4571 StackTrace st = new StackTrace(e, true);
4572 Console.WriteLine("Exception '{0}'", e.Message+st.ToString());
4573 Console.WriteLine("{0}{1}", e.Message, st.ToString());
4576 internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
4579 hwnd = Hwnd.ObjectFromHandle(handle);
4582 AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height);
4584 AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height);
4588 internal override void InvalidateNC (IntPtr handle) {
4591 hwnd = Hwnd.ObjectFromHandle(handle);
4593 AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
4596 internal override bool IsEnabled(IntPtr handle) {
4597 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4598 return (hwnd != null && hwnd.Enabled);
4601 internal override bool IsVisible(IntPtr handle) {
4602 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4603 return (hwnd != null && hwnd.visible);
4606 internal override void KillTimer(Timer timer) {
4607 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
4609 if (queue == null) {
4610 // This isn't really an error, MS doesn't start the timer if
4611 // it has no assosciated queue. In this case, remove the timer
4612 // from the list of unattached timers (if it was enabled).
4613 lock (unattached_timer_list) {
4614 if (unattached_timer_list.Contains (timer))
4615 unattached_timer_list.Remove (timer);
4619 queue.timer_list.Remove (timer);
4622 internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) {
4628 hwnd = Hwnd.ObjectFromHandle(handle);
4631 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
4638 internal override void OverrideCursor(IntPtr cursor)
4640 if (Grab.Hwnd != IntPtr.Zero) {
4641 XChangeActivePointerGrab (DisplayHandle,
4642 EventMask.ButtonMotionMask |
4643 EventMask.PointerMotionMask |
4644 EventMask.PointerMotionHintMask |
4645 EventMask.ButtonPressMask |
4646 EventMask.ButtonReleaseMask,
4647 cursor, IntPtr.Zero);
4651 OverrideCursorHandle = cursor;
4654 internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) {
4655 PaintEventArgs paint_event;
4660 // handle (and paint_hwnd) refers to the window that is should be painted.
4661 // msg.HWnd (and hwnd) refers to the window that got the paint message.
4664 hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
4665 if (msg.HWnd == handle) {
4668 paint_hwnd = Hwnd.ObjectFromHandle (handle);
4671 if (Caret.Visible == true) {
4672 Caret.Paused = true;
4679 dc = Graphics.FromHwnd (paint_hwnd.client_window);
4681 Region clip_region = new Region ();
4682 clip_region.MakeEmpty();
4684 foreach (Rectangle r in hwnd.ClipRectangles) {
4685 clip_region.Union (r);
4688 if (hwnd.UserClip != null) {
4689 clip_region.Intersect(hwnd.UserClip);
4692 dc.Clip = clip_region;
4693 paint_event = new PaintEventArgs(dc, hwnd.Invalid);
4694 hwnd.expose_pending = false;
4696 hwnd.ClearInvalidArea();
4698 hwnd.drawing_stack.Push (paint_event);
4699 hwnd.drawing_stack.Push (dc);
4703 dc = Graphics.FromHwnd (paint_hwnd.whole_window);
4705 if (!hwnd.nc_invalid.IsEmpty) {
4706 dc.SetClip (hwnd.nc_invalid);
4707 paint_event = new PaintEventArgs(dc, hwnd.nc_invalid);
4709 paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height));
4711 hwnd.nc_expose_pending = false;
4713 hwnd.ClearNcInvalidArea ();
4715 hwnd.drawing_stack.Push (paint_event);
4716 hwnd.drawing_stack.Push (dc);
4722 internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) {
4725 hwnd = Hwnd.ObjectFromHandle (msg.HWnd);
4727 Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
4731 PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop();
4732 pe.SetGraphics (null);
4735 if (Caret.Visible == true) {
4737 Caret.Paused = false;
4741 [MonoTODO("Implement filtering and PM_NOREMOVE")]
4742 internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
4743 XEventQueue queue = (XEventQueue) queue_id;
4746 if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
4747 throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
4751 if (queue.Count > 0) {
4754 // Only call UpdateMessageQueue if real events are pending
4755 // otherwise we go to sleep on the socket
4756 if (XPending(DisplayHandle) != 0) {
4757 UpdateMessageQueue((XEventQueue)queue_id);
4759 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
4764 CheckTimers(queue.timer_list, DateTime.UtcNow);
4769 return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
4772 internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) {
4773 XEvent xevent = new XEvent ();
4774 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
4776 xevent.type = XEventName.ClientMessage;
4777 xevent.ClientMessageEvent.display = DisplayHandle;
4780 xevent.ClientMessageEvent.window = hwnd.whole_window;
4782 xevent.ClientMessageEvent.window = IntPtr.Zero;
4785 xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
4786 xevent.ClientMessageEvent.format = 32;
4787 xevent.ClientMessageEvent.ptr1 = handle;
4788 xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
4789 xevent.ClientMessageEvent.ptr3 = wparam;
4790 xevent.ClientMessageEvent.ptr4 = lparam;
4793 hwnd.Queue.EnqueueLocked (xevent);
4795 ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent);
4800 internal override void PostQuitMessage(int exitCode) {
4801 ApplicationContext ctx = Application.MWFThread.Current.Context;
4802 Form f = ctx != null ? ctx.MainForm : null;
4804 PostMessage (Application.MWFThread.Current.Context.MainForm.window.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4806 PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4807 XFlush(DisplayHandle);
4810 internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave)
4815 internal override void RequestNCRecalc(IntPtr handle) {
4818 hwnd = Hwnd.ObjectFromHandle(handle);
4824 PerformNCCalc(hwnd);
4825 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4826 InvalidateNC(handle);
4829 internal override void ResetMouseHover(IntPtr handle) {
4832 hwnd = Hwnd.ObjectFromHandle(handle);
4837 HoverState.Timer.Enabled = true;
4838 HoverState.X = mouse_position.X;
4839 HoverState.Y = mouse_position.Y;
4840 HoverState.Window = handle;
4844 internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) {
4850 hwnd = Hwnd.ObjectFromHandle(handle);
4853 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
4860 internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) {
4866 hwnd = Hwnd.ObjectFromHandle(handle);
4869 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
4872 Form form = Control.FromHandle (handle) as Form;
4873 if (form != null && form.window_manager != null) {
4874 dest_y_return -= form.window_manager.TitleBarHeight;
4881 bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg)
4883 return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) &&
4884 arg == xevent.GraphicsExposeEvent.drawable;
4887 delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg);
4889 void ProcessGraphicsExpose (Hwnd hwnd)
4891 XEvent xevent = new XEvent ();
4892 IntPtr handle = Hwnd.HandleFromObject (hwnd);
4893 EventPredicate predicate = GraphicsExposePredicate;
4896 XIfEvent (Display, ref xevent, predicate, handle);
4897 if (xevent.type != XEventName.GraphicsExpose)
4900 AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y,
4901 xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height);
4903 if (xevent.GraphicsExposeEvent.count == 0)
4908 internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
4911 XGCValues gc_values;
4913 hwnd = Hwnd.ObjectFromHandle(handle);
4915 Rectangle r = Rectangle.Intersect (hwnd.Invalid, area);
4917 /* We have an invalid area in the window we're scrolling.
4918 Adjust our stored invalid rectangle to to match the scrolled amount */
4933 if (area.Contains (hwnd.Invalid))
4934 hwnd.ClearInvalidArea ();
4935 hwnd.AddInvalidArea(r);
4938 gc_values = new XGCValues();
4940 if (with_children) {
4941 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
4944 gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
4946 Rectangle visible_rect = GetTotalVisibleArea (hwnd.client_window);
4947 visible_rect.Intersect (area);
4949 Rectangle dest_rect = visible_rect;
4950 dest_rect.Y += YAmount;
4951 dest_rect.X += XAmount;
4952 dest_rect.Intersect (area);
4954 Point src = new Point (dest_rect.X - XAmount, dest_rect.Y - YAmount);
4955 XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src.X, src.Y,
4956 dest_rect.Width, dest_rect.Height, dest_rect.X, dest_rect.Y);
4958 Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount);
4959 AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height);
4961 ProcessGraphicsExpose (hwnd);
4963 XFreeGC(DisplayHandle, gc);
4966 internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) {
4970 hwnd = Hwnd.GetObjectFromWindow(handle);
4972 rect = hwnd.ClientRect;
4975 ScrollWindow(handle, rect, XAmount, YAmount, with_children);
4978 Rectangle GetDirtyArea (Rectangle total_area, Rectangle valid_area, int XAmount, int YAmount)
4980 Rectangle dirty_area = total_area;
4983 dirty_area.Height -= valid_area.Height;
4984 else if (YAmount < 0) {
4985 dirty_area.Height -= valid_area.Height;
4986 dirty_area.Y += valid_area.Height;
4990 dirty_area.Width -= valid_area.Width;
4991 else if (XAmount < 0) {
4992 dirty_area.Width -= valid_area.Width;
4993 dirty_area.X += valid_area.Width;
4999 Rectangle GetTotalVisibleArea (IntPtr handle)
5001 Control c = Control.FromHandle (handle);
5003 Rectangle visible_area = c.ClientRectangle;
5004 visible_area.Location = c.PointToScreen (Point.Empty);
5006 for (Control parent = c.Parent; parent != null; parent = parent.Parent) {
5007 if (!parent.IsHandleCreated || !parent.Visible)
5008 return visible_area; // Non visible, not need to finish computations
5010 Rectangle r = parent.ClientRectangle;
5011 r.Location = parent.PointToScreen (Point.Empty);
5013 visible_area.Intersect (r);
5016 visible_area.Location = c.PointToClient (visible_area.Location);
5017 return visible_area;
5020 internal override void SendAsyncMethod (AsyncMethodData method) {
5022 XEvent xevent = new XEvent ();
5024 hwnd = Hwnd.ObjectFromHandle(method.Handle);
5026 xevent.type = XEventName.ClientMessage;
5027 xevent.ClientMessageEvent.display = DisplayHandle;
5028 xevent.ClientMessageEvent.window = method.Handle;
5029 xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
5030 xevent.ClientMessageEvent.format = 32;
5031 xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
5033 hwnd.Queue.EnqueueLocked (xevent);
5038 delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
5040 internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
5043 h = Hwnd.ObjectFromHandle(hwnd);
5045 if (h != null && h.queue != ThreadQueue (Thread.CurrentThread)) {
5046 AsyncMethodResult result;
5047 AsyncMethodData data;
5049 result = new AsyncMethodResult ();
5050 data = new AsyncMethodData ();
5053 data.Method = new WndProcDelegate (NativeWindow.WndProc);
5054 data.Args = new object[] { hwnd, message, wParam, lParam };
5055 data.Result = result;
5057 SendAsyncMethod (data);
5058 #if DriverDebug || DriverDebugThreads
5059 Console.WriteLine ("Sending {0} message across.", message);
5064 return NativeWindow.WndProc(hwnd, message, wParam, lParam);
5067 internal override int SendInput(IntPtr handle, Queue keys) {
5068 if (handle == IntPtr.Zero)
5071 int count = keys.Count;
5072 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5074 while (keys.Count > 0) {
5076 MSG msg = (MSG)keys.Dequeue();
5078 XEvent xevent = new XEvent ();
5080 xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
5081 xevent.KeyEvent.display = DisplayHandle;
5084 xevent.KeyEvent.window = hwnd.whole_window;
5086 xevent.KeyEvent.window = IntPtr.Zero;
5089 xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
5091 hwnd.Queue.EnqueueLocked (xevent);
5096 internal override void SetAllowDrop (IntPtr handle, bool value)
5098 // We allow drop on all windows
5101 internal override DragDropEffects StartDrag (IntPtr handle, object data,
5102 DragDropEffects allowed_effects)
5104 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
5107 throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
5109 return Dnd.StartDrag (hwnd.client_window, data, allowed_effects);
5112 internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
5113 Form form = Control.FromHandle (handle) as Form;
5114 if (form != null && form.window_manager == null) {
5115 CreateParams cp = form.GetCreateParams ();
5116 if (border_style == FormBorderStyle.FixedToolWindow ||
5117 border_style == FormBorderStyle.SizableToolWindow ||
5118 cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
5119 form.window_manager = new ToolWindowManager (form);
5123 RequestNCRecalc(handle);
5126 internal override void SetCaretPos(IntPtr handle, int x, int y) {
5127 if (Caret.Hwnd == handle) {
5134 Keyboard.SetCaretPos (Caret, handle, x, y);
5136 if (Caret.Visible == true) {
5138 Caret.Timer.Start();
5143 internal override void SetClipRegion(IntPtr handle, Region region) {
5146 hwnd = Hwnd.ObjectFromHandle(handle);
5151 hwnd.UserClip = region;
5154 internal override void SetCursor(IntPtr handle, IntPtr cursor) {
5157 if (OverrideCursorHandle == IntPtr.Zero) {
5158 if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
5162 LastCursorHandle = cursor;
5163 LastCursorWindow = handle;
5165 hwnd = Hwnd.ObjectFromHandle(handle);
5167 if (cursor != IntPtr.Zero) {
5168 XDefineCursor(DisplayHandle, hwnd.whole_window, cursor);
5170 XUndefineCursor(DisplayHandle, hwnd.whole_window);
5172 XFlush(DisplayHandle);
5177 hwnd = Hwnd.ObjectFromHandle(handle);
5179 XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
5183 private void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child,
5184 out int root_x, out int root_y, out int child_x, out int child_y,
5187 /* this code was written with the help of
5188 glance at gdk. I never would have realized we
5189 needed a loop in order to traverse down in the
5190 hierarchy. I would have assumed you'd get the
5191 most deeply nested child and have to do
5192 XQueryTree to move back up the hierarchy..
5193 stupid me, of course. */
5196 XGrabServer (display);
5198 XQueryPointer(display, w, out root, out c,
5199 out root_x, out root_y, out child_x, out child_y,
5205 IntPtr child_last = IntPtr.Zero;
5206 while (c != IntPtr.Zero) {
5208 XQueryPointer(display, c, out root, out c,
5209 out root_x, out root_y, out child_x, out child_y,
5212 XUngrabServer (display);
5218 internal override void SetCursorPos(IntPtr handle, int x, int y) {
5219 if (handle == IntPtr.Zero) {
5222 int root_x, root_y, child_x, child_y, mask;
5225 * QueryPointer before warping
5226 * because if the warp is on
5227 * the RootWindow, the x/y are
5228 * relative to the current
5231 QueryPointer (DisplayHandle, RootWindow,
5234 out root_x, out root_y,
5235 out child_x, out child_y,
5238 XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
5240 XFlush (DisplayHandle);
5242 /* then we need to a
5243 * QueryPointer after warping
5244 * to manually generate a
5245 * motion event for the window
5248 QueryPointer (DisplayHandle, RootWindow,
5251 out root_x, out root_y,
5252 out child_x, out child_y,
5255 Hwnd child_hwnd = Hwnd.ObjectFromHandle(child);
5256 if (child_hwnd == null) {
5260 XEvent xevent = new XEvent ();
5262 xevent.type = XEventName.MotionNotify;
5263 xevent.MotionEvent.display = DisplayHandle;
5264 xevent.MotionEvent.window = child_hwnd.client_window;
5265 xevent.MotionEvent.root = RootWindow;
5266 xevent.MotionEvent.x = child_x;
5267 xevent.MotionEvent.y = child_y;
5268 xevent.MotionEvent.x_root = root_x;
5269 xevent.MotionEvent.y_root = root_y;
5270 xevent.MotionEvent.state = mask;
5272 child_hwnd.Queue.EnqueueLocked (xevent);
5277 hwnd = Hwnd.ObjectFromHandle(handle);
5279 XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
5284 internal override void SetFocus(IntPtr handle) {
5286 IntPtr prev_focus_window;
5288 hwnd = Hwnd.ObjectFromHandle(handle);
5290 if (hwnd.client_window == FocusWindow) {
5294 // Win32 doesn't do anything if disabled
5298 prev_focus_window = FocusWindow;
5299 FocusWindow = hwnd.client_window;
5301 if (prev_focus_window != IntPtr.Zero) {
5302 SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
5304 SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
5305 Keyboard.FocusIn (FocusWindow);
5307 //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
5310 internal override void SetIcon(IntPtr handle, Icon icon) {
5313 hwnd = Hwnd.ObjectFromHandle(handle);
5315 SetIcon(hwnd, icon);
5319 internal override void SetMenu(IntPtr handle, Menu menu) {
5322 hwnd = Hwnd.ObjectFromHandle(handle);
5325 RequestNCRecalc(handle);
5328 internal override void SetModal(IntPtr handle, bool Modal) {
5330 ModalWindows.Push(handle);
5332 if (ModalWindows.Contains(handle)) {
5335 if (ModalWindows.Count > 0) {
5336 Activate((IntPtr)ModalWindows.Peek());
5340 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
5341 Control ctrl = Control.FromHandle (handle);
5342 SetWMStyles (hwnd, ctrl.GetCreateParams ());
5345 internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
5348 hwnd = Hwnd.ObjectFromHandle(handle);
5349 hwnd.parent = Hwnd.ObjectFromHandle(parent);
5352 #if DriverDebug || DriverDebugParent
5353 Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(hwnd.Handle), XplatUI.Window(hwnd.parent != null ? hwnd.parent.Handle : IntPtr.Zero));
5355 XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent == null ? FosterParent : hwnd.parent.client_window, hwnd.x, hwnd.y);
5361 internal override void SetTimer (Timer timer) {
5362 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
5364 if (queue == null) {
5365 // This isn't really an error, MS doesn't start the timer if
5366 // it has no assosciated queue at this stage (it will be
5367 // enabled when a window is activated).
5368 unattached_timer_list.Add (timer);
5371 queue.timer_list.Add (timer);
5375 internal override bool SetTopmost(IntPtr handle, bool enabled) {
5377 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5381 int[] atoms = new int[8];
5382 atoms[0] = _NET_WM_STATE_ABOVE.ToInt32();
5383 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5387 XDeleteProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE);
5393 internal override bool SetOwner(IntPtr handle, IntPtr handle_owner) {
5397 hwnd = Hwnd.ObjectFromHandle(handle);
5399 if (handle_owner != IntPtr.Zero) {
5400 hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
5406 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
5407 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5409 if (hwnd_owner != null) {
5410 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
5412 XSetTransientForHint(DisplayHandle, hwnd.whole_window, RootWindow);
5417 XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR);
5423 internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
5427 hwnd = Hwnd.ObjectFromHandle(handle);
5428 hwnd.visible = visible;
5432 MapWindow(hwnd, WindowType.Both);
5434 if (Control.FromHandle(handle) is Form) {
5437 s = ((Form)Control.FromHandle(handle)).WindowState;
5440 case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break;
5441 case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break;
5445 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5448 UnmapWindow(hwnd, WindowType.Both);
5454 internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
5455 Control ctrl = Control.FromHandle (handle);
5456 SetWindowMinMax (handle, maximized, min, max, ctrl != null ? ctrl.GetCreateParams () : null);
5459 internal void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp)
5465 hwnd = Hwnd.ObjectFromHandle(handle);
5470 min.Width = Math.Max (min.Width, SystemInformation.MinimumWindowSize.Width);
5471 min.Height = Math.Max (min.Height, SystemInformation.MinimumWindowSize.Height);
5473 hints = new XSizeHints();
5475 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
5476 if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
5478 min = TranslateWindowSizeToXWindowSize (cp, min);
5479 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
5480 hints.min_width = min.Width;
5481 hints.min_height = min.Height;
5484 if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
5486 max = TranslateWindowSizeToXWindowSize (cp, max);
5487 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
5488 hints.max_width = max.Width;
5489 hints.max_height = max.Height;
5492 if (hints.flags != IntPtr.Zero) {
5493 // The Metacity team has decided that they won't care about this when clicking the maximize icon,
5494 // they will maximize the window to fill the screen/parent no matter what.
5495 // http://bugzilla.ximian.com/show_bug.cgi?id=80021
5496 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints);
5499 if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
5501 maximized.Size = TranslateWindowSizeToXWindowSize (cp);
5502 hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
5503 hints.x = maximized.X;
5504 hints.y = maximized.Y;
5505 hints.width = maximized.Width;
5506 hints.height = maximized.Height;
5508 // Metacity does not seem to follow this constraint for maximized (zoomed) windows
5509 XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints);
5514 internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
5517 hwnd = Hwnd.ObjectFromHandle(handle);
5523 // Win32 automatically changes negative width/height to 0.
5529 // X requires a sanity check for width & height; otherwise it dies
5530 if (hwnd.zero_sized && width > 0 && height > 0) {
5532 MapWindow(hwnd, WindowType.Whole);
5534 hwnd.zero_sized = false;
5537 if ((width < 1) || (height < 1)) {
5538 hwnd.zero_sized = true;
5539 UnmapWindow(hwnd, WindowType.Whole);
5542 // Save a server roundtrip (and prevent a feedback loop)
5543 if ((hwnd.x == x) && (hwnd.y == y) &&
5544 (hwnd.width == width) && (hwnd.height == height)) {
5548 if (!hwnd.zero_sized) {
5553 hwnd.height = height;
5554 SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5556 if (hwnd.fixed_size) {
5557 SetWindowMinMax(handle, Rectangle.Empty, new Size(width, height), new Size(width, height));
5561 Control ctrl = Control.FromHandle (handle);
5562 Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams (), new Size (width, height));
5563 MoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
5564 PerformNCCalc(hwnd);
5568 // Update our position/size immediately, so
5569 // that future calls to SetWindowPos aren't
5570 // kept from calling XMoveResizeWindow (by the
5571 // "Save a server roundtrip" block above).
5575 hwnd.height = height;
5576 hwnd.ClientRect = Rectangle.Empty;
5579 internal override void SetWindowState(IntPtr handle, FormWindowState state) {
5580 FormWindowState current_state;
5583 hwnd = Hwnd.ObjectFromHandle(handle);
5585 current_state = GetWindowState(handle);
5587 if (current_state == state) {
5592 case FormWindowState.Normal: {
5594 if (current_state == FormWindowState.Minimized) {
5595 MapWindow(hwnd, WindowType.Both);
5596 } else if (current_state == FormWindowState.Maximized) {
5597 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5604 case FormWindowState.Minimized: {
5606 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);
5609 XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo);
5614 case FormWindowState.Maximized: {
5616 if (current_state == FormWindowState.Minimized) {
5617 MapWindow(hwnd, WindowType.Both);
5620 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)1 /* Add */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5628 internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
5631 hwnd = Hwnd.ObjectFromHandle(handle);
5632 SetHwndStyles(hwnd, cp);
5633 SetWMStyles(hwnd, cp);
5636 internal override double GetWindowTransparency(IntPtr handle)
5641 internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) {
5645 hwnd = Hwnd.ObjectFromHandle(handle);
5651 hwnd.opacity = (uint)(0xffffffff * transparency);
5652 opacity = (IntPtr)((int)hwnd.opacity);
5654 IntPtr w = hwnd.whole_window;
5655 if (hwnd.reparented)
5656 w = XGetParent (hwnd.whole_window);
5657 XChangeProperty(DisplayHandle, w, _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
5660 internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) {
5661 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5669 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5672 } else if (!bottom) {
5673 Hwnd after_hwnd = null;
5675 if (after_handle != IntPtr.Zero) {
5676 after_hwnd = Hwnd.ObjectFromHandle(after_handle);
5679 XWindowChanges values = new XWindowChanges();
5681 if (after_hwnd == null) {
5682 // Work around metacity 'issues'
5686 atoms[0] = unixtime();
5687 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_USER_TIME, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, atoms, 1);
5689 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5690 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
5692 //throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order");
5695 values.sibling = after_hwnd.whole_window;
5696 values.stack_mode = StackMode.Below;
5699 XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
5704 XLowerWindow(DisplayHandle, hwnd.whole_window);
5711 internal override void ShowCursor(bool show) {
5712 ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
5715 internal override object StartLoop(Thread thread) {
5716 XEventQueue q = ThreadQueue(thread);
5720 internal override TransparencySupport SupportsTransparency() {
5721 // We need to check if the x compositing manager is running
5722 return TransparencySupport.Set;
5725 internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) {
5726 GetSystrayManagerWindow();
5728 if (SystrayMgrWindow != IntPtr.Zero) {
5729 XSizeHints size_hints;
5732 hwnd = Hwnd.ObjectFromHandle(handle);
5734 Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
5738 if (hwnd.client_window != hwnd.whole_window) {
5739 Keyboard.DestroyICForWindow (hwnd.client_window);
5740 XDestroyWindow(DisplayHandle, hwnd.client_window);
5741 hwnd.client_window = hwnd.whole_window;
5744 /* by virtue of the way the tests are ordered when determining if it's PAINT
5745 or NCPAINT, client_window == whole_window will always be PAINT. So, if we're
5746 waiting on an nc_expose, drop it and remove the hwnd from the list (unless
5747 there's a pending expose). */
5748 if (hwnd.nc_expose_pending) {
5749 hwnd.nc_expose_pending = false;
5750 if (!hwnd.expose_pending)
5751 hwnd.Queue.Paint.Remove (hwnd);
5754 size_hints = new XSizeHints();
5756 size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
5758 size_hints.min_width = 24;
5759 size_hints.min_height = 24;
5760 size_hints.max_width = 24;
5761 size_hints.max_height = 24;
5762 size_hints.base_width = 24;
5763 size_hints.base_height = 24;
5765 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints);
5767 int[] atoms = new int[2];
5768 atoms [0] = 1; // Version 1
5769 atoms [1] = 1; // we want to be mapped
5771 // This line cost me 3 days...
5772 XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2);
5774 // Need to pick some reasonable defaults
5776 tt.AutomaticDelay = 350;
5777 tt.InitialDelay = 250;
5778 tt.ReshowDelay = 250;
5779 tt.ShowAlways = true;
5781 if ((tip != null) && (tip != string.Empty)) {
5782 tt.SetToolTip(Control.FromHandle(handle), tip);
5788 SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
5796 internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) {
5799 control = Control.FromHandle(handle);
5800 if (control != null && tt != null) {
5801 tt.SetToolTip(control, tip);
5803 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5810 internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
5812 SetVisible (handle, false, false);
5814 // The caller can now re-dock it later...
5822 internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
5824 ThemeEngine.Current.ShowBalloonWindow (handle, timeout, title, text, icon);
5825 SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW);
5829 internal override bool Text(IntPtr handle, string text) {
5832 hwnd = Hwnd.ObjectFromHandle(handle);
5835 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_NAME, UNICODETEXT, 8,
5836 PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
5838 // XXX this has problems with UTF8.
5839 // we need to either use the actual
5840 // text if it's latin-1, or convert it
5841 // to compound text if it's in a
5842 // different charset.
5843 XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text);
5848 internal override bool TranslateMessage(ref MSG msg) {
5849 return Keyboard.TranslateMessage (ref msg);
5852 internal override void UpdateWindow(IntPtr handle) {
5855 hwnd = Hwnd.ObjectFromHandle(handle);
5857 if (!hwnd.visible || !hwnd.expose_pending || !hwnd.Mapped) {
5861 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5862 hwnd.Queue.Paint.Remove(hwnd);
5865 internal override void CreateOffscreenDrawable (IntPtr handle,
5866 int width, int height,
5867 out object offscreen_drawable)
5870 int x_out, y_out, width_out, height_out, border_width_out, depth_out;
5872 XGetGeometry (DisplayHandle, handle,
5874 out x_out, out y_out,
5875 out width_out, out height_out,
5876 out border_width_out, out depth_out);
5878 IntPtr pixmap = XCreatePixmap (DisplayHandle, handle, width, height, depth_out);
5880 offscreen_drawable = pixmap;
5884 internal override void DestroyOffscreenDrawable (object offscreen_drawable)
5886 XFreePixmap (DisplayHandle, (IntPtr)offscreen_drawable);
5889 internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
5891 return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
5894 internal override void BlitFromOffscreen (IntPtr dest_handle,
5896 object offscreen_drawable,
5897 Graphics offscreen_dc,
5900 XGCValues gc_values;
5903 gc_values = new XGCValues();
5905 gc = XCreateGC (DisplayHandle, dest_handle, IntPtr.Zero, ref gc_values);
5907 XCopyArea (DisplayHandle, (IntPtr)offscreen_drawable, dest_handle,
5908 gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
5910 XFreeGC (DisplayHandle, gc);
5913 #endregion // Public Static Methods
5916 internal override event EventHandler Idle;
5917 #endregion // Events
5919 #region Xcursor imports
5920 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")]
5921 internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name);
5923 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")]
5924 internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size);
5926 [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")]
5927 internal extern static void XcursorImagesDestroy (IntPtr images);
5929 [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")]
5930 internal extern static int XcursorGetDefaultSize (IntPtr display);
5932 [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")]
5933 internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image);
5935 [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")]
5936 internal extern static IntPtr XcursorGetTheme (IntPtr display);
5939 [DllImport ("libX11", EntryPoint="XOpenDisplay")]
5940 internal extern static IntPtr XOpenDisplay(IntPtr display);
5941 [DllImport ("libX11", EntryPoint="XCloseDisplay")]
5942 internal extern static int XCloseDisplay(IntPtr display);
5943 [DllImport ("libX11", EntryPoint="XSynchronize")]
5944 internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
5946 [DllImport ("libX11", EntryPoint="XCreateWindow")]
5947 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);
5948 [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
5949 internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
5950 [DllImport ("libX11", EntryPoint="XMapWindow")]
5951 internal extern static int XMapWindow(IntPtr display, IntPtr window);
5952 [DllImport ("libX11", EntryPoint="XUnmapWindow")]
5953 internal extern static int XUnmapWindow(IntPtr display, IntPtr window);
5954 [DllImport ("libX11", EntryPoint="XMapSubwindows")]
5955 internal extern static int XMapSubindows(IntPtr display, IntPtr window);
5956 [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
5957 internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
5958 [DllImport ("libX11", EntryPoint="XRootWindow")]
5959 internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
5960 [DllImport ("libX11", EntryPoint="XNextEvent")]
5961 internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
5962 [DllImport ("libX11")]
5963 internal extern static int XConnectionNumber (IntPtr diplay);
5964 [DllImport ("libX11")]
5965 internal extern static int XPending (IntPtr diplay);
5966 [DllImport ("libX11", EntryPoint="XSelectInput")]
5967 internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
5969 [DllImport ("libX11", EntryPoint="XDestroyWindow")]
5970 internal extern static int XDestroyWindow(IntPtr display, IntPtr window);
5972 [DllImport ("libX11", EntryPoint="XReparentWindow")]
5973 internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
5974 [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
5975 private extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
5977 internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height)
5979 int ret = XMoveResizeWindow (display, window, x, y, width, height);
5980 Keyboard.MoveCurrentCaretPos ();
5984 [DllImport ("libX11", EntryPoint="XResizeWindow")]
5985 internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
5987 [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
5988 internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
5990 [DllImport ("libX11", EntryPoint="XFlush")]
5991 internal extern static int XFlush(IntPtr display);
5993 [DllImport ("libX11", EntryPoint="XSetWMName")]
5994 internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
5996 [DllImport ("libX11", EntryPoint="XStoreName")]
5997 internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
5999 [DllImport ("libX11", EntryPoint="XFetchName")]
6000 internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
6002 [DllImport ("libX11", EntryPoint="XSendEvent")]
6003 internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
6005 [DllImport ("libX11", EntryPoint="XQueryTree")]
6006 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);
6008 [DllImport ("libX11", EntryPoint="XFree")]
6009 internal extern static int XFree(IntPtr data);
6011 [DllImport ("libX11", EntryPoint="XRaiseWindow")]
6012 internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
6014 [DllImport ("libX11", EntryPoint="XLowerWindow")]
6015 internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
6017 [DllImport ("libX11", EntryPoint="XConfigureWindow")]
6018 internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
6020 [DllImport ("libX11", EntryPoint="XInternAtom")]
6021 internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
6023 [DllImport ("libX11", EntryPoint="XInternAtoms")]
6024 internal extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
6026 [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
6027 internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
6029 [DllImport ("libX11", EntryPoint="XGrabPointer")]
6030 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);
6032 [DllImport ("libX11", EntryPoint="XUngrabPointer")]
6033 internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp);
6035 [DllImport ("libX11", EntryPoint="XQueryPointer")]
6036 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);
6038 [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
6039 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);
6041 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6042 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);
6044 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6045 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);
6047 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6048 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);
6050 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6051 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);
6053 [DllImport ("libX11", EntryPoint="XWarpPointer")]
6054 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);
6056 [DllImport ("libX11", EntryPoint="XClearWindow")]
6057 internal extern static int XClearWindow(IntPtr display, IntPtr window);
6059 [DllImport ("libX11", EntryPoint="XClearArea")]
6060 internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
6063 [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
6064 internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
6066 [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
6067 internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
6069 [DllImport ("libX11", EntryPoint="XDefaultVisual")]
6070 internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
6072 [DllImport ("libX11", EntryPoint="XDefaultDepth")]
6073 internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
6075 [DllImport ("libX11", EntryPoint="XDefaultScreen")]
6076 internal extern static int XDefaultScreen(IntPtr display);
6078 [DllImport ("libX11", EntryPoint="XDefaultColormap")]
6079 internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
6081 [DllImport ("libX11", EntryPoint="XLookupColor")]
6082 internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
6084 [DllImport ("libX11", EntryPoint="XAllocColor")]
6085 internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
6087 [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
6088 internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
6090 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6091 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
6093 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6094 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
6096 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6097 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
6099 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6100 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
6102 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6103 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
6105 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6106 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
6108 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6109 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
6111 [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
6112 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
6114 [DllImport ("libX11", EntryPoint="XDeleteProperty")]
6115 internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
6118 [DllImport ("libX11", EntryPoint="XCreateGC")]
6119 internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
6121 [DllImport ("libX11", EntryPoint="XFreeGC")]
6122 internal extern static int XFreeGC(IntPtr display, IntPtr gc);
6124 [DllImport ("libX11", EntryPoint="XSetFunction")]
6125 internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
6127 [DllImport ("libX11", EntryPoint="XSetLineAttributes")]
6128 internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
6130 [DllImport ("libX11", EntryPoint="XDrawLine")]
6131 internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
6133 [DllImport ("libX11", EntryPoint="XDrawRectangle")]
6134 internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
6136 [DllImport ("libX11", EntryPoint="XFillRectangle")]
6137 internal extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
6139 [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
6140 internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
6142 [DllImport ("libX11", EntryPoint="XCopyArea")]
6143 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);
6145 [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
6146 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);
6148 [DllImport ("libX11", EntryPoint="XSetInputFocus")]
6149 internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
6151 [DllImport ("libX11", EntryPoint="XIconifyWindow")]
6152 internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
6154 [DllImport ("libX11", EntryPoint="XDefineCursor")]
6155 internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
6157 [DllImport ("libX11", EntryPoint="XUndefineCursor")]
6158 internal extern static int XUndefineCursor(IntPtr display, IntPtr window);
6160 [DllImport ("libX11", EntryPoint="XFreeCursor")]
6161 internal extern static int XFreeCursor(IntPtr display, IntPtr cursor);
6163 [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
6164 internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
6166 [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
6167 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);
6169 [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
6170 internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
6172 [DllImport ("libX11", EntryPoint="XCreatePixmap")]
6173 internal extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
6175 [DllImport ("libX11", EntryPoint="XFreePixmap")]
6176 internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
6178 [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
6179 internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
6181 [DllImport ("libX11", EntryPoint="XQueryExtension")]
6182 internal extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
6184 [DllImport ("libX11", EntryPoint="XWhitePixel")]
6185 internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
6187 [DllImport ("libX11", EntryPoint="XBlackPixel")]
6188 internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
6190 [DllImport ("libX11", EntryPoint="XGrabServer")]
6191 internal extern static void XGrabServer(IntPtr display);
6193 [DllImport ("libX11", EntryPoint="XUngrabServer")]
6194 internal extern static void XUngrabServer(IntPtr display);
6196 [DllImport ("libX11", EntryPoint="XGetWMNormalHints")]
6197 internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
6199 [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
6200 internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
6202 [DllImport ("libX11", EntryPoint="XSetZoomHints")]
6203 internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
6205 [DllImport ("libX11", EntryPoint="XSetWMHints")]
6206 internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
6208 [DllImport ("libX11", EntryPoint="XGetIconSizes")]
6209 internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
6211 [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
6212 internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
6214 [DllImport ("libX11", EntryPoint="XGetErrorText")]
6215 internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
6217 [DllImport ("libX11", EntryPoint="XInitThreads")]
6218 internal extern static int XInitThreads();
6220 [DllImport ("libX11", EntryPoint="XConvertSelection")]
6221 internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
6223 [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
6224 internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
6226 [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
6227 internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
6229 [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
6230 internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
6232 [DllImport ("libX11", EntryPoint="XSetForeground")]
6233 internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
6235 [DllImport ("libX11", EntryPoint="XSetBackground")]
6236 internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
6238 [DllImport ("libX11", EntryPoint="XBell")]
6239 internal extern static int XBell(IntPtr display, int percent);
6241 [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")]
6242 internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
6244 [DllImport ("libX11", EntryPoint="XFilterEvent")]
6245 internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
6247 [DllImport ("libX11")]
6248 internal extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
6250 [DllImport ("libX11")]
6251 internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
6253 [DllImport ("libX11")]
6254 internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);