GTK UI Looks different when running from bundle an

2019-06-14 11:45发布

问题:

I have C# App using Mono framework and GTK for UI.When i run it from Xamarin Studio it looks like this

I have bundled Mono and GTK into a standalone bundle.When running from it it looks different.

Which one looks more native to the OSX Platform? If its the first one,then how can i get the same look and feel in the bundled App.

回答1:

GTK 2 Theming Options:

  • Use the default system theme
  • Per user theming via ~/.gtkrc
  • Per application theming via GTK api
  • Per application theming via environment var

GTK 2 Theming:

Theming is handled in GTK 2 via resource files with the master normally named 'gtkrc'. These resources files can be standalone, include other resources files and reference external images (icons), etc.... The internals of gtkrc-based files are out-of-scope here, but there are plenty of references on the web for GTK 2.0 resources/theming.

Mono w/ GTK 2:

Mono on OS-X installs a default GTK2 theme (gtkrc) and few alternative themes:

Location : /Library/Frameworks/Mono.framework/Versions/4.2.1

find . -name "gtkrc"
./etc/gtk-2.0/gtkrc
./share/themes/bubble/gtk-2.0/gtkrc
./share/themes/Clearlooks/gtk-2.0/gtkrc
./share/themes/Mac/gtk-2.0-key/gtkrc
./share/themes/Quartz/gtk-2.0/gtkrc
./share/themes/Xamarin/gtk-2.0/gtkrc

The one located in the <Mono/Version>/etc/gtk-2.0 is the default (Tango style) while one of the alternatives is 'Xamarin' and is the one that is used to stylize Xamarin Studio (internally named "Mac Theme for Xamarian").

As for controlling which theme is applied to your application, you can allow the user to control it via $HOME directory based .gtkrc files (IMHO: how many users really know how to do that or would even what to and the support nightmares of 'expert' end-users tweaking the UI, I prefer locking the UIX experience to something uniform to all users, but, again, that is just my opition).

You are supposed to be able to set environment var GTK2_RC_FILES in your app startup script, but I never had any luck with this.

Note: The env. var. GTK_THEME does work in GTK3 (but Mono is GTK2 bound)

  • Ref: Very good Stack exchange related to this @ https://unix.stackexchange.com/questions/14129/gtk-enable-set-dark-theme-on-a-per-application-basis
  • Ref: Another good Q/A : GTK+ application specific skin possible?

Application theming via GTK api:

With your application you can assign GTK to use one of the Mono installed themes or one that your application provides.

BEFORE the Gtk.Application.Init() you can do the following to assign the gtkrc file:

Gtk.Rc.AddDefaultFile ({gtkrcFile}); 
Gtk.Rc.Parse ({gtkrcFile}); 

If you have your own theme, bundle the files (gtkrc, other included gtkrc files, icons, images, etc...) inside your .app. Normally these would be bundled inside the Contents\Resource directory and use the above code to assign thegtkrc` that is in your bundle.

For standalone exe's I have also have used an embedded gtkrc file and extract it to a tmp file a runtime:

using System;
using System.Reflection;
using System.IO;
using Gtk;

namespace themes
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            InitGlobalResourceFile ();
            Application.Init ();
            MainWindow win = new MainWindow ();
            win.Show ();
            Application.Run ();
        }

        static void InitGlobalResourceFile ()
        { 
            String gtkResouceFile;

            Assembly myAssembly = Assembly.GetExecutingAssembly ();
            string[] names = myAssembly.GetManifestResourceNames ();
            foreach (string name in names) {
                Console.WriteLine (name);
                if (name.Contains ("GtkThemeResource.rc")) {
                    gtkResouceFile = name;
                    break;
                }
                Console.WriteLine ("Gtk Theme Resource not found in manifest");
            }

            var tmpFile = Path.GetTempFileName ();
            var stream = myAssembly.GetManifestResourceStream (gtkResouceFile);
            string gtkrc;
            using (StreamReader reader = new StreamReader (stream)) {
                gtkrc = reader.ReadToEnd ();
            }
            using (StreamWriter outputFile = new StreamWriter (tmpFile)) {
                outputFile.WriteLine (gtkrc);
            }
            Rc.AddDefaultFile (tmpFile); 
            Rc.Parse (tmpFile); 
        }

    }
}
  • FYI: The Xamarin GTK2/OS-X theme is maintained here (https://github.com/mono/xamarin-gtk-theme)