Project

General

Profile

Bug #2716

Bug #2677: fix drawing and functional differences between P2J GUI and 4GL GUI

The application with multiple windows doesn't start.

Added by Igor Skornyakov over 8 years ago. Updated over 8 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

0%

billable:
No
vendor_id:
GCD
case_num:

History

#1 Updated by Igor Skornyakov over 8 years ago

The existing test window_parenting/waitfor_2wnd.p doesn't start.

java.lang.RuntimeException: No renderer is registered for id = 12
    at com.goldencode.p2j.ui.client.gui.driver.GuiPrimitivesImpl.getWindowEmulator(GuiPrimitivesImpl.java:203)
    at com.goldencode.p2j.ui.client.gui.driver.GuiPrimitivesImpl.selectWindow(GuiPrimitivesImpl.java:270)
    at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.selectWindow(AbstractGuiDriver.java:1353)
    at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.stackWindows(AbstractGuiDriver.java:1573)
    at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.hide(WindowGuiImpl.java:244)
    at com.goldencode.p2j.ui.client.WindowManager.clearWindowList(WindowManager.java:230)
    at com.goldencode.p2j.ui.chui.ThinClient.terminate(ThinClient.java:2846)
    at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:280)
    at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:100)
    at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:201)
    at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:398)
    at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:95)
    at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:267)

#2 Updated by Greg Shah over 8 years ago

  • Status changed from New to Rejected

This will be worked in #2567 instead.

#3 Updated by Greg Shah over 8 years ago

  • Parent task set to #2677
  • Start date deleted (09/15/2015)
  • Status changed from Rejected to New

A workaround was found that takes this out of the #2567 critical path. This will be worked independently again.

#4 Updated by Greg Shah over 8 years ago

With 1811r revision 10942, the failure's actual cause can be seen:

Caused by: java.lang.IllegalStateException: Can not change window to 12 if batch is already started!
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.selectWindow(AbstractGuiDriver.java:1516)
        at com.goldencode.p2j.ui.client.gui.FillInGuiImpl.drawCaret(FillInGuiImpl.java:711)
        at com.goldencode.p2j.ui.client.gui.FillInGuiImpl$3.run(FillInGuiImpl.java:816)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.FillInGuiImpl.draw(FillInGuiImpl.java:762)
        at com.goldencode.p2j.ui.client.FillIn.draw(FillIn.java:1070)
        at com.goldencode.p2j.ui.client.widget.AbstractContainer.draw(AbstractContainer.java:319)
        at com.goldencode.p2j.ui.client.widget.Viewport.draw(Viewport.java:64)
        at com.goldencode.p2j.ui.client.widget.AbstractContainer.draw(AbstractContainer.java:319)
        at com.goldencode.p2j.ui.client.widget.BorderedPanel.draw(BorderedPanel.java:139)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl.access$501(BorderedPanelGuiImpl.java:31)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl$1$1.run(BorderedPanelGuiImpl.java:228)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl$1.run(BorderedPanelGuiImpl.java:217)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl.draw(BorderedPanelGuiImpl.java:163)
        at com.goldencode.p2j.ui.client.gui.ScrollPaneGuiImpl$2.run(ScrollPaneGuiImpl.java:148)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.ScrollPaneGuiImpl.draw(ScrollPaneGuiImpl.java:142)
        at com.goldencode.p2j.ui.client.gui.FrameGuiImpl$2.run(FrameGuiImpl.java:343)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.FrameGuiImpl.draw(FrameGuiImpl.java:329)
        at com.goldencode.p2j.ui.client.Frame.draw(Frame.java:1745)
        at com.goldencode.p2j.ui.client.widget.AbstractContainer.draw(AbstractContainer.java:319)
        at com.goldencode.p2j.ui.client.widget.Viewport.draw(Viewport.java:64)
        at com.goldencode.p2j.ui.client.widget.AbstractContainer.draw(AbstractContainer.java:319)
        at com.goldencode.p2j.ui.client.widget.BorderedPanel.draw(BorderedPanel.java:139)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl.access$501(BorderedPanelGuiImpl.java:31)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl$1$1.run(BorderedPanelGuiImpl.java:228)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl$1.run(BorderedPanelGuiImpl.java:217)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl.draw(BorderedPanelGuiImpl.java:163)
        at com.goldencode.p2j.ui.client.gui.ScrollPaneGuiImpl$2.run(ScrollPaneGuiImpl.java:148)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.ScrollPaneGuiImpl.draw(ScrollPaneGuiImpl.java:142)
        at com.goldencode.p2j.ui.client.widget.AbstractContainer.draw(AbstractContainer.java:319)
        at com.goldencode.p2j.ui.client.widget.BorderedPanel.draw(BorderedPanel.java:139)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl.access$501(BorderedPanelGuiImpl.java:31)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl$1$1.run(BorderedPanelGuiImpl.java:228)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl$1.run(BorderedPanelGuiImpl.java:217)
        at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.draw(AbstractGuiDriver.java:1649)
        at com.goldencode.p2j.ui.client.gui.BorderedPanelGuiImpl.draw(BorderedPanelGuiImpl.java:163)
        at com.goldencode.p2j.ui.client.Window.draw(Window.java:1449)
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.draw(WindowGuiImpl.java:449)
        at com.goldencode.p2j.ui.client.OutputManager.setInvalidate(OutputManager.java:1237)
        at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13538)
        at com.goldencode.p2j.ui.chui.ThinClient.independentEventDrawingBracket(ThinClient.java:13432)
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.processEvent(WindowGuiImpl.java:1206)
        at com.goldencode.p2j.ui.chui.ThinClient.processProgressEvent(ThinClient.java:15071)
        at com.goldencode.p2j.ui.chui.ThinClient.processEventsWorker(ThinClient.java:14540)
        at com.goldencode.p2j.ui.chui.ThinClient.pop(ThinClient.java:13624)
        at com.goldencode.p2j.ui.chui.ThinClient.eventBracket(ThinClient.java:13607)
        at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13533)
        at com.goldencode.p2j.ui.chui.ThinClient.applyWorker(ThinClient.java:13315)
        at com.goldencode.p2j.ui.chui.ThinClient.waitForEvent(ThinClient.java:12645)
        at com.goldencode.p2j.ui.chui.ThinClient.waitForWorker(ThinClient.java:10662)
        at com.goldencode.p2j.ui.chui.ThinClient.waitFor(ThinClient.java:10245)
        at com.goldencode.p2j.ui.chui.ThinClient.waitFor(ThinClient.java:10199)
        ... 21 more

