context: // 
  // Carbon.cs
  //  
  // Author:
  //       Michael Hutchinson <mhutchinson@novell.com>
  //       Geoff Norton  <gnorton@novell.com>
  // 
  // Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
  // 
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  // 
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  
  using System;
  using System.Runtime.InteropServices;
  using System.Collections.Generic;
  using System.Diagnostics;
  
  namespace MonoDevelop.MacInterop
  {
  	internal delegate CarbonEventHandlerStatus EventDelegate (IntPtr callRef, IntPtr eventRef, IntPtr userData);
  	internal delegate CarbonEventHandlerStatus AEHandlerDelegate (IntPtr inEvnt, IntPtr outEvt, uint refConst);
  	
  	internal static class Carbon
  	{
  		public const string CarbonLib = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon";
  		
  		[DllImport (CarbonLib)]
  		static extern int Gestalt (int selector, out int result);
  		
  		public static int Gestalt (string selector)
  		{
  			int cc = ConvertCharCode (selector);
  			int result;
  			int ret = Gestalt (cc, out result);
  			CheckReturn (ret);
  			return result;
  		}
  		
  		[DllImport (CarbonLib)]
  		public static extern IntPtr GetApplicationEventTarget ();
  		
  		[DllImport (CarbonLib)]
  		public static extern IntPtr GetControlEventTarget (IntPtr control);
  		
  		[DllImport (CarbonLib)]
  		public static extern IntPtr GetWindowEventTarget (IntPtr window);
  		
  		[DllImport (CarbonLib)]
  		public static extern IntPtr GetMenuEventTarget (IntPtr menu);
  
  		[DllImport (CarbonLib)]
  		public static extern CarbonEventClass GetEventClass (IntPtr eventref);
  		
  		[DllImport (CarbonLib)]
  		public static extern uint GetEventKind (IntPtr eventref);
  		
  		#region Event handler installation
  		
  		[DllImport (CarbonLib)]
  		static extern EventStatus InstallEventHandler (IntPtr target, EventDelegate handler, uint count,
  		                                               CarbonEventTypeSpec [] types, IntPtr user_data, out IntPtr handlerRef);
  		
  		[DllImport (CarbonLib)]
  		public static extern EventStatus RemoveEventHandler (IntPtr handlerRef);
  		
  		public static IntPtr InstallEventHandler (IntPtr target, EventDelegate handler, CarbonEventTypeSpec [] types)
  		{
  			IntPtr handlerRef;
  			CheckReturn (InstallEventHandler (target, handler, (uint)types.Length, types, IntPtr.Zero, out handlerRef));
  			return handlerRef;
  		}
  		
  		public static IntPtr InstallEventHandler (IntPtr target, EventDelegate handler, CarbonEventTypeSpec type)
  		{
  			return InstallEventHandler (target, handler, new CarbonEventTypeSpec[] { type });
  		}
  		
  		public static IntPtr InstallApplicationEventHandler (EventDelegate handler, CarbonEventTypeSpec [] types)
  		{
  			return InstallEventHandler (GetApplicationEventTarget (), handler, types);
  		}
  		
  		public static IntPtr InstallApplicationEventHandler (EventDelegate handler, CarbonEventTypeSpec type)
  		{
  			return InstallEventHandler (GetApplicationEventTarget (), handler, new CarbonEventTypeSpec[] { type });
  		}
  		
  		#endregion
  		
  		#region Event parameter extraction
  		
  		[DllImport (CarbonLib)]
  		public static extern EventStatus GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType,
  		                                                    out CarbonEventParameterType actualType, uint size, ref uint outSize, ref IntPtr outPtr);
  		
  		public static IntPtr GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType)
  		{
  			CarbonEventParameterType actualType;
  			uint outSize = 0;
  			IntPtr val = IntPtr.Zero;
  			CheckReturn (GetEventParameter (eventRef, name, desiredType, out actualType, (uint)IntPtr.Size, ref outSize, ref val));
  			return val;
  		} 
  		
  		[DllImport (CarbonLib)]
  		static extern EventStatus GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType,	
  		                                             out CarbonEventParameterType actualType, uint size, ref uint outSize, IntPtr dataBuffer);
  		  
  		[DllImport (CarbonLib)]
  		static extern EventStatus GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType,	
  		                                             uint zero, uint size, uint zero2, IntPtr dataBuffer);
  		
  		public static T GetEventParameter<T> (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType) where T : struct
  		{
  			int len = Marshal.SizeOf (typeof (T));
  			IntPtr bufferPtr = Marshal.AllocHGlobal (len);
  			CheckReturn (GetEventParameter (eventRef, name, desiredType, 0, (uint)len, 0, bufferPtr));
  			T val = (T)Marshal.PtrToStructure (bufferPtr, typeof (T));
  			Marshal.FreeHGlobal (bufferPtr);
  			return val;
  		}
  		
  		#endregion
  		
  		#region Sending events
  		
  		[DllImport (CarbonLib)]
  		static extern EventStatus SendEventToEventTarget (IntPtr eventRef, IntPtr eventTarget);
  		
  		[DllImport (CarbonLib)]
  		static extern EventStatus CreateEvent (IntPtr allocator, CarbonEventClass classID, uint kind, double eventTime,
  		                                       CarbonEventAttributes flags, out IntPtr eventHandle);
  		
  		[DllImport (CarbonLib)]
  		static extern void ReleaseEvent (IntPtr eventHandle);
  		
  		static EventStatus SendApplicationEvent (CarbonEventClass classID, uint kind, CarbonEventAttributes flags)
  		{
  			IntPtr eventHandle;
  			EventStatus s = CreateEvent (IntPtr.Zero, classID, kind, 0, flags, out eventHandle);
  			if (s != EventStatus.Ok)
  				return s;
  			s = SendEventToEventTarget (eventHandle, GetApplicationEventTarget ());
  			ReleaseEvent (eventHandle);
  			return s;
  		}
  		
  		[DllImport (CarbonLib)]
  		public static extern CarbonEventHandlerStatus ProcessHICommand (ref CarbonHICommand command);
  		
  		#endregion
  		
  		#region Error checking
  		
  		public static void CheckReturn (EventStatus status)
  		{
  			int intStatus = (int) status;
  			if (intStatus < 0)
  				throw new EventStatusException (status);
  		}
  		
  		public static void CheckReturn (int osErr)
  		{
  			if (osErr != 0) {
  				string s = GetMacOSStatusCommentString (osErr);
  				throw new SystemException ("Unexpected OS error code " + osErr + ": " + s);
  			}
  		}
  		
  		[DllImport (CarbonLib)]
  		static extern string GetMacOSStatusCommentString (int osErr);
  		
  		#endregion
  		
  		#region Char code conversion
  		
  		internal static int ConvertCharCode (string fourcc)
  		{
  			Debug.Assert (fourcc != null);
  			Debug.Assert (fourcc.Length == 4);
  			return (fourcc[3]) | (fourcc[2] << 8) | (fourcc[1] << 16) | (fourcc[0] << 24);
  		}
  		
  		internal static string UnConvertCharCode (int i)
  		{
  			return new string (new char[] {
  				(char)(i >> 24),
  				(char)(0xFF & (i >> 16)),
  				(char)(0xFF & (i >> 8)),
  				(char)(0xFF & i),
  			});
  		}
  		
  		#endregion
  		
  		#region Internal Mac API for setting process name
  		
  		[DllImport (CarbonLib)]
  		static extern int GetCurrentProcess (out ProcessSerialNumber psn);
  		
  		[DllImport (CarbonLib)]
  		static extern int CPSSetProcessName (ref ProcessSerialNumber psn, string name);
  		
  		public static void SetProcessName (string name)
  		{
  			try {
  				ProcessSerialNumber psn;
  				if (GetCurrentProcess (out psn) == 0)
  					CPSSetProcessName (ref psn, name);
  			} catch {} //EntryPointNotFoundException?
  		}
  		
  		struct ProcessSerialNumber {
  #pragma warning disable 0169
  			ulong highLongOfPSN;
  			ulong lowLongOfPSN;
  #pragma warning restore 0169
  		}
  		
  		#endregion
  		
  		public static Dictionary<string,int> GetFileListFromEventRef (IntPtr eventRef)
  		{
  			AEDesc list = GetEventParameter<AEDesc> (eventRef, CarbonEventParameterName.DirectObject, CarbonEventParameterType.AEList);
  			try {
  				int line = 0;
  				try {
  					SelectionRange range = GetEventParameter<SelectionRange> (eventRef, CarbonEventParameterName.AEPosition, CarbonEventParameterType.Char);
  					line = range.lineNum+1;
  				} catch {
  				}
  				
  				var arr = AppleEvent.GetListFromAEDesc<string,FSRef> (ref list, CoreFoundation.FSRefToString,
  					(OSType)(int)CarbonEventParameterType.FSRef);
  				var files = new Dictionary<string,int> ();
  				foreach (var s in arr) {
  					if (!string.IsNullOrEmpty (s))
  						files[s] = line;
  				}
  				return files;
  			} finally {
  				CheckReturn ((int)AppleEvent.AEDisposeDesc (ref list));
  			}
  		}
  		
  		public static IList<string> GetUrlListFromEventRef (IntPtr eventRef)
  		{
  			AEDesc list = GetEventParameter<AEDesc> (eventRef, CarbonEventParameterName.DirectObject, CarbonEventParameterType.AEList);
  			try {
  				return AppleEvent.GetUtf8StringListFromAEDesc (ref list, true);
  			} finally {
  				Carbon.CheckReturn ((int)AppleEvent.AEDisposeDesc (ref list));
  			}
  		}
  	}
  	
  	[StructLayout(LayoutKind.Sequential, Pack = 2, Size = 80)]
  	struct FSRef
  	{
  		//this is an 80-char opaque byte array
  		#pragma warning disable 0169
  		private byte hidden;
  		#pragma warning restore 0169
  	}
  	
  	[StructLayout(LayoutKind.Sequential)]
  	struct SelectionRange
  	{
  		public short unused1; // 0 (not used)
  		public short lineNum; // line to select (<0 to specify range)
  		public int startRange; // start of selection range (if line < 0)
  		public int endRange; // end of selection range (if line < 0)
  		public int unused2; // 0 (not used)
  		public int theDate; // modification date/time
  	}
  	
  	internal enum CarbonEventHandlerStatus //this is an OSStatus
  	{
  		Handled = 0,
  		NotHandled = -9874,
  		UserCancelled = -128,
  	}
  	
  	internal enum CarbonEventParameterName : uint
  	{
  		DirectObject = 757935405, // '----'
  		AEPosition = 1802530675, // 'kpos'
  	}
  	
  	internal enum CarbonEventParameterType : uint
  	{
  		HICommand = 1751346532, // 'hcmd'
  		MenuRef = 1835363957, // 'menu'
  		WindowRef = 2003398244, // 'wind'
  		Char = 1413830740, // 'TEXT'
  		UInt32 = 1835100014, // 'magn'
  		UTF8Text = 1970562616, // 'utf8'
  		UnicodeText = 1970567284, // 'utxt'
  		AEList = 1818850164, // 'list'
  		WildCard = 707406378, // '****'
  		FSRef = 1718841958, // 'fsrf' 
  	}
  	
  	internal enum CarbonEventClass : uint
  	{
  		Mouse = 1836021107, // 'mous'
  		Keyboard = 1801812322, // 'keyb'
  		TextInput = 1952807028, // 'text'
  		Application = 1634758764, // 'appl'
  		RemoteAppleEvent = 1701867619,  //'eppc' //remote apple event?
  		Menu = 1835363957, // 'menu'
  		Window = 2003398244, // 'wind'
  		Control = 1668183148, // 'cntl'
  		Command = 1668113523, // 'cmds'
  		Tablet = 1952607348, // 'tblt'
  		Volume = 1987013664, // 'vol '
  		Appearance = 1634758765, // 'appm'
  		Service = 1936028278, // 'serv'
  		Toolbar = 1952604530, // 'tbar'
  		ToolbarItem = 1952606580, // 'tbit'
  		Accessibility = 1633903461, // 'acce'
  		HIObject = 1751740258, // 'hiob'
  		AppleEvent = 1634039412, // 'aevt'
  		Internet = 1196773964, // 'GURL'
  	}
  	
  	public enum CarbonCommandID : uint
  	{
  		OK = 1869291552, // 'ok  '
  		Cancel = 1852797985, // 'not!'
  		Quit = 1903520116, // 'quit'
  		Undo = 1970168943, // 'undo'
  		Redo = 1919247471, // 'redo'
  		Cut = 1668641824, // 'cut '
  		Copy = 1668247673, // 'copy'
  		Paste = 1885434740, // 'past'
  		Clear = 1668048225, // 'clea',
  		SelectAll = 1935764588, // 'sall',
  		Preferences = 1886545254, //'pref'
  		About = 1633841013, // 'abou'
  		New = 1852143392, // 'new ',
  		Open = 1869636974, // 'open'
  		Close = 1668050803, // 'clos'
  		Save = 1935767141, // 'save',
  		SaveAs = 1937138035, // 'svas'
  		Revert = 1920365172, // 'rvrt'
  		Print = 1886547572, // 'prnt'
  		PageSetup = 1885431653, // 'page',
  		AppHelp = 1634233456, //'ahlp'
  		
  		//menu manager handles these automatically
  		
  		Hide = 1751737445, // 'hide'
  		HideOthers = 1751737455, // 'hido'
  		ShowAll = 1936220524, // 'shal'
  		ZoomWindow = 2054123373, // 'zoom'
  		MinimizeWindow = 1835626089, // 'mini'
  		MinimizeAll = 1835626081, // 'mina'
  		MaximizeAll = 1835104353, // 'maxa'
  
gt: 		ArrangeInFront = 1718775412, // 'frnt'