Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 260406 - e4 CSS: widgets need to notify CSS to apply style information
Summary: e4 CSS: widgets need to notify CSS to apply style information
Status: RESOLVED INVALID
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: E4 (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 260408 260791 271501
  Show dependency tree
 
Reported: 2009-01-08 10:49 EST by Kevin McGuire CLA
Modified: 2016-02-24 13:22 EST (History)
10 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Kevin McGuire CLA 2009-01-08 10:49:24 EST
The e4 CSS support requires an ability for widgets to notify the CSS engine that style information can be applied.  This notification should occur at the end of the widget creation cycle, conceptually just before the execution stack is popped and control is returned to the application code instantiating the widget.

The result of the notification would be that the CSS engine could apply style information in the form of calls to existing widget API (e.g. setting fonts and colors).

In discussions with SN, it wasn't clear how this could be done without requiring extra work on the part of extended widgets.  Since there is currently no "widget is finished creation" phase notification, it seems that each widget must explicitly at the end of it's constructor call some new API like notifyWidgetCreated().  Thus extended widgets must modify their constructors to do this; they cannot get it for free AFAIK.

A second issue is double or premature notification due to subclassing.  For example, the Nebula Gallery is a subclass of Canvas.  But Canvas is itself a concrete widget useable on its own.  At the end of the Canvas() init method, there would need to be a call to notifyWidgetCreated().  But at the end of the Gallery widget, there must also be a notifyWidgetCreated(), since only at that point will the Gallery internal state be initialized such that it's setters can be called legally.  This could result in double notification, with both Canvas and Gallery notifying the same listener.  Worse, if both notifications looked like they were wrt the Gallery widget, the first one (from Canvas' call  to notifyWidgetCreated()) could cause the receiver to prematurely attempt to make Gallery setter calls prior to the subclass being initialized.
Comment 1 Steve Northover CLA 2009-01-08 15:39:22 EST
We would have do to something like:

if (getClass().getName().equals("org.eclipse.swt.Canvas")) {
    ... do the work ...
}

