menu_darwin.m 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. //go:build !no_native_menus
  2. // +build !no_native_menus
  3. #import <Foundation/Foundation.h>
  4. #import <AppKit/AppKit.h>
  5. const int menuTagMin = 5000;
  6. #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
  7. NSControlStateValue STATE_ON = NSControlStateValueOn;
  8. NSControlStateValue STATE_OFF = NSControlStateValueOff;
  9. #else
  10. NSCellStateValue STATE_ON = NSOnState;
  11. NSCellStateValue STATE_OFF = NSOffState;
  12. #endif
  13. extern void menuCallback(int);
  14. extern BOOL menuEnabled(int);
  15. extern BOOL menuChecked(int);
  16. extern void exceptionCallback(const char*);
  17. @interface FyneMenuHandler : NSObject {
  18. }
  19. @end
  20. @implementation FyneMenuHandler
  21. + (void) tapped:(NSMenuItem*) item {
  22. menuCallback([item tag]-menuTagMin);
  23. }
  24. + (BOOL) validateMenuItem:(NSMenuItem*) item {
  25. BOOL checked = menuChecked([item tag]-menuTagMin);
  26. if (checked) {
  27. [item setState:STATE_ON];
  28. } else {
  29. [item setState:STATE_OFF];
  30. }
  31. return menuEnabled([item tag]-menuTagMin);
  32. }
  33. @end
  34. // forward declaration … we want methods to be ordered alphabetically
  35. NSMenu* nativeMainMenu();
  36. void assignDarwinSubmenu(const void* i, const void* m) {
  37. NSMenu* menu = (NSMenu*)m; // this menu is created in the createDarwinMenu() function
  38. NSMenuItem *item = (NSMenuItem*)i;
  39. [item setSubmenu:menu]; // this retains the menu
  40. [menu release]; // release the menu
  41. }
  42. void completeDarwinMenu(const void* m, bool prepend) {
  43. NSMenu* main = nativeMainMenu();
  44. NSMenuItem* top = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
  45. [top setTag:menuTagMin];
  46. if (prepend) {
  47. [main insertItem:top atIndex:1];
  48. } else {
  49. [main addItem:top];
  50. }
  51. assignDarwinSubmenu(top, m);
  52. }
  53. const void* createDarwinMenu(const char* label) {
  54. return (void*)[[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:label]];
  55. }
  56. const void* darwinAppMenu() {
  57. return [[nativeMainMenu() itemAtIndex:0] submenu];
  58. }
  59. void getTextColorRGBA(int* r, int* g, int* b, int* a) {
  60. CGFloat fr, fg, fb, fa;
  61. NSColor *c = [[NSColor selectedMenuItemTextColor] colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
  62. [c getRed: &fr green: &fg blue: &fb alpha: &fa];
  63. *r = fr*255.0;
  64. *g = fg*255.0;
  65. *b = fb*255.0;
  66. *a = fa*255.0;
  67. }
  68. void handleException(const char* m, id e) {
  69. exceptionCallback([[NSString stringWithFormat:@"%s failed: %@", m, e] UTF8String]);
  70. }
  71. const void* insertDarwinMenuItem(const void* m, const char* label, const char* keyEquivalent, unsigned int keyEquivalentModifierMask, int id, int index, bool isSeparator, const void *imageData, unsigned int imageDataLength) {
  72. NSMenu* menu = (NSMenu*)m;
  73. NSMenuItem* item;
  74. if (isSeparator) {
  75. item = [NSMenuItem separatorItem];
  76. } else {
  77. item = [[NSMenuItem alloc]
  78. initWithTitle:[NSString stringWithUTF8String:label]
  79. action:@selector(tapped:)
  80. keyEquivalent:[NSString stringWithUTF8String:keyEquivalent]];
  81. if (keyEquivalentModifierMask) {
  82. [item setKeyEquivalentModifierMask: keyEquivalentModifierMask];
  83. }
  84. [item setTarget:[FyneMenuHandler class]];
  85. [item setTag:id+menuTagMin];
  86. if (imageData) {
  87. char *x = (char *)imageData;
  88. NSData *data = [[NSData alloc] initWithBytes: imageData length: imageDataLength];
  89. NSImage *image = [[NSImage alloc] initWithData: data];
  90. [item setImage: image];
  91. [data release];
  92. [image release];
  93. }
  94. }
  95. if (index > -1) {
  96. [menu insertItem:item atIndex:index];
  97. } else {
  98. [menu addItem:item];
  99. }
  100. [item release]; // retained by the menu
  101. return item;
  102. }
  103. int menuFontSize() {
  104. return ceil([[NSFont menuFontOfSize: 0] pointSize]);
  105. }
  106. NSMenu* nativeMainMenu() {
  107. NSApplication* app = [NSApplication sharedApplication];
  108. return [app mainMenu];
  109. }
  110. void resetDarwinMenu() {
  111. NSMenu *root = nativeMainMenu();
  112. NSEnumerator *items = [[root itemArray] objectEnumerator];
  113. id object;
  114. while (object = [items nextObject]) {
  115. NSMenuItem *item = object;
  116. if ([item tag] < menuTagMin) {
  117. // check for inserted items (like Settings...)
  118. NSMenu *menu = [item submenu];
  119. NSEnumerator *subItems = [[menu itemArray] objectEnumerator];
  120. id sub;
  121. while (sub = [subItems nextObject]) {
  122. NSMenuItem *item = sub;
  123. if ([item tag] >= menuTagMin) {
  124. [menu removeItem: item];
  125. }
  126. }
  127. continue;
  128. }
  129. [root removeItem: item];
  130. }
  131. }
  132. const void* test_darwinMainMenu() {
  133. return nativeMainMenu();
  134. }
  135. const void* test_NSMenu_itemAtIndex(const void* m, NSInteger i) {
  136. NSMenu* menu = (NSMenu*)m;
  137. @try {
  138. return [menu itemAtIndex: i];
  139. } @catch(NSException* e) {
  140. handleException("test_NSMenu_itemAtIndex", e);
  141. return NULL;
  142. }
  143. }
  144. NSInteger test_NSMenu_numberOfItems(const void* m) {
  145. NSMenu* menu = (NSMenu*)m;
  146. return [menu numberOfItems];
  147. }
  148. void test_NSMenu_performActionForItemAtIndex(const void* m, NSInteger i) {
  149. NSMenu* menu = (NSMenu*)m;
  150. @try {
  151. // Using performActionForItemAtIndex: would be better but sadly it crashes.
  152. // We simulate the relevant effect for now.
  153. // [menu performActionForItemAtIndex:i];
  154. NSMenuItem* item = [menu itemAtIndex:i];
  155. [[item target] performSelector:[item action] withObject:item];
  156. } @catch(NSException* e) {
  157. handleException("test_NSMenu_performActionForItemAtIndex", e);
  158. }
  159. }
  160. void test_NSMenu_removeItemAtIndex(const void* m, NSInteger i) {
  161. NSMenu* menu = (NSMenu*)m;
  162. @try {
  163. [menu removeItemAtIndex: i];
  164. } @catch(NSException* e) {
  165. handleException("test_NSMenu_removeItemAtIndex", e);
  166. }
  167. }
  168. const char* test_NSMenu_title(const void* m) {
  169. NSMenu* menu = (NSMenu*)m;
  170. return [[menu title] UTF8String];
  171. }
  172. bool test_NSMenuItem_isSeparatorItem(const void* i) {
  173. NSMenuItem* item = (NSMenuItem*)i;
  174. return [item isSeparatorItem];
  175. }
  176. const char* test_NSMenuItem_keyEquivalent(const void *i) {
  177. NSMenuItem* item = (NSMenuItem*)i;
  178. return [[item keyEquivalent] UTF8String];
  179. }
  180. unsigned long test_NSMenuItem_keyEquivalentModifierMask(const void *i) {
  181. NSMenuItem* item = (NSMenuItem*)i;
  182. return [item keyEquivalentModifierMask];
  183. }
  184. const void* test_NSMenuItem_submenu(const void* i) {
  185. NSMenuItem* item = (NSMenuItem*)i;
  186. return [item submenu];
  187. }
  188. const char* test_NSMenuItem_title(const void* i) {
  189. NSMenuItem* item = (NSMenuItem*)i;
  190. return [[item title] UTF8String];
  191. }