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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXHLEvents.c --
  3.  *
  4.  * Implements high level event support for the Macintosh. Currently,
  5.  * the only event that really does anything is the Quit event.
  6.  *
  7.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  8.  * Copyright 2001, Apple Computer, Inc.
  9.  * Copyright (c) 2006 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: tkMacOSXHLEvents.c,v 1.5.2.11 2007/06/29 03:22:02 das Exp $
  15.  */
  16. #include "tkMacOSXPrivate.h"
  17. /*
  18.  * This is a Tcl_Event structure that the Quit AppleEvent handler
  19.  * uses to schedule the ReallyKillMe function.
  20.  */
  21. typedef struct KillEvent {
  22.     Tcl_Event header; /* Information that is standard for
  23.  * all events. */
  24.     Tcl_Interp *interp; /* Interp that was passed to the
  25.  * Quit AppleEvent */
  26. } KillEvent;
  27. /*
  28.  * Static functions used only in this file.
  29.  */
  30. static OSErr QuitHandler(const AppleEvent * event, AppleEvent * reply,
  31. long handlerRefcon);
  32. static OSErr OappHandler(const AppleEvent * event, AppleEvent * reply,
  33. long handlerRefcon);
  34. static OSErr RappHandler(const AppleEvent * event, AppleEvent * reply,
  35. long handlerRefcon);
  36. static OSErr OdocHandler(const AppleEvent * event, AppleEvent * reply,
  37. long handlerRefcon);
  38. static OSErr PrintHandler(const AppleEvent * event, AppleEvent * reply,
  39. long handlerRefcon);
  40. static OSErr ScriptHandler(const AppleEvent * event, AppleEvent * reply,
  41. long handlerRefcon);
  42. static OSErr PrefsHandler(const AppleEvent * event, AppleEvent * reply,
  43. long handlerRefcon);
  44. static int MissedAnyParameters(const AppleEvent *theEvent);
  45. static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
  46. static OSStatus FSRefToDString(const FSRef *fsref, Tcl_DString *ds);
  47. /*
  48.  *----------------------------------------------------------------------
  49.  *
  50.  * TkMacOSXInitAppleEvents --
  51.  *
  52.  * Initilize the Apple Events on the Macintosh. This registers the
  53.  * core event handlers.
  54.  *
  55.  * Results:
  56.  * None.
  57.  *
  58.  * Side effects:
  59.  * None.
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63. void
  64. TkMacOSXInitAppleEvents(
  65.     Tcl_Interp *interp)        /* Interp to handle basic events. */
  66. {
  67.     AEEventHandlerUPP      OappHandlerUPP, RappHandlerUPP, OdocHandlerUPP,
  68.     PrintHandlerUPP, QuitHandlerUPP, ScriptHandlerUPP, PrefsHandlerUPP;
  69.     static Boolean initialized = FALSE;
  70.     if (!initialized) {
  71. initialized = TRUE;
  72. /*
  73.  * Install event handlers for the core apple events.
  74.  */
  75. QuitHandlerUPP = NewAEEventHandlerUPP(QuitHandler);
  76. ChkErr(AEInstallEventHandler, kCoreEventClass, kAEQuitApplication,
  77. QuitHandlerUPP, (long) interp, false);
  78. OappHandlerUPP = NewAEEventHandlerUPP(OappHandler);
  79. ChkErr(AEInstallEventHandler, kCoreEventClass, kAEOpenApplication,
  80. OappHandlerUPP, (long) interp, false);
  81. RappHandlerUPP = NewAEEventHandlerUPP(RappHandler);
  82. ChkErr(AEInstallEventHandler, kCoreEventClass, kAEReopenApplication,
  83. RappHandlerUPP, (long) interp, false);
  84. OdocHandlerUPP = NewAEEventHandlerUPP(OdocHandler);
  85. ChkErr(AEInstallEventHandler, kCoreEventClass, kAEOpenDocuments,
  86. OdocHandlerUPP, (long) interp, false);
  87. PrintHandlerUPP = NewAEEventHandlerUPP(PrintHandler);
  88. ChkErr(AEInstallEventHandler, kCoreEventClass, kAEPrintDocuments,
  89. PrintHandlerUPP, (long) interp, false);
  90. PrefsHandlerUPP = NewAEEventHandlerUPP(PrefsHandler);
  91. ChkErr(AEInstallEventHandler, kCoreEventClass, kAEShowPreferences,
  92. PrefsHandlerUPP, (long) interp, false);
  93. if (interp) {
  94.     ScriptHandlerUPP = NewAEEventHandlerUPP(ScriptHandler);
  95.     ChkErr(AEInstallEventHandler, kAEMiscStandards, kAEDoScript,
  96. ScriptHandlerUPP, (long) interp, false);
  97. }
  98.     }
  99. }
  100. /*
  101.  *----------------------------------------------------------------------
  102.  *
  103.  * TkMacOSXDoHLEvent --
  104.  *
  105.  * Dispatch incomming highlevel events.
  106.  *
  107.  * Results:
  108.  * None.
  109.  *
  110.  * Side effects:
  111.  * Depends on the incoming event.
  112.  *
  113.  *----------------------------------------------------------------------
  114.  */
  115. int
  116. TkMacOSXDoHLEvent(
  117.     EventRecord *theEvent)
  118. {
  119.     return AEProcessAppleEvent(theEvent);
  120. }
  121. /*
  122.  *----------------------------------------------------------------------
  123.  *
  124.  * QuitHandler --
  125.  *
  126.  * This is the 'quit' core Apple event handler.
  127.  *
  128.  * Results:
  129.  * None.
  130.  *
  131.  * Side effects:
  132.  * None.
  133.  *
  134.  *----------------------------------------------------------------------
  135.  */
  136. OSErr
  137. QuitHandler(
  138.     const AppleEvent * event,
  139.     AppleEvent * reply,
  140.     long handlerRefcon)
  141. {
  142.     Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
  143.     KillEvent *eventPtr;
  144.     if (interp) {
  145. /*
  146.  * Call the exit command from the event loop, since you are not supposed
  147.  * to call ExitToShell in an Apple Event Handler. We put this at the head
  148.  * of Tcl's event queue because this message usually comes when the Mac is
  149.  * shutting down, and we want to kill the shell as quickly as possible.
  150.  */
  151. eventPtr = (KillEvent *) ckalloc(sizeof(KillEvent));
  152. eventPtr->header.proc = ReallyKillMe;
  153. eventPtr->interp = interp;
  154. Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD);
  155.     }
  156.     return noErr;
  157. }
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * OappHandler --
  162.  *
  163.  * This is the 'oapp' core Apple event handler.
  164.  *
  165.  * Results:
  166.  * None.
  167.  *
  168.  * Side effects:
  169.  * None.
  170.  *
  171.  *----------------------------------------------------------------------
  172.  */
  173. OSErr
  174. OappHandler(
  175.     const AppleEvent * event,
  176.     AppleEvent * reply,
  177.     long handlerRefcon)
  178. {
  179.     Tcl_CmdInfo dummy;
  180.     Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
  181.     if (interp &&
  182.     Tcl_GetCommandInfo(interp, "::tk::mac::OpenApplication", &dummy)) {
  183. Tcl_GlobalEval(interp, "::tk::mac::OpenApplication");
  184.     }
  185.     return noErr;
  186. }
  187. /*
  188.  *----------------------------------------------------------------------
  189.  *
  190.  * RappHandler --
  191.  *
  192.  * This is the 'rapp' core Apple event handler.
  193.  *
  194.  * Results:
  195.  * None.
  196.  *
  197.  * Side effects:
  198.  * None.
  199.  *
  200.  *----------------------------------------------------------------------
  201.  */
  202. OSErr
  203. RappHandler(
  204.     const AppleEvent * event,
  205.     AppleEvent * reply,
  206.     long handlerRefcon)
  207. {
  208.     Tcl_CmdInfo dummy;
  209.     Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
  210.     ProcessSerialNumber thePSN = {0, kCurrentProcess};
  211.     OSStatus err = ChkErr(SetFrontProcess, &thePSN);
  212.     if (interp &&
  213.     Tcl_GetCommandInfo(interp, "::tk::mac::ReopenApplication", &dummy)) {
  214. Tcl_GlobalEval(interp, "::tk::mac::ReopenApplication");
  215.     }
  216.     return err;
  217. }
  218. /*
  219.  *----------------------------------------------------------------------
  220.  *
  221.  * PrefsHandler --
  222.  *
  223.  * This is the 'pref' core Apple event handler.
  224.  * Called when the user selects 'Preferences...' in MacOS X
  225.  *
  226.  * Results:
  227.  * None.
  228.  *
  229.  * Side effects:
  230.  * None.
  231.  *
  232.  *----------------------------------------------------------------------
  233.  */
  234. OSErr
  235. PrefsHandler(
  236.     const AppleEvent * event,
  237.     AppleEvent * reply,
  238.     long handlerRefcon)
  239. {
  240.     Tcl_CmdInfo dummy;
  241.     Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
  242.     if (interp &&
  243.     Tcl_GetCommandInfo(interp, "::tk::mac::ShowPreferences", &dummy)) {
  244. Tcl_GlobalEval(interp, "::tk::mac::ShowPreferences");
  245.     }
  246.     return noErr;
  247. }
  248. /*
  249.  *----------------------------------------------------------------------
  250.  *
  251.  * OdocHandler --
  252.  *
  253.  * This is the 'odoc' core Apple event handler.
  254.  *
  255.  * Results:
  256.  * None.
  257.  *
  258.  * Side effects:
  259.  * None.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263. OSErr
  264. OdocHandler(
  265.     const AppleEvent * event,
  266.     AppleEvent * reply,
  267.     long handlerRefcon)
  268. {
  269.     Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
  270.     AEDescList fileSpecList;
  271.     FSRef file;
  272.     OSStatus err;
  273.     DescType type;
  274.     Size actual;
  275.     long count;
  276.     AEKeyword keyword;
  277.     long index;
  278.     Tcl_DString command;
  279.     Tcl_DString pathName;
  280.     Tcl_CmdInfo dummy;
  281.     /*
  282.      * Don't bother if we don't have an interp or
  283.      * the open document procedure doesn't exist.
  284.      */
  285.     if ((interp == NULL) ||
  286.     (Tcl_GetCommandInfo(interp, "::tk::mac::OpenDocument", &dummy)) == 0) {
  287.     return noErr;
  288.     }
  289.     /*
  290.      * If we get any errors wil retrieving our parameters
  291.      * we just return with no error.
  292.      */
  293.     err = ChkErr(AEGetParamDesc, event, keyDirectObject, typeAEList,
  294.     &fileSpecList);
  295.     if (err != noErr) {
  296. return noErr;
  297.     }
  298.     err = MissedAnyParameters(event);
  299.     if (err != noErr) {
  300. return noErr;
  301.     }
  302.     err = ChkErr(AECountItems, &fileSpecList, &count);
  303.     if (err != noErr) {
  304. return noErr;
  305.     }
  306.     Tcl_DStringInit(&command);
  307.     Tcl_DStringAppend(&command, "::tk::mac::OpenDocument", -1);
  308.     for (index = 1; index <= count; index++) {
  309. err = ChkErr(AEGetNthPtr, &fileSpecList, index, typeFSRef,
  310. &keyword, &type, (Ptr) &file, sizeof(FSRef), &actual);
  311. if ( err != noErr ) {
  312.     continue;
  313. }
  314. err = ChkErr(FSRefToDString, &file, &pathName);
  315. if (err == noErr) {
  316.     Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
  317.     Tcl_DStringFree(&pathName);
  318. }
  319.     }
  320.     Tcl_EvalEx(interp, Tcl_DStringValue(&command), Tcl_DStringLength(&command),
  321.     TCL_EVAL_GLOBAL);
  322.     Tcl_DStringFree(&command);
  323.     return noErr;
  324. }
  325. /*
  326.  *----------------------------------------------------------------------
  327.  *
  328.  * PrintHandler --
  329.  *
  330.  * This is the 'pdoc' core Apple event handler.
  331.  *
  332.  * Results:
  333.  * None.
  334.  *
  335.  * Side effects:
  336.  * None.
  337.  *
  338.  *----------------------------------------------------------------------
  339.  */
  340. OSErr
  341. PrintHandler(
  342.     const AppleEvent * event,
  343.     AppleEvent * reply,
  344.     long handlerRefcon)
  345. {
  346.     Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
  347.     AEDescList fileSpecList;
  348.     FSRef file;
  349.     OSStatus err;
  350.     DescType type;
  351.     Size actual;
  352.     long count;
  353.     AEKeyword keyword;
  354.     long index;
  355.     Tcl_DString command;
  356.     Tcl_DString pathName;
  357.     Tcl_CmdInfo dummy;
  358.     /*
  359.      * Don't bother if we don't have an interp or
  360.      * the print document procedure doesn't exist.
  361.      */
  362.     if ((interp == NULL) ||
  363.     (Tcl_GetCommandInfo(interp, "::tk::mac::PrintDocument", &dummy)) == 0) {
  364.     return noErr;
  365.     }
  366.     /*
  367.      * If we get any errors wil retrieving our parameters
  368.      * we just return with no error.
  369.      */
  370.     err = ChkErr(AEGetParamDesc, event, keyDirectObject, typeAEList,
  371.     &fileSpecList);
  372.     if (err != noErr) {
  373. return noErr;
  374.     }
  375.     err = ChkErr(MissedAnyParameters, event);
  376.     if (err != noErr) {
  377. return noErr;
  378.     }
  379.     err = ChkErr(AECountItems, &fileSpecList, &count);
  380.     if (err != noErr) {
  381. return noErr;
  382.     }
  383.     Tcl_DStringInit(&command);
  384.     Tcl_DStringAppend(&command, "::tk::mac::PrintDocument", -1);
  385.     for (index = 1; index <= count; index++) {
  386. err = ChkErr(AEGetNthPtr, &fileSpecList, index, typeFSRef, &keyword,
  387. &type, (Ptr) &file, sizeof(FSRef), &actual);
  388. if ( err != noErr ) {
  389.     continue;
  390. }
  391. err = ChkErr(FSRefToDString, &file, &pathName);
  392. if (err == noErr) {
  393.     Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
  394.     Tcl_DStringFree(&pathName);
  395. }
  396.     }
  397.     Tcl_EvalEx(interp, Tcl_DStringValue(&command), Tcl_DStringLength(&command),
  398.     TCL_EVAL_GLOBAL);
  399.     Tcl_DStringFree(&command);
  400.     return noErr;
  401. }
  402. /*
  403.  *----------------------------------------------------------------------
  404.  *
  405.  * ScriptHandler --
  406.  *
  407.  * This handler process the script event.
  408.  *
  409.  * Results:
  410.  * Schedules the given event to be processed.
  411.  *
  412.  * Side effects:
  413.  * None.
  414.  *
  415.  *----------------------------------------------------------------------
  416.  */
  417. OSErr
  418. ScriptHandler(
  419.     const AppleEvent * event,
  420.     AppleEvent * reply,
  421.     long handlerRefcon)
  422. {
  423.     OSStatus theErr;
  424.     AEDescList theDesc;
  425.     int tclErr = -1;
  426.     Tcl_Interp *interp;
  427.     char errString[128];
  428.     interp = (Tcl_Interp *) handlerRefcon;
  429.     /*
  430.      * The do script event receives one parameter that should be data or a file.
  431.      */
  432.     theErr = AEGetParamDesc(event, keyDirectObject, typeWildCard,
  433.     &theDesc);
  434.     if (theErr != noErr) {
  435. sprintf(errString, "AEDoScriptHandler: GetParamDesc error %ld",
  436. theErr);
  437. theErr = AEPutParamPtr(reply, keyErrorString, typeChar, errString,
  438. strlen(errString));
  439.     } else if (MissedAnyParameters(event)) {
  440. sprintf(errString, "AEDoScriptHandler: extra parameters");
  441. AEPutParamPtr(reply, keyErrorString, typeChar, errString,
  442. strlen(errString));
  443. theErr = -1771;
  444.     } else {
  445. if (theDesc.descriptorType == (DescType)typeChar) {
  446.     Tcl_DString encodedText;
  447.     short i;
  448.     Size  size;
  449.     char  * data;
  450.     size = AEGetDescDataSize(&theDesc);
  451.     data = (char *)ckalloc(size + 1);
  452.     if ( !data ) {
  453. theErr = -1771;
  454.     }
  455.     else {
  456.    AEGetDescData(&theDesc,data,size);
  457.    data [ size ] = 0;
  458.    for (i = 0; i < size; i++)
  459.     if (data[i] == 'r')
  460.      data[i] = 'n';
  461.    AEReplaceDescData(theDesc.descriptorType, data,
  462.    size + 1, &theDesc);
  463.     }
  464.     Tcl_ExternalToUtfDString(NULL, data, size,
  465.     &encodedText);
  466.     tclErr = Tcl_EvalEx(interp, Tcl_DStringValue(&encodedText),
  467.     Tcl_DStringLength(&encodedText), TCL_EVAL_GLOBAL);
  468.     Tcl_DStringFree(&encodedText);
  469. } else if (theDesc.descriptorType == (DescType)typeAlias) {
  470.     Boolean dummy;
  471.     FSRef file;
  472.     AliasPtr alias;
  473.     Size theSize;
  474.     theSize = AEGetDescDataSize(&theDesc);
  475.     alias = (AliasPtr) ckalloc(theSize);
  476.     if (alias) {
  477. AEGetDescData (&theDesc, alias, theSize);
  478. theErr = FSResolveAlias(NULL, &alias,
  479. &file, &dummy);
  480. ckfree((char*)alias);
  481.     } else {
  482. theErr = memFullErr;
  483.     }
  484.     if (theErr == noErr) {
  485. Tcl_DString scriptName;
  486. theErr = FSRefToDString(&file, &scriptName);
  487. if (theErr == noErr) {
  488.     Tcl_EvalFile(interp, Tcl_DStringValue(&scriptName));
  489.     Tcl_DStringFree(&scriptName);
  490. }
  491.     } else {
  492. sprintf(errString, "AEDoScriptHandler: file not found");
  493. AEPutParamPtr(reply, keyErrorString, typeChar,
  494. errString, strlen(errString));
  495.     }
  496. } else {
  497.     sprintf(errString,
  498.     "AEDoScriptHandler: invalid script type '%-4.4s', must be 'alis' or 'TEXT'",
  499.     (char *)(&theDesc.descriptorType));
  500.     AEPutParamPtr(reply, keyErrorString, typeChar,
  501.     errString, strlen(errString));
  502.     theErr = -1770;
  503. }
  504.     }
  505.     /*
  506.      * If we actually go to run Tcl code - put the result in the reply.
  507.      */
  508.     if (tclErr >= 0) {
  509. if (tclErr == TCL_OK)  {
  510.     AEPutParamPtr(reply, keyDirectObject, typeChar,
  511. Tcl_GetStringResult(interp),
  512. strlen(Tcl_GetStringResult(interp)));
  513. } else {
  514.     AEPutParamPtr(reply, keyErrorString, typeChar,
  515. Tcl_GetStringResult(interp),
  516. strlen(Tcl_GetStringResult(interp)));
  517.     AEPutParamPtr(reply, keyErrorNumber, typeInteger,
  518. (Ptr) &tclErr, sizeof(int));
  519. }
  520.     }
  521.     AEDisposeDesc(&theDesc);
  522.     return theErr;
  523. }
  524. /*
  525.  *----------------------------------------------------------------------
  526.  *
  527.  * ReallyKillMe --
  528.  *
  529.  * This proc tries to kill the shell by running exit,
  530.  * called from an event scheduled by the "Quit" AppleEvent handler.
  531.  *
  532.  * Results:
  533.  * Runs the "exit" command which might kill the shell.
  534.  *
  535.  * Side effects:
  536.  * None.
  537.  *
  538.  *----------------------------------------------------------------------
  539.  */
  540. static int
  541. ReallyKillMe(
  542.     Tcl_Event *eventPtr,
  543.     int flags)
  544. {
  545.     Tcl_Interp *interp = ((KillEvent *) eventPtr)->interp;
  546.     Tcl_CmdInfo dummy;
  547.     if (Tcl_GetCommandInfo(interp, "::tk::mac::Quit", &dummy)) {
  548.  Tcl_GlobalEval(interp, "::tk::mac::Quit");
  549.     } else {
  550. Tcl_GlobalEval(interp, "exit");
  551.     }
  552.     return 1;
  553. }
  554. /*
  555.  *----------------------------------------------------------------------
  556.  *
  557.  * MissedAnyParameters --
  558.  *
  559.  * Checks to see if parameters are still left in the event.
  560.  *
  561.  * Results:
  562.  * True or false.
  563.  *
  564.  * Side effects:
  565.  * None.
  566.  *
  567.  *----------------------------------------------------------------------
  568.  */
  569. int
  570. MissedAnyParameters(
  571.     const AppleEvent *theEvent)
  572. {
  573.    DescType returnedType;
  574.    Size actualSize;
  575.    OSStatus err;
  576.    err = ChkErr(AEGetAttributePtr, theEvent, keyMissedKeywordAttr,
  577.    typeWildCard, &returnedType, NULL, 0, &actualSize);
  578.    return (err != errAEDescNotFound);
  579. }
  580. /*
  581.  *----------------------------------------------------------------------
  582.  *
  583.  * FSRefToDString --
  584.  *
  585.  * Get a POSIX path from an FSRef.
  586.  *
  587.  * Results:
  588.  * In the parameter ds.
  589.  *
  590.  * Side effects:
  591.  * None.
  592.  *
  593.  *----------------------------------------------------------------------
  594.  */
  595. OSStatus
  596. FSRefToDString(
  597.     const FSRef *fsref,
  598.     Tcl_DString *ds)
  599. {
  600.     UInt8 fileName[PATH_MAX+1];
  601.     OSStatus err;
  602.     err = ChkErr(FSRefMakePath, fsref, fileName, sizeof(fileName));
  603.     if (err == noErr) {
  604. Tcl_ExternalToUtfDString(NULL, (char*) fileName, -1, ds);
  605.     }
  606.     return err;
  607. }