Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crossplatform threading and GTK#, not working (properly)?

I'm trying to make a crossplatform C# application using C#, mono/GTK# on Linux and .NET/GTK# on Windows, however the startup sequence seems to need to be slightly different under the two platforms:

Under Linux:

public static void Main (string[] args)
{
    Gdk.Threads.Init ();
    // etc...

Under Windows:

public static void Main (string[] args)
{
    Glib.Thread.Init ();
    Gdk.Threads.Init ();
    // etc...

Both require it to be done that way: Windows complains about g_thread_init() not being called with the linux code, and linux complains about it already being called with the Windows code. Other than this, it all works wonderfully.

My first attempt at a "solution" looked like:

public static void Main (string[] args)
{
    try {
        Gdk.Threads.Init ();
    } catch (Exception) {
        GLib.Thread.Init ();
        Gdk.Threads.Init ();
    }
    // etc...

But even this messy solution doesn't work; the error is coming from GTK+, unmanaged code, so it can't be caught. Does anyone have any bright ideas about the cause of the problem, and how to fix it? Or, failing that, have bright ideas on how to detect which one should be called at runtime?

like image 396
Matthew Scharley Avatar asked Feb 03 '09 01:02

Matthew Scharley


2 Answers

Gtk+ on Win32 does not properly support threading. You need to do all your GUI calls from the same thread as you did called Gtk.Main().

It's not actually as bad as it sounds. There's a trick you can use to dispatch functions to the main thread. Just use GLib.Idle.Add() from any thread and the function will be called shortly in the same thread as the main loop is running in. Just remember to return false in the idle handler function, or it will go on running forever.

If you follow and use the above techniques you don't even need to call Gdk.Threads.Init() at all.

like image 105
Johan Dahlin Avatar answered Sep 22 '22 16:09

Johan Dahlin


I'm not sure if this works on Mono, but you can use the Environment class to determine which OS the program is running on.

public static void Main (string[] args)
{
    PlatformID platform = Environment.OSVersion.Platform;
    if (platform == PlatformID.Win32NT ||
        platform == PlatformID.Win32S ||
        platform == PlatformID.Win32Windows)
        Glib.Thread.Init();
    else if (platform != PlatformID.Unix)
        throw new NotSupportedException("The program is not supported on this platform");

    Gdk.Threads.Init();
    // etc...

The PlatformID enum contains more than just Windows and Unix however, so you should check for other values.

like image 45
Cameron MacFarland Avatar answered Sep 19 '22 16:09

Cameron MacFarland