| Summary: | If a MessageDialog opens in an asyncExec block while a FileDialog is open, Eclipse hangs | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Product: | [Eclipse Project] Platform | Reporter: | Mike Morearty <mike> | ||||||||
| Component: | SWT | Assignee: | Platform-SWT-Inbox <platform-swt-inbox> | ||||||||
| Status: | CLOSED WONTFIX | QA Contact: | |||||||||
| Severity: | normal | ||||||||||
| Priority: | P3 | CC: | cocoakevin, lshanmug, namole, Silenio_Quarti, skovatch, swingler, Tod_Creasey | ||||||||
| Version: | 3.3.1 | Keywords: | triaged | ||||||||
| Target Milestone: | --- | ||||||||||
| Hardware: | Macintosh | ||||||||||
| OS: | Mac OS X | ||||||||||
| Whiteboard: | stalebug | ||||||||||
| Attachments: |
|
||||||||||
I should clarify that this may be a Leopard bug, not an Eclipse bug. But if it's a Leopard bug, then the question still remains whether Eclipse should try to work around it or not. MessageDialog runs its own event loop when it's opened. The second event loop combined with the FileDialog seems to be causing this.
Simplified test case:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
display.asyncExec(new Runnable() {
public void run() {
Shell shell2 = new Shell(display);
shell2.setBounds(25, 25, 100, 45);
shell2.open();
while (shell2 != null && !shell2.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
});
FileDialog fileDialog = new FileDialog(shell);
fileDialog.open();
shell.setBounds(100, 100, 640, 480);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
This case also fails on GTK. This is difficult to fix in SWT. Tod, you guys are running the event loop. Maybe there's a work around in your world? When you say "fix" what are you suggesting? The main issue we have is keeping painting while something else is going on in the UI Thread. The test case in comment 2 should include SWT.APPLICATION_MODAL when constructing the shell. I can confirm that this bug happens on Leopard, but not on Tiger. The only workaround I've found for this so far is to prevent the async messages from running when there's a file dialog open on Leopard. Something like: parent.getDisplay().runAsyncMessages = false; OS.NavDialogRun (outDialog [0]); parent.getDisplay().runAsyncMessages = true; This would avoid the problem, but it would make the behavior of FileDialog different on Leopard from every other platform. I don't know the Mac well enough to answer this question, but I wonder, should this be considered a bug in Leopard? And if so, is the proper resolution to simply file a bug with Apple, and not change Eclipse? Or, file a bug with Apple and still put in a workaround into Eclipse? Although I filed this Eclipse bug, I don't think I should be the person to file an Apple bug, because I don't know Mac coding well enough to give any example other than the Eclipse one. We try to find work around in SWT if we can. I'm not sure if this is a bug in Carbon or not. I haven't yet had time to try writing an example in xcode. Mass move of Kevin's open Mac Carbon & Cocoa bugs to Scott K. Created attachment 188606 [details]
Potential fix
This needs more testing, but basically we block sync/async execs from running when a modal dialog is up. I thought I could block them just in NSModalPanelRunLoopMode, but clicks and other events also arrive in normal mode or event tracking mode, so they still execute.
Aptana Studio and Appcelerator Titanium Studio is also running into this issue. Are there any work-arounds to the mechanism used to display the MessageDialog (we do it in an async)? I forgot to mention my environment. Tested on OSX 10.7.4 using Eclipse 3.7.1, 4.2. Issue occurs on both versions Created attachment 218405 [details]
Native Objective-C Cocoa project reproducing the bug
I was able to reproduce this with a native Objective-C Cocoa app in Xcode; if you care, see the attached Xcode project.
In this project, I tried to copy the things that SWT's Cocoa implementation does. SWT hooks into the run loop in order to run async messages more often; see Display.init() in Display.java near line 2188; specifically, the call to OS.CFRunLoopAddObserver() near line 2194.
In that call, the value OS.kCFRunLoopCommonModes is passed for the "modes" argument. This means that the callback will be called whenever any of the "common" modes are in effect. This includes the default mode, the modal mode (CFModalPanelRunLoopMode), and the mode for tracking scrollbar-drag events (NSEventTrackingRunLoopMode), and possibly others.
So the result of all that is that even when a modal dialog is running its own message loop, async messages are processed, and they can do whatever they want, including UI activities such as the one that causes these hangs.
In my sample app, if you specify kCFRunLoopDefaultMode instead of kCFRunLoopCommonModes, the problem goes away (because the window doesn't open while the File dialog is up).
I can't think of anything better than what Kevin and Scott have already suggested -- just various ways of preventing async messages from being processed while in a modal dialog.
Bug triaged, visit https://wiki.eclipse.org/SWT/Devel/Triage for more information. This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant. -- The automated Eclipse Genie. |
Created attachment 86507 [details] Sample plugin to demonstrate the problem Build ID: M20071023-1652 Steps To Reproduce: 1. OS X Leopard only -- I have not been able to reproduce this problem on OS X TIger or on Windows. 2. Download the sample plugin source. This is the key bit of source code, from SampleAction.java (and this is the only part of the plugin which is modified from the standard Hello World plugin): Display.getCurrent().asyncExec(new Runnable() { public void run() { MessageDialog.openInformation( null, "DialogHang Plug-in", "Hello, Eclipse world"); } }); FileDialog fileDialog = new FileDialog(window.getShell()); fileDialog.open(); Notice that that code does as asyncExec() which is going to display a MessageDialog, and then it opens a FileDialog. So the result is that the FileDialog will appear, and then when its message pump runs, the MessageDialog will appear. 3. With this plugin installed, launch a child instanc of Eclipse. In the child instance, click Sample Menu > Sample Action on the top-level menu. Result: Both the FileDialog and the MessageDialog appear (with the FileDialog at the top of the z-order), and you can drag the FileDialog around and click within it, but you cannot dismiss it. Niether OK nor Cancel causes the FileDialog to go away. If you try to click on the MessageDialog, you just get a small beep sound. You are hung at this point -- you have to forcibly kill Eclipse. Note that in the call to MessageDialog.openInformation(), I passed null for the Shell. When you pass null, there is code in Window.defaultModalParent.getShell() that will get invoked, and it does explicitly attempt to deal with the case of other modal windows being present -- as the comment says, "Make sure we don't pick a parent that has a modal child (this can lock the app)." But in this case, it doesn't seem to work. I also tried changing my code to pass window.getShell() instead of null; that didn't help. More information: