diff options
author | culler <culler> | 2019-02-02 19:13:17 (GMT) |
---|---|---|
committer | culler <culler> | 2019-02-02 19:13:17 (GMT) |
commit | 4f62ea993c2ba881bca1c4f8201bf261a6b52e3b (patch) | |
tree | 8025b02fc8294e7ac963366ce378b5ed7edcf0e2 | |
parent | 6f9b782763a6e1605f10e734efa396ec738a04e0 (diff) | |
parent | 43b8641102c6727136926d0494328292a4c739aa (diff) | |
download | tk-4f62ea993c2ba881bca1c4f8201bf261a6b52e3b.zip tk-4f62ea993c2ba881bca1c4f8201bf261a6b52e3b.tar.gz tk-4f62ea993c2ba881bca1c4f8201bf261a6b52e3b.tar.bz2 |
Add missing components of the implementation of transient windows on macOS.
-rw-r--r-- | macosx/tkMacOSXWm.c | 180 | ||||
-rw-r--r-- | macosx/tkMacOSXWm.h | 14 |
2 files changed, 186 insertions, 8 deletions
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index a5e1564..6a6c254 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -322,6 +322,7 @@ static void GetMaxSize(TkWindow *winPtr, int *maxWidthPtr, int *maxHeightPtr); static void RemapWindows(TkWindow *winPtr, MacDrawable *parentWin); +static void RemoveTransient(TkWindow *winPtr); #pragma mark NSWindow(TKWm) @@ -681,6 +682,7 @@ TkWmNewWindow( wmPtr->masterWindowName = NULL; wmPtr->icon = NULL; wmPtr->iconFor = NULL; + wmPtr->transientPtr = NULL; wmPtr->sizeHintsFlags = 0; wmPtr->minWidth = wmPtr->minHeight = 1; wmPtr->maxWidth = 0; @@ -882,10 +884,18 @@ TkWmDeadWindow( TkWindow *winPtr) /* Top-level window that's being deleted. */ { WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; + TkDisplay *dispPtr = TkGetDisplayList(); if (wmPtr == NULL) { return; } + + /* + *If the dead window is a transient, remove it from the master's list. + */ + + RemoveTransient(winPtr); + Tk_ManageGeometry((Tk_Window) winPtr, NULL, NULL); Tk_DeleteEventHandler((Tk_Window) winPtr, StructureNotifyMask, TopLevelEventProc, winPtr); @@ -915,7 +925,6 @@ TkWmDeadWindow( } while (wmPtr->protPtr != NULL) { ProtocolHandler *protPtr = wmPtr->protPtr; - wmPtr->protPtr = protPtr->nextPtr; Tcl_EventuallyFree(protPtr, TCL_DYNAMIC); } @@ -930,6 +939,30 @@ TkWmDeadWindow( } /* + * If the dead window has a transient, remove references to it from + * the transient. + */ + + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr) { + wmPtr2 = winPtr2->wmInfoPtr; + wmPtr2->master = None; + ckfree(wmPtr2->masterWindowName); + wmPtr2->masterWindowName = NULL; + } + } + + while (wmPtr->transientPtr != NULL) { + Transient *transientPtr = wmPtr->transientPtr; + wmPtr->transientPtr = transientPtr->nextPtr; + ckfree(transientPtr); + } + + /* * Delete the Mac window and remove it from the windowTable. The window * could be nil if the window was never mapped. However, we don't do this * for embedded windows, they don't go in the window list, and they do not @@ -1758,6 +1791,7 @@ WmDeiconifyCmd( { register WmInfo *wmPtr = winPtr->wmInfoPtr; NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); + TkDisplay *dispPtr = TkGetDisplayList(); if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "window"); @@ -1786,6 +1820,27 @@ WmDeiconifyCmd( if (wmPtr->icon) { Tk_UnmapWindow((Tk_Window)wmPtr->icon); } + + /* + * If this window has a transient, the transient must also be deiconified if + * it was withdrawn by the master. + */ + + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + WmInfo *wmPtr2 = winPtr2->wmInfoPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr) { + if (!(wmPtr2->hints.initial_state == WithdrawnState && + (transientPtr->flags & WITHDRAWN_BY_MASTER) == 0)) { + TkpWmSetState(winPtr2, NormalState); + transientPtr->flags &= ~WITHDRAWN_BY_MASTER; + } + } + } + return TCL_OK; } @@ -2272,6 +2327,7 @@ WmIconifyCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { + TkDisplay *dispPtr = TkGetDisplayList(); register WmInfo *wmPtr = winPtr->wmInfoPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "window"); @@ -2308,6 +2364,24 @@ WmIconifyCmd( if (wmPtr->icon) { Tk_MapWindow((Tk_Window)wmPtr->icon); } + + /* + * If this window has a transient the transient must be withdrawn when + * the master is iconified. + */ + + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr && + winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { + TkpWmSetState(winPtr2, WithdrawnState); + transientPtr->flags |= WITHDRAWN_BY_MASTER; + } + } + return TCL_OK; } @@ -3523,16 +3597,13 @@ WmTransientCmd( return TCL_OK; } if (Tcl_GetString(objv[3])[0] == '\0') { - wmPtr->master = None; - if (wmPtr->masterWindowName != NULL) { - ckfree(wmPtr->masterWindowName); - } - wmPtr->masterWindowName = NULL; + RemoveTransient(winPtr); + } else { if (TkGetWindowFromObj(interp, tkwin, objv[3], &master) != TCL_OK) { return TCL_ERROR; } - TkWindow* masterPtr = (TkWindow*) master; + TkWindow *masterPtr = (TkWindow*) master; while (!Tk_TopWinHierarchy(masterPtr)) { /* @@ -3568,6 +3639,27 @@ WmTransientCmd( return TCL_ERROR; } + /* + * Add the transient to the master's list. + */ + + Transient *transient = ckalloc(sizeof(Transient)); + transient->winPtr = winPtr; + transient->flags = 0; + transient->nextPtr = wmPtr->transientPtr; + wmPtr2->transientPtr = transient; + + /* + * If the master is withdrawn or iconic then withdraw the transient. + */ + + if ((wmPtr2->hints.initial_state == WithdrawnState || + wmPtr2->hints.initial_state == IconicState) && + wmPtr->hints.initial_state != WithdrawnState){ + TkpWmSetState(winPtr, WithdrawnState); + transient->flags |= WITHDRAWN_BY_MASTER; + } + wmPtr->master = Tk_WindowId(masterPtr); masterWindowName = masterPtr->pathName; length = strlen(masterWindowName); @@ -3580,6 +3672,61 @@ WmTransientCmd( ApplyMasterOverrideChanges(winPtr, NULL); return TCL_OK; } + +/* + *---------------------------------------------------------------------- + * + * RemoveTransient -- + * + * Clears the transient's master record and removes the transient + * from the master's list. + * + * Results: + * None + * + * Side effects: + * References to a master are removed from the transient's wmInfo + * structure and references to the transient are removed from its + * master's wmInfo. + * + *---------------------------------------------------------------------- + */ + +static void +RemoveTransient( + TkWindow *winPtr) +{ + WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; + TkDisplay *dispPtr = TkGetDisplayList(); + TkWindow *masterPtr; + if (wmPtr == NULL || wmPtr->master == None) { + return; + } + masterPtr = (TkWindow*)Tk_IdToWindow(dispPtr->display, wmPtr->master); + wmPtr2 = masterPtr->wmInfoPtr; + if (wmPtr2 == NULL) { + return; + } + wmPtr->master = None; + if (wmPtr->masterWindowName != NULL) { + ckfree(wmPtr->masterWindowName); + } + wmPtr->masterWindowName = NULL; + Transient *temp, *cursor = wmPtr2->transientPtr; + if (cursor->winPtr == winPtr) { + temp = cursor->nextPtr; + ckfree(cursor); + cursor = temp; + masterPtr->wmInfoPtr->transientPtr = cursor; + } + while (cursor != NULL) { + if (cursor->winPtr == winPtr) { + temp = cursor->nextPtr; + ckfree(cursor); + cursor = temp; + } + } +} /* *---------------------------------------------------------------------- @@ -3620,11 +3767,29 @@ WmWithdrawCmd( Tcl_SetErrorCode(interp, "TK", "WM", "WITHDRAW", "ICON", NULL); return TCL_ERROR; } + TkpWmSetState(winPtr, WithdrawnState); + NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); + TkDisplay *dispPtr = TkGetDisplayList(); [win orderOut:nil]; [win setExcludedFromWindowsMenu:YES]; + /* + * If this window has a transient, the transient must also be withdrawn. + */ + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr && + winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { + TkpWmSetState(winPtr2, WithdrawnState); + transientPtr->flags |= WITHDRAWN_BY_MASTER; + } + } + return TCL_OK; } @@ -4734,7 +4899,6 @@ Tk_MoveToplevelWindow( wmPtr->x = x; wmPtr->y = y; wmPtr->flags |= WM_MOVE_PENDING; - // wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y); if (!(wmPtr->sizeHintsFlags & (USPosition|PPosition))) { wmPtr->sizeHintsFlags |= USPosition; wmPtr->flags |= WM_UPDATE_SIZE_HINTS; diff --git a/macosx/tkMacOSXWm.h b/macosx/tkMacOSXWm.h index 43f1a7a..a7ea92c 100644 --- a/macosx/tkMacOSXWm.h +++ b/macosx/tkMacOSXWm.h @@ -36,6 +36,17 @@ typedef struct ProtocolHandler { * THE LAST FIELD OF THE STRUCTURE. */ } ProtocolHandler; +/* The following data structure is used in the TkWmInfo to maintain a list of all of the + * transient windows belonging to a given master. + */ + +typedef struct Transient { + TkWindow *winPtr; + int flags; + struct Transient *nextPtr; +} Transient; + +#define WITHDRAWN_BY_MASTER 0x1 /* * A data structure of the following type holds window-manager-related @@ -70,6 +81,9 @@ typedef struct TkWmInfo { * NULL. */ Tk_Window iconFor; /* Window for which this window is icon, or * NULL if this isn't an icon for anyone. */ + Transient *transientPtr; /* First item in a list of all transient windows + * belonging to this window, or NULL if there + * are no transients. */ /* * Information used to construct an XSizeHints structure for the window |