I don't think there is any good answer to this problem, other than inventing a widget creation cycle and invalidating all the existing code.  I forget all the details of this discussion but we can have them all again, here, when Silenio gets back.
Comment 2 Kevin McGuire CLA 2009-01-08 16:00:17 EST
(In reply to comment #1)
> We would have do to something like:
> 
> if (getClass().getName().equals("org.eclipse.swt.Canvas")) {
>     ... do the work ...
> }

Yeah, a bit ickky though. Or does this work?  Introduce:

  Widget(Widget parent, int style, boolean notifyOfCreate)

with 
  Widget(Widget parent, int style) {
    this(parent, style, true);
  }

and
  Canvas(Widget parent, int style, boolean notifyOfCreate) {
    super(parent, style, false);
    ...
    if(notifyOfCreate) {
      ...
    };
  }

  Gallery(Widget parent, int style, boolean notifyOfCreate) {
    super(parent, style, false);
    ...
    if(notifyOfCreate) {
      ...
    };
  }

> I forget all the details of this discussion but we can have them all again, 
> here, when Silenio gets back.

I tried to capture it as best I could in this bug but yeah we can discuss with Silenio on his return.  I believe our inescapable conclusion was that there was no free lunch for extended widgets.  But my comment was that there wasn't one anyway, since in order to style the extended widget specific attributes, you needed to write CSS extension code anyway to convert the css property change into a call on the widget subclass.  When writing that code, you should get together with the widget owner to ensure it notifies correctly.
Comment 3 Randy Hudson CLA 2009-01-12 11:18:02 EST
What if the client want to immediately change the widget's style after it is created?  Would the style information be applied twice in that case?

It seems like you may want to tie-in style application to layout, since it is another thing you want to only happen one time. Sort of like commitProperties() in Flex.

Also, wouldn't you want this method to be like an "addNotify()".  It would have to be called after construction, but also if you reparented the widget, right?
Comment 4 Kevin McGuire CLA 2009-01-12 12:15:51 EST
(In reply to comment #3)
> What if the client want to immediately change the widget's style after it is
> created?  Would the style information be applied twice in that case?

The goal with CSS is that you don't change the widget's style (well, not directly from the caller who is instantiating the widgets).  You can however do things like change it's ID and CSS Class, and doing so would trigger a second styling pass. So now that you mention it, one would like to be able to set these from within the constructor to avoid double styling, which currently isn't possible.  Related therefore is bug #260407.

> It seems like you may want to tie-in style application to layout, since it is
> another thing you want to only happen one time. Sort of like commitProperties()
> in Flex.

I don't know Flex, who calls commitProperties()?

I should preface with the fact that we would like callers to be able to avoid doing anything extra/special to get the CSS styling triggered.  This provides backwards compatibility and allows good separation between widget construction and styling.  So although one can explicitly call the styling engine today post widget creation, we'd like the programming model to be such that you'd almost never do that.

That said, you're correct that conceptually styling and layout go together.  Presently we've not committed to CSS layout, just styling, because the workbench does so much dynamic layout that it's not clear how to mix the two. But we'll likely end up with some kind of declarative layout for say spacing around the widgets.

> Also, wouldn't you want this method to be like an "addNotify()".  It would have
> to be called after construction, but also if you reparented the widget, right?

Yes good, that's a requirement I forgot to mention: restyling must happen if parenting changes because style rules can be parent chain specific.
Comment 5 Kevin McGuire CLA 2009-01-12 12:28:07 EST
(In reply to comment #4)
> (In reply to comment #3)
> > What if the client want to immediately change the widget's style after it is
> > created?  Would the style information be applied twice in that case?
> 
> The goal with CSS is that you don't change the widget's style

To clarify, I mean you don't directly call widget API for changing colors, fonts, etc.  You rely on the declarative style sheet for that.
Comment 6 Randy Hudson CLA 2009-01-12 13:40:12 EST
> I don't know Flex, who calls commitProperties()?
> 
> I should preface with the fact that we would like callers to be able to avoid
> doing anything extra/special to get the CSS styling triggered.

Yes, commitProperties in Flex is "scheduled" and called magically at the right time before stuff would repaint.  If not, let's say that's true ;-).  Similarly, in SWT, I can do:

   button.setPressed(true);
   button.setBackground(RED);

And the "system" is smart enough to queue and later paint the button just once, without any explicit requests from the client.

Unfortunately, things are not as easy when I do this:

   button.setText("Foo");
   button.setFont(ARIAL);

A repaint will happen, but layout is left to the caller, and it's not easy. In practice, the caller has no idea how far up the parent chain to go to request a layout. It would be nice if CSS and even layouts were more "automagic".

Another scenario is you change the style "class" for both a composite and a child control. Both changes affect the Font for the child, so you'd only want to refresh it once. The mark-dirty-and-schedule-update pattern for painting would be ideal for this new style application as well as improving the existing layout support. I know it's not built-in to the platforms like (re)painting, but there are ways to achieve the same.
Comment 7 Boris Bokowski CLA 2009-05-29 11:40:35 EDT
Should we revive this discussion again?

Would it be possible to add every newly created widget (from the constructor of Widget) to a set, without notifying eagerly at that point, and then at the next convenient time before the next repaint - equivalent of timerExec(0) - the notification is sent for all objects in that set?
Comment 8 Kevin McGuire CLA 2009-05-29 12:18:09 EDT
(In reply to comment #7)
> Should we revive this discussion again?

From my point of view this is a *must have* for e4 1.0/Eclipse 4.0.
Comment 9 Eric Moffatt CLA 2009-05-29 12:51:36 EDT
John A had an interesting take on the 'batching' pattern. In the current Jobs framework you can have a single job that owns the list and adding to the list calls the 'schedule' method (which is a no-op if it's already been scheduled). One of its interesting aspects is that you can call 'schedule' even if the job is currently running and it'll simply add itself back to the tail of the scheduling list once it's done.

We might have to make the list.add method thread safe so that if the job is currently running the first 'add' blocks until it's finished (then it proceeds, calls 'schedule' again...). Under most scenarios it'd be likely that all the necessary adds would take place before the job actually starts.
 
Comment 10 Mike Wilson CLA 2009-05-29 14:12:37 EDT
(In reply to comment #8)
> (In reply to comment #7)
> > Should we revive this discussion again?
> 
> From my point of view this is a *must have* for e4 1.0/Eclipse 4.0.
> 
Agreed. And to be clear, this effectively implies that it needs to happen by Sept. of this year.

Comment 11 Stefan Xenos CLA 2009-09-13 00:23:24 EDT
> A repaint will happen, but layout is left to the caller, and it's not easy. 
> In practice, the caller has no idea how far up the parent chain to go 
> to request a layout. It would be nice if CSS and even layouts were 
> more "automagic".

I couldn't agree more. FYI, this is the problem described by bug 103863.

In fact, in order for this support to be used in the way it was intended, you'd pretty much need to fix bug 103863 too.

If you have an automatic listener that's changing widget fonts and whatnot when a widget is reparented based on the parent's CSS data, that would have consequences for the widget's preferred size... so you'd need a way to mark the widget as requiring a layout before the next repaint without actually knowing the details of all the parent layouts.

FYI, bug 103863 had working code for mark-and-sweep SWT layouts attached (although it's probably somewhat stale by now).
Comment 12 Remy Suen CLA 2009-09-14 07:34:28 EDT
(In reply to comment #10)
> (In reply to comment #8)
> > (In reply to comment #7)
> > > Should we revive this discussion again?
> > 
> > From my point of view this is a *must have* for e4 1.0/Eclipse 4.0.
> > 
> Agreed. And to be clear, this effectively implies that it needs to happen by
> Sept. of this year.

We're half way through September, by the way. :o
Comment 13 Lars Vogel CLA 2015-05-07 19:30:58 EDT
This looks more like a discussion bug to me.
Comment 14 Markus Keller CLA 2016-02-24 13:22:56 EST
The associated commit http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=f15ff0bb3cff4bd3ecbcf7fe360d6cd226272c84 added magic to Widget#setData(String, Object), but only explained this in the Javadoc of Widget#reskin(int). The added magic looks unused, but since it's API, we can't just remove it.

Fixed the Javadocs with http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=3aeecc6050b5ad0d4a59c4b4f7650726018a0db3