GTK+: issues passing data to call_back functions - c

I am building a GTK program that does the following: A button gets clicked by the user, it retrieves information from the server, then creates new buttons that the user can click on. I technically have a signal in main, and in that call_back I have multiple signals (for each of the created buttons).
I would like to pass data to this new button, but here it becomes icky. If I create a struct inside my first button I will later crash in the buttons that are generated because the struct is locally defined on the stack, and so it gets deleted.
I cannot create a global variable as each of the created button need different values. I basically would like to pass a struct with multiple fields when my initial button (callback method) gets called, but each of this struct is different.
The only way I can think of is to allocate it on the heap, but it becomes a bit of overhead to know when to free it.
Is there a good way around this please, or am I following wrong design choices for GTK by having a signal handler create a new signal handler please?
Thank you very much.
EDIT:
I am still crashing, and I am very confused why.
This is the code for the main button:
struct buttonData* data = (struct buttonData*) malloc(sizeof(struct buttonData));
data->IP = strdup(newDevice.IP.c_str()); // Added strdup
data->port = atoi(newDevice.port.c_str());
g_signal_connect(G_OBJECT(deviceButton), "button_press_event", G_CALLBACK(showDeviceAndConnect), (gpointer) data);
Code for the button that is generated:
static void showDeviceAndConnect(GtkWidget * deviceButton, gpointer data) {
struct buttonData* toConnect = (struct buttonData *) data;
fprintf(stderr, "IP: %s, PORT: %d\n", toConnect->IP, toConnect->port); //SIGSEGV
}
I am not sure why. Any help would be very appreciated.

The reason for the crash is the signature of your callback. "button-press-event" expects the callback with the signature gboolean foo(GtkWidget* , GdkEvent*, gpointer). As you callback has signature of void foo (GtkWidget * , gpointer ) the second parameter which you are getting in the callback function is not gpointer data which used when registering callback but GdkEvent pointer. Thus when you are dereferencing GdkEvent pointer (thinking it as the data you had passed) you are seeing the crash. So to fix this issue change static void showDeviceAndConnect(GtkWidget * deviceButton, gpointer data) to static void showDeviceAndConnect(GtkWidget * deviceButton, GdkEvent *ev, gpointer data).
Alternatively, as you are using only data in showDeviceAndConnect function you can using g_signal_connect_swapped which will pass the data as the first parameter; so if you use g_signal_connect_swapped your function static void showDeviceAndConnect(GtkWidget * deviceButton, gpointer data) can be static void showDeviceAndConnect(gpointer data).
Hope this helps!

The only way I can think of is to allocate it on the heap, but it becomes a bit of overhead to know when to free it.
That is the way to do it. Allocate the structure on the heap and pass a pointer to it as the callback data. Note that even while it does not apply to you since you are dynamically generating those buttons, using global variables is a poor choice as a solution.

Related

How do i organize a GTK program?

