diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-12-21 22:56:39 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-12-21 22:56:39 (GMT) |
commit | 2bc8acacaa385fe4e607a99569b502032f98bc64 (patch) | |
tree | 7e70af1addc0d893b8daf4339f277cbf939998d8 /tk8.6/macosx/tkMacOSXEmbed.c | |
parent | d1a6de55efc90f190dee42ab8c4fa9070834e77d (diff) | |
parent | 1741f1b6324ead16eb1eeaa16e1f18cf0a2abb4f (diff) | |
download | blt-2bc8acacaa385fe4e607a99569b502032f98bc64.zip blt-2bc8acacaa385fe4e607a99569b502032f98bc64.tar.gz blt-2bc8acacaa385fe4e607a99569b502032f98bc64.tar.bz2 |
Merge commit '1741f1b6324ead16eb1eeaa16e1f18cf0a2abb4f' as 'tk8.6'
Diffstat (limited to 'tk8.6/macosx/tkMacOSXEmbed.c')
-rw-r--r-- | tk8.6/macosx/tkMacOSXEmbed.c | 1229 |
1 files changed, 1229 insertions, 0 deletions
diff --git a/tk8.6/macosx/tkMacOSXEmbed.c b/tk8.6/macosx/tkMacOSXEmbed.c new file mode 100644 index 0000000..99f7584 --- /dev/null +++ b/tk8.6/macosx/tkMacOSXEmbed.c @@ -0,0 +1,1229 @@ +/* + * tkMacOSXEmbed.c -- + * + * This file contains platform-specific procedures for theMac to provide + * basic operations needed for application embedding (where one + * application can use as its main window an internal window from some + * other application). Currently only Toplevel embedding within the same + * Tk application is allowed on the Macintosh. + * + * Copyright (c) 1996-1997 Sun Microsystems, Inc. + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include "tkMacOSXPrivate.h" +#include "tkBusy.h" + +/* + * One of the following structures exists for each container in this + * application. It keeps track of the container window and its associated + * embedded window. + */ + +typedef struct Container { + Window parent; /* The Mac Drawable for the parent of the pair + * (the container). */ + TkWindow *parentPtr; /* Tk's information about the container, or + * NULL if the container isn't in this + * process. */ + Window embedded; /* The MacDrawable for the embedded window. + * Starts off as None, but gets filled in when + * the window is eventually created. */ + TkWindow *embeddedPtr; /* Tk's information about the embedded window, + * or NULL if the embedded application isn't + * in this process. */ + struct Container *nextPtr; /* Next in list of all containers in this + * process. */ +} Container; + +static Container *firstContainerPtr = NULL; + /* First in list of all containers managed by + * this process. */ +/* + * Globals defined in this file: + */ + +TkMacOSXEmbedHandler *tkMacOSXEmbedHandler = NULL; + +/* + * Prototypes for static procedures defined in this file: + */ + +static void ContainerEventProc(ClientData clientData, XEvent *eventPtr); +static void EmbeddedEventProc(ClientData clientData, XEvent *eventPtr); +static void EmbedActivateProc(ClientData clientData, XEvent *eventPtr); +static void EmbedFocusProc(ClientData clientData, XEvent *eventPtr); +static void EmbedGeometryRequest(Container *containerPtr, int width, + int height); +static void EmbedSendConfigure(Container *containerPtr); +static void EmbedStructureProc(ClientData clientData, XEvent *eventPtr); +static void EmbedWindowDeleted(TkWindow *winPtr); + +/* + *---------------------------------------------------------------------- + * + * Tk_MacOSXSetEmbedHandler -- + * + * Registers a handler for an in process form of embedding, like Netscape + * plugins, where Tk is loaded into the process, but does not control the + * main window + * + * Results: + * None + * + * Side effects: + * The embed handler is set. + * + *---------------------------------------------------------------------- + */ + +void +Tk_MacOSXSetEmbedHandler( + Tk_MacOSXEmbedRegisterWinProc *registerWinProc, + Tk_MacOSXEmbedGetGrafPortProc *getPortProc, + Tk_MacOSXEmbedMakeContainerExistProc *containerExistProc, + Tk_MacOSXEmbedGetClipProc *getClipProc, + Tk_MacOSXEmbedGetOffsetInParentProc *getOffsetProc) +{ + if (tkMacOSXEmbedHandler == NULL) { + tkMacOSXEmbedHandler = ckalloc(sizeof(TkMacOSXEmbedHandler)); + } + tkMacOSXEmbedHandler->registerWinProc = registerWinProc; + tkMacOSXEmbedHandler->getPortProc = getPortProc; + tkMacOSXEmbedHandler->containerExistProc = containerExistProc; + tkMacOSXEmbedHandler->getClipProc = getClipProc; + tkMacOSXEmbedHandler->getOffsetProc = getOffsetProc; +} + +/* + *---------------------------------------------------------------------- + * + * TkpMakeWindow -- + * + * Creates an X Window (Mac subwindow). + * + * Results: + * The window id is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Window +TkpMakeWindow( + TkWindow *winPtr, + Window parent) +{ + MacDrawable *macWin; + + /* + * If this window is marked as embedded then the window structure should + * have already been created in the TkpUseWindow function. + */ + + if (Tk_IsEmbedded(winPtr)) { + macWin = winPtr->privatePtr; + } else { + /* + * Allocate sub window + */ + + macWin = ckalloc(sizeof(MacDrawable)); + if (macWin == NULL) { + winPtr->privatePtr = NULL; + return None; + } + macWin->winPtr = winPtr; + winPtr->privatePtr = macWin; + macWin->visRgn = NULL; + macWin->aboveVisRgn = NULL; + macWin->drawRgn = NULL; + macWin->referenceCount = 0; + macWin->flags = TK_CLIP_INVALID; + macWin->view = nil; + macWin->context = NULL; + macWin->size = CGSizeZero; + if (Tk_IsTopLevel(macWin->winPtr)) { + /* + * This will be set when we are mapped. + */ + + macWin->xOff = 0; + macWin->yOff = 0; + macWin->toplevel = macWin; + } else if (winPtr->parentPtr) { + macWin->xOff = winPtr->parentPtr->privatePtr->xOff + + winPtr->parentPtr->changes.border_width + + winPtr->changes.x; + macWin->yOff = winPtr->parentPtr->privatePtr->yOff + + winPtr->parentPtr->changes.border_width + + winPtr->changes.y; + macWin->toplevel = winPtr->parentPtr->privatePtr->toplevel; + } + macWin->toplevel->referenceCount++; + } + return (Window) macWin; +} + +/* + *---------------------------------------------------------------------- + * + * TkpScanWindowId -- + * + * Given a string, produce the corresponding Window Id. + * + * Results: + * The return value is normally TCL_OK; in this case *idPtr will be set + * to the Window value equivalent to string. If string is improperly + * formed then TCL_ERROR is returned and an error message will be left in + * the interp's result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpScanWindowId( + Tcl_Interp *interp, + CONST char * string, + Window *idPtr) +{ + int code; + Tcl_Obj obj; + + obj.refCount = 1; + obj.bytes = (char *) string; /* DANGER?! */ + obj.length = strlen(string); + obj.typePtr = NULL; + + code = Tcl_GetLongFromObj(interp, &obj, (long *)idPtr); + + if (obj.refCount > 1) { + Tcl_Panic("invalid sharing of Tcl_Obj on C stack"); + } + if (obj.typePtr && obj.typePtr->freeIntRepProc) { + obj.typePtr->freeIntRepProc(&obj); + } + return code; +} + +/* + *---------------------------------------------------------------------- + * + * TkpUseWindow -- + * + * This procedure causes a Tk window to use a given X window as its + * parent window, rather than the root window for the screen. It is + * invoked by an embedded application to specify the window in which it + * is embedded. + * + * Results: + * The return value is normally TCL_OK. If an error occurs (such as + * string not being a valid window spec), then the return value is + * TCL_ERROR and an error message is left in the interp's result if + * interp is non-NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpUseWindow( + Tcl_Interp *interp, /* If not NULL, used for error reporting if + * string is bogus. */ + Tk_Window tkwin, /* Tk window that does not yet have an + * associated X window. */ + const char *string) /* String identifying an X window to use for + * tkwin; must be an integer value. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + TkWindow *usePtr; + MacDrawable *parent, *macWin; + Container *containerPtr; + + if (winPtr->window != None) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't modify container after widget is created", -1)); + Tcl_SetErrorCode(interp, "TK", "EMBED", "POST_CREATE", NULL); + return TCL_ERROR; + } + + /* + * Decode the container window ID, and look for it among the list of + * available containers. + * + * N.B. For now, we are limiting the containers to be in the same Tk + * application as tkwin, since otherwise they would not be in our list of + * containers. + */ + + if (TkpScanWindowId(interp, string, (Window *)&parent) != TCL_OK) { + return TCL_ERROR; + } + + usePtr = (TkWindow *) Tk_IdToWindow(winPtr->display, (Window) parent); + if (usePtr != NULL && !(usePtr->flags & TK_CONTAINER)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "window \"%s\" doesn't have -container option set", + usePtr->pathName)); + Tcl_SetErrorCode(interp, "TK", "EMBED", "CONTAINER", NULL); + return TCL_ERROR; + } + + /* + * The code below can probably be simplified given we have already + * discovered 'usePtr' above. + */ + + /* + * Save information about the container and the embedded window in a + * Container structure. Currently, there must already be an existing + * Container structure, since we only allow the case where both container + * and embedded app. are in the same process. + */ + + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + if (containerPtr->parent == (Window) parent) { + winPtr->flags |= TK_BOTH_HALVES; + containerPtr->parentPtr->flags |= TK_BOTH_HALVES; + break; + } + } + + /* + * Make the embedded window. + */ + + macWin = ckalloc(sizeof(MacDrawable)); + if (macWin == NULL) { + winPtr->privatePtr = NULL; + return TCL_ERROR; + } + + macWin->winPtr = winPtr; + winPtr->privatePtr = macWin; + + /* + * The grafPtr will be NULL for a Tk in Tk embedded window. It is none of + * our business what it is for a Tk not in Tk embedded window, but we will + * initialize it to NULL, and let the registerWinProc set it. In any case, + * you must always use TkMacOSXGetDrawablePort to get the portPtr. It will + * correctly find the container's port. + */ + + macWin->view = nil; + macWin->context = NULL; + macWin->size = CGSizeZero; + macWin->visRgn = NULL; + macWin->aboveVisRgn = NULL; + macWin->drawRgn = NULL; + macWin->referenceCount = 0; + macWin->flags = TK_CLIP_INVALID; + macWin->toplevel = macWin; + macWin->toplevel->referenceCount++; + + winPtr->flags |= TK_EMBEDDED; + + /* + * Make a copy of the TK_EMBEDDED flag, since sometimes we need this to + * get the port after the TkWindow structure has been freed. + */ + + macWin->flags |= TK_EMBEDDED; + + /* + * Now check whether it is embedded in another Tk widget. If not (the + * first case below) we see if there is an in-process embedding handler + * registered, and if so, let that fill in the rest of the macWin. + */ + + if (containerPtr == NULL) { + /* + * If someone has registered an in-process embedding handler, then + * see if it can handle this window... + */ + + if (tkMacOSXEmbedHandler == NULL || + tkMacOSXEmbedHandler->registerWinProc((long) parent, + (Tk_Window) winPtr) != TCL_OK) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "The window ID %s does not correspond to a valid Tk Window", + string)); + Tcl_SetErrorCode(interp, "TK", "EMBED", "HANDLE", NULL); + return TCL_ERROR; + } + + containerPtr = ckalloc(sizeof(Container)); + + containerPtr->parentPtr = NULL; + containerPtr->embedded = (Window) macWin; + containerPtr->embeddedPtr = macWin->winPtr; + containerPtr->nextPtr = firstContainerPtr; + firstContainerPtr = containerPtr; + } else { + /* + * The window is embedded in another Tk window. + */ + + macWin->xOff = parent->winPtr->privatePtr->xOff + + parent->winPtr->changes.border_width + + winPtr->changes.x; + macWin->yOff = parent->winPtr->privatePtr->yOff + + parent->winPtr->changes.border_width + + winPtr->changes.y; + + /* + * Finish filling up the container structure with the embedded + * window's information. + */ + + containerPtr->embedded = (Window) macWin; + containerPtr->embeddedPtr = macWin->winPtr; + + /* + * Create an event handler to clean up the Container structure when + * tkwin is eventually deleted. + */ + + Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc, + winPtr); + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkpMakeContainer -- + * + * This procedure is called to indicate that a particular window will be + * a container for an embedded application. This changes certain aspects + * of the window's behavior, such as whether it will receive events + * anymore. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpMakeContainer( + Tk_Window tkwin) /* Token for a window that is about to become + * a container. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + Container *containerPtr; + + /* + * Register the window as a container so that, for example, we can make + * sure the argument to -use is valid. + */ + + Tk_MakeWindowExist(tkwin); + containerPtr = ckalloc(sizeof(Container)); + containerPtr->parent = Tk_WindowId(tkwin); + containerPtr->parentPtr = winPtr; + containerPtr->embedded = None; + containerPtr->embeddedPtr = NULL; + containerPtr->nextPtr = firstContainerPtr; + firstContainerPtr = containerPtr; + winPtr->flags |= TK_CONTAINER; + + /* + * Request SubstructureNotify events so that we can find out when the + * embedded application creates its window or attempts to resize it. Also + * watch Configure events on the container so that we can resize the child + * to match. Also, pass activate events from the container down to the + * embedded toplevel. + */ + + Tk_CreateEventHandler(tkwin, + SubstructureNotifyMask|SubstructureRedirectMask, + ContainerEventProc, winPtr); + Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbedStructureProc, + containerPtr); + Tk_CreateEventHandler(tkwin, ActivateMask, EmbedActivateProc, + containerPtr); + Tk_CreateEventHandler(tkwin, FocusChangeMask, EmbedFocusProc, + containerPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXContainerId -- + * + * Given an embedded window, this procedure returns the MacDrawable + * identifier for the associated container window. + * + * Results: + * The return value is the MacDrawable for winPtr's container window. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +MacDrawable * +TkMacOSXContainerId( + TkWindow *winPtr) /* Tk's structure for an embedded window. */ +{ + Container *containerPtr; + + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + if (containerPtr->embeddedPtr == winPtr) { + return (MacDrawable *) containerPtr->parent; + } + } + Tcl_Panic("TkMacOSXContainerId couldn't find window"); + return None; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXGetHostToplevel -- + * + * Given the TkWindow, return the MacDrawable for the outermost toplevel + * containing it. This will be a real Macintosh window. + * + * Results: + * Returns a MacDrawable corresponding to a Macintosh Toplevel + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +MacDrawable * +TkMacOSXGetHostToplevel( + TkWindow *winPtr) /* Tk's structure for a window. */ +{ + TkWindow *contWinPtr, *topWinPtr; + + topWinPtr = winPtr->privatePtr->toplevel->winPtr; + if (!Tk_IsEmbedded(topWinPtr)) { + return winPtr->privatePtr->toplevel; + } + contWinPtr = TkpGetOtherWindow(topWinPtr); + + /* + * TODO: Here we should handle out of process embedding. + */ + + if (contWinPtr == NULL) { + return None; + } + return TkMacOSXGetHostToplevel(contWinPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkpClaimFocus -- + * + * This procedure is invoked when someone asks for the input focus to be + * put on a window in an embedded application, but the application + * doesn't currently have the focus. It requests the input focus from the + * container application. + * + * Results: + * None. + * + * Side effects: + * The input focus may change. + * + *---------------------------------------------------------------------- + */ + +void +TkpClaimFocus( + TkWindow *topLevelPtr, /* Top-level window containing desired focus + * window; should be embedded. */ + int force) /* One means that the container should claim + * the focus if it doesn't currently have + * it. */ +{ + XEvent event; + Container *containerPtr; + + if (!(topLevelPtr->flags & TK_EMBEDDED)) { + return; + } + + for (containerPtr = firstContainerPtr; + containerPtr->embeddedPtr != topLevelPtr; + containerPtr = containerPtr->nextPtr) { + /* Empty loop body. */ + } + + event.xfocus.type = FocusIn; + event.xfocus.serial = LastKnownRequestProcessed(topLevelPtr->display); + event.xfocus.send_event = 1; + event.xfocus.display = topLevelPtr->display; + event.xfocus.window = containerPtr->parent; + event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS; + event.xfocus.detail = force; + Tk_QueueWindowEvent(&event,TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * + * TkpTestembedCmd -- + * + * This procedure implements the "testembed" command. It returns some or + * all of the information in the list pointed to by firstContainerPtr. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpTestembedCmd( + ClientData clientData, /* Main window for application. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument strings. */ +{ + int all; + Container *containerPtr; + Tcl_DString dString; + char buffer[50]; + + if ((objc > 1) && (strcmp(Tcl_GetString(objv[1]), "all") == 0)) { + all = 1; + } else { + all = 0; + } + Tcl_DStringInit(&dString); + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + Tcl_DStringStartSublist(&dString); + if (containerPtr->parent == None) { + Tcl_DStringAppendElement(&dString, ""); + } else if (all) { + sprintf(buffer, "0x%x", (int) containerPtr->parent); + Tcl_DStringAppendElement(&dString, buffer); + } else { + Tcl_DStringAppendElement(&dString, "XXX"); + } + if (containerPtr->parentPtr == NULL) { + Tcl_DStringAppendElement(&dString, ""); + } else { + Tcl_DStringAppendElement(&dString, + containerPtr->parentPtr->pathName); + } + if (containerPtr->embedded == None) { + Tcl_DStringAppendElement(&dString, ""); + } else if (all) { + sprintf(buffer, "0x%x", (int) containerPtr->embedded); + Tcl_DStringAppendElement(&dString, buffer); + } else { + Tcl_DStringAppendElement(&dString, "XXX"); + } + if (containerPtr->embeddedPtr == NULL) { + Tcl_DStringAppendElement(&dString, ""); + } else { + Tcl_DStringAppendElement(&dString, + containerPtr->embeddedPtr->pathName); + } + Tcl_DStringEndSublist(&dString); + } + Tcl_DStringResult(interp, &dString); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkpRedirectKeyEvent -- + * + * This procedure is invoked when a key press or release event arrives + * for an application that does not believe it owns the input focus. This + * can happen because of embedding; for example, X can send an event to + * an embedded application when the real focus window is in the container + * application and is an ancestor of the container. This procedure's job + * is to forward the event back to the application where it really + * belongs. + * + * Results: + * None. + * + * Side effects: + * The event may get sent to a different application. + * + *---------------------------------------------------------------------- + */ + +void +TkpRedirectKeyEvent( + TkWindow *winPtr, /* Window to which the event was originally + * reported. */ + XEvent *eventPtr) /* X event to redirect (should be KeyPress or + * KeyRelease). */ +{ + /* TODO: Implement this or decide it definitely needs no implementation */ +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetOtherWindow -- + * + * If both the container and embedded window are in the same process, + * this procedure will return either one, given the other. + * + * Results: + * If winPtr is a container, the return value is the token for the + * embedded window, and vice versa. If the "other" window isn't in this + * process, NULL is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkWindow * +TkpGetOtherWindow( + TkWindow *winPtr) /* Tk's structure for a container or embedded + * window. */ +{ + Container *containerPtr; + + /* + * TkpGetOtherWindow returns NULL if both windows are not in the same + * process... + */ + + if (!(winPtr->flags & TK_BOTH_HALVES)) { + return NULL; + } + + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + if (containerPtr->embeddedPtr == winPtr) { + return containerPtr->parentPtr; + } else if (containerPtr->parentPtr == winPtr) { + return containerPtr->embeddedPtr; + } + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * EmbeddedEventProc -- + * + * This procedure is invoked by the Tk event dispatcher when various + * useful events are received for a window that is embedded in + * another application. + * + * Results: + * None. + * + * Side effects: + * Our internal state gets cleaned up when an embedded window is + * destroyed. + * + *---------------------------------------------------------------------- + */ + +static void +EmbeddedEventProc( + ClientData clientData, /* Token for container window. */ + XEvent *eventPtr) /* ResizeRequest event. */ +{ + TkWindow *winPtr = clientData; + + if (eventPtr->type == DestroyNotify) { + EmbedWindowDeleted(winPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * ContainerEventProc -- + * + * This procedure is invoked by the Tk event dispatcher when various + * useful events are received for the children of a container window. It + * forwards relevant information, such as geometry requests, from the + * events into the container's application. + * + * NOTE: on the Mac, only the DestroyNotify branch is ever taken. We + * don't synthesize the other events. + * + * Results: + * None. + * + * Side effects: + * Depends on the event. For example, when ConfigureRequest events occur, + * geometry information gets set for the container window. + * + *---------------------------------------------------------------------- + */ + +static void +ContainerEventProc( + ClientData clientData, /* Token for container window. */ + XEvent *eventPtr) /* ResizeRequest event. */ +{ + TkWindow *winPtr = clientData; + Container *containerPtr; + Tk_ErrorHandler errHandler; + + /* + * Ignore any X protocol errors that happen in this procedure (almost any + * operation could fail, for example, if the embedded application has + * deleted its window). + */ + + errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1, + -1, -1, NULL, NULL); + + /* + * Find the Container structure associated with the parent window. + */ + + for (containerPtr = firstContainerPtr; + containerPtr->parent != eventPtr->xmaprequest.parent; + containerPtr = containerPtr->nextPtr) { + if (containerPtr == NULL) { + Tcl_Panic("ContainerEventProc couldn't find Container record"); + } + } + + if (eventPtr->type == CreateNotify) { + /* + * A new child window has been created in the container. Record its id + * in the Container structure (if more than one child is created, just + * remember the last one and ignore the earlier ones). + */ + + containerPtr->embedded = eventPtr->xcreatewindow.window; + } else if (eventPtr->type == ConfigureRequest) { + if ((eventPtr->xconfigurerequest.x != 0) + || (eventPtr->xconfigurerequest.y != 0)) { + /* + * The embedded application is trying to move itself, which isn't + * legal. At this point, the window hasn't actually moved, but we + * need to send it a ConfigureNotify event to let it know that its + * request has been denied. If the embedded application was also + * trying to resize itself, a ConfigureNotify will be sent by the + * geometry management code below, so we don't need to do + * anything. Otherwise, generate a synthetic event. + */ + + if ((eventPtr->xconfigurerequest.width == winPtr->changes.width) + && (eventPtr->xconfigurerequest.height + == winPtr->changes.height)) { + EmbedSendConfigure(containerPtr); + } + } + EmbedGeometryRequest(containerPtr, + eventPtr->xconfigurerequest.width, + eventPtr->xconfigurerequest.height); + } else if (eventPtr->type == MapRequest) { + /* + * The embedded application's map request was ignored and simply + * passed on to us, so we have to map the window for it to appear on + * the screen. + */ + + XMapWindow(eventPtr->xmaprequest.display, + eventPtr->xmaprequest.window); + } else if (eventPtr->type == DestroyNotify) { + /* + * The embedded application is gone. Destroy the container window. + */ + + Tk_DestroyWindow((Tk_Window) winPtr); + } + Tk_DeleteErrorHandler(errHandler); +} + +/* + *---------------------------------------------------------------------- + * + * EmbedStructureProc -- + * + * This procedure is invoked by the Tk event dispatcher when a container + * window owned by this application gets resized (and also at several + * other times that we don't care about). This procedure reflects the + * size change in the embedded window that corresponds to the container. + * + * Results: + * None. + * + * Side effects: + * The embedded window gets resized to match the container. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedStructureProc( + ClientData clientData, /* Token for container window. */ + XEvent *eventPtr) /* ResizeRequest event. */ +{ + Container *containerPtr = clientData; + Tk_ErrorHandler errHandler; + + if (eventPtr->type == ConfigureNotify) { + if (containerPtr->embedded != None) { + /* + * Ignore errors, since the embedded application could have + * deleted its window. + */ + + errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1, + -1, -1, NULL, NULL); + Tk_MoveResizeWindow((Tk_Window) containerPtr->embeddedPtr, 0, 0, + (unsigned) Tk_Width((Tk_Window) containerPtr->parentPtr), + (unsigned) Tk_Height((Tk_Window)containerPtr->parentPtr)); + Tk_DeleteErrorHandler(errHandler); + } + } else if (eventPtr->type == DestroyNotify) { + EmbedWindowDeleted(containerPtr->parentPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedActivateProc -- + * + * This procedure is invoked by the Tk event dispatcher when Activate and + * Deactivate events occur for a container window owned by this + * application. It is responsible for forwarding an activate event down + * into the embedded toplevel. + * + * Results: + * None. + * + * Side effects: + * The X focus may change. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedActivateProc( + ClientData clientData, /* Token for container window. */ + XEvent *eventPtr) /* ResizeRequest event. */ +{ + Container *containerPtr = clientData; + + if (containerPtr->embeddedPtr != NULL) { + if (eventPtr->type == ActivateNotify) { + TkGenerateActivateEvents(containerPtr->embeddedPtr,1); + } else if (eventPtr->type == DeactivateNotify) { + TkGenerateActivateEvents(containerPtr->embeddedPtr,0); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedFocusProc -- + * + * This procedure is invoked by the Tk event dispatcher when FocusIn and + * FocusOut events occur for a container window owned by this + * application. It is responsible for moving the focus back and forth + * between a container application and an embedded application. + * + * Results: + * None. + * + * Side effects: + * The X focus may change. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedFocusProc( + ClientData clientData, /* Token for container window. */ + XEvent *eventPtr) /* ResizeRequest event. */ +{ + Container *containerPtr = clientData; + Display *display; + XEvent event; + + if (containerPtr->embeddedPtr != NULL) { + display = Tk_Display(containerPtr->parentPtr); + event.xfocus.serial = LastKnownRequestProcessed(display); + event.xfocus.send_event = false; + event.xfocus.display = display; + event.xfocus.mode = NotifyNormal; + event.xfocus.window = containerPtr->embedded; + + if (eventPtr->type == FocusIn) { + /* + * The focus just arrived at the container. Change the X focus to + * move it to the embedded application, if there is one. Ignore X + * errors that occur during this operation (it's possible that the + * new focus window isn't mapped). + */ + + event.xfocus.detail = NotifyNonlinear; + event.xfocus.type = FocusIn; + } else if (eventPtr->type == FocusOut) { + /* + * When the container gets a FocusOut event, it has to tell the + * embedded app that it has lost the focus. + */ + + event.xfocus.type = FocusOut; + event.xfocus.detail = NotifyNonlinear; + } + + Tk_QueueWindowEvent(&event, TCL_QUEUE_MARK); + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedGeometryRequest -- + * + * This procedure is invoked when an embedded application requests a + * particular size. It processes the request (which may or may not + * actually honor the request) and reflects the results back to the + * embedded application. + * + * NOTE: On the Mac, this is a stub, since we don't synthesize + * ConfigureRequest events. + * + * Results: + * None. + * + * Side effects: + * If we deny the child's size change request, a Configure event is + * synthesized to let the child know how big it ought to be. Events get + * processed while we're waiting for the geometry managers to do their + * thing. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedGeometryRequest( + Container *containerPtr, /* Information about the embedding. */ + int width, int height) /* Size that the child has requested. */ +{ + TkWindow *winPtr = containerPtr->parentPtr; + + /* + * Forward the requested size into our geometry management hierarchy via + * the container window. We need to send a Configure event back to the + * embedded application if we decide not to honor its request; to make + * this happen, process all idle event handlers synchronously here (so + * that the geometry managers have had a chance to do whatever they want + * to do), and if the window's size didn't change then generate a + * configure event. + */ + + Tk_GeometryRequest((Tk_Window) winPtr, width, height); + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) { + /* Empty loop body. */ + } + if ((winPtr->changes.width != width) + || (winPtr->changes.height != height)) { + EmbedSendConfigure(containerPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedSendConfigure -- + * + * This is currently a stub. It is called to notify an embedded + * application of its current size and location. This procedure is called + * when the embedded application made a geometry request that we did not + * grant, so that the embedded application knows that its geometry didn't + * change after all. It is a response to ConfigureRequest events, which + * we do not currently synthesize on the Mac + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedSendConfigure( + Container *containerPtr) /* Information about the embedding. */ +{ +} + +/* + *---------------------------------------------------------------------- + * + * EmbedWindowDeleted -- + * + * This procedure is invoked when a window involved in embedding (as + * either the container or the embedded application) is destroyed. It + * cleans up the Container structure for the window. + * + * Results: + * None. + * + * Side effects: + * A Container structure may be freed. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedWindowDeleted( + TkWindow *winPtr) /* Tk's information about window that + * was deleted. */ +{ + Container *containerPtr, *prevPtr; + + /* + * Find the Container structure for this window. Delete the information + * about the embedded application and free the container's record. + */ + + prevPtr = NULL; + containerPtr = firstContainerPtr; + while (1) { + if (containerPtr->embeddedPtr == winPtr) { + /* + * We also have to destroy our parent, to clean up the container. + * Fabricate an event to do this. + */ + + if (containerPtr->parentPtr != NULL && + containerPtr->parentPtr->flags & TK_BOTH_HALVES) { + XEvent event; + + event.xany.serial = + LastKnownRequestProcessed(Tk_Display(containerPtr->parentPtr)); + event.xany.send_event = False; + event.xany.display = Tk_Display(containerPtr->parentPtr); + + event.xany.type = DestroyNotify; + event.xany.window = containerPtr->parent; + event.xdestroywindow.event = containerPtr->parent; + Tk_QueueWindowEvent(&event, TCL_QUEUE_HEAD); + } + + containerPtr->embedded = None; + containerPtr->embeddedPtr = NULL; + break; + } + if (containerPtr->parentPtr == winPtr) { + containerPtr->parentPtr = NULL; + break; + } + prevPtr = containerPtr; + containerPtr = containerPtr->nextPtr; + } + if ((containerPtr->embeddedPtr == NULL) + && (containerPtr->parentPtr == NULL)) { + if (prevPtr == NULL) { + firstContainerPtr = containerPtr->nextPtr; + } else { + prevPtr->nextPtr = containerPtr->nextPtr; + } + ckfree(containerPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpShowBusyWindow, TkpHideBusyWindow, TkpMakeTransparentWindowExist, + * TkpCreateBusy -- + * + * Portability layer for busy windows. Holds platform-specific gunk for + * the [tk busy] command, which is currently a dummy implementation for + * OSX/Aqua. The individual functions are supposed to do the following: + * + * TkpShowBusyWindow -- + * Make the busy window appear. + * + * TkpHideBusyWindow -- + * Make the busy window go away. + * + * TkpMakeTransparentWindowExist -- + * Actually make a transparent window. + * + * TkpCreateBusy -- + * Creates the platform-specific part of a busy window structure. + * + *---------------------------------------------------------------------- + */ + +void +TkpShowBusyWindow( + TkBusy busy) +{ +} + +void +TkpHideBusyWindow( + TkBusy busy) +{ +} + +void +TkpMakeTransparentWindowExist( + Tk_Window tkwin, /* Token for window. */ + Window parent) /* Parent window. */ +{ +} + +void +TkpCreateBusy( + Tk_FakeWin *winPtr, + Tk_Window tkRef, + Window* parentPtr, + Tk_Window tkParent, + TkBusy busy) +{ +} + +/* + * Local Variables: + * mode: objc + * c-basic-offset: 4 + * fill-column: 79 + * coding: utf-8 + * End: + */ |