5
// Michael Hutchinson <mhutchinson@novell.com>
6
// Geoff Norton <gnorton@novell.com>
8
// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
10
// Permission is hereby granted, free of charge, to any person obtaining a copy
11
// of this software and associated documentation files (the "Software"), to deal
12
// in the Software without restriction, including without limitation the rights
13
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
// copies of the Software, and to permit persons to whom the Software is
15
// furnished to do so, subject to the following conditions:
17
// The above copyright notice and this permission notice shall be included in
18
// all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using System.Runtime.InteropServices;
30
using System.Collections.Generic;
32
#pragma warning disable 0169
34
namespace OsxIntegration.Framework
36
internal delegate CarbonEventHandlerStatus EventDelegate (IntPtr callRef, IntPtr eventRef, IntPtr userData);
37
internal delegate CarbonEventHandlerStatus AEHandlerDelegate (IntPtr inEvnt, IntPtr outEvt, uint refConst);
39
internal static class Carbon
41
public const string CarbonLib = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon";
43
[DllImport (CarbonLib)]
44
public static extern IntPtr GetApplicationEventTarget ();
46
[DllImport (CarbonLib)]
47
public static extern IntPtr GetControlEventTarget (IntPtr control);
49
[DllImport (CarbonLib)]
50
public static extern IntPtr GetWindowEventTarget (IntPtr window);
52
[DllImport (CarbonLib)]
53
public static extern IntPtr GetMenuEventTarget (IntPtr menu);
55
[DllImport (CarbonLib)]
56
public static extern CarbonEventClass GetEventClass (IntPtr eventref);
58
[DllImport (CarbonLib)]
59
public static extern uint GetEventKind (IntPtr eventref);
61
#region Event handler installation
63
[DllImport (CarbonLib)]
64
static extern EventStatus InstallEventHandler (IntPtr target, EventDelegate handler, uint count,
65
CarbonEventTypeSpec [] types, IntPtr user_data, out IntPtr handlerRef);
67
[DllImport (CarbonLib)]
68
public static extern EventStatus RemoveEventHandler (IntPtr handlerRef);
70
public static IntPtr InstallEventHandler (IntPtr target, EventDelegate handler, CarbonEventTypeSpec [] types)
73
CheckReturn (InstallEventHandler (target, handler, (uint)types.Length, types, IntPtr.Zero, out handlerRef));
77
public static IntPtr InstallEventHandler (IntPtr target, EventDelegate handler, CarbonEventTypeSpec type)
79
return InstallEventHandler (target, handler, new CarbonEventTypeSpec[] { type });
82
public static IntPtr InstallApplicationEventHandler (EventDelegate handler, CarbonEventTypeSpec [] types)
84
return InstallEventHandler (GetApplicationEventTarget (), handler, types);
87
public static IntPtr InstallApplicationEventHandler (EventDelegate handler, CarbonEventTypeSpec type)
89
return InstallEventHandler (GetApplicationEventTarget (), handler, new CarbonEventTypeSpec[] { type });
94
#region Event parameter extraction
96
[DllImport (CarbonLib)]
97
public static extern EventStatus GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType,
98
out CarbonEventParameterType actualType, uint size, ref uint outSize, ref IntPtr outPtr);
100
public static IntPtr GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType)
102
CarbonEventParameterType actualType;
104
IntPtr val = IntPtr.Zero;
105
CheckReturn (GetEventParameter (eventRef, name, desiredType, out actualType, (uint)IntPtr.Size, ref outSize, ref val));
109
[DllImport (CarbonLib)]
110
static extern EventStatus GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType,
111
out CarbonEventParameterType actualType, uint size, ref uint outSize, IntPtr dataBuffer);
113
[DllImport (CarbonLib)]
114
static extern EventStatus GetEventParameter (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType,
115
uint zero, uint size, uint zero2, IntPtr dataBuffer);
117
public static T GetEventParameter<T> (IntPtr eventRef, CarbonEventParameterName name, CarbonEventParameterType desiredType) where T : struct
119
int len = Marshal.SizeOf (typeof (T));
120
IntPtr bufferPtr = Marshal.AllocHGlobal (len);
121
CheckReturn (GetEventParameter (eventRef, name, desiredType, 0, (uint)len, 0, bufferPtr));
122
T val = (T)Marshal.PtrToStructure (bufferPtr, typeof (T));
123
Marshal.FreeHGlobal (bufferPtr);
129
#region Sending events
131
[DllImport (CarbonLib)]
132
static extern EventStatus SendEventToEventTarget (IntPtr eventRef, IntPtr eventTarget);
134
[DllImport (CarbonLib)]
135
static extern EventStatus CreateEvent (IntPtr allocator, CarbonEventClass classID, uint kind, double eventTime,
136
CarbonEventAttributes flags, out IntPtr eventHandle);
138
[DllImport (CarbonLib)]
139
static extern void ReleaseEvent (IntPtr eventHandle);
141
static EventStatus SendApplicationEvent (CarbonEventClass classID, uint kind, CarbonEventAttributes flags)
144
EventStatus s = CreateEvent (IntPtr.Zero, classID, kind, 0, flags, out eventHandle);
145
if (s != EventStatus.Ok)
147
s = SendEventToEventTarget (eventHandle, GetApplicationEventTarget ());
148
ReleaseEvent (eventHandle);
152
[DllImport (CarbonLib)]
153
public static extern CarbonEventHandlerStatus ProcessHICommand (ref CarbonHICommand command);
157
#region AEList manipulation
159
[DllImport (CarbonLib)]
160
static extern int AECountItems (ref AEDesc descList, out int count); //return an OSErr
162
public static int AECountItems (ref AEDesc descList)
165
CheckReturn (AECountItems (ref descList, out count));
169
[DllImport (CarbonLib)]
170
static extern AEDescStatus AEGetNthPtr (ref AEDesc descList, int index, CarbonEventParameterType desiredType, uint keyword,
171
out CarbonEventParameterType actualType, IntPtr buffer, int bufferSize, out int actualSize);
173
[DllImport (CarbonLib)]
174
static extern AEDescStatus AEGetNthPtr (ref AEDesc descList, int index, CarbonEventParameterType desiredType, uint keyword,
175
uint zero, IntPtr buffer, int bufferSize, int zero2);
177
public static T AEGetNthPtr<T> (ref AEDesc descList, int index, CarbonEventParameterType desiredType) where T : struct
179
int len = Marshal.SizeOf (typeof (T));
180
IntPtr bufferPtr = Marshal.AllocHGlobal (len);
182
CheckReturn ((int)AEGetNthPtr (ref descList, index, desiredType, 0, 0, bufferPtr, len, 0));
183
T val = (T)Marshal.PtrToStructure (bufferPtr, typeof (T));
186
Marshal.FreeHGlobal (bufferPtr);
190
[DllImport (CarbonLib)]
191
static extern AEDescStatus AEGetNthPtr (ref AEDesc descList, int index, CarbonEventParameterType desiredType, uint keyword,
192
uint zero, out IntPtr outPtr, int bufferSize, int zero2);
194
public static IntPtr AEGetNthPtr (ref AEDesc descList, int index, CarbonEventParameterType desiredType)
197
CheckReturn ((int)AEGetNthPtr (ref descList, index, desiredType, 0, 0, out ret, 4, 0));
201
[DllImport (CarbonLib)]
202
public static extern int AEDisposeDesc (ref AEDesc desc);
204
[DllImport (CarbonLib)]
205
public static extern AEDescStatus AESizeOfNthItem (ref AEDesc descList, int index, ref CarbonEventParameterType type, out int size);
207
//FIXME: this might not work in some encodings. need to test more.
208
static string GetStringFromAEPtr (ref AEDesc descList, int index)
211
CarbonEventParameterType type = CarbonEventParameterType.UnicodeText;
212
if (AESizeOfNthItem (ref descList, index, ref type, out size) == AEDescStatus.Ok) {
213
IntPtr buffer = Marshal.AllocHGlobal (size);
215
if (AEGetNthPtr (ref descList, index, type, 0, 0, buffer, size, 0) == AEDescStatus.Ok)
216
return Marshal.PtrToStringAuto (buffer, size);
218
Marshal.FreeHGlobal (buffer);
226
[DllImport (CarbonLib)]
227
static extern int FSRefMakePath (ref FSRef fsRef, IntPtr buffer, uint bufferSize);
229
public static string FSRefToPath (ref FSRef fsRef)
231
//FIXME: is this big enough?
232
const int MAX_LENGTH = 4096;
233
IntPtr buf = IntPtr.Zero;
236
buf = Marshal.AllocHGlobal (MAX_LENGTH);
237
CheckReturn (FSRefMakePath (ref fsRef, buf, (uint)MAX_LENGTH));
238
//FIXME: on Mono, auto is UTF-8, which is correct but I'd prefer to be more explicit
239
ret = Marshal.PtrToStringAuto (buf, MAX_LENGTH);
241
if (buf != IntPtr.Zero)
242
Marshal.FreeHGlobal (buf);
247
#region Error checking
249
public static void CheckReturn (EventStatus status)
251
int intStatus = (int) status;
253
throw new EventStatusException (status);
256
public static void CheckReturn (int osErr)
259
string s = GetMacOSStatusCommentString (osErr);
260
throw new SystemException ("Unexpected OS error code " + osErr + ": " + s);
264
[DllImport (CarbonLib)]
265
static extern string GetMacOSStatusCommentString (int osErr);
269
#region Char code conversion
271
internal static int ConvertCharCode (string code)
273
return (code[3]) | (code[2] << 8) | (code[1] << 16) | (code[0] << 24);
276
internal static string UnConvertCharCode (int i)
278
return new string (new char[] {
280
(char)(0xFF & (i >> 16)),
281
(char)(0xFF & (i >> 8)),
288
#region Navigation services
290
[DllImport (CarbonLib)]
291
static extern NavStatus NavDialogSetFilterTypeIdentifiers (IntPtr getFileDialogRef, IntPtr typeIdentifiersCFArray);
294
[DllImport (CarbonLib)]
295
static extern NavEventUPP NewNavEventUPP (NavEventProc userRoutine);
297
[DllImport (CarbonLib)]
298
static extern NavObjectFilterUPP NewNavObjectFilterUPP (NavObjectFilterProc userRoutine);
300
[DllImport (CarbonLib)]
301
static extern NavPreviewUPP NewNavPreviewUPP (NavPreviewProc userRoutine);
303
delegate void NavEventProc (NavEventCallbackMessage callBackSelector, ref NavCBRec callBackParms, IntPtr callBackUD);
305
delegate bool NavObjectFilterProc (ref AEDesc theItem, IntPtr info, IntPtr callBackUD, NavFilterModes filterMode);
307
delegate bool NavPreviewProc (ref NavCBRec callBackParms, IntPtr callBackUD);
309
[DllImport (CarbonLib)]
310
static extern void DisposeNavEventUPP (NavEventUPP userUPP);
312
[DllImport (CarbonLib)]
313
static extern void DisposeNavObjectFilterUPP (NavObjectFilterUPP userUPP);
315
[DllImport (CarbonLib)]
316
static extern void DisposeNavPreviewUPP (NavPreviewUPP userUPP);
320
#region Internal Mac API for setting process name
322
[DllImport (CarbonLib)]
323
static extern int GetCurrentProcess (out ProcessSerialNumber psn);
325
[DllImport (CarbonLib)]
326
static extern int CPSSetProcessName (ref ProcessSerialNumber psn, string name);
328
public static void SetProcessName (string name)
331
ProcessSerialNumber psn;
332
if (GetCurrentProcess (out psn) == 0)
333
CPSSetProcessName (ref psn, name);
334
} catch {} //EntryPointNotFoundException?
337
struct ProcessSerialNumber {
344
public static List<string> GetFileListFromEventRef (IntPtr eventRef)
346
AEDesc list = GetEventParameter<AEDesc> (eventRef, CarbonEventParameterName.DirectObject, CarbonEventParameterType.AEList);
347
long count = AECountItems (ref list);
348
var files = new List<string> ();
349
for (int i = 1; i <= count; i++) {
350
FSRef fsRef = AEGetNthPtr<FSRef> (ref list, i, CarbonEventParameterType.FSRef);
351
string file = FSRefToPath (ref fsRef);
352
if (!string.IsNullOrEmpty (file))
355
CheckReturn (AEDisposeDesc (ref list));
359
public static List<string> GetUrlListFromEventRef (IntPtr eventRef)
361
AEDesc list = GetEventParameter<AEDesc> (eventRef, CarbonEventParameterName.DirectObject, CarbonEventParameterType.AEList);
362
long count = AECountItems (ref list);
363
var files = new List<string> ();
364
for (int i = 1; i <= count; i++) {
365
string url = GetStringFromAEPtr (ref list, i);
366
if (!string.IsNullOrEmpty (url))
369
Carbon.CheckReturn (Carbon.AEDisposeDesc (ref list));
375
[StructLayout(LayoutKind.Sequential, Pack = 2)]
382
[StructLayout(LayoutKind.Sequential, Pack = 2, Size = 80)]
385
//this is an 80-char opaque byte array
389
internal enum CarbonEventHandlerStatus //this is an OSStatus
395
internal enum CarbonEventParameterName : uint
397
DirectObject = 757935405, // '----'
400
internal enum CarbonEventParameterType : uint
402
HICommand = 1751346532, // 'hcmd'
403
MenuRef = 1835363957, // 'menu'
404
WindowRef = 2003398244, // 'wind'
405
Char = 1413830740, // 'TEXT'
406
UInt32 = 1835100014, // 'magn'
407
UnicodeText = 1970567284, // 'utxt'
408
AEList = 1818850164, // 'list'
409
WildCard = 707406378, // '****'
410
FSRef = 1718841958, // 'fsrf'
413
internal enum CarbonEventClass : uint
415
Mouse = 1836021107, // 'mous'
416
Keyboard = 1801812322, // 'keyb'
417
TextInput = 1952807028, // 'text'
418
Application = 1634758764, // 'appl'
419
RemoteAppleEvent = 1701867619, //'eppc' //remote apple event?
420
Menu = 1835363957, // 'menu'
421
Window = 2003398244, // 'wind'
422
Control = 1668183148, // 'cntl'
423
Command = 1668113523, // 'cmds'
424
Tablet = 1952607348, // 'tblt'
425
Volume = 1987013664, // 'vol '
426
Appearance = 1634758765, // 'appm'
427
Service = 1936028278, // 'serv'
428
Toolbar = 1952604530, // 'tbar'
429
ToolbarItem = 1952606580, // 'tbit'
430
Accessibility = 1633903461, // 'acce'
431
HIObject = 1751740258, // 'hiob'
432
AppleEvent = 1634039412, // 'aevt'
433
Internet = 1196773964, // 'GURL'
436
public enum CarbonCommandID : uint
438
OK = 1869291552, // 'ok '
439
Cancel = 1852797985, // 'not!'
440
Quit = 1903520116, // 'quit'
441
Undo = 1970168943, // 'undo'
442
Redo = 1919247471, // 'redo'
443
Cut = 1668641824, // 'cut '
444
Copy = 1668247673, // 'copy'
445
Paste = 1885434740, // 'past'
446
Clear = 1668048225, // 'clea',
447
SelectAll = 1935764588, // 'sall',
448
Preferences = 1886545254, //'pref'
449
About = 1633841013, // 'abou'
450
New = 1852143392, // 'new ',
451
Open = 1869636974, // 'open'
452
Close = 1668050803, // 'clos'
453
Save = 1935767141, // 'save',
454
SaveAs = 1937138035, // 'svas'
455
Revert = 1920365172, // 'rvrt'
456
Print = 1886547572, // 'prnt'
457
PageSetup = 1885431653, // 'page',
458
AppHelp = 1634233456, //'ahlp'
460
//menu manager handles these automatically
462
Hide = 1751737445, // 'hide'
463
HideOthers = 1751737455, // 'hido'
464
ShowAll = 1936220524, // 'shal'
465
ZoomWindow = 2054123373, // 'zoom'
466
MinimizeWindow = 1835626089, // 'mini'
467
MinimizeAll = 1835626081, // 'mina'
468
MaximizeAll = 1835104353, // 'maxa'
469
ArrangeInFront = 1718775412, // 'frnt'
470
BringAllToFront = 1650881140, // 'bfrt'
471
SelectWindow = 1937205614, // 'swin'
472
RotateWindowsForward = 1919906935, // 'rotw'
473
RotateWindowsBackward = 1919906914, // 'rotb'
474
RotateFloatingWindowsForward = 1920231031, // 'rtfw'
475
RotateFloatingWindowsBackward = 1920231010, // 'rtfb'
477
//created automatically -- used for inserting before/after the default window list
478
WindowListSeparator = 2003592310, // 'wldv'
479
WindowListTerminator = 2003596148, // 'wlst'
482
internal enum CarbonEventCommand : uint
488
internal enum CarbonEventMenu : uint
492
ChangeTrackingMode = 3,
499
internal enum CarbonEventAttributes : uint
502
UserEvent = (1 << 0),
506
internal enum CarbonEventApple
508
OpenApplication = 1868656752, // 'oapp'
509
ReopenApplication = 1918988400, //'rapp'
510
OpenDocuments = 1868853091, // 'odoc'
511
PrintDocuments = 188563030, // 'pdoc'
512
OpenContents = 1868787566, // 'ocon'
513
QuitApplication = 1903520116, // 'quit'
514
ShowPreferences = 1886545254, // 'pref'
515
ApplicationDied = 1868720500, // 'obit'
516
GetUrl = 1196773964, // 'GURL'
519
[StructLayout(LayoutKind.Sequential, Pack = 2)]
520
struct CarbonEventTypeSpec
522
public CarbonEventClass EventClass;
523
public uint EventKind;
525
public CarbonEventTypeSpec (CarbonEventClass eventClass, UInt32 eventKind)
527
this.EventClass = eventClass;
528
this.EventKind = eventKind;
531
public CarbonEventTypeSpec (CarbonEventMenu kind) : this (CarbonEventClass.Menu, (uint) kind)
535
public CarbonEventTypeSpec (CarbonEventCommand kind) : this (CarbonEventClass.Command, (uint) kind)
540
public CarbonEventTypeSpec (CarbonEventApple kind) : this (CarbonEventClass.AppleEvent, (uint) kind)
544
public static implicit operator CarbonEventTypeSpec (CarbonEventMenu kind)
546
return new CarbonEventTypeSpec (kind);
549
public static implicit operator CarbonEventTypeSpec (CarbonEventCommand kind)
551
return new CarbonEventTypeSpec (kind);
554
public static implicit operator CarbonEventTypeSpec (CarbonEventApple kind)
556
return new CarbonEventTypeSpec (kind);
560
class EventStatusException : SystemException
562
public EventStatusException (EventStatus status)
567
public EventStatus StatusCode {
572
enum EventStatus // this is an OSStatus
577
EventAlreadyPostedErr = -9860,
578
EventTargetBusyErr = -9861,
579
EventClassInvalidErr = -9862,
580
EventClassIncorrectErr = -9864,
581
EventHandlerAlreadyInstalledErr = -9866,
582
EventInternalErr = -9868,
583
EventKindIncorrectErr = -9869,
584
EventParameterNotFoundErr = -9870,
585
EventNotHandledErr = -9874,
586
EventLoopTimedOutErr = -9875,
587
EventLoopQuitErr = -9876,
588
EventNotInQueueErr = -9877,
589
EventHotKeyExistsErr = -9878,
590
EventHotKeyInvalidErr = -9879,
597
CoercionFail = -1700,
598
DescRecordNotFound = -1701,
599
WrongDataType = -1703,
601
ReplyNotArrived = -1718,
604
[StructLayout(LayoutKind.Explicit)]
605
struct CarbonHICommand //technically HICommandExtended, but they're compatible
608
CarbonHICommandAttributes attributes;
622
public CarbonHICommand (uint commandID, HIMenuItem item)
624
windowRef = controlRef = IntPtr.Zero;
625
this.commandID = commandID;
626
this.menuItem = item;
627
this.attributes = CarbonHICommandAttributes.FromMenu;
630
public CarbonHICommandAttributes Attributes { get { return attributes; } }
631
public uint CommandID { get { return commandID; } }
632
public IntPtr ControlRef { get { return controlRef; } }
633
public IntPtr WindowRef { get { return windowRef; } }
634
public HIMenuItem MenuItem { get { return menuItem; } }
636
public bool IsFromMenu {
637
get { return attributes == CarbonHICommandAttributes.FromMenu; }
640
public bool IsFromControl {
641
get { return attributes == CarbonHICommandAttributes.FromControl; }
644
public bool IsFromWindow {
645
get { return attributes == CarbonHICommandAttributes.FromWindow; }
649
[StructLayout(LayoutKind.Sequential, Pack = 2)]
655
public HIMenuItem (IntPtr menuRef, ushort index)
658
this.menuRef = menuRef;
661
public IntPtr MenuRef { get { return menuRef; } }
662
public ushort Index { get { return index; } }
666
enum CarbonHICommandAttributes : uint
669
FromControl = 1 << 1,
673
[StructLayout(LayoutKind.Sequential, Pack = 2)]
674
struct FileTranslationSpec
676
uint componentSignature; // OSType
677
IntPtr translationSystemInfo; // void*
682
[StructLayout(LayoutKind.Sequential, Pack = 2)]
685
uint format; // FileType
687
TranslationAttributes flags;
688
uint catInfoType; // OSType
689
uint catInfoCreator; // OSType