/* RemoveSlave -- * Unmanage and delete the slave. * * NOTES/ASSUMPTIONS: * * [1] It's safe to call Tk_UnmapWindow / Tk_UnmaintainGeometry even if this * routine is called from the slave's DestroyNotify event handler. */ static void RemoveSlave(Ttk_Manager *mgr, int index) { Ttk_Slave *slave = mgr->slaves[index]; int i; /* Notify manager: */ mgr->managerSpec->SlaveRemoved(mgr->managerData, index); /* Remove from array: */ --mgr->nSlaves; for (i = index ; i < mgr->nSlaves; ++i) { mgr->slaves[i] = mgr->slaves[i+1]; } /* Clean up: */ Tk_DeleteEventHandler( slave->slaveWindow, SlaveEventMask, SlaveEventHandler, slave); /* Note [1] */ Tk_UnmaintainGeometry(slave->slaveWindow, mgr->masterWindow); Tk_UnmapWindow(slave->slaveWindow); DeleteSlave(slave); ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED); }
/* ++ Ttk_UnmapSlave -- * Unmap the specified slave, but leave it managed. */ void Ttk_UnmapSlave(Ttk_Manager *mgr, int slaveIndex) { Ttk_Slave *slave = mgr->slaves[slaveIndex]; Tk_UnmaintainGeometry(slave->slaveWindow, mgr->masterWindow); slave->flags &= ~SLAVE_MAPPED; /* Contrary to documentation, Tk_UnmaintainGeometry doesn't always * unmap the slave: */ Tk_UnmapWindow(slave->slaveWindow); }
static void EmbWinDelayedUnmap( ClientData clientData) /* Token for the window to be unmapped. */ { TkTextEmbWindowClient *client = clientData; if (!client->displayed && (client->tkwin != NULL)) { if (client->textPtr->tkwin != Tk_Parent(client->tkwin)) { Tk_UnmaintainGeometry(client->tkwin, client->textPtr->tkwin); } else { Tk_UnmapWindow(client->tkwin); } } }
/* * A managed window turns control over * to another geometry manager. */ static void WindowItemLostSlave(ClientData client_data, Tk_Window win) { WindowItem wind = (WindowItem) client_data; ZnWInfo *wi = ((ZnItem) wind)->wi; Tk_DeleteEventHandler(wi->win, StructureNotifyMask, WindowDeleted, (ClientData) wind); if (wi->win != Tk_Parent(wind->win)) { Tk_UnmaintainGeometry(wind->win, wi->win); } Tk_UnmapWindow(wind->win); wind->win = NULL; }
static void EmbWinLostSlaveProc( ClientData clientData, /* Pointer to record describing window item. */ Tk_Window tkwin) /* Window that was claimed away by another * geometry manager. */ { TkTextEmbWindowClient *client = clientData; TkTextSegment *ewPtr = client->parent; TkTextIndex index; Tcl_HashEntry *hPtr; TkTextEmbWindowClient *loop; Tk_DeleteEventHandler(client->tkwin, StructureNotifyMask, EmbWinStructureProc, client); Tcl_CancelIdleCall(EmbWinDelayedUnmap, client); if (client->textPtr->tkwin != Tk_Parent(tkwin)) { Tk_UnmaintainGeometry(tkwin, client->textPtr->tkwin); } else { Tk_UnmapWindow(tkwin); } hPtr = Tcl_FindHashEntry(&ewPtr->body.ew.sharedTextPtr->windowTable, Tk_PathName(client->tkwin)); Tcl_DeleteHashEntry(hPtr); client->tkwin = NULL; ewPtr->body.ew.tkwin = NULL; /* * Free up the memory allocation for this client. */ loop = ewPtr->body.ew.clients; if (loop == client) { ewPtr->body.ew.clients = client->next; } else { while (loop->next != client) { loop = loop->next; } loop->next = client->next; } ckfree((char *) client); index.tree = ewPtr->body.ew.sharedTextPtr->tree; index.linePtr = ewPtr->body.ew.linePtr; index.byteIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); TkTextChanged(ewPtr->body.ew.sharedTextPtr, NULL, &index, &index); TkTextInvalidateLineMetrics(ewPtr->body.ew.sharedTextPtr, NULL, index.linePtr, 0, TK_TEXT_INVALIDATE_ONLY); }
/* ARGSUSED */ static void WinItemLostSlaveProc( ClientData clientData, /* WindowItem structure for slave window that * was stolen away. */ Tk_Window tkwin) /* Tk's handle for the slave window. */ { WindowItem *winItemPtr = clientData; Tk_Window canvasTkwin = Tk_CanvasTkwin(winItemPtr->canvas); Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, WinItemStructureProc, winItemPtr); if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); } Tk_UnmapWindow(winItemPtr->tkwin); winItemPtr->tkwin = NULL; }
static void DeleteWinItem( Tk_Canvas canvas, /* Overall info about widget. */ Tk_Item *itemPtr, /* Item that is being deleted. */ Display *display) /* Display containing window for canvas. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); if (winItemPtr->tkwin != NULL) { Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, WinItemStructureProc, winItemPtr); Tk_ManageGeometry(winItemPtr->tkwin, NULL, NULL); if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); } Tk_UnmapWindow(winItemPtr->tkwin); } }
/* ARGSUSED */ static void PlaceLostSlaveProc( ClientData clientData, /* Slave structure for slave window that was * stolen away. */ Tk_Window tkwin) /* Tk's handle for the slave window. */ { register Slave *slavePtr = clientData; TkDisplay *dispPtr = ((TkWindow *) slavePtr->tkwin)->dispPtr; if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); } Tk_UnmapWindow(tkwin); UnlinkSlave(slavePtr); Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->slaveTable, (char *) tkwin)); Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, slavePtr); FreeSlave(slavePtr); }
static void RecomputePlacement( ClientData clientData) /* Pointer to Master record. */ { register Master *masterPtr = clientData; register Slave *slavePtr; int x, y, width, height, tmp; int masterWidth, masterHeight, masterX, masterY; double x1, y1, x2, y2; int abort; /* May get set to non-zero to abort this * placement operation. */ masterPtr->flags &= ~PARENT_RECONFIG_PENDING; /* * Abort any nested call to RecomputePlacement for this window, since * we'll do everything necessary here, and set up so this call can be * aborted if necessary. */ if (masterPtr->abortPtr != NULL) { *masterPtr->abortPtr = 1; } masterPtr->abortPtr = &abort; abort = 0; Tcl_Preserve(masterPtr); /* * Iterate over all the slaves for the master. Each slave's geometry can * be computed independently of the other slaves. Changes to the window's * structure could cause almost anything to happen, including deleting the * parent or child. If this happens, we'll be told to abort. */ for (slavePtr = masterPtr->slavePtr; slavePtr != NULL && !abort; slavePtr = slavePtr->nextPtr) { /* * Step 1: compute size and borderwidth of master, taking into account * desired border mode. */ masterX = masterY = 0; masterWidth = Tk_Width(masterPtr->tkwin); masterHeight = Tk_Height(masterPtr->tkwin); if (slavePtr->borderMode == BM_INSIDE) { masterX = Tk_InternalBorderLeft(masterPtr->tkwin); masterY = Tk_InternalBorderTop(masterPtr->tkwin); masterWidth -= masterX + Tk_InternalBorderRight(masterPtr->tkwin); masterHeight -= masterY + Tk_InternalBorderBottom(masterPtr->tkwin); } else if (slavePtr->borderMode == BM_OUTSIDE) { masterX = masterY = -Tk_Changes(masterPtr->tkwin)->border_width; masterWidth -= 2 * masterX; masterHeight -= 2 * masterY; } /* * Step 2: compute size of slave (outside dimensions including border) * and location of anchor point within master. */ x1 = slavePtr->x + masterX + (slavePtr->relX*masterWidth); x = (int) (x1 + ((x1 > 0) ? 0.5 : -0.5)); y1 = slavePtr->y + masterY + (slavePtr->relY*masterHeight); y = (int) (y1 + ((y1 > 0) ? 0.5 : -0.5)); if (slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) { width = 0; if (slavePtr->flags & CHILD_WIDTH) { width += slavePtr->width; } if (slavePtr->flags & CHILD_REL_WIDTH) { /* * The code below is a bit tricky. In order to round correctly * when both relX and relWidth are specified, compute the * location of the right edge and round that, then compute * width. If we compute the width and round it, rounding * errors in relX and relWidth accumulate. */ x2 = x1 + (slavePtr->relWidth*masterWidth); tmp = (int) (x2 + ((x2 > 0) ? 0.5 : -0.5)); width += tmp - x; } } else { width = Tk_ReqWidth(slavePtr->tkwin) + 2*Tk_Changes(slavePtr->tkwin)->border_width; } if (slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) { height = 0; if (slavePtr->flags & CHILD_HEIGHT) { height += slavePtr->height; } if (slavePtr->flags & CHILD_REL_HEIGHT) { /* * See note above for rounding errors in width computation. */ y2 = y1 + (slavePtr->relHeight*masterHeight); tmp = (int) (y2 + ((y2 > 0) ? 0.5 : -0.5)); height += tmp - y; } } else { height = Tk_ReqHeight(slavePtr->tkwin) + 2*Tk_Changes(slavePtr->tkwin)->border_width; } /* * Step 3: adjust the x and y positions so that the desired anchor * point on the slave appears at that position. Also adjust for the * border mode and master's border. */ switch (slavePtr->anchor) { case TK_ANCHOR_N: x -= width/2; break; case TK_ANCHOR_NE: x -= width; break; case TK_ANCHOR_E: x -= width; y -= height/2; break; case TK_ANCHOR_SE: x -= width; y -= height; break; case TK_ANCHOR_S: x -= width/2; y -= height; break; case TK_ANCHOR_SW: y -= height; break; case TK_ANCHOR_W: y -= height/2; break; case TK_ANCHOR_NW: break; case TK_ANCHOR_CENTER: x -= width/2; y -= height/2; break; } /* * Step 4: adjust width and height again to reflect inside dimensions * of window rather than outside. Also make sure that the width and * height aren't zero. */ width -= 2*Tk_Changes(slavePtr->tkwin)->border_width; height -= 2*Tk_Changes(slavePtr->tkwin)->border_width; if (width <= 0) { width = 1; } if (height <= 0) { height = 1; } /* * Step 5: reconfigure the window and map it if needed. If the slave * is a child of the master, we do this ourselves. If the slave isn't * a child of the master, let Tk_MaintainGeometry do the work (it will * re-adjust things as relevant windows map, unmap, and move). */ if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) { if ((x != Tk_X(slavePtr->tkwin)) || (y != Tk_Y(slavePtr->tkwin)) || (width != Tk_Width(slavePtr->tkwin)) || (height != Tk_Height(slavePtr->tkwin))) { Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height); } if (abort) { break; } /* * Don't map the slave unless the master is mapped: the slave will * get mapped later, when the master is mapped. */ if (Tk_IsMapped(masterPtr->tkwin)) { Tk_MapWindow(slavePtr->tkwin); } } else { if ((width <= 0) || (height <= 0)) { Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin); Tk_UnmapWindow(slavePtr->tkwin); } else { Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin, x, y, width, height); } } } masterPtr->abortPtr = NULL; Tcl_Release(masterPtr); }
static int ConfigureSlave( Tcl_Interp *interp, /* Used for error reporting. */ Tk_Window tkwin, /* Token for the window to manipulate. */ Tk_OptionTable table, /* Token for option table. */ int objc, /* Number of config arguments. */ Tcl_Obj *const objv[]) /* Object values for arguments. */ { register Master *masterPtr; Tk_SavedOptions savedOptions; int mask; Slave *slavePtr; Tk_Window masterWin = (Tk_Window) NULL; if (Tk_TopWinHierarchy(tkwin)) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't use placer on top-level window \"%s\"; use " "wm command instead", Tk_PathName(tkwin))); Tcl_SetErrorCode(interp, "TK", "GEOMETRY", "TOPLEVEL", NULL); return TCL_ERROR; } slavePtr = CreateSlave(tkwin, table); if (Tk_SetOptions(interp, (char *) slavePtr, table, objc, objv, slavePtr->tkwin, &savedOptions, &mask) != TCL_OK) { goto error; } /* * Set slave flags. First clear the field, then add bits as needed. */ slavePtr->flags = 0; if (slavePtr->heightPtr) { slavePtr->flags |= CHILD_HEIGHT; } if (slavePtr->relHeightPtr) { slavePtr->flags |= CHILD_REL_HEIGHT; } if (slavePtr->relWidthPtr) { slavePtr->flags |= CHILD_REL_WIDTH; } if (slavePtr->widthPtr) { slavePtr->flags |= CHILD_WIDTH; } if (!(mask & IN_MASK) && (slavePtr->masterPtr != NULL)) { /* * If no -in option was passed and the slave is already placed then * just recompute the placement. */ masterPtr = slavePtr->masterPtr; goto scheduleLayout; } else if (mask & IN_MASK) { /* -in changed */ Tk_Window tkwin; Tk_Window ancestor; tkwin = slavePtr->inTkwin; /* * Make sure that the new master is either the logical parent of the * slave or a descendant of that window, and that the master and slave * aren't the same. */ for (ancestor = tkwin; ; ancestor = Tk_Parent(ancestor)) { if (ancestor == Tk_Parent(slavePtr->tkwin)) { break; } if (Tk_TopWinHierarchy(ancestor)) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't place %s relative to %s", Tk_PathName(slavePtr->tkwin), Tk_PathName(tkwin))); Tcl_SetErrorCode(interp, "TK", "GEOMETRY", "HIERARCHY", NULL); goto error; } } if (slavePtr->tkwin == tkwin) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't place %s relative to itself", Tk_PathName(slavePtr->tkwin))); Tcl_SetErrorCode(interp, "TK", "GEOMETRY", "LOOP", NULL); goto error; } if ((slavePtr->masterPtr != NULL) && (slavePtr->masterPtr->tkwin == tkwin)) { /* * Re-using same old master. Nothing to do. */ masterPtr = slavePtr->masterPtr; goto scheduleLayout; } if ((slavePtr->masterPtr != NULL) && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) { Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); } UnlinkSlave(slavePtr); masterWin = tkwin; } /* * If there's no master specified for this slave, use its Tk_Parent. */ if (masterWin == NULL) { masterWin = Tk_Parent(slavePtr->tkwin); slavePtr->inTkwin = masterWin; } /* * Manage the slave window in this master. */ masterPtr = CreateMaster(masterWin); slavePtr->masterPtr = masterPtr; slavePtr->nextPtr = masterPtr->slavePtr; masterPtr->slavePtr = slavePtr; Tk_ManageGeometry(slavePtr->tkwin, &placerType, slavePtr); /* * Arrange for the master to be re-arranged at the first idle moment. */ scheduleLayout: Tk_FreeSavedOptions(&savedOptions); if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) { masterPtr->flags |= PARENT_RECONFIG_PENDING; Tcl_DoWhenIdle(RecomputePlacement, masterPtr); } return TCL_OK; /* * Error while processing some option, cleanup and return. */ error: Tk_RestoreSavedOptions(&savedOptions); return TCL_ERROR; }
int Tk_PlaceObjCmd( ClientData clientData, /* Interpreter main window. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tk_Window main_win = clientData; Tk_Window tkwin; Slave *slavePtr; TkDisplay *dispPtr; Tk_OptionTable optionTable; static const char *const optionStrings[] = { "configure", "forget", "info", "slaves", NULL }; enum options { PLACE_CONFIGURE, PLACE_FORGET, PLACE_INFO, PLACE_SLAVES }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "option|pathName args"); return TCL_ERROR; } /* * Create the option table for this widget class. If it has already been * created, the cached pointer will be returned. */ optionTable = Tk_CreateOptionTable(interp, optionSpecs); /* * Handle special shortcut where window name is first argument. */ if (Tcl_GetString(objv[1])[0] == '.') { if (TkGetWindowFromObj(interp, main_win, objv[1], &tkwin) != TCL_OK) { return TCL_ERROR; } /* * Initialize, if that hasn't been done yet. */ dispPtr = ((TkWindow *) tkwin)->dispPtr; if (!dispPtr->placeInit) { Tcl_InitHashTable(&dispPtr->masterTable, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&dispPtr->slaveTable, TCL_ONE_WORD_KEYS); dispPtr->placeInit = 1; } return ConfigureSlave(interp, tkwin, optionTable, objc-2, objv+2); } /* * Handle more general case of option followed by window name followed by * possible additional arguments. */ if (TkGetWindowFromObj(interp, main_win, objv[2], &tkwin) != TCL_OK) { return TCL_ERROR; } /* * Initialize, if that hasn't been done yet. */ dispPtr = ((TkWindow *) tkwin)->dispPtr; if (!dispPtr->placeInit) { Tcl_InitHashTable(&dispPtr->masterTable, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&dispPtr->slaveTable, TCL_ONE_WORD_KEYS); dispPtr->placeInit = 1; } if (Tcl_GetIndexFromObjStruct(interp, objv[1], optionStrings, sizeof(char *), "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case PLACE_CONFIGURE: if (objc == 3 || objc == 4) { Tcl_Obj *objPtr; slavePtr = FindSlave(tkwin); if (slavePtr == NULL) { return TCL_OK; } objPtr = Tk_GetOptionInfo(interp, (char *) slavePtr, optionTable, (objc == 4) ? objv[3] : NULL, tkwin); if (objPtr == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, objPtr); return TCL_OK; } return ConfigureSlave(interp, tkwin, optionTable, objc-3, objv+3); case PLACE_FORGET: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "pathName"); return TCL_ERROR; } slavePtr = FindSlave(tkwin); if (slavePtr == NULL) { return TCL_OK; } if ((slavePtr->masterPtr != NULL) && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) { Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); } UnlinkSlave(slavePtr); Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->slaveTable, (char *) tkwin)); Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, slavePtr); Tk_ManageGeometry(tkwin, NULL, NULL); Tk_UnmapWindow(tkwin); FreeSlave(slavePtr); break; case PLACE_INFO: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "pathName"); return TCL_ERROR; } return PlaceInfoCommand(interp, tkwin); case PLACE_SLAVES: { Master *masterPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "pathName"); return TCL_ERROR; } masterPtr = FindMaster(tkwin); if (masterPtr != NULL) { Tcl_Obj *listPtr = Tcl_NewObj(); for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { Tcl_ListObjAppendElement(NULL, listPtr, TkNewWindowObj(slavePtr->tkwin)); } Tcl_SetObjResult(interp, listPtr); } break; } } return TCL_OK; }
static int EmbWinConfigure( TkText *textPtr, /* Information about text widget that contains * embedded window. */ TkTextSegment *ewPtr, /* Embedded window to be configured. */ int objc, /* Number of strings in objv. */ Tcl_Obj *const objv[]) /* Array of objects describing configuration * options. */ { Tk_Window oldWindow; TkTextEmbWindowClient *client; /* * Copy over client specific value before querying or setting. */ client = EmbWinGetClient(textPtr, ewPtr); if (client != NULL) { ewPtr->body.ew.tkwin = client->tkwin; } else { ewPtr->body.ew.tkwin = NULL; } oldWindow = ewPtr->body.ew.tkwin; if (Tk_SetOptions(textPtr->interp, (char *) &ewPtr->body.ew, ewPtr->body.ew.optionTable, objc, objv, textPtr->tkwin, NULL, NULL) != TCL_OK) { return TCL_ERROR; } if (oldWindow != ewPtr->body.ew.tkwin) { if (oldWindow != NULL) { Tcl_DeleteHashEntry(Tcl_FindHashEntry( &textPtr->sharedTextPtr->windowTable, Tk_PathName(oldWindow))); Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, EmbWinStructureProc, client); Tk_ManageGeometry(oldWindow, NULL, NULL); if (textPtr->tkwin != Tk_Parent(oldWindow)) { Tk_UnmaintainGeometry(oldWindow, textPtr->tkwin); } else { Tk_UnmapWindow(oldWindow); } } if (client != NULL) { client->tkwin = NULL; } if (ewPtr->body.ew.tkwin != NULL) { Tk_Window ancestor, parent; Tcl_HashEntry *hPtr; int isNew; /* * Make sure that the text is either the parent of the embedded * window or a descendant of that parent. Also, don't allow a * top-level window to be managed inside a text. */ parent = Tk_Parent(ewPtr->body.ew.tkwin); for (ancestor = textPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) { if (ancestor == parent) { break; } if (Tk_TopWinHierarchy(ancestor)) { badMaster: Tcl_AppendResult(textPtr->interp, "can't embed ", Tk_PathName(ewPtr->body.ew.tkwin), " in ", Tk_PathName(textPtr->tkwin), NULL); ewPtr->body.ew.tkwin = NULL; if (client != NULL) { client->tkwin = NULL; } return TCL_ERROR; } } if (Tk_TopWinHierarchy(ewPtr->body.ew.tkwin) || (ewPtr->body.ew.tkwin == textPtr->tkwin)) { goto badMaster; } if (client == NULL) { /* * Have to make the new client. */ client = (TkTextEmbWindowClient *) ckalloc(sizeof(TkTextEmbWindowClient)); client->next = ewPtr->body.ew.clients; client->textPtr = textPtr; client->tkwin = NULL; client->chunkCount = 0; client->displayed = 0; client->parent = ewPtr; ewPtr->body.ew.clients = client; } client->tkwin = ewPtr->body.ew.tkwin; /* * Take over geometry management for the window, plus create an * event handler to find out when it is deleted. */ Tk_ManageGeometry(ewPtr->body.ew.tkwin, &textGeomType, client); Tk_CreateEventHandler(ewPtr->body.ew.tkwin, StructureNotifyMask, EmbWinStructureProc, client); /* * Special trick! Must enter into the hash table *after* calling * Tk_ManageGeometry: if the window was already managed elsewhere * in this text, the Tk_ManageGeometry call will cause the entry * to be removed, which could potentially lose the new entry. */ hPtr = Tcl_CreateHashEntry(&textPtr->sharedTextPtr->windowTable, Tk_PathName(ewPtr->body.ew.tkwin), &isNew); Tcl_SetHashValue(hPtr, ewPtr); } } return TCL_OK; }
void TkTextEmbWinDisplayProc( TkText *textPtr, /* Information about text widget. */ TkTextDispChunk *chunkPtr, /* Chunk that is to be drawn. */ int x, /* X-position in dst at which to draw this * chunk (differs from the x-position in the * chunk because of scrolling). */ int y, /* Top of rectangular bounding box for line: * tells where to draw this chunk in dst * (x-position is in the chunk itself). */ int lineHeight, /* Total height of line. */ int baseline, /* Offset of baseline from y. */ Display *display, /* Display to use for drawing (unused). */ Drawable dst, /* Pixmap or window in which to draw * (unused). */ int screenY) /* Y-coordinate in text window that * corresponds to y. */ { int lineX, windowX, windowY, width, height; Tk_Window tkwin; TkTextSegment *ewPtr = chunkPtr->clientData; TkTextEmbWindowClient *client = EmbWinGetClient(textPtr, ewPtr); if (client == NULL) { return; } tkwin = client->tkwin; if (tkwin == NULL) { return; } if ((x + chunkPtr->width) <= 0) { /* * The window is off-screen; just unmap it. */ if (textPtr->tkwin != Tk_Parent(tkwin)) { Tk_UnmaintainGeometry(tkwin, textPtr->tkwin); } else { Tk_UnmapWindow(tkwin); } return; } /* * Compute the window's location and size in the text widget, taking into * account the align and stretch values for the window. */ EmbWinBboxProc(textPtr, chunkPtr, 0, screenY, lineHeight, baseline, &lineX, &windowY, &width, &height); windowX = lineX - chunkPtr->x + x; if (textPtr->tkwin == Tk_Parent(tkwin)) { if ((windowX != Tk_X(tkwin)) || (windowY != Tk_Y(tkwin)) || (Tk_ReqWidth(tkwin) != Tk_Width(tkwin)) || (height != Tk_Height(tkwin))) { Tk_MoveResizeWindow(tkwin, windowX, windowY, width, height); } Tk_MapWindow(tkwin); } else { Tk_MaintainGeometry(tkwin, textPtr->tkwin, windowX, windowY, width, height); } /* * Mark the window as displayed so that it won't get unmapped. */ client->displayed = 1; }
static void DisplayWinItem( Tk_Canvas canvas, /* Canvas that contains item. */ Tk_Item *itemPtr, /* Item to be displayed. */ Display *display, /* Display on which to draw item. */ Drawable drawable, /* Pixmap or window in which to draw item. */ int regionX, int regionY, int regionWidth, int regionHeight) /* Describes region of canvas that must be * redisplayed (not used). */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; int width, height; short x, y; Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); Tk_State state = itemPtr->state; if (winItemPtr->tkwin == NULL) { return; } if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; } /* * A drawable of None is used by the canvas UnmapNotify handler * to indicate that we should no longer display ourselves. */ if (state == TK_STATE_HIDDEN || drawable == None) { if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { Tk_UnmapWindow(winItemPtr->tkwin); } else { Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); } return; } Tk_CanvasWindowCoords(canvas, (double) winItemPtr->header.x1, (double) winItemPtr->header.y1, &x, &y); width = winItemPtr->header.x2 - winItemPtr->header.x1; height = winItemPtr->header.y2 - winItemPtr->header.y1; /* * If the window is completely out of the visible area of the canvas then * unmap it. This code used not to be present (why unmap the window if it * isn't visible anyway?) but this could cause the window to suddenly * reappear if the canvas window got resized. */ if (((x + width) <= 0) || ((y + height) <= 0) || (x >= Tk_Width(canvasTkwin)) || (y >= Tk_Height(canvasTkwin))) { if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { Tk_UnmapWindow(winItemPtr->tkwin); } else { Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); } return; } /* * Reposition and map the window (but in different ways depending on * whether the canvas is the window's parent). */ if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { if ((x != Tk_X(winItemPtr->tkwin)) || (y != Tk_Y(winItemPtr->tkwin)) || (width != Tk_Width(winItemPtr->tkwin)) || (height != Tk_Height(winItemPtr->tkwin))) { Tk_MoveResizeWindow(winItemPtr->tkwin, x, y, width, height); } Tk_MapWindow(winItemPtr->tkwin); } else { Tk_MaintainGeometry(winItemPtr->tkwin, canvasTkwin, x, y, width, height); } }
static int ConfigureWinItem( Tcl_Interp *interp, /* Used for error reporting. */ Tk_Canvas canvas, /* Canvas containing itemPtr. */ Tk_Item *itemPtr, /* Window item to reconfigure. */ int objc, /* Number of elements in objv. */ Tcl_Obj *const objv[], /* Arguments describing things to configure. */ int flags) /* Flags to pass to Tk_ConfigureWidget. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; Tk_Window oldWindow; Tk_Window canvasTkwin; oldWindow = winItemPtr->tkwin; canvasTkwin = Tk_CanvasTkwin(canvas); if (TCL_OK != Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, objc, (const char **) objv, (char *) winItemPtr, flags|TK_CONFIG_OBJS)) { return TCL_ERROR; } /* * A few of the options require additional processing. */ if (oldWindow != winItemPtr->tkwin) { if (oldWindow != NULL) { Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, WinItemStructureProc, winItemPtr); Tk_ManageGeometry(oldWindow, NULL, NULL); Tk_UnmaintainGeometry(oldWindow, canvasTkwin); Tk_UnmapWindow(oldWindow); } if (winItemPtr->tkwin != NULL) { Tk_Window ancestor, parent; /* * Make sure that the canvas is either the parent of the window * associated with the item or a descendant of that parent. Also, * don't allow a top-of-hierarchy window to be managed inside a * canvas. */ parent = Tk_Parent(winItemPtr->tkwin); for (ancestor = canvasTkwin ;; ancestor = Tk_Parent(ancestor)) { if (ancestor == parent) { break; } if (((Tk_FakeWin *) ancestor)->flags & TK_TOP_HIERARCHY) { goto badWindow; } } if (((Tk_FakeWin *) winItemPtr->tkwin)->flags & TK_TOP_HIERARCHY){ goto badWindow; } if (winItemPtr->tkwin == canvasTkwin) { goto badWindow; } Tk_CreateEventHandler(winItemPtr->tkwin, StructureNotifyMask, WinItemStructureProc, winItemPtr); Tk_ManageGeometry(winItemPtr->tkwin, &canvasGeomType, winItemPtr); } } if ((winItemPtr->tkwin != NULL) && (itemPtr->state == TK_STATE_HIDDEN)) { if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { Tk_UnmapWindow(winItemPtr->tkwin); } else { Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); } } ComputeWindowBbox(canvas, winItemPtr); return TCL_OK; badWindow: Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't use %s in a window item of this canvas", Tk_PathName(winItemPtr->tkwin))); Tcl_SetErrorCode(interp, "TK", "GEOMETRY", "HIERARCHY", NULL); winItemPtr->tkwin = NULL; return TCL_ERROR; }