views:

48

answers:

3

I am writing a GTK+ application in C (though the principle here is widely applicable) which contains a GtkComboBox. The GtkComboBox is part of a larger structure returned by another function and packed into the main window.

I don't see how I can get the value of what is selected in the GtkComboBox other than by setting a global variable from its callback function. Or is there still some way of referring to the GtkComboBox later in the program, outside of the function which declared it?

Or should I not be declaring it inside a function (other than main( )) in the first place?

+1  A: 

If the function that declares a stack variable in C has returned, that variable is no more. If you need GtkComboBox (or other object) to persist, you have a few options:

  • Use malloc to allocate space for it and pass around a pointer (which must be freed when you no longer need it).
  • Use a global variable
  • Don't use callbacks and declare it in an outer function and pass it around.

I would probably go with the malloc/pass around a pointer approach, but can't be sure without more knowledge of your situation.

Nathon
I think it's basically that, but the malloc( ) kind of confuses me. The GtkComboBox is declared only as a pointer (i.e. GtkWidget *combo_box, then later on combo_box = gtk_combo_box_new(...)) Should I be using malloc( ) here in order to see it later, or might GTK+ be handling all this for me?
tsv
Ah, this is where my not knowing from GTK comes in. If the combo box is already passed around as a pointer, you just have to either make your pointer global or pass the pointer around to your functions. No need to `malloc` a pointer to the pointer. If you can't pass the pointer (because of function parameter limitations) you'll have to go the global route.
Nathon
That sounds right to me, thanks a lot.
tsv
A: 

I'm not sure I clearly understand what you are trying to achieve. However, one approach to create a persistent variable, without using a global is to use a static variable. For example based on my probable misunderstanding of what you want you could do the following:

GtkComboBox *getComboBox()
{
  static GtkComboBox gcb = NULL;

  if (NULL != gcb)
    return gcb;

  // Initialise gcb
  return gcb;
}
torak
+1  A: 

I see you've already accepted an answer, but since GTK has an elegant mechanism for dealing with all this, I feel compelled to write another one anyway.

gtk_combo_box_new() uses malloc() internally to allocate the pointer it returns. (Well, strictly speaking, that's not true, but let's not be confusing here.) So your GtkComboBox will be alive until its parent widget is destroyed, or it is removed from its parent widget, or until you destroy it manually (with gtk_widget_destroy(), not free()). So, the widget lives on in the background, but the problem is having a pointer to it available where you need it.

Usually you will want to manipulate the combo box in response to a signal, since most of the work in a GTK program is done in signal handlers. If it's one of the combo box's own signals, like the changed signal, then the callback will be a function like this:

void on_combo_box_changed(GtkComboBox *combo_box, gpointer user_data)

and combo_box will be the pointer to your combo box.

If you want to manipulate the combo box in response to another widget's signal, let's say a button's clicked signal, then the callback will be a function like this:

void on_button_clicked(GtkButton *button, gpointer user_data)

As you can see, there is no pointer to the combo box here. Here is where the user_data parameter comes in. I assume you are connecting your signals in the function where you construct your widgets and pack them into your main window. (If you're not, you should be.) In that function, you will have pointers to both the button and the combo box available. Connect your signal like this...

g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), combo_box);

...passing combo_box as the user_data parameter to g_signal_connect(). Then the pointer to the combo box will be passed to the on_button_clicked() callback, disguised as the user_data parameter. You can then access it like this:

void on_button_clicked(GtkButton *button, gpointer user_data)
{
    GtkComboBox *combo_box = GTK_COMBO_BOX(user_data);
    gint item = gtk_combo_box_get_active(combo_box);
    etc.

or, due to the way the call stack works in C, even by declaring your callback like this:

void on_button_clicked(GtkButton *button, GtkComboBox *combo_box)

...although then you lose the type-checking cast that GTK_COMBO_BOX() gives you.

ptomato