Eclipse, Dark theme and Gtk. What Eclipse can theme and what needs to be themed by the OS.

 

About

I’m an SWT developer on the Gtk side.

Recently I’ve done a fair bit of work with Eclipse’s dark theme and Gtk’s CSS. (E.g fixing background of button and combo). As such I’ve come across what is do-able in SWT and what is not.

 

The issue with composed GtkWidgets

In SWT, we can theme individual GtkWidgets with gtk_context_add_provider(widgetProvider, css) . E.g basic labels, buttons. This works well for basic widgets.

However, some gtk widgets are composed of multiple nested widgets. E.g: GtkComboBoxText

GtkComboBoxText
— GtkToggleButton
— GtkTreeMenu
— GtkCellView
— etc..

The issue is that the CSS that we apply only get’s applied to the top-level widget and not always recursively to all it’s child widgets. (Please see 1* in appendix)

With such widgets, we can sometimes use gtk_bin_get_child() to get one of the nested components and run gtk_context_add_provider(..) on that, but this doesn’t give us access to all nested components. (bin_get_child returns only one child).
Sometimes we can hack a bit and with gtk_container_forall(..) access the child widgets that gtk_bin_get_child() does not expose.

But there is a limit as to what we can access. Some inner widgets are tucked away inside a private struct (the issue described here). As such, we have no way to apply a style context to them.

As a result, we can sometimes only apply a background color to some parts of the widget.
In the example below, we styled the Entry and the text of the menu. But the drop down button and the background of the menu cannot be styled.

MenuComboBox_2015.04.07

 

How do other Gtk Developers do it?

You might wonder, with such a limitation, how do other gtk developers get by?
Suppose you’d like to have two combo boxes, a blue and a red one. How would a Gtk Developer implement this?

To find the answer to this mystery I ventured out to the gtk+ irc channel and a guy called ‘Company’ helped me out.
To apply a theme to individual widgets in Gtk3, you would have to give them a unique class ID, then create a provider for the whole screen and select the widget based on it’s unique ID.

I wrote some native Gtk code to try it out and it worked. (In the example I assign an id ‘custom-class-123’ and then theme it from the global theme.

Technically, implementing this in SWT wouldn’t be difficult. But this would be a hack on an a somewhat epic scale. It would mean we would have 1000’s of unique CSS classes to deal with and it’s not yet obvious if it would be possible to remove styling once applied.

The main issue is that SWT’s philosophy is to style each and individual widget, there isn’t really a ‘central’ theming api. Where as Gtk3’s philosophy is to define the CSS only once and be done with it. E.g GtkComboBoxText * { background:red }  and for individual widget styling use CSS classes.

 

So what’s the deal with Check/Radio/Slider icons?

Eclipse has it’s own CSS syntax which differs from GTK. You can’t really take Eclipses’ Dark-theme CSS and just bluntly apply it to Gtk.

For example in Eclipse CSS ‘Label’ and ‘Button’ are defined, but in Gtk CSS this would need to be translated to GtkLabel and (GtkButton|GtkToggleButton|GtkRadioButton|GtkCheckButton [depending on SWT.STYLE bit]).

With that said, Eclipse CSS does not define any icons for GtkCheckButton, GtkRadioButton or sliders. As a result, we get the icons from the underlying GtkTheme if any are defined.

So when the OS has dark icons, Eclipse looks like this: (note the dark check-boxes):

And when the OS has bright icons, Eclipse looks like this:

But if the theme doesn’t define icons, then we draw our own, then it looks like this:

 

Conclusion: So how do we get Eclipse to look nice?

In essence, Eclipse’s theming doesn’t fully live on it’s own. It takes some things from the OS Gtk theme (e.g radio icons, Menu backgrounds in Combo boxes etc).
As such, For best Dark-Eclipse looks on Gtk, you should run Eclipse under a Dark theme like Adwaita-dark and use the ‘dark’ theme from Eclipse’s Appearance settings.

With the latest nightly build, you can make Eclipse look like this:
Eclipse dark looks

Hope it helps.

 

 

Appendix

1** I don’t have a good source that css is not applied recusivley. This is an observation from experimentation. As test, you can run any gtk app, open gtk inspector (Ctrl+shift+d) (if you have gtk3.14), then select a widget, on the 2nd set of tabs select ‘custom CSS’. From GtkComboBoxText you can’t theme the inner GtkToggleButton and GtkEntry from GtkComboBoxText. You can only theme them if you select the inner widgets directly. But the problem is that we don’t have access to those from SWT.
cannot_theme_gtkcomboboxtext_2015.04.07

If you spot an error in any of the text above, or have general feedback, please post a comment, it would be of much help.

SWT Bug Triage

If you are a GTK/SWT developer and want to be involved in SWT Triage,
Then you should read:
https://www.eclipse.org/swt/triage.php

It is also useful to subscribe to the swt-platform email in bugzilla.
This way you’ll get emails for new SWT bugs and comment update on un-assigned bugs.
To do this, go to bugzilla, -> Preferences -> Email preferences
-> “Add users to my watch list” , add: platform-swt-inbox@eclipse.org
The only trouble is that you’ll get emails for all platforms (Windows/Mac/Linux) and you’ll have to create some filters for sorting things out. But in general I found that it’s good to be ‘aware’ of the issues that happen on windows/mac, as those sometimes occur on Linux also, or a bug labeled as ‘windows’ often impacts linux swt also.

 

 

Correct SWT code style for widget development and using Eclipse’s regex to fix your code style.

When doing SWT Development, if you submit code with the wrong style, you might get some code-comments from other contributors advising you to fix your style.

Luckily there is an Eclipse-SWT-formatted profile that one can use or one can fix them with some Regex.

Note: I will update this article as I find out more about SWT style.
Continue reading

How to create cross-platform SWT applications packaged in a single jar in Eclipse

The deal with SWT is that you geneally create a jar that runs nativley on a single platform.

This means that if you want to create an application that works on windows/mac/linux in both 32/64 bit, then you need to compile/package jar 6 files and distribute one file per platform.

This is very cumbersome for small projects where you want a single file that runs on every platform.

The solution is to bundle the jars and load them dynamically with Mchr3k’s SWT Jar loader.

The next challenge is how to get this business working in Eclipse. Well, there is a guide for this.

Basically, you create a project with the name “HelloWorld”, you have to
download the swt jar’s and rename them to match os/version and then you
have to add a build.xml file. This takes about 30 minutes.

I followed the guide and actually got it to work.

To make life easier, I created a git-repo with a template project.  You can clone it and start a SWT project with that.

I used swt 4.4 in the project. In the future you might want to update it. To do so:

  • Download the latest jar files from Eclipse’s download site .
    • click on the most recent version, e.g ‘4’4,
    • then search for “SWT Binary and Source”
    • download the Windows 32/64 Versions,   linux x86/x86_64/GTK+ versions, Mac OS X versions
    • open the archives and extract the ‘swt.jar’ files
    • match the jar files to the jar files in the project ./gui folder. But append new version. (4.4 -> 4.x)
  • Edit the build.xml file,
    • change the “swtversion=”4.4″” to the newer version.
    • Also update <fileset dir=”./gui” includes=”swt-*-4.4.jar” />

Screen shots:

Linux

crossSwt1

You can run the generated jar file with ‘java -jar crossSWT.jar”:

crossSWT jar

OS X

Here I had to launch the jar with a special paramater:
java -jar -XstartOnFirstThread crossSWT.jar
os x

Windows

I don’t use windows :-), but rumors has it works on windows also.

