4 * These calls set up the default menus for Tk.
6 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
7 * Copyright 2001-2009, Apple Inc.
8 * Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 #include "tkMacOSXPrivate.h"
16 #include "tkMacOSXConstants.h"
18 static void GenerateEditEvent(const char *name);
19 static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
22 #pragma mark TKApplication(TKMenus)
24 @implementation TKApplication(TKMenus)
27 if (_defaultMainMenu) {
32 NSString *applicationName = [[NSBundle mainBundle]
33 objectForInfoDictionaryKey:@"CFBundleName"];
35 if (!applicationName) {
36 applicationName = [[NSProcessInfo processInfo] processName];
39 NSString *aboutName = (applicationName &&
40 ![applicationName isEqualToString:@"Wish"] &&
41 ![applicationName hasPrefix:@"tclsh"]) ?
42 applicationName : @"Tcl & Tk";
44 _servicesMenu = [NSMenu menuWithTitle:@"Services"];
45 _defaultApplicationMenuItems = [[NSArray arrayWithObjects:
46 [NSMenuItem separatorItem],
47 [NSMenuItem itemWithTitle:
48 [NSString stringWithFormat:@"Preferences%C", 0x2026]
49 action:@selector(preferences:) keyEquivalent:@","],
50 [NSMenuItem separatorItem],
51 [NSMenuItem itemWithTitle:@"Services" submenu:_servicesMenu],
52 [NSMenuItem separatorItem],
53 [NSMenuItem itemWithTitle:
54 [NSString stringWithFormat:@"Hide %@", applicationName]
55 action:@selector(hide:) keyEquivalent:@"h"],
56 [NSMenuItem itemWithTitle:@"Hide Others"
57 action:@selector(hideOtherApplications:) keyEquivalent:@"h"
58 keyEquivalentModifierMask:
59 NSCommandKeyMask|NSAlternateKeyMask],
60 [NSMenuItem itemWithTitle:@"Show All"
61 action:@selector(unhideAllApplications:)],
62 [NSMenuItem separatorItem],
63 [NSMenuItem itemWithTitle:
64 [NSString stringWithFormat:@"Quit %@", applicationName]
65 action: @selector(terminate:) keyEquivalent:@"q"],
67 _defaultApplicationMenu = [TKMenu menuWithTitle:applicationName
68 menuItems:_defaultApplicationMenuItems];
69 [_defaultApplicationMenu insertItem:
70 [NSMenuItem itemWithTitle:
71 [NSString stringWithFormat:@"About %@", aboutName]
72 action:@selector(orderFrontStandardAboutPanel:)] atIndex:0];
73 _defaultFileMenuItems =
74 [[NSArray arrayWithObjects:
75 [NSMenuItem itemWithTitle:
76 [NSString stringWithFormat:@"Source%C", 0x2026]
77 action:@selector(tkSource:)],
78 [NSMenuItem itemWithTitle:@"Run Widget Demo"
79 action:@selector(tkDemo:)],
80 [NSMenuItem itemWithTitle:@"Close" action:@selector(performClose:)
81 target:nil keyEquivalent:@"w"],
83 _demoMenuItem = [_defaultFileMenuItems objectAtIndex:1];
84 TKMenu *fileMenu = [TKMenu menuWithTitle:@"File"
85 menuItems: _defaultFileMenuItems];
86 TKMenu *editMenu = [TKMenu menuWithTitle:@"Edit" menuItems:
87 [NSArray arrayWithObjects:
88 [NSMenuItem itemWithTitle:@"Undo" action:@selector(undo:)
89 target:nil keyEquivalent:@"z"],
90 [NSMenuItem itemWithTitle:@"Redo" action:@selector(redo:)
91 target:nil keyEquivalent:@"y"],
92 [NSMenuItem separatorItem],
93 [NSMenuItem itemWithTitle:@"Cut" action:@selector(cut:)
94 target:nil keyEquivalent:@"x"],
95 [NSMenuItem itemWithTitle:@"Copy" action:@selector(copy:)
96 target:nil keyEquivalent:@"c"],
97 [NSMenuItem itemWithTitle:@"Paste" action:@selector(paste:)
98 target:nil keyEquivalent:@"v"],
99 [NSMenuItem itemWithTitle:@"Delete" action:@selector(delete:)
103 _defaultWindowsMenuItems = [NSArray arrayWithObjects:
104 [NSMenuItem itemWithTitle:@"Minimize"
105 action:@selector(performMiniaturize:) target:nil
107 [NSMenuItem itemWithTitle:@"Zoom" action:@selector(performZoom:)
112 * On OS X 10.12 we get duplicate tab control items if we create them here.
115 if ([NSApp macOSVersion] > 101200) {
116 _defaultWindowsMenuItems = [_defaultWindowsMenuItems
117 arrayByAddingObjectsFromArray:
118 [NSArray arrayWithObjects:
119 [NSMenuItem separatorItem],
120 [NSMenuItem itemWithTitle:@"Show Previous Tab"
121 action:@selector(selectPreviousTab:)
124 keyEquivalentModifierMask:
125 NSControlKeyMask|NSShiftKeyMask],
126 [NSMenuItem itemWithTitle:@"Show Next Tab"
127 action:@selector(selectNextTab:)
130 keyEquivalentModifierMask:NSControlKeyMask],
131 [NSMenuItem itemWithTitle:@"Move Tab To New Window"
132 action:@selector(moveTabToNewWindow:)
134 [NSMenuItem itemWithTitle:@"Merge All Windows"
135 action:@selector(mergeAllWindows:)
137 [NSMenuItem separatorItem],
140 _defaultWindowsMenuItems = [_defaultWindowsMenuItems arrayByAddingObject:
141 [NSMenuItem itemWithTitle:@"Bring All to Front"
142 action:@selector(arrangeInFront:)]];
143 [_defaultWindowsMenuItems retain];
144 TKMenu *windowsMenu = [TKMenu menuWithTitle:@"Window" menuItems:
145 _defaultWindowsMenuItems];
146 _defaultHelpMenuItems = [[NSArray arrayWithObjects:
147 [NSMenuItem itemWithTitle:
148 [NSString stringWithFormat:@"%@ Help", applicationName]
149 action:@selector(showHelp:) keyEquivalent:@"?"],
151 TKMenu *helpMenu = [TKMenu menuWithTitle:@"Help" menuItems:
152 _defaultHelpMenuItems];
153 [self setServicesMenu:_servicesMenu];
154 [self setWindowsMenu:windowsMenu];
155 _defaultMainMenu = [[TKMenu menuWithTitle:@"" submenus:[NSArray
156 arrayWithObjects:_defaultApplicationMenu, fileMenu, editMenu,
157 windowsMenu, helpMenu, nil]] retain];
158 [_defaultMainMenu setSpecial:tkMainMenu];
159 [_defaultApplicationMenu setSpecial:tkApplicationMenu];
160 [windowsMenu setSpecial:tkWindowsMenu];
161 [helpMenu setSpecial:tkHelpMenu];
162 [self tkSetMainMenu:nil];
167 [_defaultMainMenu release];
168 [_defaultHelpMenuItems release];
169 [_defaultWindowsMenuItems release];
170 [_defaultApplicationMenuItems release];
171 [_defaultFileMenuItems release];
175 - (BOOL) validateUserInterfaceItem: (id <NSValidatedUserInterfaceItem>) anItem
177 SEL action = [anItem action];
179 if (sel_isEqual(action, @selector(preferences:))) {
180 return (_eventInterp && Tcl_FindCommand(_eventInterp,
181 "::tk::mac::ShowPreferences", NULL, 0));
182 } else if (sel_isEqual(action, @selector(tkDemo:))) {
186 Tcl_Obj *path = GetWidgetDemoPath(_eventInterp);
189 Tcl_IncrRefCount(path);
190 haveDemo = (Tcl_FSAccess(path, R_OK) == 0);
191 Tcl_DecrRefCount(path);
196 return [super validateUserInterfaceItem:anItem];
200 - (void) orderFrontStandardAboutPanel: (id) sender
202 if (!_eventInterp || !Tcl_FindCommand(_eventInterp, "tkAboutDialog",
203 NULL, 0) || (GetCurrentEventKeyModifiers() & optionKey)) {
204 [super orderFrontStandardAboutPanel:nil];
206 int code = Tcl_EvalEx(_eventInterp, "tkAboutDialog", -1,
209 if (code != TCL_OK) {
210 Tcl_BackgroundException(_eventInterp, code);
212 Tcl_ResetResult(_eventInterp);
216 - (void) showHelp: (id) sender
218 if (!_eventInterp || !Tcl_FindCommand(_eventInterp,
219 "::tk::mac::ShowHelp", NULL, 0)) {
220 [super showHelp:sender];
222 int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ShowHelp", -1,
225 if (code != TCL_OK) {
226 Tcl_BackgroundException(_eventInterp, code);
228 Tcl_ResetResult(_eventInterp);
232 - (void) tkSource: (id) sender
235 if (Tcl_EvalEx(_eventInterp, "tk_getOpenFile -filetypes {"
236 "{{TCL Scripts} {.tcl} TEXT} {{Text Files} {} TEXT}}",
237 -1, TCL_EVAL_GLOBAL) == TCL_OK) {
238 Tcl_Obj *path = Tcl_GetObjResult(_eventInterp);
241 Tcl_GetStringFromObj(path, &len);
243 Tcl_IncrRefCount(path);
245 int code = Tcl_FSEvalFileEx(_eventInterp, path, NULL);
247 if (code != TCL_OK) {
248 Tcl_BackgroundException(_eventInterp, code);
250 Tcl_DecrRefCount(path);
253 Tcl_ResetResult(_eventInterp);
257 - (void) tkDemo: (id) sender
260 Tcl_Obj *path = GetWidgetDemoPath(_eventInterp);
263 Tcl_IncrRefCount(path);
265 [_demoMenuItem setHidden:YES];
266 int code = Tcl_FSEvalFileEx(_eventInterp, path, NULL);
268 if (code != TCL_OK) {
269 Tcl_BackgroundException(_eventInterp, code);
271 Tcl_DecrRefCount(path);
272 Tcl_ResetResult(_eventInterp);
278 #pragma mark TKContentView(TKMenus)
280 @implementation TKContentView(TKMenus)
282 - (BOOL) validateUserInterfaceItem: (id <NSValidatedUserInterfaceItem>) anItem
287 #define EDIT_ACTION(a, e) \
288 - (void) a: (id) sender \
290 if ([sender isKindOfClass:[NSMenuItem class]]) { \
291 GenerateEditEvent(#e); \
294 EDIT_ACTION(cut, Cut)
295 EDIT_ACTION(copy, Copy)
296 EDIT_ACTION(paste, Paste)
297 EDIT_ACTION(delete, Clear)
298 EDIT_ACTION(undo, Undo)
299 EDIT_ACTION(redo, Redo)
306 *----------------------------------------------------------------------
308 * GetWidgetDemoPath --
310 * Get path to the widget demo.
313 * pathObj with ref count 0.
318 *----------------------------------------------------------------------
325 Tcl_Obj *libpath, *result = NULL;
327 libpath = Tcl_GetVar2Ex(interp, "tk_library", NULL, TCL_GLOBAL_ONLY);
329 Tcl_Obj *demo[2] = { Tcl_NewStringObj("demos", 5),
330 Tcl_NewStringObj("widget", 6) };
332 Tcl_IncrRefCount(libpath);
333 result = Tcl_FSJoinToPath(libpath, 2, demo);
334 Tcl_DecrRefCount(libpath);
336 Tcl_ResetResult(interp);
342 *----------------------------------------------------------------------
344 * TkMacOSXHandleMenuSelect --
346 * Handles events that occur in the Menu bar.
354 *----------------------------------------------------------------------
358 TkMacOSXHandleMenuSelect(
360 unsigned short theItem,
361 int optionKeyPressed)
363 Tcl_Panic("TkMacOSXHandleMenuSelect: Obsolete, no more Carbon!");
367 *----------------------------------------------------------------------
369 * TkMacOSXInitMenus --
371 * This procedure initializes the Macintosh menu bar.
379 *----------------------------------------------------------------------
390 *----------------------------------------------------------------------
392 * GenerateEditEvent --
394 * Takes an edit menu item and posts the corasponding a virtual event to
401 * May place events of queue.
403 *----------------------------------------------------------------------
412 TkWindow *winPtr = TkMacOSXGetTkWindow([NSApp keyWindow]);
418 tkwin = (Tk_Window)winPtr->dispPtr->focusPtr;
422 bzero(&event, sizeof(XVirtualEvent));
423 event.type = VirtualEvent;
424 event.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
425 event.send_event = false;
426 event.display = Tk_Display(tkwin);
427 event.event = Tk_WindowId(tkwin);
428 event.root = XRootWindow(Tk_Display(tkwin), 0);
429 event.subwindow = None;
430 event.time = TkpGetMS();
431 XQueryPointer(NULL, winPtr->window, NULL, NULL,
432 &event.x_root, &event.y_root, &x, &y, &event.state);
433 Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y);
434 event.same_screen = true;
435 event.name = Tk_GetUid(name);
436 Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
441 #pragma mark NSMenu & NSMenuItem Utilities
443 @implementation NSMenu(TKUtils)
445 + (id) menuWithTitle: (NSString *) title
447 NSMenu *m = [[self alloc] initWithTitle:title];
449 return [m autorelease];
452 + (id) menuWithTitle: (NSString *) title menuItems: (NSArray *) items
454 NSMenu *m = [[self alloc] initWithTitle:title];
456 for (NSMenuItem *i in items) {
459 return [m autorelease];
462 + (id) menuWithTitle: (NSString *) title submenus: (NSArray *) submenus
464 NSMenu *m = [[self alloc] initWithTitle:title];
466 for (NSMenu *i in submenus) {
467 [m addItem:[NSMenuItem itemWithSubmenu:i]];
469 return [m autorelease];
472 - (NSMenuItem *) itemWithSubmenu: (NSMenu *) submenu
474 return [self itemAtIndex:[self indexOfItemWithSubmenu:submenu]];
477 - (NSMenuItem *) itemInSupermenu
479 NSMenu *supermenu = [self supermenu];
481 return (supermenu ? [supermenu itemWithSubmenu:self] : nil);
485 @implementation NSMenuItem(TKUtils)
487 + (id) itemWithSubmenu: (NSMenu *) submenu
489 NSMenuItem *i = [[self alloc] initWithTitle:[submenu title] action:NULL
492 [i setSubmenu:submenu];
493 return [i autorelease];
496 + (id) itemWithTitle: (NSString *) title submenu: (NSMenu *) submenu
498 NSMenuItem *i = [[self alloc] initWithTitle:title action:NULL
501 [i setSubmenu:submenu];
502 return [i autorelease];
505 + (id) itemWithTitle: (NSString *) title action: (SEL) action
507 NSMenuItem *i = [[self alloc] initWithTitle:title action:action
511 return [i autorelease];
514 + (id) itemWithTitle: (NSString *) title action: (SEL) action
517 NSMenuItem *i = [[self alloc] initWithTitle:title action:action
520 [i setTarget:target];
521 return [i autorelease];
524 + (id) itemWithTitle: (NSString *) title action: (SEL) action
525 keyEquivalent: (NSString *) keyEquivalent
527 NSMenuItem *i = [[self alloc] initWithTitle:title action:action
528 keyEquivalent:keyEquivalent];
531 return [i autorelease];
534 + (id) itemWithTitle: (NSString *) title action: (SEL) action
535 target: (id) target keyEquivalent: (NSString *) keyEquivalent
537 NSMenuItem *i = [[self alloc] initWithTitle:title action:action
538 keyEquivalent:keyEquivalent];
540 [i setTarget:target];
541 return [i autorelease];
544 + (id) itemWithTitle: (NSString *) title action: (SEL) action
545 keyEquivalent: (NSString *) keyEquivalent
546 keyEquivalentModifierMask: (NSUInteger) keyEquivalentModifierMask
548 NSMenuItem *i = [[self alloc] initWithTitle:title action:action
549 keyEquivalent:keyEquivalent];
552 [i setKeyEquivalentModifierMask:keyEquivalentModifierMask];
553 return [i autorelease];
556 + (id) itemWithTitle: (NSString *) title action: (SEL) action
557 target: (id) target keyEquivalent: (NSString *) keyEquivalent
558 keyEquivalentModifierMask: (NSUInteger) keyEquivalentModifierMask
560 NSMenuItem *i = [[self alloc] initWithTitle:title action:action
561 keyEquivalent:keyEquivalent];
563 [i setTarget:target];
564 [i setKeyEquivalentModifierMask:keyEquivalentModifierMask];
565 return [i autorelease];