[ImageJ-devel] The mystery of the vanishing menu in ImageJ2

Barry DeZonia bdezonia at gmail.com
Fri Dec 13 23:58:00 CST 2013


Good catch Johannes! I miss you and the rest of the gang too. Remember I'll
always be around until you've closed all the tickets I ever filed. :) Happy
holidays and best wishes to the ImageJ2 team.


On Fri, Dec 13, 2013 at 11:12 PM, Johannes Schindelin <
Johannes.Schindelin at gmx.de> wrote:

> Hi all,
>
> I dedicate this mail to Barry because he reported the issue first, and
> besides, I miss him ;-)
>
> The issue Barry pointed out earlier, on Ubuntu, was that ImageJ2 started
> behaving strangely with regards to the menu: as soon as the mouse was
> hovering over the tool bar, the menu would go away.
>
> Back then, I could not reproduce the issue, but today I could, so I went
> on a hunt, and here is the write-up for everybody to enjoy:
>
> First of all, I figured that I should find out whether some strange AWT
> events were processed, so I fired up Eclipse -- because I wanted to use
> Eclipse's debugger to investigate the issue -- and added this code to the
> end of AbstractSwingUI#createUI():
>
> -- snip --
> Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
>
>         @Override
>         public void eventDispatched(AWTEvent event) {
>                 System.err.println("event: " + event);
>         }
> }, -1);
> -- snap --
>
> Basically, this code asks Java to output all the UI events as they
> happen.
>
> Then, I set a breakpoint on the first line and started ImageJ2 in debug
> mode. A little-known gem is that Eclipse's Console window not only shows
> the standard output and standard error stream of the debugged program,
> but also accepts the standard input. I used this fact by adding some
> empty lines (simply focusing the Console window and hitting the Return
> key a couple of times) as soon as the main window was visible because
> the events that had been shown so far could not be responsible (or so I
> thought).
>
> But after moving the mouse over the toolbar (and the menu bar
> vanishing), really only the obvious events were shown: mouse enter,
> mouse moves (and then mouse leave).
>
> So I imagined that another way to debug the issue might be to look
> whether there actually *was* a menu bar still when the tool bar was
> painted after the mouse entered the main window.
>
> To this end, I patched in a paintComponent method into the SwingToolBar
> class:
>
> -- snip --
>         @Override
>         public void paintComponent(final Graphics g) {
>                 Container c = getParent();
>                 c = c.getParent();
>                 c = c.getParent();
>                 c = c.getParent();
>                 System.err.println(c);
>                 System.err.println(((JFrame)c).getJMenuBar());
>                 super.paintComponent(g);
>         }
> -- snap --
>
> Of course, that was not the initial version. The initial version assumed
> that already the direct parent container of the tool bar would be the
> JFrame, and in hindsight, I'd better have written something like:
>
>                 Container c = getParent();
>                 while (c != null && !(c instanceof JFrame)) {
>                         c = c.getParent();
>                 }
>
> but hindsight is 20/20 and I did not have the luxury of that yet.
> However, I had the luxury of incremental compilation (as performed by
> Eclipse, one of the few things I really like about Eclipse): I could set
> a breakpoint on the "System.err.println(c);" call, launch ImageJ2 in debug
> mode, and then insert the "c = c.getParent();" lines one by one, saving
> them, which would trigger Eclipse's incremental compiler and move
> execution back to the first line of the method, until I had the right
> amount.
>
> And sure enough, the first time round, there was a menu bar, but after
> moving the mouse over the main window the menu bar was null!
>
> Therefore the next step was to find out when it was set to null. To find
> out, I edited the SwingApplicationFrame class (which I found out from
> inspecting the "c" variable in the SwingToolBar#paintComponent(Graphics)
> method above) like so:
>
> -- snip --
>         @Override
>         public void setJMenuBar(final JMenuBar bar) {
>                 super.setJMenuBar(bar);
>         }
> -- snap --
>
> and -- you probably guessed it by now -- added a breakpoint on the
> "super.setJMenuBar(bar);" line.
>
> It turns out that it is called the first time from
> AbstractSwingUI#createUI(), as expected, but then -- unexpectedly --
> from MacOSXPlatform#onEvent(WinActivatedEvent)! On Linux, no less...
>
> There we have the culprit. As I found out by inserting
>
> -- snip --
> if (c.getName().endsWith("WinActivatedEvent")) {
>         System.err.println();
> }
> -- snap --
>
> into the DefaultEventService#subscribe(Class, EventSubscriber) method
> and -- you probably guessed that again -- setting a breakpoint on the
> "System.err.println();" line (after importing scijava-common into the
> Eclipse workspace and adjusting ImageJ2's pom.xml to set the
> scijava-common.version property to point to the checked out version),
> MacOSXPlatform is registered as an event listener.
>
> This is the consequence of some subtle, recent change that at the same
> time a Context is injected, the class is also automatically registered
> as event listener if it has @EventHandler-annotated methods).
>
> Now, MacOSXPlatform's onEvent() method does not verify that the current
> platform is actually MacOSX, nor does the EventService "forget" the
> MacOSXPlatform as one would expect when the MacOSXPlatform is
> garbage-collected after it has been determined that it does not match
> the current platform because the PlatformService is now a
> SingletonService that does not let go of its instances...
>
> So we actually need two changes to fix this:
>
> 1) MacOSXPlatform#onEvent(WinActivatedEvent) needs to be safe, and
>
> 2) the DefaultPlatformService must not keep references to Platform
> instances that are not applicable to the currently-running platform.
>
> https://github.com/imagej/imagej/commit/c814f4b0 addresses 1) while
> https://github.com/scijava/scijava-common/commit/46f64db2 and
> https://github.com/scijava/scijava-common/commit/522f524 address 2)
>
> Ciao,
> Dscho
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://imagej.net/pipermail/imagej-devel/attachments/20131213/12a49bab/attachment-0001.html>


More information about the ImageJ-devel mailing list