GTK3 Themes
From Xojo Documentation
Starting with Xojo 2017r2, Linux apps now use GTK3. Since Xojo uses native controls that means your app's controls will use the theme of the Linux distribution the app runs on. This can sometimes mean that your app's UI will not look exactly like what you designed in the Layout Editor because a theme may dramatically change control sizes and padding. This is a problem that can occur with any modern GTK3 app.
If this is a problem for your apps, there are a couple ways you can work around it:
- Use Fixed/Locked Control Padding
- Have Your App Load and Use a Specific Theme
Both of these solutions can be handled by Declares that you put in your App.Open event handler.
Contents
Use Fixed/Locked Control Padding
For many apps, the primary concern is to not have controls change their size or position depending on the theme being used. You can ensure specific styling for controls in your apps by using a static amount of padding that won't change regardless of the user's theme selection. This has the benefit of letting your app use other aspects of the theme, such as colors, while maintaining control layout better.
You can put this code in the App.Open event handler to set a specific padding:
Declare Function gdk_screen_get_default Lib "libgdk-3" () As Ptr
Declare Function gtk_css_provider_new Lib "libgtk-3" () As Ptr
Declare Function gtk_css_provider_load_from_data Lib "libgtk-3" _
(provider As Ptr, data As CString, dataLen As Integer, error As Ptr) As Boolean
Declare Sub gtk_style_context_add_provider_for_screen Lib "libgtk-3" _
(screen As Ptr, provider As Ptr, priority As UInt32)
Declare Sub g_object_unref Lib "libgobject-2.0" (obj As Ptr)
Const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION = 600
Dim screen As Ptr = gdk_screen_get_default()
Dim provider As Ptr = gtk_css_provider_new()
If provider = Nil Then Break
Dim data As String = "GtkWidget:not(GtkMenuItem) { padding-left: 1; padding-right: 1; padding-top: 1; padding-bottom: 1;}"
If gtk_css_provider_load_from_data(provider, data, Data.Len, Nil) Then
gtk_style_context_add_provider_for_screen(screen, provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION)
End If
g_object_unref(provider)
#Endif
Also refer to Examples/Platform-Specific/Linux/GTK3 Themes/LinuxLockedPaddingExample
Have Your App Load and Use a Specific Theme
If you would like your app to use a specific theme so that your layout works exactly as you want it, you can bundle a theme and load it when your app starts. Your app will use this loaded theme regardless of what the user has selected as a theme for the distribution. You load the theme from the App.Open event handler like this:
Declare Function gdk_screen_get_default Lib "libgdk-3" () As Ptr
Declare Function gtk_css_provider_new Lib "libgtk-3" () As Ptr
Declare Function gtk_css_provider_load_from_path Lib "libgtk-3" _
(provider As Ptr, path As CString, error As Ptr) As Boolean
Declare Sub gtk_style_context_add_provider_for_screen Lib "libgtk-3" _
(screen As Ptr, provider As Ptr, priority As UInt32)
Declare Sub g_object_unref Lib "libgobject-2.0" (obj As Ptr)
Const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION = 600
Dim screen As Ptr = gdk_screen_get_default()
Dim provider As Ptr = gtk_css_provider_new()
If provider = Nil Then Break
// Load the theme
Dim themePath As FolderItem
themePath = App.ExecutableFile.Parent.Parent.Child("mintxtheme").Child("gtk.css")
If gtk_css_provider_load_from_path(provider, themePath.NativePath, Nil) Then
gtk_style_context_add_provider_for_screen(screen, provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION)
End If
g_object_unref(provider)
#Endif
In the above code the "mintxtheme" that is used is loaded from a folder that is placed alongside the app's folder, but you can choose to load it from anywhere and may want to bundle it in your app's Resouces folder. You can download Mint themes from here: Mint Themes Download
Also refer to Examples/Platform-Specific/Linux/GTK3 Themes/LinuxLoadBuiltinTheme
Analyzing Theme Properties
The above code should be sufficient for most people's apps. But if you require even more control of themes and how they render widgets you will have to dig into Linux more. The GTK+ Inspector can be a great tool for this as it lets you see property and widget information in real time.
On some distributions you may need to install the "libgtk-3-dev" package before GTK+ Inspector can be enabled.
You may also find it helpful to review the GtkCssProvider documentation.
modGtk3
The Xojo community has created a project (download modGTK3) that contains all the required Declares and Styles for theming. If you intend to use it in your own projects, have a look at where the global theme is set, and where/how the Control tweaks are set:
- App.Open -> modGTK3.InitGlobalGTK3Style()
- Control.Open -> me.InitGTK3Control()
Note: modGTK3 extends InitGTK3Control for Controls. In this example project, it's called from Control Subclasses. Subclassing your Controls is highly recommended anyway, as you get a single place for tweaks and workarounds for different XojoVersions or BuildTargets.
Refer to the original Xojo forum conversation for more information.