After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 747798 - Cannot apply CSS to private members of GtkComboBox
Cannot apply CSS to private members of GtkComboBox
Status: RESOLVED DUPLICATE of bug 751409
Product: gtk+
Classification: Platform
Component: Widget: GtkComboBox
3.16.x
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2015-04-13 19:13 UTC by Leo Ufimtsev
Modified: 2015-07-28 20:33 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Example, the 'dropdown' button can't be styled per provider to GtkComboBoxText. (3.00 KB, image/png)
2015-04-13 19:15 UTC, Leo Ufimtsev
Details
button not styled on per-widget basis. (82.36 KB, image/png)
2015-04-16 14:34 UTC, Leo Ufimtsev
Details

Description Leo Ufimtsev 2015-04-13 19:13:59 UTC
Given the handle to a GtkComboBox (GtkComboBoxText), there isn't a way to style some underlying components like GtkTreeMenu or the drop down button by a context provider.
There also isn't a way to get to these sub-handles as they are in a private struct.

Example code to reproduce is here:
https://github.com/LeoUfimtsev/LeoGtk3/blob/80cc0ceda0c51f4b2748c852616331aa5f478bee/main.c


I.e, 
1) We apply: "* {background:red}" (or "GtkComboBoxText * { background:red}") 
and expect a red ComboBox, but only the entry part is red, the menu is not styled. The button of a read-only combo is not styled.

2) Alternativley, we'd like to access these widgets and style them manually, but there is no way to access them as they are in a private struct. 


I.e, please implement recursive styling for GtkComoBoxText or provide some mechanism to access the GtkTreeMenu and the GtkButton.


Note:
1) These can be styled via global provider for screen. But as an SWT library developer, we need to be able to style each induvidual widget for the use case of where one would like to have different colored comboBoxes.

2) It's technically possible to add a class to a widget and then style the class from a global css. An example of this is:
https://github.com/LeoUfimtsev/LeoGtk3/blob/057884368bf38a626dbaac5c575c15a5e1c93f2f/main.c#L35
But while this works ok for application development, it's not a very clean approach for development of libraries that build on top of Gtk. (SWT in my case).

3) There is a related Gtk2 Bug for this:
https://bugzilla.gnome.org/show_bug.cgi?id=362790
Comment 1 Leo Ufimtsev 2015-04-13 19:15:07 UTC
Created attachment 301488 [details]
Example, the 'dropdown' button can't be styled per provider to GtkComboBoxText.
Comment 2 Leo Ufimtsev 2015-04-13 19:15:53 UTC
Btw, I'm an SWT/Java developer, not a gtk developer, as such if I'm missing something obvious, please let me know.
Comment 3 Leo Ufimtsev 2015-04-13 19:18:15 UTC
related SWT bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=464228
Comment 4 Matthias Clasen 2015-04-14 17:18:19 UTC
It is unlikely that we'll give you direct access to the internals of combo boxes.

Just to make sure I understand: what is wrong with this ?

.combobox-entry > .button { background: red; }

Works fine in my testing to make those buttons you complain about red.
Comment 5 Leo Ufimtsev 2015-04-16 14:34:37 UTC
Created attachment 301736 [details]
button not styled on per-widget basis.

