Tk Source Code

View Ticket
Bounty program for improvements to Tcl and certain Tcl packages.
Ticket UUID: d1989fb7cf6e13b33f641571bb5b0304023d2e28
Title: Aqua: Empty window appears after `package require Tk`
Type: Bug Version: core-8-6-branch
Submitter: chrstphrchvz Created on: 2019-04-28 19:08:29
Subsystem: 02. Appearance Assigned To: marc_culler
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2019-05-16 19:52:28
Resolution: Fixed Closed By: marc_culler
    Closed on: 2019-05-16 19:52:28

Sometime between and the latest core-8-6-branch ([24b987ca]) As of [5e709226], doing package require Tk now causes an empty window to appear immediately. I do not know what specific change introduced this behavior.


package require Tk
puts "Waiting"
after 3000
puts "Done"

An empty window will appear before Waiting appears, whereas when run on, or in X11, no windows would appear until Done appears.

As a result, when running a program, this empty window appears for a fraction of a second; before, only the program's fully-populated, ready-to-use window would appear.

Originally observed by a Tcl::pTk user:

User Comments: marc_culler (claiming to be Marc Culler) added on 2019-05-16 19:52:28:
Nicolas and Christopher, thanks for the reviews!

I will merge the bugfix branch and close this ticket.

chrstphrchvz added on 2019-05-16 17:27:22:

Hi Marc, I have confirmed that I do not observe this issue under [9e9a9189a8]. Thank you for looking into this.

nab added on 2019-05-16 14:09:53:
Hi Marc,
I've compiled and run  9e9a9189a8, and there's no more a blank window at start.
many thanks :)


marc_culler (claiming to be Marc Culler) added on 2019-05-16 13:25:53:

@chrstphrchvz, @nab: It would be great if you two could review the proposed fix in commit 9e9a9189a8.

marc_culler (claiming to be Marc Culler) added on 2019-05-15 17:25:49:

I reviewed the problem reported as bug [56a1823c73], which commit [5e709226] was meant to fix. The underlying cause of that bug was that the root window was being created and iconified before the NSApplication had finished launching, causing it to open off screen when it was deiconified.

I found a better fix for [56a1823c73], which does not require processing any events in the XMapWindow and which also fixes this bug.

There was another place where calls to Tcl_DoOneEvent had been added in order to deal with problems that arose in OSX 10.14. That was in the fix for bug [3efbe4a397]. I found that those calls were no longer needed, so I removed them as well.

These changes are now in commit 9e9a9189a8 to the branch bug-d1989fb7cf.

In ticket [3efbe4a397] Kevin mentions a different problem which he thinks is related to the grab command. That problem is still not fixed in either the core-8-6-branch or bug-d1989fb7cf. It is not clear to me whether it had ever been fixed. In any case, it appears to be unrelated to this ticket.

marc_culler (claiming to be Marc Culler) added on 2019-05-01 13:10:17:

I won't be able to look at this for a couple of weeks, but I know what the cause is. This behavior was created by the fix for bug 56a1823c73, which was even more annoying if you had the good fortune to run into it. The change was in made in order to make it possible for a toplevel to be deiconified in response to the selection of a file in tk_getOpenFile, which is a pretty natural thing to want to be able to do.

The fix for that bug was to add a loop inside of XMapWindow which calls Tcl_DoOneEvent to process any pending events in the queue when mapping a new toplevel.

The core issue that leads to the root window appearing too soon is that Tk insists on creating the root window long before it calls the platform-specific initialization code. On the Mac this means that the root window is created before the NSApplication object exists, hence before Tk has an event source. There are many lines of code in the Mac port devoted to working around this behavior.

Now it seems that Tk does not only create the root window before calling the platform specific initialization code, it also maps it. Since, in its current state, XMapWindow briefly runs its own mini event loop, this has the effect of actually mapping the root window at the time that Tk asked for it to be mapped. Maybe the place to start with this bug would be to get a Tk expert to explain why Tk wants to map the root window before it has started its event loop and before it has run the platform specific initialization code.

nab added on 2019-05-01 09:06:34:
I also see a blank window when [package require Tk] is invoked and I find it quite disturbing...
I agree with chrstphrchvz that no blank window should appear before any Tcl_DoOneEvent() call.


fvogel added on 2019-04-30 19:56:35:
Marc, please, any thoughts perhaps?

chrstphrchvz added on 2019-04-29 03:14:34:

Bisecting identified [5e709226] as the change responsible for this behavior. Sure enough it adds a couple of temporary loops which call Tcl_DoOneEvent().

I personally am not bothered by the changed behavior, but the user that reported this to me finds it "quite disturbing".

chrstphrchvz added on 2019-04-28 20:37:51:

On Windows saying package require Tk has always triggered an empty '.' window to appear on screen.

Yes, when Tcl is not told to do anything else immediately after doing package require Tk, it gets to enter the event loop and make an empty window appear. That is what I observe on any windowingsystem, including on aqua with, and is not the issue I am describing here.

What I am describing is that a window is now appearing immediately after package require Tk before evaluating the next statement, and without entering the Tcl event loop (including returning to the interactive tclsh/wish REPL prompt).

In Tk wrappers that use the Tcl C API, the past behavior has been that no windows will appear until that wrapper's mainloop is entered, which in turn starts calling Tcl_DoOneEvent(). What this issue means is that as of sometime since, an empty window on aqua appears immediately after doing Tcl_Eval(interp, "package require Tk"), without ever calling Tcl_DoOneEvent(). Short C example:

#include <stdio.h>
#include <unistd.h>
#include <tcl.h>

int main(void) { Tcl_Interp *interp = Tcl_CreateInterp(); Tcl_Init(interp); printf("Doing `package require Tk`\n"); Tcl_Eval(interp, "package require Tk"); sleep(5); printf("Entering event loop\n"); while(1){ Tcl_DoOneEvent(TCL_ALL_EVENTS); } return 0; }

Indeed, those writing Tk programs in Tcl and using tclsh or wish interactively might be used to windows appearing and changing with each statement they type; whereas those using a non-Tcl wrapper might instead be used to seeing nothing happen until their wrapper's mainloop is irreversibly entered. (I do not know how non-Tcl users typically go about using Tk from an interactive shell, or if they expect to even be able to, the way tclsh/wish users might.)

fvogel added on 2019-04-28 19:45:47:

On Windows saying package require Tk has always triggered an empty '.' window to appear on screen.