Re: Removing widgets in the main loop from another thread



On Thu, 26 Feb 2009 17:20:04 +0100
Robert Gründler <doobre gmail com> wrote:
> > Because your arrangement doesn't on the face of it make sense, there
> > is probably more to it than at first appears.  I therefore just make
> > three points which may or may not be relevant to your question:
> >
> > 1. You cannot (without great difficulty) have different Gtk::Window
> > objects created and/or destroyed in different threads.  If it is
> > possible at all, you will need to use the GDK global thread lock,
> > which makes the use of Glib::Dispatcher redundant.  You may also
> > need to have two main loop objects, one for each thread (from your
> > description it is impossible to say).
>
> Well, i'll try to describe a little clearer what i'd like to
> accomplish:
> 
> I'm trying to write an user interface extension to an existing 
> application (pure data) . The application
> itself is written in tcl/tk. It's native interface is very simple and 
> basically consists of objects on a canvas
> which can be connected via wires to interact wich each other. I would 
> see it as an advantage to
> be able to write UI widgets using a more modern framework like gtkmm
> for the application.
> 
> My approach to this is the following:
> 
> 1. The central object is a native tcl/tk object which can be placed
> on the applications tcl/tk canvas. Upon it's creation,
> it creates a singleton ProxyClass which holds the Gtk::Window and
> runs it in a separate thread, so the 2 guis can run in paralell.
> 
> 2. All widgets that can be placed into my Gtk::Window, will also be 
> created by a native tcl/tk object placed on the applications canvas.
> When the object is created, it gets the singleton instance of the
> proxy class to the Gtk:Window, creates the native Gtk::Widget and
> passes it to the addWidget(Gtk::Widget *widget) method in the
> Gtk::Window using the glib::dispatcher.
> 
> When the tcl/tk object - holding a pointer to the gtk::widget inside
> the main window - is destroyed, it again calls the main window
> using a glib dispatcher to remove the widget from the main window.
> 
> As i'm not that familiar with inter-thread communication, i'd be glad 
> for any feedback if the this approach seems usable, or
> probably a terrible design choice over all...

Well, subject to my caveat at the end that I do not believe that you
can have two X11 client threads in the same process (but I suspect this
is not what you meant), the design looks OK were GTK+ to support it,
but I doubt that it does.

I have never tried initialising and running GTK+ in other than the main
(initial) program thread main loop, and I think you are asking for
trouble if you try to do it differently.  However, you could try a test
program which first initialises glib (by calling Glib::init() and
Glib::thread_init()), then creates a new thread and in the new thread
creates the singleton Gtk::Main object, creates a test interface with a
Gtk::Window object and then starts the main loop with
Gtk::Main::run() in the new thread.  It might work, but I doubt it.

If it doesn't, to operate your design you would need to run GTK+ in the
initial program thread and if you need to run TCL/Tk in a separate
thread (about which I know very little), run TCL/Tk rather then GTK+ in
the new thread. (Incidentally if your program uses a scripted language
anyway, then why not carry on in that direction and use PyGTK?)

In either case, you are also going to run into trouble creating a GTK+
widget in a different thread from the one in which the GTK+ main
loop is running.  Possibly you could do it with the GDK global
thread lock (about which see
http://library.gnome.org/devel/gdk/stable/gdk-Threads.html ) but I
suspect that won't work either.  It definitely won't work on Windows
(the GDK global lock only works on Unix-like operating systems).

I would instead avoid any use of the GDK global lock, and if you
are sure you need a multi-threaded solution, after doing what you need
to do in TCL/Tk, use Glib::Dispatcher to instruct the main program
thread to create whatever new GTK+ widgets that are required and to
insert them in the Gtk::Window object it maintains.  In other words,
call all GTK+ functions in the main program GUI thread. (And likewise
all X11 client calls of any kind.)

If you are then concerned that the TCL/Tk thread may cause
Glib::Dispatcher to call a method in the GTK+ main thread after your
Gtk::Window object ceases to exist, consider creating the TCL/Tk thread
with the joinable attribute and ensure the TCL/Tk thread terminates
before the Glib::Window object goes out of scope with
Gtk::Thread::join(), or if that doesn't suit your design you can
synchronise in whatever way you want with condition variables (see
Glib::Mutex and Glib::Cond).  If you know pthreads, glib condition
variables work in the same way as pthread condition variables.  If in
addition the Gtk::Window object remains in scope for the whole time
that the main loop is running (which would be the case if it is the
only Gtk::Window object you create) then you should be bullet proof.

However, you shouldn't need explicitly to remove the widgets contained
in the Gtk::Window object on program close-down anyway.  All you need to
do is to have the call to Gtk::Main::run() return, with
Gtk::Main::quit() (via eg another Glib::Dispatcher object).

Note also (because your initial query appeared to assume otherwise) that
the slot method executed by a Glib::Dispatcher object will execute in
the thread in which the Dispatcher object is created, which must also be
the thread in which GTK+ is initialised, which if you do as I suggest
will be the initial thread.

I should also give some thought to whether you can get TCL/Tk to
do what you want without establishing its own program loop (and so its
own thread).  If you can avoid any multi-threading that would be
excellent.  However, as I say I know very little about TCL/Tk.

One last point.  You refer to the objective of your proposal being "so
the 2 guis can run in parallel". I do not believe that you can have
two GUI threads accessing X11 in the same process and I suspect you
cannot do so in windows either. However, I suspect that that is not
what you meant - but if you do try to display some TCL/Tk GUI entities
in one thread and some GTK+ entities in another, I don't think that it
will work.

Chris



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]