📄 tkunixsend.c
字号:
* * Side effects: * The open registry is expanded; it is marked as modified so that * it will be written back when closed. * *---------------------------------------------------------------------- */static voidRegAddName(regPtr, name, commWindow) NameRegistry *regPtr; /* Pointer to a registry opened with a * previous call to RegOpen. */ char *name; /* Name of an application. The caller * must ensure that this name isn't * already registered. */ Window commWindow; /* X identifier for comm. window of * application. */{ char id[30]; char *newProp; int idLength, newBytes; sprintf(id, "%x ", (unsigned int) commWindow); idLength = strlen(id); newBytes = idLength + strlen(name) + 1; newProp = (char *) ckalloc((unsigned) (regPtr->propLength + newBytes)); strcpy(newProp, id); strcpy(newProp+idLength, name); if (regPtr->property != NULL) { memcpy((VOID *) (newProp + newBytes), (VOID *) regPtr->property, regPtr->propLength); if (regPtr->allocedByX) { XFree(regPtr->property); } else { ckfree(regPtr->property); } } regPtr->modified = 1; regPtr->propLength += newBytes; regPtr->property = newProp; regPtr->allocedByX = 0;}/* *---------------------------------------------------------------------- * * RegClose -- * * This procedure is called to end a series of operations on * a name registry. * * Results: * None. * * Side effects: * The registry is written back if it has been modified, and the * X server is unlocked if it was locked. Memory for the * registry is freed, so the caller should never use regPtr * again. * *---------------------------------------------------------------------- */static voidRegClose(regPtr) NameRegistry *regPtr; /* Pointer to a registry opened with a * previous call to RegOpen. */{ if (regPtr->modified) { if (!regPtr->locked && !sendDebug) { panic("The name registry was modified without being locked!"); } XChangeProperty(regPtr->dispPtr->display, RootWindow(regPtr->dispPtr->display, 0), regPtr->dispPtr->registryProperty, XA_STRING, 8, PropModeReplace, (unsigned char *) regPtr->property, (int) regPtr->propLength); } if (regPtr->locked) { XUngrabServer(regPtr->dispPtr->display); } /* * After ungrabbing the server, it's important to flush the output * immediately so that the server sees the ungrab command. Otherwise * we might do something else that needs to communicate with the * server (such as invoking a subprocess that needs to do I/O to * the screen); if the ungrab command is still sitting in our * output buffer, we could deadlock. */ XFlush(regPtr->dispPtr->display); if (regPtr->property != NULL) { if (regPtr->allocedByX) { XFree(regPtr->property); } else { ckfree(regPtr->property); } } ckfree((char *) regPtr);}/* *---------------------------------------------------------------------- * * ValidateName -- * * This procedure checks to see if an entry in the registry * is still valid. * * Results: * The return value is 1 if the given commWindow exists and its * name is "name". Otherwise 0 is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */static intValidateName(dispPtr, name, commWindow, oldOK) TkDisplay *dispPtr; /* Display for which to perform the * validation. */ char *name; /* The name of an application. */ Window commWindow; /* X identifier for the application's * comm. window. */ int oldOK; /* Non-zero means that we should consider * an application to be valid even if it * looks like an old-style (pre-4.0) one; * 0 means consider these invalid. */{ int result, actualFormat, argc, i; unsigned long length, bytesAfter; Atom actualType; char *property; Tk_ErrorHandler handler; char **argv; property = NULL; /* * Ignore X errors when reading the property (e.g., the window * might not exist). If an error occurs, result will be some * value other than Success. */ handler = Tk_CreateErrorHandler(dispPtr->display, -1, -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL); result = XGetWindowProperty(dispPtr->display, commWindow, dispPtr->appNameProperty, 0, MAX_PROP_WORDS, False, XA_STRING, &actualType, &actualFormat, &length, &bytesAfter, (unsigned char **) &property); if ((result == Success) && (actualType == None)) { XWindowAttributes atts; /* * The comm. window exists but the property we're looking for * doesn't exist. This probably means that the application * comes from an older version of Tk (< 4.0) that didn't set the * property; if this is the case, then assume for compatibility's * sake that everything's OK. However, it's also possible that * some random application has re-used the window id for something * totally unrelated. Check a few characteristics of the window, * such as its dimensions and mapped state, to be sure that it * still "smells" like a commWindow. */ if (!oldOK || !XGetWindowAttributes(dispPtr->display, commWindow, &atts) || (atts.width != 1) || (atts.height != 1) || (atts.map_state != IsUnmapped)) { result = 0; } else { result = 1; } } else if ((result == Success) && (actualFormat == 8) && (actualType == XA_STRING)) { result = 0; if (Tcl_SplitList((Tcl_Interp *) NULL, property, &argc, &argv) == TCL_OK) { for (i = 0; i < argc; i++) { if (strcmp(argv[i], name) == 0) { result = 1; break; } } ckfree((char *) argv); } } else { result = 0; } Tk_DeleteErrorHandler(handler); if (property != NULL) { XFree(property); } return result;}/* *---------------------------------------------------------------------- * * ServerSecure -- * * Check whether a server is secure enough for us to trust * Tcl scripts arriving via that server. * * Results: * The return value is 1 if the server is secure, which means * that host-style authentication is turned on but there are * no hosts in the enabled list. This means that some other * form of authorization (presumably more secure, such as xauth) * is in use. * * Side effects: * None. * *---------------------------------------------------------------------- */static intServerSecure(dispPtr) TkDisplay *dispPtr; /* Display to check. */{#ifdef TK_NO_SECURITY return 1;#else XHostAddress *addrPtr; int numHosts, secure; Bool enabled; secure = 0; addrPtr = XListHosts(dispPtr->display, &numHosts, &enabled); if (enabled && (numHosts == 0)) { secure = 1; } if (addrPtr != NULL) { XFree((char *) addrPtr); } return secure;#endif /* TK_NO_SECURITY */}/* *-------------------------------------------------------------- * * Tk_SetAppName -- * * This procedure is called to associate an ASCII name with a Tk * application. If the application has already been named, the * name replaces the old one. * * Results: * The return value is the name actually given to the application. * This will normally be the same as name, but if name was already * in use for an application then a name of the form "name #2" will * be chosen, with a high enough number to make the name unique. * * Side effects: * Registration info is saved, thereby allowing the "send" command * to be used later to invoke commands in the application. In * addition, the "send" command is created in the application's * interpreter. The registration will be removed automatically * if the interpreter is deleted or the "send" command is removed. * *-------------------------------------------------------------- */char *Tk_SetAppName(tkwin, name) Tk_Window tkwin; /* Token for any window in the application * to be named: it is just used to identify * the application and the display. */ char *name; /* The name that will be used to * refer to the interpreter in later * "send" commands. Must be globally * unique. */{ RegisteredInterp *riPtr, *riPtr2; Window w; TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr; NameRegistry *regPtr; Tcl_Interp *interp; char *actualName; Tcl_DString dString; int offset, i;#ifdef __WIN32__ return name;#endif /* __WIN32__ */ dispPtr = winPtr->dispPtr; interp = winPtr->mainPtr->interp; if (dispPtr->commTkwin == NULL) { SendInit(interp, winPtr->dispPtr); } /* * See if the application is already registered; if so, remove its * current name from the registry. */ regPtr = RegOpen(interp, winPtr->dispPtr, 1); for (riPtr = registry; ; riPtr = riPtr->nextPtr) { if (riPtr == NULL) { /* * This interpreter isn't currently registered; create * the data structure that will be used to register it locally, * plus add the "send" command to the interpreter. */ riPtr = (RegisteredInterp *) ckalloc(sizeof(RegisteredInterp)); riPtr->interp = interp; riPtr->dispPtr = winPtr->dispPtr; riPtr->nextPtr = registry; registry = riPtr; Tcl_CreateCommand(interp, "send", Tk_SendCmd, (ClientData) riPtr, DeleteProc); if (Tcl_IsSafe(interp)) { Tcl_HideCommand(interp, "send", "send"); } break; } if (riPtr->interp == interp) { /* * The interpreter is currently registered; remove it from * the name registry. */ RegDeleteName(regPtr, riPtr->name); ckfree(riPtr->name); break; } } /* * Pick a name to use for the application. Use "name" if it's not * already in use. Otherwise add a suffix such as " #2", trying * larger and larger numbers until we eventually find one that is * unique. */ actualName = name; offset = 0; /* Needed only to avoid "used before * set" compiler warnings. */ for (i = 1; ; i++) { if (i > 1) { if (i == 2) { Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, name, -1); Tcl_DStringAppend(&dString, " #", 2); offset = Tcl_DStringLength(&dString); Tcl_DStringSetLength(&dString, offset+10); actualName = Tcl_DStringValue(&dString); } sprintf(actualName + offset, "%d", i); } w = RegFindName(regPtr, actualName); if (w == None) { break; } /* * The name appears to be in use already, but double-check to * be sure (perhaps the application died without removing its * name from the registry?). */ if (w == Tk_WindowId(dispPtr->commTkwin)) { for (riPtr2 = registry; riPtr2 != NULL; riPtr2 = riPtr2->nextPtr) { if ((riPtr2->interp != interp) && (strcmp(riPtr2->name, actualName) == 0)) { goto nextSuffix; } } RegDeleteName(regPtr, actualName); break; } else if (!ValidateName(winPtr->dispPtr, actualName, w, 1)) { RegDeleteName(regPtr, actualName); break; } nextSuffix: continue; } /* * We've now got a name to use. Store it in the name registry and * in the local entry for this application, plus put it in a property * on the commWindow. */ RegAddName(regPtr, actualName, Tk_WindowId(dispPtr->commTkwin)); RegClose(regPtr); riPtr->name = (char *) ckalloc((unsigned) (strlen(actualName) + 1)); strcpy(riPtr->name, actualName); if (actualName != name) { Tcl_DStringFree(&dString); } UpdateCommWindow(dispPtr); return riPtr->name;}/* *-------------------------------------------------------------- * * Tk_SendCmd -- * * This procedure is invoked to process the "send" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */intTk_SendCmd(clientData, interp, argc, argv) ClientData clientData; /* Information about sender (only * dispPtr field is used). */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ TkWindow *winPtr; Window commWindow; PendingCommand pending; register RegisteredInterp *riPtr; char *destName, buffer[30]; int result, c, async, i, firstArg; size_t length; Tk_RestrictProc *prevRestrictProc; ClientData prevArg; TkDisplay *dispPtr; Tcl_Time timeout; NameRegistry *regPtr; Tcl_DString request; Tcl_Interp *localInterp; /* Used when the interpreter to * send the command to is within * the same process. */ /* * Process options, if any. */ async = 0; winPtr = (TkWindow *) Tk_MainWindow(interp); if (winPtr == NULL) { return TCL_ERROR; } for (i = 1; i < (argc-1); ) { if (argv[i][0] != '-') { break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -