Passing an array to a function - Different values - Segfault - c

I have the following code:
gpointer w[3];
GtkWidget *menu_item = gtk_menu_item_new();
w[0] = menu_item;
menu_item = gtk_menu_item_new();
w[1] = menu_item;
GtkTextBuffer *buffer = gtk_text_buffer_new(NULL);
w[2] = buffer;
This is all good till now. Let's now connect a signal:
g_signal_connect(w[0], "activate", G_CALLBACK(runner), w);
runner function is declared as:
void runner(gpointer root, gpointer w[]);
Testing the values of w array before entering runner and while in it shows that they (the values) are different. I need them to be the same. How can I accomplish that, and why they aren't identical? Also, segfault occurs.
I created a small program that is bare bones of the original one and that is supposed to recreate the conditions such that the problem occurs. Oddly enough, it runs fine.
#include <gtk/gtk.h>
void carry(gpointer root, gpointer a[])
{
g_print("\n");
g_print("%d\n", root);
g_print("%d\n", a[0]);
g_print("%d\n", a[1]);
g_print("%d\n", a[2]);
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *menu_item;
GtkTextBuffer *buffer;
gpointer abc[3];
menu_item = gtk_menu_item_new();
abc[0] = menu_item;
g_print("%d\t%d\n", menu_item, abc[0]);
menu_item = gtk_menu_item_new();
abc[1] = menu_item;
g_print("%d\t%d\n", menu_item, abc[1]);
buffer = gtk_text_buffer_new(NULL);
abc[2] = buffer;
g_print("%d\t%d\n", buffer, abc[2]);
g_signal_connect(abc[2], "modified-changed", G_CALLBACK(carry), abc);
gtk_text_buffer_set_modified(abc[2], TRUE);
gtk_main();
return 0;
}
Which means that something else is problematic. I'll try something else now, like commenting lines and leaving only the relevant ones.
I didn't comment any lines yet, but I tried putting g_print in both the caller and the callee.
This is an output:
1162863440 1162863440
1162864736 1162864736
1163320992 1163320992
1162863440
-2
1162668992
973486176
The first three lines compare the original values with their copies in the array (in the sense of g_print("%d\t%d\n", menu_item, abc[0]); from the code above). As you can see, everything is assigned correctly. After a new line, we check those same values in the callee. root, the first parameter, always has the correct value. So there's no problem with that. abc[0] in the callee always has the value of -2. Seriously, every time I run the program it is -2. Other two (abc[1] and abc[2]) always have some garbage random values, but they change every time I run the program unlike abc[0].
I hope this will help in diagnosing and fixing the problem.

I tried passing both abc[0] and abc normally through a function (func(arg0, arg1, ...) instead of using g_signal_connect()) and there is no problem whatsoever.
This all can mean only one thing: g_signal_connect is messing with my values. It changes them for some unknown reason.
I guess I'll have to use a struct.

You're not supposed to use gpointers everywhere. A gpointer is a void *, so you're pretty much disabling all the type checking the compiler could do for you. Use GtkWidget * instead, and do proper casts using G_OBJECT(), GTK_TEXT_BUFFER() etc. macros.
You should also use typed callback arguments, as they appear in the documentation for each signal. For example for the activate signal:
void
user_function (GtkMenuItem *menuitem,
gpointer user_data)
And if you want to pass several items in the user-data field, pass a pointer or pointer to a structure instead of an array of pointers.
And if you have a segfault, well, just use a debugger to check where the problem is.

Related

How to use g_timeout_add()?

