PageRenderTime 55ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/Managed.Windows.Forms/System.Windows.Forms.X11Internal/X11Display.cs

https://bitbucket.org/danipen/mono
C# | 2710 lines | 1994 code | 525 blank | 191 comment | 424 complexity | fcb6fc812e50ee5e684ec41fdd689f1c MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. // a copy of this software and associated documentation files (the
  2. // "Software"), to deal in the Software without restriction, including
  3. // without limitation the rights to use, copy, modify, merge, publish,
  4. // distribute, sublicense, and/or sell copies of the Software, and to
  5. // permit persons to whom the Software is furnished to do so, subject to
  6. // the following conditions:
  7. //
  8. // The above copyright notice and this permission notice shall be
  9. // included in all copies or substantial portions of the Software.
  10. //
  11. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  12. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  13. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  14. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  15. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  16. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  17. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. //
  19. // Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
  20. //
  21. //
  22. using System;
  23. using System.Collections;
  24. using System.Diagnostics;
  25. using System.Drawing;
  26. using System.Drawing.Drawing2D;
  27. using System.Drawing.Imaging;
  28. using System.IO;
  29. using System.Net;
  30. using System.Net.Sockets;
  31. using System.Reflection;
  32. using System.Runtime.InteropServices;
  33. using System.Text;
  34. using System.Threading;
  35. using System.Windows.Forms;
  36. // Only do the poll when building with mono for now
  37. #if __MonoCS__
  38. using Mono.Unix.Native;
  39. #endif
  40. namespace System.Windows.Forms.X11Internal {
  41. internal class X11Display {
  42. IntPtr display; /* our X handle */
  43. // XXX internal because X11Hwnd needs them
  44. internal IntPtr CustomVisual; // Visual for window creation
  45. internal IntPtr CustomColormap; // Colormap for window creation
  46. X11Keyboard Keyboard;
  47. internal X11Dnd Dnd; // XXX X11Hwnd needs it to enable Dnd
  48. bool detectable_key_auto_repeat;
  49. X11Atoms atoms;
  50. X11RootHwnd root_hwnd;
  51. X11Hwnd foster_hwnd;
  52. // Clipboard
  53. IntPtr ClipMagic;
  54. ClipboardStruct Clipboard; // Our clipboard
  55. // Focus tracking
  56. internal X11Hwnd ActiveWindow;
  57. X11Hwnd FocusWindow;
  58. // Modality support
  59. Stack ModalWindows; // Stack of our modal windows
  60. // Caret
  61. CaretStruct Caret;
  62. // mouse hover message generation
  63. // XXX internal because X11Atoms needs to access it..
  64. internal HoverStruct HoverState;
  65. // double click message generation
  66. ClickStruct ClickPending;
  67. int DoubleClickInterval; // msec; max interval between clicks to count as double click
  68. // Support for mouse grab
  69. GrabStruct Grab;
  70. // Cursors
  71. IntPtr LastCursorWindow; // The last window we set the cursor on
  72. IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow
  73. IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors
  74. // State
  75. Point MousePosition; // Last position of mouse, in screen coords
  76. MouseButtons MouseState; // Last state of mouse buttons
  77. XErrorHandler ErrorHandler; // Error handler delegate
  78. bool ErrorExceptions; // Throw exceptions on X errors
  79. Thread event_thread; // the background thread that just watches our X socket
  80. #if __MonoCS__
  81. Pollfd[] pollfds;
  82. #endif
  83. public X11Display (IntPtr display)
  84. {
  85. if (display == IntPtr.Zero) {
  86. throw new ArgumentNullException("Display",
  87. "Could not open display (X-Server required. Check you DISPLAY environment variable)");
  88. }
  89. this.display = display;
  90. // Debugging support
  91. if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
  92. Xlib.XSynchronize (display, true);
  93. }
  94. if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) {
  95. ErrorExceptions = true;
  96. }
  97. atoms = new X11Atoms (this);
  98. DoubleClickInterval = 500;
  99. HoverState.Interval = 500;
  100. HoverState.Timer = new Timer();
  101. HoverState.Timer.Enabled = false;
  102. HoverState.Timer.Interval = HoverState.Interval;
  103. HoverState.Timer.Tick += new EventHandler(MouseHover);
  104. HoverState.Size = new Size(4, 4);
  105. HoverState.X = -1;
  106. HoverState.Y = -1;
  107. ActiveWindow = null;
  108. FocusWindow = null;
  109. ModalWindows = new Stack(3);
  110. MouseState = MouseButtons.None;
  111. MousePosition = new Point(0, 0);
  112. Caret.Timer = new Timer();
  113. Caret.Timer.Interval = 500; // FIXME - where should this number come from?
  114. Caret.Timer.Tick += new EventHandler(CaretCallback);
  115. // XXX multiscreen work here
  116. root_hwnd = new X11RootHwnd (this, Xlib.XRootWindow (display, DefaultScreen));
  117. // XXX do we need a per-screen foster parent?
  118. // Create the foster parent
  119. foster_hwnd = new X11Hwnd (this,
  120. Xlib.XCreateSimpleWindow (display, root_hwnd.WholeWindow,
  121. 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero));
  122. #if __MonoCS__
  123. pollfds = new Pollfd [1];
  124. pollfds [0] = new Pollfd ();
  125. pollfds [0].fd = Xlib.XConnectionNumber (display);
  126. pollfds [0].events = PollEvents.POLLIN;
  127. #endif
  128. Keyboard = new X11Keyboard(display, foster_hwnd.Handle);
  129. Dnd = new X11Dnd (display, Keyboard);
  130. ErrorExceptions = false;
  131. // Handle any upcoming errors
  132. ErrorHandler = new XErrorHandler (HandleError);
  133. Xlib.XSetErrorHandler (ErrorHandler);
  134. X11DesktopColors.Initialize(); // XXX we need to figure out how to make this display specific?
  135. // Disable keyboard autorepeat
  136. try {
  137. Xlib.XkbSetDetectableAutoRepeat (display, true, IntPtr.Zero);
  138. detectable_key_auto_repeat = true;
  139. } catch {
  140. Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually.");
  141. detectable_key_auto_repeat = false;
  142. }
  143. // we re-set our error handler here, X11DesktopColor stuff might have stolen it (gtk does)
  144. Xlib.XSetErrorHandler (ErrorHandler);
  145. // create our event thread (just sits on the X socket waiting for events)
  146. event_thread = new Thread (new ThreadStart (XEventThread));
  147. event_thread.IsBackground = true;
  148. event_thread.Start ();
  149. }
  150. #region Callbacks
  151. private void MouseHover(object sender, EventArgs e)
  152. {
  153. HoverState.Timer.Enabled = false;
  154. if (HoverState.Window != IntPtr.Zero) {
  155. X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (HoverState.Window);
  156. if (hwnd != null) {
  157. XEvent xevent = new XEvent ();
  158. xevent.type = XEventName.ClientMessage;
  159. xevent.ClientMessageEvent.display = display;
  160. xevent.ClientMessageEvent.window = HoverState.Window;
  161. xevent.ClientMessageEvent.message_type = HoverState.Atom;
  162. xevent.ClientMessageEvent.format = 32;
  163. xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X);
  164. hwnd.Queue.Enqueue (xevent);
  165. }
  166. }
  167. }
  168. private void CaretCallback (object sender, EventArgs e)
  169. {
  170. if (Caret.Paused) {
  171. return;
  172. }
  173. Caret.On = !Caret.On;
  174. Xlib.XDrawLine (display, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
  175. }
  176. internal string WhereString ()
  177. {
  178. StackTrace stack;
  179. StackFrame frame;
  180. string newline;
  181. string unknown;
  182. StringBuilder sb;
  183. MethodBase method;
  184. newline = String.Format("{0}\t {1} ", Environment.NewLine, Locale.GetText("at"));
  185. unknown = Locale.GetText("<unknown method>");
  186. sb = new StringBuilder();
  187. stack = new StackTrace(true);
  188. for (int i = 0; i < stack.FrameCount; i++) {
  189. frame = stack.GetFrame (i);
  190. sb.Append(newline);
  191. method = frame.GetMethod();
  192. if (method != null) {
  193. if (frame.GetFileLineNumber() != 0)
  194. sb.AppendFormat ("{0}.{1} () [{2}:{3}]",
  195. method.DeclaringType.FullName, method.Name,
  196. Path.GetFileName(frame.GetFileName()), frame.GetFileLineNumber());
  197. else
  198. sb.AppendFormat ("{0}.{1} ()", method.DeclaringType.FullName, method.Name);
  199. } else {
  200. sb.Append(unknown);
  201. }
  202. }
  203. return sb.ToString();
  204. }
  205. private int HandleError (IntPtr display, ref XErrorEvent error_event)
  206. {
  207. if (ErrorExceptions)
  208. throw new X11Exception (error_event.display, error_event.resourceid,
  209. error_event.serial, error_event.error_code,
  210. error_event.request_code, error_event.minor_code);
  211. else
  212. Console.WriteLine ("X11 Error encountered: {0}{1}\n",
  213. X11Exception.GetMessage(error_event.display, error_event.resourceid,
  214. error_event.serial, error_event.error_code,
  215. error_event.request_code, error_event.minor_code),
  216. WhereString());
  217. return 0;
  218. }
  219. #endregion // Callbacks
  220. private void ShowCaret()
  221. {
  222. if ((Caret.gc == IntPtr.Zero) || Caret.On) {
  223. return;
  224. }
  225. Caret.On = true;
  226. Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
  227. }
  228. private void HideCaret()
  229. {
  230. if ((Caret.gc == IntPtr.Zero) || !Caret.On) {
  231. return;
  232. }
  233. Caret.On = false;
  234. Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height);
  235. }
  236. public void CaretVisible (IntPtr handle, bool visible)
  237. {
  238. if (Caret.Hwnd == handle) {
  239. if (visible) {
  240. if (!Caret.Visible) {
  241. Caret.Visible = true;
  242. ShowCaret();
  243. Caret.Timer.Start();
  244. }
  245. } else {
  246. Caret.Visible = false;
  247. Caret.Timer.Stop();
  248. HideCaret();
  249. }
  250. }
  251. }
  252. public void AudibleAlert ()
  253. {
  254. Xlib.XBell (display, 0);
  255. }
  256. public void Flush ()
  257. {
  258. Xlib.XFlush (display);
  259. }
  260. public void Close ()
  261. {
  262. // XXX shut down the event_thread
  263. Xlib.XCloseDisplay (display);
  264. }
  265. public IntPtr XGetParent(IntPtr handle)
  266. {
  267. IntPtr Root;
  268. IntPtr Parent;
  269. IntPtr Children;
  270. int ChildCount;
  271. Xlib.XQueryTree (display, handle, out Root, out Parent, out Children, out ChildCount);
  272. if (Children!=IntPtr.Zero) {
  273. Xlib.XFree(Children);
  274. }
  275. return Parent;
  276. }
  277. public bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt)
  278. {
  279. IntPtr SystrayMgrWindow;
  280. Xlib.XGrabServer (display);
  281. SystrayMgrWindow = Xlib.XGetSelectionOwner (display, Atoms._NET_SYSTEM_TRAY_S);
  282. Xlib.XUngrabServer (display);
  283. if (SystrayMgrWindow != IntPtr.Zero) {
  284. XSizeHints size_hints;
  285. X11Hwnd hwnd;
  286. hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
  287. #if DriverDebug
  288. Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}",
  289. hwnd.WholeWindow.ToInt32(), hwnd.ClientWindow.ToInt32());
  290. #endif
  291. // Oh boy.
  292. if (hwnd.ClientWindow != hwnd.WholeWindow) {
  293. Xlib.XDestroyWindow (display, hwnd.ClientWindow);
  294. hwnd.ClientWindow = hwnd.WholeWindow;
  295. try {
  296. hwnd.Queue.Lock ();
  297. /* by virtue of the way the tests are ordered when determining if it's PAINT
  298. or NCPAINT, ClientWindow == WholeWindow will always be PAINT. So, if we're
  299. waiting on an nc_expose, drop it and remove the hwnd from the list (unless
  300. there's a pending expose). */
  301. hwnd.PendingNCExpose = false;
  302. }
  303. finally {
  304. hwnd.Queue.Unlock ();
  305. }
  306. }
  307. size_hints = new XSizeHints();
  308. size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
  309. size_hints.min_width = 24;
  310. size_hints.min_height = 24;
  311. size_hints.max_width = 24;
  312. size_hints.max_height = 24;
  313. size_hints.base_width = 24;
  314. size_hints.base_height = 24;
  315. Xlib.XSetWMNormalHints (display, hwnd.WholeWindow, ref size_hints);
  316. int[] atoms = new int[2];
  317. atoms [0] = 1; // Version 1
  318. atoms [1] = 1; // we want to be mapped
  319. // This line cost me 3 days...
  320. Xlib.XChangeProperty (display,
  321. hwnd.WholeWindow, Atoms._XEMBED_INFO, Atoms._XEMBED_INFO, 32,
  322. PropertyMode.Replace, atoms, 2);
  323. // Need to pick some reasonable defaults
  324. tt = new ToolTip();
  325. tt.AutomaticDelay = 100;
  326. tt.InitialDelay = 250;
  327. tt.ReshowDelay = 250;
  328. tt.ShowAlways = true;
  329. if ((tip != null) && (tip != string.Empty)) {
  330. tt.SetToolTip(Control.FromHandle(handle), tip);
  331. tt.Active = true;
  332. } else {
  333. tt.Active = false;
  334. }
  335. SendNetClientMessage (SystrayMgrWindow,
  336. Atoms._NET_SYSTEM_TRAY_OPCODE,
  337. IntPtr.Zero,
  338. (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK,
  339. hwnd.WholeWindow);
  340. return true;
  341. }
  342. tt = null;
  343. return false;
  344. }
  345. public bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt)
  346. {
  347. Control control;
  348. control = Control.FromHandle(handle);
  349. if (control != null && tt != null) {
  350. tt.SetToolTip(control, tip);
  351. tt.Active = true;
  352. return true;
  353. } else {
  354. return false;
  355. }
  356. }
  357. public void SystrayRemove(IntPtr handle, ref ToolTip tt)
  358. {
  359. #if GTKSOCKET_SUPPORTS_REPARENTING
  360. X11Hwnd hwnd;
  361. hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
  362. /* in the XEMBED spec, it mentions 3 ways for a client window to break the protocol with the embedder.
  363. * 1. The embedder can unmap the window and reparent to the root window (we should probably handle this...)
  364. * 2. The client can reparent its window out of the embedder window.
  365. * 3. The client can destroy its window.
  366. *
  367. * this call to SetParent is case 2, but in
  368. * the spec it also mentions that gtk doesn't
  369. * support this at present. Looking at HEAD
  370. * gtksocket-x11.c jives with this statement.
  371. *
  372. * so we can't reparent. we have to destroy.
  373. */
  374. SetParent(hwnd.WholeWindow, FosterParent);
  375. #else
  376. Control control = Control.FromHandle(handle);
  377. if (control is NotifyIcon.NotifyIconWindow)
  378. ((NotifyIcon.NotifyIconWindow)control).InternalRecreateHandle ();
  379. #endif
  380. // The caller can now re-dock it later...
  381. if (tt != null) {
  382. tt.Dispose();
  383. tt = null;
  384. }
  385. }
  386. public void ResetMouseHover (X11Hwnd hovering)
  387. {
  388. HoverState.Timer.Enabled = hovering != null;
  389. HoverState.X = MousePosition.X;
  390. HoverState.Y = MousePosition.Y;
  391. HoverState.Window = hovering == null ? IntPtr.Zero : hovering.Handle;
  392. }
  393. public void ShowCursor (bool show)
  394. {
  395. ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor
  396. }
  397. public void SetModal (X11Hwnd hwnd, bool Modal)
  398. {
  399. if (Modal) {
  400. ModalWindows.Push(hwnd);
  401. } else {
  402. // XXX do we need to pop until the
  403. // hwnd is off the stack? or just the
  404. // most recently pushed hwnd?
  405. if (ModalWindows.Contains(hwnd)) {
  406. ModalWindows.Pop();
  407. }
  408. if (ModalWindows.Count > 0) {
  409. X11Hwnd top_hwnd = (X11Hwnd)ModalWindows.Peek();
  410. top_hwnd.Activate();
  411. }
  412. }
  413. }
  414. public TransparencySupport SupportsTransparency ()
  415. {
  416. // compiz adds _NET_WM_WINDOW_OPACITY to _NET_SUPPORTED on the root window, check for that
  417. return ((IList)root_hwnd._NET_SUPPORTED).Contains (Atoms._NET_WM_WINDOW_OPACITY) ? TransparencySupport.GetSet : TransparencySupport.None;
  418. }
  419. public void SendAsyncMethod (AsyncMethodData method)
  420. {
  421. X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(method.Handle);
  422. XEvent xevent = new XEvent ();
  423. xevent.type = XEventName.ClientMessage;
  424. xevent.ClientMessageEvent.display = display;
  425. xevent.ClientMessageEvent.window = method.Handle;
  426. xevent.ClientMessageEvent.message_type = Atoms.AsyncAtom;
  427. xevent.ClientMessageEvent.format = 32;
  428. xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method);
  429. hwnd.Queue.Enqueue (xevent);
  430. }
  431. delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam);
  432. public IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam)
  433. {
  434. X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
  435. if (hwnd == null)
  436. return IntPtr.Zero;
  437. if (hwnd.Queue.Thread != Thread.CurrentThread) {
  438. AsyncMethodResult result;
  439. AsyncMethodData data;
  440. result = new AsyncMethodResult ();
  441. data = new AsyncMethodData ();
  442. data.Handle = hwnd.Handle;
  443. data.Method = new WndProcDelegate (NativeWindow.WndProc);
  444. data.Args = new object[] { hwnd.Handle, message, wParam, lParam };
  445. data.Result = result;
  446. SendAsyncMethod (data);
  447. #if DriverDebug || DriverDebugThreads
  448. Console.WriteLine ("Sending {0} message across.", message);
  449. #endif
  450. return IntPtr.Zero;
  451. }
  452. else {
  453. return NativeWindow.WndProc (hwnd.Handle, message, wParam, lParam);
  454. }
  455. }
  456. public int SendInput (IntPtr handle, Queue keys) {
  457. if (handle == IntPtr.Zero)
  458. return 0;
  459. int count = keys.Count;
  460. Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
  461. while (keys.Count > 0) {
  462. MSG msg = (MSG)keys.Dequeue();
  463. XEvent xevent = new XEvent ();
  464. xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress);
  465. xevent.KeyEvent.display = display;
  466. if (hwnd != null) {
  467. xevent.KeyEvent.window = hwnd.whole_window;
  468. } else {
  469. xevent.KeyEvent.window = IntPtr.Zero;
  470. }
  471. xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam);
  472. hwnd.Queue.EnqueueLocked (xevent);
  473. }
  474. return count;
  475. }
  476. // FIXME - I think this should just enqueue directly
  477. public bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam)
  478. {
  479. XEvent xevent = new XEvent ();
  480. X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
  481. xevent.type = XEventName.ClientMessage;
  482. xevent.ClientMessageEvent.display = display;
  483. if (hwnd != null) {
  484. xevent.ClientMessageEvent.window = hwnd.WholeWindow;
  485. } else {
  486. xevent.ClientMessageEvent.window = IntPtr.Zero;
  487. }
  488. xevent.ClientMessageEvent.message_type = Atoms.PostAtom;
  489. xevent.ClientMessageEvent.format = 32;
  490. xevent.ClientMessageEvent.ptr1 = handle;
  491. xevent.ClientMessageEvent.ptr2 = (IntPtr) message;
  492. xevent.ClientMessageEvent.ptr3 = wparam;
  493. xevent.ClientMessageEvent.ptr4 = lparam;
  494. hwnd.Queue.Enqueue (xevent);
  495. return true;
  496. }
  497. public void SendNetWMMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
  498. {
  499. XEvent xev;
  500. xev = new XEvent();
  501. xev.ClientMessageEvent.type = XEventName.ClientMessage;
  502. xev.ClientMessageEvent.send_event = true;
  503. xev.ClientMessageEvent.window = window;
  504. xev.ClientMessageEvent.message_type = message_type;
  505. xev.ClientMessageEvent.format = 32;
  506. xev.ClientMessageEvent.ptr1 = l0;
  507. xev.ClientMessageEvent.ptr2 = l1;
  508. xev.ClientMessageEvent.ptr3 = l2;
  509. Xlib.XSendEvent (display, root_hwnd.Handle, false,
  510. new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev);
  511. }
  512. public void SendNetClientMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
  513. {
  514. XEvent xev;
  515. xev = new XEvent();
  516. xev.ClientMessageEvent.type = XEventName.ClientMessage;
  517. xev.ClientMessageEvent.send_event = true;
  518. xev.ClientMessageEvent.window = window;
  519. xev.ClientMessageEvent.message_type = message_type;
  520. xev.ClientMessageEvent.format = 32;
  521. xev.ClientMessageEvent.ptr1 = l0;
  522. xev.ClientMessageEvent.ptr2 = l1;
  523. xev.ClientMessageEvent.ptr3 = l2;
  524. Xlib.XSendEvent (display, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev);
  525. }
  526. public bool TranslateMessage (ref MSG msg)
  527. {
  528. return Keyboard.TranslateMessage (ref msg);
  529. }
  530. public IntPtr DispatchMessage (ref MSG msg)
  531. {
  532. return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
  533. }
  534. private void QueryPointer (IntPtr w, out IntPtr root, out IntPtr child,
  535. out int root_x, out int root_y, out int child_x, out int child_y,
  536. out int mask)
  537. {
  538. /* this code was written with the help of
  539. glance at gdk. I never would have realized we
  540. needed a loop in order to traverse down in the
  541. hierarchy. I would have assumed you'd get the
  542. most deeply nested child and have to do
  543. XQueryTree to move back up the hierarchy..
  544. stupid me, of course. */
  545. IntPtr c;
  546. // Xlib.XGrabServer (display);
  547. Xlib.XQueryPointer (display, w, out root, out c,
  548. out root_x, out root_y, out child_x, out child_y,
  549. out mask);
  550. if (root != w)
  551. c = root;
  552. IntPtr child_last = IntPtr.Zero;
  553. while (c != IntPtr.Zero) {
  554. child_last = c;
  555. Xlib.XQueryPointer (display, c, out root, out c,
  556. out root_x, out root_y, out child_x, out child_y,
  557. out mask);
  558. }
  559. // Xlib.XUngrabServer (display);
  560. child = child_last;
  561. }
  562. public void SetCursorPos (int x, int y)
  563. {
  564. IntPtr root, child;
  565. int root_x, root_y, child_x, child_y, mask;
  566. /* we need to do a
  567. * QueryPointer before warping
  568. * because if the warp is on
  569. * the RootWindow, the x/y are
  570. * relative to the current
  571. * mouse position
  572. */
  573. QueryPointer (RootWindow.Handle,
  574. out root,
  575. out child,
  576. out root_x, out root_y,
  577. out child_x, out child_y,
  578. out mask);
  579. Xlib.XWarpPointer (display, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y);
  580. Xlib.XFlush (display);
  581. /* then we need to a
  582. * QueryPointer after warping
  583. * to manually generate a
  584. * motion event for the window
  585. * we move into.
  586. */
  587. QueryPointer (RootWindow.Handle,
  588. out root,
  589. out child,
  590. out root_x, out root_y,
  591. out child_x, out child_y,
  592. out mask);
  593. X11Hwnd child_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(child);
  594. if (child_hwnd == null)
  595. return;
  596. XEvent xevent = new XEvent ();
  597. xevent.type = XEventName.MotionNotify;
  598. xevent.MotionEvent.display = display;
  599. xevent.MotionEvent.window = child_hwnd.Handle;
  600. xevent.MotionEvent.root = RootWindow.Handle;
  601. xevent.MotionEvent.x = child_x;
  602. xevent.MotionEvent.y = child_y;
  603. xevent.MotionEvent.x_root = root_x;
  604. xevent.MotionEvent.y_root = root_y;
  605. xevent.MotionEvent.state = mask;
  606. child_hwnd.Queue.Enqueue (xevent);
  607. }
  608. public void SetFocus (X11Hwnd new_focus)
  609. {
  610. if (new_focus == FocusWindow)
  611. return;
  612. X11Hwnd prev_focus = FocusWindow;
  613. FocusWindow = new_focus;
  614. if (prev_focus != null)
  615. SendMessage (prev_focus.Handle, Msg.WM_KILLFOCUS,
  616. FocusWindow == null ? IntPtr.Zero : FocusWindow.Handle, IntPtr.Zero);
  617. if (FocusWindow != null)
  618. SendMessage (FocusWindow.Handle, Msg.WM_SETFOCUS,
  619. prev_focus == null ? IntPtr.Zero : prev_focus.Handle, IntPtr.Zero);
  620. //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).ClientWindow, RevertTo.None, IntPtr.Zero);
  621. }
  622. public IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot)
  623. {
  624. IntPtr cursor;
  625. Bitmap cursor_bitmap;
  626. Bitmap cursor_mask;
  627. Byte[] cursor_bits;
  628. Byte[] mask_bits;
  629. Color c_pixel;
  630. Color m_pixel;
  631. int width;
  632. int height;
  633. IntPtr cursor_pixmap;
  634. IntPtr mask_pixmap;
  635. XColor fg;
  636. XColor bg;
  637. bool and;
  638. bool xor;
  639. if (Xlib.XQueryBestCursor (display, RootWindow.Handle, bitmap.Width, bitmap.Height, out width, out height) == 0) {
  640. return IntPtr.Zero;
  641. }
  642. // Win32 only allows creation cursors of a certain size
  643. if ((bitmap.Width != width) || (bitmap.Width != height)) {
  644. cursor_bitmap = new Bitmap(bitmap, new Size(width, height));
  645. cursor_mask = new Bitmap(mask, new Size(width, height));
  646. } else {
  647. cursor_bitmap = bitmap;
  648. cursor_mask = mask;
  649. }
  650. width = cursor_bitmap.Width;
  651. height = cursor_bitmap.Height;
  652. cursor_bits = new Byte[(width / 8) * height];
  653. mask_bits = new Byte[(width / 8) * height];
  654. for (int y = 0; y < height; y++) {
  655. for (int x = 0; x < width; x++) {
  656. c_pixel = cursor_bitmap.GetPixel(x, y);
  657. m_pixel = cursor_mask.GetPixel(x, y);
  658. and = c_pixel == cursor_pixel;
  659. xor = m_pixel == mask_pixel;
  660. if (!and && !xor) {
  661. // Black
  662. // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0
  663. mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
  664. } else if (and && !xor) {
  665. // White
  666. cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
  667. mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8));
  668. #if notneeded
  669. } else if (and && !xor) {
  670. // Screen
  671. } else if (and && xor) {
  672. // Inverse Screen
  673. // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same
  674. // we want both to be 0 so nothing to be done
  675. //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8)));
  676. //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8));
  677. #endif
  678. }
  679. }
  680. }
  681. cursor_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle,
  682. cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
  683. mask_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle,
  684. mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1);
  685. fg = new XColor();
  686. bg = new XColor();
  687. fg.pixel = Xlib.XWhitePixel (display, DefaultScreen);
  688. fg.red = (ushort)65535;
  689. fg.green = (ushort)65535;
  690. fg.blue = (ushort)65535;
  691. bg.pixel = Xlib.XBlackPixel (display, DefaultScreen);
  692. cursor = Xlib.XCreatePixmapCursor (display, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot);
  693. Xlib.XFreePixmap (display, cursor_pixmap);
  694. Xlib.XFreePixmap (display, mask_pixmap);
  695. return cursor;
  696. }
  697. public Bitmap DefineStdCursorBitmap (StdCursor id)
  698. {
  699. CursorFontShape shape;
  700. string name;
  701. IntPtr theme;
  702. int size;
  703. Bitmap bmp = null;
  704. try {
  705. shape = XplatUIX11.StdCursorToFontShape (id);
  706. name = shape.ToString ().Replace ("XC_", string.Empty);
  707. size = XplatUIX11.XcursorGetDefaultSize (Handle);
  708. theme = XplatUIX11.XcursorGetTheme (Handle);
  709. IntPtr images_ptr = XplatUIX11.XcursorLibraryLoadImages (name, theme, size);
  710. #if debug
  711. Console.WriteLine ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr);
  712. #endif
  713. if (images_ptr == IntPtr.Zero) {
  714. return null;
  715. }
  716. XcursorImages images = (XcursorImages)Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
  717. #if debug
  718. Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
  719. #endif
  720. if (images.nimage > 0) {
  721. // We only care about the first image.
  722. XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
  723. #if debug
  724. Console.WriteLine ("DefineStdCursorBitmap, loaded image <size={0}, height={1}, width={2}, xhot={3}, yhot={4}, pixels={5}", image.size, image.height, image.width, image.xhot, image.yhot, image.pixels);
  725. #endif
  726. // A sanity check
  727. if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
  728. int [] pixels = new int [image.width * image.height];
  729. Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
  730. bmp = new Bitmap (image.width, image.height);
  731. for (int w = 0; w < image.width; w++) {
  732. for (int h = 0; h < image.height; h++) {
  733. bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
  734. }
  735. }
  736. }
  737. }
  738. XplatUIX11.XcursorImagesDestroy (images_ptr);
  739. } catch (DllNotFoundException ex) {
  740. Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
  741. return null;
  742. }
  743. return bmp;
  744. }
  745. public IntPtr DefineStdCursor (StdCursor id)
  746. {
  747. CursorFontShape shape;
  748. // FIXME - define missing shapes
  749. switch (id) {
  750. case StdCursor.AppStarting:
  751. shape = CursorFontShape.XC_watch;
  752. break;
  753. case StdCursor.Arrow:
  754. shape = CursorFontShape.XC_top_left_arrow;
  755. break;
  756. case StdCursor.Cross:
  757. shape = CursorFontShape.XC_crosshair;
  758. break;
  759. case StdCursor.Default:
  760. shape = CursorFontShape.XC_top_left_arrow;
  761. break;
  762. case StdCursor.Hand:
  763. shape = CursorFontShape.XC_hand1;
  764. break;
  765. case StdCursor.Help:
  766. shape = CursorFontShape.XC_question_arrow;
  767. break;
  768. case StdCursor.HSplit:
  769. shape = CursorFontShape.XC_sb_v_double_arrow;
  770. break;
  771. case StdCursor.IBeam:
  772. shape = CursorFontShape.XC_xterm;
  773. break;
  774. case StdCursor.No:
  775. shape = CursorFontShape.XC_circle;
  776. break;
  777. case StdCursor.NoMove2D:
  778. shape = CursorFontShape.XC_fleur;
  779. break;
  780. case StdCursor.NoMoveHoriz:
  781. shape = CursorFontShape.XC_fleur;
  782. break;
  783. case StdCursor.NoMoveVert:
  784. shape = CursorFontShape.XC_fleur;
  785. break;
  786. case StdCursor.PanEast:
  787. shape = CursorFontShape.XC_fleur;
  788. break;
  789. case StdCursor.PanNE:
  790. shape = CursorFontShape.XC_fleur;
  791. break;
  792. case StdCursor.PanNorth:
  793. shape = CursorFontShape.XC_fleur;
  794. break;
  795. case StdCursor.PanNW:
  796. shape = CursorFontShape.XC_fleur;
  797. break;
  798. case StdCursor.PanSE:
  799. shape = CursorFontShape.XC_fleur;
  800. break;
  801. case StdCursor.PanSouth:
  802. shape = CursorFontShape.XC_fleur;
  803. break;
  804. case StdCursor.PanSW:
  805. shape = CursorFontShape.XC_fleur;
  806. break;
  807. case StdCursor.PanWest:
  808. shape = CursorFontShape.XC_sizing;
  809. break;
  810. case StdCursor.SizeAll:
  811. shape = CursorFontShape.XC_fleur;
  812. break;
  813. case StdCursor.SizeNESW:
  814. shape = CursorFontShape.XC_top_right_corner;
  815. break;
  816. case StdCursor.SizeNS:
  817. shape = CursorFontShape.XC_sb_v_double_arrow;
  818. break;
  819. case StdCursor.SizeNWSE:
  820. shape = CursorFontShape.XC_top_left_corner;
  821. break;
  822. case StdCursor.SizeWE:
  823. shape = CursorFontShape.XC_sb_h_double_arrow;
  824. break;
  825. case StdCursor.UpArrow:
  826. shape = CursorFontShape.XC_center_ptr;
  827. break;
  828. case StdCursor.VSplit:
  829. shape = CursorFontShape.XC_sb_h_double_arrow;
  830. break;
  831. case StdCursor.WaitCursor:
  832. shape = CursorFontShape.XC_watch;
  833. break;
  834. default:
  835. return IntPtr.Zero;
  836. }
  837. return Xlib.XCreateFontCursor (display, shape);
  838. }
  839. // XXX this should take an X11Hwnd.
  840. public void CreateCaret (IntPtr handle, int width, int height)
  841. {
  842. XGCValues gc_values;
  843. X11Hwnd hwnd;
  844. hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
  845. if (Caret.Hwnd != IntPtr.Zero)
  846. DestroyCaret(Caret.Hwnd);
  847. Caret.Hwnd = handle;
  848. Caret.Window = hwnd.ClientWindow;
  849. Caret.Width = width;
  850. Caret.Height = height;
  851. Caret.Visible = false;
  852. Caret.On = false;
  853. gc_values = new XGCValues();
  854. gc_values.line_width = width;
  855. Caret.gc = Xlib.XCreateGC (display, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values);
  856. if (Caret.gc == IntPtr.Zero) {
  857. Caret.Hwnd = IntPtr.Zero;
  858. return;
  859. }
  860. Xlib.XSetFunction (display, Caret.gc, GXFunction.GXinvert);
  861. }
  862. // XXX this should take an X11Hwnd.
  863. public void DestroyCaret (IntPtr handle)
  864. {
  865. if (Caret.Hwnd == handle) {
  866. if (Caret.Visible == true) {
  867. Caret.Timer.Stop ();
  868. }
  869. if (Caret.gc != IntPtr.Zero) {
  870. Xlib.XFreeGC (display, Caret.gc);
  871. Caret.gc = IntPtr.Zero;
  872. }
  873. Caret.Hwnd = IntPtr.Zero;
  874. Caret.Visible = false;
  875. Caret.On = false;
  876. }
  877. }
  878. public void SetCaretPos (IntPtr handle, int x, int y)
  879. {
  880. if (Caret.Hwnd == handle) {
  881. Caret.Timer.Stop();
  882. HideCaret();
  883. Caret.X = x;
  884. Caret.Y = y;
  885. if (Caret.Visible == true) {
  886. ShowCaret();
  887. Caret.Timer.Start();
  888. }
  889. }
  890. }
  891. public void DestroyCursor (IntPtr cursor)
  892. {
  893. Xlib.XFreeCursor (display, cursor);
  894. }
  895. private void AccumulateDestroyedHandles (Control c, ArrayList list)
  896. {
  897. if (c != null) {
  898. Control[] controls = c.Controls.GetAllControls ();
  899. if (c.IsHandleCreated && !c.IsDisposed) {
  900. X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(c.Handle);
  901. #if DriverDebug || DriverDebugDestroy
  902. Console.WriteLine (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle));
  903. Console.WriteLine (" + parent X window is {0:X}", XGetParent (hwnd.WholeWindow).ToInt32());
  904. #endif
  905. list.Add (hwnd);
  906. CleanupCachedWindows (hwnd);
  907. hwnd.zombie = true;
  908. }
  909. for (int i = 0; i < controls.Length; i ++) {
  910. AccumulateDestroyedHandles (controls[i], list);
  911. }
  912. }
  913. }
  914. void CleanupCachedWindows (X11Hwnd hwnd)
  915. {
  916. if (ActiveWindow == hwnd) {
  917. SendMessage (hwnd.ClientWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
  918. ActiveWindow = null;
  919. }
  920. if (FocusWindow == hwnd) {
  921. SendMessage (hwnd.ClientWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
  922. FocusWindow = null;
  923. }
  924. if (Grab.Hwnd == hwnd.Handle) {
  925. Grab.Hwnd = IntPtr.Zero;
  926. Grab.Confined = false;
  927. }
  928. DestroyCaret (hwnd.Handle);
  929. }
  930. public void DestroyWindow (X11Hwnd hwnd)
  931. {
  932. CleanupCachedWindows (hwnd);
  933. hwnd.SendParentNotify (Msg.WM_DESTROY, int.MaxValue, int.MaxValue);
  934. ArrayList windows = new ArrayList ();
  935. AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows);
  936. hwnd.DestroyWindow ();
  937. foreach (X11Hwnd h in windows) {
  938. SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero);
  939. }
  940. }
  941. public X11Hwnd GetActiveWindow ()
  942. {
  943. IntPtr actual_atom;
  944. int actual_format;
  945. IntPtr nitems;
  946. IntPtr bytes_after;
  947. IntPtr prop = IntPtr.Zero;
  948. IntPtr active = IntPtr.Zero;
  949. Xlib.XGetWindowProperty (display, RootWindow.Handle,
  950. Atoms._NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false,
  951. Atoms.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
  952. if (((long)nitems > 0) && (prop != IntPtr.Zero)) {
  953. active = (IntPtr)Marshal.ReadInt32(prop);
  954. Xlib.XFree(prop);
  955. }
  956. return (X11Hwnd)Hwnd.GetObjectFromWindow(active);
  957. }
  958. public void SetActiveWindow (X11Hwnd new_active_window)
  959. {
  960. if (new_active_window != ActiveWindow) {
  961. if (ActiveWindow != null)
  962. PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE,
  963. (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero);
  964. ActiveWindow = new_active_window;
  965. if (ActiveWindow != null)
  966. PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE,
  967. (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
  968. }
  969. if (ModalWindows.Count > 0) {
  970. // Modality handling, if we are modal and the new active window is one
  971. // of ours but not the modal one, switch back to the modal window
  972. if (ActiveWindow != null &&
  973. NativeWindow.FromHandle (ActiveWindow.Handle) != null) {
  974. if (ActiveWindow != (X11Hwnd)ModalWindows.Peek())
  975. ((X11Hwnd)ModalWindows.Peek()).Activate ();
  976. }
  977. }
  978. }
  979. public void GetDisplaySize (out Size size)
  980. {
  981. XWindowAttributes attributes = new XWindowAttributes();
  982. // FIXME - use _NET_WM messages instead?
  983. Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
  984. size = new Size(attributes.width, attributes.height);
  985. }
  986. // XXX this method doesn't really fit well anywhere in the backend
  987. public SizeF GetAutoScaleSize (Font font)
  988. {
  989. Graphics g;
  990. float width;
  991. string magic_string = "The quick brown fox jumped over the lazy dog.";
  992. double magic_number = 44.549996948242189; // XXX my god, where did this number come from?
  993. g = Graphics.FromHwnd (FosterParent.Handle);
  994. width = (float) (g.MeasureString (magic_string, font).Width / magic_number);
  995. return new SizeF(width, font.Height);
  996. }
  997. public void GetCursorPos (X11Hwnd hwnd, out int x, out int y)
  998. {
  999. IntPtr use_handle;
  1000. IntPtr root;
  1001. IntPtr child;
  1002. int root_x;
  1003. int root_y;
  1004. int win_x;
  1005. int win_y;
  1006. int keys_buttons;
  1007. if (hwnd != null)
  1008. use_handle = hwnd.Handle;
  1009. else
  1010. use_handle = RootWindow.Handle;
  1011. QueryPointer (use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons);
  1012. if (hwnd != null) {
  1013. x = win_x;
  1014. y = win_y;
  1015. } else {
  1016. x = root_x;
  1017. y = root_y;
  1018. }
  1019. }
  1020. public IntPtr GetFocus ()
  1021. {
  1022. return FocusWindow.Handle;
  1023. }
  1024. public IntPtr GetMousewParam (int Delta)
  1025. {
  1026. int result = 0;
  1027. if ((MouseState & MouseButtons.Left) != 0) {
  1028. result |= (int)MsgButtons.MK_LBUTTON;
  1029. }
  1030. if ((MouseState & MouseButtons.Middle) != 0) {
  1031. result |= (int)MsgButtons.MK_MBUTTON;
  1032. }
  1033. if ((MouseState & MouseButtons.Right) != 0) {
  1034. result |= (int)MsgButtons.MK_RBUTTON;
  1035. }
  1036. Keys mods = ModifierKeys;
  1037. if ((mods & Keys.Control) != 0) {
  1038. result |= (int)MsgButtons.MK_CONTROL;
  1039. }
  1040. if ((mods & Keys.Shift) != 0) {
  1041. result |= (int)MsgButtons.MK_SHIFT;
  1042. }
  1043. result |= Delta << 16;
  1044. return (IntPtr)result;
  1045. }
  1046. public void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea)
  1047. {
  1048. handle = Grab.Hwnd;
  1049. GrabConfined = Grab.Confined;
  1050. GrabArea = Grab.Area;
  1051. }
  1052. public void GrabWindow (X11Hwnd hwnd, X11Hwnd confine_to)
  1053. {
  1054. IntPtr confine_to_window;
  1055. confine_to_window = IntPtr.Zero;
  1056. if (confine_to != null) {
  1057. Console.WriteLine (Environment.StackTrace);
  1058. XWindowAttributes attributes = new XWindowAttributes();
  1059. Xlib.XGetWindowAttributes (display, confine_to.ClientWindow, ref attributes);
  1060. Grab.Area.X = attributes.x;
  1061. Grab.Area.Y = attributes.y;
  1062. Grab.Area.Width = attributes.width;
  1063. Grab.Area.Height = attributes.height;
  1064. Grab.Confined = true;
  1065. confine_to_window = confine_to.ClientWindow;
  1066. }
  1067. Grab.Hwnd = hwnd.ClientWindow;
  1068. Xlib.XGrabPointer (display, hwnd.ClientWindow, false,
  1069. EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
  1070. EventMask.ButtonReleaseMask | EventMask.PointerMotionMask,
  1071. GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
  1072. }
  1073. public void UngrabWindow (X11Hwnd hwnd)
  1074. {
  1075. Xlib.XUngrabPointer (display, IntPtr.Zero);
  1076. Xlib.XFlush (display);
  1077. // XXX make sure hwnd is what should have the grab and throw if not
  1078. Grab.Hwnd = IntPtr.Zero;
  1079. Grab.Confined = false;
  1080. }
  1081. #if notyet
  1082. private void TranslatePropertyToClipboard (IntPtr property)
  1083. {
  1084. IntPtr actual_atom;
  1085. int actual_format;
  1086. IntPtr nitems;
  1087. IntPtr bytes_after;
  1088. IntPtr prop = IntPtr.Zero;
  1089. Clipboard.Item = null;
  1090. Xlib.XGetWindowProperty (display, FosterParent.Handle,
  1091. property, IntPtr.Zero, new IntPtr (0x7fffffff), true,
  1092. Atoms.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
  1093. if ((long)nitems > 0) {
  1094. if (property == Atoms.XA_STRING) {
  1095. Clipboard.Item = Marshal.PtrToStringAnsi(prop);
  1096. } else if (property == Atoms.XA_BITMAP) {
  1097. // FIXME - convert bitmap to image
  1098. } else if (property == Atoms.XA_PIXMAP) {
  1099. // FIXME - convert pixmap to image
  1100. } else if (property == Atoms.OEMTEXT) {
  1101. Clipboard.Item = Marshal.PtrToStringAnsi(prop);
  1102. } else if (property == Atoms.UNICODETEXT) {
  1103. Clipboard.Item = Marshal.PtrToStringAnsi(prop);
  1104. }
  1105. Xlib.XFree(prop);
  1106. }
  1107. }
  1108. #endif
  1109. // XXX should we be using @handle instead of Atoms.CLIPBOARD here?
  1110. public int[] ClipboardAvailableFormats (IntPtr handle)
  1111. {
  1112. // XXX deal with the updatemessagequeue stuff
  1113. #if true
  1114. return new int[0];
  1115. #else
  1116. DataFormats.Format f;
  1117. int[] result;
  1118. f = DataFormats.Format.List;
  1119. if (Xlib.XGetSelectionOwner (display, Atoms.CLIPBOARD) == IntPtr.Zero) {
  1120. return null;
  1121. }
  1122. Clipboard.Formats = new ArrayList();
  1123. while (f != null) {
  1124. Xlib.XConvertSelection (display, Atoms.CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent.Handle, IntPtr.Zero);
  1125. Clipboard.Enumerating = true;
  1126. while (Clipboard.Enumerating) {
  1127. UpdateMessageQueue(null);
  1128. }
  1129. f = f.Next;
  1130. }
  1131. result = new int[Clipboard.Formats.Count];
  1132. for (int i = 0; i < Clipboard.Formats.Count; i++) {
  1133. result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 ();
  1134. }
  1135. Clipboard.Formats = null;
  1136. return result;
  1137. #endif
  1138. }
  1139. public void ClipboardClose (IntPtr handle)
  1140. {
  1141. if (handle != ClipMagic) {
  1142. throw new ArgumentException("handle is not a valid clipboard handle");
  1143. }
  1144. return;
  1145. }
  1146. public int ClipboardGetID (IntPtr handle, string format)
  1147. {
  1148. if (handle != ClipMagic) {
  1149. throw new ArgumentException("handle is not a valid clipboard handle");
  1150. }
  1151. if (format == "Text" ) return Atoms.XA_STRING.ToInt32();
  1152. else if (format == "Bitmap" ) return Atoms.XA_BITMAP.ToInt32();
  1153. //else if (format == "MetaFilePict" ) return 3;
  1154. //else if (format == "SymbolicLink" ) return 4;
  1155. //else if (format == "DataInterchangeFormat" ) return 5;
  1156. //else if (format == "Tiff" ) return 6;
  1157. else if (format == "OEMText" ) return Atoms.OEMTEXT.ToInt32();
  1158. else if (format == "DeviceIndependentBitmap" ) return Atoms.XA_PIXMAP.ToInt32();
  1159. else if (format == "Palette" ) return Atoms.XA_COLORMAP.ToInt32(); // Useless
  1160. //else if (format == "PenData" ) return 10;
  1161. //else if (format == "RiffAudio" ) return 11;
  1162. //else if (format == "WaveAudio" ) return 12;
  1163. else if (format == "UnicodeText" ) return Atoms.UNICODETEXT.ToInt32();
  1164. //else if (format == "EnhancedMetafile" ) return 14;
  1165. //else if (format == "FileDrop" ) return 15;
  1166. //else if (format == "Locale" ) return 16;
  1167. return Xlib.XInternAtom (display, format, false).ToInt32();
  1168. }
  1169. public IntPtr ClipboardOpen (bool primary_selection)
  1170. {
  1171. if (!primary_selection)
  1172. ClipMagic = Atoms.CLIPBOARD;
  1173. else
  1174. ClipMagic = Atoms.PRIMARY;
  1175. return ClipMagic;
  1176. }
  1177. // XXX @converter?
  1178. public object ClipboardRetrieve (IntPtr handle, int type, XplatUI.ClipboardToObject converter)
  1179. {
  1180. // XXX deal with the UpdateMessageQueue stuff
  1181. #if true
  1182. return null;
  1183. #else
  1184. Xlib.XConvertSelection (display, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero);
  1185. Clipboard.Retrieving = true;
  1186. while (Clipboard.Retrieving) {
  1187. UpdateMessageQueue(null);
  1188. }
  1189. return Clipboard.Item;
  1190. #endif
  1191. }
  1192. public void ClipboardStore (IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter)
  1193. {
  1194. Clipboard.Item = obj;
  1195. Clipboard.Type = type;
  1196. Clipboard.Converter = converter;
  1197. if (obj != null) {
  1198. Xlib.XSetSelectionOwner (display, Atoms.CLIPBOARD, FosterParent.Handle, IntPtr.Zero);
  1199. } else {
  1200. // Clearing the selection
  1201. Xlib.XSetSelectionOwner (display, Atoms.CLIPBOARD, IntPtr.Zero, IntPtr.Zero);
  1202. }
  1203. }
  1204. public PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client)
  1205. {
  1206. X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
  1207. if (Caret.Visible == true) {
  1208. Caret.Paused = true;
  1209. HideCaret();
  1210. }
  1211. return hwnd.PaintEventStart (ref m, client);
  1212. }
  1213. public void PaintEventEnd (ref Message m, IntPtr handle, bool client)
  1214. {
  1215. X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);
  1216. hwnd.PaintEventEnd (ref m, client);
  1217. if (Caret.Visible == true) {
  1218. ShowCaret();
  1219. Caret.Paused = false;
  1220. }
  1221. }
  1222. public void SetCursor (IntPtr handle, IntPtr cursor)
  1223. {
  1224. Hwnd hwnd;
  1225. if (OverrideCursorHandle == IntPtr.Zero) {
  1226. if ((LastCursorWindow == handle) && (LastCursorHandle == cursor))
  1227. return;
  1228. LastCursorHandle = cursor;
  1229. LastCursorWindow = handle;
  1230. hwnd = Hwnd.ObjectFromHandle(handle);
  1231. if (cursor != IntPtr.Zero)
  1232. Xlib.XDefineCursor (display, hwnd.whole_window, cursor);
  1233. else
  1234. Xlib.XUndefineCursor (display, hwnd.whole_window);
  1235. Xlib.XFlush (display);
  1236. }
  1237. else {
  1238. hwnd = Hwnd.ObjectFromHandle(handle);
  1239. Xlib.XDefineCursor (display, hwnd.whole_window, OverrideCursorHandle);
  1240. }
  1241. }
  1242. public DragDropEffects StartDrag (IntPtr handle, object data,
  1243. DragDropEffects allowed_effects)
  1244. {
  1245. X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle);
  1246. if (hwnd == null)
  1247. throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ").");
  1248. return Dnd.StartDrag (hwnd.ClientWindow, data, allowed_effects);
  1249. }
  1250. public X11Atoms Atoms {
  1251. get { return atoms; }
  1252. }
  1253. public int CurrentTimestamp {
  1254. get {
  1255. TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
  1256. return (int) t.TotalSeconds;
  1257. }
  1258. }
  1259. public Size CursorSize {
  1260. get {
  1261. int x;
  1262. int y;
  1263. if (Xlib.XQueryBestCursor (display, RootWindow.Handle, 32, 32, out x, out y) != 0) {
  1264. return new Size (x, y);
  1265. } else {
  1266. return new Size (16, 16);
  1267. }
  1268. }
  1269. }
  1270. public IntPtr Handle {
  1271. get { return display; }
  1272. }
  1273. public Size IconSize {
  1274. get {
  1275. IntPtr list;
  1276. XIconSize size;
  1277. int count;
  1278. if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) {
  1279. long current;
  1280. int largest;
  1281. current = (long)list;
  1282. largest = 0;
  1283. size = new XIconSize();
  1284. for (int i = 0; i < count; i++) {
  1285. size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
  1286. current += Marshal.SizeOf(size);
  1287. // Look for our preferred size
  1288. if (size.min_width == 32) {
  1289. Xlib.XFree(list);
  1290. return new Size(32, 32);
  1291. }
  1292. if (size.max_width == 32) {
  1293. Xlib.XFree(list);
  1294. return new Size(32, 32);
  1295. }
  1296. if (size.min_width < 32 && size.max_width > 32) {
  1297. int x;
  1298. // check if we can fit one
  1299. x = size.min_width;
  1300. while (x < size.max_width) {
  1301. x += size.width_inc;
  1302. if (x == 32) {
  1303. Xlib.XFree(list);
  1304. return new Size(32, 32);
  1305. }
  1306. }
  1307. }
  1308. if (largest < size.max_width) {
  1309. largest = size.max_width;
  1310. }
  1311. }
  1312. // We didn't find a match or we wouldn't be here
  1313. return new Size(largest, largest);
  1314. } else {
  1315. return new Size(32, 32);
  1316. }
  1317. }
  1318. }
  1319. public int KeyboardSpeed {
  1320. get {
  1321. //
  1322. // A lot harder: need to do:
  1323. // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1
  1324. // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8
  1325. // XkbGetControls(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0
  1326. //
  1327. // And from that we can tell the repetition rate
  1328. //
  1329. // Notice, the values must map to:
  1330. // [0, 31] which maps to 2.5 to 30 repetitions per second.
  1331. //
  1332. return 0;
  1333. }
  1334. }
  1335. public int KeyboardDelay {
  1336. get {
  1337. //
  1338. // Return values must range from 0 to 4, 0 meaning 250ms,
  1339. // and 4 meaning 1000 ms.
  1340. //
  1341. return 1; // ie, 500 ms
  1342. }
  1343. }
  1344. public int DefaultScreen {
  1345. get { return Xlib.XDefaultScreen (display); }
  1346. }
  1347. public IntPtr DefaultColormap {
  1348. // XXX multiscreen
  1349. get { return Xlib.XDefaultColormap (display, DefaultScreen); }
  1350. }
  1351. public Keys ModifierKeys {
  1352. get { return Keyboard.ModifierKeys; }
  1353. }
  1354. public IntPtr OverrideCursor {
  1355. get { return OverrideCursorHandle; }
  1356. set {
  1357. if (Grab.Hwnd != IntPtr.Zero) {
  1358. Xlib.XChangeActivePointerGrab (display,
  1359. EventMask.ButtonMotionMask |
  1360. EventMask.PointerMotionMask |
  1361. EventMask.ButtonPressMask |
  1362. EventMask.ButtonReleaseMask,
  1363. value, IntPtr.Zero);
  1364. return;
  1365. }
  1366. OverrideCursorHandle = value;
  1367. }
  1368. }
  1369. public X11RootHwnd RootWindow {
  1370. get { return root_hwnd; }
  1371. }
  1372. public Size SmallIconSize {
  1373. get {
  1374. IntPtr list;
  1375. XIconSize size;
  1376. int count;
  1377. if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) {
  1378. long current;
  1379. int smallest;
  1380. current = (long)list;
  1381. smallest = 0;
  1382. size = new XIconSize();
  1383. for (int i = 0; i < count; i++) {
  1384. size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType());
  1385. current += Marshal.SizeOf(size);
  1386. // Look for our preferred size
  1387. if (size.min_width == 16) {
  1388. Xlib.XFree(list);
  1389. return new Size(16, 16);
  1390. }
  1391. if (size.max_width == 16) {
  1392. Xlib.XFree(list);
  1393. return new Size(16, 16);
  1394. }
  1395. if (size.min_width < 16 && size.max_width > 16) {
  1396. int x;
  1397. // check if we can fit one
  1398. x = size.min_width;
  1399. while (x < size.max_width) {
  1400. x += size.width_inc;
  1401. if (x == 16) {
  1402. Xlib.XFree(list);
  1403. return new Size(16, 16);
  1404. }
  1405. }
  1406. }
  1407. if (smallest == 0 || smallest > size.min_width) {
  1408. smallest = size.min_width;
  1409. }
  1410. }
  1411. // We didn't find a match or we wouldn't be here
  1412. return new Size(smallest, smallest);
  1413. } else {
  1414. return new Size(16, 16);
  1415. }
  1416. }
  1417. }
  1418. public X11Hwnd FosterParent {
  1419. get { return foster_hwnd; }
  1420. }
  1421. public int MouseHoverTime {
  1422. get { return HoverState.Interval; }
  1423. }
  1424. public Rectangle VirtualScreen {
  1425. get {
  1426. IntPtr actual_atom;
  1427. int actual_format;
  1428. IntPtr nitems;
  1429. IntPtr bytes_after;
  1430. IntPtr prop = IntPtr.Zero;
  1431. int width;
  1432. int height;
  1433. Xlib.XGetWindowProperty (display, RootWindow.Handle,
  1434. Atoms._NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL,
  1435. out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
  1436. if ((long)nitems < 2)
  1437. goto failsafe;
  1438. width = Marshal.ReadIntPtr(prop, 0).ToInt32();
  1439. height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
  1440. Xlib.XFree(prop);
  1441. return new Rectangle(0, 0, width, height);
  1442. failsafe:
  1443. XWindowAttributes attributes = new XWindowAttributes();
  1444. Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
  1445. return new Rectangle(0, 0, attributes.width, attributes.height);
  1446. }
  1447. }
  1448. public Rectangle WorkingArea {
  1449. get {
  1450. IntPtr actual_atom;
  1451. int actual_format;
  1452. IntPtr nitems;
  1453. IntPtr bytes_after;
  1454. IntPtr prop = IntPtr.Zero;
  1455. int width;
  1456. int height;
  1457. int current_desktop;
  1458. int x;
  1459. int y;
  1460. Xlib.XGetWindowProperty (display, RootWindow.Handle,
  1461. Atoms._NET_CURRENT_DESKTOP, IntPtr.Zero, new IntPtr(1), false, Atoms.XA_CARDINAL,
  1462. out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
  1463. if ((long)nitems < 1) {
  1464. goto failsafe;
  1465. }
  1466. current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32();
  1467. Xlib.XFree(prop);
  1468. Xlib.XGetWindowProperty (display, RootWindow.Handle,
  1469. Atoms._NET_WORKAREA, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL,
  1470. out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
  1471. if ((long)nitems < 4 * current_desktop) {
  1472. goto failsafe;
  1473. }
  1474. x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32();
  1475. y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32();
  1476. width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32();
  1477. height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32();
  1478. Xlib.XFree(prop);
  1479. return new Rectangle(x, y, width, height);
  1480. failsafe:
  1481. XWindowAttributes attributes = new XWindowAttributes();
  1482. Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes);
  1483. return new Rectangle(0, 0, attributes.width, attributes.height);
  1484. }
  1485. }
  1486. private void XEventThread ()
  1487. {
  1488. while (true) {
  1489. #if __MonoCS__
  1490. Syscall.poll (pollfds, 1U, -1);
  1491. while (Xlib.XPending (display) > 0) {
  1492. #endif
  1493. XEvent xevent = new XEvent ();
  1494. Xlib.XNextEvent (display, ref xevent);
  1495. // this is kind of a gross place to put this, but we don't know about the
  1496. // key repeat state in X11ThreadQueue, nor to we want the queue code calling
  1497. // XPeekEvent.
  1498. if (!detectable_key_auto_repeat &&
  1499. xevent.type == XEventName.KeyRelease &&
  1500. Xlib.XPending (display) > 0) {
  1501. XEvent nextevent = new XEvent ();
  1502. Xlib.XPeekEvent (display, ref nextevent);
  1503. if (nextevent.type == XEventName.KeyPress &&
  1504. nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode &&
  1505. nextevent.KeyEvent.time == xevent.KeyEvent.time) {
  1506. continue;
  1507. }
  1508. }
  1509. X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(xevent.AnyEvent.window);
  1510. if (hwnd != null)
  1511. hwnd.Queue.Enqueue (xevent);
  1512. #if __MonoCS__
  1513. }
  1514. #endif
  1515. }
  1516. }
  1517. private void RedirectMsgToEnabledAncestor (X11Hwnd hwnd, MSG msg, IntPtr window,
  1518. ref int event_x, ref int event_y)
  1519. {
  1520. int x, y;
  1521. IntPtr dummy;
  1522. msg.hwnd = hwnd.EnabledHwnd;
  1523. Xlib.XTranslateCoordinates (display, window,
  1524. Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow,
  1525. event_x, event_y,
  1526. out x, out y, out dummy);
  1527. event_x = x;
  1528. event_y = y;
  1529. msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X);
  1530. }
  1531. // This is called from the thread owning the corresponding X11ThreadQueue
  1532. [MonoTODO("Implement filtering")]
  1533. public bool GetMessage (object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax)
  1534. {
  1535. X11ThreadQueue queue = (X11ThreadQueue)queue_id;
  1536. XEvent xevent;
  1537. bool client;
  1538. bool got_xevent = false;
  1539. X11Hwnd hwnd;
  1540. ProcessNextMessage:
  1541. do {
  1542. got_xevent = queue.Dequeue (out xevent);
  1543. if (!got_xevent) {
  1544. #if spew
  1545. Console.WriteLine (">");
  1546. Console.Out.Flush ();
  1547. #endif
  1548. break;
  1549. }
  1550. #if spew
  1551. Console.Write ("-");
  1552. Console.Out.Flush ();
  1553. #endif
  1554. hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window);
  1555. // Handle messages for windows that are already or are about to be destroyed.
  1556. // we need a special block for this because unless we remove the hwnd from the paint
  1557. // queue it will always stay there (since we don't handle the expose), and we'll
  1558. // effectively loop infinitely trying to repaint a non-existant window.
  1559. if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) {
  1560. hwnd.PendingExpose = hwnd.PendingNCExpose = false;
  1561. goto ProcessNextMessage;
  1562. }
  1563. // We need to make sure we only allow DestroyNotify events through for zombie
  1564. // hwnds, since much of the event handling code makes requests using the hwnd's
  1565. // ClientWindow, and that'll result in BadWindow errors if there's some lag
  1566. // between the XDestroyWindow call and the DestroyNotify event.
  1567. if (hwnd == null || hwnd.zombie) {
  1568. #if DriverDebug || DriverDebugDestroy
  1569. Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}",
  1570. xevent.type, xevent.AnyEvent.window.ToInt32());
  1571. #endif
  1572. goto ProcessNextMessage;
  1573. }
  1574. client = hwnd.ClientWindow == xevent.AnyEvent.window;
  1575. msg.hwnd = hwnd.Handle;
  1576. switch (xevent.type) {
  1577. case XEventName.KeyPress:
  1578. Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg);
  1579. return true;
  1580. case XEventName.KeyRelease:
  1581. Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg);
  1582. return true;
  1583. case XEventName.ButtonPress: {
  1584. switch(xevent.ButtonEvent.button) {
  1585. case 1:
  1586. MouseState |= MouseButtons.Left;
  1587. if (client) {
  1588. msg.message = Msg.WM_LBUTTONDOWN;
  1589. } else {
  1590. msg.message = Msg.WM_NCLBUTTONDOWN;
  1591. hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1592. }
  1593. // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
  1594. msg.wParam=GetMousewParam(0);
  1595. break;
  1596. case 2:
  1597. MouseState |= MouseButtons.Middle;
  1598. if (client) {
  1599. msg.message = Msg.WM_MBUTTONDOWN;
  1600. } else {
  1601. msg.message = Msg.WM_NCMBUTTONDOWN;
  1602. hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1603. }
  1604. msg.wParam=GetMousewParam(0);
  1605. break;
  1606. case 3:
  1607. MouseState |= MouseButtons.Right;
  1608. if (client) {
  1609. msg.message = Msg.WM_RBUTTONDOWN;
  1610. } else {
  1611. msg.message = Msg.WM_NCRBUTTONDOWN;
  1612. hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1613. }
  1614. msg.wParam=GetMousewParam(0);
  1615. break;
  1616. case 4:
  1617. msg.hwnd = FocusWindow.Handle;
  1618. msg.message=Msg.WM_MOUSEWHEEL;
  1619. msg.wParam=GetMousewParam(120);
  1620. break;
  1621. case 5:
  1622. msg.hwnd = FocusWindow.Handle;
  1623. msg.message=Msg.WM_MOUSEWHEEL;
  1624. msg.wParam=GetMousewParam(-120);
  1625. break;
  1626. }
  1627. msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
  1628. MousePosition.X = xevent.ButtonEvent.x;
  1629. MousePosition.Y = xevent.ButtonEvent.y;
  1630. if (!hwnd.Enabled) {
  1631. RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
  1632. ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1633. }
  1634. if (Grab.Hwnd != IntPtr.Zero)
  1635. msg.hwnd = Grab.Hwnd;
  1636. if (ClickPending.Pending &&
  1637. ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) &&
  1638. (msg.wParam == ClickPending.wParam) &&
  1639. (msg.lParam == ClickPending.lParam) &&
  1640. (msg.message == ClickPending.Message))) {
  1641. // Looks like a genuine double click, clicked twice on the same spot with the same keys
  1642. switch(xevent.ButtonEvent.button) {
  1643. case 1:
  1644. msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK;
  1645. break;
  1646. case 2:
  1647. msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK;
  1648. break;
  1649. case 3:
  1650. msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK;
  1651. break;
  1652. }
  1653. ClickPending.Pending = false;
  1654. }
  1655. else {
  1656. ClickPending.Pending = true;
  1657. ClickPending.Hwnd = msg.hwnd;
  1658. ClickPending.Message = msg.message;
  1659. ClickPending.wParam = msg.wParam;
  1660. ClickPending.lParam = msg.lParam;
  1661. ClickPending.Time = (long)xevent.ButtonEvent.time;
  1662. }
  1663. if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) {
  1664. hwnd.SendParentNotify (msg.message, MousePosition.X, MousePosition.Y);
  1665. // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
  1666. // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
  1667. // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
  1668. XEvent motionEvent = new XEvent ();
  1669. motionEvent.type = XEventName.MotionNotify;
  1670. motionEvent.MotionEvent.display = display;
  1671. motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
  1672. motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
  1673. motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
  1674. hwnd.Queue.Enqueue (motionEvent);
  1675. }
  1676. return true;
  1677. }
  1678. case XEventName.ButtonRelease:
  1679. switch(xevent.ButtonEvent.button) {
  1680. case 1:
  1681. if (client) {
  1682. msg.message = Msg.WM_LBUTTONUP;
  1683. } else {
  1684. msg.message = Msg.WM_NCLBUTTONUP;
  1685. hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1686. }
  1687. MouseState &= ~MouseButtons.Left;
  1688. msg.wParam=GetMousewParam(0);
  1689. break;
  1690. case 2:
  1691. if (client) {
  1692. msg.message = Msg.WM_MBUTTONUP;
  1693. } else {
  1694. msg.message = Msg.WM_NCMBUTTONUP;
  1695. hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1696. }
  1697. MouseState &= ~MouseButtons.Middle;
  1698. msg.wParam=GetMousewParam(0);
  1699. break;
  1700. case 3:
  1701. if (client) {
  1702. msg.message = Msg.WM_RBUTTONUP;
  1703. } else {
  1704. msg.message = Msg.WM_NCRBUTTONUP;
  1705. hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1706. }
  1707. MouseState &= ~MouseButtons.Right;
  1708. msg.wParam=GetMousewParam(0);
  1709. break;
  1710. case 4:
  1711. goto ProcessNextMessage;
  1712. case 5:
  1713. goto ProcessNextMessage;
  1714. }
  1715. if (!hwnd.Enabled) {
  1716. RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
  1717. ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y);
  1718. }
  1719. if (Grab.Hwnd != IntPtr.Zero)
  1720. msg.hwnd = Grab.Hwnd;
  1721. msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x);
  1722. MousePosition.X = xevent.ButtonEvent.x;
  1723. MousePosition.Y = xevent.ButtonEvent.y;
  1724. // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or
  1725. // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after
  1726. // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh*
  1727. if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) {
  1728. XEvent motionEvent = new XEvent ();
  1729. motionEvent.type = XEventName.MotionNotify;
  1730. motionEvent.MotionEvent.display = display;
  1731. motionEvent.MotionEvent.window = xevent.ButtonEvent.window;
  1732. motionEvent.MotionEvent.x = xevent.ButtonEvent.x;
  1733. motionEvent.MotionEvent.y = xevent.ButtonEvent.y;
  1734. hwnd.Queue.Enqueue (motionEvent);
  1735. }
  1736. return true;
  1737. case XEventName.MotionNotify:
  1738. /* XXX move the compression stuff here */
  1739. if (client) {
  1740. #if DriverDebugExtra
  1741. Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}",
  1742. client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(),
  1743. xevent.MotionEvent.x, xevent.MotionEvent.y);
  1744. #endif
  1745. if (Grab.Hwnd != IntPtr.Zero)
  1746. msg.hwnd = Grab.Hwnd;
  1747. else
  1748. NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
  1749. msg.message = Msg.WM_MOUSEMOVE;
  1750. msg.wParam = GetMousewParam(0);
  1751. msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF);
  1752. if (!hwnd.Enabled) {
  1753. RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
  1754. ref xevent.MotionEvent.x, ref xevent.MotionEvent.y);
  1755. }
  1756. MousePosition.X = xevent.MotionEvent.x;
  1757. MousePosition.Y = xevent.MotionEvent.y;
  1758. if ((HoverState.Timer.Enabled) &&
  1759. (((MousePosition.X + HoverState.Size.Width) < HoverState.X) ||
  1760. ((MousePosition.X - HoverState.Size.Width) > HoverState.X) ||
  1761. ((MousePosition.Y + HoverState.Size.Height) < HoverState.Y) ||
  1762. ((MousePosition.Y - HoverState.Size.Height) > HoverState.Y))) {
  1763. HoverState.Timer.Stop();
  1764. HoverState.Timer.Start();
  1765. HoverState.X = MousePosition.X;
  1766. HoverState.Y = MousePosition.Y;
  1767. }
  1768. }
  1769. else {
  1770. HitTest ht;
  1771. IntPtr dummy;
  1772. int screen_x;
  1773. int screen_y;
  1774. #if DriverDebugExtra
  1775. Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}",
  1776. client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(),
  1777. xevent.MotionEvent.x, xevent.MotionEvent.y);
  1778. #endif
  1779. msg.message = Msg.WM_NCMOUSEMOVE;
  1780. if (!hwnd.Enabled) {
  1781. RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window,
  1782. ref xevent.MotionEvent.x, ref xevent.MotionEvent.y);
  1783. }
  1784. // The hit test is sent in screen coordinates
  1785. Xlib.XTranslateCoordinates (display, xevent.AnyEvent.window, RootWindow.Handle,
  1786. xevent.MotionEvent.x, xevent.MotionEvent.y,
  1787. out screen_x, out screen_y, out dummy);
  1788. msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF);
  1789. ht = (HitTest)NativeWindow.WndProc (hwnd.ClientWindow, Msg.WM_NCHITTEST,
  1790. IntPtr.Zero, msg.lParam).ToInt32 ();
  1791. NativeWindow.WndProc(hwnd.ClientWindow, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht);
  1792. MousePosition.X = xevent.MotionEvent.x;
  1793. MousePosition.Y = xevent.MotionEvent.y;
  1794. }
  1795. return true;
  1796. case XEventName.EnterNotify:
  1797. if (!hwnd.Enabled)
  1798. goto ProcessNextMessage;
  1799. if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal)
  1800. goto ProcessNextMessage;
  1801. msg.message = Msg.WM_MOUSE_ENTER;
  1802. HoverState.X = xevent.CrossingEvent.x;
  1803. HoverState.Y = xevent.CrossingEvent.y;
  1804. HoverState.Timer.Enabled = true;
  1805. HoverState.Window = xevent.CrossingEvent.window;
  1806. return true;
  1807. case XEventName.LeaveNotify:
  1808. if (!hwnd.Enabled)
  1809. goto ProcessNextMessage;
  1810. if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) ||
  1811. (xevent.CrossingEvent.window != hwnd.ClientWindow))
  1812. goto ProcessNextMessage;
  1813. msg.message=Msg.WM_MOUSELEAVE;
  1814. HoverState.Timer.Enabled = false;
  1815. HoverState.Window = IntPtr.Zero;
  1816. return true;
  1817. case XEventName.ReparentNotify:
  1818. if (hwnd.parent == null) { // Toplevel
  1819. if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.WholeWindow)) {
  1820. // We need to adjust x/y
  1821. // This sucks ass, part 2
  1822. // Every WM does the reparenting of toplevel windows different, so there's
  1823. // no standard way of getting our adjustment considering frames/decorations
  1824. // The code below is needed for metacity. KDE doesn't works just fine without this
  1825. int dummy_int;
  1826. IntPtr dummy_ptr;
  1827. int new_x;
  1828. int new_y;
  1829. int frame_left;
  1830. int frame_top;
  1831. hwnd.Reparented = true;
  1832. Xlib.XGetGeometry(display, XGetParent(hwnd.WholeWindow),
  1833. out dummy_ptr, out new_x, out new_y,
  1834. out dummy_int, out dummy_int, out dummy_int, out dummy_int);
  1835. hwnd.FrameExtents(out frame_left, out frame_top);
  1836. if ((frame_left != 0) && (frame_top != 0) && (new_x != frame_left) && (new_y != frame_top)) {
  1837. hwnd.x = new_x;
  1838. hwnd.y = new_y;
  1839. hwnd.whacky_wm = true;
  1840. }
  1841. if (hwnd.opacity != 0xffffffff) {
  1842. IntPtr opacity;
  1843. opacity = (IntPtr)(Int32)hwnd.opacity;
  1844. Xlib.XChangeProperty (display, XGetParent(hwnd.WholeWindow),
  1845. Atoms._NET_WM_WINDOW_OPACITY, Atoms.XA_CARDINAL, 32,
  1846. PropertyMode.Replace, ref opacity, 1);
  1847. }
  1848. SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam);
  1849. goto ProcessNextMessage;
  1850. } else {
  1851. hwnd.Reparented = false;
  1852. goto ProcessNextMessage;
  1853. }
  1854. }
  1855. goto ProcessNextMessage;
  1856. case XEventName.ConfigureNotify:
  1857. hwnd.HandleConfigureNotify (xevent);
  1858. goto ProcessNextMessage;
  1859. case XEventName.MapNotify: {
  1860. if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
  1861. hwnd.Mapped = true;
  1862. msg.message = Msg.WM_SHOWWINDOW;
  1863. msg.wParam = (IntPtr) 1;
  1864. // XXX we're missing the lParam..
  1865. break;
  1866. }
  1867. goto ProcessNextMessage;
  1868. }
  1869. case XEventName.UnmapNotify: {
  1870. if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas
  1871. hwnd.Mapped = false;
  1872. msg.message = Msg.WM_SHOWWINDOW;
  1873. msg.wParam = (IntPtr) 0;
  1874. // XXX we're missing the lParam..
  1875. break;
  1876. }
  1877. goto ProcessNextMessage;
  1878. }
  1879. case XEventName.FocusIn:
  1880. // We received focus. We use X11 focus only to know if the app window does or does not have focus
  1881. // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally
  1882. // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know
  1883. // about it having focus again
  1884. if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear)
  1885. goto ProcessNextMessage;
  1886. if (FocusWindow == null) {
  1887. Control c = Control.FromHandle (hwnd.ClientWindow);
  1888. if (c == null)
  1889. goto ProcessNextMessage;
  1890. Form form = c.FindForm ();
  1891. if (form == null)
  1892. goto ProcessNextMessage;
  1893. X11Hwnd new_active = (X11Hwnd)Hwnd.ObjectFromHandle (form.Handle);
  1894. if (ActiveWindow != new_active) {
  1895. ActiveWindow = new_active;
  1896. SendMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero);
  1897. }
  1898. goto ProcessNextMessage;
  1899. }
  1900. Keyboard.FocusIn(FocusWindow.Handle);
  1901. SendMessage(FocusWindow.Handle, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
  1902. goto ProcessNextMessage;
  1903. case XEventName.FocusOut:
  1904. // Se the comment for our FocusIn handler
  1905. if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear)
  1906. goto ProcessNextMessage;
  1907. if (FocusWindow == null)
  1908. goto ProcessNextMessage;
  1909. Keyboard.FocusOut(FocusWindow.Handle);
  1910. while (Keyboard.ResetKeyState(FocusWindow.Handle, ref msg))
  1911. SendMessage(FocusWindow.Handle, msg.message, msg.wParam, msg.lParam);
  1912. SendMessage(FocusWindow.Handle, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
  1913. goto ProcessNextMessage;
  1914. case XEventName.Expose:
  1915. if (!hwnd.Mapped) {
  1916. hwnd.PendingExpose = hwnd.PendingNCExpose = false;
  1917. continue;
  1918. }
  1919. msg.hwnd = hwnd.Handle;
  1920. if (client) {
  1921. #if DriverDebugExtra
  1922. Console.WriteLine("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}",
  1923. hwnd.client_window.ToInt32(),
  1924. xevent.ExposeEvent.x, xevent.ExposeEvent.y,
  1925. xevent.ExposeEvent.width, xevent.ExposeEvent.height);
  1926. #endif
  1927. msg.message = Msg.WM_PAINT;
  1928. }
  1929. else {
  1930. Graphics g;
  1931. switch (hwnd.border_style) {
  1932. case FormBorderStyle.Fixed3D:
  1933. g = Graphics.FromHwnd(hwnd.WholeWindow);
  1934. ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height),
  1935. Border3DStyle.Sunken);
  1936. g.Dispose();
  1937. break;
  1938. case FormBorderStyle.FixedSingle:
  1939. g = Graphics.FromHwnd(hwnd.WholeWindow);
  1940. ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height),
  1941. Color.Black, ButtonBorderStyle.Solid);
  1942. g.Dispose();
  1943. break;
  1944. }
  1945. #if DriverDebugExtra
  1946. Console.WriteLine("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}",
  1947. hwnd.ClientWindow.ToInt32(),
  1948. xevent.ExposeEvent.x, xevent.ExposeEvent.y,
  1949. xevent.ExposeEvent.width, xevent.ExposeEvent.height);
  1950. #endif
  1951. Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y,
  1952. xevent.ExposeEvent.width, xevent.ExposeEvent.height);
  1953. Region region = new Region (rect);
  1954. IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed
  1955. msg.message = Msg.WM_NCPAINT;
  1956. msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn;
  1957. msg.refobject = region;
  1958. }
  1959. return true;
  1960. case XEventName.DestroyNotify:
  1961. // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children
  1962. hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window);
  1963. // We may get multiple for the same window, act only one the first (when Hwnd still knows about it)
  1964. if ((hwnd != null) && (hwnd.ClientWindow == xevent.DestroyWindowEvent.window)) {
  1965. CleanupCachedWindows (hwnd);
  1966. #if DriverDebugDestroy
  1967. Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.ClientWindow));
  1968. #endif
  1969. msg.hwnd = hwnd.ClientWindow;
  1970. msg.message=Msg.WM_DESTROY;
  1971. hwnd.Dispose();
  1972. }
  1973. else
  1974. goto ProcessNextMessage;
  1975. return true;
  1976. case XEventName.ClientMessage:
  1977. if (Dnd.HandleClientMessage (ref xevent))
  1978. goto ProcessNextMessage;
  1979. if (xevent.ClientMessageEvent.message_type == Atoms.AsyncAtom) {
  1980. XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1);
  1981. goto ProcessNextMessage;
  1982. }
  1983. if (xevent.ClientMessageEvent.message_type == HoverState.Atom) {
  1984. msg.message = Msg.WM_MOUSEHOVER;
  1985. msg.wParam = GetMousewParam(0);
  1986. msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1);
  1987. return true;
  1988. }
  1989. if (xevent.ClientMessageEvent.message_type == Atoms.PostAtom) {
  1990. msg.hwnd = xevent.ClientMessageEvent.ptr1;
  1991. msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 ();
  1992. msg.wParam = xevent.ClientMessageEvent.ptr3;
  1993. msg.lParam = xevent.ClientMessageEvent.ptr4;
  1994. // if we posted a WM_QUIT message, make sure we return
  1995. // false here as well.
  1996. if (msg.message == (Msg)Msg.WM_QUIT)
  1997. return false;
  1998. else
  1999. return true;
  2000. }
  2001. if (xevent.ClientMessageEvent.message_type == Atoms._XEMBED) {
  2002. #if DriverDebugXEmbed
  2003. Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}",
  2004. xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32());
  2005. #endif
  2006. if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) {
  2007. XSizeHints hints = new XSizeHints();
  2008. IntPtr dummy;
  2009. Xlib.XGetWMNormalHints (display, hwnd.WholeWindow, ref hints, out dummy);
  2010. hwnd.width = hints.max_width;
  2011. hwnd.height = hints.max_height;
  2012. hwnd.ClientRect = Rectangle.Empty;
  2013. SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
  2014. }
  2015. }
  2016. if (xevent.ClientMessageEvent.message_type == Atoms.WM_PROTOCOLS) {
  2017. if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_DELETE_WINDOW) {
  2018. msg.message = Msg.WM_CLOSE;
  2019. return true;
  2020. }
  2021. // We should not get this, but I'll leave the code in case we need it in the future
  2022. if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_TAKE_FOCUS) {
  2023. goto ProcessNextMessage;
  2024. }
  2025. }
  2026. goto ProcessNextMessage;
  2027. case XEventName.PropertyNotify:
  2028. // The Hwnd's themselves handle this
  2029. hwnd.PropertyChanged (xevent);
  2030. goto ProcessNextMessage;
  2031. }
  2032. } while (true);
  2033. msg.hwnd= IntPtr.Zero;
  2034. msg.message = Msg.WM_ENTERIDLE;
  2035. return true;
  2036. }
  2037. [MonoTODO("Implement filtering and PM_NOREMOVE")]
  2038. public bool PeekMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags)
  2039. {
  2040. X11ThreadQueue queue = (X11ThreadQueue) queue_id;
  2041. bool pending;
  2042. if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) {
  2043. throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag
  2044. }
  2045. try {
  2046. queue.Lock ();
  2047. pending = false;
  2048. if (queue.CountUnlocked > 0)
  2049. pending = true;
  2050. }
  2051. catch {
  2052. return false;
  2053. }
  2054. finally {
  2055. queue.Unlock ();
  2056. }
  2057. queue.CheckTimers ();
  2058. if (!pending)
  2059. return false;
  2060. return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax);
  2061. }
  2062. public void DoEvents (X11ThreadQueue queue)
  2063. {
  2064. MSG msg = new MSG ();
  2065. if (OverrideCursorHandle != IntPtr.Zero)
  2066. OverrideCursorHandle = IntPtr.Zero;
  2067. queue.DispatchIdle = false;
  2068. while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) {
  2069. TranslateMessage (ref msg);
  2070. DispatchMessage (ref msg);
  2071. }
  2072. queue.DispatchIdle = true;
  2073. }
  2074. // double buffering support
  2075. public void CreateOffscreenDrawable (IntPtr handle,
  2076. int width, int height,
  2077. out object offscreen_drawable)
  2078. {
  2079. IntPtr root_out;
  2080. int x_out, y_out, width_out, height_out, border_width_out, depth_out;
  2081. Xlib.XGetGeometry (display, handle,
  2082. out root_out,
  2083. out x_out, out y_out,
  2084. out width_out, out height_out,
  2085. out border_width_out, out depth_out);
  2086. IntPtr pixmap = Xlib.XCreatePixmap (display, handle, width, height, depth_out);
  2087. offscreen_drawable = pixmap;
  2088. }
  2089. public void DestroyOffscreenDrawable (object offscreen_drawable)
  2090. {
  2091. Xlib.XFreePixmap (display, (IntPtr)offscreen_drawable);
  2092. }
  2093. public Graphics GetOffscreenGraphics (object offscreen_drawable)
  2094. {
  2095. return Graphics.FromHwnd ((IntPtr) offscreen_drawable);
  2096. }
  2097. public void BlitFromOffscreen (IntPtr dest_handle,
  2098. Graphics dest_dc,
  2099. object offscreen_drawable,
  2100. Graphics offscreen_dc,
  2101. Rectangle r)
  2102. {
  2103. XGCValues gc_values;
  2104. IntPtr gc;
  2105. gc_values = new XGCValues();
  2106. gc = Xlib.XCreateGC (display, dest_handle, IntPtr.Zero, ref gc_values);
  2107. Xlib.XCopyArea (display, (IntPtr)offscreen_drawable, dest_handle,
  2108. gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y);
  2109. Xlib.XFreeGC (display, gc);
  2110. }
  2111. // reversible screen-level drawing
  2112. IntPtr GetReversibleScreenGC (Color backColor)
  2113. {
  2114. XGCValues gc_values;
  2115. IntPtr gc;
  2116. uint pixel;
  2117. XColor xcolor = new XColor();
  2118. xcolor.red = (ushort)(backColor.R * 257);
  2119. xcolor.green = (ushort)(backColor.G * 257);
  2120. xcolor.blue = (ushort)(backColor.B * 257);
  2121. Xlib.XAllocColor (display, DefaultColormap, ref xcolor);
  2122. pixel = (uint)xcolor.pixel.ToInt32();
  2123. gc_values = new XGCValues();
  2124. gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors;
  2125. gc_values.foreground = (IntPtr)pixel;
  2126. gc = Xlib.XCreateGC (display, RootWindow.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values);
  2127. Xlib.XSetForeground (display, gc, (UIntPtr)pixel);
  2128. Xlib.XSetFunction (display, gc, GXFunction.GXxor);
  2129. return gc;
  2130. }
  2131. public void DrawReversibleLine (Point start, Point end, Color backColor)
  2132. {
  2133. if (backColor.GetBrightness() < 0.5)
  2134. backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
  2135. IntPtr gc = GetReversibleScreenGC (backColor);
  2136. Xlib.XDrawLine (display, RootWindow.Handle, gc, start.X, start.Y, end.X, end.Y);
  2137. Xlib.XFreeGC (display, gc);
  2138. }
  2139. public void FillReversibleRectangle (Rectangle rectangle, Color backColor)
  2140. {
  2141. if (backColor.GetBrightness() < 0.5)
  2142. backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
  2143. IntPtr gc = GetReversibleScreenGC (backColor);
  2144. if (rectangle.Width < 0) {
  2145. rectangle.X += rectangle.Width;
  2146. rectangle.Width = -rectangle.Width;
  2147. }
  2148. if (rectangle.Height < 0) {
  2149. rectangle.Y += rectangle.Height;
  2150. rectangle.Height = -rectangle.Height;
  2151. }
  2152. Xlib.XFillRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
  2153. Xlib.XFreeGC (display, gc);
  2154. }
  2155. public void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
  2156. {
  2157. if (backColor.GetBrightness() < 0.5)
  2158. backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
  2159. IntPtr gc = GetReversibleScreenGC (backColor);
  2160. if (rectangle.Width < 0) {
  2161. rectangle.X += rectangle.Width;
  2162. rectangle.Width = -rectangle.Width;
  2163. }
  2164. if (rectangle.Height < 0) {
  2165. rectangle.Y += rectangle.Height;
  2166. rectangle.Height = -rectangle.Height;
  2167. }
  2168. int line_width = 1;
  2169. GCLineStyle line_style = GCLineStyle.LineSolid;
  2170. GCCapStyle cap_style = GCCapStyle.CapButt;
  2171. GCJoinStyle join_style = GCJoinStyle.JoinMiter;
  2172. switch (style) {
  2173. case FrameStyle.Dashed:
  2174. line_style = GCLineStyle.LineOnOffDash;
  2175. break;
  2176. case FrameStyle.Thick:
  2177. line_width = 2;
  2178. break;
  2179. }
  2180. Xlib.XSetLineAttributes (display, gc, line_width, line_style, cap_style, join_style);
  2181. Xlib.XDrawRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
  2182. Xlib.XFreeGC (display, gc);
  2183. }
  2184. }
  2185. }