I have a function called create_interface. In that function is a signal handler for the Open menu button (the menu is created in create_interface). I want to pass the window widget and also pass along the tree view widget, because when you open a file an entry in the tree view is supposed to show up. I tried passing them as a struct, but, although its works, GTK generates some error messages.
// This is global.
struct everything
{
GtkWidget *window;
GtkWidget *tree_view;
}
GtkWidget *create_interface (void)
{
struct everything instance;
struct everything *widgets;
widgets = &instance;
...code here...
g_signal_connect(file_mi_open_file_dialog, "clicked", G_CALLBACK(open_file_dialog), widgets);
The function open_file_dialog looks like this:
void open_file_dialog (GtkWidget *wid, gpointer data)
{
struct everything *sample_name = data;
...rest of code here...
I was wondering if there was another way of organizing a program so you do not have to have global variables.
I tried passing them as a struct, but, although its works, GTK generates some error messages.
The problem is that you're trying to use a stack-allocated struct, which becomes invalid after the create_interface() function is done, while you would normally expect these values to still be valid at a later moment in time (for example, when open_file_dialog() is called.
I was wondering if there was another way of organizing a program so you do not have to have global variables.
One possible solution is indeed to use a global variable: this will be valid throughout the lifetime of the program, but it has major drawbacks: it doesn't scale if you have to do that for each callback, and it's architecturally not really clean.
Another solution is to allocate your "closure" (i.e. the variables you want to capture at the moment you create your callback) on the heap, and to free it when you're done with it. GLib even helps you with this by a call g_signal_connect_data() (or g_signal_connect_object() if you save your fields in a GObject)
// Technically you don't need the typedef
typedef struct _ClickedClosure {
GtkWidget *window;
GtkWidget *treeview;
} ClickedClosure;
GtkWidget *create_interface (void)
{
// Note that the g_new0 allocates on the heap instead of using the stack
ClickedClosure *closure = g_new0 (ClickedClosure, 1);
// code here to initialize your window/treeview ...
// put the widgets in the closure
closure->window = my_window;
closure->treeview = treeview;
// Connect to the signal
g_signal_connect_data(file_mi_open_file_dialog, "clicked",
G_CALLBACK(open_file_dialog), closure, g_free, 0);
}
void open_file_dialog (GtkWidget *wid, gpointer data)
{
// Since this was allocated on the heap, this is still valid
ClickedClosure *sample_name = data;
// code handling here ...
}
Very often, what developers using GTK do, is that they're using their own GObject classes/objects already, which they can then use with g_signal_connect_object(), or by manually freeing it with g_object_unref() later. Using GObject then also allows you to to a runtime-typecheck cast, which makes sure your closure has the right type.

GTK/C sharing data and variables between functions

The problem is: what's the best way to share data between functions, but specifically in GTK/C application? The best means the most 'proper', the fastest in run and/or absorbing as low CPU power as possible.
I'm asking because I have to code some app with GUI under linux, but I'm rather a microcontroller programmer (and maybe it's hard to me to think like big computer). In small 8-bit MCU's world, where code is in plain C, globals are the fastest and commonly used way to share data between functions.
But I guess that in much more complicated app running under operating system there must be other 'special' way to do that. To this point I noticed that GTK (GDK, Glib etc.) offer many special functions and build-in mechanisms to makes programmer's life easiest, so I suppose it should be something elegant for sharing variables between functions.
Searching through the net I've seen different solutions:
- classes with private variables and methods to get/set them - but my app is coded in C, not C++, I'd like to avoid using object programming,
- global structs or even one big global struct with many members,
- good plain globals,
- GtkClipboard, but I think it's for different purposes.
What I want to do is simply to set some variable 'A' in one callback function, set that variable once again in second callback, and then in another callback do something depending upon value of variable 'A', like this:
callback_func1{
//...
A = some_func();
//...
}
callback_func2{
//...
A = another_func();
//...
}
callback_func3{
//...
if(A>threshold) do_something();
else do_nothing();
//...
}
You're right to be wary of globals, especially if you only want to allow certain functions to be modifying them.
Assuming you're retaining more data than just A (which for simplicity I've defined as int), you can set up your structure in the familiar way
typedef struct t_MYCBSD
{
int A;
// other members
} MYCBSD; // callback struct data
including other data members as necessary. (I've included the t_MYCBSD in case there is some self-referencing).
You can then implement your callback functions as follows:
void callback_func1( GtkWidget *widget, gpointer user_data )
{
MYCBSD *data = user_data;
data->A = some_func();
}
void callback_func2( GtkWidget *widget, gpointer user_data )
{
MYCBSD *data = user_data;
data->A = another_func();
}
void callback_func3( GtkWidget *widget, gpointer user_data )
{
MYCBSD *data = user_data;
if( data->A > threshold ) do_something();
else do_nothing();
}
Obviously, some_func(), another_func(), threshold, do_something() and do_nothing() are valid in this context.
NOTE: the data pointer to your struct makes the syntax a little more clear. You can also use:
((MYCBSD *) user_data)->A = some_func();
In any case, you usually set up your callbacks when creating your widgets. In the following (heavily culled, non-GtkBuilder) code, MYCBSD mydata will be locally scoped. I'm assuming the callbacks will be set for some buttons with the "clicked" event.
int main( int argc, char* argv[] )
{
MYCBSD mydata;
// Below-referenced widgets
GtkWidget *mywidget1, *mywidget2, *mywidget3;
// ... other widgets and variables
mydata.A = 0; // Optionally set an initial value to A
// Standard init via gtk_init( &argc, &argv );
// ... Create the toplevel and a container of some kind
// Create mywidget1,2,3 (as buttons, for example)
mywidget1 = gtk_button_new_with_label ("widget1");
mywidget2 = gtk_button_new_with_label ("widget2");
mywidget1 = gtk_button_new_with_label ("widget3");
g_signal_connect( mywidget1, "clicked", G_CALLBACK(callback_func1), &mydata );
g_signal_connect( mywidget2, "clicked", G_CALLBACK(callback_func2), &mydata );
g_signal_connect( mywidget3, "clicked", G_CALLBACK(callback_func3), &mydata );
// ... Attach those widgets to container
// ... and show all
// Run the app in a standard way via gtk_main();
return 0;
}
The important lines here are:
g_signal_connect( mywidget1, "clicked", G_CALLBACK(callback_func1), &mydata );
g_signal_connect( mywidget2, "clicked", G_CALLBACK(callback_func2), &mydata );
g_signal_connect( mywidget3, "clicked", G_CALLBACK(callback_func3), &mydata );
where the last parameter passes your data to the callback functions.
If you're only looking to share a single value, A, you can pass that in a similar way without the need of a struct.
If you want to use globals, just use globals. And, regardless of what the world says, nobody died because used globals.
Globals are avoided because make maintenance hard on big programs and, from your description, this just does not seem to be the case.
On the sharing side, GTK+ programs are usually not parallel, so you can freely access globals in RW without problems. And also when tasks are used, it is best practice to put all the GTK+ calls on the same task: you are still allowed to access globals in RW from the same task.

passing multiple values using GTK_SIGNAL_FUNC

I'm trying to pass multiple values to a function when gtk_button click event invoke. The value are type of struct, int and gtk_image. I have a set of gtk images which attached to a table. The code fraction is as below,
`
GtkWidget *coin[6][7];
....
for(i=0;i<6;i++){
for(j=0;j<7;j++){
coin[i][j] = gtk_image_new_from_file("CoinC.png");
gtk_table_attach_defaults (GTK_TABLE(boardTable), coin[i][j], j, j+1, t, t+1);
}
t-=1;
}
`
I have created buttons to do some function and in the function involve some widgets set properties. One of it is I would like to change my image display as per code below
gtk_image_set_from_file(coin[slot][b->heights[0]],"CoinB.png");
The event fire code for button is as per below
gtk_signal_connect (GTK_OBJECT(button[0]), "clicked", GTK_SIGNAL_FUNC(dropCoin(b,0,coin)),NULL);
And the dropCoin function is as per below
gint dropCoin(board_type *b, gint slot, GtkWidget *coin[6][7]){
if(cp(b)==PLAYER_ONE){
makeMove(b,slot);
gtk_image_set_from_file(coin[slot][b->heights[0]-1],"CoinB.png");
}else{
makeMove(b, getReasonedMove(b));
gtk_image_set_from_file(coin[slot][b->heights[0]-1],"CoinA.png");
}
return 0;
}
Everytime I compile and run the program, the event straightway fired up without any clicking action being done. And when I tried to click back the same button, the event is not fired. I also received below error g_cclosure_new: assertion callback_func != NULL failed and
g_signal_connect_closure_by_id:assertion `closure != NULL' failed
Is there any other way to pass multiple values with widget to the event function.
What you're doing is using the return value from a call to dropCoin() as the function pointer.
You are not in any way telling GTK+ that it should call dropCoin() with the indicated parameters at a later time: the call happens right there before gtk_signal_connect() runs.
Signal callbacks only have a single user-settable parameter: the gpointer user_data. You need to find a way to associate all your desired data with that single pointer, typically by allocating some memory to hold the data and passing a pointer to that memory. In C, this is of course typically done by declaring a struct, and then allocating an instance of it.
Btw, your code is using an old version of GTK+, you should consider upgrading to 3.x.
You must give a function pointer to GTK_SIGNAL_FUNC. What you do is calling dropCoin and passing the resulting int to GTK_SIGNAL_FUNC.
Your call should look more like
gtk_signal_connect (GTK_OBJECT(button[0]), "clicked", GTK_SIGNAL_FUNC(dropCoin),NULL);
You can pass only one parameter, but you can wrap more than one value into a struct and pass that instead.
Update:
The function will be called with the argument you passed to gtk_signal_connect
struct send_Data {
board_type *b;
gint slot;
GtkWidget *coin;
};
struct send_Data arg;
gtk_signal_connect (GTK_OBJECT(button[0]), "clicked", GTK_SIGNAL_FUNC(dropCoin), &arg);
and dropCoin is defined as
void dropCoin(struct send_Data *arg){
...
// do something with arg
makeMove(arg->b, arg->slot);
foo(arg->b);
bar(arg->coin);
...
}

[C]Dynamic allocation memory of structure, related to GTK

I have following structure:
typedef struct
{
GtkWidget* PoziomaLinijka;
GtkWidget* PionowaLinijka;
GtkWidget* Label1;
GtkWidget* Label2;
gint x,y;
} StrukturaDrawing;
And i need to allocate it on the heap because later I have functions which uses that structure and I don't want to use global variables. So I allocate it like this:
StrukturaDrawing* Wsk;
Wsk = (StrukturaDrawing*)malloc(sizeof(StrukturaDrawing));
if (!Wsk)
{
printf("Error\n");
}
And it doesn't returning error and also works great with other functions, it works the way I wanted it to work so finally i wanted to free that memory and here is problem because in Debug Mode compilator bitches:
First-chance exception at 0x102d12b4 in GTK.exe: 0xC0000005: Access violation reading location 0xfffffffc.
Unhandled exception at 0x102d12b4 in GTK.exe: 0xC0000005: Access violation reading location 0xfffffffc.
I connect callback to my function, like that:
g_signal_connect(G_OBJECT(Okno), "destroy", G_CALLBACK(Wyjscie), Wsk);
Function which is suppose to free memory and close program:
void Wyjscie(GtkWindow* window, GdkEvent* event, StrukturaDrawing* data)
{
gtk_main_quit();
free(data);
data = NULL;
}
Any help really appreciated.
Well durning debugging data structure have following values:
The first one has: PoziomaLinijka CXX0017: Error: symbol "" not found
And later the whole rest have: PionowaLinijka CXX0030: Error: expression cannot be evaluated
Oh: I am the oen who started question, sorry about confusing with nicknames.
The "destroy" signal has a different signature for its callback than your Wyjscie function. Maybe you rather want the "destroy-event" of GtkWidget, see docshere
If you want the "destroy" event of GtkObject, see here, you have to change your callback to
void Wyjscie(GtkObject* window,StrukturaDrawing* data)
{
gtk_main_quit();
free(data);
}

Function pointers and callbacks in C

I have started to review callbacks. I found this link on SO:
What is a "callback" in C and how are they implemented? It has a good example of callback which is very similar to what we use at work. However, I have tried to get it to work, but I have many errors.
#include <stdio.h>
/* Is the actual function pointer? */
typedef void (*event_cb_t)(const struct event *evt, void *user_data);
struct event_cb
{
event_cb_t cb;
void *data;
};
int event_cb_register(event_ct_t cb, void *user_data);
static void my_event_cb(const struct event *evt, void *data)
{
/* do some stuff */
}
int main(void)
{
event_cb_register(my_event_cb, &my_custom_data);
struct event_cb *callback;
callback->cb(event, callback->data);
return 0;
}
I know that callbacks use function pointers to store an address of a function. But there are a few things that I find I don't understand:
What is meant by "registering the callback" and "event dispatcher"?
This code compiles and runs under GCC with -Wall.
#include <stdio.h>
struct event_cb;
typedef void (*event_cb_t)(const struct event_cb *evt, void *user_data);
struct event_cb
{
event_cb_t cb;
void *data;
};
static struct event_cb saved = { 0, 0 };
void event_cb_register(event_cb_t cb, void *user_data)
{
saved.cb = cb;
saved.data = user_data;
}
static void my_event_cb(const struct event_cb *evt, void *data)
{
printf("in %s\n", __func__);
printf("data1: %s\n", (const char *)data);
printf("data2: %s\n", (const char *)evt->data);
}
int main(void)
{
char my_custom_data[40] = "Hello!";
event_cb_register(my_event_cb, my_custom_data);
saved.cb(&saved, saved.data);
return 0;
}
You probably need to review whether the call back function gets the whole struct event_cb or not - usually, you'd just pass the data because, as demonstrated, otherwise you have two sources of the same information (and a spare copy of the pointer to the function that you're in). There is a lot of cleanup that can be done on this - but it does work.
A question in the comments asks: Is this a good example of a callback?
Succinctly, no - but in part because there isn't sufficient infrastructure here.
In a sense, you can think of the comparison function passed to the qsort() or bsearch() functions as a callback. It is a pointer to a function that is passed into the generic function that does what the generic function cannot do for itself.
Another example of a callback is a signal handler function. You tell the system to call your function when the event - a signal - occurs. You set up the mechanisms ahead of time so that when the system needs to call a function, it knows which function to call.
The example code is attempting to provide a more elaborate mechanism - a callback with a context. In C++, this would perhaps be a functor.
Some of the code I work with has very fussy requirements about memory management - when used in a particular context. So, for testing, I use malloc() et al, but in production, I have to set the memory allocators to the specialized allocators. Then I provide a function call in the package so that the fussy code can override the default memory allocators with its own surrogate versions - and provided the surrogates work OK, the code will behave as before. Those are a form of callback - again, a form that does not need much (or anything) in the way of user context data.
Windowing systems have event handlers (callbacks) that are registered and that the GUI main event loop will call when events occur. Those usually need user context as well as the event-specific information provided by the GUI system.
What is meant by "registering the callback" and "event dispatcher"?
"registering the callback" is the act of telling the underlying system which precise function to call, and (optionally) with which parameters, and possibly also for which particular class of events that callback should be invoked.
The "event dispatcher" receives events from the O/S (or GUI, etc), and actually invokes the callbacks, by looking in the list of registered callbacks to see which are interested in that event.
Without the compiler output it's hard, but I can see a few problems;
int event_cb_register(event_ct_t cb, void *user_data);
Should be
int event_cb_register(event_cb_t cb, void *user_data);
The my_custom_data variable does not exist when it's used here;
event_cb_register(my_event_cb, &my_custom_data);
This pointer is never initialized;
struct event_cb *callback;
And in;
callback->cb(event, callback->data);
You cannot pass the name of a type ('event') to a function, you must pass an instance of that type.
int event_cb_register(event_ct_t cb, void *user_data);
What is that type event_ct_t? Do you mean event_cb_t?
struct event_cb *callback;
Creates an uninitialized pointer to a structure event_cb. Note mostly this points to garbage.
callback->cb(event, callback->data);
You are trying to call garbage. You need initialization:
struct event_cb callback;
callback.cb = my_event_cb;
callback.data = 42;
or some such stuff.
Registering a callback means that you are specifying which function should be called when the event of interest occurs. Basically you are setting the function pointer when registering a callback.
You created a pointer of the struct you declared, but it does not point to anything:
struct event_cb *callback;
You should just create a type of your struct:
struct event_cb callback;
and then pass its address to the functions.

Resources