I'm building an application that uses drag and drop using GTK in C language but I have a problem with this part of code
void view_onDragDataReceived(GtkWidget *wgt, GdkDragContext *context, int x, int y,GtkSelectionData *seldata, guint info, guint time,gpointer userdata)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = GTK_TREE_MODEL(userdata);
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_URI,(gchar*)seldata->data, -1);
pathh=(char*)seldata->data;
}
I call this Function from this line of code
g_signal_connect(view, "drag_data_received",G_CALLBACK(view_onDragDataReceived), liststore);
the problem i'm having is that when i try to use that pathh variable in an other function i find it empty even though it's declared a global variable type char*
Try this way
struct SelectionData
{
GtkListStore *listStore;
gchar *path;
}
and then in the caller function
struct SelectionData *data;
data = malloc(sizeof(*data));
if (data == NULL)
handleMallocFailureAndPleaseDoNotContinue();
data->listStore = liststore;
data->path = NULL;
g_signal_connect(view, "drag_data_received",G_CALLBACK(view_onDragDataReceived), data);
and then
void view_onDragDataReceived(GtkWidget *wgt, GdkDragContext *context, int x, int y,GtkSelectionData *seldata, guint info, guint time, gpointer userdata)
{
GtkTreeModel *model;
GtkTreeIter iter;
SelectionData *selectionData;
size_t length;
selectionData = (SelectionData *)userdata;
model = GTK_TREE_MODEL(selectionData->liststore);
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_URI,(gchar*)seldata->data, -1);
length = strlen((char*)seldata->data);
if (selectionData->path != NULL) /* for subsequent calls */
free(selectionData->path);
selectionData->path = malloc(1 + length);
if (selectionData->path != NULL)
memcpy(selectionData->path, seldata->data, 1 + length);
}
and then you can access selectionData somewhere else and thus it's path field, which must be freed after you finish using it.
Try to avoid global variables as much as possible.
You can also use the same technique to copy seldata->data into your pathh global variable, but rethink your design and try not to use pathh global variable, since you are going to use malloc to allocate space for the string, and the global variable will be a pointer to it, so it will be very dificult to understand where and how you must free it.
Related
I guess i have a pure C problem here and that it has nothing to do with GTK, but i'm not sure.
I have this function in which i'm retreiving the content of a GtkEntry, converting the gchar to gint64 with another function, and then i want to add it to the list. Thou, while the first printf gives me the right value, the second one gives an incorrect value.
So, i can't figure out how to pass this value contained in the *c to the gtk_list_store_set.
void on_button_add_clicked (GtkButton *button, app_widgets *app_wid) {
GtkTreeIter iter;
//get the entry content
gint64 *c = mult_by_100_char2int(gtk_entry_get_text(GTK_ENTRY(app_wid->ent_mont)));
printf("c=%li\n",*c);
gint64 cval = *c;
printf("cval=%li\n",cval);
//put in the liststore
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app_wid->treeview)));
gtk_list_store_append(store, &iter); // Acquire an iterator
gtk_list_store_set(store, &iter,
AMOUNT_COLUMN, cval, //the column requires a gint64
-1);
}
//prototype of other function is:
gint64* mult_by_100_char2int (const gchar* number)
Edit: (added functions - in reverse order)
gint64* mult_by_100_char2int (const gchar* number) {
const gchar* buf1 = mult_by_100(number);
gint64 buf2 = g_ascii_strtoll(buf1,NULL,10);
gint64 *buf3 = &buf2;
return buf3;
}
gchar* mult_by_100 (const gchar *number) {
int thesize = strlen(number);
gchar *entiers = substring(number,0,thesize-3);
gchar *centimes = substring(number,thesize-2,2);
gchar *result = g_strjoin("",entiers,centimes,NULL);
return result;
g_free(result);
}
gchar* substring(const gchar* s, int p, int l) {
char sub[128] = "";
char schar[128] = "";
gchar* result;
int i;
strcat(schar,s);
for(i=0;i<l;i++) {
sub[i] = schar[p+i];
//printf("i=%d - sub=%s\n",i,sub);
}
sub[i+1] = '\0';
result = g_strdup(sub);
return result;
g_free(result);
}
buf3 is an address of a variable local to mult_by_100_char2int. This variable does not exist anymore once mult_by_100_char2int returns. Your program has no right to access it.
It is an unlucky coincidence that the first printf produced a correct result. We may theorize why it did happen (I wouldn't be surprised is removal of first printf make the second one appear to work correctly), but the bottomline is that the behavior is undefined.
This is a generic question about pointers, nothing to do, as you stated, with Gtk. The #user58697 answer explain the why this happens.
The solve this problem, the mult_by_100_char2int function should return a gint64 instead of a pointer to a local variable.
It should look something like this:
gint64 mult_by_100_char2int (const gchar* number) {
gchar* buf1 = mult_by_100(number);
gint64 retval = g_ascii_strtoll(buf1,NULL,10);
g_free (buf1);
return retval;
}
Then, your callback function should be:
void on_button_add_clicked (GtkButton *button, app_widgets *app_wid) {
GtkTreeIter iter;
//get the entry content
gint64 c = mult_by_100_char2int(gtk_entry_get_text(GTK_ENTRY(app_wid->ent_mont)));
printf("c=%li\n",c);
//put in the liststore
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app_wid->treeview)));
gtk_list_store_append(store, &iter); // Acquire an iterator
gtk_list_store_set(store, &iter,
AMOUNT_COLUMN, c, //the column requires a gint64
-1);
}
The other functions, as stated in the comments, have redundant g_free's, so they should be something like this (notice that i've only looked at the g_free calls, no other action taken, the code could be improved):
gchar* mult_by_100 (const gchar *number) {
int thesize = strlen(number);
gchar *entiers = substring(number,0,thesize-3);
gchar *centimes = substring(number,thesize-2,2);
gchar *result = g_strjoin("",entiers,centimes,NULL);
g_free(entiers);
g_free(centimes);
return result;
}
gchar* substring(const gchar* s, int p, int l) {
char sub[128] = "";
char schar[128] = "";
gchar* result;
int i;
strcat(schar,s);
for(i=0;i<l;i++) {
sub[i] = schar[p+i];
//printf("i=%d - sub=%s\n",i,sub);
}
sub[i+1] = '\0';
result = g_strdup(sub);
return result;
}
Haven't tested the code but it should work now.
I'm having a bit of a strange issue that seems to be related to pthread_create.
I have a struct that contains const char * variables:
typedef struct Notification {
const char *summary;
const char *body;
} Notification;
It might be worth noting that data is assigned to these variables using g_variant_get_string(content, NULL);, which is of type const gchar *, but to my knowledge that should not affect this issue.
The problem seems to come when using this struct in a pthread.
const gchar *summary = NULL;
const gchar *body = NULL;
summary = g_variant_get_string(content, NULL);
body = g_variant_get_string(content, NULL);
Notification *n = malloc(sizeof(Notification));
assert(n != NULL);
n->summary = summary;
n->body = body;
pthread_create(&split_notification, NULL, &run, (void *)n));
Where run is simply:
void *
run(void *arg)
{
Notification *n = (Notification *)arg;
printf("summary: %s\n", n->summary);
printf("body: %s\n", n->body);
return NULL;
}
Where it produces garbage, such as:
summary: 0[
body: /
I have tried casting the same struct to void and back, and it produces the desired result. What is happening?
I am trying to create a set of gstreamer plugins for image processing routines. I have successfully created a source element that reads the image and the metadata into a GstBuffer, and a sink element that writes the data in the buffer to disk (along with the accompanying metadata) as desired. I have successfully tested these, and achieve the desired output (identical to the input with no filters in place).
I have also created a stretching element, that utilizes an external library to fill the dynamic range available (ie a 16-bit image with only 12-bits used per pixel can be stretched to fill the whole 16-bits available).
If I simply push the unchanged buffer out on the srcpad for the Stretching element, I get what I would expect (an unchanged image). However, if I try to perform any sort of manipulation of the data in the buffer, the data in the buffer is set to 0's.
Here is the current implementation of the chain() function for my Stretching plugin:
static GstFlowReturn
gst_stretching_chain(GstPad *pad, GstObject *parent, GstBuffer *buf)
{
GstStretching *filter;
filter = GST_STRETCHING(parent);
g_print("Stretching...\n");
guint num_rows;
g_object_get(G_OBJECT(parent), "num_rows", &num_rows, NULL);
guint num_cols;
g_object_get(G_OBJECT(parent), "num_cols", &num_cols, NULL);
guint bit_depth;
g_object_get(G_OBJECT(parent), "bit_depth", &bit_depth, NULL);
guint sig_bits;
g_object_get(G_OBJECT(parent), "sig_bits", &sig_bits, NULL);
gchar *product;
g_object_get(G_OBJECT(parent), "product", &product, NULL);
GstMapInfo info_in;
gst_buffer_map(buf, &info_in, GST_MAP_WRITE);
guint8 *in = info_in.data;
GstMemory *mem;
mem = gst_allocator_alloc(NULL, num_rows*num_cols*bit_depth/8, NULL);
GstMapInfo info_out;
gst_memory_map(mem, &info_out, GST_MAP_WRITE);
guint8 *out = info_out.data;
float *rad_gain[4] = {NULL, NULL, NULL, NULL};
float *rad_offset[4] = {NULL, NULL, NULL, NULL};
StretchingImage((unsigned short int *)in, num_rows, num_cols, sig_bits,
bit_depth, rad_gain, rad_offset, 0, product, (unsigned short int *)out);
gst_buffer_unmap(buf, &info_in);
gst_buffer_replace_all_memory(buf, mem);
return gst_pad_push(filter->srcpad, buf);
}
When this did not work, I also tried a simple change of the data manually (to see if I would get the expected output):
static GstFlowReturn
gst_stretching_chain(GstPad *pad, GstObject *parent, GstBuffer *buf)
{
GstStretching *filter;
filter = GST_STRETCHING(parent);
g_print("Stretching...\n");
guint num_rows;
g_object_get(G_OBJECT(parent), "num_rows", &num_rows, NULL);
guint num_cols;
g_object_get(G_OBJECT(parent), "num_cols", &num_cols, NULL);
guint bit_depth;
g_object_get(G_OBJECT(parent), "bit_depth", &bit_depth, NULL);
guint sig_bits;
g_object_get(G_OBJECT(parent), "sig_bits", &sig_bits, NULL);
gchar *product;
g_object_get(G_OBJECT(parent), "product", &product, NULL);
GstMapInfo info_in;
gst_buffer_map(buf, &info_in, GST_MAP_WRITE);
guint8 *in = info_in.data;
GstMemory *mem;
mem = gst_allocator_alloc(NULL, num_rows*num_cols*bit_depth/8, NULL);
GstMapInfo info_out;
gst_memory_map(mem, &info_out, GST_MAP_WRITE);
guint8 *out = info_out.data;
int i;
for (i=0; i<num_rows*num_cols*bit_depth/8; i++) {
out[i] = 255;
}
float *rad_gain[4] = {NULL, NULL, NULL, NULL};
float *rad_offset[4] = {NULL, NULL, NULL, NULL};
StretchingImage((unsigned short int *)in, num_rows, num_cols, sig_bits,
bit_depth, rad_gain, rad_offset, 0, product, (unsigned short int *)out);
gst_buffer_unmap(buf, &info_in);
gst_buffer_replace_all_memory(buf, mem);
return gst_pad_push(filter->srcpad, buf);
}
Even with this, I still obtain all 0's when I examine the output. I am assuming I am doing something wrong when trying to access the data in the buffer, but haven't yet been able to figure out what it may be. Any ideas?
The
gst_buffer_map(buf, &info_in, GST_MAP_WRITE);
should be
gst_buffer_map(buf, &info_in, GST_MAP_READ);
Also fyi, you can simplfy the code
guint num_rows, num_cols, ...;
g_object_get(G_OBJECT(parent),
"num_rows", &num_rows,
"num_cols", &num_cols,
...
NULL);
I have a memory issue in my GTK programm and I don't know how to fix it.
The data in the liststore of my programm saved with fwrite in a binary file when I close the programm. The code seems to work:
void on_window_destroy (GtkWidget *object, gpointer user_data)
{
gint i;
GtkTreeIter iter;
GtkTreeModel *model = GTK_TREE_MODEL(gtk_builder_get_object (builder,"liststore"));
gint n_rows = gtk_tree_model_iter_n_children( model, NULL ); //count the rows
FILE *pfile = fopen("Data", "wb" );
gtk_tree_model_get_iter_first (model, &iter);//set iter postion to the first row
data *pdata = malloc(sizeof(data));
for (i = 0 ; i < n_rows; i++)
{
gtk_tree_model_get (model, &iter,
SPALTE_ArtName, &pdata->ArtBez,
SPALTE_ArtNr, &pdata->ArtNr,
SPALTE_LBest, &pdata->LBest,
-1);
//just to check the data
g_printf("Zeile %d: %s | %d | %d\n",i, pdata->ArtBez, pdata->ArtNr, pdata->LBest);
fwrite(pdata,sizeof(data),1,pfile);
gtk_tree_model_iter_next (model, &iter); //iter = next row
}
free(pdata);
fclose(pfile);
g_printf("Saved successfully!\n\n");
gtk_main_quit();
}
After this when I start the program again it should read the binary file with fread and add the data in the empty liststore
I tried this like this:
data *pdata = malloc (sizeof(data));
FILE *pfile = fopen("Data","rb");
if (pfile == NULL)
{
g_printf("Error: Data File not Found! Creating new list....\n");
}
else
{
while (fread (pdata,sizeof(data),1,pfile))
{
g_printf("Test 1 \n\n\n");
gtk_list_store_append(GTK_LIST_STORE(model), &iter); //add new row
g_printf("Test 1 \n\n\n");
gtk_list_store_set (GTK_LIST_STORE(model), &iter,
SPALTE_ArtName,pdata->ArtBez,
SPALTE_ArtNr,pdata->ArtNr,
SPALTE_LBest,pdata->LBest,
-1);
}
free(pdata);
fclose(pfile);
}
Here is the data struct used from pdata:
typedef struct _data
{
gchar *ArtBez;
gint *ArtNr;
gint *LBest;
}data;
The issue must has to do with the pdata->ArtBez because when I tab it out it works fine.
EDIT:
After I red the answer from stark (Thank you so much!) I changed the "data" struct to a struct without Pointers
typedef struct _data
{
gchar ArtBez[128];
gint ArtNr;
gint LBest;
}data;
Then I changed the write function from above to:
void on_window_destroy (GtkWidget *widget, gpointer user_data)
{
gint i, *BufArtNr, *BufLBest;
gchar *BufArtBez;
GtkTreeIter iter;
GtkTreeModel *model = GTK_TREE_MODEL(gtk_builder_get_object (builder, "liststore")); //Hole liststore aus glade-Datei
gint n_rows = gtk_tree_model_iter_n_children( model, NULL ); //count rows
FILE *pfile = fopen("Data", "wb" );
gtk_tree_model_get_iter_first (model, &iter); //Zeiger auf erste Zeile setzen
data *pdata = malloc(sizeof(data)*n_rows);
for (i = 0 ; i < n_rows; i++) //For every row
{
gtk_tree_model_get (model, &iter, //Get data from row
SPALTE_ArtNr, &BufArtNr,
SPALTE_ArtBez, &BufArtBez,
SPALTE_LBest, &BufLBest,
-1);
//Schreibe Daten in Struct
pdata[i].ArtNr = BufArtNr;
strcpy(pdata[i].ArtBez, BufArtBez);
pdata[i].LBest = BufLBest;
fwrite(&pdata[i],sizeof(data),1,pfile); //Write data to file
gtk_tree_model_iter_next (model, &iter); //Next row
}
free(pdata);free(BufArtBez);
fclose(pfile);
g_printf("Saved successfully\n\n");
}
That works, but when I compile the program, the compiler gets me a warning:
warning: assignment makes integer from pointer without a cast [enabled by default]
pdata[i].ArtNr = BufArtNr;
Same warning for pdata[i].LBest = BufLBest;
Where is my mistake?
pdata only contains pointers, which are not useful to save and restore. Instead of
fwrite(pdata,sizeof(data),1,pfile);
you need to do
fwrite(pdata->ArtBez,...
fwrite(pdata->ArtNr,...
fwrite(pdata->LBest,...
and then build a new structure when you read them back.
I read this thread, which helped me figure out dereferencing properly, but then I went and created exactly the situation that post's answer's author said to avoid, haha.
What I'm trying to accomplish is the creation of a basic file browser (per the book I'm reading). The code below is supposed to be reading through the directory contents and filling the details I've chosen into a struct. That struct is then appended as the data member of a GSList. That list is then used to populate row data for a GtkTreeView, and so forth.
typedef struct
{
gchar *name, *size, *date_modified;
}FileProperties;
//...
static void refresh_directory_listing(GtkTreeView *treeview)
{
GtkListStore *store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
GSList *files = NULL;
GtkTreeIter iter;
get_current_directory_contents(&files);
for(GSList *current = files; current != NULL; current = g_slist_next(current))
{
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, FILE_NAME, ((FileProperties *) current->data)->name,
FILE_SIZE, ((FileProperties *) current->data)->size,
DATE_MODIFIED, ((FileProperties *) current->data)->date_modified, -1);
}
gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
g_object_unref(store);
g_slist_free(files);
}
static void get_current_directory_contents(GSList **files)
{
GDir *current_dir = g_dir_open(g_get_current_dir(), 0, NULL);
gchar *file_name = NULL;
FileProperties *file = g_malloc(sizeof(FileProperties));
while((file_name = (gchar *) g_dir_read_name(current_dir)))
{
memset(file, 0, sizeof(FileProperties));
file->name = g_strdup(file_name);
file->size = g_strdup_printf("Nope");
file->date_modified = g_strdup_printf("Nuh uh");
*files = g_slist_append(*files, file);
}
g_free(file);
}
Working to understand why my file names return blank and everybody has the same memory address, it's obvious to me that g_slist_append() is handing the FileProperties structure over directly. So, everything references the same struct that keeps getting overwritten and eventually freed. Whoops.
My question is this: what would be the appropriate way to hand a GSList of struct's back and forth between functions?
You are only allocating one FileProperties structure before the while loop, and then you just change the contents of that single struct, and append it many times.
You need to allocate one FileProperties structure instance for each file whose properties you want to store.
Move the allocation inside the loop, replacing the (spurious) memset():
while((file_name = (gchar *) g_dir_read_name(current_dir)))
{
FileProperties *file = g_malloc(sizeof *file);
/* rest of loop here ... */
}