I'm having a problem using g_timeout_add. The function I'm calling is:
gboolean time_handler(GtkWidget *widget, GtkWidget *sum) {
if (widget == NULL) return FALSE;
gchar *display;
display = g_strdup_printf("%d", globalCounter); //convert num to str
gtk_label_set_text (GTK_LABEL(sum), display); //set label to "display"
g_free(display);
return TRUE;
}
main...
g_timeout_add(1000, (GSourceFunc) time_handler, (window, sum))
This is the warning I get:
gtkp2.c:66:60: warning: left-hand operand of comma expression has no effect [-Wunused-value]
g_timeout_add(1000, (GSourceFunc) time_handler, (window,sum));
While running the program I get a segmentation fault.
Let's take a look at the manual for g_timeout_add and GSourceFunc.
There we see:
gboolean
(*GSourceFunc) (gpointer user_data);
and
guint
g_timeout_add (guint interval,
GSourceFunc function,
gpointer data);
This means you have 2 basic errors in your code:
gboolean time_handler(GtkWidget *widget, GtkWidget *sum)
Your function does not follow the definition of GSourceFunc as it is only allowed to take 1 single parameter.
The compiler probably told you about this error becouse you have a cast to the proper type in your code. If you use the correct type, no cast should be required.
If GTK does not pass 2 parameters to your function (how should it know about your invalid function signature?) but you access that parameter and try to dereference it as a pointer, you invoke undefined behaviour which manifests as a segmentation fault in this case.
You try to pass 2 pointers via 1 parameter.
As the compiler told you, the left operand does not have any effect at all.
If you want to pass 2 values, you need to define a struct and pass a pointer to such a struct:
typedef struct{
GtkWidget *widget,
GtkWidget *sum
} myParameters;
gboolean time_handler(gpointer *par) {
myParams *params = par;
...
}
...
myParams param = {widget, sum};
g_timeout_add(1000, time_handler, &params);
// Make sure that lifetime of params does not end before your handler might be called! Local variables in main are OK for this.

Validating entry for GtkCellRendererText, g_signal_connect gpointer to struct contains garbage

I'm trying to come up with a general purpose library to remove a lot of the set up work for GTK, so that the GTK code can be hidden away neatly. Mostly it works okay. The problem I have is with providing a validator for an edited Cell. If I put the validation code into my tree_cell_edited function then it works fine - but I don't want to do that because that messes with my nicely reusable libraries (they won't be reusable anymore!)
What I tried to do is implement tree_cell_edited as follows:
void tree_cell_edited (GtkCellRendererText *cell, const gchar *path_string, const gchar *new_text, gpointer model_definition_ptr) {
struct model_definition *model_def = (struct model_definition*)model_definition_ptr;
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(model_def->tableview));
if (model_def->validator_ptr == NULL) {
g_print("Validator is null\n");
}
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
GtkTreeIter iter;
gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column_number"));
gtk_tree_model_get_iter (model, &iter, path);
char *upd_text=(char *)malloc( strlen(new_text) * 2 ); // need to malloc twice the size of the text to allow modification - need a better solution later
strcpy(upd_text, new_text);
if ( ( ((struct model_definition*)model_definition_ptr)->validator_ptr == NULL ) || (*model_def->validator_ptr)(cell, path_string, (char **) &upd_text, model) ) {
gtk_tree_store_set(GTK_TREE_STORE (model), &iter, column, upd_text, -1);
}
free(upd_text);
gtk_tree_path_free (path);
}
Which is set up as follows:
g_signal_connect (cell, "edited", G_CALLBACK (tree_cell_edited), &model_def);
The model_def struct is set up as:
typedef struct model_definition {
bool (*validator_ptr)();
GtkWidget *tableview;
} model_definition;
and
model_definition model_def;
model_def.validator_ptr = &valid_edit;
model_def.tableview = tableview;
where valid_edit is my validation function. When I try this with valid_edit set to NULL then Validator is NULL never gets printed. When I use this style of code I get invalid cast from 'GtkWindow' to 'GtkTreeView' errors some of the time but not all of the time - whereas if I do the more traditional passing of the GtkTreeModel in to tree_cell_edited it all works fine.
Whats the issue here? Do I not have complete freedom over what I pass into whatever function I call with g_signal_connect for an edited cell? Is there something embarrassing and obviously wrong with my code? Is there a better way of calling my validation routine, bearing in mind that I don't want it in my Gtk code (for reasons of reusability).
If it helps, this code needs to be usable on Linux, Windows and macOS - so if it's a clever but platform specific trick then it isn't going to work.

GTK2 C - how to pass 2D array of structures to callback function and change this array's values?

