In Test/System.Windows.Forms:
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / XplatUIX11.cs
blobf66f2cf1591bbe80c1c0b2c8a684258ac0a37f3e
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
91 // Clipboard
92 private static IntPtr ClipMagic;
93 private static ClipboardStruct Clipboard; // Our clipboard
95 // Communication
96 private static IntPtr PostAtom; // PostMessage atom
97 private static IntPtr AsyncAtom; // Support for async messages
99 // Message Loop
100 private static Hashtable MessageQueues; // Holds our thread-specific XEventQueues
101 #if __MonoCS__ //
102 private static Pollfd[] pollfds; // For watching the X11 socket
103 private static bool wake_waiting;
104 private static object wake_waiting_lock = new object ();
105 #endif //
106 private static X11Keyboard Keyboard; //
107 private static X11Dnd Dnd;
108 private static Socket listen; //
109 private static Socket wake; //
110 private static Socket wake_receive; //
111 private static byte[] network_buffer; //
112 private static bool detectable_key_auto_repeat;
114 // Focus tracking
115 private static IntPtr ActiveWindow; // Handle of the active window
116 private static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any)
118 // Modality support
119 private static Stack ModalWindows; // Stack of our modal windows
121 // Systray
122 private static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window
124 // Cursors
125 private static IntPtr LastCursorWindow; // The last window we set the cursor on
126 private static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
127 private static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
129 // Caret
130 private static CaretStruct Caret; //
132 // Our atoms
133 private static IntPtr WM_PROTOCOLS;
134 private static IntPtr WM_DELETE_WINDOW;
135 private static IntPtr WM_TAKE_FOCUS;
136 //private static IntPtr _NET_SUPPORTED;
137 //private static IntPtr _NET_CLIENT_LIST;
138 //private static IntPtr _NET_NUMBER_OF_DESKTOPS;
139 //private static IntPtr _NET_DESKTOP_GEOMETRY;
140 //private static IntPtr _NET_DESKTOP_VIEWPORT;
141 private static IntPtr _NET_CURRENT_DESKTOP;
142 //private static IntPtr _NET_DESKTOP_NAMES;
143 private static IntPtr _NET_ACTIVE_WINDOW;
144 private static IntPtr _NET_WORKAREA;
145 //private static IntPtr _NET_SUPPORTING_WM_CHECK;
146 //private static IntPtr _NET_VIRTUAL_ROOTS;
147 //private static IntPtr _NET_DESKTOP_LAYOUT;
148 //private static IntPtr _NET_SHOWING_DESKTOP;
149 //private static IntPtr _NET_CLOSE_WINDOW;
150 //private static IntPtr _NET_MOVERESIZE_WINDOW;
151 //private static IntPtr _NET_WM_MOVERESIZE;
152 //private static IntPtr _NET_RESTACK_WINDOW;
153 //private static IntPtr _NET_REQUEST_FRAME_EXTENTS;
154 private static IntPtr _NET_WM_NAME;
155 //private static IntPtr _NET_WM_VISIBLE_NAME;
156 //private static IntPtr _NET_WM_ICON_NAME;
157 //private static IntPtr _NET_WM_VISIBLE_ICON_NAME;
158 //private static IntPtr _NET_WM_DESKTOP;
159 private static IntPtr _NET_WM_WINDOW_TYPE;
160 private static IntPtr _NET_WM_STATE;
161 //private static IntPtr _NET_WM_ALLOWED_ACTIONS;
162 //private static IntPtr _NET_WM_STRUT;
163 //private static IntPtr _NET_WM_STRUT_PARTIAL;
164 //private static IntPtr _NET_WM_ICON_GEOMETRY;
165 private static IntPtr _NET_WM_ICON;
166 //private static IntPtr _NET_WM_PID;
167 //private static IntPtr _NET_WM_HANDLED_ICONS;
168 private static IntPtr _NET_WM_USER_TIME;
169 private static IntPtr _NET_FRAME_EXTENTS;
170 //private static IntPtr _NET_WM_PING;
171 //private static IntPtr _NET_WM_SYNC_REQUEST;
172 private static IntPtr _NET_SYSTEM_TRAY_S;
173 //private static IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
174 private static IntPtr _NET_SYSTEM_TRAY_OPCODE;
175 private static IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
176 private static IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
177 private static IntPtr _XEMBED;
178 private static IntPtr _XEMBED_INFO;
179 private static IntPtr _MOTIF_WM_HINTS;
180 private static IntPtr _NET_WM_STATE_SKIP_TASKBAR;
181 //private static IntPtr _NET_WM_STATE_ABOVE;
182 //private static IntPtr _NET_WM_STATE_MODAL;
183 private static IntPtr _NET_WM_STATE_HIDDEN;
184 private static IntPtr _NET_WM_CONTEXT_HELP;
185 private static IntPtr _NET_WM_WINDOW_OPACITY;
186 //private static IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
187 //private static IntPtr _NET_WM_WINDOW_TYPE_DOCK;
188 //private static IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
189 //private static IntPtr _NET_WM_WINDOW_TYPE_MENU;
190 private static IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
191 //private static IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
192 //private static IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
193 private static IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
194 private static IntPtr CLIPBOARD;
195 private static IntPtr PRIMARY;
196 //private static IntPtr DIB;
197 private static IntPtr OEMTEXT;
198 private static IntPtr UNICODETEXT;
199 private static IntPtr TARGETS;
201 // mouse hover message generation
202 private static HoverStruct HoverState; //
204 // double click message generation
205 private static ClickStruct ClickPending; //
207 // Support for mouse grab
208 private static GrabStruct Grab; //
210 // State
211 Point mouse_position; // Last position of mouse, in screen coords
212 internal static MouseButtons MouseState; // Last state of mouse buttons
214 // 'Constants'
215 private static int DoubleClickInterval; // msec; max interval between clicks to count as double click
217 const EventMask SelectInputMask = (EventMask.ButtonPressMask |
218 EventMask.ButtonReleaseMask |
219 EventMask.KeyPressMask |
220 EventMask.KeyReleaseMask |
221 EventMask.EnterWindowMask |
222 EventMask.LeaveWindowMask |
223 EventMask.ExposureMask |
224 EventMask.FocusChangeMask |
225 EventMask.PointerMotionMask |
226 EventMask.SubstructureNotifyMask);
228 static readonly object lockobj = new object ();
230 #endregion // Local Variables
231 #region Constructors
232 private XplatUIX11() {
233 // Handle singleton stuff first
234 RefCount = 0;
236 // Now regular initialization
237 XlibLock = new object ();
238 MessageQueues = Hashtable.Synchronized (new Hashtable(7));
239 XInitThreads();
241 ErrorExceptions = false;
243 // X11 Initialization
244 SetDisplay(XOpenDisplay(IntPtr.Zero));
245 X11DesktopColors.Initialize();
248 // Disable keyboard autorepeat
249 try {
250 XkbSetDetectableAutoRepeat (DisplayHandle, true, IntPtr.Zero);
251 detectable_key_auto_repeat = true;
252 } catch {
253 Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually.");
254 detectable_key_auto_repeat = false;
257 // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does)
258 ErrorHandler = new XErrorHandler(HandleError);
259 XSetErrorHandler(ErrorHandler);
262 ~XplatUIX11() {
263 // Remove our display handle from S.D
264 Graphics.FromHdcInternal (IntPtr.Zero);
267 #endregion // Constructors
269 #region Singleton Specific Code
270 public static XplatUIX11 GetInstance() {
271 lock (lockobj) {
272 if (Instance == null) {
273 Instance=new XplatUIX11();
275 RefCount++;
277 return Instance;
280 public int Reference {
281 get {
282 return RefCount;
285 #endregion
287 #region Internal Properties
288 internal static IntPtr Display {
289 get {
290 return DisplayHandle;
293 set {
294 XplatUIX11.GetInstance().SetDisplay(value);
298 internal static int Screen {
299 get {
300 return ScreenNo;
303 set {
304 ScreenNo = value;
308 internal static IntPtr RootWindowHandle {
309 get {
310 return RootWindow;
313 set {
314 RootWindow = value;
318 internal static IntPtr Visual {
319 get {
320 return CustomVisual;
323 set {
324 CustomVisual = value;
328 internal static IntPtr ColorMap {
329 get {
330 return CustomColormap;
333 set {
334 CustomColormap = value;
337 #endregion
339 #region XExceptionClass
340 internal class XException : ApplicationException {
341 IntPtr Display;
342 IntPtr ResourceID;
343 IntPtr Serial;
344 XRequest RequestCode;
345 byte ErrorCode;
346 byte MinorCode;
348 public XException(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
349 this.Display = Display;
350 this.ResourceID = ResourceID;
351 this.Serial = Serial;
352 this.RequestCode = RequestCode;
353 this.ErrorCode = ErrorCode;
354 this.MinorCode = MinorCode;
357 public override string Message {
358 get {
359 return GetMessage(Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode);
363 public static string GetMessage(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) {
364 StringBuilder sb;
365 string x_error_text;
366 string error;
367 string hwnd_text;
368 string control_text;
369 Hwnd hwnd;
370 Control c;
372 sb = new StringBuilder(160);
373 XGetErrorText(Display, ErrorCode, sb, sb.Capacity);
374 x_error_text = sb.ToString();
375 hwnd = Hwnd.ObjectFromHandle(ResourceID);
376 if (hwnd != null) {
377 hwnd_text = hwnd.ToString();
378 c = Control.FromHandle(hwnd.Handle);
379 if (c != null) {
380 control_text = c.ToString();
381 } else {
382 control_text = String.Format("<handle {0:X} non-existant>", hwnd.Handle);
384 } else {
385 hwnd_text = "<null>";
386 control_text = "<null>";
390 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, RequestCode, ResourceID.ToInt32(), Serial, hwnd_text, control_text);
391 return error;
394 #endregion // XExceptionClass
396 #region Internal Methods
397 internal void SetDisplay(IntPtr display_handle) {
398 if (display_handle != IntPtr.Zero) {
399 Hwnd hwnd;
401 if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) {
402 hwnd = Hwnd.ObjectFromHandle(FosterParent);
403 XDestroyWindow(DisplayHandle, FosterParent);
404 hwnd.Dispose();
407 if (DisplayHandle != IntPtr.Zero) {
408 XCloseDisplay(DisplayHandle);
411 DisplayHandle=display_handle;
413 // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has
414 // been hacked to do this for us.
415 Graphics.FromHdcInternal (DisplayHandle);
417 // Debugging support
418 if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
419 XSynchronize(DisplayHandle, true);
422 if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
423 ErrorExceptions = true;
426 // Generic X11 setup
427 ScreenNo = XDefaultScreen(DisplayHandle);
428 RootWindow = XRootWindow(DisplayHandle, ScreenNo);
429 DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
431 // Create the foster parent
432 FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero);
433 if (FosterParent==IntPtr.Zero) {
434 Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
437 hwnd = new Hwnd();
438 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
439 hwnd.WholeWindow = FosterParent;
440 hwnd.ClientWindow = FosterParent;
442 // Create a HWND for RootWIndow as well, so our queue doesn't eat the events
443 hwnd = new Hwnd();
444 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
445 hwnd.whole_window = RootWindow;
446 hwnd.ClientWindow = RootWindow;
448 // For sleeping on the X11 socket
449 listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
450 IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0);
451 listen.Bind(ep);
452 listen.Listen(1);
454 // To wake up when a timer is ready
455 network_buffer = new byte[10];
457 wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
458 wake.Connect(listen.LocalEndPoint);
459 wake_receive = listen.Accept();
461 #if __MonoCS__
462 pollfds = new Pollfd [2];
463 pollfds [0] = new Pollfd ();
464 pollfds [0].fd = XConnectionNumber (DisplayHandle);
465 pollfds [0].events = PollEvents.POLLIN;
467 pollfds [1] = new Pollfd ();
468 pollfds [1].fd = wake_receive.Handle.ToInt32 ();
469 pollfds [1].events = PollEvents.POLLIN;
470 #endif
472 Keyboard = new X11Keyboard(DisplayHandle, FosterParent);
473 Dnd = new X11Dnd (DisplayHandle, Keyboard);
475 DoubleClickInterval = 500;
477 HoverState.Interval = 500;
478 HoverState.Timer = new Timer();
479 HoverState.Timer.Enabled = false;
480 HoverState.Timer.Interval = HoverState.Interval;
481 HoverState.Timer.Tick += new EventHandler(MouseHover);
482 HoverState.Size = new Size(4, 4);
483 HoverState.X = -1;
484 HoverState.Y = -1;
486 ActiveWindow = IntPtr.Zero;
487 FocusWindow = IntPtr.Zero;
488 ModalWindows = new Stack(3);
490 MouseState = MouseButtons.None;
491 mouse_position = new Point(0, 0);
493 Caret.Timer = new Timer();
494 Caret.Timer.Interval = 500; // FIXME - where should this number come from?
495 Caret.Timer.Tick += new EventHandler(CaretCallback);
497 SetupAtoms();
499 // Grab atom changes off the root window to catch certain WM events
500 XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int)EventMask.PropertyChangeMask));
502 // Handle any upcoming errors
503 ErrorHandler = new XErrorHandler(HandleError);
504 XSetErrorHandler(ErrorHandler);
505 } else {
506 throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check you DISPLAY environment variable)");
509 #endregion // Internal Methods
511 #region Private Methods
512 private int unixtime() {
513 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
515 return (int) t.TotalSeconds;
518 private static void SetupAtoms() {
519 // make sure this array stays in sync with the statements below
520 string [] atom_names = new string[] {
521 "WM_PROTOCOLS",
522 "WM_DELETE_WINDOW",
523 "WM_TAKE_FOCUS",
524 //"_NET_SUPPORTED",
525 //"_NET_CLIENT_LIST",
526 //"_NET_NUMBER_OF_DESKTOPS",
527 //"_NET_DESKTOP_GEOMETRY",
528 //"_NET_DESKTOP_VIEWPORT",
529 "_NET_CURRENT_DESKTOP",
530 //"_NET_DESKTOP_NAMES",
531 "_NET_ACTIVE_WINDOW",
532 "_NET_WORKAREA",
533 //"_NET_SUPPORTING_WM_CHECK",
534 //"_NET_VIRTUAL_ROOTS",
535 //"_NET_DESKTOP_LAYOUT",
536 //"_NET_SHOWING_DESKTOP",
537 //"_NET_CLOSE_WINDOW",
538 //"_NET_MOVERESIZE_WINDOW",
539 //"_NET_WM_MOVERESIZE",
540 //"_NET_RESTACK_WINDOW",
541 //"_NET_REQUEST_FRAME_EXTENTS",
542 "_NET_WM_NAME",
543 //"_NET_WM_VISIBLE_NAME",
544 //"_NET_WM_ICON_NAME",
545 //"_NET_WM_VISIBLE_ICON_NAME",
546 //"_NET_WM_DESKTOP",
547 "_NET_WM_WINDOW_TYPE",
548 "_NET_WM_STATE",
549 //"_NET_WM_ALLOWED_ACTIONS",
550 //"_NET_WM_STRUT",
551 //"_NET_WM_STRUT_PARTIAL",
552 //"_NET_WM_ICON_GEOMETRY",
553 "_NET_WM_ICON",
554 //"_NET_WM_PID",
555 //"_NET_WM_HANDLED_ICONS",
556 "_NET_WM_USER_TIME",
557 "_NET_FRAME_EXTENTS",
558 //"_NET_WM_PING",
559 //"_NET_WM_SYNC_REQUEST",
560 "_NET_SYSTEM_TRAY_OPCODE",
561 //"_NET_SYSTEM_TRAY_ORIENTATION",
562 "_NET_WM_STATE_MAXIMIZED_HORZ",
563 "_NET_WM_STATE_MAXIMIZED_VERT",
564 "_NET_WM_STATE_HIDDEN",
565 "_XEMBED",
566 "_XEMBED_INFO",
567 "_MOTIF_WM_HINTS",
568 "_NET_WM_STATE_SKIP_TASKBAR",
569 //"_NET_WM_STATE_ABOVE",
570 //"_NET_WM_STATE_MODAL",
571 "_NET_WM_CONTEXT_HELP",
572 "_NET_WM_WINDOW_OPACITY",
573 //"_NET_WM_WINDOW_TYPE_DESKTOP",
574 //"_NET_WM_WINDOW_TYPE_DOCK",
575 //"_NET_WM_WINDOW_TYPE_TOOLBAR",
576 //"_NET_WM_WINDOW_TYPE_MENU",
577 "_NET_WM_WINDOW_TYPE_UTILITY",
578 //"_NET_WM_WINDOW_TYPE_DIALOG",
579 //"_NET_WM_WINDOW_TYPE_SPLASH",
580 "_NET_WM_WINDOW_TYPE_NORMAL",
581 "CLIPBOARD",
582 "PRIMARY",
583 "COMPOUND_TEXT",
584 "UTF8_STRING",
585 "TARGETS",
586 "_SWF_AsyncAtom",
587 "_SWF_PostMessageAtom",
588 "_SWF_HoverAtom" };
590 IntPtr[] atoms = new IntPtr [atom_names.Length];;
592 XInternAtoms (DisplayHandle, atom_names, atom_names.Length, false, atoms);
594 int off = 0;
595 WM_PROTOCOLS = atoms [off++];
596 WM_DELETE_WINDOW = atoms [off++];
597 WM_TAKE_FOCUS = atoms [off++];
598 //_NET_SUPPORTED = atoms [off++];
599 //_NET_CLIENT_LIST = atoms [off++];
600 //_NET_NUMBER_OF_DESKTOPS = atoms [off++];
601 //_NET_DESKTOP_GEOMETRY = atoms [off++];
602 //_NET_DESKTOP_VIEWPORT = atoms [off++];
603 _NET_CURRENT_DESKTOP = atoms [off++];
604 //_NET_DESKTOP_NAMES = atoms [off++];
605 _NET_ACTIVE_WINDOW = atoms [off++];
606 _NET_WORKAREA = atoms [off++];
607 //_NET_SUPPORTING_WM_CHECK = atoms [off++];
608 //_NET_VIRTUAL_ROOTS = atoms [off++];
609 //_NET_DESKTOP_LAYOUT = atoms [off++];
610 //_NET_SHOWING_DESKTOP = atoms [off++];
611 //_NET_CLOSE_WINDOW = atoms [off++];
612 //_NET_MOVERESIZE_WINDOW = atoms [off++];
613 //_NET_WM_MOVERESIZE = atoms [off++];
614 //_NET_RESTACK_WINDOW = atoms [off++];
615 //_NET_REQUEST_FRAME_EXTENTS = atoms [off++];
616 _NET_WM_NAME = atoms [off++];
617 //_NET_WM_VISIBLE_NAME = atoms [off++];
618 //_NET_WM_ICON_NAME = atoms [off++];
619 //_NET_WM_VISIBLE_ICON_NAME = atoms [off++];
620 //_NET_WM_DESKTOP = atoms [off++];
621 _NET_WM_WINDOW_TYPE = atoms [off++];
622 _NET_WM_STATE = atoms [off++];
623 //_NET_WM_ALLOWED_ACTIONS = atoms [off++];
624 //_NET_WM_STRUT = atoms [off++];
625 //_NET_WM_STRUT_PARTIAL = atoms [off++];
626 //_NET_WM_ICON_GEOMETRY = atoms [off++];
627 _NET_WM_ICON = atoms [off++];
628 //_NET_WM_PID = atoms [off++];
629 //_NET_WM_HANDLED_ICONS = atoms [off++];
630 _NET_WM_USER_TIME = atoms [off++];
631 _NET_FRAME_EXTENTS = atoms [off++];
632 //_NET_WM_PING = atoms [off++];
633 //_NET_WM_SYNC_REQUEST = atoms [off++];
634 _NET_SYSTEM_TRAY_OPCODE = atoms [off++];
635 //_NET_SYSTEM_TRAY_ORIENTATION = atoms [off++];
636 _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++];
637 _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++];
638 _NET_WM_STATE_HIDDEN = atoms [off++];
639 _XEMBED = atoms [off++];
640 _XEMBED_INFO = atoms [off++];
641 _MOTIF_WM_HINTS = atoms [off++];
642 _NET_WM_STATE_SKIP_TASKBAR = atoms [off++];
643 //_NET_WM_STATE_ABOVE = atoms [off++];
644 //_NET_WM_STATE_MODAL = atoms [off++];
645 _NET_WM_CONTEXT_HELP = atoms [off++];
646 _NET_WM_WINDOW_OPACITY = atoms [off++];
647 //_NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++];
648 //_NET_WM_WINDOW_TYPE_DOCK = atoms [off++];
649 //_NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++];
650 //_NET_WM_WINDOW_TYPE_MENU = atoms [off++];
651 _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++];
652 //_NET_WM_WINDOW_TYPE_DIALOG = atoms [off++];
653 //_NET_WM_WINDOW_TYPE_SPLASH = atoms [off++];
654 _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++];
655 CLIPBOARD = atoms [off++];
656 PRIMARY = atoms [off++];
657 OEMTEXT = atoms [off++];
658 UNICODETEXT = atoms [off++];
659 TARGETS = atoms [off++];
660 AsyncAtom = atoms [off++];
661 PostAtom = atoms [off++];
662 HoverState.Atom = atoms [off++];
664 //DIB = (IntPtr)Atom.XA_PIXMAP;
665 _NET_SYSTEM_TRAY_S = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString(), false);
668 private void GetSystrayManagerWindow() {
669 XGrabServer(DisplayHandle);
670 SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, _NET_SYSTEM_TRAY_S);
671 XUngrabServer(DisplayHandle);
672 XFlush(DisplayHandle);
675 private void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
676 XEvent xev;
678 xev = new XEvent();
679 xev.ClientMessageEvent.type = XEventName.ClientMessage;
680 xev.ClientMessageEvent.send_event = true;
681 xev.ClientMessageEvent.window = window;
682 xev.ClientMessageEvent.message_type = message_type;
683 xev.ClientMessageEvent.format = 32;
684 xev.ClientMessageEvent.ptr1 = l0;
685 xev.ClientMessageEvent.ptr2 = l1;
686 xev.ClientMessageEvent.ptr3 = l2;
687 XSendEvent(DisplayHandle, RootWindow, false, new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
690 private void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) {
691 XEvent xev;
693 xev = new XEvent();
694 xev.ClientMessageEvent.type = XEventName.ClientMessage;
695 xev.ClientMessageEvent.send_event = true;
696 xev.ClientMessageEvent.window = window;
697 xev.ClientMessageEvent.message_type = message_type;
698 xev.ClientMessageEvent.format = 32;
699 xev.ClientMessageEvent.ptr1 = l0;
700 xev.ClientMessageEvent.ptr2 = l1;
701 xev.ClientMessageEvent.ptr3 = l2;
702 XSendEvent(DisplayHandle, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev);
705 // For WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN
706 // WM_CREATE and WM_DESTROY causes
707 void SendParentNotify(IntPtr child, Msg cause, int x, int y)
709 Hwnd hwnd;
711 if (child == IntPtr.Zero) {
712 return;
715 hwnd = Hwnd.GetObjectFromWindow (child);
717 if (hwnd == null) {
718 return;
721 if (hwnd.Handle == IntPtr.Zero) {
722 return;
725 if (ExStyleSet ((int) hwnd.initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY)) {
726 return;
729 if (hwnd.Parent == null) {
730 return;
733 if (hwnd.Parent.Handle == IntPtr.Zero) {
734 return;
737 if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) {
738 SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Control.MakeParam((int)cause, 0), child);
739 } else {
740 SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Control.MakeParam((int)cause, 0), Control.MakeParam(x, y));
743 SendParentNotify (hwnd.Parent.Handle, cause, x, y);
746 bool StyleSet (int s, WindowStyles ws)
748 return (s & (int)ws) == (int)ws;
751 bool ExStyleSet (int ex, WindowExStyles exws)
753 return (ex & (int)exws) == (int)exws;
756 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) {
758 caption_height = 0;
759 tool_caption_height = 19;
760 border_static = false;
762 if (StyleSet (Style, WindowStyles.WS_CHILD)) {
763 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) {
764 border_style = FormBorderStyle.Fixed3D;
765 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
766 border_style = FormBorderStyle.Fixed3D;
767 border_static = true;
768 } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) {
769 border_style = FormBorderStyle.None;
770 } else {
771 border_style = FormBorderStyle.FixedSingle;
773 title_style = TitleStyle.None;
775 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
776 caption_height = 19;
777 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
778 title_style = TitleStyle.Tool;
779 } else {
780 title_style = TitleStyle.Normal;
784 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) {
785 caption_height = 19;
787 if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) ||
788 ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
789 border_style = (FormBorderStyle) 0xFFFF;
790 } else {
791 border_style = FormBorderStyle.None;
795 } else {
796 title_style = TitleStyle.None;
797 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
798 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
799 title_style = TitleStyle.Tool;
800 } else {
801 title_style = TitleStyle.Normal;
805 border_style = FormBorderStyle.None;
807 if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) {
808 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
809 border_style = FormBorderStyle.SizableToolWindow;
810 } else {
811 border_style = FormBorderStyle.Sizable;
813 } else {
814 if (StyleSet (Style, WindowStyles.WS_CAPTION)) {
815 if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) {
816 border_style = FormBorderStyle.Fixed3D;
817 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) {
818 border_style = FormBorderStyle.Fixed3D;
819 border_static = true;
820 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
821 border_style = FormBorderStyle.FixedDialog;
822 } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
823 border_style = FormBorderStyle.FixedToolWindow;
824 } else if (StyleSet (Style, WindowStyles.WS_BORDER)) {
825 border_style = FormBorderStyle.FixedSingle;
827 } else {
828 if (StyleSet (Style, WindowStyles.WS_BORDER)) {
829 border_style = FormBorderStyle.FixedSingle;
836 private void SetHwndStyles(Hwnd hwnd, CreateParams cp) {
837 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);
840 private void SetWMStyles(Hwnd hwnd, CreateParams cp) {
841 MotifWmHints mwmHints;
842 MotifFunctions functions;
843 MotifDecorations decorations;
844 int[] atoms;
845 int atom_count;
846 Rectangle client_rect;
848 // Windows we manage ourselves don't need WM window styles.
849 if (cp.HasWindowManager && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
850 return;
853 atoms = new int[8];
854 mwmHints = new MotifWmHints();
855 functions = 0;
856 decorations = 0;
858 mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
859 mwmHints.functions = (IntPtr)0;
860 mwmHints.decorations = (IntPtr)0;
862 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)
863 || !StyleSet (cp.Style, WindowStyles.WS_CAPTION | WindowStyles.WS_BORDER | WindowStyles.WS_DLGFRAME)) {
864 /* tool windows get no window manager
865 decorations, and neither do windows
866 which lack CAPTION/BORDER/DLGFRAME
867 styles.
870 /* just because the window doesn't get any decorations doesn't
871 mean we should disable the functions. for instance, without
872 MotifFunctions.Maximize, changing the windowstate to Maximized
873 is ignored by metacity. */
874 functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
876 else {
877 if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
878 functions |= MotifFunctions.Move;
879 decorations |= MotifDecorations.Title | MotifDecorations.Menu;
882 if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) {
883 functions |= MotifFunctions.Move | MotifFunctions.Resize;
884 decorations |= MotifDecorations.Border | MotifDecorations.ResizeH;
887 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) {
888 functions |= MotifFunctions.Minimize;
889 decorations |= MotifDecorations.Minimize;
892 if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) {
893 functions |= MotifFunctions.Maximize;
894 decorations |= MotifDecorations.Maximize;
897 if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) {
898 functions |= MotifFunctions.Resize;
899 decorations |= MotifDecorations.ResizeH;
902 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) {
903 decorations |= MotifDecorations.Border;
906 if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) {
907 decorations |= MotifDecorations.Border;
910 if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) {
911 decorations |= MotifDecorations.Border;
914 if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) {
915 functions |= MotifFunctions.Close;
917 else {
918 functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close);
919 decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize);
920 if (cp.Caption == "") {
921 functions &= ~MotifFunctions.Move;
922 decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH);
927 if ((functions & MotifFunctions.Resize) == 0) {
928 hwnd.fixed_size = true;
929 XplatUI.SetWindowMinMax(hwnd.Handle, new Rectangle(cp.X, cp.Y, cp.Width, cp.Height), new Size(cp.Width, cp.Height), new Size(cp.Width, cp.Height));
930 } else {
931 hwnd.fixed_size = false;
934 mwmHints.functions = (IntPtr)functions;
935 mwmHints.decorations = (IntPtr)decorations;
937 FormWindowState current_state = GetWindowState (hwnd.Handle);
938 if (current_state == (FormWindowState)(-1))
939 current_state = FormWindowState.Normal;
941 client_rect = hwnd.ClientRect;
942 lock (XlibLock) {
943 atom_count = 0;
945 // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
946 // and get those windows in front of their parents
947 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
948 atoms [0] = _NET_WM_WINDOW_TYPE_UTILITY.ToInt32 ();
949 XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE,
950 (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
952 Form f = Control.FromHandle(hwnd.Handle) as Form;
953 if (f != null && !hwnd.reparented) {
954 if (f.Owner != null && f.Owner.Handle != IntPtr.Zero) {
955 Hwnd owner_hwnd = Hwnd.ObjectFromHandle(f.Owner.Handle);
956 if (owner_hwnd != null)
957 XSetTransientForHint(DisplayHandle, hwnd.whole_window,
958 owner_hwnd.whole_window);
963 XChangeProperty(DisplayHandle, hwnd.whole_window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref mwmHints, 5);
964 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
965 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
966 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
968 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd.parent.whole_window);
969 } else if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_APPWINDOW)) {
970 /* this line keeps the window from showing up in gnome's taskbar */
971 atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
973 if ((client_rect.Width < 1) || (client_rect.Height < 1)) {
974 XMoveResizeWindow(DisplayHandle, hwnd.client_window, -5, -5, 1, 1);
975 } else {
976 XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
979 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
980 atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
982 /* we need to add these atoms in the
983 * event we're maximized, since we're
984 * replacing the existing
985 * _NET_WM_STATE here. If we don't
986 * add them, future calls to
987 * GetWindowState will return Normal
988 * for a window which is maximized. */
989 if (current_state == FormWindowState.Maximized) {
990 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_HORZ.ToInt32();
991 atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_VERT.ToInt32();
993 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
995 atom_count = 0;
996 IntPtr[] atom_ptrs = new IntPtr[2];
997 atom_ptrs[atom_count++] = WM_DELETE_WINDOW;
998 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP)) {
999 atom_ptrs[atom_count++] = _NET_WM_CONTEXT_HELP;
1002 XSetWMProtocols(DisplayHandle, hwnd.whole_window, atom_ptrs, atom_count);
1006 private void SetIcon(Hwnd hwnd, Icon icon)
1008 if (icon == null) {
1009 // XXX
1011 // This really needs to do whatever it
1012 // takes to remove the window manager
1013 // menu, not just delete the ICON
1014 // property. This will cause metacity
1015 // to use the "no icon set" icon, and
1016 // we'll still have an icon.
1017 XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_ICON);
1019 else {
1020 Bitmap bitmap;
1021 int size;
1022 IntPtr[] data;
1023 int index;
1025 bitmap = icon.ToBitmap();
1026 index = 0;
1027 size = bitmap.Width * bitmap.Height + 2;
1028 data = new IntPtr[size];
1030 data[index++] = (IntPtr)bitmap.Width;
1031 data[index++] = (IntPtr)bitmap.Height;
1033 for (int y = 0; y < bitmap.Height; y++) {
1034 for (int x = 0; x < bitmap.Width; x++) {
1035 data[index++] = (IntPtr)bitmap.GetPixel (x, y).ToArgb ();
1039 XChangeProperty (DisplayHandle, hwnd.whole_window,
1040 _NET_WM_ICON, (IntPtr)Atom.XA_CARDINAL, 32,
1041 PropertyMode.Replace, data, size);
1045 private void WakeupMain () {
1046 wake.Send (new byte [] { 0xFF });
1049 private XEventQueue ThreadQueue(Thread thread) {
1050 XEventQueue queue;
1052 queue = (XEventQueue)MessageQueues[thread];
1053 if (queue == null) {
1054 queue = new XEventQueue(thread);
1055 MessageQueues[thread] = queue;
1058 return queue;
1061 private void TranslatePropertyToClipboard(IntPtr property) {
1062 IntPtr actual_atom;
1063 int actual_format;
1064 IntPtr nitems;
1065 IntPtr bytes_after;
1066 IntPtr prop = IntPtr.Zero;
1068 Clipboard.Item = null;
1070 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);
1072 if ((long)nitems > 0) {
1073 if (property == (IntPtr)Atom.XA_STRING) {
1074 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1075 } else if (property == (IntPtr)Atom.XA_BITMAP) {
1076 // FIXME - convert bitmap to image
1077 } else if (property == (IntPtr)Atom.XA_PIXMAP) {
1078 // FIXME - convert pixmap to image
1079 } else if (property == OEMTEXT) {
1080 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1081 } else if (property == UNICODETEXT) {
1082 Clipboard.Item = Marshal.PtrToStringAnsi(prop);
1085 XFree(prop);
1089 private void AddExpose (Hwnd hwnd, bool client, int x, int y, int width, int height) {
1090 // Don't waste time
1091 if ((hwnd == null) || (x > hwnd.Width) || (y > hwnd.Height) || ((x + width) < 0) || ((y + height) < 0)) {
1092 return;
1095 // Keep the invalid area as small as needed
1096 if ((x + width) > hwnd.width) {
1097 width = hwnd.width - x;
1100 if ((y + height) > hwnd.height) {
1101 height = hwnd.height - y;
1104 if (client) {
1105 hwnd.AddInvalidArea(x, y, width, height);
1106 if (!hwnd.expose_pending) {
1107 if (!hwnd.nc_expose_pending) {
1108 hwnd.Queue.Paint.Enqueue(hwnd);
1110 hwnd.expose_pending = true;
1112 } else {
1113 hwnd.AddNcInvalidArea (x, y, width, height);
1115 if (!hwnd.nc_expose_pending) {
1116 if (!hwnd.expose_pending) {
1117 hwnd.Queue.Paint.Enqueue(hwnd);
1119 hwnd.nc_expose_pending = true;
1124 private void FrameExtents(IntPtr window, out int left, out int top) {
1125 IntPtr actual_atom;
1126 int actual_format;
1127 IntPtr nitems;
1128 IntPtr bytes_after;
1129 IntPtr prop = IntPtr.Zero;
1131 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);
1132 if (((long)nitems == 4) && (prop != IntPtr.Zero)) {
1133 left = Marshal.ReadIntPtr(prop, 0).ToInt32();
1134 //right = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
1135 top = Marshal.ReadIntPtr(prop, IntPtr.Size * 2).ToInt32();
1136 //bottom = Marshal.ReadIntPtr(prop, IntPtr.Size * 3).ToInt32();
1137 } else {
1138 left = 0;
1139 top = 0;
1142 if (prop != IntPtr.Zero) {
1143 XFree(prop);
1145 return;
1148 private void AddConfigureNotify (XEvent xevent) {
1149 Hwnd hwnd;
1151 hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window);
1153 // Don't waste time
1154 if (hwnd == null) {
1155 return;
1158 if ((xevent.ConfigureEvent.window == hwnd.whole_window) && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)) {
1159 if (!hwnd.reparented) {
1160 hwnd.x = xevent.ConfigureEvent.x;
1161 hwnd.y = xevent.ConfigureEvent.y;
1162 } else {
1163 // This sucks ass, part 1
1164 // Every WM does the ConfigureEvents of toplevel windows different, so there's
1165 // no standard way of getting our adjustment.
1166 // The code below is needed for KDE and FVWM, the 'whacky_wm' part is for metacity
1167 // Several other WMs do their decorations different yet again and we fail to deal
1168 // with that, since I couldn't find any frigging commonality between them.
1169 // The only sane WM seems to be KDE
1171 if (!xevent.ConfigureEvent.send_event) {
1172 IntPtr dummy_ptr;
1174 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, -xevent.ConfigureEvent.x, -xevent.ConfigureEvent.y, out hwnd.x, out hwnd.y, out dummy_ptr);
1175 } else {
1176 // This is a synthetic event, coordinates are in root space
1177 hwnd.x = xevent.ConfigureEvent.x;
1178 hwnd.y = xevent.ConfigureEvent.y;
1179 if (hwnd.whacky_wm) {
1180 int frame_left;
1181 int frame_top;
1183 FrameExtents(hwnd.whole_window, out frame_left, out frame_top);
1184 hwnd.x -= frame_left;
1185 hwnd.y -= frame_top;
1190 // XXX this sucks. this isn't thread safe
1191 hwnd.width = xevent.ConfigureEvent.width;
1192 hwnd.height = xevent.ConfigureEvent.height;
1193 hwnd.ClientRect = Rectangle.Empty;
1195 lock (hwnd.configure_lock) {
1196 if (!hwnd.configure_pending) {
1197 hwnd.Queue.EnqueueLocked (xevent);
1198 hwnd.configure_pending = true;
1202 // We drop configure events for Client windows
1205 private void ShowCaret() {
1206 if ((Caret.gc == IntPtr.Zero) || Caret.On) {
1207 return;
1209 Caret.On = true;
1211 lock (XlibLock) {
1212 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1216 private void HideCaret() {
1217 if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
1218 return;
1220 Caret.On = false;
1222 lock (XlibLock) {
1223 XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1227 private int NextTimeout (ArrayList timers, DateTime now) {
1228 int timeout = Int32.MaxValue;
1230 foreach (Timer timer in timers) {
1231 int next = (int) (timer.Expires - now).TotalMilliseconds;
1232 if (next < 0) {
1233 return 0; // Have a timer that has already expired
1236 if (next < timeout) {
1237 timeout = next;
1240 if (timeout < Timer.Minimum) {
1241 timeout = Timer.Minimum;
1244 if (timeout > 1000)
1245 timeout = 1000;
1246 return timeout;
1249 private void CheckTimers (ArrayList timers, DateTime now) {
1250 int count;
1252 count = timers.Count;
1254 if (count == 0)
1255 return;
1257 for (int i = 0; i < timers.Count; i++) {
1258 Timer timer;
1260 timer = (Timer) timers [i];
1262 if (timer.Enabled && timer.Expires <= now) {
1263 timer.Update (now);
1264 timer.FireTick ();
1269 private void WaitForHwndMessage (Hwnd hwnd, Msg message) {
1270 MSG msg = new MSG ();
1271 XEventQueue queue;
1273 queue = ThreadQueue(Thread.CurrentThread);
1275 queue.DispatchIdle = false;
1277 bool done = false;
1278 do {
1279 if (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
1280 if ((Msg)msg.message == Msg.WM_QUIT) {
1281 PostQuitMessage (0);
1282 done = true;
1284 else {
1285 if ((msg.hwnd == hwnd.Handle) &&
1286 ((Msg)msg.message == message || (Msg)msg.message == Msg.WM_DESTROY))
1287 done = true;
1288 TranslateMessage (ref msg);
1289 DispatchMessage (ref msg);
1292 } while (!done);
1294 queue.DispatchIdle = true;
1298 private void MapWindow(Hwnd hwnd, WindowType windows) {
1299 if (!hwnd.mapped) {
1300 bool need_to_wait = false;
1302 if ((windows & WindowType.Whole) != 0) {
1303 XMapWindow(DisplayHandle, hwnd.whole_window);
1305 if ((windows & WindowType.Client) != 0) {
1306 XMapWindow(DisplayHandle, hwnd.client_window);
1308 need_to_wait = true;
1311 hwnd.mapped = true;
1313 if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
1314 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1318 private void UnmapWindow(Hwnd hwnd, WindowType windows) {
1319 if (hwnd.mapped) {
1320 bool need_to_wait = false;
1322 if ((windows & WindowType.Client) != 0) {
1323 XUnmapWindow(DisplayHandle, hwnd.client_window);
1325 need_to_wait = true;
1327 if ((windows & WindowType.Whole) != 0) {
1328 XUnmapWindow(DisplayHandle, hwnd.whole_window);
1331 hwnd.mapped = false;
1333 if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
1334 WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
1338 private void UpdateMessageQueue (XEventQueue queue) {
1339 DateTime now;
1340 int pending;
1341 Hwnd hwnd;
1343 now = DateTime.UtcNow;
1345 lock (XlibLock) {
1346 pending = XPending (DisplayHandle);
1349 if (pending == 0) {
1350 if ((queue == null || queue.DispatchIdle) && Idle != null) {
1351 Idle (this, EventArgs.Empty);
1354 lock (XlibLock) {
1355 pending = XPending (DisplayHandle);
1359 if (pending == 0) {
1360 int timeout = 0;
1362 if (queue != null) {
1363 if (queue.Paint.Count > 0)
1364 return;
1366 timeout = NextTimeout (queue.timer_list, now);
1369 if (timeout > 0) {
1370 #if __MonoCS__
1371 int length = pollfds.Length - 1;
1372 lock (wake_waiting_lock) {
1373 if (wake_waiting == false) {
1374 length ++;
1375 wake_waiting = true;
1379 Syscall.poll (pollfds, (uint)length, timeout);
1380 // Clean out buffer, so we're not busy-looping on the same data
1381 if (length == pollfds.Length) {
1382 if (pollfds[1].revents != 0)
1383 wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None);
1384 lock (wake_waiting_lock) {
1385 wake_waiting = false;
1388 #endif
1389 lock (XlibLock) {
1390 pending = XPending (DisplayHandle);
1395 if (queue != null)
1396 CheckTimers (queue.timer_list, now);
1398 while (true) {
1399 XEvent xevent = new XEvent ();
1401 lock (XlibLock) {
1402 if (XPending (DisplayHandle) == 0)
1403 break;
1405 XNextEvent (DisplayHandle, ref xevent);
1407 if (xevent.AnyEvent.type == XEventName.KeyPress) {
1408 if (XFilterEvent(ref xevent, FosterParent)) {
1409 continue;
1414 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
1415 if (hwnd == null)
1416 continue;
1418 switch (xevent.type) {
1419 case XEventName.Expose:
1420 AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
1421 break;
1423 case XEventName.SelectionClear: {
1424 // Should we do something?
1425 break;
1428 case XEventName.SelectionRequest: {
1429 if (Dnd.HandleSelectionRequestEvent (ref xevent))
1430 break;
1431 XEvent sel_event;
1433 sel_event = new XEvent();
1434 sel_event.SelectionEvent.type = XEventName.SelectionNotify;
1435 sel_event.SelectionEvent.send_event = true;
1436 sel_event.SelectionEvent.display = DisplayHandle;
1437 sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection;
1438 sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target;
1439 sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor;
1440 sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time;
1441 sel_event.SelectionEvent.property = IntPtr.Zero;
1443 // Seems that some apps support asking for supported types
1444 if (xevent.SelectionEvent.target == TARGETS) {
1445 int[] atoms;
1446 int atom_count;
1448 atoms = new int[5];
1449 atom_count = 0;
1451 if (Clipboard.Item is String) {
1452 atoms[atom_count++] = (int)Atom.XA_STRING;
1453 atoms[atom_count++] = (int)OEMTEXT;
1454 atoms[atom_count++] = (int)UNICODETEXT;
1455 } else if (Clipboard.Item is Image) {
1456 atoms[atom_count++] = (int)Atom.XA_PIXMAP;
1457 atoms[atom_count++] = (int)Atom.XA_BITMAP;
1458 } else {
1459 // FIXME - handle other types
1462 XChangeProperty(DisplayHandle, xevent.SelectionEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count);
1463 } else if (Clipboard.Item is string) {
1464 IntPtr buffer;
1465 int buflen;
1467 buflen = 0;
1469 if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) {
1470 Byte[] bytes;
1472 bytes = new ASCIIEncoding().GetBytes((string)Clipboard.Item);
1473 buffer = Marshal.AllocHGlobal(bytes.Length);
1474 buflen = bytes.Length;
1476 for (int i = 0; i < buflen; i++) {
1477 Marshal.WriteByte(buffer, i, bytes[i]);
1479 } else if (xevent.SelectionRequestEvent.target == OEMTEXT) {
1480 // FIXME - this should encode into ISO2022
1481 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1482 while (Marshal.ReadByte(buffer, buflen) != 0) {
1483 buflen++;
1485 } else if (xevent.SelectionRequestEvent.target == UNICODETEXT) {
1486 buffer = Marshal.StringToHGlobalAnsi((string)Clipboard.Item);
1487 while (Marshal.ReadByte(buffer, buflen) != 0) {
1488 buflen++;
1490 } else {
1491 buffer = IntPtr.Zero;
1494 if (buffer != IntPtr.Zero) {
1495 XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen);
1496 sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property;
1497 Marshal.FreeHGlobal(buffer);
1499 } else if (Clipboard.Item is Image) {
1500 if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1501 // FIXME - convert image and store as property
1502 } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) {
1503 // FIXME - convert image and store as property
1507 XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event);
1508 break;
1511 case XEventName.SelectionNotify: {
1512 if (Clipboard.Enumerating) {
1513 Clipboard.Enumerating = false;
1514 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1515 XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property);
1516 if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) {
1517 Clipboard.Formats.Add(xevent.SelectionEvent.property);
1518 #if DriverDebugExtra
1519 Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property);
1520 #endif
1523 } else if (Clipboard.Retrieving) {
1524 Clipboard.Retrieving = false;
1525 if (xevent.SelectionEvent.property != IntPtr.Zero) {
1526 TranslatePropertyToClipboard(xevent.SelectionEvent.property);
1527 } else {
1528 Clipboard.Item = null;
1530 } else {
1531 Dnd.HandleSelectionNotifyEvent (ref xevent);
1533 break;
1536 case XEventName.KeyRelease:
1537 if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) {
1538 XEvent nextevent = new XEvent ();
1540 XPeekEvent (DisplayHandle, ref nextevent);
1542 if (nextevent.type == XEventName.KeyPress &&
1543 nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
1544 nextevent.KeyEvent.time == xevent.KeyEvent.time) {
1545 continue;
1548 goto case XEventName.KeyPress;
1550 case XEventName.MotionNotify: {
1551 XEvent peek;
1553 /* we can't do motion compression across threads, so just punt if we don't match up */
1554 if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) {
1555 peek = hwnd.Queue.Peek();
1556 if (peek.AnyEvent.type == XEventName.MotionNotify) {
1557 continue;
1560 goto case XEventName.KeyPress;
1563 case XEventName.KeyPress:
1564 case XEventName.ButtonPress:
1565 case XEventName.ButtonRelease:
1566 case XEventName.EnterNotify:
1567 case XEventName.LeaveNotify:
1568 case XEventName.CreateNotify:
1569 case XEventName.DestroyNotify:
1570 case XEventName.FocusIn:
1571 case XEventName.FocusOut:
1572 case XEventName.ClientMessage:
1573 case XEventName.ReparentNotify:
1574 case XEventName.MapNotify:
1575 case XEventName.UnmapNotify:
1576 hwnd.Queue.EnqueueLocked (xevent);
1577 break;
1579 case XEventName.ConfigureNotify:
1580 AddConfigureNotify(xevent);
1581 break;
1583 case XEventName.PropertyNotify:
1584 if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) {
1585 IntPtr actual_atom;
1586 int actual_format;
1587 IntPtr nitems;
1588 IntPtr bytes_after;
1589 IntPtr prop = IntPtr.Zero;
1590 IntPtr prev_active;
1592 prev_active = ActiveWindow;
1593 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);
1594 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
1595 ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop));
1596 XFree(prop);
1598 if (prev_active != ActiveWindow) {
1599 if (prev_active != IntPtr.Zero) {
1600 PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1602 if (ActiveWindow != IntPtr.Zero) {
1603 PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
1606 if (ModalWindows.Count == 0) {
1607 break;
1608 } else {
1609 // Modality handling, if we are modal and the new active window is one
1610 // of ours but not the modal one, switch back to the modal window
1612 if (NativeWindow.FindWindow(ActiveWindow) != null) {
1613 if (ActiveWindow != (IntPtr)ModalWindows.Peek()) {
1614 Activate((IntPtr)ModalWindows.Peek());
1617 break;
1621 break;
1627 private IntPtr GetMousewParam(int Delta) {
1628 int result = 0;
1630 if ((MouseState & MouseButtons.Left) != 0) {
1631 result |= (int)MsgButtons.MK_LBUTTON;
1634 if ((MouseState & MouseButtons.Middle) != 0) {
1635 result |= (int)MsgButtons.MK_MBUTTON;
1638 if ((MouseState & MouseButtons.Right) != 0) {
1639 result |= (int)MsgButtons.MK_RBUTTON;
1642 Keys mods = ModifierKeys;
1643 if ((mods & Keys.Control) != 0) {
1644 result |= (int)MsgButtons.MK_CONTROL;
1647 if ((mods & Keys.Shift) != 0) {
1648 result |= (int)MsgButtons.MK_SHIFT;
1651 result |= Delta << 16;
1653 return (IntPtr)result;
1655 private IntPtr XGetParent(IntPtr handle) {
1656 IntPtr Root;
1657 IntPtr Parent;
1658 IntPtr Children;
1659 int ChildCount;
1661 lock (XlibLock) {
1662 XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount);
1665 if (Children!=IntPtr.Zero) {
1666 lock (XlibLock) {
1667 XFree(Children);
1670 return Parent;
1673 private int HandleError(IntPtr display, ref XErrorEvent error_event) {
1674 if (ErrorExceptions) {
1675 throw new XException(error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code);
1676 } else {
1677 Console.WriteLine("X11 Error encountered: {0}{1}\n", XException.GetMessage(error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code), Environment.StackTrace);
1679 return 0;
1682 private void AccumulateDestroyedHandles (Control c, ArrayList list)
1684 if (c != null) {
1685 Control[] controls = c.Controls.GetAllControls ();
1687 if (c.IsHandleCreated && !c.IsDisposed) {
1688 Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle);
1690 #if DriverDebug || DriverDebugDestroy
1691 Console.WriteLine (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
1692 Console.WriteLine (" + parent X window is {0:X}", XGetParent (hwnd.whole_window).ToInt32());
1693 #endif
1695 list.Add (hwnd);
1696 CleanupCachedWindows (hwnd);
1697 hwnd.zombie = true;
1700 for (int i = 0; i < controls.Length; i ++) {
1701 AccumulateDestroyedHandles (controls[i], list);
1707 void CleanupCachedWindows (Hwnd hwnd)
1709 if (ActiveWindow == hwnd.Handle) {
1710 SendMessage(hwnd.client_window, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
1711 ActiveWindow = IntPtr.Zero;
1714 if (FocusWindow == hwnd.Handle) {
1715 SendMessage(hwnd.client_window, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
1716 FocusWindow = IntPtr.Zero;
1719 if (Grab.Hwnd == hwnd.Handle) {
1720 Grab.Hwnd = IntPtr.Zero;
1721 Grab.Confined = false;
1724 DestroyCaret (hwnd.Handle);
1727 private void PerformNCCalc(Hwnd hwnd) {
1728 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
1729 IntPtr ptr;
1730 Rectangle rect;
1732 rect = hwnd.DefaultClientRect;
1734 ncp = new XplatUIWin32.NCCALCSIZE_PARAMS();
1735 ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp));
1737 ncp.rgrc1.left = rect.Left;
1738 ncp.rgrc1.top = rect.Top;
1739 ncp.rgrc1.right = rect.Right;
1740 ncp.rgrc1.bottom = rect.Bottom;
1742 Marshal.StructureToPtr(ncp, ptr, true);
1743 NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr);
1744 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
1745 Marshal.FreeHGlobal(ptr);
1747 // FIXME - debug this with Menus
1749 rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
1750 hwnd.ClientRect = rect;
1752 if (hwnd.visible) {
1753 if ((rect.Width < 1) || (rect.Height < 1)) {
1754 XMoveResizeWindow(DisplayHandle, hwnd.client_window, -5, -5, 1, 1);
1755 } else {
1756 XMoveResizeWindow(DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
1760 AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
1762 #endregion // Private Methods
1764 #region Callbacks
1765 private void MouseHover(object sender, EventArgs e) {
1766 XEvent xevent;
1767 Hwnd hwnd;
1769 HoverState.Timer.Enabled = false;
1771 if (HoverState.Window != IntPtr.Zero) {
1772 hwnd = Hwnd.GetObjectFromWindow(HoverState.Window);
1773 if (hwnd != null) {
1774 xevent = new XEvent ();
1776 xevent.type = XEventName.ClientMessage;
1777 xevent.ClientMessageEvent.display = DisplayHandle;
1778 xevent.ClientMessageEvent.window = HoverState.Window;
1779 xevent.ClientMessageEvent.message_type = HoverState.Atom;
1780 xevent.ClientMessageEvent.format = 32;
1781 xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
1783 hwnd.Queue.EnqueueLocked (xevent);
1785 WakeupMain ();
1790 private void CaretCallback(object sender, EventArgs e) {
1791 if (Caret.Paused) {
1792 return;
1794 Caret.On = !Caret.On;
1796 XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
1798 #endregion // Callbacks
1800 #region Public Properties
1802 internal override int Caption {
1803 get {
1804 return 19;
1808 internal override Size CursorSize {
1809 get {
1810 int x;
1811 int y;
1813 if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) {
1814 return new Size(x, y);
1815 } else {
1816 return new Size(16, 16);
1821 internal override bool DragFullWindows {
1822 get {
1823 return true;
1827 internal override Size DragSize {
1828 get {
1829 return new Size(4, 4);
1833 internal override Size FrameBorderSize {
1834 get {
1835 return new Size (4, 4);
1839 internal override Size IconSize {
1840 get {
1841 IntPtr list;
1842 XIconSize size;
1843 int count;
1845 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
1846 long current;
1847 int largest;
1849 current = (long)list;
1850 largest = 0;
1852 size = new XIconSize();
1854 for (int i = 0; i < count; i++) {
1855 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
1856 current += Marshal.SizeOf(size);
1858 // Look for our preferred size
1859 if (size.min_width == 32) {
1860 XFree(list);
1861 return new Size(32, 32);
1864 if (size.max_width == 32) {
1865 XFree(list);
1866 return new Size(32, 32);
1869 if (size.min_width < 32 && size.max_width > 32) {
1870 int x;
1872 // check if we can fit one
1873 x = size.min_width;
1874 while (x < size.max_width) {
1875 x += size.width_inc;
1876 if (x == 32) {
1877 XFree(list);
1878 return new Size(32, 32);
1883 if (largest < size.max_width) {
1884 largest = size.max_width;
1888 // We didn't find a match or we wouldn't be here
1889 return new Size(largest, largest);
1891 } else {
1892 return new Size(32, 32);
1897 internal override int KeyboardSpeed {
1898 get{
1900 // A lot harder: need to do:
1901 // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
1902 // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
1903 // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
1905 // And from that we can tell the repetition rate
1907 // Notice, the values must map to:
1908 // [0, 31] which maps to 2.5 to 30 repetitions per second.
1910 return 0;
1914 internal override int KeyboardDelay {
1915 get {
1917 // Return values must range from 0 to 4, 0 meaning 250ms,
1918 // and 4 meaning 1000 ms.
1920 return 1; // ie, 500 ms
1924 internal override Size MaxWindowTrackSize {
1925 get {
1926 return new Size (WorkingArea.Width, WorkingArea.Height);
1930 internal override Size MinimizedWindowSize {
1931 get {
1932 return new Size(1, 1);
1936 internal override Size MinimizedWindowSpacingSize {
1937 get {
1938 return new Size(1, 1);
1942 internal override Size MinimumWindowSize {
1943 get {
1944 return new Size(1, 1);
1948 internal override Size MinWindowTrackSize {
1949 get {
1950 return new Size(1, 1);
1954 internal override Keys ModifierKeys {
1955 get {
1956 return Keyboard.ModifierKeys;
1960 internal override Size SmallIconSize {
1961 get {
1962 IntPtr list;
1963 XIconSize size;
1964 int count;
1966 if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) {
1967 long current;
1968 int smallest;
1970 current = (long)list;
1971 smallest = 0;
1973 size = new XIconSize();
1975 for (int i = 0; i < count; i++) {
1976 size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
1977 current += Marshal.SizeOf(size);
1979 // Look for our preferred size
1980 if (size.min_width == 16) {
1981 XFree(list);
1982 return new Size(16, 16);
1985 if (size.max_width == 16) {
1986 XFree(list);
1987 return new Size(16, 16);
1990 if (size.min_width < 16 && size.max_width > 16) {
1991 int x;
1993 // check if we can fit one
1994 x = size.min_width;
1995 while (x < size.max_width) {
1996 x += size.width_inc;
1997 if (x == 16) {
1998 XFree(list);
1999 return new Size(16, 16);
2004 if (smallest == 0 || smallest > size.min_width) {
2005 smallest = size.min_width;
2009 // We didn't find a match or we wouldn't be here
2010 return new Size(smallest, smallest);
2012 } else {
2013 return new Size(16, 16);
2018 internal override int MouseButtonCount {
2019 get {
2020 return 3;
2024 internal override bool MouseButtonsSwapped {
2025 get {
2026 return false; // FIXME - how to detect?
2030 internal override Point MousePosition {
2031 get {
2032 return mouse_position;
2036 internal override Size MouseHoverSize {
2037 get {
2038 return new Size (1, 1);
2042 internal override int MouseHoverTime {
2043 get {
2044 return HoverState.Interval;
2050 internal override bool MouseWheelPresent {
2051 get {
2052 return true; // FIXME - how to detect?
2056 internal override Rectangle VirtualScreen {
2057 get {
2058 return WorkingArea;
2062 internal override Rectangle WorkingArea {
2063 get {
2064 IntPtr actual_atom;
2065 int actual_format;
2066 IntPtr nitems;
2067 IntPtr bytes_after;
2068 IntPtr prop = IntPtr.Zero;
2069 int width;
2070 int height;
2071 int current_desktop;
2072 int x;
2073 int y;
2075 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);
2076 if ((long)nitems < 1) {
2077 goto failsafe;
2080 current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
2081 XFree(prop);
2083 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);
2084 if ((long)nitems < 4 * current_desktop) {
2085 goto failsafe;
2088 x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
2089 y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
2090 width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
2091 height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
2092 XFree(prop);
2094 return new Rectangle(x, y, width, height);
2096 failsafe:
2097 XWindowAttributes attributes=new XWindowAttributes();
2099 lock (XlibLock) {
2100 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
2103 return new Rectangle(0, 0, attributes.width, attributes.height);
2107 internal override bool ThemesEnabled {
2108 get {
2109 return XplatUIX11.themes_enabled;
2114 #endregion // Public properties
2116 #region Public Static Methods
2117 internal override IntPtr InitializeDriver() {
2118 lock (this) {
2119 if (DisplayHandle==IntPtr.Zero) {
2120 SetDisplay(XOpenDisplay(IntPtr.Zero));
2123 return IntPtr.Zero;
2126 internal override void ShutdownDriver(IntPtr token) {
2127 lock (this) {
2128 if (DisplayHandle!=IntPtr.Zero) {
2129 XCloseDisplay(DisplayHandle);
2130 DisplayHandle=IntPtr.Zero;
2135 internal override void EnableThemes() {
2136 themes_enabled = true;
2140 internal override void Activate(IntPtr handle) {
2141 Hwnd hwnd;
2143 hwnd = Hwnd.ObjectFromHandle(handle);
2145 if (hwnd != null) {
2146 lock (XlibLock) {
2147 if (true /* the window manager supports NET_ACTIVE_WINDOW */) {
2148 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
2150 // else {
2151 // XRaiseWindow(DisplayHandle, handle);
2152 // }
2157 internal override void AudibleAlert() {
2158 XBell(DisplayHandle, 0);
2159 return;
2163 internal override void CaretVisible(IntPtr handle, bool visible) {
2164 if (Caret.Hwnd == handle) {
2165 if (visible) {
2166 if (!Caret.Visible) {
2167 Caret.Visible = true;
2168 ShowCaret();
2169 Caret.Timer.Start();
2171 } else {
2172 Caret.Visible = false;
2173 Caret.Timer.Stop();
2174 HideCaret();
2179 internal override bool CalculateWindowRect(ref Rectangle ClientRect, int Style, int ExStyle, Menu menu, out Rectangle WindowRect) {
2180 FormBorderStyle border_style;
2181 TitleStyle title_style;
2182 bool border_static;
2183 int caption_height;
2184 int tool_caption_height;
2186 DeriveStyles(Style, ExStyle, out border_style, out border_static, out title_style,
2187 out caption_height, out tool_caption_height);
2189 WindowRect = Hwnd.GetWindowRectangle(border_style, border_static, menu, title_style,
2190 caption_height, tool_caption_height,
2191 ClientRect);
2192 return true;
2195 internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) {
2196 int dest_x_return;
2197 int dest_y_return;
2198 IntPtr child;
2199 Hwnd hwnd;
2201 hwnd = Hwnd.ObjectFromHandle(handle);
2203 lock (XlibLock) {
2204 XTranslateCoordinates(DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
2207 x = dest_x_return;
2208 y = dest_y_return;
2211 internal override int[] ClipboardAvailableFormats(IntPtr handle) {
2212 DataFormats.Format f;
2213 int[] result;
2215 f = DataFormats.Format.List;
2217 if (XGetSelectionOwner(DisplayHandle, CLIPBOARD) == IntPtr.Zero) {
2218 return null;
2221 Clipboard.Formats = new ArrayList();
2223 while (f != null) {
2224 XConvertSelection(DisplayHandle, CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent, IntPtr.Zero);
2226 Clipboard.Enumerating = true;
2227 while (Clipboard.Enumerating) {
2228 UpdateMessageQueue(null);
2230 f = f.Next;
2233 result = new int[Clipboard.Formats.Count];
2235 for (int i = 0; i < Clipboard.Formats.Count; i++) {
2236 result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
2239 Clipboard.Formats = null;
2240 return result;
2243 internal override void ClipboardClose(IntPtr handle) {
2244 if (handle != ClipMagic) {
2245 throw new ArgumentException("handle is not a valid clipboard handle");
2247 return;
2250 internal override int ClipboardGetID(IntPtr handle, string format) {
2251 if (handle != ClipMagic) {
2252 throw new ArgumentException("handle is not a valid clipboard handle");
2255 if (format == "Text" ) return (int)Atom.XA_STRING;
2256 else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP;
2257 //else if (format == "MetaFilePict" ) return 3;
2258 //else if (format == "SymbolicLink" ) return 4;
2259 //else if (format == "DataInterchangeFormat" ) return 5;
2260 //else if (format == "Tiff" ) return 6;
2261 else if (format == "OEMText" ) return OEMTEXT.ToInt32();
2262 else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP;
2263 else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless
2264 //else if (format == "PenData" ) return 10;
2265 //else if (format == "RiffAudio" ) return 11;
2266 //else if (format == "WaveAudio" ) return 12;
2267 else if (format == "UnicodeText" ) return UNICODETEXT.ToInt32();
2268 //else if (format == "EnhancedMetafile" ) return 14;
2269 //else if (format == "FileDrop" ) return 15;
2270 //else if (format == "Locale" ) return 16;
2272 return XInternAtom(DisplayHandle, format, false).ToInt32();
2275 internal override IntPtr ClipboardOpen(bool primary_selection) {
2276 if (!primary_selection)
2277 ClipMagic = CLIPBOARD;
2278 else
2279 ClipMagic = PRIMARY;
2280 return ClipMagic;
2283 internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) {
2284 XConvertSelection(DisplayHandle, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
2286 Clipboard.Retrieving = true;
2287 while (Clipboard.Retrieving) {
2288 UpdateMessageQueue(null);
2291 return Clipboard.Item;
2294 internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter) {
2295 Clipboard.Item = obj;
2296 Clipboard.Type = type;
2297 Clipboard.Converter = converter;
2299 if (obj != null) {
2300 XSetSelectionOwner(DisplayHandle, CLIPBOARD, FosterParent, IntPtr.Zero);
2301 } else {
2302 // Clearing the selection
2303 XSetSelectionOwner(DisplayHandle, CLIPBOARD, IntPtr.Zero, IntPtr.Zero);
2307 internal override void CreateCaret (IntPtr handle, int width, int height)
2309 XGCValues gc_values;
2310 Hwnd hwnd;
2312 hwnd = Hwnd.ObjectFromHandle(handle);
2314 if (Caret.Hwnd != IntPtr.Zero) {
2315 DestroyCaret(Caret.Hwnd);
2318 Caret.Hwnd = handle;
2319 Caret.Window = hwnd.client_window;
2320 Caret.Width = width;
2321 Caret.Height = height;
2322 Caret.Visible = false;
2323 Caret.On = false;
2325 gc_values = new XGCValues();
2326 gc_values.line_width = width;
2328 Caret.gc = XCreateGC(DisplayHandle, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
2329 if (Caret.gc == IntPtr.Zero) {
2330 Caret.Hwnd = IntPtr.Zero;
2331 return;
2334 XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert);
2337 internal override IntPtr CreateWindow (CreateParams cp)
2339 XSetWindowAttributes Attributes;
2340 Hwnd hwnd;
2341 int X;
2342 int Y;
2343 int Width;
2344 int Height;
2345 IntPtr ParentHandle;
2346 IntPtr WholeWindow;
2347 IntPtr ClientWindow;
2348 Rectangle ClientRect;
2349 SetWindowValuemask ValueMask;
2350 int[] atoms;
2352 hwnd = new Hwnd();
2354 Attributes = new XSetWindowAttributes();
2355 X = cp.X;
2356 Y = cp.Y;
2357 Width = cp.Width;
2358 Height = cp.Height;
2360 if (Width<1) Width=1;
2361 if (Height<1) Height=1;
2363 if (cp.Parent != IntPtr.Zero) {
2364 ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).client_window;
2365 } else {
2366 if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2367 // We need to use our foster parent window until this poor child gets it's parent assigned
2368 ParentHandle=FosterParent;
2369 } else if (StyleSet (cp.Style, WindowStyles.WS_POPUP)) {
2370 ParentHandle=RootWindow;
2371 } else {
2372 // Default position on screen, if window manager doesn't place us somewhere else
2373 if (X<0) X = 50;
2374 if (Y<0) Y = 50;
2375 ParentHandle=RootWindow;
2379 ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
2381 Attributes.bit_gravity = Gravity.NorthWestGravity;
2382 Attributes.win_gravity = Gravity.NorthWestGravity;
2384 // Save what's under the toolwindow
2385 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
2386 Attributes.save_under = true;
2387 ValueMask |= SetWindowValuemask.SaveUnder;
2391 // If we're a popup without caption we override the WM
2392 if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
2393 Attributes.override_redirect = true;
2394 ValueMask |= SetWindowValuemask.OverrideRedirect;
2397 hwnd.x = X;
2398 hwnd.y = Y;
2399 hwnd.width = Width;
2400 hwnd.height = Height;
2401 hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent);
2402 hwnd.initial_ex_style = (WindowExStyles) cp.ExStyle;
2404 if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) {
2405 hwnd.enabled = false;
2408 ClientRect = hwnd.ClientRect;
2409 ClientWindow = IntPtr.Zero;
2411 lock (XlibLock) {
2412 WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, Width, Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes);
2413 if (WholeWindow != IntPtr.Zero) {
2414 ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder);
2416 if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) {
2417 ValueMask = SetWindowValuemask.ColorMap;
2418 Attributes.colormap = CustomColormap;
2420 ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes);
2424 if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) {
2425 throw new Exception("Could not create X11 windows");
2428 hwnd.Queue = ThreadQueue(Thread.CurrentThread);
2429 hwnd.WholeWindow = WholeWindow;
2430 hwnd.ClientWindow = ClientWindow;
2432 #if DriverDebug || DriverDebugCreate
2433 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);
2434 #endif
2436 if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
2437 if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
2438 XSizeHints hints;
2440 hints = new XSizeHints();
2441 hints.x = X;
2442 hints.y = Y;
2443 hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition);
2444 XSetWMNormalHints(DisplayHandle, WholeWindow, ref hints);
2448 lock (XlibLock) {
2449 XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask)));
2450 if (hwnd.whole_window != hwnd.client_window)
2451 XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask)));
2454 if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
2455 atoms = new int[2];
2456 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
2457 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
2459 XSetTransientForHint (DisplayHandle, hwnd.whole_window, RootWindow);
2462 SetWMStyles(hwnd, cp);
2464 // set the group leader
2465 XWMHints wm_hints = new XWMHints ();
2467 wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint);
2468 wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED);
2469 wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState;
2471 if (ParentHandle != RootWindow) {
2472 wm_hints.window_group = hwnd.whole_window;
2473 } else {
2474 wm_hints.window_group = ParentHandle;
2477 lock (XlibLock) {
2478 XSetWMHints(DisplayHandle, hwnd.whole_window, ref wm_hints );
2481 if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) {
2482 SetWindowState(hwnd.Handle, FormWindowState.Minimized);
2483 } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) {
2484 SetWindowState(hwnd.Handle, FormWindowState.Maximized);
2487 // for now make all windows dnd enabled
2488 Dnd.SetAllowDrop (hwnd, true);
2490 // Set caption/window title
2491 Text(hwnd.Handle, cp.Caption);
2493 SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */);
2494 SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue);
2496 if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) {
2497 hwnd.visible = true;
2498 MapWindow(hwnd, WindowType.Both);
2499 if (!(Control.FromHandle(hwnd.Handle) is Form))
2500 SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
2503 return hwnd.Handle;
2506 internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) {
2507 CreateParams create_params = new CreateParams();
2509 create_params.Caption = "";
2510 create_params.X = X;
2511 create_params.Y = Y;
2512 create_params.Width = Width;
2513 create_params.Height = Height;
2515 create_params.ClassName=XplatUI.DefaultClassName;
2516 create_params.ClassStyle = 0;
2517 create_params.ExStyle=0;
2518 create_params.Parent=IntPtr.Zero;
2519 create_params.Param=0;
2521 return CreateWindow(create_params);
2524 internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) {
2525 IntPtr cursor;
2526 Bitmap cursor_bitmap;
2527 Bitmap cursor_mask;
2528 Byte[] cursor_bits;
2529 Byte[] mask_bits;
2530 Color c_pixel;
2531 Color m_pixel;
2532 int width;
2533 int height;
2534 IntPtr cursor_pixmap;
2535 IntPtr mask_pixmap;
2536 XColor fg;
2537 XColor bg;
2538 bool and;
2539 bool xor;
2541 if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) {
2542 return IntPtr.Zero;
2545 // Win32 only allows creation cursors of a certain size
2546 if ((bitmap.Width != width) || (bitmap.Width != height)) {
2547 cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
2548 cursor_mask = new Bitmap(mask, new Size(width, height));
2549 } else {
2550 cursor_bitmap = bitmap;
2551 cursor_mask = mask;
2554 width = cursor_bitmap.Width;
2555 height = cursor_bitmap.Height;
2557 cursor_bits = new Byte[(width / 8) * height];
2558 mask_bits = new Byte[(width / 8) * height];
2560 for (int y = 0; y < height; y++) {
2561 for (int x = 0; x < width; x++) {
2562 c_pixel = cursor_bitmap.GetPixel(x, y);
2563 m_pixel = cursor_mask.GetPixel(x, y);
2565 and = c_pixel == cursor_pixel;
2566 xor = m_pixel == mask_pixel;
2568 if (!and && !xor) {
2569 // Black
2570 // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
2571 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2572 } else if (and && !xor) {
2573 // White
2574 cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2575 mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
2576 #if notneeded
2577 } else if (and && !xor) {
2578 // Screen
2579 } else if (and && xor) {
2580 // Inverse Screen
2582 // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
2583 // we want both to be 0 so nothing to be done
2584 //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
2585 //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
2586 #endif
2591 cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2592 mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
2593 fg = new XColor();
2594 bg = new XColor();
2596 fg.pixel = XWhitePixel(DisplayHandle, ScreenNo);
2597 fg.red = (ushort)65535;
2598 fg.green = (ushort)65535;
2599 fg.blue = (ushort)65535;
2601 bg.pixel = XBlackPixel(DisplayHandle, ScreenNo);
2603 cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
2605 XFreePixmap(DisplayHandle, cursor_pixmap);
2606 XFreePixmap(DisplayHandle, mask_pixmap);
2608 return cursor;
2611 internal override IntPtr DefineStdCursor(StdCursor id) {
2612 CursorFontShape shape;
2613 IntPtr cursor;
2615 // FIXME - define missing shapes
2617 switch (id) {
2618 case StdCursor.AppStarting: {
2619 shape = CursorFontShape.XC_watch;
2620 break;
2623 case StdCursor.Arrow: {
2624 shape = CursorFontShape.XC_top_left_arrow;
2625 break;
2628 case StdCursor.Cross: {
2629 shape = CursorFontShape.XC_crosshair;
2630 break;
2633 case StdCursor.Default: {
2634 shape = CursorFontShape.XC_top_left_arrow;
2635 break;
2638 case StdCursor.Hand: {
2639 shape = CursorFontShape.XC_hand1;
2640 break;
2643 case StdCursor.Help: {
2644 shape = CursorFontShape.XC_question_arrow;
2645 break;
2648 case StdCursor.HSplit: {
2649 shape = CursorFontShape.XC_sb_v_double_arrow;
2650 break;
2653 case StdCursor.IBeam: {
2654 shape = CursorFontShape.XC_xterm;
2655 break;
2658 case StdCursor.No: {
2659 shape = CursorFontShape.XC_circle;
2660 break;
2663 case StdCursor.NoMove2D: {
2664 shape = CursorFontShape.XC_fleur;
2665 break;
2668 case StdCursor.NoMoveHoriz: {
2669 shape = CursorFontShape.XC_fleur;
2670 break;
2673 case StdCursor.NoMoveVert: {
2674 shape = CursorFontShape.XC_fleur;
2675 break;
2678 case StdCursor.PanEast: {
2679 shape = CursorFontShape.XC_fleur;
2680 break;
2683 case StdCursor.PanNE: {
2684 shape = CursorFontShape.XC_fleur;
2685 break;
2688 case StdCursor.PanNorth: {
2689 shape = CursorFontShape.XC_fleur;
2690 break;
2693 case StdCursor.PanNW: {
2694 shape = CursorFontShape.XC_fleur;
2695 break;
2698 case StdCursor.PanSE: {
2699 shape = CursorFontShape.XC_fleur;
2700 break;
2703 case StdCursor.PanSouth: {
2704 shape = CursorFontShape.XC_fleur;
2705 break;
2708 case StdCursor.PanSW: {
2709 shape = CursorFontShape.XC_fleur;
2710 break;
2713 case StdCursor.PanWest: {
2714 shape = CursorFontShape.XC_sizing;
2715 break;
2718 case StdCursor.SizeAll: {
2719 shape = CursorFontShape.XC_fleur;
2720 break;
2723 case StdCursor.SizeNESW: {
2724 shape = CursorFontShape.XC_top_right_corner;
2725 break;
2728 case StdCursor.SizeNS: {
2729 shape = CursorFontShape.XC_sb_v_double_arrow;
2730 break;
2733 case StdCursor.SizeNWSE: {
2734 shape = CursorFontShape.XC_top_left_corner;
2735 break;
2738 case StdCursor.SizeWE: {
2739 shape = CursorFontShape.XC_sb_h_double_arrow;
2740 break;
2743 case StdCursor.UpArrow: {
2744 shape = CursorFontShape.XC_center_ptr;
2745 break;
2748 case StdCursor.VSplit: {
2749 shape = CursorFontShape.XC_sb_h_double_arrow;
2750 break;
2753 case StdCursor.WaitCursor: {
2754 shape = CursorFontShape.XC_watch;
2755 break;
2758 default: {
2759 return IntPtr.Zero;
2763 lock (XlibLock) {
2764 cursor = XCreateFontCursor(DisplayHandle, shape);
2766 return cursor;
2769 internal override IntPtr DefWndProc(ref Message msg) {
2770 switch ((Msg)msg.Msg) {
2771 case Msg.WM_PAINT: {
2772 Hwnd hwnd;
2774 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
2775 if (hwnd != null) {
2776 hwnd.expose_pending = false;
2779 return IntPtr.Zero;
2782 case Msg.WM_NCPAINT: {
2783 Hwnd hwnd;
2785 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
2786 if (hwnd != null) {
2787 hwnd.nc_expose_pending = false;
2790 return IntPtr.Zero;
2793 case Msg.WM_CONTEXTMENU: {
2794 Hwnd hwnd;
2796 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
2798 if ((hwnd != null) && (hwnd.parent != null)) {
2799 SendMessage(hwnd.parent.client_window, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam);
2801 return IntPtr.Zero;
2804 case Msg.WM_MOUSEWHEEL: {
2805 Hwnd hwnd;
2807 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
2809 if ((hwnd != null) && (hwnd.parent != null)) {
2810 SendMessage(hwnd.parent.client_window, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam);
2811 if (msg.Result == IntPtr.Zero) {
2812 return IntPtr.Zero;
2815 return IntPtr.Zero;
2818 case Msg.WM_SETCURSOR: {
2819 Hwnd hwnd;
2821 hwnd = Hwnd.GetObjectFromWindow(msg.HWnd);
2822 if (hwnd == null)
2823 break; // not sure how this happens, but it does
2825 // Pass to parent window first
2826 while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) {
2827 hwnd = hwnd.parent;
2828 msg.Result = NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam);
2831 if (msg.Result == IntPtr.Zero) {
2832 IntPtr handle;
2834 switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) {
2835 case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break;
2836 case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break;
2837 case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break;
2838 case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break;
2839 case HitTest.HTERROR: if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) {
2840 AudibleAlert();
2842 handle = Cursors.Default.handle;
2843 break;
2845 case HitTest.HTHELP: handle = Cursors.Help.handle; break;
2846 case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break;
2847 case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break;
2848 case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break;
2849 case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break;
2850 case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break;
2852 #if SameAsDefault
2853 case HitTest.HTGROWBOX:
2854 case HitTest.HTSIZE:
2855 case HitTest.HTZOOM:
2856 case HitTest.HTVSCROLL:
2857 case HitTest.HTSYSMENU:
2858 case HitTest.HTREDUCE:
2859 case HitTest.HTNOWHERE:
2860 case HitTest.HTMAXBUTTON:
2861 case HitTest.HTMINBUTTON:
2862 case HitTest.HTMENU:
2863 case HitTest.HSCROLL:
2864 case HitTest.HTBOTTOM:
2865 case HitTest.HTCAPTION:
2866 case HitTest.HTCLIENT:
2867 case HitTest.HTCLOSE:
2868 #endif
2869 default: handle = Cursors.Default.handle; break;
2871 SetCursor(msg.HWnd, handle);
2873 return (IntPtr)1;
2876 return IntPtr.Zero;
2879 internal override void DestroyCaret(IntPtr handle) {
2880 if (Caret.Hwnd == handle) {
2881 if (Caret.Visible) {
2882 HideCaret ();
2883 Caret.Timer.Stop();
2885 if (Caret.gc != IntPtr.Zero) {
2886 XFreeGC(DisplayHandle, Caret.gc);
2887 Caret.gc = IntPtr.Zero;
2889 Caret.Hwnd = IntPtr.Zero;
2890 Caret.Visible = false;
2891 Caret.On = false;
2895 internal override void DestroyCursor(IntPtr cursor) {
2896 lock (XlibLock) {
2897 XFreeCursor(DisplayHandle, cursor);
2901 internal override void DestroyWindow(IntPtr handle) {
2902 Hwnd hwnd;
2904 hwnd = Hwnd.ObjectFromHandle(handle);
2906 if (hwnd == null) {
2907 #if DriverDebug || DriverDebugDestroy
2908 Console.WriteLine("window {0:X} already destroyed", handle.ToInt32());
2909 #endif
2910 return;
2913 #if DriverDebug || DriverDebugDestroy
2914 Console.WriteLine("Destroying window {0}", XplatUI.Window(hwnd.client_window));
2915 #endif
2917 SendParentNotify (hwnd.Handle, Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
2919 CleanupCachedWindows (hwnd);
2921 ArrayList windows = new ArrayList ();
2923 AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
2925 lock (XlibLock) {
2926 if (hwnd.whole_window != IntPtr.Zero) {
2927 #if DriverDebug || DriverDebugDestroy
2928 Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32());
2929 #endif
2930 XDestroyWindow(DisplayHandle, hwnd.whole_window);
2932 else if (hwnd.client_window != IntPtr.Zero) {
2933 #if DriverDebug || DriverDebugDestroy
2934 Console.WriteLine ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32());
2935 #endif
2936 XDestroyWindow(DisplayHandle, hwnd.client_window);
2941 foreach (Hwnd h in windows) {
2942 SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
2946 internal override IntPtr DispatchMessage(ref MSG msg) {
2947 return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
2950 IntPtr GetReversibleScreenGC (Color backColor)
2952 XGCValues gc_values;
2953 IntPtr gc;
2954 uint pixel;
2956 XColor xcolor = new XColor();
2957 xcolor.red = (ushort)(backColor.R * 257);
2958 xcolor.green = (ushort)(backColor.G * 257);
2959 xcolor.blue = (ushort)(backColor.B * 257);
2960 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
2961 pixel = (uint)xcolor.pixel.ToInt32();
2964 gc_values = new XGCValues();
2966 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
2967 gc_values.foreground = (IntPtr)pixel;
2969 gc = XCreateGC(DisplayHandle, RootWindow, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
2970 XSetForeground(DisplayHandle, gc, (UIntPtr)pixel);
2971 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
2973 return gc;
2976 IntPtr GetReversibleControlGC (Control control, int line_width)
2978 XGCValues gc_values;
2979 IntPtr gc;
2981 gc_values = new XGCValues();
2983 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
2984 gc_values.line_width = line_width;
2985 gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo);
2987 // This logic will give us true rubber bands: (libsx, SANE_XOR)
2988 //mask = foreground ^ background;
2989 //XSetForeground(DisplayHandle, gc, 0xffffffff);
2990 //XSetBackground(DisplayHandle, gc, background);
2991 //XSetFunction(DisplayHandle, gc, GXxor);
2992 //XSetPlaneMask(DisplayHandle, gc, mask);
2995 gc = XCreateGC(DisplayHandle, control.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values);
2996 uint foreground;
2997 uint background;
2999 XColor xcolor = new XColor();
3001 xcolor.red = (ushort)(control.ForeColor.R * 257);
3002 xcolor.green = (ushort)(control.ForeColor.G * 257);
3003 xcolor.blue = (ushort)(control.ForeColor.B * 257);
3004 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3005 foreground = (uint)xcolor.pixel.ToInt32();
3007 xcolor.red = (ushort)(control.BackColor.R * 257);
3008 xcolor.green = (ushort)(control.BackColor.G * 257);
3009 xcolor.blue = (ushort)(control.BackColor.B * 257);
3010 XAllocColor(DisplayHandle, DefaultColormap, ref xcolor);
3011 background = (uint)xcolor.pixel.ToInt32();
3013 uint mask = foreground ^ background;
3015 XSetForeground(DisplayHandle, gc, (UIntPtr)0xffffffff);
3016 XSetBackground(DisplayHandle, gc, (UIntPtr)background);
3017 XSetFunction(DisplayHandle, gc, GXFunction.GXxor);
3018 XSetPlaneMask(DisplayHandle, gc, (IntPtr)mask);
3020 return gc;
3023 internal override void DrawReversibleLine(Point start, Point end, Color backColor)
3025 IntPtr gc = GetReversibleScreenGC (backColor);
3027 XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y);
3029 XFreeGC(DisplayHandle, gc);
3032 internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
3034 IntPtr gc = GetReversibleScreenGC (backColor);
3036 if (rectangle.Width < 0) {
3037 rectangle.X += rectangle.Width;
3038 rectangle.Width = -rectangle.Width;
3040 if (rectangle.Height < 0) {
3041 rectangle.Y += rectangle.Height;
3042 rectangle.Height = -rectangle.Height;
3045 int line_width = 1;
3046 GCLineStyle line_style = GCLineStyle.LineSolid;
3047 GCCapStyle cap_style = GCCapStyle.CapButt;
3048 GCJoinStyle join_style = GCJoinStyle.JoinMiter;
3050 switch (style) {
3051 case FrameStyle.Dashed:
3052 line_style = GCLineStyle.LineOnOffDash;
3053 break;
3054 case FrameStyle.Thick:
3055 line_width = 2;
3056 break;
3059 XSetLineAttributes (DisplayHandle, gc, line_width, line_style, cap_style, join_style);
3061 XDrawRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3063 XFreeGC(DisplayHandle, gc);
3066 internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
3068 IntPtr gc = GetReversibleScreenGC (backColor);
3070 if (rectangle.Width < 0) {
3071 rectangle.X += rectangle.Width;
3072 rectangle.Width = -rectangle.Width;
3074 if (rectangle.Height < 0) {
3075 rectangle.Y += rectangle.Height;
3076 rectangle.Height = -rectangle.Height;
3078 XFillRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
3080 XFreeGC(DisplayHandle, gc);
3083 internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) {
3084 IntPtr gc;
3085 Control control = Control.FromHandle(handle);
3087 gc = GetReversibleControlGC (control, line_width);
3089 if ((rect.Width > 0) && (rect.Height > 0)) {
3090 XDrawRectangle(DisplayHandle, control.Handle, gc, rect.Left, rect.Top, rect.Width, rect.Height);
3091 } else {
3092 if (rect.Width > 0) {
3093 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.Right, rect.Y);
3094 } else {
3095 XDrawLine(DisplayHandle, control.Handle, gc, rect.X, rect.Y, rect.X, rect.Bottom);
3098 XFreeGC(DisplayHandle, gc);
3101 internal override void DoEvents() {
3102 MSG msg = new MSG ();
3103 XEventQueue queue;
3105 if (OverrideCursorHandle != IntPtr.Zero) {
3106 OverrideCursorHandle = IntPtr.Zero;
3109 queue = ThreadQueue(Thread.CurrentThread);
3111 queue.DispatchIdle = false;
3113 while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
3114 TranslateMessage (ref msg);
3115 DispatchMessage (ref msg);
3118 queue.DispatchIdle = true;
3121 internal override void EnableWindow(IntPtr handle, bool Enable) {
3122 Hwnd hwnd;
3124 hwnd = Hwnd.ObjectFromHandle(handle);
3125 if (hwnd != null) {
3126 hwnd.Enabled = Enable;
3130 internal override void EndLoop(Thread thread) {
3131 // This is where we one day will shut down the loop for the thread
3134 internal override IntPtr GetActive() {
3135 IntPtr actual_atom;
3136 int actual_format;
3137 IntPtr nitems;
3138 IntPtr bytes_after;
3139 IntPtr prop = IntPtr.Zero;
3140 IntPtr active = IntPtr.Zero;
3142 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);
3143 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
3144 active = (IntPtr)Marshal.ReadInt32(prop);
3145 XFree(prop);
3148 if (active != IntPtr.Zero) {
3149 Hwnd hwnd;
3151 hwnd = Hwnd.GetObjectFromWindow(active);
3152 if (hwnd != null) {
3153 active = hwnd.Handle;
3154 } else {
3155 active = IntPtr.Zero;
3158 return active;
3161 internal override Region GetClipRegion(IntPtr handle) {
3162 Hwnd hwnd;
3164 hwnd = Hwnd.ObjectFromHandle(handle);
3165 if (hwnd != null) {
3166 return hwnd.UserClip;
3169 return null;
3172 internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) {
3173 width = 20;
3174 height = 20;
3175 hotspot_x = 0;
3176 hotspot_y = 0;
3179 internal override void GetDisplaySize(out Size size) {
3180 XWindowAttributes attributes=new XWindowAttributes();
3182 lock (XlibLock) {
3183 // FIXME - use _NET_WM messages instead?
3184 XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes);
3187 size = new Size(attributes.width, attributes.height);
3190 internal override SizeF GetAutoScaleSize(Font font) {
3191 Graphics g;
3192 float width;
3193 string magic_string = "The quick brown fox jumped over the lazy dog.";
3194 double magic_number = 44.549996948242189;
3196 g = Graphics.FromHwnd(FosterParent);
3198 width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
3199 return new SizeF(width, font.Height);
3202 internal override IntPtr GetParent(IntPtr handle) {
3203 Hwnd hwnd;
3205 hwnd = Hwnd.ObjectFromHandle(handle);
3206 if (hwnd != null && hwnd.parent != null) {
3207 return hwnd.parent.Handle;
3209 return IntPtr.Zero;
3212 internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
3213 IntPtr use_handle;
3214 IntPtr root;
3215 IntPtr child;
3216 int root_x;
3217 int root_y;
3218 int win_x;
3219 int win_y;
3220 int keys_buttons;
3222 if (handle != IntPtr.Zero) {
3223 use_handle = Hwnd.ObjectFromHandle(handle).client_window;
3224 } else {
3225 use_handle = RootWindow;
3228 lock (XlibLock) {
3229 QueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
3232 if (handle != IntPtr.Zero) {
3233 x = win_x;
3234 y = win_y;
3235 } else {
3236 x = root_x;
3237 y = root_y;
3241 internal override IntPtr GetFocus() {
3242 return FocusWindow;
3246 internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) {
3247 return GetFontMetrics(g.GetHdc(), font.ToHfont(), out ascent, out descent);
3250 internal override Point GetMenuOrigin(IntPtr handle) {
3251 Hwnd hwnd;
3253 hwnd = Hwnd.ObjectFromHandle(handle);
3255 if (hwnd != null) {
3256 return hwnd.MenuOrigin;
3258 return Point.Empty;
3261 [MonoTODO("Implement filtering")]
3262 internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) {
3263 XEvent xevent;
3264 bool client;
3265 Hwnd hwnd;
3267 ProcessNextMessage:
3269 if (((XEventQueue)queue_id).Count > 0) {
3270 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3271 } else {
3272 UpdateMessageQueue ((XEventQueue)queue_id);
3274 if (((XEventQueue)queue_id).Count > 0) {
3275 xevent = (XEvent) ((XEventQueue)queue_id).Dequeue ();
3276 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
3277 xevent = ((XEventQueue)queue_id).Paint.Dequeue();
3278 } else {
3279 msg.hwnd= IntPtr.Zero;
3280 msg.message = Msg.WM_ENTERIDLE;
3281 return true;
3285 hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
3287 // Handle messages for windows that are already or are about to be destroyed.
3289 // we need a special block for this because unless we remove the hwnd from the paint
3290 // queue it will always stay there (since we don't handle the expose), and we'll
3291 // effectively loop infinitely trying to repaint a non-existant window.
3292 if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
3293 hwnd.expose_pending = hwnd.nc_expose_pending = false;
3294 hwnd.Queue.Paint.Remove (hwnd);
3295 goto ProcessNextMessage;
3298 // We need to make sure we only allow DestroyNotify events through for zombie
3299 // hwnds, since much of the event handling code makes requests using the hwnd's
3300 // client_window, and that'll result in BadWindow errors if there's some lag
3301 // between the XDestroyWindow call and the DestroyNotify event.
3302 if (hwnd == null || hwnd.zombie) {
3303 #if DriverDebug || DriverDebugDestroy
3304 Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
3305 #endif
3306 goto ProcessNextMessage;
3309 if (hwnd.client_window == xevent.AnyEvent.window) {
3310 client = true;
3311 //Console.WriteLine("Client message {1}, sending to window {0:X}", msg.hwnd.ToInt32(), xevent.type);
3312 } else {
3313 client = false;
3314 //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32());
3317 msg.hwnd = hwnd.Handle;
3320 // If you add a new event to this switch make sure to add it in
3321 // UpdateMessage also unless it is not coming through the X event system.
3323 switch(xevent.type) {
3324 case XEventName.KeyPress: {
3325 if (Dnd.InDrag ())
3326 Dnd.HandleKeyPress (ref xevent);
3327 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3328 break;
3331 case XEventName.KeyRelease: {
3332 Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
3333 break;
3336 case XEventName.ButtonPress: {
3337 switch(xevent.ButtonEvent.button) {
3338 case 1: {
3339 MouseState |= MouseButtons.Left;
3340 if (client) {
3341 msg.message = Msg.WM_LBUTTONDOWN;
3342 } else {
3343 msg.message = Msg.WM_NCLBUTTONDOWN;
3344 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3346 // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
3347 msg.wParam=GetMousewParam(0);
3348 break;
3351 case 2: {
3352 MouseState |= MouseButtons.Middle;
3353 if (client) {
3354 msg.message = Msg.WM_MBUTTONDOWN;
3355 } else {
3356 msg.message = Msg.WM_NCMBUTTONDOWN;
3357 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3359 msg.wParam=GetMousewParam(0);
3360 break;
3363 case 3: {
3364 MouseState |= MouseButtons.Right;
3365 if (client) {
3366 msg.message = Msg.WM_RBUTTONDOWN;
3367 } else {
3368 msg.message = Msg.WM_NCRBUTTONDOWN;
3369 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3371 msg.wParam=GetMousewParam(0);
3372 break;
3375 case 4: {
3376 msg.hwnd = FocusWindow;
3377 msg.message=Msg.WM_MOUSEWHEEL;
3378 msg.wParam=GetMousewParam(120);
3379 break;
3382 case 5: {
3383 msg.hwnd = FocusWindow;
3384 msg.message=Msg.WM_MOUSEWHEEL;
3385 msg.wParam=GetMousewParam(-120);
3386 break;
3391 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3392 mouse_position.X = xevent.ButtonEvent.x;
3393 mouse_position.Y = xevent.ButtonEvent.y;
3395 if (!hwnd.Enabled) {
3396 IntPtr dummy;
3398 msg.hwnd = hwnd.EnabledHwnd;
3399 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);
3400 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3403 if (Grab.Hwnd != IntPtr.Zero) {
3404 msg.hwnd = Grab.Hwnd;
3407 if (ClickPending.Pending && ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
3408 // Looks like a genuine double click, clicked twice on the same spot with the same keys
3409 switch(xevent.ButtonEvent.button) {
3410 case 1: {
3411 msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
3412 break;
3415 case 2: {
3416 msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
3417 break;
3420 case 3: {
3421 msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
3422 break;
3425 ClickPending.Pending = false;
3426 } else {
3427 ClickPending.Pending = true;
3428 ClickPending.Hwnd = msg.hwnd;
3429 ClickPending.Message = msg.message;
3430 ClickPending.wParam = msg.wParam;
3431 ClickPending.lParam = msg.lParam;
3432 ClickPending.Time = (long)xevent.ButtonEvent.time;
3435 if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN)
3436 SendParentNotify(msg.hwnd, msg.message, mouse_position.X, mouse_position.Y);
3438 break;
3441 case XEventName.ButtonRelease: {
3442 if (Dnd.InDrag()) {
3443 if (Dnd.HandleButtonRelease (ref xevent)) {
3444 break;
3446 // Allow the LBUTTONUP message to get through
3449 switch(xevent.ButtonEvent.button) {
3450 case 1: {
3451 if (client) {
3452 msg.message = Msg.WM_LBUTTONUP;
3453 } else {
3454 msg.message = Msg.WM_NCLBUTTONUP;
3455 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3457 MouseState &= ~MouseButtons.Left;
3458 msg.wParam=GetMousewParam(0);
3459 break;
3462 case 2: {
3463 if (client) {
3464 msg.message = Msg.WM_MBUTTONUP;
3465 } else {
3466 msg.message = Msg.WM_NCMBUTTONUP;
3467 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3469 MouseState &= ~MouseButtons.Middle;
3470 msg.wParam=GetMousewParam(0);
3471 break;
3474 case 3: {
3475 if (client) {
3476 msg.message = Msg.WM_RBUTTONUP;
3477 } else {
3478 msg.message = Msg.WM_NCRBUTTONUP;
3479 MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
3481 MouseState &= ~MouseButtons.Right;
3482 msg.wParam=GetMousewParam(0);
3483 break;
3486 case 4: {
3487 goto ProcessNextMessage;
3490 case 5: {
3491 goto ProcessNextMessage;
3495 if (!hwnd.Enabled) {
3496 IntPtr dummy;
3498 msg.hwnd = hwnd.EnabledHwnd;
3499 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);
3500 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3503 if (Grab.Hwnd != IntPtr.Zero) {
3504 msg.hwnd = Grab.Hwnd;
3507 msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
3508 mouse_position.X = xevent.ButtonEvent.x;
3509 mouse_position.Y = xevent.ButtonEvent.y;
3510 break;
3513 case XEventName.MotionNotify: {
3514 if (client) {
3515 #if DriverDebugExtra
3516 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);
3517 #endif
3519 if (Dnd.HandleMotionNotify (ref xevent))
3520 goto ProcessNextMessage;
3521 if (Grab.Hwnd != IntPtr.Zero) {
3522 msg.hwnd = Grab.Hwnd;
3523 } else {
3524 NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
3527 msg.message = Msg.WM_MOUSEMOVE;
3528 msg.wParam = GetMousewParam(0);
3529 msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
3531 if (!hwnd.Enabled) {
3532 IntPtr dummy;
3534 msg.hwnd = hwnd.EnabledHwnd;
3535 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);
3536 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3539 mouse_position.X = xevent.MotionEvent.x;
3540 mouse_position.Y = xevent.MotionEvent.y;
3542 if ((HoverState.Timer.Enabled) &&
3543 (((mouse_position.X + HoverState.Size.Width) < HoverState.X) ||
3544 ((mouse_position.X - HoverState.Size.Width) > HoverState.X) ||
3545 ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) ||
3546 ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) {
3547 HoverState.Timer.Stop();
3548 HoverState.Timer.Start();
3549 HoverState.X = mouse_position.X;
3550 HoverState.Y = mouse_position.Y;
3553 break;
3554 } else {
3555 HitTest ht;
3556 IntPtr dummy;
3557 int screen_x;
3558 int screen_y;
3560 #if DriverDebugExtra
3561 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);
3562 #endif
3563 msg.message = Msg.WM_NCMOUSEMOVE;
3565 if (!hwnd.Enabled) {
3566 msg.hwnd = hwnd.EnabledHwnd;
3567 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);
3568 msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
3571 // The hit test is sent in screen coordinates
3572 XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, RootWindow,
3573 xevent.MotionEvent.x, xevent.MotionEvent.y,
3574 out screen_x, out screen_y, out dummy);
3576 msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF);
3577 ht = (HitTest)NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST,
3578 IntPtr.Zero, msg.lParam).ToInt32 ();
3579 NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
3581 mouse_position.X = xevent.MotionEvent.x;
3582 mouse_position.Y = xevent.MotionEvent.y;
3585 break;
3588 case XEventName.EnterNotify: {
3589 if (!hwnd.Enabled) {
3590 goto ProcessNextMessage;
3592 if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
3593 goto ProcessNextMessage;
3595 msg.message = Msg.WM_MOUSE_ENTER;
3596 HoverState.X = xevent.CrossingEvent.x;
3597 HoverState.Y = xevent.CrossingEvent.y;
3598 HoverState.Timer.Enabled = true;
3599 HoverState.Window = xevent.CrossingEvent.window;
3600 break;
3603 case XEventName.LeaveNotify: {
3604 if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) {
3605 WindowUngrabbed (hwnd.Handle);
3606 goto ProcessNextMessage;
3608 if (!hwnd.Enabled) {
3609 goto ProcessNextMessage;
3611 if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
3612 goto ProcessNextMessage;
3614 msg.message=Msg.WM_MOUSELEAVE;
3615 HoverState.Timer.Enabled = false;
3616 HoverState.Window = IntPtr.Zero;
3617 break;
3620 #if later
3621 case XEventName.CreateNotify: {
3622 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) {
3623 msg.message = WM_CREATE;
3624 // Set up CreateStruct
3625 } else {
3626 goto ProcessNextMessage;
3628 break;
3630 #endif
3633 case XEventName.ReparentNotify: {
3634 if (hwnd.parent == null) { // Toplevel
3635 if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) {
3636 // We need to adjust x/y
3637 // This sucks ass, part 2
3638 // Every WM does the reparenting of toplevel windows different, so there's
3639 // no standard way of getting our adjustment considering frames/decorations
3640 // The code below is needed for metacity. KDE doesn't works just fine without this
3641 int dummy_int;
3642 IntPtr dummy_ptr;
3643 int new_x;
3644 int new_y;
3645 int frame_left;
3646 int frame_top;
3648 hwnd.Reparented = true;
3650 XGetGeometry(DisplayHandle, XGetParent(hwnd.whole_window), out dummy_ptr, out new_x, out new_y, out dummy_int, out dummy_int, out dummy_int, out dummy_int);
3651 FrameExtents(hwnd.whole_window, out frame_left, out frame_top);
3652 if ((frame_left != 0) && (frame_top != 0) && (new_x != frame_left) && (new_y != frame_top)) {
3653 hwnd.x = new_x;
3654 hwnd.y = new_y;
3655 hwnd.whacky_wm = true;
3658 if (hwnd.opacity != 0xffffffff) {
3659 IntPtr opacity;
3661 opacity = (IntPtr)(Int32)hwnd.opacity;
3662 XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
3664 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
3665 goto ProcessNextMessage;
3666 } else {
3667 hwnd.Reparented = false;
3668 goto ProcessNextMessage;
3671 goto ProcessNextMessage;
3674 case XEventName.ConfigureNotify: {
3675 if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
3676 #if DriverDebugExtra
3677 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);
3678 #endif
3679 // if ((hwnd.x != xevent.ConfigureEvent.x) || (hwnd.y != xevent.ConfigureEvent.y) || (hwnd.width != xevent.ConfigureEvent.width) || (hwnd.height != xevent.ConfigureEvent.height)) {
3680 lock (hwnd.configure_lock) {
3681 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
3682 hwnd.configure_pending = false;
3685 // We need to adjust our client window to track the resize of whole_window
3686 if (hwnd.whole_window != hwnd.client_window)
3687 PerformNCCalc(hwnd);
3688 // }
3690 goto ProcessNextMessage;
3693 case XEventName.FocusIn: {
3694 // We received focus. We use X11 focus only to know if the app window does or does not have focus
3695 // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
3696 // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
3697 // about it having focus again
3698 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
3699 goto ProcessNextMessage;
3702 if (FocusWindow == IntPtr.Zero) {
3703 Control c = Control.FromHandle (hwnd.client_window);
3704 if (c == null)
3705 goto ProcessNextMessage;
3706 Form form = c.FindForm ();
3707 if (form == null)
3708 goto ProcessNextMessage;
3709 if (ActiveWindow != form.Handle) {
3710 ActiveWindow = form.Handle;
3711 SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
3713 goto ProcessNextMessage;
3715 Keyboard.FocusIn(FocusWindow);
3716 SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
3717 goto ProcessNextMessage;
3720 case XEventName.FocusOut: {
3721 // Se the comment for our FocusIn handler
3722 if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
3723 goto ProcessNextMessage;
3725 Keyboard.FocusOut(FocusWindow);
3727 while (Keyboard.ResetKeyState(FocusWindow, ref msg)) {
3728 SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam);
3731 SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
3732 goto ProcessNextMessage;
3735 case XEventName.MapNotify: {
3736 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
3737 hwnd.mapped = true;
3738 msg.message = Msg.WM_SHOWWINDOW;
3739 msg.wParam = (IntPtr) 1;
3740 // XXX we're missing the lParam..
3741 break;
3743 goto ProcessNextMessage;
3746 case XEventName.UnmapNotify: {
3747 if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
3748 hwnd.mapped = false;
3749 msg.message = Msg.WM_SHOWWINDOW;
3750 msg.wParam = (IntPtr) 0;
3751 // XXX we're missing the lParam..
3752 break;
3754 goto ProcessNextMessage;
3757 case XEventName.Expose: {
3758 if (!hwnd.Mapped) {
3759 if (client) {
3760 hwnd.expose_pending = false;
3761 } else {
3762 hwnd.nc_expose_pending = false;
3764 goto ProcessNextMessage;
3767 if (client) {
3768 if (!hwnd.expose_pending) {
3769 goto ProcessNextMessage;
3771 } else {
3772 if (!hwnd.nc_expose_pending) {
3773 goto ProcessNextMessage;
3776 switch (hwnd.border_style) {
3777 case FormBorderStyle.Fixed3D: {
3778 Graphics g;
3780 g = Graphics.FromHwnd(hwnd.whole_window);
3781 if (hwnd.border_static)
3782 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter);
3783 else
3784 ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken);
3785 g.Dispose();
3786 break;
3789 case FormBorderStyle.FixedSingle: {
3790 Graphics g;
3792 g = Graphics.FromHwnd(hwnd.whole_window);
3793 ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid);
3794 g.Dispose();
3795 break;
3798 #if DriverDebugExtra
3799 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);
3800 #endif
3802 Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height);
3803 Region region = new Region (rect);
3804 IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
3805 msg.message = Msg.WM_NCPAINT;
3806 msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
3807 msg.refobject = region;
3808 break;
3810 #if DriverDebugExtra
3811 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);
3812 #endif
3813 if (Caret.Visible == true) {
3814 Caret.Paused = true;
3815 HideCaret();
3818 if (Caret.Visible == true) {
3819 ShowCaret();
3820 Caret.Paused = false;
3822 msg.message = Msg.WM_PAINT;
3823 break;
3826 case XEventName.DestroyNotify: {
3828 // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
3829 hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
3831 // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
3832 if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) {
3833 CleanupCachedWindows (hwnd);
3835 #if DriverDebugDestroy
3836 Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window));
3837 #endif
3839 msg.hwnd = hwnd.client_window;
3840 msg.message=Msg.WM_DESTROY;
3841 hwnd.Dispose();
3842 } else {
3843 goto ProcessNextMessage;
3846 break;
3849 case XEventName.ClientMessage: {
3850 if (Dnd.HandleClientMessage (ref xevent)) {
3851 goto ProcessNextMessage;
3854 if (xevent.ClientMessageEvent.message_type == AsyncAtom) {
3855 XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
3856 goto ProcessNextMessage;
3859 if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
3860 msg.message = Msg.WM_MOUSEHOVER;
3861 msg.wParam = GetMousewParam(0);
3862 msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
3863 return true;
3866 if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) {
3867 msg.hwnd = xevent.ClientMessageEvent.ptr1;
3868 msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
3869 msg.wParam = xevent.ClientMessageEvent.ptr3;
3870 msg.lParam = xevent.ClientMessageEvent.ptr4;
3871 if (msg.message == (Msg)Msg.WM_QUIT)
3872 return false;
3873 else
3874 return true;
3877 if (xevent.ClientMessageEvent.message_type == _XEMBED) {
3878 #if DriverDebugXEmbed
3879 Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
3880 #endif
3882 if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
3883 XSizeHints hints = new XSizeHints();
3884 IntPtr dummy;
3886 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
3888 hwnd.width = hints.max_width;
3889 hwnd.height = hints.max_height;
3890 hwnd.ClientRect = Rectangle.Empty;
3891 SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
3895 if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) {
3896 if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) {
3897 msg.message = Msg.WM_CLOSE;
3898 return true;
3901 // We should not get this, but I'll leave the code in case we need it in the future
3902 if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) {
3903 goto ProcessNextMessage;
3906 goto ProcessNextMessage;
3909 default: {
3910 goto ProcessNextMessage;
3914 return true;
3917 internal override bool GetText(IntPtr handle, out string text) {
3919 lock (XlibLock) {
3920 IntPtr actual_atom;
3921 int actual_format;
3922 IntPtr nitems;
3923 IntPtr bytes_after;
3924 IntPtr prop = IntPtr.Zero;
3926 XGetWindowProperty(DisplayHandle, handle,
3927 _NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false,
3928 UNICODETEXT, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
3930 if ((long)nitems > 0 && prop != IntPtr.Zero) {
3931 text = Marshal.PtrToStringUni (prop, (int)nitems);
3932 XFree (prop);
3933 return true;
3935 else {
3936 // fallback on the non-_NET property
3937 IntPtr textptr;
3939 textptr = IntPtr.Zero;
3941 XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr);
3942 if (textptr != IntPtr.Zero) {
3943 text = Marshal.PtrToStringAnsi(textptr);
3944 XFree(textptr);
3945 return true;
3946 } else {
3947 text = "";
3948 return false;
3954 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) {
3955 Hwnd hwnd;
3957 hwnd = Hwnd.ObjectFromHandle(handle);
3959 if (hwnd != null) {
3960 x = hwnd.x;
3961 y = hwnd.y;
3962 width = hwnd.width;
3963 height = hwnd.height;
3965 PerformNCCalc(hwnd);
3967 client_width = hwnd.ClientRect.Width;
3968 client_height = hwnd.ClientRect.Height;
3970 return;
3973 // Should we throw an exception or fail silently?
3974 // throw new ArgumentException("Called with an invalid window handle", "handle");
3976 x = 0;
3977 y = 0;
3978 width = 0;
3979 height = 0;
3980 client_width = 0;
3981 client_height = 0;
3984 internal override FormWindowState GetWindowState(IntPtr handle) {
3985 IntPtr actual_atom;
3986 int actual_format;
3987 IntPtr nitems;
3988 IntPtr bytes_after;
3989 IntPtr prop = IntPtr.Zero;
3990 IntPtr atom;
3991 int maximized;
3992 bool minimized;
3993 XWindowAttributes attributes;
3994 Hwnd hwnd;
3996 hwnd = Hwnd.ObjectFromHandle(handle);
3998 maximized = 0;
3999 minimized = false;
4000 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);
4001 if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
4002 for (int i = 0; i < (long)nitems; i++) {
4003 atom = (IntPtr)Marshal.ReadInt32(prop, i * 4);
4004 if ((atom == _NET_WM_STATE_MAXIMIZED_HORZ) || (atom == _NET_WM_STATE_MAXIMIZED_VERT)) {
4005 maximized++;
4006 } else if (atom == _NET_WM_STATE_HIDDEN) {
4007 minimized = true;
4010 XFree(prop);
4013 if (minimized) {
4014 return FormWindowState.Minimized;
4015 } else if (maximized == 2) {
4016 return FormWindowState.Maximized;
4019 attributes = new XWindowAttributes();
4020 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4021 if (attributes.map_state == MapState.IsUnmapped) {
4022 return (FormWindowState)(-1);
4026 return FormWindowState.Normal;
4029 internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) {
4030 handle = Grab.Hwnd;
4031 GrabConfined = Grab.Confined;
4032 GrabArea = Grab.Area;
4035 internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) {
4036 Hwnd hwnd;
4037 IntPtr confine_to_window;
4039 confine_to_window = IntPtr.Zero;
4041 if (confine_to_handle != IntPtr.Zero) {
4042 XWindowAttributes attributes = new XWindowAttributes();
4044 hwnd = Hwnd.ObjectFromHandle(confine_to_handle);
4046 lock (XlibLock) {
4047 XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes);
4049 Grab.Area.X = attributes.x;
4050 Grab.Area.Y = attributes.y;
4051 Grab.Area.Width = attributes.width;
4052 Grab.Area.Height = attributes.height;
4053 Grab.Confined = true;
4054 confine_to_window = hwnd.client_window;
4057 Grab.Hwnd = handle;
4059 hwnd = Hwnd.ObjectFromHandle(handle);
4061 lock (XlibLock) {
4062 XGrabPointer(DisplayHandle, hwnd.client_window, false,
4063 EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
4064 EventMask.ButtonReleaseMask | EventMask.PointerMotionMask |
4065 EventMask.LeaveWindowMask,
4066 GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
4070 internal override void UngrabWindow(IntPtr hwnd) {
4071 lock (XlibLock) {
4072 XUngrabPointer(DisplayHandle, IntPtr.Zero);
4073 XFlush(DisplayHandle);
4075 WindowUngrabbed (hwnd);
4078 private void WindowUngrabbed (IntPtr hwnd) {
4079 bool was_grabbed = Grab.Hwnd != IntPtr.Zero;
4081 Grab.Hwnd = IntPtr.Zero;
4082 Grab.Confined = false;
4084 if (was_grabbed) {
4085 // lparam should be the handle to the window gaining the mouse capture,
4086 // but X doesn't seem to give us that information.
4087 // Also only generate WM_CAPTURECHANGED if the window actually was grabbed.
4088 // X will send a NotifyUngrab, but since it comes late sometimes we're
4089 // calling WindowUngrabbed directly from UngrabWindow in order to send
4090 // this WM right away.
4091 SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero);
4095 internal override void HandleException(Exception e) {
4096 StackTrace st = new StackTrace(e, true);
4097 Console.WriteLine("Exception '{0}'", e.Message+st.ToString());
4098 Console.WriteLine("{0}{1}", e.Message, st.ToString());
4101 internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) {
4102 Hwnd hwnd;
4104 hwnd = Hwnd.ObjectFromHandle(handle);
4106 if (clear) {
4107 AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height);
4108 } else {
4109 AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height);
4113 internal override void InvalidateNC (IntPtr handle) {
4114 Hwnd hwnd;
4116 hwnd = Hwnd.ObjectFromHandle(handle);
4118 AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
4121 internal override bool IsEnabled(IntPtr handle) {
4122 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4123 return (hwnd != null && hwnd.Enabled);
4126 internal override bool IsVisible(IntPtr handle) {
4127 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4128 return (hwnd != null && hwnd.visible);
4131 internal override void KillTimer(Timer timer) {
4132 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
4134 if (queue == null) {
4135 // This isn't really an error, MS doesn't start the timer if
4136 // it has no assosciated queue
4137 return;
4139 queue.timer_list.Remove (timer);
4142 internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) {
4143 int dest_x_return;
4144 int dest_y_return;
4145 IntPtr child;
4146 Hwnd hwnd;
4148 hwnd = Hwnd.ObjectFromHandle(handle);
4150 lock (XlibLock) {
4151 XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child);
4154 x = dest_x_return;
4155 y = dest_y_return;
4158 internal override void OverrideCursor(IntPtr cursor)
4160 if (Grab.Hwnd != IntPtr.Zero) {
4161 XChangeActivePointerGrab (DisplayHandle,
4162 EventMask.ButtonMotionMask |
4163 EventMask.PointerMotionMask |
4164 EventMask.ButtonPressMask |
4165 EventMask.ButtonReleaseMask,
4166 cursor, IntPtr.Zero);
4167 return;
4170 OverrideCursorHandle = cursor;
4173 internal override PaintEventArgs PaintEventStart(IntPtr handle, bool client) {
4174 PaintEventArgs paint_event;
4175 Hwnd hwnd;
4177 hwnd = Hwnd.ObjectFromHandle(handle);
4179 if (Caret.Visible == true) {
4180 Caret.Paused = true;
4181 HideCaret();
4184 Graphics dc;
4186 if (client) {
4187 dc = Graphics.FromHwnd (hwnd.client_window);
4189 Region clip_region = new Region ();
4190 clip_region.MakeEmpty();
4192 foreach (Rectangle r in hwnd.ClipRectangles) {
4193 clip_region.Union (r);
4196 if (hwnd.UserClip != null) {
4197 clip_region.Intersect(hwnd.UserClip);
4200 dc.Clip = clip_region;
4201 paint_event = new PaintEventArgs(dc, hwnd.Invalid);
4202 hwnd.expose_pending = false;
4204 hwnd.ClearInvalidArea();
4206 hwnd.drawing_stack.Push (paint_event);
4207 hwnd.drawing_stack.Push (dc);
4209 return paint_event;
4210 } else {
4211 dc = Graphics.FromHwnd (hwnd.whole_window);
4213 if (!hwnd.nc_invalid.IsEmpty) {
4214 dc.SetClip (hwnd.nc_invalid);
4215 paint_event = new PaintEventArgs(dc, hwnd.nc_invalid);
4216 } else {
4217 paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height));
4219 hwnd.nc_expose_pending = false;
4221 hwnd.ClearNcInvalidArea ();
4223 hwnd.drawing_stack.Push (paint_event);
4224 hwnd.drawing_stack.Push (dc);
4226 return paint_event;
4230 internal override void PaintEventEnd(IntPtr handle, bool client) {
4231 Hwnd hwnd;
4233 hwnd = Hwnd.ObjectFromHandle(handle);
4235 Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
4236 dc.Flush();
4237 dc.Dispose();
4239 PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop();
4240 pe.SetGraphics (null);
4241 pe.Dispose ();
4243 if (Caret.Visible == true) {
4244 ShowCaret();
4245 Caret.Paused = false;
4249 [MonoTODO("Implement filtering and PM_NOREMOVE")]
4250 internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) {
4251 XEventQueue queue = (XEventQueue) queue_id;
4252 bool pending;
4254 if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
4255 throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
4258 pending = false;
4259 if (queue.Count > 0) {
4260 pending = true;
4261 } else {
4262 // Only call UpdateMessageQueue if real events are pending
4263 // otherwise we go to sleep on the socket
4264 if (XPending(DisplayHandle) != 0) {
4265 UpdateMessageQueue((XEventQueue)queue_id);
4266 pending = true;
4267 } else if (((XEventQueue)queue_id).Paint.Count > 0) {
4268 pending = true;
4272 CheckTimers(queue.timer_list, DateTime.UtcNow);
4274 if (!pending) {
4275 return false;
4277 return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
4280 internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) {
4281 XEvent xevent = new XEvent ();
4282 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
4284 xevent.type = XEventName.ClientMessage;
4285 xevent.ClientMessageEvent.display = DisplayHandle;
4287 if (hwnd != null) {
4288 xevent.ClientMessageEvent.window = hwnd.whole_window;
4289 } else {
4290 xevent.ClientMessageEvent.window = IntPtr.Zero;
4293 xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom;
4294 xevent.ClientMessageEvent.format = 32;
4295 xevent.ClientMessageEvent.ptr1 = handle;
4296 xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
4297 xevent.ClientMessageEvent.ptr3 = wparam;
4298 xevent.ClientMessageEvent.ptr4 = lparam;
4300 hwnd.Queue.EnqueueLocked (xevent);
4302 return true;
4305 internal override void PostQuitMessage(int exitCode) {
4306 PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
4307 XFlush(DisplayHandle);
4310 internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave)
4312 // TODO
4315 internal override void RequestNCRecalc(IntPtr handle) {
4316 Hwnd hwnd;
4318 hwnd = Hwnd.ObjectFromHandle(handle);
4320 if (hwnd == null) {
4321 return;
4324 PerformNCCalc(hwnd);
4325 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4326 InvalidateNC(handle);
4329 internal override void ResetMouseHover(IntPtr handle) {
4330 Hwnd hwnd;
4332 hwnd = Hwnd.ObjectFromHandle(handle);
4333 if (hwnd == null) {
4334 return;
4337 HoverState.Timer.Enabled = true;
4338 HoverState.X = mouse_position.X;
4339 HoverState.Y = mouse_position.Y;
4340 HoverState.Window = handle;
4344 internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) {
4345 int dest_x_return;
4346 int dest_y_return;
4347 IntPtr child;
4348 Hwnd hwnd;
4350 hwnd = Hwnd.ObjectFromHandle(handle);
4352 lock (XlibLock) {
4353 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child);
4356 x = dest_x_return;
4357 y = dest_y_return;
4360 internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) {
4361 int dest_x_return;
4362 int dest_y_return;
4363 IntPtr child;
4364 Hwnd hwnd;
4366 hwnd = Hwnd.ObjectFromHandle(handle);
4368 lock (XlibLock) {
4369 XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
4372 x = dest_x_return;
4373 y = dest_y_return;
4376 internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
4377 Hwnd hwnd;
4378 IntPtr gc;
4379 XGCValues gc_values;
4381 hwnd = Hwnd.ObjectFromHandle(handle);
4383 Rectangle r = Rectangle.Intersect (hwnd.Invalid, area);
4384 if (!r.IsEmpty) {
4385 /* We have an invalid area in the window we're scrolling.
4386 Adjust our stored invalid rectangle to to match the scrolled amount */
4388 r.X += XAmount;
4389 r.Y += YAmount;
4391 if (r.X < 0) {
4392 r.Width += r.X;
4393 r.X =0;
4396 if (r.Y < 0) {
4397 r.Height += r.Y;
4398 r.Y =0;
4401 if (area.Contains (hwnd.Invalid))
4402 hwnd.ClearInvalidArea ();
4403 hwnd.AddInvalidArea(r);
4406 gc_values = new XGCValues();
4408 if (with_children) {
4409 gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
4412 gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
4414 int src_x, src_y;
4415 int dest_x, dest_y;
4416 int width, height;
4418 if (YAmount > 0) {
4419 src_y = area.Y;
4420 height = area.Height - YAmount;
4421 dest_y = area.Y + YAmount;
4423 else {
4424 src_y = area.Y - YAmount;
4425 height = area.Height + YAmount;
4426 dest_y = area.Y;
4429 if (XAmount > 0) {
4430 src_x = area.X;
4431 width = area.Width - XAmount;
4432 dest_x = area.X + XAmount;
4434 else {
4435 src_x = area.X - XAmount;
4436 width = area.Width + XAmount;
4437 dest_x = area.X;
4440 XCopyArea(DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src_x, src_y, width, height, dest_x, dest_y);
4442 // Generate an expose for the area exposed by the horizontal scroll
4443 // We don't use AddExpose since we're
4444 if (XAmount > 0) {
4445 AddExpose(hwnd, true, area.X, area.Y, XAmount, area.Height);
4446 } else if (XAmount < 0) {
4447 AddExpose(hwnd, true, XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
4450 // Generate an expose for the area exposed by the vertical scroll
4451 if (YAmount > 0) {
4452 AddExpose(hwnd, true, area.X, area.Y, area.Width, YAmount);
4453 } else if (YAmount < 0) {
4454 AddExpose(hwnd, true, area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
4456 XFreeGC(DisplayHandle, gc);
4459 internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) {
4460 Hwnd hwnd;
4461 Rectangle rect;
4463 hwnd = Hwnd.GetObjectFromWindow(handle);
4465 rect = hwnd.ClientRect;
4466 rect.X = 0;
4467 rect.Y = 0;
4468 ScrollWindow(handle, rect, XAmount, YAmount, with_children);
4471 internal override void SendAsyncMethod (AsyncMethodData method) {
4472 Hwnd hwnd;
4473 XEvent xevent = new XEvent ();
4475 hwnd = Hwnd.ObjectFromHandle(method.Handle);
4477 xevent.type = XEventName.ClientMessage;
4478 xevent.ClientMessageEvent.display = DisplayHandle;
4479 xevent.ClientMessageEvent.window = method.Handle;
4480 xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom;
4481 xevent.ClientMessageEvent.format = 32;
4482 xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
4484 hwnd.Queue.EnqueueLocked (xevent);
4486 WakeupMain ();
4489 delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
4491 internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam)
4493 Hwnd h;
4494 h = Hwnd.ObjectFromHandle(hwnd);
4496 if (h != null && h.queue != ThreadQueue (Thread.CurrentThread)) {
4497 AsyncMethodResult result;
4498 AsyncMethodData data;
4500 result = new AsyncMethodResult ();
4501 data = new AsyncMethodData ();
4503 data.Handle = hwnd;
4504 data.Method = new WndProcDelegate (NativeWindow.WndProc);
4505 data.Args = new object[] { hwnd, message, wParam, lParam };
4506 data.Result = result;
4508 SendAsyncMethod (data);
4509 #if DriverDebug || DriverDebugThreads
4510 Console.WriteLine ("Sending {0} message across.", message);
4511 #endif
4513 return IntPtr.Zero;
4515 return NativeWindow.WndProc(hwnd, message, wParam, lParam);
4518 internal override int SendInput(IntPtr handle, Queue keys) {
4519 if (handle == IntPtr.Zero)
4520 return 0;
4522 int count = keys.Count;
4523 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
4525 while (keys.Count > 0) {
4527 MSG msg = (MSG)keys.Dequeue();
4529 XEvent xevent = new XEvent ();
4531 xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
4532 xevent.KeyEvent.display = DisplayHandle;
4534 if (hwnd != null) {
4535 xevent.KeyEvent.window = hwnd.whole_window;
4536 } else {
4537 xevent.KeyEvent.window = IntPtr.Zero;
4540 xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
4542 hwnd.Queue.EnqueueLocked (xevent);
4544 return count;
4547 internal override void SetAllowDrop (IntPtr handle, bool value)
4549 // We allow drop on all windows
4552 internal override DragDropEffects StartDrag (IntPtr handle, object data,
4553 DragDropEffects allowed_effects)
4555 Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
4557 if (hwnd == null)
4558 throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
4560 return Dnd.StartDrag (hwnd.client_window, data, allowed_effects);
4563 internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
4564 Form form = Control.FromHandle (handle) as Form;
4565 if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow ||
4566 border_style == FormBorderStyle.SizableToolWindow)) {
4567 form.window_manager = new ToolWindowManager (form);
4570 RequestNCRecalc(handle);
4573 internal override void SetCaretPos(IntPtr handle, int x, int y) {
4574 if (Caret.Hwnd == handle) {
4575 Caret.Timer.Stop();
4576 HideCaret();
4578 Caret.X = x;
4579 Caret.Y = y;
4581 if (Caret.Visible == true) {
4582 ShowCaret();
4583 Caret.Timer.Start();
4588 internal override void SetClipRegion(IntPtr handle, Region region) {
4589 Hwnd hwnd;
4591 hwnd = Hwnd.ObjectFromHandle(handle);
4592 if (hwnd == null) {
4593 return;
4596 hwnd.UserClip = region;
4597 Invalidate(handle, new Rectangle(0, 0, hwnd.Width, hwnd.Height), false);
4600 internal override void SetCursor(IntPtr handle, IntPtr cursor) {
4601 Hwnd hwnd;
4603 if (OverrideCursorHandle == IntPtr.Zero) {
4604 if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) {
4605 return;
4608 LastCursorHandle = cursor;
4609 LastCursorWindow = handle;
4611 hwnd = Hwnd.ObjectFromHandle(handle);
4612 lock (XlibLock) {
4613 if (cursor != IntPtr.Zero) {
4614 XDefineCursor(DisplayHandle, hwnd.whole_window, cursor);
4615 } else {
4616 XUndefineCursor(DisplayHandle, hwnd.whole_window);
4618 XFlush(DisplayHandle);
4620 return;
4623 hwnd = Hwnd.ObjectFromHandle(handle);
4624 lock (XlibLock) {
4625 XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle);
4629 private void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child,
4630 out int root_x, out int root_y, out int child_x, out int child_y,
4631 out int mask)
4633 /* this code was written with the help of
4634 glance at gdk. I never would have realized we
4635 needed a loop in order to traverse down in the
4636 hierarchy. I would have assumed you'd get the
4637 most deeply nested child and have to do
4638 XQueryTree to move back up the hierarchy..
4639 stupid me, of course. */
4640 IntPtr c;
4642 XGrabServer (display);
4644 XQueryPointer(display, w, out root, out c,
4645 out root_x, out root_y, out child_x, out child_y,
4646 out mask);
4648 if (root != w)
4649 c = root;
4651 IntPtr child_last = IntPtr.Zero;
4652 while (c != IntPtr.Zero) {
4653 child_last = c;
4654 XQueryPointer(display, c, out root, out c,
4655 out root_x, out root_y, out child_x, out child_y,
4656 out mask);
4658 XUngrabServer (display);
4659 XFlush (display);
4661 child = child_last;
4664 internal override void SetCursorPos(IntPtr handle, int x, int y) {
4665 if (handle == IntPtr.Zero) {
4666 lock (XlibLock) {
4667 IntPtr root, child;
4668 int root_x, root_y, child_x, child_y, mask;
4670 /* we need to do a
4671 * QueryPointer before warping
4672 * because if the warp is on
4673 * the RootWindow, the x/y are
4674 * relative to the current
4675 * mouse position
4677 QueryPointer (DisplayHandle, RootWindow,
4678 out root,
4679 out child,
4680 out root_x, out root_y,
4681 out child_x, out child_y,
4682 out mask);
4684 XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
4686 XFlush (DisplayHandle);
4688 /* then we need to a
4689 * QueryPointer after warping
4690 * to manually generate a
4691 * motion event for the window
4692 * we move into.
4694 QueryPointer (DisplayHandle, RootWindow,
4695 out root,
4696 out child,
4697 out root_x, out root_y,
4698 out child_x, out child_y,
4699 out mask);
4701 Hwnd child_hwnd = Hwnd.ObjectFromHandle(child);
4702 if (child_hwnd == null) {
4703 return;
4706 XEvent xevent = new XEvent ();
4708 xevent.type = XEventName.MotionNotify;
4709 xevent.MotionEvent.display = DisplayHandle;
4710 xevent.MotionEvent.window = child_hwnd.client_window;
4711 xevent.MotionEvent.root = RootWindow;
4712 xevent.MotionEvent.x = child_x;
4713 xevent.MotionEvent.y = child_y;
4714 xevent.MotionEvent.x_root = root_x;
4715 xevent.MotionEvent.y_root = root_y;
4716 xevent.MotionEvent.state = mask;
4718 child_hwnd.Queue.EnqueueLocked (xevent);
4720 } else {
4721 Hwnd hwnd;
4723 hwnd = Hwnd.ObjectFromHandle(handle);
4724 lock (XlibLock) {
4725 XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y);
4730 internal override void SetFocus(IntPtr handle) {
4731 Hwnd hwnd;
4732 IntPtr prev_focus_window;
4734 hwnd = Hwnd.ObjectFromHandle(handle);
4736 if (hwnd.client_window == FocusWindow) {
4737 return;
4740 prev_focus_window = FocusWindow;
4741 FocusWindow = hwnd.client_window;
4743 if (prev_focus_window != IntPtr.Zero) {
4744 SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
4746 SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
4748 //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
4751 internal override void SetIcon(IntPtr handle, Icon icon) {
4752 Hwnd hwnd;
4754 hwnd = Hwnd.ObjectFromHandle(handle);
4755 if (hwnd != null) {
4756 SetIcon(hwnd, icon);
4760 internal override void SetMenu(IntPtr handle, Menu menu) {
4761 Hwnd hwnd;
4763 hwnd = Hwnd.ObjectFromHandle(handle);
4764 hwnd.menu = menu;
4766 RequestNCRecalc(handle);
4769 internal override void SetModal(IntPtr handle, bool Modal) {
4770 if (Modal) {
4771 ModalWindows.Push(handle);
4772 } else {
4773 if (ModalWindows.Contains(handle)) {
4774 ModalWindows.Pop();
4776 if (ModalWindows.Count > 0) {
4777 Activate((IntPtr)ModalWindows.Peek());
4782 internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
4783 Hwnd hwnd;
4785 hwnd = Hwnd.ObjectFromHandle(handle);
4786 hwnd.parent = Hwnd.ObjectFromHandle(parent);
4788 lock (XlibLock) {
4789 #if DriverDebug || DriverDebugParent
4790 Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(hwnd.Handle), XplatUI.Window(hwnd.parent != null ? hwnd.parent.Handle : IntPtr.Zero));
4791 #endif
4792 XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent == null ? FosterParent : hwnd.parent.client_window, hwnd.x, hwnd.y);
4795 return IntPtr.Zero;
4798 internal override void SetTimer (Timer timer) {
4799 XEventQueue queue = (XEventQueue) MessageQueues [timer.thread];
4801 if (queue == null) {
4802 // This isn't really an error, MS doesn't start the timer if
4803 // it has no assosciated queue
4804 return;
4806 queue.timer_list.Add (timer);
4807 WakeupMain ();
4810 internal override bool SetTopmost(IntPtr handle, IntPtr handle_owner, bool enabled) {
4811 Hwnd hwnd;
4812 Hwnd hwnd_owner;
4814 hwnd = Hwnd.ObjectFromHandle(handle);
4816 if (handle_owner != IntPtr.Zero) {
4817 hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
4818 } else {
4819 hwnd_owner = null;
4822 if (enabled) {
4823 lock (XlibLock) {
4824 int[] atoms;
4826 atoms = new int[8];
4828 atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
4829 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
4831 if (hwnd_owner != null) {
4832 XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window);
4833 } else {
4834 XSetTransientForHint(DisplayHandle, hwnd.whole_window, RootWindow);
4837 } else {
4838 lock (XlibLock) {
4839 XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR);
4842 return true;
4845 internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
4847 Hwnd hwnd;
4849 hwnd = Hwnd.ObjectFromHandle(handle);
4850 hwnd.visible = visible;
4852 lock (XlibLock) {
4853 if (visible) {
4854 MapWindow(hwnd, WindowType.Both);
4856 if (Control.FromHandle(handle) is Form) {
4857 FormWindowState s;
4859 s = ((Form)Control.FromHandle(handle)).WindowState;
4861 switch(s) {
4862 case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break;
4863 case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break;
4867 SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4869 else {
4870 UnmapWindow(hwnd, WindowType.Both);
4873 return true;
4876 internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
4877 Hwnd hwnd;
4878 XSizeHints hints;
4879 IntPtr dummy;
4881 hwnd = Hwnd.ObjectFromHandle(handle);
4882 if (hwnd == null) {
4883 return;
4886 hints = new XSizeHints();
4888 XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy);
4889 if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) {
4890 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
4891 hints.min_width = min.Width;
4892 hints.min_height = min.Height;
4895 if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) {
4896 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
4897 hints.max_width = max.Width;
4898 hints.max_height = max.Height;
4901 if (hints.flags != IntPtr.Zero) {
4902 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints);
4905 if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) {
4906 hints.flags = (IntPtr)XSizeHintsFlags.PPosition;
4907 hints.x = maximized.X;
4908 hints.y = maximized.Y;
4909 hints.width = maximized.Width;
4910 hints.height = maximized.Height;
4912 // Metacity does not seem to follow this constraint for maximized (zoomed) windows
4913 XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints);
4918 internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) {
4919 Hwnd hwnd;
4921 hwnd = Hwnd.ObjectFromHandle(handle);
4923 if (hwnd == null) {
4924 return;
4927 // Win32 automatically changes negative width/height to 0.
4928 if (width < 0)
4929 width = 0;
4930 if (height < 0)
4931 height = 0;
4933 // X requires a sanity check for width & height; otherwise it dies
4934 if (hwnd.zero_sized && width > 0 && height > 0) {
4935 if (hwnd.visible) {
4936 MapWindow(hwnd, WindowType.Whole);
4938 hwnd.zero_sized = false;
4941 if ((width < 1) || (height < 1)) {
4942 hwnd.zero_sized = true;
4943 UnmapWindow(hwnd, WindowType.Whole);
4946 // Save a server roundtrip (and prevent a feedback loop)
4947 if ((hwnd.x == x) && (hwnd.y == y) &&
4948 (hwnd.width == width) && (hwnd.height == height)) {
4949 return;
4952 if (!hwnd.zero_sized) {
4953 //Hack?
4954 hwnd.x = x;
4955 hwnd.y = y;
4956 hwnd.width = width;
4957 hwnd.height = height;
4958 SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
4960 if (hwnd.fixed_size) {
4961 SetWindowMinMax(handle, Rectangle.Empty, new Size(width, height), new Size(width, height));
4964 lock (XlibLock) {
4965 XMoveResizeWindow(DisplayHandle, hwnd.whole_window, x, y, width, height);
4966 PerformNCCalc(hwnd);
4970 // Update our position/size immediately, so
4971 // that future calls to SetWindowPos aren't
4972 // kept from calling XMoveResizeWindow (by the
4973 // "Save a server roundtrip" block above).
4974 hwnd.x = x;
4975 hwnd.y = y;
4976 hwnd.width = width;
4977 hwnd.height = height;
4978 hwnd.ClientRect = Rectangle.Empty;
4981 internal override void SetWindowState(IntPtr handle, FormWindowState state) {
4982 FormWindowState current_state;
4983 Hwnd hwnd;
4985 hwnd = Hwnd.ObjectFromHandle(handle);
4987 current_state = GetWindowState(handle);
4989 if (current_state == state) {
4990 return;
4993 switch(state) {
4994 case FormWindowState.Normal: {
4995 lock (XlibLock) {
4996 if (current_state == FormWindowState.Minimized) {
4997 MapWindow(hwnd, WindowType.Both);
4998 } else if (current_state == FormWindowState.Maximized) {
4999 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5002 Activate(handle);
5003 return;
5006 case FormWindowState.Minimized: {
5007 lock (XlibLock) {
5008 if (current_state == FormWindowState.Maximized) {
5009 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5011 XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo);
5013 return;
5016 case FormWindowState.Maximized: {
5017 lock (XlibLock) {
5018 if (current_state == FormWindowState.Minimized) {
5019 MapWindow(hwnd, WindowType.Both);
5022 SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)1 /* Add */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT);
5024 Activate(handle);
5025 return;
5030 internal override void SetWindowStyle(IntPtr handle, CreateParams cp) {
5031 Hwnd hwnd;
5033 hwnd = Hwnd.ObjectFromHandle(handle);
5034 SetHwndStyles(hwnd, cp);
5035 SetWMStyles(hwnd, cp);
5038 internal override double GetWindowTransparency(IntPtr handle)
5040 return 1.0;
5043 internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) {
5044 Hwnd hwnd;
5045 IntPtr opacity;
5047 hwnd = Hwnd.ObjectFromHandle(handle);
5049 if (hwnd == null) {
5050 return;
5053 hwnd.opacity = (uint)(0xffffffff * transparency);
5054 opacity = (IntPtr)((int)hwnd.opacity);
5056 IntPtr w = hwnd.whole_window;
5057 if (hwnd.reparented)
5058 w = XGetParent (hwnd.whole_window);
5059 XChangeProperty(DisplayHandle, w, _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1);
5062 internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) {
5063 Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
5065 if (!hwnd.mapped) {
5066 return false;
5069 if (top) {
5070 lock (XlibLock) {
5071 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5073 return true;
5074 } else if (!bottom) {
5075 Hwnd after_hwnd = null;
5077 if (after_handle != IntPtr.Zero) {
5078 after_hwnd = Hwnd.ObjectFromHandle(after_handle);
5081 XWindowChanges values = new XWindowChanges();
5083 if (after_hwnd == null) {
5084 // Work around metacity 'issues'
5085 int[] atoms;
5087 atoms = new int[2];
5088 atoms[0] = unixtime();
5089 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_USER_TIME, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, atoms, 1);
5091 XRaiseWindow(DisplayHandle, hwnd.whole_window);
5092 SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
5093 return true;
5094 //throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order");
5097 values.sibling = after_hwnd.whole_window;
5098 values.stack_mode = StackMode.Below;
5100 lock (XlibLock) {
5101 XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values);
5103 } else {
5104 // Bottom
5105 lock (XlibLock) {
5106 XLowerWindow(DisplayHandle, hwnd.whole_window);
5108 return true;
5110 return false;
5113 internal override void ShowCursor(bool show) {
5114 ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
5117 internal override object StartLoop(Thread thread) {
5118 XEventQueue q = ThreadQueue(thread);
5119 return q;
5122 internal override TransparencySupport SupportsTransparency() {
5123 // We need to check if the x compositing manager is running
5124 return TransparencySupport.Set;
5127 internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) {
5128 GetSystrayManagerWindow();
5130 if (SystrayMgrWindow != IntPtr.Zero) {
5131 XSizeHints size_hints;
5132 Hwnd hwnd;
5134 hwnd = Hwnd.ObjectFromHandle(handle);
5135 #if DriverDebug
5136 Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32());
5137 #endif
5139 // Oh boy.
5140 if (hwnd.client_window != hwnd.whole_window) {
5141 XDestroyWindow(DisplayHandle, hwnd.client_window);
5142 hwnd.client_window = hwnd.whole_window;
5144 /* by virtue of the way the tests are ordered when determining if it's PAINT
5145 or NCPAINT, client_window == whole_window will always be PAINT. So, if we're
5146 waiting on an nc_expose, drop it and remove the hwnd from the list (unless
5147 there's a pending expose). */
5148 if (hwnd.nc_expose_pending) {
5149 hwnd.nc_expose_pending = false;
5150 if (!hwnd.expose_pending)
5151 hwnd.Queue.Paint.Remove (hwnd);
5155 size_hints = new XSizeHints();
5157 size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
5159 size_hints.min_width = 24;
5160 size_hints.min_height = 24;
5161 size_hints.max_width = 24;
5162 size_hints.max_height = 24;
5163 size_hints.base_width = 24;
5164 size_hints.base_height = 24;
5166 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints);
5168 int[] atoms = new int[2];
5169 atoms [0] = 1; // Version 1
5170 atoms [1] = 1; // we want to be mapped
5172 // This line cost me 3 days...
5173 XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2);
5175 // Need to pick some reasonable defaults
5176 tt = new ToolTip();
5177 tt.AutomaticDelay = 100;
5178 tt.InitialDelay = 250;
5179 tt.ReshowDelay = 250;
5180 tt.ShowAlways = true;
5182 if ((tip != null) && (tip != string.Empty)) {
5183 tt.SetToolTip(Control.FromHandle(handle), tip);
5184 tt.Active = true;
5185 } else {
5186 tt.Active = false;
5189 SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window);
5191 return true;
5193 tt = null;
5194 return false;
5197 internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) {
5198 Control control;
5200 control = Control.FromHandle(handle);
5201 if (control != null && tt != null) {
5202 tt.SetToolTip(control, tip);
5203 tt.Active = true;
5204 return true;
5205 } else {
5206 return false;
5210 internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
5212 #if GTKSOCKET_SUPPORTS_REPARENTING
5213 Hwnd hwnd;
5215 hwnd = Hwnd.ObjectFromHandle(handle);
5217 /* in the XEMBED spec, it mentions 3 ways for a client window to break the protocol with the embedder.
5218 * 1. The embedder can unmap the window and reparent to the root window (we should probably handle this...)
5219 * 2. The client can reparent its window out of the embedder window.
5220 * 3. The client can destroy its window.
5222 * this call to SetParent is case 2, but in
5223 * the spec it also mentions that gtk doesn't
5224 * support this at present. Looking at HEAD
5225 * gtksocket-x11.c jives with this statement.
5227 * so we can't reparent. we have to destroy.
5229 SetParent(hwnd.whole_window, FosterParent);
5230 #else
5231 Control control = Control.FromHandle(handle);
5232 if (control is NotifyIcon.NotifyIconWindow)
5233 ((NotifyIcon.NotifyIconWindow)control).InternalRecreateHandle ();
5234 #endif
5236 // The caller can now re-dock it later...
5237 if (tt != null) {
5238 tt.Dispose();
5239 tt = null;
5243 internal override bool Text(IntPtr handle, string text) {
5244 Hwnd hwnd;
5246 hwnd = Hwnd.ObjectFromHandle(handle);
5248 lock (XlibLock) {
5249 XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_NAME, UNICODETEXT, 8,
5250 PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text));
5252 // XXX this has problems with UTF8.
5253 // we need to either use the actual
5254 // text if it's latin-1, or convert it
5255 // to compound text if it's in a
5256 // different charset.
5257 XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text);
5259 return true;
5262 internal override bool TranslateMessage(ref MSG msg) {
5263 return Keyboard.TranslateMessage (ref msg);
5266 internal override void UpdateWindow(IntPtr handle) {
5267 Hwnd hwnd;
5269 hwnd = Hwnd.ObjectFromHandle(handle);
5271 if (!hwnd.visible || !hwnd.expose_pending || !hwnd.Mapped) {
5272 return;
5275 SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
5276 hwnd.Queue.Paint.Remove(hwnd);
5279 internal override void CreateOffscreenDrawable (IntPtr handle,
5280 int width, int height,
5281 out object offscreen_drawable)
5283 IntPtr root_out;
5284 int x_out, y_out, width_out, height_out, border_width_out, depth_out;
5286 XGetGeometry (DisplayHandle, handle,
5287 out root_out,
5288 out x_out, out y_out,
5289 out width_out, out height_out,
5290 out border_width_out, out depth_out);
5292 IntPtr pixmap = XCreatePixmap (DisplayHandle, handle, width, height, depth_out);
5294 offscreen_drawable = pixmap;
5298 internal override void DestroyOffscreenDrawable (object offscreen_drawable)
5300 XFreePixmap (DisplayHandle, (IntPtr)offscreen_drawable);
5303 internal override Graphics GetOffscreenGraphics (object offscreen_drawable)
5305 return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
5308 internal override void BlitFromOffscreen (IntPtr dest_handle,
5309 Graphics dest_dc,
5310 object offscreen_drawable,
5311 Graphics offscreen_dc,
5312 Rectangle r)
5314 XGCValues gc_values;
5315 IntPtr gc;
5317 gc_values = new XGCValues();
5319 gc = XCreateGC (DisplayHandle, dest_handle, IntPtr.Zero, ref gc_values);
5321 XCopyArea (DisplayHandle, (IntPtr)offscreen_drawable, dest_handle,
5322 gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
5324 XFreeGC (DisplayHandle, gc);
5327 #endregion // Public Static Methods
5329 #region Events
5330 internal override event EventHandler Idle;
5331 #endregion // Events
5333 #region X11 Imports
5334 [DllImport ("libX11", EntryPoint="XOpenDisplay")]
5335 internal extern static IntPtr XOpenDisplay(IntPtr display);
5336 [DllImport ("libX11", EntryPoint="XCloseDisplay")]
5337 internal extern static int XCloseDisplay(IntPtr display);
5338 [DllImport ("libX11", EntryPoint="XSynchronize")]
5339 internal extern static IntPtr XSynchronize(IntPtr display, bool onoff);
5341 [DllImport ("libX11", EntryPoint="XCreateWindow")]
5342 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);
5343 [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")]
5344 internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background);
5345 [DllImport ("libX11", EntryPoint="XMapWindow")]
5346 internal extern static int XMapWindow(IntPtr display, IntPtr window);
5347 [DllImport ("libX11", EntryPoint="XUnmapWindow")]
5348 internal extern static int XUnmapWindow(IntPtr display, IntPtr window);
5349 [DllImport ("libX11", EntryPoint="XMapSubwindows")]
5350 internal extern static int XMapSubindows(IntPtr display, IntPtr window);
5351 [DllImport ("libX11", EntryPoint="XUnmapSubwindows")]
5352 internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window);
5353 [DllImport ("libX11", EntryPoint="XRootWindow")]
5354 internal extern static IntPtr XRootWindow(IntPtr display, int screen_number);
5355 [DllImport ("libX11", EntryPoint="XNextEvent")]
5356 internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
5357 [DllImport ("libX11")]
5358 internal extern static int XConnectionNumber (IntPtr diplay);
5359 [DllImport ("libX11")]
5360 internal extern static int XPending (IntPtr diplay);
5361 [DllImport ("libX11", EntryPoint="XSelectInput")]
5362 internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask);
5364 [DllImport ("libX11", EntryPoint="XDestroyWindow")]
5365 internal extern static int XDestroyWindow(IntPtr display, IntPtr window);
5367 [DllImport ("libX11", EntryPoint="XReparentWindow")]
5368 internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
5369 [DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
5370 internal extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
5372 [DllImport ("libX11", EntryPoint="XResizeWindow")]
5373 internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
5375 [DllImport ("libX11", EntryPoint="XGetWindowAttributes")]
5376 internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
5378 [DllImport ("libX11", EntryPoint="XFlush")]
5379 internal extern static int XFlush(IntPtr display);
5381 [DllImport ("libX11", EntryPoint="XSetWMName")]
5382 internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop);
5384 [DllImport ("libX11", EntryPoint="XStoreName")]
5385 internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name);
5387 [DllImport ("libX11", EntryPoint="XFetchName")]
5388 internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name);
5390 [DllImport ("libX11", EntryPoint="XSendEvent")]
5391 internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
5393 [DllImport ("libX11", EntryPoint="XQueryTree")]
5394 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);
5396 [DllImport ("libX11", EntryPoint="XFree")]
5397 internal extern static int XFree(IntPtr data);
5399 [DllImport ("libX11", EntryPoint="XRaiseWindow")]
5400 internal extern static int XRaiseWindow(IntPtr display, IntPtr window);
5402 [DllImport ("libX11", EntryPoint="XLowerWindow")]
5403 internal extern static uint XLowerWindow(IntPtr display, IntPtr window);
5405 [DllImport ("libX11", EntryPoint="XConfigureWindow")]
5406 internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values);
5408 [DllImport ("libX11", EntryPoint="XInternAtom")]
5409 internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
5411 [DllImport ("libX11", EntryPoint="XInternAtoms")]
5412 internal extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms);
5414 [DllImport ("libX11", EntryPoint="XSetWMProtocols")]
5415 internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count);
5417 [DllImport ("libX11", EntryPoint="XGrabPointer")]
5418 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);
5420 [DllImport ("libX11", EntryPoint="XUngrabPointer")]
5421 internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp);
5423 [DllImport ("libX11", EntryPoint="XQueryPointer")]
5424 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);
5426 [DllImport ("libX11", EntryPoint="XTranslateCoordinates")]
5427 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);
5429 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5430 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);
5432 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5433 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);
5435 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5436 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);
5438 [DllImport ("libX11", EntryPoint="XGetGeometry")]
5439 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);
5441 [DllImport ("libX11", EntryPoint="XWarpPointer")]
5442 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);
5444 [DllImport ("libX11", EntryPoint="XClearWindow")]
5445 internal extern static int XClearWindow(IntPtr display, IntPtr window);
5447 [DllImport ("libX11", EntryPoint="XClearArea")]
5448 internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures);
5450 // Colormaps
5451 [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")]
5452 internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display);
5454 [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")]
5455 internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen);
5457 [DllImport ("libX11", EntryPoint="XDefaultVisual")]
5458 internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number);
5460 [DllImport ("libX11", EntryPoint="XDefaultDepth")]
5461 internal extern static uint XDefaultDepth(IntPtr display, int screen_number);
5463 [DllImport ("libX11", EntryPoint="XDefaultScreen")]
5464 internal extern static int XDefaultScreen(IntPtr display);
5466 [DllImport ("libX11", EntryPoint="XDefaultColormap")]
5467 internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number);
5469 [DllImport ("libX11", EntryPoint="XLookupColor")]
5470 internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color);
5472 [DllImport ("libX11", EntryPoint="XAllocColor")]
5473 internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def);
5475 [DllImport ("libX11", EntryPoint="XSetTransientForHint")]
5476 internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window);
5478 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5479 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements);
5481 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5482 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements);
5484 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5485 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements);
5487 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5488 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements);
5490 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5491 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements);
5493 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5494 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements);
5496 [DllImport ("libX11", EntryPoint="XChangeProperty")]
5497 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements);
5499 [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)]
5500 internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length);
5502 [DllImport ("libX11", EntryPoint="XDeleteProperty")]
5503 internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
5505 [DllImport ("gdiplus", EntryPoint="GetFontMetrics")]
5506 internal extern static bool GetFontMetrics(IntPtr graphicsObject, IntPtr nativeObject, out int ascent, out int descent);
5508 // Drawing
5509 [DllImport ("libX11", EntryPoint="XCreateGC")]
5510 internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
5512 [DllImport ("libX11", EntryPoint="XFreeGC")]
5513 internal extern static int XFreeGC(IntPtr display, IntPtr gc);
5515 [DllImport ("libX11", EntryPoint="XSetFunction")]
5516 internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function);
5518 [DllImport ("libX11", EntryPoint="XSetLineAttributes")]
5519 internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style);
5521 [DllImport ("libX11", EntryPoint="XDrawLine")]
5522 internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2);
5524 [DllImport ("libX11", EntryPoint="XDrawRectangle")]
5525 internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
5527 [DllImport ("libX11", EntryPoint="XFillRectangle")]
5528 internal extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height);
5530 [DllImport ("libX11", EntryPoint="XSetWindowBackground")]
5531 internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background);
5533 [DllImport ("libX11", EntryPoint="XCopyArea")]
5534 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);
5536 [DllImport ("libX11", EntryPoint="XGetWindowProperty")]
5537 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);
5539 [DllImport ("libX11", EntryPoint="XSetInputFocus")]
5540 internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time);
5542 [DllImport ("libX11", EntryPoint="XIconifyWindow")]
5543 internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number);
5545 [DllImport ("libX11", EntryPoint="XDefineCursor")]
5546 internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
5548 [DllImport ("libX11", EntryPoint="XUndefineCursor")]
5549 internal extern static int XUndefineCursor(IntPtr display, IntPtr window);
5551 [DllImport ("libX11", EntryPoint="XFreeCursor")]
5552 internal extern static int XFreeCursor(IntPtr display, IntPtr cursor);
5554 [DllImport ("libX11", EntryPoint="XCreateFontCursor")]
5555 internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape);
5557 [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")]
5558 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);
5560 [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")]
5561 internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth);
5563 [DllImport ("libX11", EntryPoint="XCreatePixmap")]
5564 internal extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth);
5566 [DllImport ("libX11", EntryPoint="XFreePixmap")]
5567 internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap);
5569 [DllImport ("libX11", EntryPoint="XQueryBestCursor")]
5570 internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
5572 [DllImport ("libX11", EntryPoint="XWhitePixel")]
5573 internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
5575 [DllImport ("libX11", EntryPoint="XBlackPixel")]
5576 internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no);
5578 [DllImport ("libX11", EntryPoint="XGrabServer")]
5579 internal extern static void XGrabServer(IntPtr display);
5581 [DllImport ("libX11", EntryPoint="XUngrabServer")]
5582 internal extern static void XUngrabServer(IntPtr display);
5584 [DllImport ("libX11", EntryPoint="XGetWMNormalHints")]
5585 internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
5587 [DllImport ("libX11", EntryPoint="XSetWMNormalHints")]
5588 internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
5590 [DllImport ("libX11", EntryPoint="XSetZoomHints")]
5591 internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
5593 [DllImport ("libX11", EntryPoint="XSetWMHints")]
5594 internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints);
5596 [DllImport ("libX11", EntryPoint="XGetIconSizes")]
5597 internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count);
5599 [DllImport ("libX11", EntryPoint="XSetErrorHandler")]
5600 internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler);
5602 [DllImport ("libX11", EntryPoint="XGetErrorText")]
5603 internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length);
5605 [DllImport ("libX11", EntryPoint="XInitThreads")]
5606 internal extern static int XInitThreads();
5608 [DllImport ("libX11", EntryPoint="XConvertSelection")]
5609 internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time);
5611 [DllImport ("libX11", EntryPoint="XGetSelectionOwner")]
5612 internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection);
5614 [DllImport ("libX11", EntryPoint="XSetSelectionOwner")]
5615 internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time);
5617 [DllImport ("libX11", EntryPoint="XSetPlaneMask")]
5618 internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask);
5620 [DllImport ("libX11", EntryPoint="XSetForeground")]
5621 internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground);
5623 [DllImport ("libX11", EntryPoint="XSetBackground")]
5624 internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background);
5626 [DllImport ("libX11", EntryPoint="XBell")]
5627 internal extern static int XBell(IntPtr display, int percent);
5629 [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")]
5630 internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time);
5632 [DllImport ("libX11", EntryPoint="XFilterEvent")]
5633 internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
5635 [DllImport ("libX11")]
5636 internal extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported);
5638 [DllImport ("libX11")]
5639 internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
5640 #endregion