tkMacOSXMenus.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:10k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXMenus.c --
  3.  *
  4.  * These calls set up and manage the menubar for the
  5.  * Macintosh version of Tk.
  6.  *
  7.  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
  8.  * Copyright 2001, Apple Computer, Inc.
  9.  * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net>
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkMacOSXMenus.c,v 1.2.2.16 2007/11/09 06:26:56 das Exp $
  15.  */
  16. #include "tkMacOSXPrivate.h"
  17. #define kAppleMenu 256
  18. #define kAppleAboutItem 1
  19. #define kFileMenu 2
  20. #define kEditMenu 3
  21. #define kSourceItem 1
  22. #define kDemoItem 2
  23. #define kCloseItem 3
  24. #define EDIT_CUT 1
  25. #define EDIT_COPY 2
  26. #define EDIT_PASTE 3
  27. #define EDIT_CLEAR 4
  28. MenuRef tkAppleMenu;
  29. MenuRef tkFileMenu;
  30. MenuRef tkEditMenu;
  31. static Tcl_Interp * gInterp = NULL;     /* Standard menu interpreter. */
  32. static EventHandlerRef menuEventHandlerRef = NULL;
  33. static void GenerateEditEvent(int flag);
  34. static Tcl_Obj* GetWidgetDemoPath(Tcl_Interp *interp);
  35. static OSStatus MenuEventHandlerProc(EventHandlerCallRef callRef,
  36. EventRef event, void *userData);
  37. /*
  38.  *----------------------------------------------------------------------
  39.  *
  40.  * GetWidgetDemoPath --
  41.  *
  42.  * Get path to the widget demo.
  43.  *
  44.  * Results:
  45.  * pathObj with ref count 0.
  46.  *
  47.  * Side effects:
  48.  * None.
  49.  *
  50.  *----------------------------------------------------------------------
  51.  */
  52. Tcl_Obj*
  53. GetWidgetDemoPath(
  54.     Tcl_Interp *interp)
  55. {
  56.     Tcl_Obj *libpath , *result = NULL;
  57.     libpath = Tcl_GetVar2Ex(gInterp, "tk_library", NULL, TCL_GLOBAL_ONLY);
  58.     if (libpath) {
  59. Tcl_Obj *demo[2] = { Tcl_NewStringObj("demos", 5),
  60. Tcl_NewStringObj("widget", 6) };
  61. Tcl_IncrRefCount(libpath);
  62. result = Tcl_FSJoinToPath(libpath, 2, demo);
  63. Tcl_DecrRefCount(libpath);
  64.     }
  65.     return result;
  66. }
  67. /*
  68.  *----------------------------------------------------------------------
  69.  *
  70.  * TkMacOSXHandleMenuSelect --
  71.  *
  72.  * Handles events that occur in the Menu bar.
  73.  *
  74.  * Results:
  75.  * None.
  76.  *
  77.  * Side effects:
  78.  * None.
  79.  *
  80.  *----------------------------------------------------------------------
  81.  */
  82. void
  83. TkMacOSXHandleMenuSelect(
  84.     MenuID theMenu,
  85.     MenuItemIndex theItem,
  86.     int optionKeyPressed)
  87. {
  88.     Tk_Window tkwin;
  89.     Window window;
  90.     TkDisplay *dispPtr;
  91.     if (theItem == 0) {
  92. TkMacOSXClearMenubarActive();
  93. return;
  94.     }
  95.     switch (theMenu) {
  96. case kAppleMenu:
  97.     switch (theItem) {
  98. case kAppleAboutItem:
  99.     {
  100. Tcl_CmdInfo dummy;
  101. if (optionKeyPressed || gInterp == NULL ||
  102.     Tcl_GetCommandInfo(gInterp,
  103. "tkAboutDialog", &dummy) == 0) {
  104.     TkAboutDlg();
  105. } else {
  106.     if (Tcl_EvalEx(gInterp, "tkAboutDialog", -1,
  107.     TCL_EVAL_GLOBAL) != TCL_OK) {
  108. Tcl_BackgroundError(gInterp);
  109.     }
  110.     Tcl_ResetResult(gInterp);
  111. }
  112. break;
  113.     }
  114.     }
  115.     break;
  116. case kFileMenu:
  117.     switch (theItem) {
  118. case kSourceItem:
  119.     if (gInterp) {
  120. if(Tcl_EvalEx(gInterp, "tk_getOpenFile -filetypes {"
  121. "{{TCL Scripts} {.tcl} TEXT} "
  122. "{{Text Files} {} TEXT}}", -1, TCL_EVAL_GLOBAL)
  123. == TCL_OK) {
  124.     Tcl_Obj *path = Tcl_GetObjResult(gInterp);
  125.     int len;
  126.     
  127.     Tcl_GetStringFromObj(path, &len);
  128.     if (len) {
  129. Tcl_IncrRefCount(path);
  130. if (Tcl_FSEvalFile(gInterp, path)
  131. == TCL_ERROR) {
  132.     Tcl_BackgroundError(gInterp);
  133. }
  134. Tcl_DecrRefCount(path);
  135.     }
  136. }
  137. Tcl_ResetResult(gInterp);
  138.     }
  139.     break;
  140. case kDemoItem:
  141.     if (gInterp) {
  142. Tcl_Obj *path = GetWidgetDemoPath(gInterp);
  143. if (path) {
  144.     Tcl_IncrRefCount(path);
  145.     if (Tcl_FSEvalFile(gInterp, path)
  146.     == TCL_ERROR) {
  147. Tcl_BackgroundError(gInterp);
  148.     }
  149.     Tcl_DecrRefCount(path);
  150.     Tcl_ResetResult(gInterp);
  151. }
  152.     }
  153.     break;
  154. case kCloseItem:
  155.     /* Send close event */
  156.     window = TkMacOSXGetXWindow(ActiveNonFloatingWindow());
  157.     dispPtr = TkGetDisplayList();
  158.     tkwin = Tk_IdToWindow(dispPtr->display, window);
  159.     TkGenWMDestroyEvent(tkwin);
  160.     break;
  161.     }
  162.     break;
  163. case kEditMenu:
  164.     /*
  165.      * This implementation just send the keysyms Tk thinks are
  166.      * associated with function keys that do Cut, Copy & Paste on
  167.      * a Sun keyboard.
  168.      */
  169.     GenerateEditEvent(theItem);
  170.     break;
  171. default:
  172.     TkMacOSXDispatchMenuEvent(theMenu, theItem);
  173.     break;
  174.     }
  175.     /*
  176.      * Finally we unhighlight the menu.
  177.      */
  178.     HiliteMenu(0);
  179. }
  180. /*
  181.  *----------------------------------------------------------------------
  182.  *
  183.  * MenuEventHandlerProc --
  184.  *
  185.  * One-time handler of kEventMenuEnableItems for the edit menu.
  186.  *
  187.  * Results:
  188.  * OS status code.
  189.  *
  190.  * Side effects:
  191.  * None.
  192.  *
  193.  *----------------------------------------------------------------------
  194.  */
  195. static OSStatus
  196. MenuEventHandlerProc(
  197.     EventHandlerCallRef callRef,
  198.     EventRef event,
  199.     void *userData)
  200. {
  201.     OSStatus result = eventNotHandledErr, err;
  202.     int menuContext;
  203.     err = ChkErr(GetEventParameter, event, kEventParamMenuContext, typeUInt32,
  204.     NULL, sizeof(menuContext), NULL, &menuContext);
  205.     if (err == noErr && (menuContext & kMenuContextMenuBarTracking)) {
  206. if (gInterp) {
  207.     Tcl_Obj *path = GetWidgetDemoPath(gInterp);
  208.     if (path) {
  209. Tcl_IncrRefCount(path);
  210. if (Tcl_FSAccess(path, R_OK) == 0) {
  211.     EnableMenuItem(tkFileMenu, kDemoItem);
  212. }
  213. Tcl_DecrRefCount(path);
  214.     }
  215. }
  216. ChkErr(RemoveEventHandler, menuEventHandlerRef);
  217. menuEventHandlerRef = NULL;
  218. result = noErr;
  219.     }
  220.     return result;
  221. }
  222. /*
  223.  *----------------------------------------------------------------------
  224.  *
  225.  * TkMacOSXInitMenus --
  226.  *
  227.  * This procedure initializes the Macintosh menu bar.
  228.  *
  229.  * Results:
  230.  * None.
  231.  *
  232.  * Side effects:
  233.  * None.
  234.  *
  235.  *----------------------------------------------------------------------
  236.  */
  237. void
  238. TkMacOSXInitMenus(
  239.     Tcl_Interp *interp)
  240. {
  241.     OSStatus err;
  242.     EventHandlerUPP menuEventHandlerUPP;
  243.     const EventTypeSpec menuEventTypes[] = {
  244. {kEventClassMenu, kEventMenuEnableItems},
  245.     };
  246.     gInterp = interp;
  247.     if (TkMacOSXUseMenuID(kAppleMenu) != TCL_OK) {
  248. Tcl_Panic("Menu ID %d is already in use!", kAppleMenu);
  249.     }
  250.     err = ChkErr(CreateNewMenu, kAppleMenu, kMenuAttrDoNotUseUserCommandKeys,
  251.     &tkAppleMenu);
  252.     if (err != noErr) {
  253. Tcl_Panic("CreateNewMenu failed !");
  254.     }
  255.     SetMenuTitle(tkAppleMenu, "p24");
  256.     InsertMenu(tkAppleMenu, 0);
  257.     AppendMenu(tkAppleMenu, "pAbout Tcl & Tkxc9");
  258.     AppendMenu(tkAppleMenu, "p(-");
  259.     if (TkMacOSXUseMenuID(kFileMenu) != TCL_OK) {
  260. Tcl_Panic("Menu ID %d is already in use!", kFileMenu);
  261.     }
  262.     err = ChkErr(CreateNewMenu, kFileMenu, kMenuAttrDoNotUseUserCommandKeys,
  263.     &tkFileMenu);
  264.     if (err != noErr) {
  265. Tcl_Panic("CreateNewMenu failed !");
  266.     }
  267.     SetMenuTitle(tkFileMenu, "pFile");
  268.     InsertMenu(tkFileMenu, 0);
  269.     InsertMenuItem(tkFileMenu, "pSourcexc9", kSourceItem - 1);
  270.     InsertMenuItem(tkFileMenu, "pRun Widget Demo", kDemoItem - 1);
  271.     InsertMenuItem(tkFileMenu, "pClose/W", kCloseItem - 1);
  272.     DisableMenuItem(tkFileMenu, kDemoItem);
  273.     menuEventHandlerUPP = NewEventHandlerUPP(MenuEventHandlerProc);
  274.     ChkErr(InstallEventHandler, GetMenuEventTarget(tkFileMenu),
  275.     menuEventHandlerUPP, GetEventTypeCount(menuEventTypes),
  276.     menuEventTypes, NULL, &menuEventHandlerRef);
  277.     DisposeEventHandlerUPP(menuEventHandlerUPP);
  278.     if (TkMacOSXUseMenuID(kEditMenu) != TCL_OK) {
  279. Tcl_Panic("Menu ID %d is already in use!", kEditMenu);
  280.     }
  281.     err = ChkErr(CreateNewMenu, kEditMenu, kMenuAttrDoNotUseUserCommandKeys,
  282.     &tkEditMenu);
  283.     if (err != noErr) {
  284. Tcl_Panic("CreateNewMenu failed !");
  285.     }
  286.     SetMenuTitle(tkEditMenu, "pEdit");
  287.     InsertMenu(tkEditMenu, 0);
  288.     AppendMenu(tkEditMenu, "pCut/X");
  289.     AppendMenu(tkEditMenu, "pCopy/C");
  290.     AppendMenu(tkEditMenu, "pPaste/V");
  291.     AppendMenu(tkEditMenu, "pClear");
  292.     if (TkMacOSXUseMenuID(kHMHelpMenuID) != TCL_OK) {
  293. Tcl_Panic("Help menu ID %s is already in use!", kHMHelpMenuID);
  294.     }
  295.     /*
  296.      * Workaround a Carbon bug with kHICommandPreferences: the first call to
  297.      * IsMenuKeyEvent returns false for the preferences menu item key shorcut
  298.      * event (even if the corresponding menu item is dynamically enabled by a
  299.      * kEventCommandUpdateStatus handler), unless the kHICommandPreferences
  300.      * menu item has previously been enabled manually. [Bug 1481503]
  301.      */
  302.     EnableMenuCommand(NULL, kHICommandPreferences);
  303.     DrawMenuBar();
  304.     return;
  305. }
  306. /*
  307.  *----------------------------------------------------------------------
  308.  *
  309.  * GenerateEditEvent --
  310.  *
  311.  * Takes an edit menu item and posts the corasponding a virtual
  312.  * event to Tk's event queue.
  313.  *
  314.  * Results:
  315.  * None.
  316.  *
  317.  * Side effects:
  318.  * May place events of queue.
  319.  *
  320.  *----------------------------------------------------------------------
  321.  */
  322. static void
  323. GenerateEditEvent(
  324.     int flag)
  325. {
  326.     XVirtualEvent event;
  327.     int x, y;
  328.     Tk_Window tkwin;
  329.     Window window;
  330.     TkDisplay *dispPtr;
  331.     window = TkMacOSXGetXWindow(ActiveNonFloatingWindow());
  332.     dispPtr = TkGetDisplayList();
  333.     tkwin = Tk_IdToWindow(dispPtr->display, window);
  334.     tkwin = (Tk_Window) ((TkWindow *) tkwin)->dispPtr->focusPtr;
  335.     if (tkwin == NULL) {
  336. return;
  337.     }
  338.     bzero(&event, sizeof(XVirtualEvent));
  339.     event.type = VirtualEvent;
  340.     event.serial = Tk_Display(tkwin)->request;
  341.     event.send_event = false;
  342.     event.display = Tk_Display(tkwin);
  343.     event.event = Tk_WindowId(tkwin);
  344.     event.root = XRootWindow(Tk_Display(tkwin), 0);
  345.     event.subwindow = None;
  346.     event.time = TkpGetMS();
  347.     XQueryPointer(NULL, None, NULL, NULL,
  348.     &event.x_root, &event.y_root, &x, &y, &event.state);
  349.     tkwin = Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y);
  350.     event.same_screen = true;
  351.     switch (flag) {
  352. case EDIT_CUT:
  353.     event.name = Tk_GetUid("Cut");
  354.     break;
  355. case EDIT_COPY:
  356.     event.name = Tk_GetUid("Copy");
  357.     break;
  358. case EDIT_PASTE:
  359.     event.name = Tk_GetUid("Paste");
  360.     break;
  361. case EDIT_CLEAR:
  362.     event.name = Tk_GetUid("Clear");
  363.     break;
  364.     }
  365.     Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
  366. }