I'm writing an app (Battleships puzzle) in GTK+ in C. I have a structure shippart:
typedef enum {
water, single, top, bot, mid, left, right, waterU, shipU, unknown
} shiptype;
typedef struct {
GtkWidget *img;
shiptype type; //shiptype is typedef enum
shiptype hiddenType;
} shippart;
The whole map is two-dimensional array of shippart (shippart battlemap[10][10]) and I have it declared in my main(). I fill all these 3 fields, user clicks on a single part (1 of 100) of the map to mark it as water or as a ship part. When he wants to check if his guesses are correct, he should be able to click 'Check' which, if his guesses were correct, will change his water-marked parts as water, ship-marked parts as (more specified) ship parts and if he did something wrong, it will unmark it.
Everything is fine until the point of checking. It just doesn't work and I assume it's caused by something with passing this map array.
void buttonCheckHandler(GtkWidget *widget, gpointer user_data) {
//this is most likely wrong, I found it somewhere in the other question here
//but honestly I tried everything and it just doesn't work
shippart * (*map)[MAP_SIZE] = (shippart *(*)[MAP_SIZE])user_data;
//this part might be unnecessary
int i, j;
for(i = 0; i<MAP_SIZE; i++) {
for(j = 0; j<MAP_SIZE; j++) {
if(map[i][j]->type == waterU) {
if(map[i][j]->hiddenType == water) {
gtk_image_set_from_pixbuf(GTK_IMAGE(map[i][j]->img), shiptypes[0]);
map[i][j]->type = water;
}
else {
gtk_image_set_from_pixbuf(GTK_IMAGE(map[i][j]->img), shiptypes[9]);
map[i][j]->type = unknown;
}
continue;
}
//... very similar lines to these 11 above
}
}
}
void makeOverlay(shippart map[][MAP_SIZE], (...)) {
//...
g_signal_connect(G_OBJECT(btnCheck), "clicked", G_CALLBACK(buttonCheckHandler), &map);
//...
}
int main(int argc, char *argv[]) {
shippart battlemap[MAP_SIZE][MAP_SIZE];
fillMap(battlemap); //fills hiddenType's
makeUserMap(battlemap); //fills type's with 'unknown' and 2-4 fields with those from hiddenType
makeOverlay(battlemap, (...)); //almost everything with gtk
}
So my question is: how to correctly pass this map from makeOverlay() to buttonCheckHandler()? Is it even possible? I used to have shippart map[10][10] as global variable and it worked (my buttonCheckHandler was like this:)
void buttonCheckHandler(GtkWidget *widget, gpointer user_data) {
checkMap(); //without parameteres, because it changed global variable
//I tried same thing with checkMap(user_data); earlier but it didn't work
}
but my code was pretty horrible to read and undestand and now I messed it up. Can you help me?
There's a difference between a 2D array and an array of pointers (aka ragged 2D array).
When passing a 2D array, it decays to a pointer to the first element. You can access the data through the pointer by treating it as a 1D array, but you must calculate the index.
shippart * map = user_data;
...
map[i*MAP_SIZE+j].type;
//or
(map+i*MAP_SIZE+j)->type;
As for messing up your source when making big changes, you should use a version control system. One of the most widely available (and primitive) is RCS, which can work with single files, too. Whenever you make a change and get it to compile and run correctly, check-in the source. With RCS, it's
ci -l filename.c
The -l immediately extracts a new editable file after checking it in. Then if you make bad changes, you can revert to the previous checked-in version with
ls filename.c,v # <-- before deleting, make sure you actually have a checked-in file
rm filename.c
co -l filename.c

GTK+: issues passing data to call_back functions

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.

My g_thread_push is not working

I am trying to create a multi-thread, jpg rotation program but I am having problems getting g_thread to work.
int processUserRequest (UserRequest *uRequest,
char * const* argv, int argc, int optind){
struct RotationData CurData;
CurData.argv=argv;
CurData.argc=argc;
CurData.optind=optind;
CurData.uRequest=uRequest;
gpointer user_data = &CurData;
int transform = FALSE;
int max_files = argc - optind;
int i;
gpointer data=&i;
GThreadPool *pool;
if(!g_thread_supported())
g_thread_init(NULL);
pool = g_thread_pool_new(MultiThreadRotation,user_data, 5, TRUE, NULL);
for(i=0;i
{
g_thread_pool_push(pool, &data,NULL);
}
//g_thread_pool_free (pool, TRUE,TRUE);
//Create a montage file
transform = createMontageFile (uRequest);
return transform;
}
The function MultiThreadRotation is suppose to be called by g_thread_pool_push, but it is not being good once. Can anyone help, I am quite the novice.
Also, I thought about outputting the error from g_thread_pool_push, how would you output a GError *error message?
First off, in the code you pasted, there's a bug in the for statement.
Assuming that's fixed, here are a few remarks.
I'm not sure why this is failing, but you can get some indication from the GError's "message" member, which is a human-readable C string you can use with printf() or whatever you like. Unfortunately, you've set the GError arguments to NULL in the g_thread_*() calls.
This routine leaks the thread pool; you should call g_thread_pool_free() before exiting it.
If you're doing other threading in your program, and you care about performance, you should think carefully about whether you want these threads to be exclusive or shared. That's set with the argument to g_thread_pool_new() which you've set to TRUE (exclusive).

Resources