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;
1077 window_type = _NET_WM_WINDOW_TYPE_NORMAL;
1080 if (!cp.IsSet (WindowExStyles.WS_EX_APPWINDOW)) {
1081 hide_from_taskbar = true;
1082 } else if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW) && form != null && form.Parent != null && !form.ShowInTaskbar) {
1083 hide_from_taskbar = true;
1085 hide_from_taskbar = false;
1088 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
1089 if (form != null && !hwnd.reparented) {
1090 if (form.Owner != null && form.Owner.Handle != IntPtr.Zero) {
1091 Hwnd owner_hwnd = Hwnd.ObjectFromHandle (form.Owner.Handle);
1092 if (owner_hwnd != null)
1093 transient_for_parent = owner_hwnd.whole_window;
1097 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
1098 transient_for_parent = hwnd.parent.whole_window;
1101 FormWindowState current_state = GetWindowState (hwnd.Handle);
1102 if (current_state == (FormWindowState)(-1))
1103 current_state = FormWindowState.Normal;
1105 client_rect = TranslateClientRectangleToXClientRectangle (hwnd);
1110 atoms [0] = window_type.ToInt32 ();
1111 XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
1113 XChangeProperty(DisplayHandle, hwnd.whole_window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref mwmHints, 5);
1115 if (transient_for_parent != IntPtr.Zero) {
1116 XSetTransientForHint (DisplayHandle, hwnd.whole_window, transient_for_parent);
1119 MoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
1121 if (hide_from_taskbar) {
1122 /* this line keeps the window from showing up in gnome's taskbar */
1123 atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
1125 /* we need to add these atoms in the
1126 * event we're maximized, since we're
1127 * replacing the existing
1128 * _NET_WM_STATE here. If we don't
1129 * add them, future calls to
1130 * GetWindowState will return Normal
1131 * for a window which is maximized. */
1132 if (current_state == FormWindowState.Maximized) {
1133 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_HORZ.ToInt32();
1134 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_VERT.ToInt32();
1137 if (form != null && form.Modal) {
1138 atoms[atom_count++] = _NET_WM_STATE_MODAL.ToInt32 ();
1141 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
1144 IntPtr[] atom_ptrs = new IntPtr[2];
1145 atom_ptrs[atom_count++] = WM_DELETE_WINDOW;
1146 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP)) {
1147 atom_ptrs[atom_count++] = _NET_WM_CONTEXT_HELP;
1150 XSetWMProtocols(DisplayHandle, hwnd.whole_window, atom_ptrs, atom_count);
1154 private void SetIcon(Hwnd hwnd, Icon icon)
1159 // This really needs to do whatever it
1160 // takes to remove the window manager
1161 // menu, not just delete the ICON
1162 // property. This will cause metacity
1163 // to use the "no icon set" icon, and
1164 // we'll still have an icon.
1165 XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_ICON);
1173 bitmap = icon.ToBitmap();
1175 size = bitmap.Width * bitmap.Height + 2;
1176 data = new IntPtr[size];
1178 data[index++] = (IntPtr)bitmap.Width;
1179 data[index++] = (IntPtr)bitmap.Height;
1181 for (int y = 0; y < bitmap.Height; y++) {
1182 for (int x = 0; x < bitmap.Width; x++) {
1183 data[index++] = (IntPtr)bitmap.GetPixel (x, y).ToArgb ();
1187 XChangeProperty (DisplayHandle, hwnd.whole_window,
1188 _NET_WM_ICON, (IntPtr)Atom.XA_CARDINAL, 32,
1189 PropertyMode.Replace, data, size);
1193 private void WakeupMain () {
1194 wake.Send (new byte [] { 0xFF });
1197 private XEventQueue ThreadQueue(Thread thread) {
1200 queue = (XEventQueue)MessageQueues[thread];
1201 if (queue == null) {
1202 queue = new XEventQueue(thread);
1203 MessageQueues[thread] = queue;
1209 private void TranslatePropertyToClipboard(IntPtr property) {
1214 IntPtr prop = IntPtr.Zero;
1216 Clipboard.Item = null;
1218 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);
1220 if ((long)nitems > 0) {
1221 if (property == (IntPtr)Atom.XA_STRING) {
1222 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1223 } else if (property == (IntPtr)Atom.XA_BITMAP) {
1224 // FIXME - convert bitmap to image
1225 } else if (property == (IntPtr)Atom.XA_PIXMAP) {
1226 // FIXME - convert pixmap to image
1227 } else if (property == OEMTEXT) {
1228 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1229 } else if (property == UNICODETEXT) {
1230 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1237 private void AddExpose (Hwnd hwnd, bool client, int x, int y, int width, int height) {
1239 if ((hwnd == null) || (x > hwnd.Width) || (y > hwnd.Height) || ((x + width) < 0) || ((y + height) < 0)) {
1243 // Keep the invalid area as small as needed
1244 if ((x + width) > hwnd.width) {
1245 width = hwnd.width - x;
1248 if ((y + height) > hwnd.height) {
1249 height = hwnd.height - y;
1253 hwnd.AddInvalidArea(x, y, width, height);
1254 if (!hwnd.expose_pending) {
1255 if (!hwnd.nc_expose_pending) {
1256 hwnd.Queue.Paint.Enqueue(hwnd);
1258 hwnd.expose_pending = true;
1261 hwnd.AddNcInvalidArea (x, y, width, height);
1263 if (!hwnd.nc_expose_pending) {
1264 if (!hwnd.expose_pending) {
1265 hwnd.Queue.Paint.Enqueue(hwnd);
1267 hwnd.nc_expose_pending = true;
1272 private static Hwnd.Borders FrameExtents (IntPtr window)
1278 IntPtr prop = IntPtr.Zero;
1279 Hwnd.Borders rect = new Hwnd.Borders ();
1281 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);
1282 if (prop != IntPtr.Zero) {
1283 if (nitems.ToInt32 () == 4) {
1284 rect.left = Marshal.ReadInt32 (prop, 0);
1285 rect.right = Marshal.ReadInt32 (prop, IntPtr.Size);
1286 rect.top = Marshal.ReadInt32 (prop, 2 * IntPtr.Size);
1287 rect.bottom = Marshal.ReadInt32 (prop, 3 * IntPtr.Size);
1295 private void AddConfigureNotify (XEvent xevent) {
1298 hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window);
1301 if (hwnd == null || hwnd.zombie) {
1304 if ((xevent.ConfigureEvent.window == hwnd.whole_window)/* && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)*/) {
1305 if (hwnd.parent == null) {
1306 // The location given by the event is not reliable between different wm's,
1307 // so use an alternative way of getting it.
1308 Point location = GetTopLevelWindowLocation (hwnd);
1309 hwnd.x = location.X;
1310 hwnd.y = location.Y;
1313 // XXX this sucks. this isn't thread safe
1314 Control ctrl = Control.FromHandle (hwnd.Handle);
1315 Size TranslatedSize;
1317 TranslatedSize = TranslateXWindowSizeToWindowSize (ctrl.GetCreateParams (), xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
1319 TranslatedSize = new Size (xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
1321 hwnd.width = TranslatedSize.Width;
1322 hwnd.height = TranslatedSize.Height;
1323 hwnd.ClientRect = Rectangle.Empty;
1326 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));
1328 lock (hwnd.configure_lock) {
1329 if (!hwnd.configure_pending) {
1330 hwnd.Queue.EnqueueLocked (xevent);
1331 hwnd.configure_pending = true;
1335 // We drop configure events for Client windows
1338 private void ShowCaret() {
1339 if ((Caret.gc == IntPtr.Zero) || Caret.On) {
1345 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1349 private void HideCaret() {
1350 if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
1356 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1360 private int NextTimeout (ArrayList timers, DateTime now) {
1363 foreach (Timer timer in timers) {
1364 int next = (int) (timer.Expires - now).TotalMilliseconds;
1366 return 0; // Have a timer that has already expired
1369 if (next < timeout) {
1373 if (timeout < Timer.Minimum) {
1374 timeout = Timer.Minimum;
1382 private void CheckTimers (ArrayList timers, DateTime now) {
1385 count = timers.Count;
1390 for (int i = 0; i < timers.Count; i++) {
1393 timer = (Timer) timers [i];
1395 if (timer.Enabled && timer.Expires <= now && !timer.Busy) {
1404 private void WaitForHwndMessage (Hwnd hwnd, Msg message) {
1405 MSG msg = new MSG ();
1408 queue = ThreadQueue(Thread.CurrentThread);
1410 queue.DispatchIdle = false;
1414 if (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
1415 if ((Msg)msg.message == Msg.WM_QUIT) {
1416 PostQuitMessage (0);
1420 if (msg.hwnd == hwnd.Handle) {
1421 if ((Msg)msg.message == message)
1423 else if ((Msg)msg.message == Msg.WM_DESTROY)
1427 TranslateMessage (ref msg);
1428 DispatchMessage (ref msg);
1433 queue.DispatchIdle = true;
1437 private void MapWindow(Hwnd hwnd, WindowType windows) {
1439 Form f = Control.FromHandle(hwnd.Handle) as Form;
1441 if (f.WindowState == FormWindowState.Normal) {
1442 f.waiting_showwindow = true;
1443 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
1447 // it's possible that our Hwnd is no
1448 // longer valid after making that
1449 // SendMessage call, so check here.
1453 if ((windows & WindowType.Whole) != 0) {
1454 XMapWindow(DisplayHandle, hwnd.whole_window);
1456 if ((windows & WindowType.Client) != 0) {
1457 XMapWindow(DisplayHandle, hwnd.client_window);
1462 if (f != null && f.waiting_showwindow)
1463 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1467 private void UnmapWindow(Hwnd hwnd, WindowType windows) {
1470 if (Control.FromHandle(hwnd.Handle) is Form) {
1471 f = Control.FromHandle(hwnd.Handle) as Form;
1472 if (f.WindowState == FormWindowState.Normal) {
1473 f.waiting_showwindow = true;
1474 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
1478 // it's possible that our Hwnd is no
1479 // longer valid after making that
1480 // SendMessage call, so check here.
1481 // FIXME: it is likely wrong, as it has already sent WM_SHOWWINDOW
1485 if ((windows & WindowType.Client) != 0) {
1486 XUnmapWindow(DisplayHandle, hwnd.client_window);
1488 if ((windows & WindowType.Whole) != 0) {
1489 XUnmapWindow(DisplayHandle, hwnd.whole_window);
1492 hwnd.mapped = false;
1494 if (f != null && f.waiting_showwindow)
1495 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1499 private void UpdateMessageQueue (XEventQueue queue) {
1504 now = DateTime.UtcNow;
1507 pending = XPending (DisplayHandle);
1511 if ((queue == null || queue.DispatchIdle) && Idle != null) {
1512 Idle (this, EventArgs.Empty);
1516 pending = XPending (DisplayHandle);
1523 if (queue != null) {
1524 if (queue.Paint.Count > 0)
1527 timeout = NextTimeout (queue.timer_list, now);
1532 int length = pollfds.Length - 1;
1533 lock (wake_waiting_lock) {
1534 if (wake_waiting == false) {
1536 wake_waiting = true;
1540 Syscall.poll (pollfds, (uint)length, timeout);
1541 // Clean out buffer, so we're not busy-looping on the same data
1542 if (length == pollfds.Length) {
1543 if (pollfds[1].revents != 0)
1544 wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
1545 lock (wake_waiting_lock) {
1546 wake_waiting = false;
1551 pending = XPending (DisplayHandle);
1557 CheckTimers (queue.timer_list, now);
1560 XEvent xevent = new XEvent ();
1563 if (XPending (DisplayHandle) == 0)
1566 XNextEvent (DisplayHandle, ref xevent);
1568 if (xevent.AnyEvent.type == XEventName.KeyPress ||
1569 xevent.AnyEvent.type == XEventName.KeyRelease) {
1570 // PreFilter() handles "shift key state updates.
1571 Keyboard.PreFilter (xevent);
1572 if (XFilterEvent (ref xevent, Keyboard.ClientWindow)) {
1573 // probably here we could raise WM_IME_KEYDOWN and
1574 // WM_IME_KEYUP, but I'm not sure it is worthy.
1578 else if (XFilterEvent (ref xevent, IntPtr.Zero))
1582 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
1587 Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
1589 switch (xevent.type) {
1590 case XEventName.Expose:
1591 AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
1594 case XEventName.SelectionClear: {
1595 // Should we do something?
1599 case XEventName.SelectionRequest: {
1600 if (Dnd.HandleSelectionRequestEvent (ref xevent))
1604 sel_event = new XEvent();
1605 sel_event.SelectionEvent.type = XEventName.SelectionNotify;
1606 sel_event.SelectionEvent.send_event = true;
1607 sel_event.SelectionEvent.display = DisplayHandle;
1608 sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
1609 sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
1610 sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
1611 sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
1612 sel_event.SelectionEvent.property = IntPtr.Zero;
1614 // Seems that some apps support asking for supported types
1615 if (xevent.SelectionEvent.target == TARGETS) {
1622 if (Clipboard.Item is String) {
1623 atoms[atom_count++] = (int)Atom.XA_STRING;
1624 atoms[atom_count++] = (int)OEMTEXT;
1625 atoms[atom_count++] = (int)UNICODETEXT;
1626 } else if (Clipboard.Item is Image) {
1627 atoms[atom_count++] = (int)Atom.XA_PIXMAP;
1628 atoms[atom_count++] = (int)Atom.XA_BITMAP;
1630 // FIXME - handle other types
1633 XChangeProperty(DisplayHandle, xevent.SelectionEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
1634 } else if (Clipboard.Item is string) {
1640 if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) {
1643 bytes = new ASCIIEncoding().GetBytes((string)Clipboard.Item);
1644 buffer = Marshal.AllocHGlobal(bytes.Length);
1645 buflen = bytes.Length;
1647 for (int i = 0; i < buflen; i++) {
1648 Marshal.WriteByte(buffer, i, bytes[i]);
1650 } else if (xevent.SelectionRequestEvent.target == OEMTEXT) {
1651 // FIXME - this should encode into ISO2022
1652 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1653 while (Marshal.ReadByte(buffer, buflen) != 0) {
1656 } else if (xevent.SelectionRequestEvent.target == UNICODETEXT) {
1657 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1658 while (Marshal.ReadByte(buffer, buflen) != 0) {
1662 buffer = IntPtr.Zero;
1665 if (buffer != IntPtr.Zero) {
1666 XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
1667 sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
1668 Marshal.FreeHGlobal(buffer);
1670 } else if (Clipboard.Item is Image) {
1671 if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1672 // FIXME - convert image and store as property
1673 } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1674 // FIXME - convert image and store as property
1678 XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event);
1682 case XEventName.SelectionNotify: {
1683 if (Clipboard.Enumerating) {
1684 Clipboard.Enumerating = false;
1685 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1686 XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property);
1687 if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) {
1688 Clipboard.Formats.Add(xevent.SelectionEvent.property);
1689 #if DriverDebugExtra
1690 Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
1694 } else if (Clipboard.Retrieving) {
1695 Clipboard.Retrieving = false;
1696 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1697 TranslatePropertyToClipboard(xevent.SelectionEvent.property);
1699 Clipboard.Item = null;
1702 Dnd.HandleSelectionNotifyEvent (ref xevent);
1707 case XEventName.KeyRelease:
1708 if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) {
1709 XEvent nextevent = new XEvent ();
1711 XPeekEvent (DisplayHandle, ref nextevent);
1713 if (nextevent.type == XEventName.KeyPress &&
1714 nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
1715 nextevent.KeyEvent.time == xevent.KeyEvent.time) {
1719 goto case XEventName.KeyPress;
1721 case XEventName.MotionNotify: {
1724 /* we can't do motion compression across threads, so just punt if we don't match up */
1725 if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) {
1726 peek = hwnd.Queue.Peek();
1727 if (peek.AnyEvent.type == XEventName.MotionNotify) {
1731 goto case XEventName.KeyPress;
1734 case XEventName.KeyPress:
1735 hwnd.Queue.EnqueueLocked (xevent);
1736 /* Process KeyPresses immediately. Otherwise multiple Compose messages as a result of a
1737 * single physical keypress are not processed correctly */
1739 case XEventName.ButtonPress:
1740 case XEventName.ButtonRelease:
1741 case XEventName.EnterNotify:
1742 case XEventName.LeaveNotify:
1743 case XEventName.CreateNotify:
1744 case XEventName.DestroyNotify:
1745 case XEventName.FocusIn:
1746 case XEventName.FocusOut:
1747 case XEventName.ClientMessage:
1748 case XEventName.ReparentNotify:
1749 case XEventName.MapNotify:
1750 case XEventName.UnmapNotify:
1751 hwnd.Queue.EnqueueLocked (xevent);
1754 case XEventName.ConfigureNotify:
1755 AddConfigureNotify(xevent);
1758 case XEventName.PropertyNotify:
1760 Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
1762 if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) {
1767 IntPtr prop = IntPtr.Zero;
1770 prev_active = ActiveWindow;
1771 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);
1772 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
1773 ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop));
1776 if (prev_active != ActiveWindow) {
1777 if (prev_active != IntPtr.Zero) {
1778 PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1780 if (ActiveWindow != IntPtr.Zero) {
1781 PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
1784 if (ModalWindows.Count == 0) {
1787 // Modality Handling
1789 // If there is a modal window on the stack and the new active
1790 // window is MWF window, but not the modal one and not a non-modal
1791 // child of the modal one, switch back to the modal window.
1793 // To identify if a non-modal form is child of a modal form
1794 // we match their ApplicationContexts, which will be the same.
1795 // This is because each modal form runs the loop with a
1796 // new ApplicationContext, which is inherited by the non-modal
1799 Form activeForm = Control.FromHandle (ActiveWindow) as Form;
1800 if (activeForm != null) {
1801 Form modalForm = Control.FromHandle ((IntPtr)ModalWindows.Peek()) as Form;
1802 if (ActiveWindow != (IntPtr)ModalWindows.Peek() &&
1803 (modalForm == null || activeForm.context == modalForm.context)) {
1804 Activate((IntPtr)ModalWindows.Peek());
1811 else if (xevent.PropertyEvent.atom == _NET_WM_STATE) {
1812 // invalidate our cache - we'll query again the next time someone does GetWindowState.
1813 hwnd.cached_window_state = (FormWindowState)(-1);
1814 PostMessage (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
1822 private IntPtr GetMousewParam(int Delta) {
1825 if ((MouseState & MouseButtons.Left) != 0) {
1826 result |= (int)MsgButtons.MK_LBUTTON;
1829 if ((MouseState & MouseButtons.Middle) != 0) {
1830 result |= (int)MsgButtons.MK_MBUTTON;
1833 if ((MouseState & MouseButtons.Right) != 0) {
1834 result |= (int)MsgButtons.MK_RBUTTON;
1837 Keys mods = ModifierKeys;
1838 if ((mods & Keys.Control) != 0) {
1839 result |= (int)MsgButtons.MK_CONTROL;
1842 if ((mods & Keys.Shift) != 0) {
1843 result |= (int)MsgButtons.MK_SHIFT;
1846 result |= Delta << 16;
1848 return (IntPtr)result;
1850 private IntPtr XGetParent(IntPtr handle) {
1857 XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount);
1860 if (Children!=IntPtr.Zero) {
1868 private int HandleError (IntPtr display, ref XErrorEvent error_event)
1870 // we need to workaround a problem with the
1871 // ordering of destruction of Drawables and
1872 // Pictures that exists between cairo and
1873 // RENDER on the server.
1874 if (error_event.request_code == (XRequest)render_major_opcode
1875 && error_event.minor_code == 7 /* X_RenderFreePicture from render.h */
1876 && error_event.error_code == render_first_error + 1 /* BadPicture from render.h */) {
1880 if (ErrorExceptions) {
1881 XUngrabPointer (display, IntPtr.Zero);
1882 throw new XException (error_event.display, error_event.resourceid,
1883 error_event.serial, error_event.error_code,
1884 error_event.request_code, error_event.minor_code);
1886 Console.WriteLine("X11 Error encountered: {0}{1}\n",
1887 XException.GetMessage (error_event.display, error_event.resourceid,
1888 error_event.serial, error_event.error_code,
1889 error_event.request_code, error_event.minor_code),
1890 Environment.StackTrace);
1895 private void AccumulateDestroyedHandles (Control c, ArrayList list)
1898 Control[] controls = c.Controls.GetAllControls ();
1900 if (c.IsHandleCreated && !c.IsDisposed) {
1901 Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle);
1903 #if DriverDebug || DriverDebugDestroy
1904 Console.WriteLine (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
1905 Console.WriteLine (" + parent X window is {0:X}", XGetParent (hwnd.whole_window).ToInt32());
1909 CleanupCachedWindows (hwnd);
1912 for (int i = 0; i < controls.Length; i ++) {
1913 AccumulateDestroyedHandles (controls[i], list);
1919 void CleanupCachedWindows (Hwnd hwnd)
1921 if (ActiveWindow == hwnd.Handle) {
1922 SendMessage(hwnd.client_window, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1923 ActiveWindow = IntPtr.Zero;
1926 if (FocusWindow == hwnd.Handle) {
1927 SendMessage(hwnd.client_window, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
1928 FocusWindow = IntPtr.Zero;
1931 if (Grab.Hwnd == hwnd.Handle) {
1932 Grab.Hwnd = IntPtr.Zero;
1933 Grab.Confined = false;
1936 DestroyCaret (hwnd.Handle);
1939 private void PerformNCCalc(Hwnd hwnd) {
1940 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
1944 rect = new Rectangle (0, 0, hwnd.Width, hwnd.Height);
1946 ncp = new XplatUIWin32.NCCALCSIZE_PARAMS();
1947 ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp));
1949 ncp.rgrc1.left = rect.Left;
1950 ncp.rgrc1.top = rect.Top;
1951 ncp.rgrc1.right = rect.Right;
1952 ncp.rgrc1.bottom = rect.Bottom;
1954 Marshal.StructureToPtr(ncp, ptr, true);
1955 NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr);
1956 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
1957 Marshal.FreeHGlobal(ptr);
1960 rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
1961 hwnd.ClientRect = rect;
1963 rect = TranslateClientRectangleToXClientRectangle (hwnd);
1966 MoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
1969 AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
1971 #endregion // Private Methods
1974 private void MouseHover(object sender, EventArgs e) {
1978 HoverState.Timer.Enabled = false;
1980 if (HoverState.Window != IntPtr.Zero) {
1981 hwnd = Hwnd.GetObjectFromWindow(HoverState.Window);
1983 xevent = new XEvent ();
1985 xevent.type = XEventName.ClientMessage;
1986 xevent.ClientMessageEvent.display = DisplayHandle;
1987 xevent.ClientMessageEvent.window = HoverState.Window;
1988 xevent.ClientMessageEvent.message_type = HoverState.Atom;
1989 xevent.ClientMessageEvent.format = 32;
1990 xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
1992 hwnd.Queue.EnqueueLocked (xevent);
1999 private void CaretCallback(object sender, EventArgs e) {
2003 Caret.On = !Caret.On;
2005 XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
2007 #endregion // Callbacks
2009 #region Public Properties
2011 internal override int CaptionHeight {
2017 internal override Size CursorSize {
2022 if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) {
2023 return new Size(x, y);
2025 return new Size(16, 16);
2030 internal override bool DragFullWindows {
2036 internal override Size DragSize {
2038 return new Size(4, 4);
2042 internal override Size FrameBorderSize {
2044 return new Size (4, 4);
2048 internal override Size IconSize {
2054 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
2058 current = (long)list;
2061 size = new XIconSize();
2063 for (int i = 0; i < count; i++) {
2064 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
2065 current += Marshal.SizeOf(size);
2067 // Look for our preferred size
2068 if (size.min_width == 32) {
2070 return new Size(32, 32);
2073 if (size.max_width == 32) {
2075 return new Size(32, 32);
2078 if (size.min_width < 32 && size.max_width > 32) {
2081 // check if we can fit one
2083 while (x < size.max_width) {
2084 x += size.width_inc;
2087 return new Size(32, 32);
2092 if (largest < size.max_width) {
2093 largest = size.max_width;
2097 // We didn't find a match or we wouldn't be here
2098 return new Size(largest, largest);
2101 return new Size(32, 32);
2106 internal override int KeyboardSpeed {
2109 // A lot harder: need to do:
2110 // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
2111 // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
2112 // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
2114 // And from that we can tell the repetition rate
2116 // Notice, the values must map to:
2117 // [0, 31] which maps to 2.5 to 30 repetitions per second.
2123 internal override int KeyboardDelay {
2126 // Return values must range from 0 to 4, 0 meaning 250ms,
2127 // and 4 meaning 1000 ms.
2129 return 1; // ie, 500 ms
2133 internal override Size MaxWindowTrackSize {
2135 return new Size (WorkingArea.Width, WorkingArea.Height);
2139 internal override bool MenuAccessKeysUnderlined {
2145 internal override Size MinimizedWindowSpacingSize {
2147 return new Size(1, 1);
2151 internal override Size MinimumWindowSize {
2153 return new Size(110, 22);
2157 internal override Size MinimumFixedToolWindowSize {
2158 get { return new Size (27, 22); }
2161 internal override Size MinimumSizeableToolWindowSize {
2162 get { return new Size (37, 22); }
2165 internal override Size MinimumNoBorderWindowSize {
2166 get { return new Size (2, 2); }
2169 internal override Keys ModifierKeys {
2171 return Keyboard.ModifierKeys;
2175 internal override Size SmallIconSize {
2181 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
2185 current = (long)list;
2188 size = new XIconSize();
2190 for (int i = 0; i < count; i++) {
2191 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
2192 current += Marshal.SizeOf(size);
2194 // Look for our preferred size
2195 if (size.min_width == 16) {
2197 return new Size(16, 16);
2200 if (size.max_width == 16) {
2202 return new Size(16, 16);
2205 if (size.min_width < 16 && size.max_width > 16) {
2208 // check if we can fit one
2210 while (x < size.max_width) {
2211 x += size.width_inc;
2214 return new Size(16, 16);
2219 if (smallest == 0 || smallest > size.min_width) {
2220 smallest = size.min_width;
2224 // We didn't find a match or we wouldn't be here
2225 return new Size(smallest, smallest);
2228 return new Size(16, 16);
2233 internal override int MouseButtonCount {
2239 internal override bool MouseButtonsSwapped {
2241 return false; // FIXME - how to detect?
2245 internal override Point MousePosition {
2247 return mouse_position;
2251 internal override Size MouseHoverSize {
2253 return new Size (1, 1);
2257 internal override int MouseHoverTime {
2259 return HoverState.Interval;
2265 internal override bool MouseWheelPresent {
2267 return true; // FIXME - how to detect?
2271 internal override MouseButtons MouseButtons {
2277 internal override Rectangle VirtualScreen {
2283 IntPtr prop = IntPtr.Zero;
2287 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);
2288 if ((long)nitems < 2)
2291 width = Marshal.ReadIntPtr(prop, 0).ToInt32();
2292 height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
2296 return new Rectangle(0, 0, width, height);
2299 XWindowAttributes attributes=new XWindowAttributes();
2302 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2305 return new Rectangle(0, 0, attributes.width, attributes.height);
2309 internal override Rectangle WorkingArea {
2315 IntPtr prop = IntPtr.Zero;
2318 int current_desktop;
2322 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);
2323 if ((long)nitems < 1) {
2327 current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
2330 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);
2331 if ((long)nitems < 4 * current_desktop) {
2335 x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
2336 y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
2337 width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
2338 height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
2341 return new Rectangle(x, y, width, height);
2344 XWindowAttributes attributes=new XWindowAttributes();
2347 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2350 return new Rectangle(0, 0, attributes.width, attributes.height);
2354 internal override bool ThemesEnabled {
2356 return XplatUIX11.themes_enabled;
2361 #endregion // Public properties
2363 #region Public Static Methods
2364 internal override void RaiseIdle (EventArgs e)
2370 internal override IntPtr InitializeDriver() {
2372 if (DisplayHandle==IntPtr.Zero) {
2373 SetDisplay(XOpenDisplay(IntPtr.Zero));
2379 internal override void ShutdownDriver(IntPtr token) {
2381 if (DisplayHandle!=IntPtr.Zero) {
2382 XCloseDisplay(DisplayHandle);
2383 DisplayHandle=IntPtr.Zero;
2388 internal override void EnableThemes() {
2389 themes_enabled = true;
2393 internal override void Activate(IntPtr handle) {
2396 hwnd = Hwnd.ObjectFromHandle(handle);
2400 if (true /* the window manager supports NET_ACTIVE_WINDOW */) {
2401 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
2402 XEventQueue q = null;
2403 lock (unattached_timer_list) {
2404 foreach (Timer t in unattached_timer_list) {
2406 q= (XEventQueue) MessageQueues [Thread.CurrentThread];
2407 t.thread = q.Thread;
2408 q.timer_list.Add (t);
2410 unattached_timer_list.Clear ();
2414 // XRaiseWindow(DisplayHandle, handle);
2420 internal override void AudibleAlert() {
2421 XBell(DisplayHandle, 0);
2426 internal override void CaretVisible(IntPtr handle, bool visible) {
2427 if (Caret.Hwnd == handle) {
2429 if (!Caret.Visible) {
2430 Caret.Visible = true;
2432 Caret.Timer.Start();
2435 Caret.Visible = false;
2442 internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) {
2443 WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect);
2447 internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) {
2453 hwnd = Hwnd.ObjectFromHandle(handle);
2456 XTranslateCoordinates(DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
2463 internal override int[] ClipboardAvailableFormats(IntPtr handle) {
2464 DataFormats.Format f;
2467 f = DataFormats.Format.List;
2469 if (XGetSelectionOwner(DisplayHandle, CLIPBOARD) == IntPtr.Zero) {
2473 Clipboard.Formats = new ArrayList();
2476 XConvertSelection(DisplayHandle, CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent, IntPtr.Zero);
2478 Clipboard.Enumerating = true;
2479 while (Clipboard.Enumerating) {
2480 UpdateMessageQueue(null);
2485 result = new int[Clipboard.Formats.Count];
2487 for (int i = 0; i < Clipboard.Formats.Count; i++) {
2488 result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
2491 Clipboard.Formats = null;
2495 internal override void ClipboardClose(IntPtr handle) {
2496 if (handle != ClipMagic) {
2497 throw new ArgumentException("handle is not a valid clipboard handle");
2502 internal override int ClipboardGetID(IntPtr handle, string format) {
2503 if (handle != ClipMagic) {
2504 throw new ArgumentException("handle is not a valid clipboard handle");
2507 if (format == "Text" ) return (int)Atom.XA_STRING;
2508 else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP;
2509 //else if (format == "MetaFilePict" ) return 3;
2510 //else if (format == "SymbolicLink" ) return 4;
2511 //else if (format == "DataInterchangeFormat" ) return 5;
2512 //else if (format == "Tiff" ) return 6;
2513 else if (format == "OEMText" ) return OEMTEXT.ToInt32();
2514 else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP;
2515 else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless
2516 //else if (format == "PenData" ) return 10;
2517 //else if (format == "RiffAudio" ) return 11;
2518 //else if (format == "WaveAudio" ) return 12;
2519 else if (format == "UnicodeText" ) return UNICODETEXT.ToInt32();
2520 //else if (format == "EnhancedMetafile" ) return 14;
2521 //else if (format == "FileDrop" ) return 15;
2522 //else if (format == "Locale" ) return 16;
2524 return XInternAtom(DisplayHandle, format, false).ToInt32();
2527 internal override IntPtr ClipboardOpen(bool primary_selection) {
2528 if (!primary_selection)
2529 ClipMagic = CLIPBOARD;
2531 ClipMagic = PRIMARY;
2535 internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) {
2536 XConvertSelection(DisplayHandle, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
2538 Clipboard.Retrieving = true;
2539 while (Clipboard.Retrieving) {
2540 UpdateMessageQueue(null);
2543 return Clipboard.Item;
2546 internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter) {
2547 Clipboard.Item = obj;
2548 Clipboard.Type = type;
2549 Clipboard.Converter = converter;
2552 XSetSelectionOwner(DisplayHandle, CLIPBOARD, FosterParent, IntPtr.Zero);
2554 // Clearing the selection
2555 XSetSelectionOwner(DisplayHandle, CLIPBOARD, IntPtr.Zero, IntPtr.Zero);
2559 internal override void CreateCaret (IntPtr handle, int width, int height)
2561 XGCValues gc_values;
2564 hwnd = Hwnd.ObjectFromHandle(handle);
2566 if (Caret.Hwnd != IntPtr.Zero) {
2567 DestroyCaret(Caret.Hwnd);
2570 Caret.Hwnd = handle;
2571 Caret.Window = hwnd.client_window;
2572 Caret.Width = width;
2573 Caret.Height = height;
2574 Caret.Visible = false;
2577 gc_values = new XGCValues();
2578 gc_values.line_width = width;
2580 Caret.gc = XCreateGC(DisplayHandle, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
2581 if (Caret.gc == IntPtr.Zero) {
2582 Caret.Hwnd = IntPtr.Zero;
2586 XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert);
2589 internal override IntPtr CreateWindow (CreateParams cp)
2591 XSetWindowAttributes Attributes;
2593 Hwnd parent_hwnd = null;
2598 IntPtr ParentHandle;
2600 IntPtr ClientWindow;
2601 SetWindowValuemask ValueMask;
2606 Attributes = new XSetWindowAttributes();
2612 if (Width<1) Width=1;
2613 if (Height<1) Height=1;
2615 if (cp.Parent != IntPtr.Zero) {
2616 parent_hwnd = Hwnd.ObjectFromHandle(cp.Parent);
2617 ParentHandle = parent_hwnd.client_window;
2619 if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2620 // We need to use our foster parent window until this poor child gets it's parent assigned
2621 ParentHandle=FosterParent;
2623 ParentHandle=RootWindow;
2627 // Set the default location location for forms.
2629 if (cp.control is Form) {
2630 next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd);
2634 ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
2636 Attributes.bit_gravity = Gravity.NorthWestGravity;
2637 Attributes.win_gravity = Gravity.NorthWestGravity;
2639 // Save what's under the toolwindow
2640 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
2641 Attributes.save_under = true;
2642 ValueMask |= SetWindowValuemask.SaveUnder;
2646 // If we're a popup without caption we override the WM
2647 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
2648 Attributes.override_redirect = true;
2649 ValueMask |= SetWindowValuemask.OverrideRedirect;
2655 hwnd.height = Height;
2656 hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent);
2657 hwnd.initial_style = cp.WindowStyle;
2658 hwnd.initial_ex_style = cp.WindowExStyle;
2660 if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) {
2661 hwnd.enabled = false;
2664 ClientWindow = IntPtr.Zero;
2666 Size XWindowSize = TranslateWindowSizeToXWindowSize (cp);
2667 Rectangle XClientRect = TranslateClientRectangleToXClientRectangle (hwnd, cp.control);
2670 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);
2671 if (WholeWindow != IntPtr.Zero) {
2672 ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
2674 if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) {
2675 ValueMask = SetWindowValuemask.ColorMap;
2676 Attributes.colormap = CustomColormap;
2678 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);
2682 if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) {
2683 throw new Exception("Could not create X11 windows");
2686 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
2687 hwnd.WholeWindow = WholeWindow;
2688 hwnd.ClientWindow = ClientWindow;
2690 #if DriverDebug || DriverDebugCreate
2691 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);
2694 if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2695 if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
2698 hints = new XSizeHints();
2701 hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition);
2702 XSetWMNormalHints(DisplayHandle, WholeWindow, ref hints);
2707 XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
2708 if (hwnd.whole_window != hwnd.client_window)
2709 XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | Keyboard.KeyEventMask)));
2712 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
2714 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
2715 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
2717 XSetTransientForHint (DisplayHandle, hwnd.whole_window, RootWindow);
2720 SetWMStyles(hwnd, cp);
2722 // set the group leader
2723 XWMHints wm_hints = new XWMHints ();
2725 wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint);
2726 wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
2727 wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState;
2729 if (ParentHandle != RootWindow) {
2730 wm_hints.window_group = hwnd.whole_window;
2732 wm_hints.window_group = ParentHandle;
2736 XSetWMHints(DisplayHandle, hwnd.whole_window, ref wm_hints );
2739 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) {
2740 SetWindowState(hwnd.Handle, FormWindowState.Minimized);
2741 } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) {
2742 SetWindowState(hwnd.Handle, FormWindowState.Maximized);
2745 // for now make all windows dnd enabled
2746 Dnd.SetAllowDrop (hwnd, true);
2748 // Set caption/window title
2749 Text(hwnd.Handle, cp.Caption);
2751 SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */);
2752 SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue);
2754 if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) {
2755 hwnd.visible = true;
2756 MapWindow(hwnd, WindowType.Both);
2757 if (!(Control.FromHandle(hwnd.Handle) is Form))
2758 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
2764 internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) {
2765 CreateParams create_params = new CreateParams();
2767 create_params.Caption = "";
2768 create_params.X = X;
2769 create_params.Y = Y;
2770 create_params.Width = Width;
2771 create_params.Height = Height;
2773 create_params.ClassName=XplatUI.DefaultClassName;
2774 create_params.ClassStyle = 0;
2775 create_params.ExStyle=0;
2776 create_params.Parent=IntPtr.Zero;
2777 create_params.Param=0;
2779 return CreateWindow(create_params);
2782 internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
2784 Bitmap cursor_bitmap;
2792 IntPtr cursor_pixmap;
2799 if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) {
2803 // Win32 only allows creation cursors of a certain size
2804 if ((bitmap.Width != width) || (bitmap.Width != height)) {
2805 cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
2806 cursor_mask = new Bitmap(mask, new Size(width, height));
2808 cursor_bitmap = bitmap;
2812 width = cursor_bitmap.Width;
2813 height = cursor_bitmap.Height;
2815 cursor_bits = new Byte[(width / 8) * height];
2816 mask_bits = new Byte[(width / 8) * height];
2818 for (int y = 0; y < height; y++) {
2819 for (int x = 0; x < width; x++) {
2820 c_pixel = cursor_bitmap.GetPixel(x, y);
2821 m_pixel = cursor_mask.GetPixel(x, y);
2823 and = c_pixel == cursor_pixel;
2824 xor = m_pixel == mask_pixel;
2828 // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
2829 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2830 } else if (and && !xor) {
2832 cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2833 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2835 } else if (and && !xor) {
2837 } else if (and && xor) {
2840 // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
2841 // we want both to be 0 so nothing to be done
2842 //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
2843 //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
2849 cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2850 mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2854 fg.pixel = XWhitePixel(DisplayHandle, ScreenNo);
2855 fg.red = (ushort)65535;
2856 fg.green = (ushort)65535;
2857 fg.blue = (ushort)65535;
2859 bg.pixel = XBlackPixel(DisplayHandle, ScreenNo);
2861 cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
2863 XFreePixmap(DisplayHandle, cursor_pixmap);
2864 XFreePixmap(DisplayHandle, mask_pixmap);
2869 internal override Bitmap DefineStdCursorBitmap (StdCursor id) {
2870 CursorFontShape shape;
2877 shape = StdCursorToFontShape (id);
2878 name = shape.ToString ().Replace ("XC_", string.Empty);
2879 size = XcursorGetDefaultSize (DisplayHandle);
2880 theme = XcursorGetTheme (DisplayHandle);
2881 IntPtr images_ptr = XcursorLibraryLoadImages (name, theme, size);
2883 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);
2886 if (images_ptr == IntPtr.Zero) {
2890 XcursorImages images = (XcursorImages) Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
2892 Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
2895 if (images.nimage > 0) {
2896 // We only care about the first image.
2897 XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
2900 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);
2903 if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
2904 int [] pixels = new int [image.width * image.height];
2905 Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
2906 bmp = new Bitmap (image.width, image.height);
2907 for (int w = 0; w < image.width; w++) {
2908 for (int h = 0; h < image.height; h++) {
2909 bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
2915 XcursorImagesDestroy (images_ptr);
2917 } catch (DllNotFoundException ex) {
2918 Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
2926 internal override IntPtr DefineStdCursor(StdCursor id) {
2927 CursorFontShape shape;
2930 shape = StdCursorToFontShape (id);
2933 cursor = XCreateFontCursor(DisplayHandle, shape);
2938 internal static CursorFontShape StdCursorToFontShape (StdCursor id) {
2939 CursorFontShape shape;
2940 // FIXME - define missing shapes
2943 case StdCursor.AppStarting: {
2944 shape = CursorFontShape.XC_watch;
2948 case StdCursor.Arrow: {
2949 shape = CursorFontShape.XC_top_left_arrow;
2953 case StdCursor.Cross: {
2954 shape = CursorFontShape.XC_crosshair;
2958 case StdCursor.Default: {
2959 shape = CursorFontShape.XC_top_left_arrow;
2963 case StdCursor.Hand: {
2964 shape = CursorFontShape.XC_hand1;
2968 case StdCursor.Help: {
2969 shape = CursorFontShape.XC_question_arrow;
2973 case StdCursor.HSplit: {
2974 shape = CursorFontShape.XC_sb_v_double_arrow;
2978 case StdCursor.IBeam: {
2979 shape = CursorFontShape.XC_xterm;
2983 case StdCursor.No: {
2984 shape = CursorFontShape.XC_circle;
2988 case StdCursor.NoMove2D: {
2989 shape = CursorFontShape.XC_fleur;
2993 case StdCursor.NoMoveHoriz: {
2994 shape = CursorFontShape.XC_fleur;
2998 case StdCursor.NoMoveVert: {
2999 shape = CursorFontShape.XC_fleur;
3003 case StdCursor.PanEast: {
3004 shape = CursorFontShape.XC_fleur;
3008 case StdCursor.PanNE: {
3009 shape = CursorFontShape.XC_fleur;
3013 case StdCursor.PanNorth: {
3014 shape = CursorFontShape.XC_fleur;
3018 case StdCursor.PanNW: {
3019 shape = CursorFontShape.XC_fleur;
3023 case StdCursor.PanSE: {
3024 shape = CursorFontShape.XC_fleur;
3028 case StdCursor.PanSouth: {
3029 shape = CursorFontShape.XC_fleur;
3033 case StdCursor.PanSW: {
3034 shape = CursorFontShape.XC_fleur;
3038 case StdCursor.PanWest: {
3039 shape = CursorFontShape.XC_sizing;
3043 case StdCursor.SizeAll: {
3044 shape = CursorFontShape.XC_fleur;
3048 case StdCursor.SizeNESW: {
3049 shape = CursorFontShape.XC_top_right_corner;
3053 case StdCursor.SizeNS: {
3054 shape = CursorFontShape.XC_sb_v_double_arrow;
3058 case StdCursor.SizeNWSE: {
3059 shape = CursorFontShape.XC_top_left_corner;
3063 case StdCursor.SizeWE: {
3064 shape = CursorFontShape.XC_sb_h_double_arrow;
3068 case StdCursor.UpArrow: {
3069 shape = CursorFontShape.XC_center_ptr;
3073 case StdCursor.VSplit: {
3074 shape = CursorFontShape.XC_sb_h_double_arrow;
3078 case StdCursor.WaitCursor: {
3079 shape = CursorFontShape.XC_watch;
3084 shape = (CursorFontShape) 0;
3092 internal override IntPtr DefWndProc(ref Message msg) {
3093 switch ((Msg)msg.Msg) {
3095 case Msg.WM_IME_COMPOSITION:
3096 string s = Keyboard.GetCompositionString ();
3097 foreach (char c in s)
3098 SendMessage (msg.HWnd, Msg.WM_IME_CHAR, (IntPtr) c, msg.LParam);
3101 case Msg.WM_IME_CHAR:
3102 // On Windows API it sends two WM_CHAR messages for each byte, but
3103 // I wonder if it is worthy to emulate it (also no idea how to
3104 // reconstruct those bytes into chars).
3105 SendMessage (msg.HWnd, Msg.WM_CHAR, msg.WParam, msg.LParam);
3108 case Msg.WM_PAINT: {
3111 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3113 hwnd.expose_pending = false;
3119 case Msg.WM_NCPAINT: {
3122 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3124 hwnd.nc_expose_pending = false;
3130 case Msg.WM_NCCALCSIZE: {
3133 if (msg.WParam == (IntPtr)1) {
3134 hwnd = Hwnd.GetObjectFromWindow (msg.HWnd);
3136 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
3137 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (msg.LParam, typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
3139 // Add all the stuff X is supposed to draw.
3140 Control ctrl = Control.FromHandle (hwnd.Handle);
3143 Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null);
3145 ncp.rgrc1.top += rect.top;
3146 ncp.rgrc1.bottom -= rect.bottom;
3147 ncp.rgrc1.left += rect.left;
3148 ncp.rgrc1.right -= rect.right;
3150 Marshal.StructureToPtr (ncp, msg.LParam, true);
3157 case Msg.WM_CONTEXTMENU: {
3160 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3162 if ((hwnd != null) && (hwnd.parent != null)) {
3163 SendMessage(hwnd.parent.client_window, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam);
3168 case Msg.WM_MOUSEWHEEL: {
3171 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3173 if ((hwnd != null) && (hwnd.parent != null)) {
3174 SendMessage(hwnd.parent.client_window, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam);
3175 if (msg.Result == IntPtr.Zero) {
3182 case Msg.WM_SETCURSOR: {
3185 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3187 break; // not sure how this happens, but it does
3189 // Pass to parent window first
3190 while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) {
3192 msg.Result = NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam);
3195 if (msg.Result == IntPtr.Zero) {
3198 switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) {
3199 case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break;
3200 case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break;
3201 case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break;
3202 case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break;
3203 case HitTest.HTERROR: if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) {
3206 handle = Cursors.Default.handle;
3209 case HitTest.HTHELP: handle = Cursors.Help.handle; break;
3210 case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break;
3211 case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break;
3212 case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break;
3213 case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break;
3214 case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break;
3217 case HitTest.HTGROWBOX:
3218 case HitTest.HTSIZE:
3219 case HitTest.HTZOOM:
3220 case HitTest.HTVSCROLL:
3221 case HitTest.HTSYSMENU:
3222 case HitTest.HTREDUCE:
3223 case HitTest.HTNOWHERE:
3224 case HitTest.HTMAXBUTTON:
3225 case HitTest.HTMINBUTTON:
3226 case HitTest.HTMENU:
3227 case HitTest.HSCROLL:
3228 case HitTest.HTBOTTOM:
3229 case HitTest.HTCAPTION:
3230 case HitTest.HTCLIENT:
3231 case HitTest.HTCLOSE:
3233 default: handle = Cursors.Default.handle; break;
3235 SetCursor(msg.HWnd, handle);
3243 internal override void DestroyCaret(IntPtr handle) {
3244 if (Caret.Hwnd == handle) {
3245 if (Caret.Visible) {
3249 if (Caret.gc != IntPtr.Zero) {
3250 XFreeGC(DisplayHandle, Caret.gc);
3251 Caret.gc = IntPtr.Zero;
3253 Caret.Hwnd = IntPtr.Zero;
3254 Caret.Visible = false;
3259 internal override void DestroyCursor(IntPtr cursor) {
3261 XFreeCursor(DisplayHandle, cursor);
3265 internal override void DestroyWindow(IntPtr handle) {
3268 hwnd = Hwnd.ObjectFromHandle(handle);
3271 #if DriverDebug || DriverDebugDestroy
3272 Console.WriteLine("window {0:X} already destroyed", handle.ToInt32());
3277 #if DriverDebug || DriverDebugDestroy
3278 Console.WriteLine("Destroying window {0}", XplatUI.Window(hwnd.client_window));
3281 SendParentNotify (hwnd.Handle, Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
3283 CleanupCachedWindows (hwnd);
3285 ArrayList windows = new ArrayList ();
3287 AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
3290 foreach (Hwnd h in windows) {
3291 SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
3296 if (hwnd.whole_window != IntPtr.Zero) {
3297 #if DriverDebug || DriverDebugDestroy
3298 Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32());
3300 Keyboard.DestroyICForWindow (hwnd.whole_window);
3301 XDestroyWindow(DisplayHandle, hwnd.whole_window);
3303 else if (hwnd.client_window != IntPtr.Zero) {
3304 #if DriverDebug || DriverDebugDestroy
3305 Console.WriteLine ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32());
3307 Keyboard.DestroyICForWindow (hwnd.client_window);
3308 XDestroyWindow(DisplayHandle, hwnd.client_window);
3314 internal override IntPtr DispatchMessage(ref MSG msg) {
3315 return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
3318 IntPtr GetReversibleScreenGC (Color backColor)
3320 XGCValues gc_values;
3324 XColor xcolor = new XColor();
3325 xcolor.red = (ushort)(backColor.R * 257);
3326 xcolor.green = (ushort)(backColor.G * 257);
3327 xcolor.blue = (ushort)(backColor.B * 257);
3328 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3329 pixel = (uint)xcolor.pixel.ToInt32();
3332 gc_values = new XGCValues();
3334 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
3335 gc_values.foreground = (IntPtr)pixel;
3337 gc = XCreateGC(DisplayHandle, RootWindow, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
3338 XSetForeground(DisplayHandle, gc, (UIntPtr)pixel);
3339 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
3344 IntPtr GetReversibleControlGC (Control control, int line_width)
3346 XGCValues gc_values;
3349 gc_values = new XGCValues();
3351 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
3352 gc_values.line_width = line_width;
3353 gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo);
3355 // This logic will give us true rubber bands: (libsx, SANE_XOR)
3356 //mask = foreground ^ background;
3357 //XSetForeground(DisplayHandle, gc, 0xffffffff);
3358 //XSetBackground(DisplayHandle, gc, background);
3359 //XSetFunction(DisplayHandle, gc, GXxor);
3360 //XSetPlaneMask(DisplayHandle, gc, mask);
3363 gc = XCreateGC(DisplayHandle, control.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values);
3367 XColor xcolor = new XColor();
3369 xcolor.red = (ushort)(control.ForeColor.R * 257);
3370 xcolor.green = (ushort)(control.ForeColor.G * 257);
3371 xcolor.blue = (ushort)(control.ForeColor.B * 257);
3372 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3373 foreground = (uint)xcolor.pixel.ToInt32();
3375 xcolor.red = (ushort)(control.BackColor.R * 257);
3376 xcolor.green = (ushort)(control.BackColor.G * 257);
3377 xcolor.blue = (ushort)(control.BackColor.B * 257);
3378 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3379 background = (uint)xcolor.pixel.ToInt32();
3381 uint mask = foreground ^ background;
3383 XSetForeground(DisplayHandle, gc, (UIntPtr)0xffffffff);
3384 XSetBackground(DisplayHandle, gc, (UIntPtr)background);
3385 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
3386 XSetPlaneMask(DisplayHandle, gc, (IntPtr)mask);
3391 internal override void DrawReversibleLine(Point start, Point end, Color backColor)
3393 if (backColor.GetBrightness() < 0.5)
3394 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
3396 IntPtr gc = GetReversibleScreenGC (backColor);
3398 XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y);
3400 XFreeGC(DisplayHandle, gc);
3403 internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
3405 if (backColor.GetBrightness() < 0.5)
3406 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
3408 IntPtr gc = GetReversibleScreenGC (backColor);
3410 if (rectangle.Width < 0) {
3411 rectangle.X += rectangle.Width;
3412 rectangle.Width = -rectangle.Width;
3414 if (rectangle.Height < 0) {
3415 rectangle.Y += rectangle.Height;
3416 rectangle.Height = -rectangle.Height;
3420 GCLineStyle line_style = GCLineStyle.LineSolid;
3421 GCCapStyle cap_style = GCCapStyle.CapButt;
3422 GCJoinStyle join_style = GCJoinStyle.JoinMiter;
3425 case FrameStyle.Dashed:
3426 line_style = GCLineStyle.LineOnOffDash;
3428 case FrameStyle.Thick:
3433 XSetLineAttributes (DisplayHandle, gc, line_width, line_style, cap_style, join_style);
3435 XDrawRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3437 XFreeGC(DisplayHandle, gc);
3440 internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
3442 if (backColor.GetBrightness() < 0.5)
3443 backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
3445 IntPtr gc = GetReversibleScreenGC (backColor);
3447 if (rectangle.Width < 0) {
3448 rectangle.X += rectangle.Width;
3449 rectangle.Width = -rectangle.Width;
3451 if (rectangle.Height < 0) {
3452 rectangle.Y += rectangle.Height;
3453 rectangle.Height = -rectangle.Height;
3455 XFillRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3457 XFreeGC(DisplayHandle, gc);
3460 internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width)
3463 Control control = Control.FromHandle(handle);
3465 gc = GetReversibleControlGC (control, line_width);
3467 if ((rect.Width > 0) && (rect.Height > 0)) {
3468 XDrawRectangle(DisplayHandle, control.Handle, gc, rect.Left, rect.Top, rect.Width, rect.Height);
3470 if (rect.Width > 0) {
3471 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.Right, rect.Y);
3473 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.X, rect.Bottom);
3476 XFreeGC(DisplayHandle, gc);
3479 internal override void DoEvents() {
3480 MSG msg = new MSG ();
3483 if (OverrideCursorHandle != IntPtr.Zero) {
3484 OverrideCursorHandle = IntPtr.Zero;
3487 queue = ThreadQueue(Thread.CurrentThread);
3489 queue.DispatchIdle = false;
3491 while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
3492 TranslateMessage (ref msg);
3493 DispatchMessage (ref msg);
3496 queue.DispatchIdle = true;
3499 internal override void EnableWindow(IntPtr handle, bool Enable) {
3502 hwnd = Hwnd.ObjectFromHandle(handle);
3504 hwnd.Enabled = Enable;
3508 internal override void EndLoop(Thread thread) {
3509 // This is where we one day will shut down the loop for the thread
3512 internal override IntPtr GetActive() {
3517 IntPtr prop = IntPtr.Zero;
3518 IntPtr active = IntPtr.Zero;
3520 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);
3521 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
3522 active = (IntPtr)Marshal.ReadInt32(prop);
3526 if (active != IntPtr.Zero) {
3529 hwnd = Hwnd.GetObjectFromWindow(active);
3531 active = hwnd.Handle;
3533 active = IntPtr.Zero;
3539 internal override Region GetClipRegion(IntPtr handle) {
3542 hwnd = Hwnd.ObjectFromHandle(handle);
3544 return hwnd.UserClip;
3550 internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) {
3557 internal override void GetDisplaySize(out Size size) {
3558 XWindowAttributes attributes=new XWindowAttributes();
3561 // FIXME - use _NET_WM messages instead?
3562 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
3565 size = new Size(attributes.width, attributes.height);
3568 internal override SizeF GetAutoScaleSize(Font font) {
3571 string magic_string = "The quick brown fox jumped over the lazy dog.";
3572 double magic_number = 44.549996948242189;
3574 g = Graphics.FromHwnd(FosterParent);
3576 width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
3577 return new SizeF(width, font.Height);
3580 internal override IntPtr GetParent(IntPtr handle) {
3583 hwnd = Hwnd.ObjectFromHandle(handle);
3584 if (hwnd != null && hwnd.parent != null) {
3585 return hwnd.parent.Handle;
3590 // This is a nop on win32 and x11
3591 internal override IntPtr GetPreviousWindow(IntPtr handle) {
3595 internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
3605 if (handle != IntPtr.Zero) {
3606 use_handle = Hwnd.ObjectFromHandle(handle).client_window;
3608 use_handle = RootWindow;
3612 QueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
3615 if (handle != IntPtr.Zero) {
3624 internal override IntPtr GetFocus() {
3629 internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) {
3630 FontFamily ff = font.FontFamily;
3631 ascent = ff.GetCellAscent (font.Style);
3632 descent = ff.GetCellDescent (font.Style);
3636 internal override Point GetMenuOrigin(IntPtr handle) {
3639 hwnd = Hwnd.ObjectFromHandle(handle);
3642 return hwnd.MenuOrigin;
3647 [MonoTODO("Implement filtering")]
3648 internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) {
3655 if (((XEventQueue)queue_id).Count > 0) {
3656 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3658 UpdateMessageQueue ((XEventQueue)queue_id);
3660 if (((XEventQueue)queue_id).Count > 0) {
3661 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3662 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
3663 xevent = ((XEventQueue)queue_id).Paint.Dequeue();
3665 msg.hwnd= IntPtr.Zero;
3666 msg.message = Msg.WM_ENTERIDLE;
3671 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
3673 // Handle messages for windows that are already or are about to be destroyed.
3675 // we need a special block for this because unless we remove the hwnd from the paint
3676 // queue it will always stay there (since we don't handle the expose), and we'll
3677 // effectively loop infinitely trying to repaint a non-existant window.
3678 if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
3679 hwnd.expose_pending = hwnd.nc_expose_pending = false;
3680 hwnd.Queue.Paint.Remove (hwnd);
3681 goto ProcessNextMessage;
3684 // We need to make sure we only allow DestroyNotify events through for zombie
3685 // hwnds, since much of the event handling code makes requests using the hwnd's
3686 // client_window, and that'll result in BadWindow errors if there's some lag
3687 // between the XDestroyWindow call and the DestroyNotify event.
3688 if (hwnd == null || hwnd.zombie && xevent.AnyEvent.type != XEventName.ClientMessage) {
3689 #if DriverDebug || DriverDebugDestroy
3690 Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
3692 goto ProcessNextMessage;
3695 if (hwnd.client_window == xevent.AnyEvent.window) {
3697 //Console.WriteLine("Client message {1}, sending to window {0:X}", msg.hwnd.ToInt32(), xevent.type);
3700 //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32());
3703 msg.hwnd = hwnd.Handle;
3705 // Windows sends WM_ENTERSIZEMOVE when a form resize/move operation starts and WM_EXITSIZEMOVE
3706 // when it is done. The problem in X11 is that there is no concept of start-end of a moving/sizing.
3707 // Configure events ("this window has resized/moved") are sent for each step of the resize. We send a
3708 // WM_ENTERSIZEMOVE when we get the first Configure event. The problem is the WM_EXITSIZEMOVE.
3710 // - There is no way for us to know which is the last Configure event. We can't traverse the events
3711 // queue, because the next configure event might not be pending yet.
3712 // - We can't get ButtonPress/Release events for the window decorations, because they are not part
3713 // of the window(s) we manage.
3714 // - We can't rely on the mouse state to change to "up" before the last Configure event. It doesn't.
3716 // We are almost 100% guaranteed to get another event (e.g Expose or other), but we can't know for sure
3717 // which, so we have here to check if the mouse buttons state is "up" and send the WM_EXITSIZEMOVE
3719 if (hwnd.resizing_or_moving) {
3720 int root_x, root_y, win_x, win_y, keys_buttons;
3722 XQueryPointer (DisplayHandle, hwnd.Handle, out root, out child, out root_x, out root_y,
3723 out win_x, out win_y, out keys_buttons);
3724 if ((keys_buttons & (int)MouseKeyMasks.Button1Mask) == 0 &&
3725 (keys_buttons & (int)MouseKeyMasks.Button2Mask) == 0 &&
3726 (keys_buttons & (int)MouseKeyMasks.Button3Mask) == 0) {
3727 hwnd.resizing_or_moving = false;
3728 SendMessage (hwnd.Handle, Msg.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
3733 // If you add a new event to this switch make sure to add it in
3734 // UpdateMessage also unless it is not coming through the X event system.
3736 switch(xevent.type) {
3737 case XEventName.KeyPress: {
3738 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3740 // F1 key special case - WM_HELP sending
3741 if (msg.wParam == (IntPtr)VirtualKeys.VK_F1 || msg.wParam == (IntPtr)VirtualKeys.VK_HELP) {
3742 // Send the keypress message first
3743 NativeWindow.WndProc (hwnd.client_window, msg.message, msg.wParam, msg.lParam);
3746 HELPINFO helpInfo = new HELPINFO ();
3747 GetCursorPos (IntPtr.Zero, out helpInfo.MousePos.x, out helpInfo.MousePos.y);
3748 IntPtr helpInfoPtr = Marshal.AllocHGlobal (Marshal.SizeOf (helpInfo));
3749 Marshal.StructureToPtr (helpInfo, helpInfoPtr, true);
3750 NativeWindow.WndProc (hwnd.client_window, Msg.WM_HELP, IntPtr.Zero, helpInfoPtr);
3751 Marshal.FreeHGlobal (helpInfoPtr);
3753 goto ProcessNextMessage;
3758 case XEventName.KeyRelease: {
3759 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3763 case XEventName.ButtonPress: {
3764 switch(xevent.ButtonEvent.button) {
3766 MouseState |= MouseButtons.Left;
3768 msg.message = Msg.WM_LBUTTONDOWN;
3769 msg.wParam = GetMousewParam (0);
3771 msg.message = Msg.WM_NCLBUTTONDOWN;
3772 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3773 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3779 MouseState |= MouseButtons.Middle;
3781 msg.message = Msg.WM_MBUTTONDOWN;
3782 msg.wParam = GetMousewParam (0);
3784 msg.message = Msg.WM_NCMBUTTONDOWN;
3785 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3786 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3792 MouseState |= MouseButtons.Right;
3794 msg.message = Msg.WM_RBUTTONDOWN;
3795 msg.wParam = GetMousewParam (0);
3797 msg.message = Msg.WM_NCRBUTTONDOWN;
3798 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3799 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3805 msg.hwnd = FocusWindow;
3806 msg.message=Msg.WM_MOUSEWHEEL;
3807 msg.wParam=GetMousewParam(120);
3812 msg.hwnd = FocusWindow;
3813 msg.message=Msg.WM_MOUSEWHEEL;
3814 msg.wParam=GetMousewParam(-120);
3820 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3821 mouse_position.X = xevent.ButtonEvent.x;
3822 mouse_position.Y = xevent.ButtonEvent.y;
3824 if (!hwnd.Enabled) {
3827 msg.hwnd = hwnd.EnabledHwnd;
3828 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);
3829 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3832 if (Grab.Hwnd != IntPtr.Zero) {
3833 msg.hwnd = Grab.Hwnd;
3836 if (ClickPending.Pending && ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
3837 // Looks like a genuine double click, clicked twice on the same spot with the same keys
3838 switch(xevent.ButtonEvent.button) {
3840 msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
3845 msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
3850 msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
3854 ClickPending.Pending = false;
3856 ClickPending.Pending = true;
3857 ClickPending.Hwnd = msg.hwnd;
3858 ClickPending.Message = msg.message;
3859 ClickPending.wParam = msg.wParam;
3860 ClickPending.lParam = msg.lParam;
3861 ClickPending.Time = (long)xevent.ButtonEvent.time;
3864 if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
3865 SendParentNotify(msg.hwnd, msg.message, mouse_position.X, mouse_position.Y);
3871 case XEventName.ButtonRelease: {
3872 switch(xevent.ButtonEvent.button) {
3875 msg.message = Msg.WM_LBUTTONUP;
3877 msg.message = Msg.WM_NCLBUTTONUP;
3878 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3879 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3881 MouseState &= ~MouseButtons.Left;
3882 msg.wParam = GetMousewParam (0);
3888 msg.message = Msg.WM_MBUTTONUP;
3890 msg.message = Msg.WM_NCMBUTTONUP;
3891 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3892 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3894 MouseState &= ~MouseButtons.Middle;
3895 msg.wParam = GetMousewParam (0);
3901 msg.message = Msg.WM_RBUTTONUP;
3903 msg.message = Msg.WM_NCRBUTTONUP;
3904 msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
3905 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3907 MouseState &= ~MouseButtons.Right;
3908 msg.wParam = GetMousewParam (0);
3913 goto ProcessNextMessage;
3917 goto ProcessNextMessage;
3921 if (!hwnd.Enabled) {
3924 msg.hwnd = hwnd.EnabledHwnd;
3925 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);
3926 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3929 if (Grab.Hwnd != IntPtr.Zero) {
3930 msg.hwnd = Grab.Hwnd;
3933 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3934 mouse_position.X = xevent.ButtonEvent.x;
3935 mouse_position.Y = xevent.ButtonEvent.y;
3937 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
3938 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
3939 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
3940 if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
3941 XEvent motionEvent = new XEvent ();
3942 motionEvent.type = XEventName.MotionNotify;
3943 motionEvent.MotionEvent.display = DisplayHandle;
3944 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
3945 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
3946 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
3947 hwnd.Queue.EnqueueLocked (motionEvent);
3952 case XEventName.MotionNotify: {
3954 #if DriverDebugExtra
3955 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);
3958 if (Grab.Hwnd != IntPtr.Zero) {
3959 msg.hwnd = Grab.Hwnd;
3962 NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
3966 if (xevent.MotionEvent.is_hint != 0)
3970 XQueryPointer (DisplayHandle, xevent.AnyEvent.window,
3971 out root, out child,
3972 out xevent.MotionEvent.x_root,
3973 out xevent.MotionEvent.y_root,
3974 out xevent.MotionEvent.x,
3975 out xevent.MotionEvent.y, out mask);
3978 msg.message = Msg.WM_MOUSEMOVE;
3979 msg.wParam = GetMousewParam(0);
3980 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
3982 if (!hwnd.Enabled) {
3985 msg.hwnd = hwnd.EnabledHwnd;
3986 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);
3987 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3990 mouse_position.X = xevent.MotionEvent.x;
3991 mouse_position.Y = xevent.MotionEvent.y;
3993 if ((HoverState.Timer.Enabled) &&
3994 (((mouse_position.X + HoverState.Size.Width) < HoverState.X) ||
3995 ((mouse_position.X - HoverState.Size.Width) > HoverState.X) ||
3996 ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) ||
3997 ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) {
3998 HoverState.Timer.Stop();
3999 HoverState.Timer.Start();
4000 HoverState.X = mouse_position.X;
4001 HoverState.Y = mouse_position.Y;
4009 #if DriverDebugExtra
4010 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);
4012 msg.message = Msg.WM_NCMOUSEMOVE;
4014 if (!hwnd.Enabled) {
4015 msg.hwnd = hwnd.EnabledHwnd;
4016 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);
4017 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
4020 ht = NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y);
4021 NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
4023 mouse_position.X = xevent.MotionEvent.x;
4024 mouse_position.Y = xevent.MotionEvent.y;
4030 case XEventName.EnterNotify: {
4031 if (!hwnd.Enabled) {
4032 goto ProcessNextMessage;
4034 if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || xevent.AnyEvent.window != hwnd.client_window) {
4035 goto ProcessNextMessage;
4037 if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) { // Pseudo motion caused by grabbing
4038 if (LastPointerWindow == xevent.AnyEvent.window)
4039 goto ProcessNextMessage;
4041 if (LastPointerWindow != IntPtr.Zero) {
4042 Point enter_loc = new Point (xevent.ButtonEvent.x, xevent.ButtonEvent.y);
4044 // We need this due to EnterNotify being fired on all the parent controls
4045 // of the Control being grabbed, and obviously in that scenario we are not
4046 // actuallty entering them
4047 Control ctrl = Control.FromHandle (hwnd.client_window);
4048 foreach (Control child_control in ctrl.Controls.GetAllControls ())
4049 if (child_control.Bounds.Contains (enter_loc))
4050 goto ProcessNextMessage;
4052 // A MouseLeave/LeaveNotify event is sent to the previous window
4053 // until the mouse is ungrabbed, not when actually leaving its bounds
4054 int x = xevent.CrossingEvent.x_root;
4055 int y = xevent.CrossingEvent.y_root;
4056 ScreenToClient (LastPointerWindow, ref x, ref y);
4058 XEvent leaveEvent = new XEvent ();
4059 leaveEvent.type = XEventName.LeaveNotify;
4060 leaveEvent.CrossingEvent.display = DisplayHandle;
4061 leaveEvent.CrossingEvent.window = LastPointerWindow;
4062 leaveEvent.CrossingEvent.x = x;
4063 leaveEvent.CrossingEvent.y = y;
4064 leaveEvent.CrossingEvent.mode = NotifyMode.NotifyNormal;
4065 Hwnd last_pointer_hwnd = Hwnd.ObjectFromHandle (LastPointerWindow);
4066 last_pointer_hwnd.Queue.EnqueueLocked (leaveEvent);
4070 LastPointerWindow = xevent.AnyEvent.window;
4072 msg.message = Msg.WM_MOUSE_ENTER;
4073 HoverState.X = xevent.CrossingEvent.x;
4074 HoverState.Y = xevent.CrossingEvent.y;
4075 HoverState.Timer.Enabled = true;
4076 HoverState.Window = xevent.CrossingEvent.window;
4078 // Win32 sends a WM_MOUSEMOVE after mouse enter
4079 XEvent motionEvent = new XEvent ();
4080 motionEvent.type = XEventName.MotionNotify;
4081 motionEvent.MotionEvent.display = DisplayHandle;
4082 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
4083 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
4084 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
4085 hwnd.Queue.EnqueueLocked (motionEvent);
4089 case XEventName.LeaveNotify: {
4090 if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) {
4091 WindowUngrabbed (hwnd.Handle);
4092 goto ProcessNextMessage;
4094 if (!hwnd.Enabled) {
4095 goto ProcessNextMessage;
4097 if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
4098 goto ProcessNextMessage;
4100 // If a grab is taking place, ignore it - we handle it in EnterNotify
4101 if (Grab.Hwnd != IntPtr.Zero)
4102 goto ProcessNextMessage;
4104 // Reset the cursor explicitly on X11.
4105 // X11 remembers the last set cursor for the window and in cases where
4106 // the control won't get a WM_SETCURSOR X11 will restore the last
4107 // known cursor, which we don't want.
4109 SetCursor (hwnd.client_window, IntPtr.Zero);
4111 msg.message=Msg.WM_MOUSELEAVE;
4112 HoverState.Timer.Enabled = false;
4113 HoverState.Window = IntPtr.Zero;
4118 case XEventName.CreateNotify: {
4119 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
4120 msg.message = WM_CREATE;
4121 // Set up CreateStruct
4123 goto ProcessNextMessage;
4130 case XEventName.ReparentNotify: {
4131 if (hwnd.parent == null) { // Toplevel
4132 if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) {
4133 hwnd.Reparented = true;
4135 // The location given by the event is not reliable between different wm's,
4136 // so use an alternative way of getting it.
4137 Point location = GetTopLevelWindowLocation (hwnd);
4138 hwnd.X = location.X;
4139 hwnd.Y = location.Y;
4141 if (hwnd.opacity != 0xffffffff) {
4144 opacity = (IntPtr)(Int32)hwnd.opacity;
4145 XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
4147 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
4148 goto ProcessNextMessage;
4150 hwnd.Reparented = false;
4151 goto ProcessNextMessage;
4154 goto ProcessNextMessage;
4157 case XEventName.ConfigureNotify: {
4158 if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4159 #if DriverDebugExtra
4160 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);
4163 lock (hwnd.configure_lock) {
4164 Form form = Control.FromHandle (hwnd.client_window) as Form;
4165 if (form != null && !hwnd.resizing_or_moving) {
4166 if (hwnd.x != form.Bounds.X || hwnd.y != form.Bounds.Y) {
4167 SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_MOVE, IntPtr.Zero);
4168 hwnd.resizing_or_moving = true;
4169 } else if (hwnd.width != form.Bounds.Width || hwnd.height != form.Bounds.Height) {
4170 SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_SIZE, IntPtr.Zero);
4171 hwnd.resizing_or_moving = true;
4173 if (hwnd.resizing_or_moving)
4174 SendMessage (form.Handle, Msg.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero);
4177 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4178 hwnd.configure_pending = false;
4180 // We need to adjust our client window to track the resize of whole_window
4181 if (hwnd.whole_window != hwnd.client_window)
4182 PerformNCCalc(hwnd);
4185 goto ProcessNextMessage;
4188 case XEventName.FocusIn: {
4189 // We received focus. We use X11 focus only to know if the app window does or does not have focus
4190 // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
4191 // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
4192 // about it having focus again
4193 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4194 goto ProcessNextMessage;
4197 if (FocusWindow == IntPtr.Zero) {
4198 Control c = Control.FromHandle (hwnd.client_window);
4200 goto ProcessNextMessage;
4201 Form form = c.FindForm ();
4203 goto ProcessNextMessage;
4204 if (ActiveWindow != form.Handle) {
4205 ActiveWindow = form.Handle;
4206 SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
4208 goto ProcessNextMessage;
4210 SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
4211 Keyboard.FocusIn (FocusWindow);
4212 goto ProcessNextMessage;
4215 case XEventName.FocusOut: {
4216 // Se the comment for our FocusIn handler
4217 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4218 goto ProcessNextMessage;
4221 while (Keyboard.ResetKeyState(FocusWindow, ref msg)) {
4222 SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam);
4225 Keyboard.FocusOut(hwnd.client_window);
4226 SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
4227 goto ProcessNextMessage;
4230 case XEventName.MapNotify: {
4231 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4233 msg.message = Msg.WM_SHOWWINDOW;
4234 msg.wParam = (IntPtr) 1;
4235 // XXX we're missing the lParam..
4238 goto ProcessNextMessage;
4241 case XEventName.UnmapNotify: {
4242 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4243 hwnd.mapped = false;
4244 msg.message = Msg.WM_SHOWWINDOW;
4245 msg.wParam = (IntPtr) 0;
4246 // XXX we're missing the lParam..
4249 goto ProcessNextMessage;
4252 case XEventName.Expose: {
4255 hwnd.expose_pending = false;
4257 hwnd.nc_expose_pending = false;
4259 goto ProcessNextMessage;
4263 if (!hwnd.expose_pending) {
4264 goto ProcessNextMessage;
4267 if (!hwnd.nc_expose_pending) {
4268 goto ProcessNextMessage;
4271 switch (hwnd.border_style) {
4272 case FormBorderStyle.Fixed3D: {
4275 g = Graphics.FromHwnd(hwnd.whole_window);
4276 if (hwnd.border_static)
4277 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter);
4279 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken);
4284 case FormBorderStyle.FixedSingle: {
4287 g = Graphics.FromHwnd(hwnd.whole_window);
4288 ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
4293 #if DriverDebugExtra
4294 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);
4297 Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
4298 Region region = new Region (rect);
4299 IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
4300 msg.message = Msg.WM_NCPAINT;
4301 msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
4302 msg.refobject = region;
4305 #if DriverDebugExtra
4306 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);
4308 if (Caret.Visible == true) {
4309 Caret.Paused = true;
4313 if (Caret.Visible == true) {
4315 Caret.Paused = false;
4317 msg.message = Msg.WM_PAINT;
4321 case XEventName.DestroyNotify: {
4323 // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
4324 hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
4326 // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
4327 if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) {
4328 CleanupCachedWindows (hwnd);
4330 #if DriverDebugDestroy
4331 Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window));
4334 msg.hwnd = hwnd.client_window;
4335 msg.message=Msg.WM_DESTROY;
4338 goto ProcessNextMessage;
4344 case XEventName.ClientMessage: {
4345 if (Dnd.HandleClientMessage (ref xevent)) {
4346 goto ProcessNextMessage;
4349 if (xevent.ClientMessageEvent.message_type == AsyncAtom) {
4350 XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
4351 goto ProcessNextMessage;
4354 if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
4355 msg.message = Msg.WM_MOUSEHOVER;
4356 msg.wParam = GetMousewParam(0);
4357 msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
4361 if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
4362 msg.hwnd = xevent.ClientMessageEvent.ptr1;
4363 msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
4364 msg.wParam = xevent.ClientMessageEvent.ptr3;
4365 msg.lParam = xevent.ClientMessageEvent.ptr4;
4366 if (msg.message == (Msg)Msg.WM_QUIT)
4372 if (xevent.ClientMessageEvent.message_type == _XEMBED) {
4373 #if DriverDebugXEmbed
4374 Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
4377 if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
4378 XSizeHints hints = new XSizeHints();
4381 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
4383 hwnd.width = hints.max_width;
4384 hwnd.height = hints.max_height;
4385 hwnd.ClientRect = Rectangle.Empty;
4386 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4390 if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) {
4391 if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) {
4392 SendMessage (msg.hwnd, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_CLOSE, IntPtr.Zero);
4393 msg.message = Msg.WM_CLOSE;
4397 // We should not get this, but I'll leave the code in case we need it in the future
4398 if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) {
4399 goto ProcessNextMessage;
4402 goto ProcessNextMessage;
4406 goto ProcessNextMessage;
4413 private HitTest NCHitTest (Hwnd hwnd, int x, int y)
4415 // The hit test is sent in screen coordinates
4417 int screen_x, screen_y;
4418 XTranslateCoordinates (DisplayHandle, hwnd.WholeWindow, RootWindow, x, y, out screen_x, out screen_y, out dummy);
4419 return (HitTest) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero,
4420 (IntPtr) (screen_y << 16 | screen_x & 0xFFFF));
4423 internal override bool GetText(IntPtr handle, out string text) {
4430 IntPtr prop = IntPtr.Zero;
4432 XGetWindowProperty(DisplayHandle, handle,
4433 _NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
4434 UNICODETEXT, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
4436 if ((long)nitems > 0 && prop != IntPtr.Zero) {
4437 text = Marshal.PtrToStringUni (prop, (int)nitems);
4442 // fallback on the non-_NET property
4445 textptr = IntPtr.Zero;
4447 XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr);
4448 if (textptr != IntPtr.Zero) {
4449 text = Marshal.PtrToStringAnsi(textptr);
4460 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) {
4463 hwnd = Hwnd.ObjectFromHandle(handle);
4469 height = hwnd.height;
4471 PerformNCCalc(hwnd);
4473 client_width = hwnd.ClientRect.Width;
4474 client_height = hwnd.ClientRect.Height;
4479 // Should we throw an exception or fail silently?
4480 // throw new ArgumentException("Called with an invalid window handle", "handle");
4490 internal override FormWindowState GetWindowState(IntPtr handle) {
4493 hwnd = Hwnd.ObjectFromHandle(handle);
4495 if (hwnd.cached_window_state == (FormWindowState)(-1))
4496 hwnd.cached_window_state = UpdateWindowState (handle);
4498 return hwnd.cached_window_state;
4501 private FormWindowState UpdateWindowState (IntPtr handle) {
4506 IntPtr prop = IntPtr.Zero;
4510 XWindowAttributes attributes;
4513 hwnd = Hwnd.ObjectFromHandle(handle);
4517 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);
4518 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
4519 for (int i = 0; i < (long)nitems; i++) {
4520 atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
4521 if ((atom == _NET_WM_STATE_MAXIMIZED_HORZ) || (atom == _NET_WM_STATE_MAXIMIZED_VERT)) {
4523 } else if (atom == _NET_WM_STATE_HIDDEN) {
4531 return FormWindowState.Minimized;
4532 } else if (maximized == 2) {
4533 return FormWindowState.Maximized;
4536 attributes = new XWindowAttributes();
4537 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4538 if (attributes.map_state == MapState.IsUnmapped) {
4539 return (FormWindowState)(-1);
4543 return FormWindowState.Normal;
4546 internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) {
4548 GrabConfined = Grab.Confined;
4549 GrabArea = Grab.Area;
4552 internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) {
4554 IntPtr confine_to_window;
4556 confine_to_window = IntPtr.Zero;
4558 if (confine_to_handle != IntPtr.Zero) {
4559 XWindowAttributes attributes = new XWindowAttributes();
4561 hwnd = Hwnd.ObjectFromHandle(confine_to_handle);
4564 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4566 Grab.Area.X = attributes.x;
4567 Grab.Area.Y = attributes.y;
4568 Grab.Area.Width = attributes.width;
4569 Grab.Area.Height = attributes.height;
4570 Grab.Confined = true;
4571 confine_to_window = hwnd.client_window;
4576 hwnd = Hwnd.ObjectFromHandle(handle);
4579 XGrabPointer(DisplayHandle, hwnd.client_window, false,
4580 EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
4581 EventMask.ButtonReleaseMask | EventMask.PointerMotionMask |
4582 EventMask.PointerMotionHintMask | EventMask.LeaveWindowMask,
4583 GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
4587 internal override void UngrabWindow(IntPtr hwnd) {
4589 XUngrabPointer(DisplayHandle, IntPtr.Zero);
4590 XFlush(DisplayHandle);
4592 WindowUngrabbed (hwnd);
4595 private void WindowUngrabbed (IntPtr hwnd) {
4596 bool was_grabbed = Grab.Hwnd != IntPtr.Zero;
4598 Grab.Hwnd = IntPtr.Zero;
4599 Grab.Confined = false;
4602 // lparam should be the handle to the window gaining the mouse capture,
4603 // but X doesn't seem to give us that information.
4604 // Also only generate WM_CAPTURECHANGED if the window actually was grabbed.
4605 // X will send a NotifyUngrab, but since it comes late sometimes we're
4606 // calling WindowUngrabbed directly from UngrabWindow in order to send
4607 // this WM right away.
4608 SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero);
4612 internal override void HandleException(Exception e) {
4613 StackTrace st = new StackTrace(e, true);
4614 Console.WriteLine("Exception '{0}'", e.Message+st.ToString());
4615 Console.WriteLine("{0}{1}", e.Message, st.ToString());
4618 internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
4621 hwnd = Hwnd.ObjectFromHandle(handle);
4624 AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height);
4626 AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height);
4630 internal override void InvalidateNC (IntPtr handle) {
4633 hwnd = Hwnd.ObjectFromHandle(handle);
4635 AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
4638 internal override bool IsEnabled(IntPtr handle) {
4639 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4640 return (hwnd != null && hwnd.Enabled);
4643 internal override bool IsVisible(IntPtr handle) {
4644 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4645 return (hwnd != null && hwnd.visible);
4648 internal override void KillTimer(Timer timer) {
4649 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
4651 if (queue == null) {
4652 // This isn't really an error, MS doesn't start the timer if
4653 // it has no assosciated queue. In this case, remove the timer
4654 // from the list of unattached timers (if it was enabled).
4655 lock (unattached_timer_list) {
4656 if (unattached_timer_list.Contains (timer))
4657 unattached_timer_list.Remove (timer);
4661 queue.timer_list.Remove (timer);
4664 internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) {
4670 hwnd = Hwnd.ObjectFromHandle(handle);
4673 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
4680 internal override void OverrideCursor(IntPtr cursor)
4682 if (Grab.Hwnd != IntPtr.Zero) {
4683 XChangeActivePointerGrab (DisplayHandle,
4684 EventMask.ButtonMotionMask |
4685 EventMask.PointerMotionMask |
4686 EventMask.PointerMotionHintMask |
4687 EventMask.ButtonPressMask |
4688 EventMask.ButtonReleaseMask,
4689 cursor, IntPtr.Zero);
4693 OverrideCursorHandle = cursor;
4696 internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) {
4697 PaintEventArgs paint_event;
4702 // handle (and paint_hwnd) refers to the window that is should be painted.
4703 // msg.HWnd (and hwnd) refers to the window that got the paint message.
4706 hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
4707 if (msg.HWnd == handle) {
4710 paint_hwnd = Hwnd.ObjectFromHandle (handle);
4713 if (Caret.Visible == true) {
4714 Caret.Paused = true;
4721 dc = Graphics.FromHwnd (paint_hwnd.client_window);
4723 Region clip_region = new Region ();
4724 clip_region.MakeEmpty();
4726 foreach (Rectangle r in hwnd.ClipRectangles) {
4727 clip_region.Union (r);
4730 if (hwnd.UserClip != null) {
4731 clip_region.Intersect(hwnd.UserClip);
4734 dc.Clip = clip_region;
4735 paint_event = new PaintEventArgs(dc, hwnd.Invalid);
4736 hwnd.expose_pending = false;
4738 hwnd.ClearInvalidArea();
4740 hwnd.drawing_stack.Push (paint_event);
4741 hwnd.drawing_stack.Push (dc);
4745 dc = Graphics.FromHwnd (paint_hwnd.whole_window);
4747 if (!hwnd.nc_invalid.IsEmpty) {
4748 dc.SetClip (hwnd.nc_invalid);
4749 paint_event = new PaintEventArgs(dc, hwnd.nc_invalid);
4751 paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height));
4753 hwnd.nc_expose_pending = false;
4755 hwnd.ClearNcInvalidArea ();
4757 hwnd.drawing_stack.Push (paint_event);
4758 hwnd.drawing_stack.Push (dc);
4764 internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) {
4767 hwnd = Hwnd.ObjectFromHandle (msg.HWnd);
4769 Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
4773 PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop();
4774 pe.SetGraphics (null);
4777 if (Caret.Visible == true) {
4779 Caret.Paused = false;
4783 [MonoTODO("Implement filtering and PM_NOREMOVE")]
4784 internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
4785 XEventQueue queue = (XEventQueue) queue_id;
4788 if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
4789 throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
4793 if (queue.Count > 0) {
4796 // Only call UpdateMessageQueue if real events are pending
4797 // otherwise we go to sleep on the socket
4798 if (XPending(DisplayHandle) != 0) {
4799 UpdateMessageQueue((XEventQueue)queue_id);
4801 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
4806 CheckTimers(queue.timer_list, DateTime.UtcNow);
4811 return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
4814 internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) {
4815 XEvent xevent = new XEvent ();
4816 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
4818 xevent.type = XEventName.ClientMessage;
4819 xevent.ClientMessageEvent.display = DisplayHandle;
4822 xevent.ClientMessageEvent.window = hwnd.whole_window;
4824 xevent.ClientMessageEvent.window = IntPtr.Zero;
4827 xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
4828 xevent.ClientMessageEvent.format = 32;
4829 xevent.ClientMessageEvent.ptr1 = handle;
4830 xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
4831 xevent.ClientMessageEvent.ptr3 = wparam;
4832 xevent.ClientMessageEvent.ptr4 = lparam;
4835 hwnd.Queue.EnqueueLocked (xevent);
4837 ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent);
4842 internal override void PostQuitMessage(int exitCode) {
4843 ApplicationContext ctx = Application.MWFThread.Current.Context;
4844 Form f = ctx != null ? ctx.MainForm : null;
4846 PostMessage (Application.MWFThread.Current.Context.MainForm.window.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4848 PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4849 XFlush(DisplayHandle);
4852 internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave)
4857 internal override void RequestNCRecalc(IntPtr handle) {
4860 hwnd = Hwnd.ObjectFromHandle(handle);
4866 PerformNCCalc(hwnd);
4867 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4868 InvalidateNC(handle);
4871 internal override void ResetMouseHover(IntPtr handle) {
4874 hwnd = Hwnd.ObjectFromHandle(handle);
4879 HoverState.Timer.Enabled = true;
4880 HoverState.X = mouse_position.X;
4881 HoverState.Y = mouse_position.Y;
4882 HoverState.Window = handle;
4886 internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) {
4892 hwnd = Hwnd.ObjectFromHandle(handle);
4895 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
4902 internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) {
4908 hwnd = Hwnd.ObjectFromHandle(handle);
4911 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
4914 Form form = Control.FromHandle (handle) as Form;
4915 if (form != null && form.window_manager != null) {
4916 dest_y_return -= form.window_manager.TitleBarHeight;
4923 bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg)
4925 return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) &&
4926 arg == xevent.GraphicsExposeEvent.drawable;
4929 delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg);
4931 void ProcessGraphicsExpose (Hwnd hwnd)
4933 XEvent xevent = new XEvent ();
4934 IntPtr handle = Hwnd.HandleFromObject (hwnd);
4935 EventPredicate predicate = GraphicsExposePredicate;
4938 XIfEvent (Display, ref xevent, predicate, handle);
4939 if (xevent.type != XEventName.GraphicsExpose)
4942 AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y,
4943 xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height);
4945 if (xevent.GraphicsExposeEvent.count == 0)
4950 internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
4953 XGCValues gc_values;
4955 hwnd = Hwnd.ObjectFromHandle(handle);
4957 Rectangle r = Rectangle.Intersect (hwnd.Invalid, area);
4959 /* We have an invalid area in the window we're scrolling.
4960 Adjust our stored invalid rectangle to to match the scrolled amount */
4975 if (area.Contains (hwnd.Invalid))
4976 hwnd.ClearInvalidArea ();
4977 hwnd.AddInvalidArea(r);
4980 gc_values = new XGCValues();
4982 if (with_children) {
4983 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
4986 gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
4988 Rectangle visible_rect = GetTotalVisibleArea (hwnd.client_window);
4989 visible_rect.Intersect (area);
4991 Rectangle dest_rect = visible_rect;
4992 dest_rect.Y += YAmount;
4993 dest_rect.X += XAmount;
4994 dest_rect.Intersect (area);
4996 Point src = new Point (dest_rect.X - XAmount, dest_rect.Y - YAmount);
4997 XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src.X, src.Y,
4998 dest_rect.Width, dest_rect.Height, dest_rect.X, dest_rect.Y);
5000 Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount);
5001 AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height);
5003 ProcessGraphicsExpose (hwnd);
5005 XFreeGC(DisplayHandle, gc);
5008 internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) {
5012 hwnd = Hwnd.GetObjectFromWindow(handle);
5014 rect = hwnd.ClientRect;
5017 ScrollWindow(handle, rect, XAmount, YAmount, with_children);
5020 Rectangle GetDirtyArea (Rectangle total_area, Rectangle valid_area, int XAmount, int YAmount)
5022 Rectangle dirty_area = total_area;
5025 dirty_area.Height -= valid_area.Height;
5026 else if (YAmount < 0) {
5027 dirty_area.Height -= valid_area.Height;
5028 dirty_area.Y += valid_area.Height;
5032 dirty_area.Width -= valid_area.Width;
5033 else if (XAmount < 0) {
5034 dirty_area.Width -= valid_area.Width;
5035 dirty_area.X += valid_area.Width;
5041 Rectangle GetTotalVisibleArea (IntPtr handle)
5043 Control c = Control.FromHandle (handle);
5045 Rectangle visible_area = c.ClientRectangle;
5046 visible_area.Location = c.PointToScreen (Point.Empty);
5048 for (Control parent = c.Parent; parent != null; parent = parent.Parent) {
5049 if (!parent.IsHandleCreated || !parent.Visible)
5050 return visible_area; // Non visible, not need to finish computations
5052 Rectangle r = parent.ClientRectangle;
5053 r.Location = parent.PointToScreen (Point.Empty);
5055 visible_area.Intersect (r);
5058 visible_area.Location = c.PointToClient (visible_area.Location);
5059 return visible_area;
5062 internal override void SendAsyncMethod (AsyncMethodData method) {
5064 XEvent xevent = new XEvent ();
5066 hwnd = Hwnd.ObjectFromHandle(method.Handle);
5068 xevent.type = XEventName.ClientMessage;
5069 xevent.ClientMessageEvent.display = DisplayHandle;
5070 xevent.ClientMessageEvent.window = method.Handle;
5071 xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
5072 xevent.ClientMessageEvent.format = 32;
5073 xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
5075 hwnd.Queue.EnqueueLocked (xevent);
5080 delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
5082 internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
5085 h = Hwnd.ObjectFromHandle(hwnd);
5087 if (h != null && h.queue != ThreadQueue (Thread.CurrentThread)) {
5088 AsyncMethodResult result;
5089 AsyncMethodData data;
5091 result = new AsyncMethodResult ();
5092 data = new AsyncMethodData ();
5095 data.Method = new WndProcDelegate (NativeWindow.WndProc);
5096 data.Args = new object[] { hwnd, message, wParam, lParam };
5097 data.Result = result;
5099 SendAsyncMethod (data);
5100 #if DriverDebug || DriverDebugThreads
5101 Console.WriteLine ("Sending {0} message across.", message);
5106 return NativeWindow.WndProc(hwnd, message, wParam, lParam);
5109 internal override int SendInput(IntPtr handle, Queue keys) {
5110 if (handle == IntPtr.Zero)
5113 int count = keys.Count;
5114 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5116 while (keys.Count > 0) {
5118 MSG msg = (MSG)keys.Dequeue();
5120 XEvent xevent = new XEvent ();
5122 xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
5123 xevent.KeyEvent.display = DisplayHandle;
5126 xevent.KeyEvent.window = hwnd.whole_window;
5128 xevent.KeyEvent.window = IntPtr.Zero;
5131 xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
5133 hwnd.Queue.EnqueueLocked (xevent);
5138 internal override void SetAllowDrop (IntPtr handle, bool value)
5140 // We allow drop on all windows
5143 internal override DragDropEffects StartDrag (IntPtr handle, object data,
5144 DragDropEffects allowed_effects)
5146 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
5149 throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
5151 return Dnd.StartDrag (hwnd.client_window, data, allowed_effects);
5154 internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
5155 Form form = Control.FromHandle (handle) as Form;
5156 if (form != null && form.window_manager == null) {
5157 CreateParams cp = form.GetCreateParams ();
5158 if (border_style == FormBorderStyle.FixedToolWindow ||
5159 border_style == FormBorderStyle.SizableToolWindow ||
5160 cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
5161 form.window_manager = new ToolWindowManager (form);
5165 RequestNCRecalc(handle);
5168 internal override void SetCaretPos(IntPtr handle, int x, int y) {
5169 if (Caret.Hwnd == handle) {
5176 Keyboard.SetCaretPos (Caret, handle, x, y);
5178 if (Caret.Visible == true) {
5180 Caret.Timer.Start();
5185 internal override void SetClipRegion(IntPtr handle, Region region) {
5188 hwnd = Hwnd.ObjectFromHandle(handle);
5193 hwnd.UserClip = region;
5196 internal override void SetCursor(IntPtr handle, IntPtr cursor) {
5199 if (OverrideCursorHandle == IntPtr.Zero) {
5200 if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
5204 LastCursorHandle = cursor;
5205 LastCursorWindow = handle;
5207 hwnd = Hwnd.ObjectFromHandle(handle);
5209 if (cursor != IntPtr.Zero) {
5210 XDefineCursor(DisplayHandle, hwnd.whole_window, cursor);
5212 XUndefineCursor(DisplayHandle, hwnd.whole_window);
5214 XFlush(DisplayHandle);
5219 hwnd = Hwnd.ObjectFromHandle(handle);
5221 XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
5225 private void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child,
5226 out int root_x, out int root_y, out int child_x, out int child_y,
5229 /* this code was written with the help of
5230 glance at gdk. I never would have realized we
5231 needed a loop in order to traverse down in the
5232 hierarchy. I would have assumed you'd get the
5233 most deeply nested child and have to do
5234 XQueryTree to move back up the hierarchy..
5235 stupid me, of course. */
5238 XGrabServer (display);
5240 XQueryPointer(display, w, out root, out c,
5241 out root_x, out root_y, out child_x, out child_y,
5247 IntPtr child_last = IntPtr.Zero;
5248 while (c != IntPtr.Zero) {
5250 XQueryPointer(display, c, out root, out c,
5251 out root_x, out root_y, out child_x, out child_y,
5254 XUngrabServer (display);
5260 internal override void SetCursorPos(IntPtr handle, int x, int y) {
5261 if (handle == IntPtr.Zero) {
5264 int root_x, root_y, child_x, child_y, mask;
5267 * QueryPointer before warping
5268 * because if the warp is on
5269 * the RootWindow, the x/y are
5270 * relative to the current
5273 QueryPointer (DisplayHandle, RootWindow,
5276 out root_x, out root_y,
5277 out child_x, out child_y,
5280 XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
5282 XFlush (DisplayHandle);
5284 /* then we need to a
5285 * QueryPointer after warping
5286 * to manually generate a
5287 * motion event for the window
5290 QueryPointer (DisplayHandle, RootWindow,
5293 out root_x, out root_y,
5294 out child_x, out child_y,
5297 Hwnd child_hwnd = Hwnd.ObjectFromHandle(child);
5298 if (child_hwnd == null) {
5302 XEvent xevent = new XEvent ();
5304 xevent.type = XEventName.MotionNotify;
5305 xevent.MotionEvent.display = DisplayHandle;
5306 xevent.MotionEvent.window = child_hwnd.client_window;
5307 xevent.MotionEvent.root = RootWindow;
5308 xevent.MotionEvent.x = child_x;
5309 xevent.MotionEvent.y = child_y;
5310 xevent.MotionEvent.x_root = root_x;
5311 xevent.MotionEvent.y_root = root_y;
5312 xevent.MotionEvent.state = mask;
5314 child_hwnd.Queue.EnqueueLocked (xevent);
5319 hwnd = Hwnd.ObjectFromHandle(handle);
5321 XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
5326 internal override void SetFocus(IntPtr handle) {
5328 IntPtr prev_focus_window;
5330 hwnd = Hwnd.ObjectFromHandle(handle);
5332 if (hwnd.client_window == FocusWindow) {
5336 // Win32 doesn't do anything if disabled
5340 prev_focus_window = FocusWindow;
5341 FocusWindow = hwnd.client_window;
5343 if (prev_focus_window != IntPtr.Zero) {
5344 SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
5346 SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
5347 Keyboard.FocusIn (FocusWindow);
5349 //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
5352 internal override void SetIcon(IntPtr handle, Icon icon) {
5355 hwnd = Hwnd.ObjectFromHandle(handle);
5357 SetIcon(hwnd, icon);
5361 internal override void SetMenu(IntPtr handle, Menu menu) {
5364 hwnd = Hwnd.ObjectFromHandle(handle);
5367 RequestNCRecalc(handle);
5370 internal override void SetModal(IntPtr handle, bool Modal) {
5372 ModalWindows.Push(handle);
5374 if (ModalWindows.Contains(handle)) {
5377 if (ModalWindows.Count > 0) {
5378 Activate((IntPtr)ModalWindows.Peek());
5382 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
5383 Control ctrl = Control.FromHandle (handle);
5384 SetWMStyles (hwnd, ctrl.GetCreateParams ());
5387 internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
5390 hwnd = Hwnd.ObjectFromHandle(handle);
5391 hwnd.parent = Hwnd.ObjectFromHandle(parent);
5394 #if DriverDebug || DriverDebugParent
5395 Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(hwnd.Handle), XplatUI.Window(hwnd.parent != null ? hwnd.parent.Handle : IntPtr.Zero));
5397 XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent == null ? FosterParent : hwnd.parent.client_window, hwnd.x, hwnd.y);
5403 internal override void SetTimer (Timer timer) {
5404 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
5406 if (queue == null) {
5407 // This isn't really an error, MS doesn't start the timer if
5408 // it has no assosciated queue at this stage (it will be
5409 // enabled when a window is activated).
5410 unattached_timer_list.Add (timer);
5413 queue.timer_list.Add (timer);
5417 internal override bool SetTopmost(IntPtr handle, bool enabled) {
5419 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5424 SendNetWMMessage(hwnd.WholeWindow, _NET_WM_STATE, (IntPtr) NetWmStateRequest._NET_WM_STATE_ADD, _NET_WM_STATE_ABOVE, IntPtr.Zero);
5426 int[] atoms = new int[8];
5427 atoms[0] = _NET_WM_STATE_ABOVE.ToInt32();
5428 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5434 SendNetWMMessage(hwnd.WholeWindow, _NET_WM_STATE, (IntPtr) NetWmStateRequest._NET_WM_STATE_REMOVE, _NET_WM_STATE_ABOVE, IntPtr.Zero);
5436 XDeleteProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE);
5442 internal override bool SetOwner(IntPtr handle, IntPtr handle_owner) {
5446 hwnd = Hwnd.ObjectFromHandle(handle);
5448 if (handle_owner != IntPtr.Zero) {
5449 hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
5455 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
5456 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5458 if (hwnd_owner != null) {
5459 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
5461 XSetTransientForHint(DisplayHandle, hwnd.whole_window, RootWindow);
5466 XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR);
5472 internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
5476 hwnd = Hwnd.ObjectFromHandle(handle);
5477 hwnd.visible = visible;
5481 MapWindow(hwnd, WindowType.Both);
5483 if (Control.FromHandle(handle) is Form) {
5486 s = ((Form)Control.FromHandle(handle)).WindowState;
5489 case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break;
5490 case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break;
5494 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5497 UnmapWindow(hwnd, WindowType.Both);
5503 internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
5504 Control ctrl = Control.FromHandle (handle);
5505 SetWindowMinMax (handle, maximized, min, max, ctrl != null ? ctrl.GetCreateParams () : null);
5508 internal void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp)
5514 hwnd = Hwnd.ObjectFromHandle(handle);
5519 min.Width = Math.Max (min.Width, SystemInformation.MinimumWindowSize.Width);
5520 min.Height = Math.Max (min.Height, SystemInformation.MinimumWindowSize.Height);
5522 hints = new XSizeHints();
5524 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
5525 if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
5527 min = TranslateWindowSizeToXWindowSize (cp, min);
5528 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
5529 hints.min_width = min.Width;
5530 hints.min_height = min.Height;
5533 if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
5535 max = TranslateWindowSizeToXWindowSize (cp, max);
5536 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
5537 hints.max_width = max.Width;
5538 hints.max_height = max.Height;
5541 if (hints.flags != IntPtr.Zero) {
5542 // The Metacity team has decided that they won't care about this when clicking the maximize icon,
5543 // they will maximize the window to fill the screen/parent no matter what.
5544 // http://bugzilla.ximian.com/show_bug.cgi?id=80021
5545 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints);
5548 if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
5550 maximized.Size = TranslateWindowSizeToXWindowSize (cp);
5551 hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
5552 hints.x = maximized.X;
5553 hints.y = maximized.Y;
5554 hints.width = maximized.Width;
5555 hints.height = maximized.Height;
5557 // Metacity does not seem to follow this constraint for maximized (zoomed) windows
5558 XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints);
5563 internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
5566 hwnd = Hwnd.ObjectFromHandle(handle);
5572 // Win32 automatically changes negative width/height to 0.
5578 // X requires a sanity check for width & height; otherwise it dies
5579 if (hwnd.zero_sized && width > 0 && height > 0) {
5581 MapWindow(hwnd, WindowType.Whole);
5583 hwnd.zero_sized = false;
5586 if ((width < 1) || (height < 1)) {
5587 hwnd.zero_sized = true;
5588 UnmapWindow(hwnd, WindowType.Whole);
5591 // Save a server roundtrip (and prevent a feedback loop)
5592 if ((hwnd.x == x) && (hwnd.y == y) &&
5593 (hwnd.width == width) && (hwnd.height == height)) {
5597 if (!hwnd.zero_sized) {
5602 hwnd.height = height;
5603 SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5605 if (hwnd.fixed_size) {
5606 SetWindowMinMax(handle, Rectangle.Empty, new Size(width, height), new Size(width, height));
5610 Control ctrl = Control.FromHandle (handle);
5611 Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams (), new Size (width, height));
5612 MoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
5613 PerformNCCalc(hwnd);
5617 // Update our position/size immediately, so
5618 // that future calls to SetWindowPos aren't
5619 // kept from calling XMoveResizeWindow (by the
5620 // "Save a server roundtrip" block above).
5624 hwnd.height = height;
5625 hwnd.ClientRect = Rectangle.Empty;
5628 internal override void SetWindowState(IntPtr handle, FormWindowState state) {
5629 FormWindowState current_state;
5632 hwnd = Hwnd.ObjectFromHandle(handle);
5634 current_state = GetWindowState(handle);
5636 if (current_state == state) {
5641 case FormWindowState.Normal: {
5643 if (current_state == FormWindowState.Minimized) {
5644 MapWindow(hwnd, WindowType.Both);
5645 } else if (current_state == FormWindowState.Maximized) {
5646 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5653 case FormWindowState.Minimized: {
5655 if (current_state == FormWindowState.Maximized) {
5656 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5658 XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo);
5663 case FormWindowState.Maximized: {
5665 if (current_state == FormWindowState.Minimized) {
5666 MapWindow(hwnd, WindowType.Both);
5669 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)1 /* Add */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5677 internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
5680 hwnd = Hwnd.ObjectFromHandle(handle);
5681 SetHwndStyles(hwnd, cp);
5682 SetWMStyles(hwnd, cp);
5685 internal override double GetWindowTransparency(IntPtr handle)
5690 internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) {
5694 hwnd = Hwnd.ObjectFromHandle(handle);
5700 hwnd.opacity = (uint)(0xffffffff * transparency);
5701 opacity = (IntPtr)((int)hwnd.opacity);
5703 IntPtr w = hwnd.whole_window;
5704 if (hwnd.reparented)
5705 w = XGetParent (hwnd.whole_window);
5706 XChangeProperty(DisplayHandle, w, _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
5709 internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) {
5710 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5718 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5721 } else if (!bottom) {
5722 Hwnd after_hwnd = null;
5724 if (after_handle != IntPtr.Zero) {
5725 after_hwnd = Hwnd.ObjectFromHandle(after_handle);
5728 XWindowChanges values = new XWindowChanges();
5730 if (after_hwnd == null) {
5731 // Work around metacity 'issues'
5735 atoms[0] = unixtime();
5736 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_USER_TIME, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, atoms, 1);
5738 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5739 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
5741 //throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order");
5744 values.sibling = after_hwnd.whole_window;
5745 values.stack_mode = StackMode.Below;
5748 XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
5753 XLowerWindow(DisplayHandle, hwnd.whole_window);
5760 internal override void ShowCursor(bool show) {
5761 ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
5764 internal override object StartLoop(Thread thread) {
5765 XEventQueue q = ThreadQueue(thread);
5769 internal override TransparencySupport SupportsTransparency() {
5770 // We need to check if the x compositing manager is running
5771 return TransparencySupport.Set;
5774 internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) {
5775 GetSystrayManagerWindow();
5777 if (SystrayMgrWindow != IntPtr.Zero) {
5778 XSizeHints size_hints;
5781 hwnd = Hwnd.ObjectFromHandle(handle);
5783 Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
5787 if (hwnd.client_window != hwnd.whole_window) {
5788 Keyboard.DestroyICForWindow (hwnd.client_window);
5789 XDestroyWindow(DisplayHandle, hwnd.client_window);
5790 hwnd.client_window = hwnd.whole_window;
5793 /* by virtue of the way the tests are ordered when determining if it's PAINT
5794 or NCPAINT, client_window == whole_window will always be PAINT. So, if we're
5795 waiting on an nc_expose, drop it and remove the hwnd from the list (unless
5796 there's a pending expose). */
5797 if (hwnd.nc_expose_pending) {
5798 hwnd.nc_expose_pending = false;
5799 if (!hwnd.expose_pending)
5800 hwnd.Queue.Paint.Remove (hwnd);
5803 size_hints = new XSizeHints();
5805 size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
5807 size_hints.min_width = 24;
5808 size_hints.min_height = 24;
5809 size_hints.max_width = 24;
5810 size_hints.max_height = 24;
5811 size_hints.base_width = 24;
5812 size_hints.base_height = 24;
5814 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints);
5816 int[] atoms = new int[2];
5817 atoms [0] = 1; // Version 1
5818 atoms [1] = 1; // we want to be mapped
5820 // This line cost me 3 days...
5821 XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2);
5823 // Need to pick some reasonable defaults
5825 tt.AutomaticDelay = 350;
5826 tt.InitialDelay = 250;
5827 tt.ReshowDelay = 250;
5828 tt.ShowAlways = true;
5830 if ((tip != null) && (tip != string.Empty)) {
5831 tt.SetToolTip(Control.FromHandle(handle), tip);
5837 SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
5845 internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) {
5848 control = Control.FromHandle(handle);
5849 if (control != null && tt != null) {
5850 tt.SetToolTip(control, tip);
5852 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5859 internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
5861 SetVisible (handle, false, false);
5863 // The caller can now re-dock it later...
5871 internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
5873 ThemeEngine.Current.ShowBalloonWindow (handle, timeout, title, text, icon);
5874 SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW);
5878 internal override bool Text(IntPtr handle, string text) {
5881 hwnd = Hwnd.ObjectFromHandle(handle);
5884 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_NAME, UNICODETEXT, 8,
5885 PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
5887 // XXX this has problems with UTF8.
5888 // we need to either use the actual
5889 // text if it's latin-1, or convert it
5890 // to compound text if it's in a
5891 // different charset.
5892 XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text);
5897 internal override bool TranslateMessage(ref MSG msg) {
5898 return Keyboard.TranslateMessage (ref msg);
5901 internal override void UpdateWindow(IntPtr handle) {
5904 hwnd = Hwnd.ObjectFromHandle(handle);
5906 if (!hwnd.visible || !hwnd.expose_pending || !hwnd.Mapped) {
5910 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5911 hwnd.Queue.Paint.Remove(hwnd);
5914 internal override void CreateOffscreenDrawable (IntPtr handle,
5915 int width, int height,
5916 out object offscreen_drawable)
5919 int x_out, y_out, width_out, height_out, border_width_out, depth_out;
5921 XGetGeometry (DisplayHandle, handle,
5923 out x_out, out y_out,
5924 out width_out, out height_out,
5925 out border_width_out, out depth_out);
5927 IntPtr pixmap = XCreatePixmap (DisplayHandle, handle, width, height, depth_out);
5929 offscreen_drawable = pixmap;
5933 internal override void DestroyOffscreenDrawable (object offscreen_drawable)
5935 XFreePixmap (DisplayHandle, (IntPtr)offscreen_drawable);
5938 internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
5940 return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
5943 internal override void BlitFromOffscreen (IntPtr dest_handle,
5945 object offscreen_drawable,
5946 Graphics offscreen_dc,
5949 XGCValues gc_values;
5952 gc_values = new XGCValues();
5954 gc = XCreateGC (DisplayHandle, dest_handle, IntPtr.Zero, ref gc_values);
5956 XCopyArea (DisplayHandle, (IntPtr)offscreen_drawable, dest_handle,
5957 gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
5959 XFreeGC (DisplayHandle, gc);
5962 #endregion // Public Static Methods
5965 internal override event EventHandler Idle;
5966 #endregion // Events
5968 #region Xcursor imports
5969 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")]
5970 internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name);
5972 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")]
5973 internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size);
5975 [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")]
5976 internal extern static void XcursorImagesDestroy (IntPtr images);
5978 [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")]
5979 internal extern static int XcursorGetDefaultSize (IntPtr display);
5981 [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")]
5982 internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image);
5984 [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")]
5985 internal extern static IntPtr XcursorGetTheme (IntPtr display);
5988 [DllImport ("libX11", EntryPoint="XOpenDisplay")]
5989 internal extern static IntPtr XOpenDisplay(IntPtr display);
5990 [DllImport ("libX11", EntryPoint="XCloseDisplay")]
5991 internal extern static int XCloseDisplay(IntPtr display);
5992 [DllImport ("libX11", EntryPoint="XSynchronize")]
5993 internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
5995 [DllImport ("libX11", EntryPoint="XCreateWindow")]
5996 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);
5997 [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
5998 internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
5999 [DllImport ("libX11", EntryPoint="XMapWindow")]
6000 internal extern static int XMapWindow(IntPtr display, IntPtr window);
6001 [DllImport ("libX11", EntryPoint="XUnmapWindow")]
6002 internal extern static int XUnmapWindow(IntPtr display, IntPtr window);
6003 [DllImport ("libX11", EntryPoint="XMapSubwindows")]
6004 internal extern static int XMapSubindows(IntPtr display, IntPtr window);
6005 [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
6006 internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
6007 [DllImport ("libX11", EntryPoint="XRootWindow")]
6008 internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
6009 [DllImport ("libX11", EntryPoint="XNextEvent")]
6010 internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
6011 [DllImport ("libX11")]
6012 internal extern static int XConnectionNumber (IntPtr diplay);
6013 [DllImport ("libX11")]
6014 internal extern static int XPending (IntPtr diplay);
6015 [DllImport ("libX11", EntryPoint="XSelectInput")]
6016 internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
6018 [DllImport ("libX11", EntryPoint="XDestroyWindow")]
6019 internal extern static int XDestroyWindow(IntPtr display, IntPtr window);
6021 [DllImport ("libX11", EntryPoint="XReparentWindow")]
6022 internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
6023 [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
6024 private extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
6026 internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height)
6028 int ret = XMoveResizeWindow (display, window, x, y, width, height);
6029 Keyboard.MoveCurrentCaretPos ();
6033 [DllImport ("libX11", EntryPoint="XResizeWindow")]
6034 internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
6036 [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
6037 internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
6039 [DllImport ("libX11", EntryPoint="XFlush")]
6040 internal extern static int XFlush(IntPtr display);
6042 [DllImport ("libX11", EntryPoint="XSetWMName")]
6043 internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
6045 [DllImport ("libX11", EntryPoint="XStoreName")]
6046 internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
6048 [DllImport ("libX11", EntryPoint="XFetchName")]
6049 internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
6051 [DllImport ("libX11", EntryPoint="XSendEvent")]
6052 internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
6054 [DllImport ("libX11", EntryPoint="XQueryTree")]
6055 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);
6057 [DllImport ("libX11", EntryPoint="XFree")]
6058 internal extern static int XFree(IntPtr data);
6060 [DllImport ("libX11", EntryPoint="XRaiseWindow")]
6061 internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
6063 [DllImport ("libX11", EntryPoint="XLowerWindow")]
6064 internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
6066 [DllImport ("libX11", EntryPoint="XConfigureWindow")]
6067 internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
6069 [DllImport ("libX11", EntryPoint="XInternAtom")]
6070 internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
6072 [DllImport ("libX11", EntryPoint="XInternAtoms")]
6073 internal extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
6075 [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
6076 internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
6078 [DllImport ("libX11", EntryPoint="XGrabPointer")]
6079 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);
6081 [DllImport ("libX11", EntryPoint="XUngrabPointer")]
6082 internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp);
6084 [DllImport ("libX11", EntryPoint="XQueryPointer")]
6085 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);
6087 [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
6088 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);
6090 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6091 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);
6093 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6094 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);
6096 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6097 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);
6099 [DllImport ("libX11", EntryPoint="XGetGeometry")]
6100 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);
6102 [DllImport ("libX11", EntryPoint="XWarpPointer")]
6103 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);
6105 [DllImport ("libX11", EntryPoint="XClearWindow")]
6106 internal extern static int XClearWindow(IntPtr display, IntPtr window);
6108 [DllImport ("libX11", EntryPoint="XClearArea")]
6109 internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
6112 [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
6113 internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
6115 [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
6116 internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
6118 [DllImport ("libX11", EntryPoint="XDefaultVisual")]
6119 internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
6121 [DllImport ("libX11", EntryPoint="XDefaultDepth")]
6122 internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
6124 [DllImport ("libX11", EntryPoint="XDefaultScreen")]
6125 internal extern static int XDefaultScreen(IntPtr display);
6127 [DllImport ("libX11", EntryPoint="XDefaultColormap")]
6128 internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
6130 [DllImport ("libX11", EntryPoint="XLookupColor")]
6131 internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
6133 [DllImport ("libX11", EntryPoint="XAllocColor")]
6134 internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
6136 [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
6137 internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
6139 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6140 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
6142 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6143 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
6145 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6146 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
6148 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6149 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
6151 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6152 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
6154 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6155 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
6157 [DllImport ("libX11", EntryPoint="XChangeProperty")]
6158 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
6160 [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
6161 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
6163 [DllImport ("libX11", EntryPoint="XDeleteProperty")]
6164 internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
6167 [DllImport ("libX11", EntryPoint="XCreateGC")]
6168 internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
6170 [DllImport ("libX11", EntryPoint="XFreeGC")]
6171 internal extern static int XFreeGC(IntPtr display, IntPtr gc);
6173 [DllImport ("libX11", EntryPoint="XSetFunction")]
6174 internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
6176 [DllImport ("libX11", EntryPoint="XSetLineAttributes")]
6177 internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
6179 [DllImport ("libX11", EntryPoint="XDrawLine")]
6180 internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
6182 [DllImport ("libX11", EntryPoint="XDrawRectangle")]
6183 internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
6185 [DllImport ("libX11", EntryPoint="XFillRectangle")]
6186 internal extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
6188 [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
6189 internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
6191 [DllImport ("libX11", EntryPoint="XCopyArea")]
6192 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);
6194 [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
6195 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);
6197 [DllImport ("libX11", EntryPoint="XSetInputFocus")]
6198 internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
6200 [DllImport ("libX11", EntryPoint="XIconifyWindow")]
6201 internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
6203 [DllImport ("libX11", EntryPoint="XDefineCursor")]
6204 internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
6206 [DllImport ("libX11", EntryPoint="XUndefineCursor")]
6207 internal extern static int XUndefineCursor(IntPtr display, IntPtr window);
6209 [DllImport ("libX11", EntryPoint="XFreeCursor")]
6210 internal extern static int XFreeCursor(IntPtr display, IntPtr cursor);
6212 [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
6213 internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
6215 [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
6216 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);
6218 [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
6219 internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
6221 [DllImport ("libX11", EntryPoint="XCreatePixmap")]
6222 internal extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
6224 [DllImport ("libX11", EntryPoint="XFreePixmap")]
6225 internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
6227 [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
6228 internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
6230 [DllImport ("libX11", EntryPoint="XQueryExtension")]
6231 internal extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
6233 [DllImport ("libX11", EntryPoint="XWhitePixel")]
6234 internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
6236 [DllImport ("libX11", EntryPoint="XBlackPixel")]
6237 internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
6239 [DllImport ("libX11", EntryPoint="XGrabServer")]
6240 internal extern static void XGrabServer(IntPtr display);
6242 [DllImport ("libX11", EntryPoint="XUngrabServer")]
6243 internal extern static void XUngrabServer(IntPtr display);
6245 [DllImport ("libX11", EntryPoint="XGetWMNormalHints")]
6246 internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
6248 [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
6249 internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
6251 [DllImport ("libX11", EntryPoint="XSetZoomHints")]
6252 internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
6254 [DllImport ("libX11", EntryPoint="XSetWMHints")]
6255 internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
6257 [DllImport ("libX11", EntryPoint="XGetIconSizes")]
6258 internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
6260 [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
6261 internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
6263 [DllImport ("libX11", EntryPoint="XGetErrorText")]
6264 internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
6266 [DllImport ("libX11", EntryPoint="XInitThreads")]
6267 internal extern static int XInitThreads();
6269 [DllImport ("libX11", EntryPoint="XConvertSelection")]
6270 internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
6272 [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
6273 internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
6275 [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
6276 internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
6278 [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
6279 internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
6281 [DllImport ("libX11", EntryPoint="XSetForeground")]
6282 internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
6284 [DllImport ("libX11", EntryPoint="XSetBackground")]
6285 internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
6287 [DllImport ("libX11", EntryPoint="XBell")]
6288 internal extern static int XBell(IntPtr display, int percent);
6290 [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")]
6291 internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
6293 [DllImport ("libX11", EntryPoint="XFilterEvent")]
6294 internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
6296 [DllImport ("libX11")]
6297 internal extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
6299 [DllImport ("libX11")]
6300 internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
6302 [DllImport ("libX11")]
6303 internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);