2007-05-03 Chris Toshok <toshok@ximian.com>
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / XplatUIX11.cs
blob407c9cd9cf4f01f60c337d12bca88a950784c633
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:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
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.
22 // Authors:
23 // Peter Bartok pbartok@novell.com
27 // NOTE:
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
37 // NOT COMPLETE
39 // define to log Window handles and relationships to stdout
40 #undef DriverDebug
42 // Extra detailed debug
43 #undef DriverDebugExtra
44 #undef DriverDebugParent
45 #undef DriverDebugCreate
46 #undef DriverDebugDestroy
47 #undef DriverDebugThreads
48 #undef DriverDebugXEmbed
50 using System;
51 using System.ComponentModel;
52 using System.Collections;
53 using System.Diagnostics;
54 using System.Drawing;
55 using System.Drawing.Drawing2D;
56 using System.Drawing.Imaging;
57 using System.IO;
58 using System.Net;
59 using System.Net.Sockets;
60 using System.Reflection;
61 using System.Runtime.InteropServices;
62 using System.Text;
63 using System.Threading;
65 // Only do the poll when building with mono for now
66 #if __MonoCS__
67 using Mono.Unix.Native;
68 #endif
70 /// X11 Version
71 namespace System.Windows.Forms {
72 internal class XplatUIX11 : XplatUIDriver {
73 #region Local Variables
74 // General
75 static volatile XplatUIX11 Instance;
76 private static int RefCount;
77 private static object XlibLock; // Our locking object
78 private static bool themes_enabled;
80 // General X11
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;
94 // Clipboard
95 private static IntPtr ClipMagic;
96 private static ClipboardStruct Clipboard; // Our clipboard
98 // Communication
99 private static IntPtr PostAtom; // PostMessage atom
100 private static IntPtr AsyncAtom; // Support for async messages
102 // Message Loop
103 private static Hashtable MessageQueues; // Holds our thread-specific XEventQueues
104 #if __MonoCS__ //
105 private static Pollfd[] pollfds; // For watching the X11 socket
106 private static bool wake_waiting;
107 private static object wake_waiting_lock = new object ();
108 #endif //
109 private static X11Keyboard Keyboard; //
110 private static X11Dnd Dnd;
111 private static Socket listen; //
112 private static Socket wake; //
113 private static Socket wake_receive; //
114 private static byte[] network_buffer; //
115 private static bool detectable_key_auto_repeat;
117 // Focus tracking
118 private static IntPtr ActiveWindow; // Handle of the active window
119 private static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any)
121 // Modality support
122 private static Stack ModalWindows; // Stack of our modal windows
124 // Systray
125 private static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window
127 // Cursors
128 private static IntPtr LastCursorWindow; // The last window we set the cursor on
129 private static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
130 private static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
132 // Caret
133 private static CaretStruct Caret; //
135 // Our atoms
136 private static IntPtr WM_PROTOCOLS;
137 private static IntPtr WM_DELETE_WINDOW;
138 private static IntPtr WM_TAKE_FOCUS;
139 //private static IntPtr _NET_SUPPORTED;
140 //private static IntPtr _NET_CLIENT_LIST;
141 //private static IntPtr _NET_NUMBER_OF_DESKTOPS;
142 private static IntPtr _NET_DESKTOP_GEOMETRY;
143 //private static IntPtr _NET_DESKTOP_VIEWPORT;
144 private static IntPtr _NET_CURRENT_DESKTOP;
145 //private static IntPtr _NET_DESKTOP_NAMES;
146 private static IntPtr _NET_ACTIVE_WINDOW;
147 private static IntPtr _NET_WORKAREA;
148 //private static IntPtr _NET_SUPPORTING_WM_CHECK;
149 //private static IntPtr _NET_VIRTUAL_ROOTS;
150 //private static IntPtr _NET_DESKTOP_LAYOUT;
151 //private static IntPtr _NET_SHOWING_DESKTOP;
152 //private static IntPtr _NET_CLOSE_WINDOW;
153 //private static IntPtr _NET_MOVERESIZE_WINDOW;
154 //private static IntPtr _NET_WM_MOVERESIZE;
155 //private static IntPtr _NET_RESTACK_WINDOW;
156 //private static IntPtr _NET_REQUEST_FRAME_EXTENTS;
157 private static IntPtr _NET_WM_NAME;
158 //private static IntPtr _NET_WM_VISIBLE_NAME;
159 //private static IntPtr _NET_WM_ICON_NAME;
160 //private static IntPtr _NET_WM_VISIBLE_ICON_NAME;
161 //private static IntPtr _NET_WM_DESKTOP;
162 private static IntPtr _NET_WM_WINDOW_TYPE;
163 private static IntPtr _NET_WM_STATE;
164 //private static IntPtr _NET_WM_ALLOWED_ACTIONS;
165 //private static IntPtr _NET_WM_STRUT;
166 //private static IntPtr _NET_WM_STRUT_PARTIAL;
167 //private static IntPtr _NET_WM_ICON_GEOMETRY;
168 private static IntPtr _NET_WM_ICON;
169 //private static IntPtr _NET_WM_PID;
170 //private static IntPtr _NET_WM_HANDLED_ICONS;
171 private static IntPtr _NET_WM_USER_TIME;
172 private static IntPtr _NET_FRAME_EXTENTS;
173 //private static IntPtr _NET_WM_PING;
174 //private static IntPtr _NET_WM_SYNC_REQUEST;
175 private static IntPtr _NET_SYSTEM_TRAY_S;
176 //private static IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
177 private static IntPtr _NET_SYSTEM_TRAY_OPCODE;
178 private static IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
179 private static IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
180 private static IntPtr _XEMBED;
181 private static IntPtr _XEMBED_INFO;
182 private static IntPtr _MOTIF_WM_HINTS;
183 private static IntPtr _NET_WM_STATE_SKIP_TASKBAR;
184 private static IntPtr _NET_WM_STATE_ABOVE;
185 private static IntPtr _NET_WM_STATE_MODAL;
186 private static IntPtr _NET_WM_STATE_HIDDEN;
187 private static IntPtr _NET_WM_CONTEXT_HELP;
188 private static IntPtr _NET_WM_WINDOW_OPACITY;
189 //private static IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
190 //private static IntPtr _NET_WM_WINDOW_TYPE_DOCK;
191 //private static IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
192 //private static IntPtr _NET_WM_WINDOW_TYPE_MENU;
193 private static IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
194 //private static IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
195 private static IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
196 private static IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
197 private static IntPtr CLIPBOARD;
198 private static IntPtr PRIMARY;
199 //private static IntPtr DIB;
200 private static IntPtr OEMTEXT;
201 private static IntPtr UNICODETEXT;
202 private static IntPtr TARGETS;
204 // mouse hover message generation
205 private static HoverStruct HoverState; //
207 // double click message generation
208 private static ClickStruct ClickPending; //
210 // Support for mouse grab
211 private static GrabStruct Grab; //
213 // State
214 Point mouse_position; // Last position of mouse, in screen coords
215 internal static MouseButtons MouseState; // Last state of mouse buttons
217 // 'Constants'
218 private static int DoubleClickInterval; // msec; max interval between clicks to count as double click
220 const EventMask SelectInputMask = (EventMask.ButtonPressMask |
221 EventMask.ButtonReleaseMask |
222 EventMask.KeyPressMask |
223 EventMask.KeyReleaseMask |
224 EventMask.EnterWindowMask |
225 EventMask.LeaveWindowMask |
226 EventMask.ExposureMask |
227 EventMask.FocusChangeMask |
228 EventMask.PointerMotionMask |
229 EventMask.SubstructureNotifyMask);
231 static readonly object lockobj = new object ();
233 #endregion // Local Variables
234 #region Constructors
235 private XplatUIX11() {
236 // Handle singleton stuff first
237 RefCount = 0;
239 // Now regular initialization
240 XlibLock = new object ();
241 MessageQueues = Hashtable.Synchronized (new Hashtable(7));
242 XInitThreads();
244 ErrorExceptions = false;
246 // X11 Initialization
247 SetDisplay(XOpenDisplay(IntPtr.Zero));
248 X11DesktopColors.Initialize();
251 // Disable keyboard autorepeat
252 try {
253 XkbSetDetectableAutoRepeat (DisplayHandle, true, IntPtr.Zero);
254 detectable_key_auto_repeat = true;
255 } catch {
256 Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually.");
257 detectable_key_auto_repeat = false;
260 // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does)
261 ErrorHandler = new XErrorHandler(HandleError);
262 XSetErrorHandler(ErrorHandler);
265 ~XplatUIX11() {
266 // Remove our display handle from S.D
267 Graphics.FromHdcInternal (IntPtr.Zero);
270 #endregion // Constructors
272 #region Singleton Specific Code
273 public static XplatUIX11 GetInstance() {
274 lock (lockobj) {
275 if (Instance == null) {
276 Instance=new XplatUIX11();
278 RefCount++;
280 return Instance;
283 public int Reference {
284 get {
285 return RefCount;
288 #endregion
290 #region Internal Properties
291 internal static IntPtr Display {
292 get {
293 return DisplayHandle;
296 set {
297 XplatUIX11.GetInstance().SetDisplay(value);
301 internal static int Screen {
302 get {
303 return ScreenNo;
306 set {
307 ScreenNo = value;
311 internal static IntPtr RootWindowHandle {
312 get {
313 return RootWindow;
316 set {
317 RootWindow = value;
321 internal static IntPtr Visual {
322 get {
323 return CustomVisual;
326 set {
327 CustomVisual = value;
331 internal static IntPtr ColorMap {
332 get {
333 return CustomColormap;
336 set {
337 CustomColormap = value;
340 #endregion
342 #region XExceptionClass
343 internal class XException : ApplicationException {
344 IntPtr Display;
345 IntPtr ResourceID;
346 IntPtr Serial;
347 XRequest RequestCode;
348 byte ErrorCode;
349 byte MinorCode;
351 public XException(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
352 this.Display = Display;
353 this.ResourceID = ResourceID;
354 this.Serial = Serial;
355 this.RequestCode = RequestCode;
356 this.ErrorCode = ErrorCode;
357 this.MinorCode = MinorCode;
360 public override string Message {
361 get {
362 return GetMessage(Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode);
366 public static string GetMessage(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
367 StringBuilder sb;
368 string x_error_text;
369 string error;
370 string hwnd_text;
371 string control_text;
372 Hwnd hwnd;
373 Control c;
375 sb = new StringBuilder(160);
376 XGetErrorText(Display, ErrorCode, sb, sb.Capacity);
377 x_error_text = sb.ToString();
378 hwnd = Hwnd.ObjectFromHandle(ResourceID);
379 if (hwnd != null) {
380 hwnd_text = hwnd.ToString();
381 c = Control.FromHandle(hwnd.Handle);
382 if (c != null) {
383 control_text = c.ToString();
384 } else {
385 control_text = String.Format("<handle {0:X} non-existant>", hwnd.Handle);
387 } else {
388 hwnd_text = "<null>";
389 control_text = "<null>";
393 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);
394 return error;
397 #endregion // XExceptionClass
399 #region Internal Methods
400 internal void SetDisplay(IntPtr display_handle) {
401 if (display_handle != IntPtr.Zero) {
402 Hwnd hwnd;
404 if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) {
405 hwnd = Hwnd.ObjectFromHandle(FosterParent);
406 XDestroyWindow(DisplayHandle, FosterParent);
407 hwnd.Dispose();
410 if (DisplayHandle != IntPtr.Zero) {
411 XCloseDisplay(DisplayHandle);
414 DisplayHandle=display_handle;
416 // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has
417 // been hacked to do this for us.
418 Graphics.FromHdcInternal (DisplayHandle);
420 // query for the render extension so
421 // we can ignore the spurious
422 // BadPicture errors that are
423 // generated by cairo/render.
424 XQueryExtension (DisplayHandle, "RENDER",
425 ref render_major_opcode, ref render_first_event, ref render_first_error);
427 // Debugging support
428 if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
429 XSynchronize(DisplayHandle, true);
432 if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
433 ErrorExceptions = true;
436 // Generic X11 setup
437 ScreenNo = XDefaultScreen(DisplayHandle);
438 RootWindow = XRootWindow(DisplayHandle, ScreenNo);
439 DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
441 // Create the foster parent
442 FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero);
443 if (FosterParent==IntPtr.Zero) {
444 Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
447 hwnd = new Hwnd();
448 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
449 hwnd.WholeWindow = FosterParent;
450 hwnd.ClientWindow = FosterParent;
452 // Create a HWND for RootWIndow as well, so our queue doesn't eat the events
453 hwnd = new Hwnd();
454 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
455 hwnd.whole_window = RootWindow;
456 hwnd.ClientWindow = RootWindow;
458 // For sleeping on the X11 socket
459 listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
460 IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0);
461 listen.Bind(ep);
462 listen.Listen(1);
464 // To wake up when a timer is ready
465 network_buffer = new byte[10];
467 wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
468 wake.Connect(listen.LocalEndPoint);
469 wake_receive = listen.Accept();
471 #if __MonoCS__
472 pollfds = new Pollfd [2];
473 pollfds [0] = new Pollfd ();
474 pollfds [0].fd = XConnectionNumber (DisplayHandle);
475 pollfds [0].events = PollEvents.POLLIN;
477 pollfds [1] = new Pollfd ();
478 pollfds [1].fd = wake_receive.Handle.ToInt32 ();
479 pollfds [1].events = PollEvents.POLLIN;
480 #endif
482 Keyboard = new X11Keyboard(DisplayHandle, FosterParent);
483 Dnd = new X11Dnd (DisplayHandle, Keyboard);
485 DoubleClickInterval = 500;
487 HoverState.Interval = 500;
488 HoverState.Timer = new Timer();
489 HoverState.Timer.Enabled = false;
490 HoverState.Timer.Interval = HoverState.Interval;
491 HoverState.Timer.Tick += new EventHandler(MouseHover);
492 HoverState.Size = new Size(4, 4);
493 HoverState.X = -1;
494 HoverState.Y = -1;
496 ActiveWindow = IntPtr.Zero;
497 FocusWindow = IntPtr.Zero;
498 ModalWindows = new Stack(3);
500 MouseState = MouseButtons.None;
501 mouse_position = new Point(0, 0);
503 Caret.Timer = new Timer();
504 Caret.Timer.Interval = 500; // FIXME - where should this number come from?
505 Caret.Timer.Tick += new EventHandler(CaretCallback);
507 SetupAtoms();
509 // Grab atom changes off the root window to catch certain WM events
510 XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int)EventMask.PropertyChangeMask));
512 // Handle any upcoming errors
513 ErrorHandler = new XErrorHandler(HandleError);
514 XSetErrorHandler(ErrorHandler);
515 } else {
516 throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check you DISPLAY environment variable)");
519 #endregion // Internal Methods
521 #region Private Methods
522 private int unixtime() {
523 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
525 return (int) t.TotalSeconds;
528 private static void SetupAtoms() {
529 // make sure this array stays in sync with the statements below
530 string [] atom_names = new string[] {
531 "WM_PROTOCOLS",
532 "WM_DELETE_WINDOW",
533 "WM_TAKE_FOCUS",
534 //"_NET_SUPPORTED",
535 //"_NET_CLIENT_LIST",
536 //"_NET_NUMBER_OF_DESKTOPS",
537 "_NET_DESKTOP_GEOMETRY",
538 //"_NET_DESKTOP_VIEWPORT",
539 "_NET_CURRENT_DESKTOP",
540 //"_NET_DESKTOP_NAMES",
541 "_NET_ACTIVE_WINDOW",
542 "_NET_WORKAREA",
543 //"_NET_SUPPORTING_WM_CHECK",
544 //"_NET_VIRTUAL_ROOTS",
545 //"_NET_DESKTOP_LAYOUT",
546 //"_NET_SHOWING_DESKTOP",
547 //"_NET_CLOSE_WINDOW",
548 //"_NET_MOVERESIZE_WINDOW",
549 //"_NET_WM_MOVERESIZE",
550 //"_NET_RESTACK_WINDOW",
551 //"_NET_REQUEST_FRAME_EXTENTS",
552 "_NET_WM_NAME",
553 //"_NET_WM_VISIBLE_NAME",
554 //"_NET_WM_ICON_NAME",
555 //"_NET_WM_VISIBLE_ICON_NAME",
556 //"_NET_WM_DESKTOP",
557 "_NET_WM_WINDOW_TYPE",
558 "_NET_WM_STATE",
559 //"_NET_WM_ALLOWED_ACTIONS",
560 //"_NET_WM_STRUT",
561 //"_NET_WM_STRUT_PARTIAL",
562 //"_NET_WM_ICON_GEOMETRY",
563 "_NET_WM_ICON",
564 //"_NET_WM_PID",
565 //"_NET_WM_HANDLED_ICONS",
566 "_NET_WM_USER_TIME",
567 "_NET_FRAME_EXTENTS",
568 //"_NET_WM_PING",
569 //"_NET_WM_SYNC_REQUEST",
570 "_NET_SYSTEM_TRAY_OPCODE",
571 //"_NET_SYSTEM_TRAY_ORIENTATION",
572 "_NET_WM_STATE_MAXIMIZED_HORZ",
573 "_NET_WM_STATE_MAXIMIZED_VERT",
574 "_NET_WM_STATE_HIDDEN",
575 "_XEMBED",
576 "_XEMBED_INFO",
577 "_MOTIF_WM_HINTS",
578 "_NET_WM_STATE_SKIP_TASKBAR",
579 "_NET_WM_STATE_ABOVE",
580 "_NET_WM_STATE_MODAL",
581 "_NET_WM_CONTEXT_HELP",
582 "_NET_WM_WINDOW_OPACITY",
583 //"_NET_WM_WINDOW_TYPE_DESKTOP",
584 //"_NET_WM_WINDOW_TYPE_DOCK",
585 //"_NET_WM_WINDOW_TYPE_TOOLBAR",
586 //"_NET_WM_WINDOW_TYPE_MENU",
587 "_NET_WM_WINDOW_TYPE_UTILITY",
588 "_NET_WM_WINDOW_TYPE_DIALOG",
589 //"_NET_WM_WINDOW_TYPE_SPLASH",
590 "_NET_WM_WINDOW_TYPE_NORMAL",
591 "CLIPBOARD",
592 "PRIMARY",
593 "COMPOUND_TEXT",
594 "UTF8_STRING",
595 "TARGETS",
596 "_SWF_AsyncAtom",
597 "_SWF_PostMessageAtom",
598 "_SWF_HoverAtom" };
600 IntPtr[] atoms = new IntPtr [atom_names.Length];;
602 XInternAtoms (DisplayHandle, atom_names, atom_names.Length, false, atoms);
604 int off = 0;
605 WM_PROTOCOLS = atoms [off++];
606 WM_DELETE_WINDOW = atoms [off++];
607 WM_TAKE_FOCUS = atoms [off++];
608 //_NET_SUPPORTED = atoms [off++];
609 //_NET_CLIENT_LIST = atoms [off++];
610 //_NET_NUMBER_OF_DESKTOPS = atoms [off++];
611 _NET_DESKTOP_GEOMETRY = atoms [off++];
612 //_NET_DESKTOP_VIEWPORT = atoms [off++];
613 _NET_CURRENT_DESKTOP = atoms [off++];
614 //_NET_DESKTOP_NAMES = atoms [off++];
615 _NET_ACTIVE_WINDOW = atoms [off++];
616 _NET_WORKAREA = atoms [off++];
617 //_NET_SUPPORTING_WM_CHECK = atoms [off++];
618 //_NET_VIRTUAL_ROOTS = atoms [off++];
619 //_NET_DESKTOP_LAYOUT = atoms [off++];
620 //_NET_SHOWING_DESKTOP = atoms [off++];
621 //_NET_CLOSE_WINDOW = atoms [off++];
622 //_NET_MOVERESIZE_WINDOW = atoms [off++];
623 //_NET_WM_MOVERESIZE = atoms [off++];
624 //_NET_RESTACK_WINDOW = atoms [off++];
625 //_NET_REQUEST_FRAME_EXTENTS = atoms [off++];
626 _NET_WM_NAME = atoms [off++];
627 //_NET_WM_VISIBLE_NAME = atoms [off++];
628 //_NET_WM_ICON_NAME = atoms [off++];
629 //_NET_WM_VISIBLE_ICON_NAME = atoms [off++];
630 //_NET_WM_DESKTOP = atoms [off++];
631 _NET_WM_WINDOW_TYPE = atoms [off++];
632 _NET_WM_STATE = atoms [off++];
633 //_NET_WM_ALLOWED_ACTIONS = atoms [off++];
634 //_NET_WM_STRUT = atoms [off++];
635 //_NET_WM_STRUT_PARTIAL = atoms [off++];
636 //_NET_WM_ICON_GEOMETRY = atoms [off++];
637 _NET_WM_ICON = atoms [off++];
638 //_NET_WM_PID = atoms [off++];
639 //_NET_WM_HANDLED_ICONS = atoms [off++];
640 _NET_WM_USER_TIME = atoms [off++];
641 _NET_FRAME_EXTENTS = atoms [off++];
642 //_NET_WM_PING = atoms [off++];
643 //_NET_WM_SYNC_REQUEST = atoms [off++];
644 _NET_SYSTEM_TRAY_OPCODE = atoms [off++];
645 //_NET_SYSTEM_TRAY_ORIENTATION = atoms [off++];
646 _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++];
647 _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++];
648 _NET_WM_STATE_HIDDEN = atoms [off++];
649 _XEMBED = atoms [off++];
650 _XEMBED_INFO = atoms [off++];
651 _MOTIF_WM_HINTS = atoms [off++];
652 _NET_WM_STATE_SKIP_TASKBAR = atoms [off++];
653 _NET_WM_STATE_ABOVE = atoms [off++];
654 _NET_WM_STATE_MODAL = atoms [off++];
655 _NET_WM_CONTEXT_HELP = atoms [off++];
656 _NET_WM_WINDOW_OPACITY = atoms [off++];
657 //_NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++];
658 //_NET_WM_WINDOW_TYPE_DOCK = atoms [off++];
659 //_NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++];
660 //_NET_WM_WINDOW_TYPE_MENU = atoms [off++];
661 _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++];
662 _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++];
663 //_NET_WM_WINDOW_TYPE_SPLASH = atoms [off++];
664 _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++];
665 CLIPBOARD = atoms [off++];
666 PRIMARY = atoms [off++];
667 OEMTEXT = atoms [off++];
668 UNICODETEXT = atoms [off++];
669 TARGETS = atoms [off++];
670 AsyncAtom = atoms [off++];
671 PostAtom = atoms [off++];
672 HoverState.Atom = atoms [off++];
674 //DIB = (IntPtr)Atom.XA_PIXMAP;
675 _NET_SYSTEM_TRAY_S = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString(), false);
678 private void GetSystrayManagerWindow() {
679 XGrabServer(DisplayHandle);
680 SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, _NET_SYSTEM_TRAY_S);
681 XUngrabServer(DisplayHandle);
682 XFlush(DisplayHandle);
685 private void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
686 XEvent xev;
688 xev = new XEvent();
689 xev.ClientMessageEvent.type = XEventName.ClientMessage;
690 xev.ClientMessageEvent.send_event = true;
691 xev.ClientMessageEvent.window = window;
692 xev.ClientMessageEvent.message_type = message_type;
693 xev.ClientMessageEvent.format = 32;
694 xev.ClientMessageEvent.ptr1 = l0;
695 xev.ClientMessageEvent.ptr2 = l1;
696 xev.ClientMessageEvent.ptr3 = l2;
697 XSendEvent(DisplayHandle, RootWindow, false, new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
700 private void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
701 XEvent xev;
703 xev = new XEvent();
704 xev.ClientMessageEvent.type = XEventName.ClientMessage;
705 xev.ClientMessageEvent.send_event = true;
706 xev.ClientMessageEvent.window = window;
707 xev.ClientMessageEvent.message_type = message_type;
708 xev.ClientMessageEvent.format = 32;
709 xev.ClientMessageEvent.ptr1 = l0;
710 xev.ClientMessageEvent.ptr2 = l1;
711 xev.ClientMessageEvent.ptr3 = l2;
712 XSendEvent(DisplayHandle, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev);
715 // For WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN
716 // WM_CREATE and WM_DESTROY causes
717 void SendParentNotify(IntPtr child, Msg cause, int x, int y)
719 Hwnd hwnd;
721 if (child == IntPtr.Zero) {
722 return;
725 hwnd = Hwnd.GetObjectFromWindow (child);
727 if (hwnd == null) {
728 return;
731 if (hwnd.Handle == IntPtr.Zero) {
732 return;
735 if (ExStyleSet ((int) hwnd.initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY)) {
736 return;
739 if (hwnd.Parent == null) {
740 return;
743 if (hwnd.Parent.Handle == IntPtr.Zero) {
744 return;
747 if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) {
748 SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Control.MakeParam((int)cause, 0), child);
749 } else {
750 SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Control.MakeParam((int)cause, 0), Control.MakeParam(x, y));
753 SendParentNotify (hwnd.Parent.Handle, cause, x, y);
756 bool StyleSet (int s, WindowStyles ws)
758 return (s & (int)ws) == (int)ws;
761 bool ExStyleSet (int ex, WindowExStyles exws)
763 return (ex & (int)exws) == (int)exws;
766 internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd)
768 return TranslateClientRectangleToXClientRectangle (hwnd, Control.FromHandle (hwnd.Handle));
771 internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd, Control ctrl)
774 * If this is a form with no window manager, X is handling all the border and caption painting
775 * so remove that from the area (since the area we set of the window here is the part of the window
776 * we're painting in only)
778 Rectangle rect = hwnd.ClientRect;
779 Form form = ctrl as Form;
780 if (form != null && form.window_manager == null) {
781 CreateParams cp = form.GetCreateParams ();
782 Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
783 Rectangle xrect = rect;
785 xrect.Y -= borders.top;
786 xrect.X -= borders.left;
787 xrect.Width += borders.left + borders.right;
788 xrect.Height += borders.top + borders.bottom;
790 rect = xrect;
793 if (rect.Width < 1 || rect.Height < 1) {
794 rect.Width = 1;
795 rect.Height = 1;
796 rect.X = -5;
797 rect.Y = -5;
800 return rect;
803 internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp)
806 * If this is a form with no window manager, X is handling all the border and caption painting
807 * so remove that from the area (since the area we set of the window here is the part of the window
808 * we're painting in only)
810 Size rect = new Size (cp.Width, cp.Height);
811 Form form = cp.control as Form;
812 if (form != null && form.window_manager == null) {
813 Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
814 Size xrect = rect;
816 xrect.Width -= borders.left + borders.right;
817 xrect.Height -= borders.top + borders.bottom;
819 rect = xrect;
821 if (rect.Height == 0)
822 rect.Height = 1;
823 if (rect.Width == 0)
824 rect.Width = 1;
825 return rect;
828 internal static Size TranslateXWindowSizeToWindowSize (CreateParams cp, int xWidth, int xHeight)
831 * If this is a form with no window manager, X is handling all the border and caption painting
832 * so remove that from the area (since the area we set of the window here is the part of the window
833 * we're painting in only)
835 Size rect = new Size (xWidth, xHeight);
836 Form form = cp.control as Form;
837 if (form != null && form.window_manager == null) {
838 Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
839 Size xrect = rect;
841 xrect.Width += borders.left + borders.right;
842 xrect.Height += borders.top + borders.bottom;
844 rect = xrect;
846 return rect;
849 internal static Point GetTopLevelWindowLocation (Hwnd hwnd)
851 IntPtr dummy;
852 int x, y;
853 Hwnd.Borders frame;
855 XTranslateCoordinates (DisplayHandle, hwnd.whole_window, RootWindow, 0, 0, out x, out y, out dummy);
856 frame = FrameExtents (hwnd.whole_window);
858 x -= frame.left;
859 y -= frame.top;
861 return new Point (x, y);
864 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) {
866 caption_height = 0;
867 tool_caption_height = 19;
868 border_static = false;
870 if (StyleSet (Style, WindowStyles.WS_CHILD)) {
871 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) {
872 border_style = FormBorderStyle.Fixed3D;
873 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
874 border_style = FormBorderStyle.Fixed3D;
875 border_static = true;
876 } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) {
877 border_style = FormBorderStyle.None;
878 } else {
879 border_style = FormBorderStyle.FixedSingle;
881 title_style = TitleStyle.None;
883 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
884 caption_height = 19;
885 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
886 title_style = TitleStyle.Tool;
887 } else {
888 title_style = TitleStyle.Normal;
892 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) {
893 caption_height = 19;
895 if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) ||
896 ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
897 border_style = (FormBorderStyle) 0xFFFF;
898 } else {
899 border_style = FormBorderStyle.None;
903 } else {
904 title_style = TitleStyle.None;
905 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
906 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
907 title_style = TitleStyle.Tool;
908 } else {
909 title_style = TitleStyle.Normal;
913 border_style = FormBorderStyle.None;
915 if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) {
916 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
917 border_style = FormBorderStyle.SizableToolWindow;
918 } else {
919 border_style = FormBorderStyle.Sizable;
921 } else {
922 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
923 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) {
924 border_style = FormBorderStyle.Fixed3D;
925 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
926 border_style = FormBorderStyle.Fixed3D;
927 border_static = true;
928 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
929 border_style = FormBorderStyle.FixedDialog;
930 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
931 border_style = FormBorderStyle.FixedToolWindow;
932 } else if (StyleSet (Style, WindowStyles.WS_BORDER)) {
933 border_style = FormBorderStyle.FixedSingle;
935 } else {
936 if (StyleSet (Style, WindowStyles.WS_BORDER)) {
937 border_style = FormBorderStyle.FixedSingle;
944 private void SetHwndStyles(Hwnd hwnd, CreateParams cp) {
945 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);
948 private void SetWMStyles(Hwnd hwnd, CreateParams cp) {
949 MotifWmHints mwmHints;
950 MotifFunctions functions;
951 MotifDecorations decorations;
952 int[] atoms;
953 int atom_count;
954 Rectangle client_rect;
955 Form form;
956 IntPtr window_type;
957 bool hide_from_taskbar;
958 IntPtr transient_for_parent;
960 // Windows we manage ourselves don't need WM window styles.
961 if (cp.HasWindowManager && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
962 return;
965 atoms = new int[8];
966 mwmHints = new MotifWmHints();
967 functions = 0;
968 decorations = 0;
969 window_type = _NET_WM_WINDOW_TYPE_NORMAL;
970 transient_for_parent = IntPtr.Zero;
972 mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
973 mwmHints.functions = (IntPtr)0;
974 mwmHints.decorations = (IntPtr)0;
976 form = cp.control as Form;
978 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
979 /* tool windows get no window manager
980 decorations.
983 /* just because the window doesn't get any decorations doesn't
984 mean we should disable the functions. for instance, without
985 MotifFunctions.Maximize, changing the windowstate to Maximized
986 is ignored by metacity. */
987 functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
988 } else if (form != null && form.FormBorderStyle == FormBorderStyle.None) {
989 // No functions nor decorations whatsoever.
990 } else {
991 if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
992 functions |= MotifFunctions.Move;
993 decorations |= MotifDecorations.Title | MotifDecorations.Menu;
996 if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) {
997 functions |= MotifFunctions.Move | MotifFunctions.Resize;
998 decorations |= MotifDecorations.Border | MotifDecorations.ResizeH;
1001 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) {
1002 functions |= MotifFunctions.Minimize;
1003 decorations |= MotifDecorations.Minimize;
1006 if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) {
1007 functions |= MotifFunctions.Maximize;
1008 decorations |= MotifDecorations.Maximize;
1011 if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) {
1012 functions |= MotifFunctions.Resize;
1013 decorations |= MotifDecorations.ResizeH;
1016 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
1017 decorations |= MotifDecorations.Border;
1020 if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) {
1021 decorations |= MotifDecorations.Border;
1024 if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) {
1025 decorations |= MotifDecorations.Border;
1028 if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) {
1029 functions |= MotifFunctions.Close;
1031 else {
1032 functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close);
1033 decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize);
1034 if (cp.Caption == "") {
1035 functions &= ~MotifFunctions.Move;
1036 decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH);
1041 if ((functions & MotifFunctions.Resize) == 0) {
1042 hwnd.fixed_size = true;
1043 Rectangle fixed_rectangle = new Rectangle (cp.X, cp.Y, cp.Width, cp.Height);
1044 SetWindowMinMax(hwnd.Handle, fixed_rectangle, fixed_rectangle.Size, fixed_rectangle.Size, cp);
1045 } else {
1046 hwnd.fixed_size = false;
1049 mwmHints.functions = (IntPtr)functions;
1050 mwmHints.decorations = (IntPtr)decorations;
1052 #if debug
1053 Console.WriteLine ("SetWMStyles ({0}, {1}) functions = {2}, decorations = {3}", hwnd, cp, functions, decorations);
1054 #endif
1056 if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
1057 // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
1058 // and get those windows in front of their parents
1059 window_type = _NET_WM_WINDOW_TYPE_UTILITY;
1060 } else if (form != null && form.Modal) {
1061 window_type = _NET_WM_WINDOW_TYPE_DIALOG;
1062 } else {
1063 window_type = _NET_WM_WINDOW_TYPE_NORMAL;
1066 if (!cp.IsSet (WindowExStyles.WS_EX_APPWINDOW)) {
1067 hide_from_taskbar = true;
1068 } else if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW) && form != null && form.Parent != null && !form.ShowInTaskbar) {
1069 hide_from_taskbar = true;
1070 } else {
1071 hide_from_taskbar = false;
1074 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
1075 if (form != null && !hwnd.reparented) {
1076 if (form.Owner != null && form.Owner.Handle != IntPtr.Zero) {
1077 Hwnd owner_hwnd = Hwnd.ObjectFromHandle (form.Owner.Handle);
1078 if (owner_hwnd != null)
1079 transient_for_parent = owner_hwnd.whole_window;
1083 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
1084 transient_for_parent = hwnd.parent.whole_window;
1087 FormWindowState current_state = GetWindowState (hwnd.Handle);
1088 if (current_state == (FormWindowState)(-1))
1089 current_state = FormWindowState.Normal;
1091 client_rect = TranslateClientRectangleToXClientRectangle (hwnd);
1093 lock (XlibLock) {
1094 atom_count = 0;
1096 atoms [0] = window_type.ToInt32 ();
1097 XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
1099 XChangeProperty(DisplayHandle, hwnd.whole_window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref mwmHints, 5);
1101 if (transient_for_parent != IntPtr.Zero) {
1102 XSetTransientForHint (DisplayHandle, hwnd.whole_window, transient_for_parent);
1105 XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
1107 if (hide_from_taskbar) {
1108 /* this line keeps the window from showing up in gnome's taskbar */
1109 atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
1111 /* we need to add these atoms in the
1112 * event we're maximized, since we're
1113 * replacing the existing
1114 * _NET_WM_STATE here. If we don't
1115 * add them, future calls to
1116 * GetWindowState will return Normal
1117 * for a window which is maximized. */
1118 if (current_state == FormWindowState.Maximized) {
1119 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_HORZ.ToInt32();
1120 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_VERT.ToInt32();
1123 if (form != null && form.Modal) {
1124 atoms[atom_count++] = _NET_WM_STATE_MODAL.ToInt32 ();
1127 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
1129 atom_count = 0;
1130 IntPtr[] atom_ptrs = new IntPtr[2];
1131 atom_ptrs[atom_count++] = WM_DELETE_WINDOW;
1132 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP)) {
1133 atom_ptrs[atom_count++] = _NET_WM_CONTEXT_HELP;
1136 XSetWMProtocols(DisplayHandle, hwnd.whole_window, atom_ptrs, atom_count);
1140 private void SetIcon(Hwnd hwnd, Icon icon)
1142 if (icon == null) {
1143 // XXX
1145 // This really needs to do whatever it
1146 // takes to remove the window manager
1147 // menu, not just delete the ICON
1148 // property. This will cause metacity
1149 // to use the "no icon set" icon, and
1150 // we'll still have an icon.
1151 XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_ICON);
1153 else {
1154 Bitmap bitmap;
1155 int size;
1156 IntPtr[] data;
1157 int index;
1159 bitmap = icon.ToBitmap();
1160 index = 0;
1161 size = bitmap.Width * bitmap.Height + 2;
1162 data = new IntPtr[size];
1164 data[index++] = (IntPtr)bitmap.Width;
1165 data[index++] = (IntPtr)bitmap.Height;
1167 for (int y = 0; y < bitmap.Height; y++) {
1168 for (int x = 0; x < bitmap.Width; x++) {
1169 data[index++] = (IntPtr)bitmap.GetPixel (x, y).ToArgb ();
1173 XChangeProperty (DisplayHandle, hwnd.whole_window,
1174 _NET_WM_ICON, (IntPtr)Atom.XA_CARDINAL, 32,
1175 PropertyMode.Replace, data, size);
1179 private void WakeupMain () {
1180 wake.Send (new byte [] { 0xFF });
1183 private XEventQueue ThreadQueue(Thread thread) {
1184 XEventQueue queue;
1186 queue = (XEventQueue)MessageQueues[thread];
1187 if (queue == null) {
1188 queue = new XEventQueue(thread);
1189 MessageQueues[thread] = queue;
1192 return queue;
1195 private void TranslatePropertyToClipboard(IntPtr property) {
1196 IntPtr actual_atom;
1197 int actual_format;
1198 IntPtr nitems;
1199 IntPtr bytes_after;
1200 IntPtr prop = IntPtr.Zero;
1202 Clipboard.Item = null;
1204 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);
1206 if ((long)nitems > 0) {
1207 if (property == (IntPtr)Atom.XA_STRING) {
1208 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1209 } else if (property == (IntPtr)Atom.XA_BITMAP) {
1210 // FIXME - convert bitmap to image
1211 } else if (property == (IntPtr)Atom.XA_PIXMAP) {
1212 // FIXME - convert pixmap to image
1213 } else if (property == OEMTEXT) {
1214 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1215 } else if (property == UNICODETEXT) {
1216 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1219 XFree(prop);
1223 private void AddExpose (Hwnd hwnd, bool client, int x, int y, int width, int height) {
1224 // Don't waste time
1225 if ((hwnd == null) || (x > hwnd.Width) || (y > hwnd.Height) || ((x + width) < 0) || ((y + height) < 0)) {
1226 return;
1229 // Keep the invalid area as small as needed
1230 if ((x + width) > hwnd.width) {
1231 width = hwnd.width - x;
1234 if ((y + height) > hwnd.height) {
1235 height = hwnd.height - y;
1238 if (client) {
1239 hwnd.AddInvalidArea(x, y, width, height);
1240 if (!hwnd.expose_pending) {
1241 if (!hwnd.nc_expose_pending) {
1242 hwnd.Queue.Paint.Enqueue(hwnd);
1244 hwnd.expose_pending = true;
1246 } else {
1247 hwnd.AddNcInvalidArea (x, y, width, height);
1249 if (!hwnd.nc_expose_pending) {
1250 if (!hwnd.expose_pending) {
1251 hwnd.Queue.Paint.Enqueue(hwnd);
1253 hwnd.nc_expose_pending = true;
1258 private static Hwnd.Borders FrameExtents (IntPtr window)
1260 IntPtr actual_atom;
1261 int actual_format;
1262 IntPtr nitems;
1263 IntPtr bytes_after;
1264 IntPtr prop = IntPtr.Zero;
1265 Hwnd.Borders rect = new Hwnd.Borders ();
1267 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);
1268 if (prop != IntPtr.Zero) {
1269 if (nitems.ToInt32 () == 4) {
1270 rect.left = Marshal.ReadInt32 (prop, 0);
1271 rect.right = Marshal.ReadInt32 (prop, IntPtr.Size);
1272 rect.top = Marshal.ReadInt32 (prop, 2 * IntPtr.Size);
1273 rect.bottom = Marshal.ReadInt32 (prop, 3 * IntPtr.Size);
1275 XFree (prop);
1278 return rect;
1281 private void AddConfigureNotify (XEvent xevent) {
1282 Hwnd hwnd;
1284 hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window);
1286 // Don't waste time
1287 if (hwnd == null || hwnd.zombie) {
1288 return;
1290 if ((xevent.ConfigureEvent.window == hwnd.whole_window)/* && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)*/) {
1291 if (hwnd.parent == null) {
1292 // The location given by the event is not reliable between different wm's,
1293 // so use an alternative way of getting it.
1294 Point location = GetTopLevelWindowLocation (hwnd);
1295 hwnd.x = location.X;
1296 hwnd.y = location.Y;
1299 // XXX this sucks. this isn't thread safe
1300 Control ctrl = Control.FromHandle (hwnd.Handle);
1301 Size TranslatedSize;
1302 if (ctrl != null) {
1303 TranslatedSize = TranslateXWindowSizeToWindowSize (ctrl.GetCreateParams (), xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
1304 } else {
1305 TranslatedSize = new Size (xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
1307 hwnd.width = TranslatedSize.Width;
1308 hwnd.height = TranslatedSize.Height;
1309 hwnd.ClientRect = Rectangle.Empty;
1311 #if debug
1312 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));
1313 #endif
1314 lock (hwnd.configure_lock) {
1315 if (!hwnd.configure_pending) {
1316 hwnd.Queue.EnqueueLocked (xevent);
1317 hwnd.configure_pending = true;
1321 // We drop configure events for Client windows
1324 private void ShowCaret() {
1325 if ((Caret.gc == IntPtr.Zero) || Caret.On) {
1326 return;
1328 Caret.On = true;
1330 lock (XlibLock) {
1331 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1335 private void HideCaret() {
1336 if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
1337 return;
1339 Caret.On = false;
1341 lock (XlibLock) {
1342 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1346 private int NextTimeout (ArrayList timers, DateTime now) {
1347 int timeout = Int32.MaxValue;
1349 foreach (Timer timer in timers) {
1350 int next = (int) (timer.Expires - now).TotalMilliseconds;
1351 if (next < 0) {
1352 return 0; // Have a timer that has already expired
1355 if (next < timeout) {
1356 timeout = next;
1359 if (timeout < Timer.Minimum) {
1360 timeout = Timer.Minimum;
1363 if (timeout > 1000)
1364 timeout = 1000;
1365 return timeout;
1368 private void CheckTimers (ArrayList timers, DateTime now) {
1369 int count;
1371 count = timers.Count;
1373 if (count == 0)
1374 return;
1376 for (int i = 0; i < timers.Count; i++) {
1377 Timer timer;
1379 timer = (Timer) timers [i];
1381 if (timer.Enabled && timer.Expires <= now) {
1382 timer.Update (now);
1383 timer.FireTick ();
1388 private void WaitForHwndMessage (Hwnd hwnd, Msg message) {
1389 MSG msg = new MSG ();
1390 XEventQueue queue;
1392 queue = ThreadQueue(Thread.CurrentThread);
1394 queue.DispatchIdle = false;
1396 bool done = false;
1397 do {
1398 if (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
1399 if ((Msg)msg.message == Msg.WM_QUIT) {
1400 PostQuitMessage (0);
1401 done = true;
1403 else {
1404 if (msg.hwnd == hwnd.Handle) {
1405 if ((Msg)msg.message == message)
1406 break;
1407 else if ((Msg)msg.message == Msg.WM_DESTROY)
1408 done = true;
1411 TranslateMessage (ref msg);
1412 DispatchMessage (ref msg);
1415 } while (!done);
1417 queue.DispatchIdle = true;
1421 private void MapWindow(Hwnd hwnd, WindowType windows) {
1422 if (!hwnd.mapped) {
1423 if (Control.FromHandle(hwnd.Handle) is Form) {
1424 Form f = Control.FromHandle(hwnd.Handle) as Form;
1425 if (f.WindowState == FormWindowState.Normal)
1426 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
1429 // it's possible that our Hwnd is no
1430 // longer valid after making that
1431 // SendMessage call, so check here.
1432 if (hwnd.zombie)
1433 return;
1435 bool need_to_wait = false;
1437 if ((windows & WindowType.Whole) != 0) {
1438 XMapWindow(DisplayHandle, hwnd.whole_window);
1440 if ((windows & WindowType.Client) != 0) {
1441 XMapWindow(DisplayHandle, hwnd.client_window);
1443 need_to_wait = true;
1446 hwnd.mapped = true;
1448 if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
1449 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1453 private void UnmapWindow(Hwnd hwnd, WindowType windows) {
1454 if (hwnd.mapped) {
1455 if (Control.FromHandle(hwnd.Handle) is Form) {
1456 Form f = Control.FromHandle(hwnd.Handle) as Form;
1457 if (f.WindowState == FormWindowState.Normal)
1458 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
1461 // it's possible that our Hwnd is no
1462 // longer valid after making that
1463 // SendMessage call, so check here.
1464 if (hwnd.zombie)
1465 return;
1467 bool need_to_wait = false;
1469 if ((windows & WindowType.Client) != 0) {
1470 XUnmapWindow(DisplayHandle, hwnd.client_window);
1472 need_to_wait = true;
1474 if ((windows & WindowType.Whole) != 0) {
1475 XUnmapWindow(DisplayHandle, hwnd.whole_window);
1478 hwnd.mapped = false;
1480 if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
1481 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1485 private void UpdateMessageQueue (XEventQueue queue) {
1486 DateTime now;
1487 int pending;
1488 Hwnd hwnd;
1490 now = DateTime.UtcNow;
1492 lock (XlibLock) {
1493 pending = XPending (DisplayHandle);
1496 if (pending == 0) {
1497 if ((queue == null || queue.DispatchIdle) && Idle != null) {
1498 Idle (this, EventArgs.Empty);
1501 lock (XlibLock) {
1502 pending = XPending (DisplayHandle);
1506 if (pending == 0) {
1507 int timeout = 0;
1509 if (queue != null) {
1510 if (queue.Paint.Count > 0)
1511 return;
1513 timeout = NextTimeout (queue.timer_list, now);
1516 if (timeout > 0) {
1517 #if __MonoCS__
1518 int length = pollfds.Length - 1;
1519 lock (wake_waiting_lock) {
1520 if (wake_waiting == false) {
1521 length ++;
1522 wake_waiting = true;
1526 Syscall.poll (pollfds, (uint)length, timeout);
1527 // Clean out buffer, so we're not busy-looping on the same data
1528 if (length == pollfds.Length) {
1529 if (pollfds[1].revents != 0)
1530 wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
1531 lock (wake_waiting_lock) {
1532 wake_waiting = false;
1535 #endif
1536 lock (XlibLock) {
1537 pending = XPending (DisplayHandle);
1542 if (queue != null)
1543 CheckTimers (queue.timer_list, now);
1545 while (true) {
1546 XEvent xevent = new XEvent ();
1548 lock (XlibLock) {
1549 if (XPending (DisplayHandle) == 0)
1550 break;
1552 XNextEvent (DisplayHandle, ref xevent);
1554 if (xevent.AnyEvent.type == XEventName.KeyPress) {
1555 if (XFilterEvent(ref xevent, FosterParent)) {
1556 continue;
1561 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
1562 if (hwnd == null)
1563 continue;
1565 #if debug
1566 Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
1567 #endif
1568 switch (xevent.type) {
1569 case XEventName.Expose:
1570 AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
1571 break;
1573 case XEventName.SelectionClear: {
1574 // Should we do something?
1575 break;
1578 case XEventName.SelectionRequest: {
1579 if (Dnd.HandleSelectionRequestEvent (ref xevent))
1580 break;
1581 XEvent sel_event;
1583 sel_event = new XEvent();
1584 sel_event.SelectionEvent.type = XEventName.SelectionNotify;
1585 sel_event.SelectionEvent.send_event = true;
1586 sel_event.SelectionEvent.display = DisplayHandle;
1587 sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
1588 sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
1589 sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
1590 sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
1591 sel_event.SelectionEvent.property = IntPtr.Zero;
1593 // Seems that some apps support asking for supported types
1594 if (xevent.SelectionEvent.target == TARGETS) {
1595 int[] atoms;
1596 int atom_count;
1598 atoms = new int[5];
1599 atom_count = 0;
1601 if (Clipboard.Item is String) {
1602 atoms[atom_count++] = (int)Atom.XA_STRING;
1603 atoms[atom_count++] = (int)OEMTEXT;
1604 atoms[atom_count++] = (int)UNICODETEXT;
1605 } else if (Clipboard.Item is Image) {
1606 atoms[atom_count++] = (int)Atom.XA_PIXMAP;
1607 atoms[atom_count++] = (int)Atom.XA_BITMAP;
1608 } else {
1609 // FIXME - handle other types
1612 XChangeProperty(DisplayHandle, xevent.SelectionEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
1613 } else if (Clipboard.Item is string) {
1614 IntPtr buffer;
1615 int buflen;
1617 buflen = 0;
1619 if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) {
1620 Byte[] bytes;
1622 bytes = new ASCIIEncoding().GetBytes((string)Clipboard.Item);
1623 buffer = Marshal.AllocHGlobal(bytes.Length);
1624 buflen = bytes.Length;
1626 for (int i = 0; i < buflen; i++) {
1627 Marshal.WriteByte(buffer, i, bytes[i]);
1629 } else if (xevent.SelectionRequestEvent.target == OEMTEXT) {
1630 // FIXME - this should encode into ISO2022
1631 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1632 while (Marshal.ReadByte(buffer, buflen) != 0) {
1633 buflen++;
1635 } else if (xevent.SelectionRequestEvent.target == UNICODETEXT) {
1636 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1637 while (Marshal.ReadByte(buffer, buflen) != 0) {
1638 buflen++;
1640 } else {
1641 buffer = IntPtr.Zero;
1644 if (buffer != IntPtr.Zero) {
1645 XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
1646 sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
1647 Marshal.FreeHGlobal(buffer);
1649 } else if (Clipboard.Item is Image) {
1650 if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1651 // FIXME - convert image and store as property
1652 } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1653 // FIXME - convert image and store as property
1657 XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event);
1658 break;
1661 case XEventName.SelectionNotify: {
1662 if (Clipboard.Enumerating) {
1663 Clipboard.Enumerating = false;
1664 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1665 XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property);
1666 if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) {
1667 Clipboard.Formats.Add(xevent.SelectionEvent.property);
1668 #if DriverDebugExtra
1669 Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
1670 #endif
1673 } else if (Clipboard.Retrieving) {
1674 Clipboard.Retrieving = false;
1675 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1676 TranslatePropertyToClipboard(xevent.SelectionEvent.property);
1677 } else {
1678 Clipboard.Item = null;
1680 } else {
1681 Dnd.HandleSelectionNotifyEvent (ref xevent);
1683 break;
1686 case XEventName.KeyRelease:
1687 if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) {
1688 XEvent nextevent = new XEvent ();
1690 XPeekEvent (DisplayHandle, ref nextevent);
1692 if (nextevent.type == XEventName.KeyPress &&
1693 nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
1694 nextevent.KeyEvent.time == xevent.KeyEvent.time) {
1695 continue;
1698 goto case XEventName.KeyPress;
1700 case XEventName.MotionNotify: {
1701 XEvent peek;
1703 /* we can't do motion compression across threads, so just punt if we don't match up */
1704 if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) {
1705 peek = hwnd.Queue.Peek();
1706 if (peek.AnyEvent.type == XEventName.MotionNotify) {
1707 continue;
1710 goto case XEventName.KeyPress;
1713 case XEventName.KeyPress:
1714 case XEventName.ButtonPress:
1715 case XEventName.ButtonRelease:
1716 case XEventName.EnterNotify:
1717 case XEventName.LeaveNotify:
1718 case XEventName.CreateNotify:
1719 case XEventName.DestroyNotify:
1720 case XEventName.FocusIn:
1721 case XEventName.FocusOut:
1722 case XEventName.ClientMessage:
1723 case XEventName.ReparentNotify:
1724 case XEventName.MapNotify:
1725 case XEventName.UnmapNotify:
1726 hwnd.Queue.EnqueueLocked (xevent);
1727 break;
1729 case XEventName.ConfigureNotify:
1730 AddConfigureNotify(xevent);
1731 break;
1733 case XEventName.PropertyNotify:
1734 #if debug
1735 Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
1736 #endif
1737 if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) {
1738 IntPtr actual_atom;
1739 int actual_format;
1740 IntPtr nitems;
1741 IntPtr bytes_after;
1742 IntPtr prop = IntPtr.Zero;
1743 IntPtr prev_active;
1745 prev_active = ActiveWindow;
1746 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);
1747 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
1748 ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop));
1749 XFree(prop);
1751 if (prev_active != ActiveWindow) {
1752 if (prev_active != IntPtr.Zero) {
1753 PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1755 if (ActiveWindow != IntPtr.Zero) {
1756 PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
1759 if (ModalWindows.Count == 0) {
1760 break;
1761 } else {
1762 // Modality handling, if we are modal and the new active window is one
1763 // of ours but not the modal one, switch back to the modal window
1765 if (NativeWindow.FindWindow(ActiveWindow) != null) {
1766 if (ActiveWindow != (IntPtr)ModalWindows.Peek()) {
1767 Activate((IntPtr)ModalWindows.Peek());
1770 break;
1774 else if (xevent.PropertyEvent.atom == _NET_WM_STATE) {
1775 // invalidate our cache - we'll query again the next time someone does GetWindowState.
1776 hwnd.cached_window_state = (FormWindowState)(-1);
1778 break;
1784 private IntPtr GetMousewParam(int Delta) {
1785 int result = 0;
1787 if ((MouseState & MouseButtons.Left) != 0) {
1788 result |= (int)MsgButtons.MK_LBUTTON;
1791 if ((MouseState & MouseButtons.Middle) != 0) {
1792 result |= (int)MsgButtons.MK_MBUTTON;
1795 if ((MouseState & MouseButtons.Right) != 0) {
1796 result |= (int)MsgButtons.MK_RBUTTON;
1799 Keys mods = ModifierKeys;
1800 if ((mods & Keys.Control) != 0) {
1801 result |= (int)MsgButtons.MK_CONTROL;
1804 if ((mods & Keys.Shift) != 0) {
1805 result |= (int)MsgButtons.MK_SHIFT;
1808 result |= Delta << 16;
1810 return (IntPtr)result;
1812 private IntPtr XGetParent(IntPtr handle) {
1813 IntPtr Root;
1814 IntPtr Parent;
1815 IntPtr Children;
1816 int ChildCount;
1818 lock (XlibLock) {
1819 XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount);
1822 if (Children!=IntPtr.Zero) {
1823 lock (XlibLock) {
1824 XFree(Children);
1827 return Parent;
1830 private int HandleError (IntPtr display, ref XErrorEvent error_event)
1832 // we need to workaround a problem with the
1833 // ordering of destruction of Drawables and
1834 // Pictures that exists between cairo and
1835 // RENDER on the server.
1836 if (error_event.request_code == (XRequest)render_major_opcode
1837 && error_event.minor_code == 7 /* X_RenderFreePicture from render.h */
1838 && error_event.error_code == render_first_error + 1 /* BadPicture from render.h */) {
1839 return 0;
1842 if (ErrorExceptions) {
1843 XUngrabPointer (display, IntPtr.Zero);
1844 throw new XException (error_event.display, error_event.resourceid,
1845 error_event.serial, error_event.error_code,
1846 error_event.request_code, error_event.minor_code);
1847 } else {
1848 Console.WriteLine("X11 Error encountered: {0}{1}\n",
1849 XException.GetMessage (error_event.display, error_event.resourceid,
1850 error_event.serial, error_event.error_code,
1851 error_event.request_code, error_event.minor_code),
1852 Environment.StackTrace);
1854 return 0;
1857 private void AccumulateDestroyedHandles (Control c, ArrayList list)
1859 if (c != null) {
1860 Control[] controls = c.Controls.GetAllControls ();
1862 if (c.IsHandleCreated && !c.IsDisposed) {
1863 Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle);
1865 #if DriverDebug || DriverDebugDestroy
1866 Console.WriteLine (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
1867 Console.WriteLine (" + parent X window is {0:X}", XGetParent (hwnd.whole_window).ToInt32());
1868 #endif
1870 list.Add (hwnd);
1871 CleanupCachedWindows (hwnd);
1874 for (int i = 0; i < controls.Length; i ++) {
1875 AccumulateDestroyedHandles (controls[i], list);
1881 void CleanupCachedWindows (Hwnd hwnd)
1883 if (ActiveWindow == hwnd.Handle) {
1884 SendMessage(hwnd.client_window, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1885 ActiveWindow = IntPtr.Zero;
1888 if (FocusWindow == hwnd.Handle) {
1889 SendMessage(hwnd.client_window, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
1890 FocusWindow = IntPtr.Zero;
1893 if (Grab.Hwnd == hwnd.Handle) {
1894 Grab.Hwnd = IntPtr.Zero;
1895 Grab.Confined = false;
1898 DestroyCaret (hwnd.Handle);
1901 private void PerformNCCalc(Hwnd hwnd) {
1902 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
1903 IntPtr ptr;
1904 Rectangle rect;
1906 rect = new Rectangle (0, 0, hwnd.Width, hwnd.Height);
1908 ncp = new XplatUIWin32.NCCALCSIZE_PARAMS();
1909 ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp));
1911 ncp.rgrc1.left = rect.Left;
1912 ncp.rgrc1.top = rect.Top;
1913 ncp.rgrc1.right = rect.Right;
1914 ncp.rgrc1.bottom = rect.Bottom;
1916 Marshal.StructureToPtr(ncp, ptr, true);
1917 NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr);
1918 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
1919 Marshal.FreeHGlobal(ptr);
1922 rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
1923 hwnd.ClientRect = rect;
1925 rect = TranslateClientRectangleToXClientRectangle (hwnd);
1927 if (hwnd.visible) {
1928 XMoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
1931 AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
1933 #endregion // Private Methods
1935 #region Callbacks
1936 private void MouseHover(object sender, EventArgs e) {
1937 XEvent xevent;
1938 Hwnd hwnd;
1940 HoverState.Timer.Enabled = false;
1942 if (HoverState.Window != IntPtr.Zero) {
1943 hwnd = Hwnd.GetObjectFromWindow(HoverState.Window);
1944 if (hwnd != null) {
1945 xevent = new XEvent ();
1947 xevent.type = XEventName.ClientMessage;
1948 xevent.ClientMessageEvent.display = DisplayHandle;
1949 xevent.ClientMessageEvent.window = HoverState.Window;
1950 xevent.ClientMessageEvent.message_type = HoverState.Atom;
1951 xevent.ClientMessageEvent.format = 32;
1952 xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
1954 hwnd.Queue.EnqueueLocked (xevent);
1956 WakeupMain ();
1961 private void CaretCallback(object sender, EventArgs e) {
1962 if (Caret.Paused) {
1963 return;
1965 Caret.On = !Caret.On;
1967 XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1969 #endregion // Callbacks
1971 #region Public Properties
1973 internal override int CaptionHeight {
1974 get {
1975 return 19;
1979 internal override Size CursorSize {
1980 get {
1981 int x;
1982 int y;
1984 if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) {
1985 return new Size(x, y);
1986 } else {
1987 return new Size(16, 16);
1992 internal override bool DragFullWindows {
1993 get {
1994 return true;
1998 internal override Size DragSize {
1999 get {
2000 return new Size(4, 4);
2004 internal override Size FrameBorderSize {
2005 get {
2006 return new Size (4, 4);
2010 internal override Size IconSize {
2011 get {
2012 IntPtr list;
2013 XIconSize size;
2014 int count;
2016 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
2017 long current;
2018 int largest;
2020 current = (long)list;
2021 largest = 0;
2023 size = new XIconSize();
2025 for (int i = 0; i < count; i++) {
2026 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
2027 current += Marshal.SizeOf(size);
2029 // Look for our preferred size
2030 if (size.min_width == 32) {
2031 XFree(list);
2032 return new Size(32, 32);
2035 if (size.max_width == 32) {
2036 XFree(list);
2037 return new Size(32, 32);
2040 if (size.min_width < 32 && size.max_width > 32) {
2041 int x;
2043 // check if we can fit one
2044 x = size.min_width;
2045 while (x < size.max_width) {
2046 x += size.width_inc;
2047 if (x == 32) {
2048 XFree(list);
2049 return new Size(32, 32);
2054 if (largest < size.max_width) {
2055 largest = size.max_width;
2059 // We didn't find a match or we wouldn't be here
2060 return new Size(largest, largest);
2062 } else {
2063 return new Size(32, 32);
2068 internal override int KeyboardSpeed {
2069 get{
2071 // A lot harder: need to do:
2072 // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
2073 // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
2074 // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
2076 // And from that we can tell the repetition rate
2078 // Notice, the values must map to:
2079 // [0, 31] which maps to 2.5 to 30 repetitions per second.
2081 return 0;
2085 internal override int KeyboardDelay {
2086 get {
2088 // Return values must range from 0 to 4, 0 meaning 250ms,
2089 // and 4 meaning 1000 ms.
2091 return 1; // ie, 500 ms
2095 internal override Size MaxWindowTrackSize {
2096 get {
2097 return new Size (WorkingArea.Width, WorkingArea.Height);
2101 internal override bool MenuAccessKeysUnderlined {
2102 get {
2103 return false;
2107 internal override Size MinimizedWindowSize {
2108 get {
2109 return new Size(1, 1);
2113 internal override Size MinimizedWindowSpacingSize {
2114 get {
2115 return new Size(1, 1);
2119 internal override Size MinimumWindowSize {
2120 get {
2121 return new Size(1, 1);
2125 internal override Size MinWindowTrackSize {
2126 get {
2127 return new Size(1, 1);
2131 internal override Keys ModifierKeys {
2132 get {
2133 return Keyboard.ModifierKeys;
2137 internal override Size SmallIconSize {
2138 get {
2139 IntPtr list;
2140 XIconSize size;
2141 int count;
2143 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
2144 long current;
2145 int smallest;
2147 current = (long)list;
2148 smallest = 0;
2150 size = new XIconSize();
2152 for (int i = 0; i < count; i++) {
2153 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
2154 current += Marshal.SizeOf(size);
2156 // Look for our preferred size
2157 if (size.min_width == 16) {
2158 XFree(list);
2159 return new Size(16, 16);
2162 if (size.max_width == 16) {
2163 XFree(list);
2164 return new Size(16, 16);
2167 if (size.min_width < 16 && size.max_width > 16) {
2168 int x;
2170 // check if we can fit one
2171 x = size.min_width;
2172 while (x < size.max_width) {
2173 x += size.width_inc;
2174 if (x == 16) {
2175 XFree(list);
2176 return new Size(16, 16);
2181 if (smallest == 0 || smallest > size.min_width) {
2182 smallest = size.min_width;
2186 // We didn't find a match or we wouldn't be here
2187 return new Size(smallest, smallest);
2189 } else {
2190 return new Size(16, 16);
2195 internal override int MouseButtonCount {
2196 get {
2197 return 3;
2201 internal override bool MouseButtonsSwapped {
2202 get {
2203 return false; // FIXME - how to detect?
2207 internal override Point MousePosition {
2208 get {
2209 return mouse_position;
2213 internal override Size MouseHoverSize {
2214 get {
2215 return new Size (1, 1);
2219 internal override int MouseHoverTime {
2220 get {
2221 return HoverState.Interval;
2227 internal override bool MouseWheelPresent {
2228 get {
2229 return true; // FIXME - how to detect?
2233 internal override Rectangle VirtualScreen {
2234 get {
2235 IntPtr actual_atom;
2236 int actual_format;
2237 IntPtr nitems;
2238 IntPtr bytes_after;
2239 IntPtr prop = IntPtr.Zero;
2240 int width;
2241 int height;
2243 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);
2244 if ((long)nitems < 2)
2245 goto failsafe;
2247 width = Marshal.ReadIntPtr(prop, 0).ToInt32();
2248 height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
2250 XFree(prop);
2252 return new Rectangle(0, 0, width, height);
2254 failsafe:
2255 XWindowAttributes attributes=new XWindowAttributes();
2257 lock (XlibLock) {
2258 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2261 return new Rectangle(0, 0, attributes.width, attributes.height);
2265 internal override Rectangle WorkingArea {
2266 get {
2267 IntPtr actual_atom;
2268 int actual_format;
2269 IntPtr nitems;
2270 IntPtr bytes_after;
2271 IntPtr prop = IntPtr.Zero;
2272 int width;
2273 int height;
2274 int current_desktop;
2275 int x;
2276 int y;
2278 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);
2279 if ((long)nitems < 1) {
2280 goto failsafe;
2283 current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
2284 XFree(prop);
2286 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);
2287 if ((long)nitems < 4 * current_desktop) {
2288 goto failsafe;
2291 x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
2292 y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
2293 width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
2294 height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
2295 XFree(prop);
2297 return new Rectangle(x, y, width, height);
2299 failsafe:
2300 XWindowAttributes attributes=new XWindowAttributes();
2302 lock (XlibLock) {
2303 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2306 return new Rectangle(0, 0, attributes.width, attributes.height);
2310 internal override bool ThemesEnabled {
2311 get {
2312 return XplatUIX11.themes_enabled;
2317 #endregion // Public properties
2319 #region Public Static Methods
2320 internal override void RaiseIdle (EventArgs e)
2322 if (Idle != null)
2323 Idle (this, e);
2326 internal override IntPtr InitializeDriver() {
2327 lock (this) {
2328 if (DisplayHandle==IntPtr.Zero) {
2329 SetDisplay(XOpenDisplay(IntPtr.Zero));
2332 return IntPtr.Zero;
2335 internal override void ShutdownDriver(IntPtr token) {
2336 lock (this) {
2337 if (DisplayHandle!=IntPtr.Zero) {
2338 XCloseDisplay(DisplayHandle);
2339 DisplayHandle=IntPtr.Zero;
2344 internal override void EnableThemes() {
2345 themes_enabled = true;
2349 internal override void Activate(IntPtr handle) {
2350 Hwnd hwnd;
2352 hwnd = Hwnd.ObjectFromHandle(handle);
2354 if (hwnd != null) {
2355 lock (XlibLock) {
2356 if (true /* the window manager supports NET_ACTIVE_WINDOW */) {
2357 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
2359 // else {
2360 // XRaiseWindow(DisplayHandle, handle);
2361 // }
2366 internal override void AudibleAlert() {
2367 XBell(DisplayHandle, 0);
2368 return;
2372 internal override void CaretVisible(IntPtr handle, bool visible) {
2373 if (Caret.Hwnd == handle) {
2374 if (visible) {
2375 if (!Caret.Visible) {
2376 Caret.Visible = true;
2377 ShowCaret();
2378 Caret.Timer.Start();
2380 } else {
2381 Caret.Visible = false;
2382 Caret.Timer.Stop();
2383 HideCaret();
2388 internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) {
2389 WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect);
2390 return true;
2393 internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) {
2394 int dest_x_return;
2395 int dest_y_return;
2396 IntPtr child;
2397 Hwnd hwnd;
2399 hwnd = Hwnd.ObjectFromHandle(handle);
2401 lock (XlibLock) {
2402 XTranslateCoordinates(DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
2405 x = dest_x_return;
2406 y = dest_y_return;
2409 internal override int[] ClipboardAvailableFormats(IntPtr handle) {
2410 DataFormats.Format f;
2411 int[] result;
2413 f = DataFormats.Format.List;
2415 if (XGetSelectionOwner(DisplayHandle, CLIPBOARD) == IntPtr.Zero) {
2416 return null;
2419 Clipboard.Formats = new ArrayList();
2421 while (f != null) {
2422 XConvertSelection(DisplayHandle, CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent, IntPtr.Zero);
2424 Clipboard.Enumerating = true;
2425 while (Clipboard.Enumerating) {
2426 UpdateMessageQueue(null);
2428 f = f.Next;
2431 result = new int[Clipboard.Formats.Count];
2433 for (int i = 0; i < Clipboard.Formats.Count; i++) {
2434 result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
2437 Clipboard.Formats = null;
2438 return result;
2441 internal override void ClipboardClose(IntPtr handle) {
2442 if (handle != ClipMagic) {
2443 throw new ArgumentException("handle is not a valid clipboard handle");
2445 return;
2448 internal override int ClipboardGetID(IntPtr handle, string format) {
2449 if (handle != ClipMagic) {
2450 throw new ArgumentException("handle is not a valid clipboard handle");
2453 if (format == "Text" ) return (int)Atom.XA_STRING;
2454 else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP;
2455 //else if (format == "MetaFilePict" ) return 3;
2456 //else if (format == "SymbolicLink" ) return 4;
2457 //else if (format == "DataInterchangeFormat" ) return 5;
2458 //else if (format == "Tiff" ) return 6;
2459 else if (format == "OEMText" ) return OEMTEXT.ToInt32();
2460 else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP;
2461 else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless
2462 //else if (format == "PenData" ) return 10;
2463 //else if (format == "RiffAudio" ) return 11;
2464 //else if (format == "WaveAudio" ) return 12;
2465 else if (format == "UnicodeText" ) return UNICODETEXT.ToInt32();
2466 //else if (format == "EnhancedMetafile" ) return 14;
2467 //else if (format == "FileDrop" ) return 15;
2468 //else if (format == "Locale" ) return 16;
2470 return XInternAtom(DisplayHandle, format, false).ToInt32();
2473 internal override IntPtr ClipboardOpen(bool primary_selection) {
2474 if (!primary_selection)
2475 ClipMagic = CLIPBOARD;
2476 else
2477 ClipMagic = PRIMARY;
2478 return ClipMagic;
2481 internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) {
2482 XConvertSelection(DisplayHandle, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
2484 Clipboard.Retrieving = true;
2485 while (Clipboard.Retrieving) {
2486 UpdateMessageQueue(null);
2489 return Clipboard.Item;
2492 internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter) {
2493 Clipboard.Item = obj;
2494 Clipboard.Type = type;
2495 Clipboard.Converter = converter;
2497 if (obj != null) {
2498 XSetSelectionOwner(DisplayHandle, CLIPBOARD, FosterParent, IntPtr.Zero);
2499 } else {
2500 // Clearing the selection
2501 XSetSelectionOwner(DisplayHandle, CLIPBOARD, IntPtr.Zero, IntPtr.Zero);
2505 internal override void CreateCaret (IntPtr handle, int width, int height)
2507 XGCValues gc_values;
2508 Hwnd hwnd;
2510 hwnd = Hwnd.ObjectFromHandle(handle);
2512 if (Caret.Hwnd != IntPtr.Zero) {
2513 DestroyCaret(Caret.Hwnd);
2516 Caret.Hwnd = handle;
2517 Caret.Window = hwnd.client_window;
2518 Caret.Width = width;
2519 Caret.Height = height;
2520 Caret.Visible = false;
2521 Caret.On = false;
2523 gc_values = new XGCValues();
2524 gc_values.line_width = width;
2526 Caret.gc = XCreateGC(DisplayHandle, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
2527 if (Caret.gc == IntPtr.Zero) {
2528 Caret.Hwnd = IntPtr.Zero;
2529 return;
2532 XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert);
2535 internal override IntPtr CreateWindow (CreateParams cp)
2537 XSetWindowAttributes Attributes;
2538 Hwnd hwnd;
2539 Hwnd parent_hwnd = null;
2540 int X;
2541 int Y;
2542 int Width;
2543 int Height;
2544 IntPtr ParentHandle;
2545 IntPtr WholeWindow;
2546 IntPtr ClientWindow;
2547 SetWindowValuemask ValueMask;
2548 int[] atoms;
2550 hwnd = new Hwnd();
2552 Attributes = new XSetWindowAttributes();
2553 X = cp.X;
2554 Y = cp.Y;
2555 Width = cp.Width;
2556 Height = cp.Height;
2558 if (Width<1) Width=1;
2559 if (Height<1) Height=1;
2561 if (cp.Parent != IntPtr.Zero) {
2562 parent_hwnd = Hwnd.ObjectFromHandle(cp.Parent);
2563 ParentHandle = parent_hwnd.client_window;
2564 } else {
2565 if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2566 // We need to use our foster parent window until this poor child gets it's parent assigned
2567 ParentHandle=FosterParent;
2568 } else {
2569 ParentHandle=RootWindow;
2573 // Set the default location location for forms.
2574 Point previous, next;
2575 Rectangle within;
2576 if (cp.control is Form) {
2577 if (parent_hwnd != null) {
2578 previous = parent_hwnd.previous_child_startup_location;
2579 within = parent_hwnd.client_rectangle;
2580 } else {
2581 previous = Hwnd.previous_main_startup_location;
2582 within = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
2585 if (previous.X == int.MinValue || previous.Y == int.MinValue) {
2586 next = Point.Empty;
2587 } else {
2588 next = new Point (previous.X + 22, previous.Y + 22);
2591 if (!within.Contains (next.X * 3, next.Y * 3)) {
2592 next = Point.Empty;
2595 if (next == Point.Empty && cp.Parent == IntPtr.Zero) {
2596 next = new Point (22, 22);
2599 if (parent_hwnd != null) {
2600 parent_hwnd.previous_child_startup_location = next;
2601 } else {
2602 Hwnd.previous_main_startup_location = next;
2605 if (X == int.MinValue && Y == int.MinValue) {
2606 X = next.X;
2607 Y = next.Y;
2610 ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
2612 Attributes.bit_gravity = Gravity.NorthWestGravity;
2613 Attributes.win_gravity = Gravity.NorthWestGravity;
2615 // Save what's under the toolwindow
2616 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
2617 Attributes.save_under = true;
2618 ValueMask |= SetWindowValuemask.SaveUnder;
2622 // If we're a popup without caption we override the WM
2623 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
2624 Attributes.override_redirect = true;
2625 ValueMask |= SetWindowValuemask.OverrideRedirect;
2628 hwnd.x = X;
2629 hwnd.y = Y;
2630 hwnd.width = Width;
2631 hwnd.height = Height;
2632 hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent);
2633 hwnd.initial_style = cp.WindowStyle;
2634 hwnd.initial_ex_style = cp.WindowExStyle;
2636 if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) {
2637 hwnd.enabled = false;
2640 ClientWindow = IntPtr.Zero;
2642 Size XWindowSize = TranslateWindowSizeToXWindowSize (cp);
2643 Rectangle XClientRect = TranslateClientRectangleToXClientRectangle (hwnd, cp.control);
2645 lock (XlibLock) {
2646 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);
2647 if (WholeWindow != IntPtr.Zero) {
2648 ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
2650 if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) {
2651 ValueMask = SetWindowValuemask.ColorMap;
2652 Attributes.colormap = CustomColormap;
2654 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);
2658 if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) {
2659 throw new Exception("Could not create X11 windows");
2662 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
2663 hwnd.WholeWindow = WholeWindow;
2664 hwnd.ClientWindow = ClientWindow;
2666 #if DriverDebug || DriverDebugCreate
2667 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);
2668 #endif
2670 if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2671 if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
2672 XSizeHints hints;
2674 hints = new XSizeHints();
2675 hints.x = X;
2676 hints.y = Y;
2677 hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition);
2678 XSetWMNormalHints(DisplayHandle, WholeWindow, ref hints);
2682 lock (XlibLock) {
2683 XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask)));
2684 if (hwnd.whole_window != hwnd.client_window)
2685 XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask)));
2688 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
2689 atoms = new int[2];
2690 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
2691 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
2693 XSetTransientForHint (DisplayHandle, hwnd.whole_window, RootWindow);
2696 SetWMStyles(hwnd, cp);
2698 // set the group leader
2699 XWMHints wm_hints = new XWMHints ();
2701 wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint);
2702 wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
2703 wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState;
2705 if (ParentHandle != RootWindow) {
2706 wm_hints.window_group = hwnd.whole_window;
2707 } else {
2708 wm_hints.window_group = ParentHandle;
2711 lock (XlibLock) {
2712 XSetWMHints(DisplayHandle, hwnd.whole_window, ref wm_hints );
2715 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) {
2716 SetWindowState(hwnd.Handle, FormWindowState.Minimized);
2717 } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) {
2718 SetWindowState(hwnd.Handle, FormWindowState.Maximized);
2721 // for now make all windows dnd enabled
2722 Dnd.SetAllowDrop (hwnd, true);
2724 // Set caption/window title
2725 Text(hwnd.Handle, cp.Caption);
2727 SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */);
2728 SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue);
2730 if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) {
2731 hwnd.visible = true;
2732 MapWindow(hwnd, WindowType.Both);
2733 if (!(Control.FromHandle(hwnd.Handle) is Form))
2734 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
2737 return hwnd.Handle;
2740 internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) {
2741 CreateParams create_params = new CreateParams();
2743 create_params.Caption = "";
2744 create_params.X = X;
2745 create_params.Y = Y;
2746 create_params.Width = Width;
2747 create_params.Height = Height;
2749 create_params.ClassName=XplatUI.DefaultClassName;
2750 create_params.ClassStyle = 0;
2751 create_params.ExStyle=0;
2752 create_params.Parent=IntPtr.Zero;
2753 create_params.Param=0;
2755 return CreateWindow(create_params);
2758 internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
2759 IntPtr cursor;
2760 Bitmap cursor_bitmap;
2761 Bitmap cursor_mask;
2762 Byte[] cursor_bits;
2763 Byte[] mask_bits;
2764 Color c_pixel;
2765 Color m_pixel;
2766 int width;
2767 int height;
2768 IntPtr cursor_pixmap;
2769 IntPtr mask_pixmap;
2770 XColor fg;
2771 XColor bg;
2772 bool and;
2773 bool xor;
2775 if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) {
2776 return IntPtr.Zero;
2779 // Win32 only allows creation cursors of a certain size
2780 if ((bitmap.Width != width) || (bitmap.Width != height)) {
2781 cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
2782 cursor_mask = new Bitmap(mask, new Size(width, height));
2783 } else {
2784 cursor_bitmap = bitmap;
2785 cursor_mask = mask;
2788 width = cursor_bitmap.Width;
2789 height = cursor_bitmap.Height;
2791 cursor_bits = new Byte[(width / 8) * height];
2792 mask_bits = new Byte[(width / 8) * height];
2794 for (int y = 0; y < height; y++) {
2795 for (int x = 0; x < width; x++) {
2796 c_pixel = cursor_bitmap.GetPixel(x, y);
2797 m_pixel = cursor_mask.GetPixel(x, y);
2799 and = c_pixel == cursor_pixel;
2800 xor = m_pixel == mask_pixel;
2802 if (!and && !xor) {
2803 // Black
2804 // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
2805 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2806 } else if (and && !xor) {
2807 // White
2808 cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2809 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2810 #if notneeded
2811 } else if (and && !xor) {
2812 // Screen
2813 } else if (and && xor) {
2814 // Inverse Screen
2816 // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
2817 // we want both to be 0 so nothing to be done
2818 //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
2819 //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
2820 #endif
2825 cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2826 mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2827 fg = new XColor();
2828 bg = new XColor();
2830 fg.pixel = XWhitePixel(DisplayHandle, ScreenNo);
2831 fg.red = (ushort)65535;
2832 fg.green = (ushort)65535;
2833 fg.blue = (ushort)65535;
2835 bg.pixel = XBlackPixel(DisplayHandle, ScreenNo);
2837 cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
2839 XFreePixmap(DisplayHandle, cursor_pixmap);
2840 XFreePixmap(DisplayHandle, mask_pixmap);
2842 return cursor;
2845 internal override Bitmap DefineStdCursorBitmap (StdCursor id) {
2846 CursorFontShape shape;
2847 string name;
2848 IntPtr theme;
2849 int size;
2850 Bitmap bmp = null;
2852 try {
2853 shape = StdCursorToFontShape (id);
2854 name = shape.ToString ().Replace ("XC_", string.Empty);
2855 size = XcursorGetDefaultSize (DisplayHandle);
2856 theme = XcursorGetTheme (DisplayHandle);
2857 IntPtr images_ptr = XcursorLibraryLoadImages (name, theme, size);
2858 #if debug
2859 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);
2860 #endif
2862 if (images_ptr == IntPtr.Zero) {
2863 return null;
2866 XcursorImages images = (XcursorImages) Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
2867 #if debug
2868 Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
2869 #endif
2871 if (images.nimage > 0) {
2872 // We only care about the first image.
2873 XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
2875 #if debug
2876 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);
2877 #endif
2878 // A sanity check
2879 if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
2880 int [] pixels = new int [image.width * image.height];
2881 Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
2882 bmp = new Bitmap (image.width, image.height);
2883 for (int w = 0; w < image.width; w++) {
2884 for (int h = 0; h < image.height; h++) {
2885 bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
2891 XcursorImagesDestroy (images_ptr);
2893 } catch (DllNotFoundException ex) {
2894 Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
2895 return null;
2898 return bmp;
2902 internal override IntPtr DefineStdCursor(StdCursor id) {
2903 CursorFontShape shape;
2904 IntPtr cursor;
2906 shape = StdCursorToFontShape (id);
2908 lock (XlibLock) {
2909 cursor = XCreateFontCursor(DisplayHandle, shape);
2911 return cursor;
2914 internal static CursorFontShape StdCursorToFontShape (StdCursor id) {
2915 CursorFontShape shape;
2916 // FIXME - define missing shapes
2918 switch (id) {
2919 case StdCursor.AppStarting: {
2920 shape = CursorFontShape.XC_watch;
2921 break;
2924 case StdCursor.Arrow: {
2925 shape = CursorFontShape.XC_top_left_arrow;
2926 break;
2929 case StdCursor.Cross: {
2930 shape = CursorFontShape.XC_crosshair;
2931 break;
2934 case StdCursor.Default: {
2935 shape = CursorFontShape.XC_top_left_arrow;
2936 break;
2939 case StdCursor.Hand: {
2940 shape = CursorFontShape.XC_hand1;
2941 break;
2944 case StdCursor.Help: {
2945 shape = CursorFontShape.XC_question_arrow;
2946 break;
2949 case StdCursor.HSplit: {
2950 shape = CursorFontShape.XC_sb_v_double_arrow;
2951 break;
2954 case StdCursor.IBeam: {
2955 shape = CursorFontShape.XC_xterm;
2956 break;
2959 case StdCursor.No: {
2960 shape = CursorFontShape.XC_circle;
2961 break;
2964 case StdCursor.NoMove2D: {
2965 shape = CursorFontShape.XC_fleur;
2966 break;
2969 case StdCursor.NoMoveHoriz: {
2970 shape = CursorFontShape.XC_fleur;
2971 break;
2974 case StdCursor.NoMoveVert: {
2975 shape = CursorFontShape.XC_fleur;
2976 break;
2979 case StdCursor.PanEast: {
2980 shape = CursorFontShape.XC_fleur;
2981 break;
2984 case StdCursor.PanNE: {
2985 shape = CursorFontShape.XC_fleur;
2986 break;
2989 case StdCursor.PanNorth: {
2990 shape = CursorFontShape.XC_fleur;
2991 break;
2994 case StdCursor.PanNW: {
2995 shape = CursorFontShape.XC_fleur;
2996 break;
2999 case StdCursor.PanSE: {
3000 shape = CursorFontShape.XC_fleur;
3001 break;
3004 case StdCursor.PanSouth: {
3005 shape = CursorFontShape.XC_fleur;
3006 break;
3009 case StdCursor.PanSW: {
3010 shape = CursorFontShape.XC_fleur;
3011 break;
3014 case StdCursor.PanWest: {
3015 shape = CursorFontShape.XC_sizing;
3016 break;
3019 case StdCursor.SizeAll: {
3020 shape = CursorFontShape.XC_fleur;
3021 break;
3024 case StdCursor.SizeNESW: {
3025 shape = CursorFontShape.XC_top_right_corner;
3026 break;
3029 case StdCursor.SizeNS: {
3030 shape = CursorFontShape.XC_sb_v_double_arrow;
3031 break;
3034 case StdCursor.SizeNWSE: {
3035 shape = CursorFontShape.XC_top_left_corner;
3036 break;
3039 case StdCursor.SizeWE: {
3040 shape = CursorFontShape.XC_sb_h_double_arrow;
3041 break;
3044 case StdCursor.UpArrow: {
3045 shape = CursorFontShape.XC_center_ptr;
3046 break;
3049 case StdCursor.VSplit: {
3050 shape = CursorFontShape.XC_sb_h_double_arrow;
3051 break;
3054 case StdCursor.WaitCursor: {
3055 shape = CursorFontShape.XC_watch;
3056 break;
3059 default: {
3060 shape = (CursorFontShape) 0;
3061 break;
3065 return shape;
3068 internal override IntPtr DefWndProc(ref Message msg) {
3069 switch ((Msg)msg.Msg) {
3070 case Msg.WM_PAINT: {
3071 Hwnd hwnd;
3073 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3074 if (hwnd != null) {
3075 hwnd.expose_pending = false;
3078 return IntPtr.Zero;
3081 case Msg.WM_NCPAINT: {
3082 Hwnd hwnd;
3084 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3085 if (hwnd != null) {
3086 hwnd.nc_expose_pending = false;
3089 return IntPtr.Zero;
3092 case Msg.WM_NCCALCSIZE: {
3093 Hwnd hwnd;
3095 if (msg.WParam == (IntPtr)1) {
3096 hwnd = Hwnd.GetObjectFromWindow (msg.HWnd);
3098 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
3099 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (msg.LParam, typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
3101 // Add all the stuff X is supposed to draw.
3102 Control ctrl = Control.FromHandle (hwnd.Handle);
3103 Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null);
3105 ncp.rgrc1.top += rect.top;
3106 ncp.rgrc1.bottom -= rect.bottom;
3107 ncp.rgrc1.left += rect.left;
3108 ncp.rgrc1.right -= rect.right;
3110 Marshal.StructureToPtr (ncp, msg.LParam, true);
3113 return IntPtr.Zero;
3116 case Msg.WM_CONTEXTMENU: {
3117 Hwnd hwnd;
3119 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3121 if ((hwnd != null) && (hwnd.parent != null)) {
3122 SendMessage(hwnd.parent.client_window, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam);
3124 return IntPtr.Zero;
3127 case Msg.WM_MOUSEWHEEL: {
3128 Hwnd hwnd;
3130 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3132 if ((hwnd != null) && (hwnd.parent != null)) {
3133 SendMessage(hwnd.parent.client_window, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam);
3134 if (msg.Result == IntPtr.Zero) {
3135 return IntPtr.Zero;
3138 return IntPtr.Zero;
3141 case Msg.WM_SETCURSOR: {
3142 Hwnd hwnd;
3144 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
3145 if (hwnd == null)
3146 break; // not sure how this happens, but it does
3148 // Pass to parent window first
3149 while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) {
3150 hwnd = hwnd.parent;
3151 msg.Result = NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam);
3154 if (msg.Result == IntPtr.Zero) {
3155 IntPtr handle;
3157 switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) {
3158 case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break;
3159 case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break;
3160 case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break;
3161 case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break;
3162 case HitTest.HTERROR: if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) {
3163 AudibleAlert();
3165 handle = Cursors.Default.handle;
3166 break;
3168 case HitTest.HTHELP: handle = Cursors.Help.handle; break;
3169 case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break;
3170 case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break;
3171 case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break;
3172 case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break;
3173 case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break;
3175 #if SameAsDefault
3176 case HitTest.HTGROWBOX:
3177 case HitTest.HTSIZE:
3178 case HitTest.HTZOOM:
3179 case HitTest.HTVSCROLL:
3180 case HitTest.HTSYSMENU:
3181 case HitTest.HTREDUCE:
3182 case HitTest.HTNOWHERE:
3183 case HitTest.HTMAXBUTTON:
3184 case HitTest.HTMINBUTTON:
3185 case HitTest.HTMENU:
3186 case HitTest.HSCROLL:
3187 case HitTest.HTBOTTOM:
3188 case HitTest.HTCAPTION:
3189 case HitTest.HTCLIENT:
3190 case HitTest.HTCLOSE:
3191 #endif
3192 default: handle = Cursors.Default.handle; break;
3194 SetCursor(msg.HWnd, handle);
3196 return (IntPtr)1;
3199 return IntPtr.Zero;
3202 internal override void DestroyCaret(IntPtr handle) {
3203 if (Caret.Hwnd == handle) {
3204 if (Caret.Visible) {
3205 HideCaret ();
3206 Caret.Timer.Stop();
3208 if (Caret.gc != IntPtr.Zero) {
3209 XFreeGC(DisplayHandle, Caret.gc);
3210 Caret.gc = IntPtr.Zero;
3212 Caret.Hwnd = IntPtr.Zero;
3213 Caret.Visible = false;
3214 Caret.On = false;
3218 internal override void DestroyCursor(IntPtr cursor) {
3219 lock (XlibLock) {
3220 XFreeCursor(DisplayHandle, cursor);
3224 internal override void DestroyWindow(IntPtr handle) {
3225 Hwnd hwnd;
3227 hwnd = Hwnd.ObjectFromHandle(handle);
3229 if (hwnd == null) {
3230 #if DriverDebug || DriverDebugDestroy
3231 Console.WriteLine("window {0:X} already destroyed", handle.ToInt32());
3232 #endif
3233 return;
3236 #if DriverDebug || DriverDebugDestroy
3237 Console.WriteLine("Destroying window {0}", XplatUI.Window(hwnd.client_window));
3238 #endif
3240 SendParentNotify (hwnd.Handle, Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
3242 CleanupCachedWindows (hwnd);
3244 ArrayList windows = new ArrayList ();
3246 AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
3249 foreach (Hwnd h in windows) {
3250 SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
3251 h.zombie = true;
3254 lock (XlibLock) {
3255 if (hwnd.whole_window != IntPtr.Zero) {
3256 #if DriverDebug || DriverDebugDestroy
3257 Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32());
3258 #endif
3259 XDestroyWindow(DisplayHandle, hwnd.whole_window);
3261 else if (hwnd.client_window != IntPtr.Zero) {
3262 #if DriverDebug || DriverDebugDestroy
3263 Console.WriteLine ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32());
3264 #endif
3265 XDestroyWindow(DisplayHandle, hwnd.client_window);
3271 internal override IntPtr DispatchMessage(ref MSG msg) {
3272 return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
3275 IntPtr GetReversibleScreenGC (Color backColor)
3277 XGCValues gc_values;
3278 IntPtr gc;
3279 uint pixel;
3281 XColor xcolor = new XColor();
3282 xcolor.red = (ushort)(backColor.R * 257);
3283 xcolor.green = (ushort)(backColor.G * 257);
3284 xcolor.blue = (ushort)(backColor.B * 257);
3285 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3286 pixel = (uint)xcolor.pixel.ToInt32();
3289 gc_values = new XGCValues();
3291 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
3292 gc_values.foreground = (IntPtr)pixel;
3294 gc = XCreateGC(DisplayHandle, RootWindow, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
3295 XSetForeground(DisplayHandle, gc, (UIntPtr)pixel);
3296 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
3298 return gc;
3301 IntPtr GetReversibleControlGC (Control control, int line_width)
3303 XGCValues gc_values;
3304 IntPtr gc;
3306 gc_values = new XGCValues();
3308 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
3309 gc_values.line_width = line_width;
3310 gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo);
3312 // This logic will give us true rubber bands: (libsx, SANE_XOR)
3313 //mask = foreground ^ background;
3314 //XSetForeground(DisplayHandle, gc, 0xffffffff);
3315 //XSetBackground(DisplayHandle, gc, background);
3316 //XSetFunction(DisplayHandle, gc, GXxor);
3317 //XSetPlaneMask(DisplayHandle, gc, mask);
3320 gc = XCreateGC(DisplayHandle, control.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values);
3321 uint foreground;
3322 uint background;
3324 XColor xcolor = new XColor();
3326 xcolor.red = (ushort)(control.ForeColor.R * 257);
3327 xcolor.green = (ushort)(control.ForeColor.G * 257);
3328 xcolor.blue = (ushort)(control.ForeColor.B * 257);
3329 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3330 foreground = (uint)xcolor.pixel.ToInt32();
3332 xcolor.red = (ushort)(control.BackColor.R * 257);
3333 xcolor.green = (ushort)(control.BackColor.G * 257);
3334 xcolor.blue = (ushort)(control.BackColor.B * 257);
3335 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3336 background = (uint)xcolor.pixel.ToInt32();
3338 uint mask = foreground ^ background;
3340 XSetForeground(DisplayHandle, gc, (UIntPtr)0xffffffff);
3341 XSetBackground(DisplayHandle, gc, (UIntPtr)background);
3342 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
3343 XSetPlaneMask(DisplayHandle, gc, (IntPtr)mask);
3345 return gc;
3348 internal override void DrawReversibleLine(Point start, Point end, Color backColor)
3350 IntPtr gc = GetReversibleScreenGC (backColor);
3352 XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y);
3354 XFreeGC(DisplayHandle, gc);
3357 internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
3359 IntPtr gc = GetReversibleScreenGC (backColor);
3361 if (rectangle.Width < 0) {
3362 rectangle.X += rectangle.Width;
3363 rectangle.Width = -rectangle.Width;
3365 if (rectangle.Height < 0) {
3366 rectangle.Y += rectangle.Height;
3367 rectangle.Height = -rectangle.Height;
3370 int line_width = 1;
3371 GCLineStyle line_style = GCLineStyle.LineSolid;
3372 GCCapStyle cap_style = GCCapStyle.CapButt;
3373 GCJoinStyle join_style = GCJoinStyle.JoinMiter;
3375 switch (style) {
3376 case FrameStyle.Dashed:
3377 line_style = GCLineStyle.LineOnOffDash;
3378 break;
3379 case FrameStyle.Thick:
3380 line_width = 2;
3381 break;
3384 XSetLineAttributes (DisplayHandle, gc, line_width, line_style, cap_style, join_style);
3386 XDrawRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3388 XFreeGC(DisplayHandle, gc);
3391 internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
3393 IntPtr gc = GetReversibleScreenGC (backColor);
3395 if (rectangle.Width < 0) {
3396 rectangle.X += rectangle.Width;
3397 rectangle.Width = -rectangle.Width;
3399 if (rectangle.Height < 0) {
3400 rectangle.Y += rectangle.Height;
3401 rectangle.Height = -rectangle.Height;
3403 XFillRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3405 XFreeGC(DisplayHandle, gc);
3408 internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) {
3409 IntPtr gc;
3410 Control control = Control.FromHandle(handle);
3412 gc = GetReversibleControlGC (control, line_width);
3414 if ((rect.Width > 0) && (rect.Height > 0)) {
3415 XDrawRectangle(DisplayHandle, control.Handle, gc, rect.Left, rect.Top, rect.Width, rect.Height);
3416 } else {
3417 if (rect.Width > 0) {
3418 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.Right, rect.Y);
3419 } else {
3420 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.X, rect.Bottom);
3423 XFreeGC(DisplayHandle, gc);
3426 internal override void DoEvents() {
3427 MSG msg = new MSG ();
3428 XEventQueue queue;
3430 if (OverrideCursorHandle != IntPtr.Zero) {
3431 OverrideCursorHandle = IntPtr.Zero;
3434 queue = ThreadQueue(Thread.CurrentThread);
3436 queue.DispatchIdle = false;
3438 while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
3439 TranslateMessage (ref msg);
3440 DispatchMessage (ref msg);
3443 queue.DispatchIdle = true;
3446 internal override void EnableWindow(IntPtr handle, bool Enable) {
3447 Hwnd hwnd;
3449 hwnd = Hwnd.ObjectFromHandle(handle);
3450 if (hwnd != null) {
3451 hwnd.Enabled = Enable;
3455 internal override void EndLoop(Thread thread) {
3456 // This is where we one day will shut down the loop for the thread
3459 internal override IntPtr GetActive() {
3460 IntPtr actual_atom;
3461 int actual_format;
3462 IntPtr nitems;
3463 IntPtr bytes_after;
3464 IntPtr prop = IntPtr.Zero;
3465 IntPtr active = IntPtr.Zero;
3467 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);
3468 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
3469 active = (IntPtr)Marshal.ReadInt32(prop);
3470 XFree(prop);
3473 if (active != IntPtr.Zero) {
3474 Hwnd hwnd;
3476 hwnd = Hwnd.GetObjectFromWindow(active);
3477 if (hwnd != null) {
3478 active = hwnd.Handle;
3479 } else {
3480 active = IntPtr.Zero;
3483 return active;
3486 internal override Region GetClipRegion(IntPtr handle) {
3487 Hwnd hwnd;
3489 hwnd = Hwnd.ObjectFromHandle(handle);
3490 if (hwnd != null) {
3491 return hwnd.UserClip;
3494 return null;
3497 internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) {
3498 width = 20;
3499 height = 20;
3500 hotspot_x = 0;
3501 hotspot_y = 0;
3504 internal override void GetDisplaySize(out Size size) {
3505 XWindowAttributes attributes=new XWindowAttributes();
3507 lock (XlibLock) {
3508 // FIXME - use _NET_WM messages instead?
3509 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
3512 size = new Size(attributes.width, attributes.height);
3515 internal override SizeF GetAutoScaleSize(Font font) {
3516 Graphics g;
3517 float width;
3518 string magic_string = "The quick brown fox jumped over the lazy dog.";
3519 double magic_number = 44.549996948242189;
3521 g = Graphics.FromHwnd(FosterParent);
3523 width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
3524 return new SizeF(width, font.Height);
3527 internal override IntPtr GetParent(IntPtr handle) {
3528 Hwnd hwnd;
3530 hwnd = Hwnd.ObjectFromHandle(handle);
3531 if (hwnd != null && hwnd.parent != null) {
3532 return hwnd.parent.Handle;
3534 return IntPtr.Zero;
3537 internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
3538 IntPtr use_handle;
3539 IntPtr root;
3540 IntPtr child;
3541 int root_x;
3542 int root_y;
3543 int win_x;
3544 int win_y;
3545 int keys_buttons;
3547 if (handle != IntPtr.Zero) {
3548 use_handle = Hwnd.ObjectFromHandle(handle).client_window;
3549 } else {
3550 use_handle = RootWindow;
3553 lock (XlibLock) {
3554 QueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
3557 if (handle != IntPtr.Zero) {
3558 x = win_x;
3559 y = win_y;
3560 } else {
3561 x = root_x;
3562 y = root_y;
3566 internal override IntPtr GetFocus() {
3567 return FocusWindow;
3571 internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) {
3572 FontFamily ff = font.FontFamily;
3573 ascent = ff.GetCellAscent (font.Style);
3574 descent = ff.GetCellDescent (font.Style);
3575 return true;
3578 internal override Point GetMenuOrigin(IntPtr handle) {
3579 Hwnd hwnd;
3581 hwnd = Hwnd.ObjectFromHandle(handle);
3583 if (hwnd != null) {
3584 return hwnd.MenuOrigin;
3586 return Point.Empty;
3589 [MonoTODO("Implement filtering")]
3590 internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) {
3591 XEvent xevent;
3592 bool client;
3593 Hwnd hwnd;
3595 ProcessNextMessage:
3597 if (((XEventQueue)queue_id).Count > 0) {
3598 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3599 } else {
3600 UpdateMessageQueue ((XEventQueue)queue_id);
3602 if (((XEventQueue)queue_id).Count > 0) {
3603 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3604 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
3605 xevent = ((XEventQueue)queue_id).Paint.Dequeue();
3606 } else {
3607 msg.hwnd= IntPtr.Zero;
3608 msg.message = Msg.WM_ENTERIDLE;
3609 return true;
3613 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
3615 // Handle messages for windows that are already or are about to be destroyed.
3617 // we need a special block for this because unless we remove the hwnd from the paint
3618 // queue it will always stay there (since we don't handle the expose), and we'll
3619 // effectively loop infinitely trying to repaint a non-existant window.
3620 if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
3621 hwnd.expose_pending = hwnd.nc_expose_pending = false;
3622 hwnd.Queue.Paint.Remove (hwnd);
3623 goto ProcessNextMessage;
3626 // We need to make sure we only allow DestroyNotify events through for zombie
3627 // hwnds, since much of the event handling code makes requests using the hwnd's
3628 // client_window, and that'll result in BadWindow errors if there's some lag
3629 // between the XDestroyWindow call and the DestroyNotify event.
3630 if (hwnd == null || hwnd.zombie) {
3631 #if DriverDebug || DriverDebugDestroy
3632 Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
3633 #endif
3634 goto ProcessNextMessage;
3637 if (hwnd.client_window == xevent.AnyEvent.window) {
3638 client = true;
3639 //Console.WriteLine("Client message {1}, sending to window {0:X}", msg.hwnd.ToInt32(), xevent.type);
3640 } else {
3641 client = false;
3642 //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32());
3645 msg.hwnd = hwnd.Handle;
3648 // If you add a new event to this switch make sure to add it in
3649 // UpdateMessage also unless it is not coming through the X event system.
3651 switch(xevent.type) {
3652 case XEventName.KeyPress: {
3653 if (Dnd.InDrag ())
3654 Dnd.HandleKeyPress (ref xevent);
3655 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3656 break;
3659 case XEventName.KeyRelease: {
3660 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3661 break;
3664 case XEventName.ButtonPress: {
3665 switch(xevent.ButtonEvent.button) {
3666 case 1: {
3667 MouseState |= MouseButtons.Left;
3668 if (client) {
3669 msg.message = Msg.WM_LBUTTONDOWN;
3670 } else {
3671 msg.message = Msg.WM_NCLBUTTONDOWN;
3672 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3674 // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
3675 msg.wParam=GetMousewParam(0);
3676 break;
3679 case 2: {
3680 MouseState |= MouseButtons.Middle;
3681 if (client) {
3682 msg.message = Msg.WM_MBUTTONDOWN;
3683 } else {
3684 msg.message = Msg.WM_NCMBUTTONDOWN;
3685 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3687 msg.wParam=GetMousewParam(0);
3688 break;
3691 case 3: {
3692 MouseState |= MouseButtons.Right;
3693 if (client) {
3694 msg.message = Msg.WM_RBUTTONDOWN;
3695 } else {
3696 msg.message = Msg.WM_NCRBUTTONDOWN;
3697 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3699 msg.wParam=GetMousewParam(0);
3700 break;
3703 case 4: {
3704 msg.hwnd = FocusWindow;
3705 msg.message=Msg.WM_MOUSEWHEEL;
3706 msg.wParam=GetMousewParam(120);
3707 break;
3710 case 5: {
3711 msg.hwnd = FocusWindow;
3712 msg.message=Msg.WM_MOUSEWHEEL;
3713 msg.wParam=GetMousewParam(-120);
3714 break;
3719 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3720 mouse_position.X = xevent.ButtonEvent.x;
3721 mouse_position.Y = xevent.ButtonEvent.y;
3723 if (!hwnd.Enabled) {
3724 IntPtr dummy;
3726 msg.hwnd = hwnd.EnabledHwnd;
3727 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);
3728 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3731 if (Grab.Hwnd != IntPtr.Zero) {
3732 msg.hwnd = Grab.Hwnd;
3735 if (ClickPending.Pending && ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
3736 // Looks like a genuine double click, clicked twice on the same spot with the same keys
3737 switch(xevent.ButtonEvent.button) {
3738 case 1: {
3739 msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
3740 break;
3743 case 2: {
3744 msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
3745 break;
3748 case 3: {
3749 msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
3750 break;
3753 ClickPending.Pending = false;
3754 } else {
3755 ClickPending.Pending = true;
3756 ClickPending.Hwnd = msg.hwnd;
3757 ClickPending.Message = msg.message;
3758 ClickPending.wParam = msg.wParam;
3759 ClickPending.lParam = msg.lParam;
3760 ClickPending.Time = (long)xevent.ButtonEvent.time;
3763 if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
3764 SendParentNotify(msg.hwnd, msg.message, mouse_position.X, mouse_position.Y);
3766 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
3767 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
3768 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
3769 XEvent motionEvent = new XEvent ();
3770 motionEvent.type = XEventName.MotionNotify;
3771 motionEvent.MotionEvent.display = DisplayHandle;
3772 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
3773 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
3774 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
3775 hwnd.Queue.EnqueueLocked (motionEvent);
3778 break;
3781 case XEventName.ButtonRelease: {
3782 if (Dnd.InDrag()) {
3783 if (Dnd.HandleButtonRelease (ref xevent)) {
3784 break;
3786 // Allow the LBUTTONUP message to get through
3789 switch(xevent.ButtonEvent.button) {
3790 case 1: {
3791 if (client) {
3792 msg.message = Msg.WM_LBUTTONUP;
3793 } else {
3794 msg.message = Msg.WM_NCLBUTTONUP;
3795 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3797 MouseState &= ~MouseButtons.Left;
3798 msg.wParam=GetMousewParam(0);
3799 break;
3802 case 2: {
3803 if (client) {
3804 msg.message = Msg.WM_MBUTTONUP;
3805 } else {
3806 msg.message = Msg.WM_NCMBUTTONUP;
3807 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3809 MouseState &= ~MouseButtons.Middle;
3810 msg.wParam=GetMousewParam(0);
3811 break;
3814 case 3: {
3815 if (client) {
3816 msg.message = Msg.WM_RBUTTONUP;
3817 } else {
3818 msg.message = Msg.WM_NCRBUTTONUP;
3819 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3821 MouseState &= ~MouseButtons.Right;
3822 msg.wParam=GetMousewParam(0);
3823 break;
3826 case 4: {
3827 goto ProcessNextMessage;
3830 case 5: {
3831 goto ProcessNextMessage;
3835 if (!hwnd.Enabled) {
3836 IntPtr dummy;
3838 msg.hwnd = hwnd.EnabledHwnd;
3839 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);
3840 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3843 if (Grab.Hwnd != IntPtr.Zero) {
3844 msg.hwnd = Grab.Hwnd;
3847 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3848 mouse_position.X = xevent.ButtonEvent.x;
3849 mouse_position.Y = xevent.ButtonEvent.y;
3851 // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
3852 // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
3853 // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
3854 if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
3855 XEvent motionEvent = new XEvent ();
3856 motionEvent.type = XEventName.MotionNotify;
3857 motionEvent.MotionEvent.display = DisplayHandle;
3858 motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
3859 motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
3860 motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
3861 hwnd.Queue.EnqueueLocked (motionEvent);
3863 break;
3866 case XEventName.MotionNotify: {
3867 if (client) {
3868 #if DriverDebugExtra
3869 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);
3870 #endif
3872 if (Dnd.HandleMotionNotify (ref xevent))
3873 goto ProcessNextMessage;
3874 if (Grab.Hwnd != IntPtr.Zero) {
3875 msg.hwnd = Grab.Hwnd;
3876 } else {
3877 if (hwnd.Enabled) {
3878 NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
3882 msg.message = Msg.WM_MOUSEMOVE;
3883 msg.wParam = GetMousewParam(0);
3884 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
3886 if (!hwnd.Enabled) {
3887 IntPtr dummy;
3889 msg.hwnd = hwnd.EnabledHwnd;
3890 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);
3891 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3894 mouse_position.X = xevent.MotionEvent.x;
3895 mouse_position.Y = xevent.MotionEvent.y;
3897 if ((HoverState.Timer.Enabled) &&
3898 (((mouse_position.X + HoverState.Size.Width) < HoverState.X) ||
3899 ((mouse_position.X - HoverState.Size.Width) > HoverState.X) ||
3900 ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) ||
3901 ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) {
3902 HoverState.Timer.Stop();
3903 HoverState.Timer.Start();
3904 HoverState.X = mouse_position.X;
3905 HoverState.Y = mouse_position.Y;
3908 break;
3909 } else {
3910 HitTest ht;
3911 IntPtr dummy;
3912 int screen_x;
3913 int screen_y;
3915 #if DriverDebugExtra
3916 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);
3917 #endif
3918 msg.message = Msg.WM_NCMOUSEMOVE;
3920 if (!hwnd.Enabled) {
3921 msg.hwnd = hwnd.EnabledHwnd;
3922 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);
3923 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3926 // The hit test is sent in screen coordinates
3927 XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, RootWindow,
3928 xevent.MotionEvent.x, xevent.MotionEvent.y,
3929 out screen_x, out screen_y, out dummy);
3931 msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF);
3932 ht = (HitTest)NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST,
3933 IntPtr.Zero, msg.lParam).ToInt32 ();
3934 NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
3936 mouse_position.X = xevent.MotionEvent.x;
3937 mouse_position.Y = xevent.MotionEvent.y;
3940 break;
3943 case XEventName.EnterNotify: {
3944 if (!hwnd.Enabled) {
3945 goto ProcessNextMessage;
3947 if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
3948 goto ProcessNextMessage;
3950 msg.message = Msg.WM_MOUSE_ENTER;
3951 HoverState.X = xevent.CrossingEvent.x;
3952 HoverState.Y = xevent.CrossingEvent.y;
3953 HoverState.Timer.Enabled = true;
3954 HoverState.Window = xevent.CrossingEvent.window;
3955 break;
3958 case XEventName.LeaveNotify: {
3959 if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) {
3960 WindowUngrabbed (hwnd.Handle);
3961 goto ProcessNextMessage;
3963 if (!hwnd.Enabled) {
3964 goto ProcessNextMessage;
3966 if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
3967 goto ProcessNextMessage;
3969 msg.message=Msg.WM_MOUSELEAVE;
3970 HoverState.Timer.Enabled = false;
3971 HoverState.Window = IntPtr.Zero;
3972 break;
3975 #if later
3976 case XEventName.CreateNotify: {
3977 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
3978 msg.message = WM_CREATE;
3979 // Set up CreateStruct
3980 } else {
3981 goto ProcessNextMessage;
3983 break;
3985 #endif
3988 case XEventName.ReparentNotify: {
3989 if (hwnd.parent == null) { // Toplevel
3990 if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) {
3991 hwnd.Reparented = true;
3993 // The location given by the event is not reliable between different wm's,
3994 // so use an alternative way of getting it.
3995 Point location = GetTopLevelWindowLocation (hwnd);
3996 hwnd.X = location.X;
3997 hwnd.Y = location.Y;
3999 if (hwnd.opacity != 0xffffffff) {
4000 IntPtr opacity;
4002 opacity = (IntPtr)(Int32)hwnd.opacity;
4003 XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
4005 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
4006 goto ProcessNextMessage;
4007 } else {
4008 hwnd.Reparented = false;
4009 goto ProcessNextMessage;
4012 goto ProcessNextMessage;
4015 case XEventName.ConfigureNotify: {
4016 if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4017 #if DriverDebugExtra
4018 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);
4019 #endif
4020 // if ((hwnd.x != xevent.ConfigureEvent.x) || (hwnd.y != xevent.ConfigureEvent.y) || (hwnd.width != xevent.ConfigureEvent.width) || (hwnd.height != xevent.ConfigureEvent.height)) {
4021 lock (hwnd.configure_lock) {
4022 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4023 hwnd.configure_pending = false;
4026 // We need to adjust our client window to track the resize of whole_window
4027 if (hwnd.whole_window != hwnd.client_window)
4028 PerformNCCalc(hwnd);
4029 // }
4031 goto ProcessNextMessage;
4034 case XEventName.FocusIn: {
4035 // We received focus. We use X11 focus only to know if the app window does or does not have focus
4036 // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
4037 // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
4038 // about it having focus again
4039 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4040 goto ProcessNextMessage;
4043 if (FocusWindow == IntPtr.Zero) {
4044 Control c = Control.FromHandle (hwnd.client_window);
4045 if (c == null)
4046 goto ProcessNextMessage;
4047 Form form = c.FindForm ();
4048 if (form == null)
4049 goto ProcessNextMessage;
4050 if (ActiveWindow != form.Handle) {
4051 ActiveWindow = form.Handle;
4052 SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
4054 goto ProcessNextMessage;
4056 Keyboard.FocusIn(FocusWindow);
4057 SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
4058 goto ProcessNextMessage;
4061 case XEventName.FocusOut: {
4062 // Se the comment for our FocusIn handler
4063 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
4064 goto ProcessNextMessage;
4066 Keyboard.FocusOut(FocusWindow);
4068 while (Keyboard.ResetKeyState(FocusWindow, ref msg)) {
4069 SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam);
4072 SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
4073 goto ProcessNextMessage;
4076 case XEventName.MapNotify: {
4077 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4078 hwnd.mapped = true;
4079 msg.message = Msg.WM_SHOWWINDOW;
4080 msg.wParam = (IntPtr) 1;
4081 // XXX we're missing the lParam..
4082 break;
4084 goto ProcessNextMessage;
4087 case XEventName.UnmapNotify: {
4088 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
4089 hwnd.mapped = false;
4090 msg.message = Msg.WM_SHOWWINDOW;
4091 msg.wParam = (IntPtr) 0;
4092 // XXX we're missing the lParam..
4093 break;
4095 goto ProcessNextMessage;
4098 case XEventName.Expose: {
4099 if (!hwnd.Mapped) {
4100 if (client) {
4101 hwnd.expose_pending = false;
4102 } else {
4103 hwnd.nc_expose_pending = false;
4105 goto ProcessNextMessage;
4108 if (client) {
4109 if (!hwnd.expose_pending) {
4110 goto ProcessNextMessage;
4112 } else {
4113 if (!hwnd.nc_expose_pending) {
4114 goto ProcessNextMessage;
4117 switch (hwnd.border_style) {
4118 case FormBorderStyle.Fixed3D: {
4119 Graphics g;
4121 g = Graphics.FromHwnd(hwnd.whole_window);
4122 if (hwnd.border_static)
4123 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter);
4124 else
4125 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken);
4126 g.Dispose();
4127 break;
4130 case FormBorderStyle.FixedSingle: {
4131 Graphics g;
4133 g = Graphics.FromHwnd(hwnd.whole_window);
4134 ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
4135 g.Dispose();
4136 break;
4139 #if DriverDebugExtra
4140 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);
4141 #endif
4143 Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
4144 Region region = new Region (rect);
4145 IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
4146 msg.message = Msg.WM_NCPAINT;
4147 msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
4148 msg.refobject = region;
4149 break;
4151 #if DriverDebugExtra
4152 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);
4153 #endif
4154 if (Caret.Visible == true) {
4155 Caret.Paused = true;
4156 HideCaret();
4159 if (Caret.Visible == true) {
4160 ShowCaret();
4161 Caret.Paused = false;
4163 msg.message = Msg.WM_PAINT;
4164 break;
4167 case XEventName.DestroyNotify: {
4169 // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
4170 hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
4172 // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
4173 if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) {
4174 CleanupCachedWindows (hwnd);
4176 #if DriverDebugDestroy
4177 Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window));
4178 #endif
4180 msg.hwnd = hwnd.client_window;
4181 msg.message=Msg.WM_DESTROY;
4182 hwnd.Dispose();
4183 } else {
4184 goto ProcessNextMessage;
4187 break;
4190 case XEventName.ClientMessage: {
4191 if (Dnd.HandleClientMessage (ref xevent)) {
4192 goto ProcessNextMessage;
4195 if (xevent.ClientMessageEvent.message_type == AsyncAtom) {
4196 XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
4197 goto ProcessNextMessage;
4200 if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
4201 msg.message = Msg.WM_MOUSEHOVER;
4202 msg.wParam = GetMousewParam(0);
4203 msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
4204 return true;
4207 if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
4208 msg.hwnd = xevent.ClientMessageEvent.ptr1;
4209 msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
4210 msg.wParam = xevent.ClientMessageEvent.ptr3;
4211 msg.lParam = xevent.ClientMessageEvent.ptr4;
4212 if (msg.message == (Msg)Msg.WM_QUIT)
4213 return false;
4214 else
4215 return true;
4218 if (xevent.ClientMessageEvent.message_type == _XEMBED) {
4219 #if DriverDebugXEmbed
4220 Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
4221 #endif
4223 if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
4224 XSizeHints hints = new XSizeHints();
4225 IntPtr dummy;
4227 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
4229 hwnd.width = hints.max_width;
4230 hwnd.height = hints.max_height;
4231 hwnd.ClientRect = Rectangle.Empty;
4232 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4236 if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) {
4237 if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) {
4238 msg.message = Msg.WM_CLOSE;
4239 return true;
4242 // We should not get this, but I'll leave the code in case we need it in the future
4243 if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) {
4244 goto ProcessNextMessage;
4247 goto ProcessNextMessage;
4250 default: {
4251 goto ProcessNextMessage;
4255 return true;
4258 internal override bool GetText(IntPtr handle, out string text) {
4260 lock (XlibLock) {
4261 IntPtr actual_atom;
4262 int actual_format;
4263 IntPtr nitems;
4264 IntPtr bytes_after;
4265 IntPtr prop = IntPtr.Zero;
4267 XGetWindowProperty(DisplayHandle, handle,
4268 _NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
4269 UNICODETEXT, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
4271 if ((long)nitems > 0 && prop != IntPtr.Zero) {
4272 text = Marshal.PtrToStringUni (prop, (int)nitems);
4273 XFree (prop);
4274 return true;
4276 else {
4277 // fallback on the non-_NET property
4278 IntPtr textptr;
4280 textptr = IntPtr.Zero;
4282 XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr);
4283 if (textptr != IntPtr.Zero) {
4284 text = Marshal.PtrToStringAnsi(textptr);
4285 XFree(textptr);
4286 return true;
4287 } else {
4288 text = "";
4289 return false;
4295 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) {
4296 Hwnd hwnd;
4298 hwnd = Hwnd.ObjectFromHandle(handle);
4300 if (hwnd != null) {
4301 x = hwnd.x;
4302 y = hwnd.y;
4303 width = hwnd.width;
4304 height = hwnd.height;
4306 PerformNCCalc(hwnd);
4308 client_width = hwnd.ClientRect.Width;
4309 client_height = hwnd.ClientRect.Height;
4311 return;
4314 // Should we throw an exception or fail silently?
4315 // throw new ArgumentException("Called with an invalid window handle", "handle");
4317 x = 0;
4318 y = 0;
4319 width = 0;
4320 height = 0;
4321 client_width = 0;
4322 client_height = 0;
4325 internal override FormWindowState GetWindowState(IntPtr handle) {
4326 Hwnd hwnd;
4328 hwnd = Hwnd.ObjectFromHandle(handle);
4330 if (hwnd.cached_window_state == (FormWindowState)(-1))
4331 hwnd.cached_window_state = UpdateWindowState (handle);
4333 return hwnd.cached_window_state;
4336 private FormWindowState UpdateWindowState (IntPtr handle) {
4337 IntPtr actual_atom;
4338 int actual_format;
4339 IntPtr nitems;
4340 IntPtr bytes_after;
4341 IntPtr prop = IntPtr.Zero;
4342 IntPtr atom;
4343 int maximized;
4344 bool minimized;
4345 XWindowAttributes attributes;
4346 Hwnd hwnd;
4348 hwnd = Hwnd.ObjectFromHandle(handle);
4350 maximized = 0;
4351 minimized = false;
4352 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);
4353 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
4354 for (int i = 0; i < (long)nitems; i++) {
4355 atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
4356 if ((atom == _NET_WM_STATE_MAXIMIZED_HORZ) || (atom == _NET_WM_STATE_MAXIMIZED_VERT)) {
4357 maximized++;
4358 } else if (atom == _NET_WM_STATE_HIDDEN) {
4359 minimized = true;
4362 XFree(prop);
4365 if (minimized) {
4366 return FormWindowState.Minimized;
4367 } else if (maximized == 2) {
4368 return FormWindowState.Maximized;
4371 attributes = new XWindowAttributes();
4372 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4373 if (attributes.map_state == MapState.IsUnmapped) {
4374 return (FormWindowState)(-1);
4378 return FormWindowState.Normal;
4381 internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) {
4382 handle = Grab.Hwnd;
4383 GrabConfined = Grab.Confined;
4384 GrabArea = Grab.Area;
4387 internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) {
4388 Hwnd hwnd;
4389 IntPtr confine_to_window;
4391 confine_to_window = IntPtr.Zero;
4393 if (confine_to_handle != IntPtr.Zero) {
4394 XWindowAttributes attributes = new XWindowAttributes();
4396 hwnd = Hwnd.ObjectFromHandle(confine_to_handle);
4398 lock (XlibLock) {
4399 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4401 Grab.Area.X = attributes.x;
4402 Grab.Area.Y = attributes.y;
4403 Grab.Area.Width = attributes.width;
4404 Grab.Area.Height = attributes.height;
4405 Grab.Confined = true;
4406 confine_to_window = hwnd.client_window;
4409 Grab.Hwnd = handle;
4411 hwnd = Hwnd.ObjectFromHandle(handle);
4413 lock (XlibLock) {
4414 XGrabPointer(DisplayHandle, hwnd.client_window, false,
4415 EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
4416 EventMask.ButtonReleaseMask | EventMask.PointerMotionMask |
4417 EventMask.LeaveWindowMask,
4418 GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
4422 internal override void UngrabWindow(IntPtr hwnd) {
4423 lock (XlibLock) {
4424 XUngrabPointer(DisplayHandle, IntPtr.Zero);
4425 XFlush(DisplayHandle);
4427 WindowUngrabbed (hwnd);
4430 private void WindowUngrabbed (IntPtr hwnd) {
4431 bool was_grabbed = Grab.Hwnd != IntPtr.Zero;
4433 Grab.Hwnd = IntPtr.Zero;
4434 Grab.Confined = false;
4436 if (was_grabbed) {
4437 // lparam should be the handle to the window gaining the mouse capture,
4438 // but X doesn't seem to give us that information.
4439 // Also only generate WM_CAPTURECHANGED if the window actually was grabbed.
4440 // X will send a NotifyUngrab, but since it comes late sometimes we're
4441 // calling WindowUngrabbed directly from UngrabWindow in order to send
4442 // this WM right away.
4443 SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero);
4447 internal override void HandleException(Exception e) {
4448 StackTrace st = new StackTrace(e, true);
4449 Console.WriteLine("Exception '{0}'", e.Message+st.ToString());
4450 Console.WriteLine("{0}{1}", e.Message, st.ToString());
4453 internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
4454 Hwnd hwnd;
4456 hwnd = Hwnd.ObjectFromHandle(handle);
4458 if (clear) {
4459 AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height);
4460 } else {
4461 AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height);
4465 internal override void InvalidateNC (IntPtr handle) {
4466 Hwnd hwnd;
4468 hwnd = Hwnd.ObjectFromHandle(handle);
4470 AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
4473 internal override bool IsEnabled(IntPtr handle) {
4474 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4475 return (hwnd != null && hwnd.Enabled);
4478 internal override bool IsVisible(IntPtr handle) {
4479 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4480 return (hwnd != null && hwnd.visible);
4483 internal override void KillTimer(Timer timer) {
4484 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
4486 if (queue == null) {
4487 // This isn't really an error, MS doesn't start the timer if
4488 // it has no assosciated queue
4489 return;
4491 queue.timer_list.Remove (timer);
4494 internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) {
4495 int dest_x_return;
4496 int dest_y_return;
4497 IntPtr child;
4498 Hwnd hwnd;
4500 hwnd = Hwnd.ObjectFromHandle(handle);
4502 lock (XlibLock) {
4503 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
4506 x = dest_x_return;
4507 y = dest_y_return;
4510 internal override void OverrideCursor(IntPtr cursor)
4512 if (Grab.Hwnd != IntPtr.Zero) {
4513 XChangeActivePointerGrab (DisplayHandle,
4514 EventMask.ButtonMotionMask |
4515 EventMask.PointerMotionMask |
4516 EventMask.ButtonPressMask |
4517 EventMask.ButtonReleaseMask,
4518 cursor, IntPtr.Zero);
4519 return;
4522 OverrideCursorHandle = cursor;
4525 internal override PaintEventArgs PaintEventStart(IntPtr handle, bool client) {
4526 PaintEventArgs paint_event;
4527 Hwnd hwnd;
4529 hwnd = Hwnd.ObjectFromHandle(handle);
4531 if (Caret.Visible == true) {
4532 Caret.Paused = true;
4533 HideCaret();
4536 Graphics dc;
4538 if (client) {
4539 dc = Graphics.FromHwnd (hwnd.client_window);
4541 Region clip_region = new Region ();
4542 clip_region.MakeEmpty();
4544 foreach (Rectangle r in hwnd.ClipRectangles) {
4545 clip_region.Union (r);
4548 if (hwnd.UserClip != null) {
4549 clip_region.Intersect(hwnd.UserClip);
4552 dc.Clip = clip_region;
4553 paint_event = new PaintEventArgs(dc, hwnd.Invalid);
4554 hwnd.expose_pending = false;
4556 hwnd.ClearInvalidArea();
4558 hwnd.drawing_stack.Push (paint_event);
4559 hwnd.drawing_stack.Push (dc);
4561 return paint_event;
4562 } else {
4563 dc = Graphics.FromHwnd (hwnd.whole_window);
4565 if (!hwnd.nc_invalid.IsEmpty) {
4566 dc.SetClip (hwnd.nc_invalid);
4567 paint_event = new PaintEventArgs(dc, hwnd.nc_invalid);
4568 } else {
4569 paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height));
4571 hwnd.nc_expose_pending = false;
4573 hwnd.ClearNcInvalidArea ();
4575 hwnd.drawing_stack.Push (paint_event);
4576 hwnd.drawing_stack.Push (dc);
4578 return paint_event;
4582 internal override void PaintEventEnd(IntPtr handle, bool client) {
4583 Hwnd hwnd;
4585 hwnd = Hwnd.ObjectFromHandle(handle);
4587 Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
4588 dc.Flush();
4589 dc.Dispose();
4591 PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop();
4592 pe.SetGraphics (null);
4593 pe.Dispose ();
4595 if (Caret.Visible == true) {
4596 ShowCaret();
4597 Caret.Paused = false;
4601 [MonoTODO("Implement filtering and PM_NOREMOVE")]
4602 internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
4603 XEventQueue queue = (XEventQueue) queue_id;
4604 bool pending;
4606 if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
4607 throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
4610 pending = false;
4611 if (queue.Count > 0) {
4612 pending = true;
4613 } else {
4614 // Only call UpdateMessageQueue if real events are pending
4615 // otherwise we go to sleep on the socket
4616 if (XPending(DisplayHandle) != 0) {
4617 UpdateMessageQueue((XEventQueue)queue_id);
4618 pending = true;
4619 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
4620 pending = true;
4624 CheckTimers(queue.timer_list, DateTime.UtcNow);
4626 if (!pending) {
4627 return false;
4629 return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
4632 internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) {
4633 XEvent xevent = new XEvent ();
4634 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
4636 xevent.type = XEventName.ClientMessage;
4637 xevent.ClientMessageEvent.display = DisplayHandle;
4639 if (hwnd != null) {
4640 xevent.ClientMessageEvent.window = hwnd.whole_window;
4641 } else {
4642 xevent.ClientMessageEvent.window = IntPtr.Zero;
4645 xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
4646 xevent.ClientMessageEvent.format = 32;
4647 xevent.ClientMessageEvent.ptr1 = handle;
4648 xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
4649 xevent.ClientMessageEvent.ptr3 = wparam;
4650 xevent.ClientMessageEvent.ptr4 = lparam;
4652 hwnd.Queue.EnqueueLocked (xevent);
4654 return true;
4657 internal override void PostQuitMessage(int exitCode) {
4658 PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4659 XFlush(DisplayHandle);
4662 internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave)
4664 // TODO
4667 internal override void RequestNCRecalc(IntPtr handle) {
4668 Hwnd hwnd;
4670 hwnd = Hwnd.ObjectFromHandle(handle);
4672 if (hwnd == null) {
4673 return;
4676 PerformNCCalc(hwnd);
4677 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4678 InvalidateNC(handle);
4681 internal override void ResetMouseHover(IntPtr handle) {
4682 Hwnd hwnd;
4684 hwnd = Hwnd.ObjectFromHandle(handle);
4685 if (hwnd == null) {
4686 return;
4689 HoverState.Timer.Enabled = true;
4690 HoverState.X = mouse_position.X;
4691 HoverState.Y = mouse_position.Y;
4692 HoverState.Window = handle;
4696 internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) {
4697 int dest_x_return;
4698 int dest_y_return;
4699 IntPtr child;
4700 Hwnd hwnd;
4702 hwnd = Hwnd.ObjectFromHandle(handle);
4704 lock (XlibLock) {
4705 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
4708 x = dest_x_return;
4709 y = dest_y_return;
4712 internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) {
4713 int dest_x_return;
4714 int dest_y_return;
4715 IntPtr child;
4716 Hwnd hwnd;
4718 hwnd = Hwnd.ObjectFromHandle(handle);
4720 lock (XlibLock) {
4721 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
4724 Form form = Control.FromHandle (handle) as Form;
4725 if (form != null && form.window_manager != null) {
4726 dest_y_return -= form.window_manager.TitleBarHeight;
4729 x = dest_x_return;
4730 y = dest_y_return;
4733 internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
4734 Hwnd hwnd;
4735 IntPtr gc;
4736 XGCValues gc_values;
4738 hwnd = Hwnd.ObjectFromHandle(handle);
4740 Rectangle r = Rectangle.Intersect (hwnd.Invalid, area);
4741 if (!r.IsEmpty) {
4742 /* We have an invalid area in the window we're scrolling.
4743 Adjust our stored invalid rectangle to to match the scrolled amount */
4745 r.X += XAmount;
4746 r.Y += YAmount;
4748 if (r.X < 0) {
4749 r.Width += r.X;
4750 r.X =0;
4753 if (r.Y < 0) {
4754 r.Height += r.Y;
4755 r.Y =0;
4758 if (area.Contains (hwnd.Invalid))
4759 hwnd.ClearInvalidArea ();
4760 hwnd.AddInvalidArea(r);
4763 gc_values = new XGCValues();
4765 if (with_children) {
4766 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
4769 gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
4771 int src_x, src_y;
4772 int dest_x, dest_y;
4773 int width, height;
4775 if (YAmount > 0) {
4776 src_y = area.Y;
4777 height = area.Height - YAmount;
4778 dest_y = area.Y + YAmount;
4780 else {
4781 src_y = area.Y - YAmount;
4782 height = area.Height + YAmount;
4783 dest_y = area.Y;
4786 if (XAmount > 0) {
4787 src_x = area.X;
4788 width = area.Width - XAmount;
4789 dest_x = area.X + XAmount;
4791 else {
4792 src_x = area.X - XAmount;
4793 width = area.Width + XAmount;
4794 dest_x = area.X;
4797 XCopyArea(DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src_x, src_y, width, height, dest_x, dest_y);
4799 // Generate an expose for the area exposed by the horizontal scroll
4800 // We don't use AddExpose since we're
4801 if (XAmount > 0) {
4802 AddExpose(hwnd, true, area.X, area.Y, XAmount, area.Height);
4803 } else if (XAmount < 0) {
4804 AddExpose(hwnd, true, XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
4807 // Generate an expose for the area exposed by the vertical scroll
4808 if (YAmount > 0) {
4809 AddExpose(hwnd, true, area.X, area.Y, area.Width, YAmount);
4810 } else if (YAmount < 0) {
4811 AddExpose(hwnd, true, area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
4813 XFreeGC(DisplayHandle, gc);
4816 internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) {
4817 Hwnd hwnd;
4818 Rectangle rect;
4820 hwnd = Hwnd.GetObjectFromWindow(handle);
4822 rect = hwnd.ClientRect;
4823 rect.X = 0;
4824 rect.Y = 0;
4825 ScrollWindow(handle, rect, XAmount, YAmount, with_children);
4828 internal override void SendAsyncMethod (AsyncMethodData method) {
4829 Hwnd hwnd;
4830 XEvent xevent = new XEvent ();
4832 hwnd = Hwnd.ObjectFromHandle(method.Handle);
4834 xevent.type = XEventName.ClientMessage;
4835 xevent.ClientMessageEvent.display = DisplayHandle;
4836 xevent.ClientMessageEvent.window = method.Handle;
4837 xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
4838 xevent.ClientMessageEvent.format = 32;
4839 xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
4841 hwnd.Queue.EnqueueLocked (xevent);
4843 WakeupMain ();
4846 delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
4848 internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
4850 Hwnd h;
4851 h = Hwnd.ObjectFromHandle(hwnd);
4853 if (h != null && h.queue != ThreadQueue (Thread.CurrentThread)) {
4854 AsyncMethodResult result;
4855 AsyncMethodData data;
4857 result = new AsyncMethodResult ();
4858 data = new AsyncMethodData ();
4860 data.Handle = hwnd;
4861 data.Method = new WndProcDelegate (NativeWindow.WndProc);
4862 data.Args = new object[] { hwnd, message, wParam, lParam };
4863 data.Result = result;
4865 SendAsyncMethod (data);
4866 #if DriverDebug || DriverDebugThreads
4867 Console.WriteLine ("Sending {0} message across.", message);
4868 #endif
4870 return IntPtr.Zero;
4872 return NativeWindow.WndProc(hwnd, message, wParam, lParam);
4875 internal override int SendInput(IntPtr handle, Queue keys) {
4876 if (handle == IntPtr.Zero)
4877 return 0;
4879 int count = keys.Count;
4880 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
4882 while (keys.Count > 0) {
4884 MSG msg = (MSG)keys.Dequeue();
4886 XEvent xevent = new XEvent ();
4888 xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
4889 xevent.KeyEvent.display = DisplayHandle;
4891 if (hwnd != null) {
4892 xevent.KeyEvent.window = hwnd.whole_window;
4893 } else {
4894 xevent.KeyEvent.window = IntPtr.Zero;
4897 xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
4899 hwnd.Queue.EnqueueLocked (xevent);
4901 return count;
4904 internal override void SetAllowDrop (IntPtr handle, bool value)
4906 // We allow drop on all windows
4909 internal override DragDropEffects StartDrag (IntPtr handle, object data,
4910 DragDropEffects allowed_effects)
4912 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4914 if (hwnd == null)
4915 throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
4917 return Dnd.StartDrag (hwnd.client_window, data, allowed_effects);
4920 internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
4921 Form form = Control.FromHandle (handle) as Form;
4922 if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow ||
4923 border_style == FormBorderStyle.SizableToolWindow)) {
4924 form.window_manager = new ToolWindowManager (form);
4927 RequestNCRecalc(handle);
4930 internal override void SetCaretPos(IntPtr handle, int x, int y) {
4931 if (Caret.Hwnd == handle) {
4932 Caret.Timer.Stop();
4933 HideCaret();
4935 Caret.X = x;
4936 Caret.Y = y;
4938 if (Caret.Visible == true) {
4939 ShowCaret();
4940 Caret.Timer.Start();
4945 internal override void SetClipRegion(IntPtr handle, Region region) {
4946 Hwnd hwnd;
4948 hwnd = Hwnd.ObjectFromHandle(handle);
4949 if (hwnd == null) {
4950 return;
4953 hwnd.UserClip = region;
4956 internal override void SetCursor(IntPtr handle, IntPtr cursor) {
4957 Hwnd hwnd;
4959 if (OverrideCursorHandle == IntPtr.Zero) {
4960 if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
4961 return;
4964 LastCursorHandle = cursor;
4965 LastCursorWindow = handle;
4967 hwnd = Hwnd.ObjectFromHandle(handle);
4968 lock (XlibLock) {
4969 if (cursor != IntPtr.Zero) {
4970 XDefineCursor(DisplayHandle, hwnd.whole_window, cursor);
4971 } else {
4972 XUndefineCursor(DisplayHandle, hwnd.whole_window);
4974 XFlush(DisplayHandle);
4976 return;
4979 hwnd = Hwnd.ObjectFromHandle(handle);
4980 lock (XlibLock) {
4981 XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
4985 private void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child,
4986 out int root_x, out int root_y, out int child_x, out int child_y,
4987 out int mask)
4989 /* this code was written with the help of
4990 glance at gdk. I never would have realized we
4991 needed a loop in order to traverse down in the
4992 hierarchy. I would have assumed you'd get the
4993 most deeply nested child and have to do
4994 XQueryTree to move back up the hierarchy..
4995 stupid me, of course. */
4996 IntPtr c;
4998 XGrabServer (display);
5000 XQueryPointer(display, w, out root, out c,
5001 out root_x, out root_y, out child_x, out child_y,
5002 out mask);
5004 if (root != w)
5005 c = root;
5007 IntPtr child_last = IntPtr.Zero;
5008 while (c != IntPtr.Zero) {
5009 child_last = c;
5010 XQueryPointer(display, c, out root, out c,
5011 out root_x, out root_y, out child_x, out child_y,
5012 out mask);
5014 XUngrabServer (display);
5015 XFlush (display);
5017 child = child_last;
5020 internal override void SetCursorPos(IntPtr handle, int x, int y) {
5021 if (handle == IntPtr.Zero) {
5022 lock (XlibLock) {
5023 IntPtr root, child;
5024 int root_x, root_y, child_x, child_y, mask;
5026 /* we need to do a
5027 * QueryPointer before warping
5028 * because if the warp is on
5029 * the RootWindow, the x/y are
5030 * relative to the current
5031 * mouse position
5033 QueryPointer (DisplayHandle, RootWindow,
5034 out root,
5035 out child,
5036 out root_x, out root_y,
5037 out child_x, out child_y,
5038 out mask);
5040 XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
5042 XFlush (DisplayHandle);
5044 /* then we need to a
5045 * QueryPointer after warping
5046 * to manually generate a
5047 * motion event for the window
5048 * we move into.
5050 QueryPointer (DisplayHandle, RootWindow,
5051 out root,
5052 out child,
5053 out root_x, out root_y,
5054 out child_x, out child_y,
5055 out mask);
5057 Hwnd child_hwnd = Hwnd.ObjectFromHandle(child);
5058 if (child_hwnd == null) {
5059 return;
5062 XEvent xevent = new XEvent ();
5064 xevent.type = XEventName.MotionNotify;
5065 xevent.MotionEvent.display = DisplayHandle;
5066 xevent.MotionEvent.window = child_hwnd.client_window;
5067 xevent.MotionEvent.root = RootWindow;
5068 xevent.MotionEvent.x = child_x;
5069 xevent.MotionEvent.y = child_y;
5070 xevent.MotionEvent.x_root = root_x;
5071 xevent.MotionEvent.y_root = root_y;
5072 xevent.MotionEvent.state = mask;
5074 child_hwnd.Queue.EnqueueLocked (xevent);
5076 } else {
5077 Hwnd hwnd;
5079 hwnd = Hwnd.ObjectFromHandle(handle);
5080 lock (XlibLock) {
5081 XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
5086 internal override void SetFocus(IntPtr handle) {
5087 Hwnd hwnd;
5088 IntPtr prev_focus_window;
5090 hwnd = Hwnd.ObjectFromHandle(handle);
5092 if (hwnd.client_window == FocusWindow) {
5093 return;
5096 prev_focus_window = FocusWindow;
5097 FocusWindow = hwnd.client_window;
5099 if (prev_focus_window != IntPtr.Zero) {
5100 SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
5102 SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
5104 //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
5107 internal override void SetIcon(IntPtr handle, Icon icon) {
5108 Hwnd hwnd;
5110 hwnd = Hwnd.ObjectFromHandle(handle);
5111 if (hwnd != null) {
5112 SetIcon(hwnd, icon);
5116 internal override void SetMenu(IntPtr handle, Menu menu) {
5117 Hwnd hwnd;
5119 hwnd = Hwnd.ObjectFromHandle(handle);
5120 hwnd.menu = menu;
5122 RequestNCRecalc(handle);
5125 internal override void SetModal(IntPtr handle, bool Modal) {
5126 if (Modal) {
5127 ModalWindows.Push(handle);
5128 } else {
5129 if (ModalWindows.Contains(handle)) {
5130 ModalWindows.Pop();
5132 if (ModalWindows.Count > 0) {
5133 Activate((IntPtr)ModalWindows.Peek());
5137 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
5138 Control ctrl = Control.FromHandle (handle);
5139 SetWMStyles (hwnd, ctrl.GetCreateParams ());
5142 internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
5143 Hwnd hwnd;
5145 hwnd = Hwnd.ObjectFromHandle(handle);
5146 hwnd.parent = Hwnd.ObjectFromHandle(parent);
5148 lock (XlibLock) {
5149 #if DriverDebug || DriverDebugParent
5150 Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(hwnd.Handle), XplatUI.Window(hwnd.parent != null ? hwnd.parent.Handle : IntPtr.Zero));
5151 #endif
5152 XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent == null ? FosterParent : hwnd.parent.client_window, hwnd.x, hwnd.y);
5155 return IntPtr.Zero;
5158 internal override void SetTimer (Timer timer) {
5159 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
5161 if (queue == null) {
5162 // This isn't really an error, MS doesn't start the timer if
5163 // it has no assosciated queue
5164 return;
5166 queue.timer_list.Add (timer);
5167 WakeupMain ();
5170 internal override bool SetTopmost(IntPtr handle, bool enabled) {
5172 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5174 if (enabled) {
5175 lock (XlibLock) {
5176 int[] atoms = new int[8];
5177 atoms[0] = _NET_WM_STATE_ABOVE.ToInt32();
5178 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5180 } else {
5181 lock (XlibLock) {
5182 XDeleteProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE);
5185 return true;
5188 internal override bool SetOwner(IntPtr handle, IntPtr handle_owner) {
5189 Hwnd hwnd;
5190 Hwnd hwnd_owner;
5192 hwnd = Hwnd.ObjectFromHandle(handle);
5194 if (handle_owner != IntPtr.Zero) {
5195 hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
5196 lock (XlibLock) {
5197 int[] atoms;
5199 atoms = new int[8];
5201 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
5202 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
5204 if (hwnd_owner != null) {
5205 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
5206 } else {
5207 XSetTransientForHint(DisplayHandle, hwnd.whole_window, RootWindow);
5210 } else {
5211 lock (XlibLock) {
5212 XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR);
5215 return true;
5218 internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
5220 Hwnd hwnd;
5222 hwnd = Hwnd.ObjectFromHandle(handle);
5223 hwnd.visible = visible;
5225 lock (XlibLock) {
5226 if (visible) {
5227 MapWindow(hwnd, WindowType.Both);
5229 if (Control.FromHandle(handle) is Form) {
5230 FormWindowState s;
5232 s = ((Form)Control.FromHandle(handle)).WindowState;
5234 switch(s) {
5235 case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break;
5236 case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break;
5240 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5242 else {
5243 UnmapWindow(hwnd, WindowType.Both);
5246 return true;
5249 internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
5250 Control ctrl = Control.FromHandle (handle);
5251 SetWindowMinMax (handle, maximized, min, max, ctrl != null ? ctrl.GetCreateParams () : null);
5254 internal void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp)
5256 Hwnd hwnd;
5257 XSizeHints hints;
5258 IntPtr dummy;
5260 hwnd = Hwnd.ObjectFromHandle(handle);
5261 if (hwnd == null) {
5262 return;
5265 hints = new XSizeHints();
5267 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
5268 if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
5269 if (cp != null)
5270 min = TranslateWindowSizeToXWindowSize (cp);
5271 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
5272 hints.min_width = min.Width;
5273 hints.min_height = min.Height;
5276 if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
5277 if (cp != null)
5278 max = TranslateWindowSizeToXWindowSize (cp);
5279 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
5280 hints.max_width = max.Width;
5281 hints.max_height = max.Height;
5284 if (hints.flags != IntPtr.Zero) {
5285 // The Metacity team has decided that they won't care about this when clicking the maximize icon,
5286 // they will maximize the window to fill the screen/parent no matter what.
5287 // http://bugzilla.ximian.com/show_bug.cgi?id=80021
5288 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints);
5291 if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
5292 if (cp != null)
5293 maximized.Size = TranslateWindowSizeToXWindowSize (cp);
5294 hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
5295 hints.x = maximized.X;
5296 hints.y = maximized.Y;
5297 hints.width = maximized.Width;
5298 hints.height = maximized.Height;
5300 // Metacity does not seem to follow this constraint for maximized (zoomed) windows
5301 XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints);
5306 internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
5307 Hwnd hwnd;
5309 hwnd = Hwnd.ObjectFromHandle(handle);
5311 if (hwnd == null) {
5312 return;
5315 // Win32 automatically changes negative width/height to 0.
5316 if (width < 0)
5317 width = 0;
5318 if (height < 0)
5319 height = 0;
5321 // X requires a sanity check for width & height; otherwise it dies
5322 if (hwnd.zero_sized && width > 0 && height > 0) {
5323 if (hwnd.visible) {
5324 MapWindow(hwnd, WindowType.Whole);
5326 hwnd.zero_sized = false;
5329 if ((width < 1) || (height < 1)) {
5330 hwnd.zero_sized = true;
5331 UnmapWindow(hwnd, WindowType.Whole);
5334 // Save a server roundtrip (and prevent a feedback loop)
5335 if ((hwnd.x == x) && (hwnd.y == y) &&
5336 (hwnd.width == width) && (hwnd.height == height)) {
5337 return;
5340 if (!hwnd.zero_sized) {
5341 //Hack?
5342 hwnd.x = x;
5343 hwnd.y = y;
5344 hwnd.width = width;
5345 hwnd.height = height;
5346 SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
5348 if (hwnd.fixed_size) {
5349 SetWindowMinMax(handle, Rectangle.Empty, new Size(width, height), new Size(width, height));
5352 lock (XlibLock) {
5353 Control ctrl = Control.FromHandle (handle);
5354 Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams ());
5355 XMoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
5356 PerformNCCalc(hwnd);
5360 // Update our position/size immediately, so
5361 // that future calls to SetWindowPos aren't
5362 // kept from calling XMoveResizeWindow (by the
5363 // "Save a server roundtrip" block above).
5364 hwnd.x = x;
5365 hwnd.y = y;
5366 hwnd.width = width;
5367 hwnd.height = height;
5368 hwnd.ClientRect = Rectangle.Empty;
5371 internal override void SetWindowState(IntPtr handle, FormWindowState state) {
5372 FormWindowState current_state;
5373 Hwnd hwnd;
5375 hwnd = Hwnd.ObjectFromHandle(handle);
5377 current_state = GetWindowState(handle);
5379 if (current_state == state) {
5380 return;
5383 switch(state) {
5384 case FormWindowState.Normal: {
5385 lock (XlibLock) {
5386 if (current_state == FormWindowState.Minimized) {
5387 MapWindow(hwnd, WindowType.Both);
5388 } else if (current_state == FormWindowState.Maximized) {
5389 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5392 Activate(handle);
5393 return;
5396 case FormWindowState.Minimized: {
5397 lock (XlibLock) {
5398 if (current_state == FormWindowState.Maximized) {
5399 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5401 XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo);
5403 return;
5406 case FormWindowState.Maximized: {
5407 lock (XlibLock) {
5408 if (current_state == FormWindowState.Minimized) {
5409 MapWindow(hwnd, WindowType.Both);
5412 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)1 /* Add */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5414 Activate(handle);
5415 return;
5420 internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
5421 Hwnd hwnd;
5423 hwnd = Hwnd.ObjectFromHandle(handle);
5424 SetHwndStyles(hwnd, cp);
5425 SetWMStyles(hwnd, cp);
5428 internal override double GetWindowTransparency(IntPtr handle)
5430 return 1.0;
5433 internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) {
5434 Hwnd hwnd;
5435 IntPtr opacity;
5437 hwnd = Hwnd.ObjectFromHandle(handle);
5439 if (hwnd == null) {
5440 return;
5443 hwnd.opacity = (uint)(0xffffffff * transparency);
5444 opacity = (IntPtr)((int)hwnd.opacity);
5446 IntPtr w = hwnd.whole_window;
5447 if (hwnd.reparented)
5448 w = XGetParent (hwnd.whole_window);
5449 XChangeProperty(DisplayHandle, w, _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
5452 internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) {
5453 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5455 if (!hwnd.mapped) {
5456 return false;
5459 if (top) {
5460 lock (XlibLock) {
5461 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5463 return true;
5464 } else if (!bottom) {
5465 Hwnd after_hwnd = null;
5467 if (after_handle != IntPtr.Zero) {
5468 after_hwnd = Hwnd.ObjectFromHandle(after_handle);
5471 XWindowChanges values = new XWindowChanges();
5473 if (after_hwnd == null) {
5474 // Work around metacity 'issues'
5475 int[] atoms;
5477 atoms = new int[2];
5478 atoms[0] = unixtime();
5479 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_USER_TIME, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, atoms, 1);
5481 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5482 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
5483 return true;
5484 //throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order");
5487 values.sibling = after_hwnd.whole_window;
5488 values.stack_mode = StackMode.Below;
5490 lock (XlibLock) {
5491 XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
5493 } else {
5494 // Bottom
5495 lock (XlibLock) {
5496 XLowerWindow(DisplayHandle, hwnd.whole_window);
5498 return true;
5500 return false;
5503 internal override void ShowCursor(bool show) {
5504 ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
5507 internal override object StartLoop(Thread thread) {
5508 XEventQueue q = ThreadQueue(thread);
5509 return q;
5512 internal override TransparencySupport SupportsTransparency() {
5513 // We need to check if the x compositing manager is running
5514 return TransparencySupport.Set;
5517 internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) {
5518 GetSystrayManagerWindow();
5520 if (SystrayMgrWindow != IntPtr.Zero) {
5521 XSizeHints size_hints;
5522 Hwnd hwnd;
5524 hwnd = Hwnd.ObjectFromHandle(handle);
5525 #if DriverDebug
5526 Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
5527 #endif
5529 // Oh boy.
5530 if (hwnd.client_window != hwnd.whole_window) {
5531 XDestroyWindow(DisplayHandle, hwnd.client_window);
5532 hwnd.client_window = hwnd.whole_window;
5535 /* by virtue of the way the tests are ordered when determining if it's PAINT
5536 or NCPAINT, client_window == whole_window will always be PAINT. So, if we're
5537 waiting on an nc_expose, drop it and remove the hwnd from the list (unless
5538 there's a pending expose). */
5539 if (hwnd.nc_expose_pending) {
5540 hwnd.nc_expose_pending = false;
5541 if (!hwnd.expose_pending)
5542 hwnd.Queue.Paint.Remove (hwnd);
5545 size_hints = new XSizeHints();
5547 size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
5549 size_hints.min_width = 24;
5550 size_hints.min_height = 24;
5551 size_hints.max_width = 24;
5552 size_hints.max_height = 24;
5553 size_hints.base_width = 24;
5554 size_hints.base_height = 24;
5556 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints);
5558 int[] atoms = new int[2];
5559 atoms [0] = 1; // Version 1
5560 atoms [1] = 1; // we want to be mapped
5562 // This line cost me 3 days...
5563 XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2);
5565 // Need to pick some reasonable defaults
5566 tt = new ToolTip();
5567 tt.AutomaticDelay = 350;
5568 tt.InitialDelay = 250;
5569 tt.ReshowDelay = 250;
5570 tt.ShowAlways = true;
5572 if ((tip != null) && (tip != string.Empty)) {
5573 tt.SetToolTip(Control.FromHandle(handle), tip);
5574 tt.Active = true;
5575 } else {
5576 tt.Active = false;
5579 SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
5581 return true;
5583 tt = null;
5584 return false;
5587 internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) {
5588 Control control;
5590 control = Control.FromHandle(handle);
5591 if (control != null && tt != null) {
5592 tt.SetToolTip(control, tip);
5593 tt.Active = true;
5594 return true;
5595 } else {
5596 return false;
5600 internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
5602 SetVisible (handle, false, false);
5604 // The caller can now re-dock it later...
5605 if (tt != null) {
5606 tt.Dispose();
5607 tt = null;
5611 #if NET_2_0
5612 internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
5614 ThemeEngine.Current.ShowBalloonWindow (handle, timeout, title, text, icon);
5615 SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW);
5617 #endif
5619 internal override bool Text(IntPtr handle, string text) {
5620 Hwnd hwnd;
5622 hwnd = Hwnd.ObjectFromHandle(handle);
5624 lock (XlibLock) {
5625 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_NAME, UNICODETEXT, 8,
5626 PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
5628 // XXX this has problems with UTF8.
5629 // we need to either use the actual
5630 // text if it's latin-1, or convert it
5631 // to compound text if it's in a
5632 // different charset.
5633 XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text);
5635 return true;
5638 internal override bool TranslateMessage(ref MSG msg) {
5639 return Keyboard.TranslateMessage (ref msg);
5642 internal override void UpdateWindow(IntPtr handle) {
5643 Hwnd hwnd;
5645 hwnd = Hwnd.ObjectFromHandle(handle);
5647 if (!hwnd.visible || !hwnd.expose_pending || !hwnd.Mapped) {
5648 return;
5651 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5652 hwnd.Queue.Paint.Remove(hwnd);
5655 internal override void CreateOffscreenDrawable (IntPtr handle,
5656 int width, int height,
5657 out object offscreen_drawable)
5659 IntPtr root_out;
5660 int x_out, y_out, width_out, height_out, border_width_out, depth_out;
5662 XGetGeometry (DisplayHandle, handle,
5663 out root_out,
5664 out x_out, out y_out,
5665 out width_out, out height_out,
5666 out border_width_out, out depth_out);
5668 IntPtr pixmap = XCreatePixmap (DisplayHandle, handle, width, height, depth_out);
5670 offscreen_drawable = pixmap;
5674 internal override void DestroyOffscreenDrawable (object offscreen_drawable)
5676 XFreePixmap (DisplayHandle, (IntPtr)offscreen_drawable);
5679 internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
5681 return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
5684 internal override void BlitFromOffscreen (IntPtr dest_handle,
5685 Graphics dest_dc,
5686 object offscreen_drawable,
5687 Graphics offscreen_dc,
5688 Rectangle r)
5690 XGCValues gc_values;
5691 IntPtr gc;
5693 gc_values = new XGCValues();
5695 gc = XCreateGC (DisplayHandle, dest_handle, IntPtr.Zero, ref gc_values);
5697 XCopyArea (DisplayHandle, (IntPtr)offscreen_drawable, dest_handle,
5698 gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
5700 XFreeGC (DisplayHandle, gc);
5703 #endregion // Public Static Methods
5705 #region Events
5706 internal override event EventHandler Idle;
5707 #endregion // Events
5709 #region Xcursor imports
5710 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")]
5711 internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name);
5713 [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")]
5714 internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size);
5716 [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")]
5717 internal extern static void XcursorImagesDestroy (IntPtr images);
5719 [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")]
5720 internal extern static int XcursorGetDefaultSize (IntPtr display);
5722 [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")]
5723 internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image);
5725 [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")]
5726 internal extern static IntPtr XcursorGetTheme (IntPtr display);
5727 #endregion
5728 #region X11 Imports
5729 [DllImport ("libX11", EntryPoint="XOpenDisplay")]
5730 internal extern static IntPtr XOpenDisplay(IntPtr display);
5731 [DllImport ("libX11", EntryPoint="XCloseDisplay")]
5732 internal extern static int XCloseDisplay(IntPtr display);
5733 [DllImport ("libX11", EntryPoint="XSynchronize")]
5734 internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
5736 [DllImport ("libX11", EntryPoint="XCreateWindow")]
5737 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);
5738 [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
5739 internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
5740 [DllImport ("libX11", EntryPoint="XMapWindow")]
5741 internal extern static int XMapWindow(IntPtr display, IntPtr window);
5742 [DllImport ("libX11", EntryPoint="XUnmapWindow")]
5743 internal extern static int XUnmapWindow(IntPtr display, IntPtr window);
5744 [DllImport ("libX11", EntryPoint="XMapSubwindows")]
5745 internal extern static int XMapSubindows(IntPtr display, IntPtr window);
5746 [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
5747 internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
5748 [DllImport ("libX11", EntryPoint="XRootWindow")]
5749 internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
5750 [DllImport ("libX11", EntryPoint="XNextEvent")]
5751 internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
5752 [DllImport ("libX11")]
5753 internal extern static int XConnectionNumber (IntPtr diplay);
5754 [DllImport ("libX11")]
5755 internal extern static int XPending (IntPtr diplay);
5756 [DllImport ("libX11", EntryPoint="XSelectInput")]
5757 internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
5759 [DllImport ("libX11", EntryPoint="XDestroyWindow")]
5760 internal extern static int XDestroyWindow(IntPtr display, IntPtr window);
5762 [DllImport ("libX11", EntryPoint="XReparentWindow")]
5763 internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
5764 [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
5765 internal extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
5767 [DllImport ("libX11", EntryPoint="XResizeWindow")]
5768 internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
5770 [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
5771 internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
5773 [DllImport ("libX11", EntryPoint="XFlush")]
5774 internal extern static int XFlush(IntPtr display);
5776 [DllImport ("libX11", EntryPoint="XSetWMName")]
5777 internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
5779 [DllImport ("libX11", EntryPoint="XStoreName")]
5780 internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
5782 [DllImport ("libX11", EntryPoint="XFetchName")]
5783 internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
5785 [DllImport ("libX11", EntryPoint="XSendEvent")]
5786 internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
5788 [DllImport ("libX11", EntryPoint="XQueryTree")]
5789 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);
5791 [DllImport ("libX11", EntryPoint="XFree")]
5792 internal extern static int XFree(IntPtr data);
5794 [DllImport ("libX11", EntryPoint="XRaiseWindow")]
5795 internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
5797 [DllImport ("libX11", EntryPoint="XLowerWindow")]
5798 internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
5800 [DllImport ("libX11", EntryPoint="XConfigureWindow")]
5801 internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
5803 [DllImport ("libX11", EntryPoint="XInternAtom")]
5804 internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
5806 [DllImport ("libX11", EntryPoint="XInternAtoms")]
5807 internal extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
5809 [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
5810 internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
5812 [DllImport ("libX11", EntryPoint="XGrabPointer")]
5813 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);
5815 [DllImport ("libX11", EntryPoint="XUngrabPointer")]
5816 internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp);
5818 [DllImport ("libX11", EntryPoint="XQueryPointer")]
5819 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);
5821 [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
5822 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);
5824 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5825 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);
5827 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5828 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);
5830 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5831 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);
5833 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5834 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);
5836 [DllImport ("libX11", EntryPoint="XWarpPointer")]
5837 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);
5839 [DllImport ("libX11", EntryPoint="XClearWindow")]
5840 internal extern static int XClearWindow(IntPtr display, IntPtr window);
5842 [DllImport ("libX11", EntryPoint="XClearArea")]
5843 internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
5845 // Colormaps
5846 [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
5847 internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
5849 [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
5850 internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
5852 [DllImport ("libX11", EntryPoint="XDefaultVisual")]
5853 internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
5855 [DllImport ("libX11", EntryPoint="XDefaultDepth")]
5856 internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
5858 [DllImport ("libX11", EntryPoint="XDefaultScreen")]
5859 internal extern static int XDefaultScreen(IntPtr display);
5861 [DllImport ("libX11", EntryPoint="XDefaultColormap")]
5862 internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
5864 [DllImport ("libX11", EntryPoint="XLookupColor")]
5865 internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
5867 [DllImport ("libX11", EntryPoint="XAllocColor")]
5868 internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
5870 [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
5871 internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
5873 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5874 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
5876 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5877 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
5879 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5880 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
5882 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5883 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
5885 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5886 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
5888 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5889 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
5891 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5892 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
5894 [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
5895 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
5897 [DllImport ("libX11", EntryPoint="XDeleteProperty")]
5898 internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
5900 // Drawing
5901 [DllImport ("libX11", EntryPoint="XCreateGC")]
5902 internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
5904 [DllImport ("libX11", EntryPoint="XFreeGC")]
5905 internal extern static int XFreeGC(IntPtr display, IntPtr gc);
5907 [DllImport ("libX11", EntryPoint="XSetFunction")]
5908 internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
5910 [DllImport ("libX11", EntryPoint="XSetLineAttributes")]
5911 internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
5913 [DllImport ("libX11", EntryPoint="XDrawLine")]
5914 internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
5916 [DllImport ("libX11", EntryPoint="XDrawRectangle")]
5917 internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
5919 [DllImport ("libX11", EntryPoint="XFillRectangle")]
5920 internal extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
5922 [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
5923 internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
5925 [DllImport ("libX11", EntryPoint="XCopyArea")]
5926 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);
5928 [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
5929 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);
5931 [DllImport ("libX11", EntryPoint="XSetInputFocus")]
5932 internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
5934 [DllImport ("libX11", EntryPoint="XIconifyWindow")]
5935 internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
5937 [DllImport ("libX11", EntryPoint="XDefineCursor")]
5938 internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
5940 [DllImport ("libX11", EntryPoint="XUndefineCursor")]
5941 internal extern static int XUndefineCursor(IntPtr display, IntPtr window);
5943 [DllImport ("libX11", EntryPoint="XFreeCursor")]
5944 internal extern static int XFreeCursor(IntPtr display, IntPtr cursor);
5946 [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
5947 internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
5949 [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
5950 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);
5952 [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
5953 internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
5955 [DllImport ("libX11", EntryPoint="XCreatePixmap")]
5956 internal extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
5958 [DllImport ("libX11", EntryPoint="XFreePixmap")]
5959 internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
5961 [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
5962 internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
5964 [DllImport ("libX11", EntryPoint="XQueryExtension")]
5965 internal extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
5967 [DllImport ("libX11", EntryPoint="XWhitePixel")]
5968 internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
5970 [DllImport ("libX11", EntryPoint="XBlackPixel")]
5971 internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
5973 [DllImport ("libX11", EntryPoint="XGrabServer")]
5974 internal extern static void XGrabServer(IntPtr display);
5976 [DllImport ("libX11", EntryPoint="XUngrabServer")]
5977 internal extern static void XUngrabServer(IntPtr display);
5979 [DllImport ("libX11", EntryPoint="XGetWMNormalHints")]
5980 internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
5982 [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
5983 internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
5985 [DllImport ("libX11", EntryPoint="XSetZoomHints")]
5986 internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
5988 [DllImport ("libX11", EntryPoint="XSetWMHints")]
5989 internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
5991 [DllImport ("libX11", EntryPoint="XGetIconSizes")]
5992 internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
5994 [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
5995 internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
5997 [DllImport ("libX11", EntryPoint="XGetErrorText")]
5998 internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
6000 [DllImport ("libX11", EntryPoint="XInitThreads")]
6001 internal extern static int XInitThreads();
6003 [DllImport ("libX11", EntryPoint="XConvertSelection")]
6004 internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
6006 [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
6007 internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
6009 [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
6010 internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
6012 [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
6013 internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
6015 [DllImport ("libX11", EntryPoint="XSetForeground")]
6016 internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
6018 [DllImport ("libX11", EntryPoint="XSetBackground")]
6019 internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
6021 [DllImport ("libX11", EntryPoint="XBell")]
6022 internal extern static int XBell(IntPtr display, int percent);
6024 [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")]
6025 internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
6027 [DllImport ("libX11", EntryPoint="XFilterEvent")]
6028 internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
6030 [DllImport ("libX11")]
6031 internal extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
6033 [DllImport ("libX11")]
6034 internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
6035 #endregion