(In reply to Matthias Clasen from comment #4)
> It is unlikely that we'll give you direct access to the internals of combo
> boxes.
> 
> Just to make sure I understand: what is wrong with this ?
> 
> .combobox-entry > .button { background: red; }
> 
> Works fine in my testing to make those buttons you complain about red.

Hello Matthias, 

Thank you for your reply.

This ".combobox-entry > .button { background: red; }" works if you apply it to the 'global' CSS screen. 
But in the SWT library (e.g used by Eclipse),  we need to be able to style individual ComboBoxText widgets. E.g one should be able to be blue and the other red. Otherwise it would mean api breakage.
The above snippet doesn't seem to work on a per-widget basis. I.e when applied to a specific GtkComboBoxText.
To illustrate: Given the handle to GtkComboBoxText, if I open GtkInspector, click on GtkComboBoxText, open the custom-css Tab (for GtkComboBoxText, not global), then paste it in there, the button is not styled. (please see screenshot). 

If I am missing something(?), please let me know. I am my no means a Gtk expert.

It's no necessary to expose the private widgets. The requirement from SWT is that given the GtkComboBoxText handle, style the inner components of only that specific widget (not style all widgets of the same type).  (at present TreeMenu and ToggleButton are not stylable).

If there is a native Gtk way of doing this already, please let me know and I can implement it into SWT. Otherwise it would be nice for such functionality to be implemented somehow.?
Comment 6 Emmanuele Bassi (:ebassi) 2015-04-16 14:44:46 UTC
The way this is usually achieved is by specifying a style class and apply that class only to a specific widget, using gtk_widget_get_style_context() and gtk_style_context_add_class().

You can also create a new GtkCssProvider and add it to the widget, though that will come at a cost when computing the style. You can follow the code in bug 747136 for a plausible approach.
Comment 7 Leo Ufimtsev 2015-04-16 15:07:28 UTC
(In reply to Emmanuele Bassi (:ebassi) from comment #6)
> The way this is usually achieved is by specifying a style class and apply
> that class only to a specific widget, using gtk_widget_get_style_context()
> and gtk_style_context_add_class().
>
> You can also create a new GtkCssProvider and add it to the widget, though
> that will come at a cost when computing the style. You can follow the code
> in bug 747136 for a plausible approach.

Hello Emmanuele, 

If I understand correctly, you are suggesting to add a unique class to a widget and style the class globally, as I did in this snippet:
https://github.com/LeoUfimtsev/LeoGtk3/blob/b73e8154f4da41ca07c951902015fc70fe288d7c/main.c#L35
...
gtk_style_context_add_class (button_context, "custom-class-123");
gtk_css_provider_load_from_data (GTK_CSS_PROVIDER(provider),
                                   " GtkComboBoxText.custom-class-123 * {\n"
                                   "   background: rgb (255, 0, 0);\n"  
....

If so, this approach would work well for a small/medium/large Gtk Application. But unfortunately it doesn't scale well for a library such as SWT that is build on top of Gtk.

The main issue is that in SWT each widget is an isolated unit that doesn't know anything about the widget next to it.

E.g Eclipse can have 1000's of widgets running concurrently. With the above method, we would have to add a unique class to each individual widget and then style the unique classes from the global style sheet.
I don't know how it would impact performance, but it would mean a gloabl pool of classes. It is somewhat error-prone and may be difficult to debug and maintain. 
We're also not in a position to break compatibility because SWT also has to work on Cocoa and Win32 which don't have notions of CSS. 

We need something like Widget_set_background(..) to function on a per-widget basis for GtkComboBoxText. Is this in any way possible?
Comment 8 Emmanuele Bassi (:ebassi) 2015-04-16 15:20:04 UTC
> We need something like Widget_set_background(..) to function on a per-widget
> basis for GtkComboBoxText. Is this in any way possible?

What you're asking is not at all trivial.

There is gtk_widget_modify_background_color(), which is deprecated because it does not match semantics and assumptions of the CSS model.

If a widget is style to have a gradient, what happens when you change the background color? Do we ignore the gradient? Do we change the the initial stop of the gradient? The final one? Do we blend the gradient with the color? What happens if the background is an image? Any answer to these questions may or may not be valid under certain assumptions; we cannot provide an entry point for each combination of option — it'd be an unmaintainable madness.
Comment 9 Emmanuele Bassi (:ebassi) 2015-04-16 15:27:28 UTC
(In reply to Leo Ufimtsev from comment #7)

> We're also not in a position to break compatibility because SWT also has to
> work on Cocoa and Win32 which don't have notions of CSS. 

Leaving aside Windows, the only way to change the background color of a NSControl on AppKit is to subclass that control and draw yourself — unless you go into weird contraptions and assume all controls are actually transparent. You can do the same with GTK+, up to a point.
Comment 10 Leo Ufimtsev 2015-04-16 15:55:07 UTC
(In reply to Emmanuele Bassi (:ebassi) from comment #8)
> > We need something like Widget_set_background(..) to function on a per-widget
> > basis for GtkComboBoxText. Is this in any way possible?
> 
> What you're asking is not at all trivial.
> 
> There is gtk_widget_modify_background_color(), which is deprecated because
> it does not match semantics and assumptions of the CSS model.
> 
> If a widget is style to have a gradient, what happens when you change the
> background color? Do we ignore the gradient? Do we change the the initial
> stop of the gradient? The final one? Do we blend the gradient with the
> color? What happens if the background is an image? Any answer to these
> questions may or may not be valid under certain assumptions; we cannot
> provide an entry point for each combination of option — it'd be an
> unmaintainable madness.

Hmm, that is a good point. 

1) What about a recursive approach like:
gtk_css_provider_load_from_data_recursivley ( ...)  which would apply the CSS to the given provider as well as to the sub-widgets inside of it?

2) Btw, what would be the issue with exposing internal widgets GtkTreeMenu and GtkToggleButton? We'd have access to those in SWT we could style them ourselfes manually?

Or, maybe if that's too messy, add methods into GtkComboBoxText to return *just* the providers of the GtkTreeMenu and ToggleButton:
GtkToggleButton like 
   gtk_combo_box_get_treeView_provider()
and 
   gtk_combo_box_get_toggleButton_provider()
Because given the providers, we could style them ourselfes in SWT.

Thoughts?

I'm generally open to what ever works, if you have any other suggestion/ideas, please let me know. In essence we're trying to make SWT look nice running on Gtk3 so that things like Eclipse Dark theme look nice.
Comment 11 Emmanuele Bassi (:ebassi) 2015-04-16 16:33:56 UTC
(In reply to Leo Ufimtsev from comment #10)

> 1) What about a recursive approach like:
> gtk_css_provider_load_from_data_recursivley ( ...)  which would apply the
> CSS to the given provider as well as to the sub-widgets inside of it?

That's what the "C" in Cascading Style Sheet means: all styles will cascade through the style tree. Matching is done via selectors and specificity.

I fail to understand how that applies to this situation, though; isn't that what you're trying to avoid?
 
> 2) Btw, what would be the issue with exposing internal widgets GtkTreeMenu
> and GtkToggleButton? We'd have access to those in SWT we could style them
> ourselfes manually?

That is not going to happen. It would make internals part of the API stability guarantee, essentially freezing GTK itself.
Comment 12 Leo Ufimtsev 2015-04-16 19:01:29 UTC
(In reply to Emmanuele Bassi (:ebassi) from comment #11)
> (In reply to Leo Ufimtsev from comment #10)
> 
> > 1) What about a recursive approach like:
> > gtk_css_provider_load_from_data_recursivley ( ...)  which would apply the
> > CSS to the given provider as well as to the sub-widgets inside of it?
> 
> That's what the "C" in Cascading Style Sheet means: all styles will cascade
> through the style tree. Matching is done via selectors and specificity.

The trouble is that applying a style like {background:red} onto GtkComboBoxText doesn't peculate down to GtkTreeMenu and GtkToggleButton. To be more precise, it peculates when you apply CSS to the screen (globally), but not when you apply via gtk_css_provider_load_from_data() onto a *specific* widget.

If you look at this example:
https://github.com/LeoUfimtsev/LeoGtk3/blob/80cc0ceda0c51f4b2748c852616331aa5f478bee/main.c#L47

I apply CSS to GtkComboBoxText 
gtk_css_provider_load_from_data (GTK_CSS_PROVIDER(provider),
                                   "* {\n"
                                   "   background: rgb (255, 0, 0);\n"  //red
				   //				   "   background-color: rgb(255,0,0);\n" //red
                                   "}\n", -1, NULL);

But this does not make all of GtkComboBoxText red. The GtkToggleButton and the GtkTreeMenu are not styled. See screenshot:
https://bug747798.bugzilla-attachments.gnome.org/attachment.cgi?id=301488

To reproduce or see what I mean, try:
git clone https://github.com/LeoUfimtsev/LeoGtk3/tree/80cc0ceda0c51f4b2748c852616331aa5f478bee
make 
./main 

I have tried various CSS selectors like "GtkComboBoxText * { ..}" "* * { ..}" ".combobox-entry > .button { background: red; }" etc.. None of these work in conjunction with gtk_css_provider_load_from_data(..) when applied locally to a widget.

Is there a solution to this?

Thank you for your time.
Comment 13 Emmanuele Bassi (:ebassi) 2015-04-17 10:54:47 UTC
(In reply to Leo Ufimtsev from comment #12)

So, in the end, we actually found the issue.

> The trouble is that applying a style like {background:red} onto
> GtkComboBoxText doesn't peculate down to GtkTreeMenu and GtkToggleButton.

This is the bug of GtkComboBox; the toggle button should be styled accordingly, since it's a child of the combo box widget.

The popup GtkTreeMenu is a completely private widget, whose API is not exported for public use. Whether a style should apply to popup widgets is debatable — you don't want the context menu of a GtkTextView to have the same font as the GtkTextView, like in bug 697127 — but GtkTreeMenu should at least have a way to connect to the attached widget style, so that styles propagate correctly.

The proper fix is to ensure that the style applied to a GtkComboBox gets properly propagated to its children; we should consider the GtkComboBox not as a composite widget, but as an atomic one; exposing the private children to the CSS style machinery is definitely not a good idea.
Comment 14 Leo Ufimtsev 2015-04-17 14:33:25 UTC
(In reply to Emmanuele Bassi (:ebassi) from comment #13)
> (In reply to Leo Ufimtsev from comment #12)
> 
> So, in the end, we actually found the issue.

:-D

> > The trouble is that applying a style like {background:red} onto
> > GtkComboBoxText doesn't peculate down to GtkTreeMenu and GtkToggleButton.
> 
> This is the bug of GtkComboBox; the toggle button should be styled
> accordingly, since it's a child of the combo box widget.

1) 
Yea, it would be nice for the style to peculate down to the GtkToggleButton.

> The popup GtkTreeMenu is a completely private widget, whose API is not
> exported for public use. Whether a style should apply to popup widgets is
> debatable — you don't want the context menu of a GtkTextView to have the
> same font as the GtkTextView, like in bug 697127 — but GtkTreeMenu should at
> least have a way to connect to the attached widget style, so that styles
> propagate correctly.
> 
> The proper fix is to ensure that the style applied to a GtkComboBox gets
> properly propagated to its children; we should consider the GtkComboBox not
> as a composite widget, but as an atomic one; exposing the private children
> to the CSS style machinery is definitely not a good idea.

2)
I see.  I read the related bugs. Menu inherited a font that made it look strange. 

How about: Would the following be possible: 
 - Given the provider of GtkComboBoxText (*not global provider*)
 - Apply CSS data onto GtkComboBoxText that selects the menu from inside the GtkComboBoxText like so:
   "GtkComboBoxText  .menu {background:red}" [*1]
 - This would technically not expose a handle to GtkTreeMenu, but allow us to style it on a per-widget basis. 

Please note: currently the CSS snippet above (*1) works when applied to global provider, but not when applied to GtkComboBoxText provider (I can provide snippet if you like?). I'm not sure if this is a bug or design of Gtk. 
If the above would work, it would resolve the issue with menu styling. 

Thoughts? 
But if you have something else in mind, please let me know.
Comment 15 Leo Ufimtsev 2015-07-27 22:24:41 UTC
Any updates on one?

Was the idea to make it so that styles are applied recursively?
Comment 16 Matthias Clasen 2015-07-28 19:28:00 UTC
I think we need new api for that, see bug 751409
Comment 17 Leo Ufimtsev 2015-07-28 20:33:54 UTC
Thank you for pointing this out. You're right, that's pretty much what is needed.

In this case, this bug is a duplicate of the bug above.

*** This bug has been marked as a duplicate of bug 751409 ***