Menu

#2659 WM_DELETE_WINDOW error

obsolete: 8.6b1.1
closed-fixed
5
2009-08-24
2009-07-14
No

Under Tk-Cocoa, cancelling the WM_DELETE_WINDOW protocol causes the main window to withdraw, and not to return.

The sample code below is a test case. Under Tk 8.4.7, it causes Wish to exit if "yes" is chosen and the command to be cancelled if "no" is chosen, leaving the toplevel mapped. Under Tk-Cocoa, Wish exists if "yes" is chosen, and the toplevel is unmapped if "no" is chosen. The toplevel should remain mapped.

wm protocol . WM_DELETE_WINDOW shutDown

proc shutDown {} {

global datadir

set fetchanswer [tk_messageBox -title "Quit" -icon info -message "Do you really want to quit?" -type yesno -parent . ]
switch $fetchanswer {
yes {
exit
}
no {
destroy $fetchanswer
}
}
}

Discussion

  • Kevin Walzer

    Kevin Walzer - 2009-07-18

    After doing some additional digging, it appears that defining WM_DELETE_WINDOW causes unexpected behavior with deleting the window. For instance, this command:

    wm protocol . WM_DELETE_WINDOW return

    should cause the root window to remain mapped. This works as expected in Wish 8.4.7. However, in Tk-Cocoa 8.5 and 8.6, . withdraws, but Wish remains running. This is default Cocoa application behavior, perhaps, but not standard Wish behavior. If WM_DELETE_WINDOW is undefined by a script, then Wish exits if . is destroyed; otherwise it displays the strange behavior noted above.

     
  • Kevin Walzer

    Kevin Walzer - 2009-08-15
     
  • Kevin Walzer

    Kevin Walzer - 2009-08-15

    I've attached a patch that seems to solve the worst part of this problem. I removed a call to Tk_HandleEvent in TkGenWMDestroyEvent in TkMacOSXWindowEvent.c and restored a call to Tk_QueueWindowEvent, which was present in the Tk-Carbon version of this file. Restoring the QueueWindowEvent call appears to allow a custom WM_DELETE_PROTOCOL handler to intercept the [window destroy] event, which my example script illustrates. The call to Tk_HandleEvent destroyed the window immediately before it could be intercepted by the WM_DELETE_PROTOCOL handler.

    This fix isn't perfect because it causes the window to flash briefly before bringing up the messagebox (in my sample script above); there may be a better way to achieve this than I've been able to discover. But hopefully this patch is a start, or at the very least a suitable workaround.

     
  • Daniel A. Steffen

    The fact that that change worked with your example turns out to be purely accidental (due to the message box attaching to the parent window at the right time and thus preventing it from closing).
    The real cause of the problem is that TkGenWMDestroyEvent() is called too late (from a NSWindowWillCloseNotification handler), at that point it is no longer possible to prevent window closure...
    The correct fix is to call TkGenWMDestroyEvent() from the window delegate's -windowShouldClose: method and to always return NO (and rely on the WM_DELETE_PROTOCOL handler to [close] the window if necessary).
    Patch with that fix attached and committed to HEAD and git de-carbon-8-5

     
  • Daniel A. Steffen

    • status: open --> closed-fixed
     
  • Daniel A. Steffen

    patch as committed to HEAD