PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/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

Large files files are truncated, but you can click here to view the full file

  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

Large files files are truncated, but you can click here to view the full file