Project

General

Profile

Bug #10423

Scrollbar is clipped by frame after a virtual width assignment

Added by Șerban Bursuc 11 months ago. Updated 6 months ago.

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

100%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

10377_resize_showcase_swing.flv (1 MB) Șerban Bursuc, 08/14/2025 03:29 AM

10377_resize_showcase_2.flv (1.52 MB) Șerban Bursuc, 08/14/2025 03:29 AM

History

#1 Updated by Șerban Bursuc 11 months ago

Testcase (from #10377-6):

define frame fr_main.
define frame fr_parent.
define frame fr1.
frame fr_parent:frame = frame fr_main:handle.
frame fr1:frame = frame fr_parent:handle.
define button btn.
enable btn with frame fr_main.

current-window:width-pixels = 900.
current-window:height-pixels = 500.

frame fr_main:scrollable = true.
frame fr_main:width-pixels = 900.
frame fr_main:height-pixels = 400.
frame fr_main:bgcolor = 7.

frame fr_parent:scrollable = true.
frame fr_parent:width-pixels = 900.
frame fr_parent:height-pixels = 300.
frame fr_parent:virtual-width-pixels = 900.
frame fr_parent:virtual-height-pixels = 600.
frame fr_parent:BGCOLOR = 5.

frame fr1:width-pixels = 300.
frame fr1:height-pixels = 250.
frame fr1:bgcolor = 6.

btn:row = 18.

on choose of btn do:
    frame fr1:width-pixels = 600.
    frame fr_parent:width-pixels = 600.
end.

on window-resized of current-window do:
/*    frame fr_parent:virtual-width-pixels = current-window:width-pixels.*/
    frame fr_main:width-pixels = current-window:width-pixels.
    frame fr_parent:width-pixels = current-window:width-pixels + 20.
    frame fr_main:virtual-width-pixels = current-window:width-pixels.
    frame fr_parent:VIRTUAL-WIDTH-PIXELS = current-window:width-pixels.
end.

wait-for close of current-window.

Steps to reproduce are in the attached videos.

FWD behaves the same as OE as long as this assignment frame fr_parent:VIRTUAL-WIDTH-PIXELS = current-window:width-pixels. does not exist, if it does, OE doesn't clip the scrollbar anymore but FWD still does. Previously this had a workaround in FrameWidth.setWidthImpl where the maxWidth was the ancestorWidth and not the virtualWidth, but that is incorrect.

#3 Updated by Razvan-Nicolae Chichirau 8 months ago

As far as I can tell, the client correctly draws the vertical scrollbar. The problem is that it has an incorrect position which comes from the server.

Spent some time in ThinClient.pushWidgetAttr() and observed that when making the window bigger, the width value of the frame is sent correctly from the server and updated accordingly on the client. If I make the window smaller, this value seems to not change, so the problem may not be related to the actual drawing, but rather with the attributes which are sent to the client.

#4 Updated by Șerban Bursuc 8 months ago

Razvan-Nicolae Chichirau wrote:

As far as I can tell, the client correctly draws the vertical scrollbar. The problem is that it has an incorrect position which comes from the server.

Spent some time in ThinClient.pushWidgetAttr() and observed that when making the window bigger, the width value of the frame is sent correctly from the server and updated accordingly on the client. If I make the window smaller, this value seems to not change, so the problem may not be related to the actual drawing, but rather with the attributes which are sent to the client.

That would explain why limiting the width assignment fixed the issue in the past. I think the +20 width is still being applied when resizing to the left.

Also, to be more clear about the previous fix for this that was in trunk, this was the patch:

=== modified file 'src/com/goldencode/p2j/ui/FrameWidget.java'
--- old/src/com/goldencode/p2j/ui/FrameWidget.java    2025-09-30 10:41:57 +0000
+++ new/src/com/goldencode/p2j/ui/FrameWidget.java    2025-11-19 08:44:10 +0000
@@ -2988,7 +2988,7 @@
                final PaneEntity paneEntity = (PaneEntity) f;
                final int virtualWidth = paneEntity.getVirtWidthPixels().intValue();
                final int ancestorWidth = paneEntity.getWidthPixels().intValue();
-               int maxWidth = virtualWidth - x;
+               int maxWidth = ancestorWidth - x;

                if (virtualWidth > 0 && restrictedWidth > maxWidth)
                {

If this width assignment frame fr_parent:VIRTUAL-WIDTH-PIXELS = current-window:width-pixels. takes place after the resize, that explains the bug entirely and why the workaround works.

#5 Updated by Razvan-Nicolae Chichirau 8 months ago

Discovered why the server pushes wrong values to the client. So when making the window bigger, the WIDTH-CHARS is not set because of this code in PaneEntity.setVirtWidthCharsWorker():

if (width < _getWidthChars().doubleValue())
{
   // decreasing below regular size also affects regular size
   setWidthChars(width);
}

When making the window smaller, WIDTH-CHARS is set due to the same code. This will end up calling FrameWidget.setWidthImpl() -> config.widthPixels = restrictedWidth;, where restrictedWidth has the newly updated value. After this assignment, SyncCoordinatesAspect.afterSetWidthPixels() kicks in:

public void afterSetWidthPixels(BaseConfig cfg)
{
   if (isSuspended())
      return;

   WorkArea wa = contextData.get();

   cfg.widthChars = wa.cc.columnFromPixels(cfg.widthPixels);
}

, where isSuspended() returns true, preventing the update of cfg.widthChars. This is important because widthChars (and not widthPixels) is used on the client when setting the frame dimensions.

I've tested by manually making isSuspended() return false while executing frame fr_parent:VIRTUAL-WIDTH-PIXELS = current-window:width-pixels. and the vertical scrollbar is set now in the right position.

#6 Updated by Șerban Bursuc 8 months ago

Well I didn't think of checking aspect assignments so great job, but adding unexpected behaviors in aspects seems like an awful idea exactly due to scenarios like this. We expect aspects to do a basic assignment and no more.

Once the bug is solved I would document this somewhere in the width assignment functions.

#7 Updated by Razvan-Nicolae Chichirau 8 months ago

The suspend part is intentional because BaseEntity.setSizePixels() is defined as such:

@NoSyncCoordinates
protected void setSizePixels(Integer value, SizeAttribute attr)

This triggers SyncCoordinatesAspect.suspend() on method entry and SyncCoordinatesAspect.resume() on method exit. I think this was implemented to avoid side-effects while modifying any dimension-related attributes.

#8 Updated by Razvan-Nicolae Chichirau 8 months ago

  • % Done changed from 0 to 100
  • Status changed from New to WIP
  • Assignee set to Razvan-Nicolae Chichirau
  • reviewer Hynek Cihlar added

Hynek: Please review 10423a/rev. 16278.

#9 Updated by Razvan-Nicolae Chichirau 8 months ago

  • Status changed from WIP to Review

#10 Updated by Hynek Cihlar 8 months ago

Razvan-Nicolae Chichirau wrote:

I think this was implemented to avoid side-effects while modifying any dimension-related attributes.

Correct.

#11 Updated by Hynek Cihlar 8 months ago

Code review 10423a.

Instead of widthFromNative use columnFromPixels. The value truly represents pixels so in ChUI the conversion wouldn't work correct.

Should the assignment be done only when SCA.isSuspended()?

Also should the same modification be done for setHeightImpl?

#12 Updated by Razvan-Nicolae Chichirau 8 months ago

Hynek Cihlar wrote:

Code review 10423a.

Instead of widthFromNative use columnFromPixels. The value truly represents pixels so in ChUI the conversion wouldn't work correct.

Should the assignment be done only when SCA.isSuspended()?

Also should the same modification be done for setHeightImpl?

Right, it should also hold for setHeightImpl. I've tested with the following procedure:

Please check 10423a/rev. 16279.

#13 Updated by Hynek Cihlar 8 months ago

Hynek Cihlar wrote:

Should the assignment be done only when SCA.isSuspended()?

Otherwise the assignment triggers the aspect, I don't think this is desired.

#14 Updated by Hynek Cihlar 7 months ago

Hynek Cihlar wrote:

Hynek Cihlar wrote:

Should the assignment be done only when SCA.isSuspended()?

Otherwise the assignment triggers the aspect, I don't think this is desired.

Razvan, please reply to "Should the assignment be done only when SCA.isSuspended()?".

#15 Updated by Razvan-Nicolae Chichirau 7 months ago

If we would remove the if statement, heightChars would be basically updated twice: once when setting heightPixels by SCA.afterSetHeightPixels(), and once from the explicit assignment.

So, the answer is yes. The assignment should be done only when SCA.isSuspended() to avoid setting the config field twice.

#16 Updated by Hynek Cihlar 7 months ago

  • % Done changed from 100 to 90
  • Status changed from Review to WIP

Code review 10423a. The changes look good, just please move CoordinatesConversion cc = LogicalTerminal.coordinates() inside the isSuspended branch.

#17 Updated by Razvan-Nicolae Chichirau 6 months ago

  • Status changed from WIP to Review
  • % Done changed from 90 to 100

Hynek: Please check 10423a/rev. 16280.

#18 Updated by Hynek Cihlar 6 months ago

  • Status changed from Review to Internal Test

Razvan-Nicolae Chichirau wrote:

Hynek: Please check 10423a/rev. 16280.

It's good. Please regression-test.

#19 Updated by Razvan-Nicolae Chichirau 6 months ago

Testing that passed:
  • ChUI regression tests
  • tests from testcases projects related to HEIGHT-CHARS, HEIGHT-PIXELS, WIDTH-CHARS and WIDTH-PIXELS
  • smoke-tests for Hotel GUI + 2 other customer apps
  • unit-tests from a customer
  • isolated testcases, such as #10423-1

If this is enough, we should merge 10423a.

#20 Updated by Hynek Cihlar 6 months ago

  • Status changed from Internal Test to Merge Pending

Please merge 10423a to trunk.

#21 Updated by Razvan-Nicolae Chichirau 6 months ago

  • Status changed from Merge Pending to Test

Branch 10423a was merged into trunk as rev. 16360 and archived.

#22 Updated by Vladimir Tsichevski 6 months ago

Hynek,

side question: What exactly is Aspect4J used for in the FWD runtime?

IMO this makes development, debugging and maintenance harder:

  • FWD building takes a lot of time, incremental building is not available
  • the FWD build scenario cannot be reliable reproduced in Eclipse
  • debugging stepping is often broken

What would it realistically cost to move away from byte-code instrumentation / Aspect4J completely?
Any internal docs / old tickets discussing alternatives to Aspect4J weaving?

#23 Updated by Hynek Cihlar 6 months ago

Vladimir Tsichevski wrote:

Hynek,

side question: What exactly is Aspect4J used for in the FWD runtime?

IMO this makes development, debugging and maintenance harder:

Agree. But we are so deep in it that moving away from it would not be an easy task. Search for all the classes *Aspect in the project, you will see what I mean.

  • FWD building takes a lot of time, incremental building is not available
  • the FWD build scenario cannot be reliable reproduced in Eclipse
  • debugging stepping is often broken

For development it helps to switch to runtime time weaving.

Also available in: Atom PDF