This is a very similar issue to #2734 but it comes from drawCaret() in this case.

#5 Updated by Greg Shah over 8 years ago

The code for the failing testcase:

def var hwin1 as handle.
def var hwin2 as handle.

create window hwin1.
create window hwin2.

def var i1 as int init 14.
def var i2 as int init 30.

enable i1 with frame f1 in window hwin1.
enable i2 with frame f2 in window hwin2.

wait-for "6" of i1 or "8" of i2.

delete widget hwin1.
delete widget hwin2.

#6 Updated by Greg Shah over 8 years ago

It looks to me like we have a "ghostbusters" problem here. We have "crossed streams" of drawing operations. :)

#7 Updated by Constantin Asofiei over 8 years ago

The problem is in TC.viewWorker:9234:

         if (moved)
         {
            final TitledWindow<?> old = WindowManager.findWindow(fcfg.windowID);

            eventDrawingBracket(wframe, new Runnable()
            {
               @Override
               public void run()
               {
                  // ensure the frame's previous window is selected, so drawing will be done on
                  // the correct window
                  OutputManager.getDriver().getPrimitives().selectWindow(UiUtils.getWidgetIdAsInt(old));

                  // repaint is triggered before the frame is detached; this is required because
                  // during repaint the frame's (current) parent window is needed to compute the
                  // clipping rectangle, and after detaching the frame, its parent window will 
                  // no longer be available
                  wframe.repaint();

                  // just detach, do not remove the widget
                  old.detach(wframe);
               }
            });

The old.detach() is not removing the frame from the window - in GUI, the frames are added to the workspace, not directly to the window. old.detach() calls AbstractContainer.detach(), which uses the window's widget list, not the workspace.

#8 Updated by Constantin Asofiei over 8 years ago

To get past the abend, override detach() in WindowGuiImpl:

   @Override
   public void detach(Widget<GuiOutputManager> widget)
   {
      workspace.getContentPane().detach(widget);
   }

But the test is still not working properly: the WAIT-FOR does not wait for 6 or 8 key.

#9 Updated by Greg Shah over 8 years ago

The WAIT-FOR exits immediately because of this code (waitForWorker()):

               case FocusManager.FOCUS_UNDEF:
                  // undefined, implicit
                  immedExit = !focusManager.focusUndefImplicit(list, false);
                  break;

That fails because of this code in focusUndefImplicit():

      Widget first = getFirstEnabledWidget();

first is assigned null after this call. Since the triggers aren't anywhere triggers, we shortcut out.

However, there should be 1 enabled widget for frame f1 and another enabled widget for frame f2. getFirstEnabledWidget() fails because getFirstVisibleFrame() returns null. getFirstVisibleFrame() starts with this:

   Widget<?>[] items = Window.resolveWindow().getWidgets();

This fails because when it tries to get the list of widgets, it is operating with the currentWindow as window id 1 (the default window). There are no widgets in the default window, because the frames are in the two dynamically created windows. Those windows are never checked for enabled widgets.

There are at least 2 problems going on here:

1. The default window (id 1) should not be visible. On windev01 it does not appear.

2. Our logic for iterating through frames is not multi-window aware.

#10 Updated by Greg Shah over 8 years ago

The last results were with your fix applied. I'm not sure I fully understand the ramifications of your change. Before your fix, I saw something else concerning.

When we create new windows, they have at least some of their listeners active. The ENABLE statements in this case will cause the two new windows to be displayed and made sensitive.

Then we go into the WAIT-FOR. For whatever reason, the current window (AbstractGuiImpl.ews) is id 1 which is the default window. We are in the middle of a batch drawing set for that window.

At some point, the Java environment has queued up a WindowActivated event for one of the created windows (the on with id 12). Since event processing is active already (or at least partially active at window create), the event gets picked up by the WAIT-FOR loop and since we are still in a drawing batch, we abend.

Your fix did avoid this, but I'm worried that having windows start with some portion of their event processing active is potentially a problem.

#11 Updated by Constantin Asofiei over 8 years ago

I've added the fix for notes 7/8 in 1811r rev 10944. The reason this is required is because frames are in GUI are not attached directly to the window's content-pane (which contains the title, workspace, message and status area), but to the window's workspace - all frames are added there. So a frame needs to detach from the workspace, not the window.

#12 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

At some point, the Java environment has queued up a WindowActivated event for one of the created windows (the on with id 12). Since event processing is active already (or at least partially active at window create), the event gets picked up by the WAIT-FOR loop and since we are still in a drawing batch, we abend.

I think I know where this is coming from: some Swing events I think are processed by P2J from the AWT event thread (like window resize and/or positioning...)

Your fix did avoid this, but I'm worried that having windows start with some portion of their event processing active is potentially a problem.

All drawing must be done from the client's main thread: no P2J drawing (or anything which requires the driver to switch windows) should be done within the AWT event thread...

#13 Updated by Constantin Asofiei over 8 years ago

An example of P2J window selection done while P2J is drawing is this:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Can not change window to 1 if batch is already started!
    at com.goldencode.p2j.ui.client.gui.driver.AbstractGuiDriver.selectWindow(AbstractGuiDriver.java:1516)
    at com.goldencode.p2j.ui.client.gui.driver.swing.MouseMoveable.mouseExited(MouseMoveable.java:78)
    at com.goldencode.p2j.ui.client.gui.driver.swing.SwingMouseHandler.processAction(SwingMouseHandler.java:329)
    at com.goldencode.p2j.ui.client.gui.driver.swing.SwingMouseHandler.mouseMoved(SwingMouseHandler.java:181)
    at java.awt.Component.processMouseMotionEvent(Component.java:6570)
    at javax.swing.JComponent.processMouseMotionEvent(JComponent.java:3342)
    at java.awt.Component.processEvent(Component.java:6294)
    at java.awt.Container.processEvent(Container.java:2234)

When the GUI driver is notified by the AWT event thread of a new event, it should be aware if P2J is in the middle of drawing. If P2J is drawing, it should block (not ignore, as it did previously) and wait for a notification that the drawing has finished. Once is notified, it will process the event and listen for new ones.

#14 Updated by Constantin Asofiei over 8 years ago

The abends are fixed in 1811r rev 10948. The remaining issue is multi-window focus management. Greg, do you want me to take this next?

#15 Updated by Greg Shah over 8 years ago

Yes, please do.

#16 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

Yes, please do.

OK, I'll build my changes in branch 1811r, otherwise the multi-window tests in P2J will not be stable.

#17 Updated by Constantin Asofiei over 8 years ago

  • Assignee set to Constantin Asofiei
  • Status changed from New to WIP

#18 Updated by Constantin Asofiei over 8 years ago

The changes which add multi-window focus support and multi-window frame placement are in branch 1811r rev 10952. Please review.

#19 Updated by Greg Shah over 8 years ago

  • Status changed from WIP to Closed

The code review was posted in #1811 note 1348.

I've confirmed that this is fixed in the branch 1811r.

Also available in: Atom PDF