How to compile various gtk3 versions and run eclipse Apps with those (for SWT Widget testing)

ScreenShot_2014_09_29__15_07_28_

When developing SWT widgets, we need to test them on various GTK versions to ensure backwards compatibility.

There are some tricks and perks involved.

Get Gtk sources

  • Go to the gtk git repo and pull the code: https://git.gnome.org/browse/gtk+/
    (I recommend the https version: https://git.gnome.org/browse/gtk+)
    (if you don’t know how to use eclipse’s EGit, read this)
  • Check out the versions that you’re interested in (e.g 2.24, 3.10, 3.4, 3.8)
    These are found in major Linux distributions (e.g ubuntu 12..).
  • For the time being, check out the newest gtk version (e.g 3.10 at the time of writing).
    (It’s easier to build a newer version than an older one)
  • Open Terminal, go to your checked out gtk branch.
    Run the following commands:

    ./autogen.sh
    ./configure --enable-x11-backend --enable-wayland-backend
    make
    
  • The first time you run the commands, you might run into errors telling you you’re missing something on your system. Inspect autogen.sh to see what it runs and then install the utilities with yum.
  • Now copy gtk to another place on your system. E.g ~/src/gtk2_24 This way you don’t have to recompile this business every time.
  • Now you can build the other versions and similarly copy them to ~/src/gtk*_*
  • NOTE ON gtk3.4 (and maybe older) The Wayland configuration makes certain things look more correct. But sometimes it makes building older versions (like gtk3.4) near impossible due to missing dependencies. In this case, run the configure without these:
     ./autogen.sh ./configure make 

Configure Eclipse to use the gtk you compiled

  • Edit your run-configuration of the code snippet that you want to run.
  • Navigate to “Environmental Variables”
  • Click on “Add”, type in:
    name: LD_LIBRARY_PATH
    path: #your_compiled_gtk      //e.g /home/lufimtse/src/gtk3_10/gtk/.libs
  • Name your configuration (I reccomend appending gtk version, e.g “ControlExample (g3-10)”)
  • It should look something like this:
    Eclipse env var
  • Now run the configuration and you should see your application rendered in gtk*.*.
    You may note that it won’t have any styling:
    java app in compiled gtk
  • The lack of styling is due to the fact that there is no theaming.
    Now sometimes you might want the compiled gtk to use your system theame to see impact of themes on looks.
    To do so, do as above except run the configuration as following:

    ./configure --prefix=/usr --sysconfdir=/etc --enable-broadway-backend --enable-x11-backend --disable-wayland-backend
    

    In the interest of comparison: (left native look, right bare look)
    native vs bare

  • Lastly, in your source code, you might want to verify that you’re running the compiled gtk and not your own. Use this line of code:
    System.out.println("GTK Version: " + OS.gtk_major_version() + "." + OS.gtk_minor_version() + "." + OS.gtk_micro_version());