gtk_container_get_children - c

When list of stations is printed in Preset rol list and you are at the begining or at the end of the list, you see many empty items.
I create list of about 20 stations and try to display them, go to the begining and to the end of the list.
I think the problem is in this piece of code:
static void add_button_clicked_cb(GtkWidget *widget, gpointer data)
{
preset *ps;
gchar *buffer;
GtkTreeIter iter = {0};
GtkAdjustment* v_scb;
GtkTreePath *path = NULL;
GList* menuitems;
GtkWidget *menuitem;
ps = malloc(sizeof(preset));
ps->title = g_strdup(_("unnamed"));
ps->freq = rint(gtk_adjustment_get_value(adj)) / STEPS;
settings.presets = g_list_append(settings.presets, (gpointer) ps);
buffer = g_strdup_printf("%.2f", ps->freq);
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter, 0, ps->title, 1, buffer, -1);
g_free(buffer);
gtk_tree_selection_unselect_all(selection);
v_scb = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(list_view));
gtk_adjustment_set_value(v_scb, gtk_adjustment_get_upper(v_scb));
if (main_visible) {
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(preset_combo), ps->title);
mom_ps = g_list_length(settings.presets) - 1;
preset_combo_set_item(mom_ps);
menuitems = gtk_container_get_children(GTK_CONTAINER(tray_menu));
menuitem = gtk_menu_item_new_with_label(ps->title);
gtk_menu_shell_insert(GTK_MENU_SHELL(tray_menu), menuitem, mom_ps);
g_signal_connect(G_OBJECT(menuitem), "activate", (GCallback)preset_menuitem_activate_cb, (gpointer)mom_ps);
gtk_widget_show(menuitem);
}
buffer = g_strdup_printf("%d", g_list_length(settings.presets) - 1);
path = gtk_tree_path_new_from_string(buffer);
g_free(buffer);
gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, NULL, FALSE);
gtk_tree_path_free(path);
}
Could you please suggest me how can correct it?

Inside of the if (main_visible), you have:
menuitems = gtk_container_get_children(GTK_CONTAINER(tray_menu));
That is, you're setting the value of menuitems to the return value of that function call. However, none of the rest of your code actually does anything with menuitems. So, the compiler gives you that warning.
Fixing it might be as easy as simply getting rid of menuitems:
gtk_container_get_children(GTK_CONTAINER(tray_menu));
That would definitely get rid of the warning. But you have to think about it: Maybe you should be doing something with the return value of that function call, and the reason that you're not doing anything with it is that you forgot to (or whatever).

warning: variable 'menuitems' set but not used
Your compiler in layman's terms is saying the following:
Dude... youve created a class with a few attributes, one of which are called 'menuitems'. That's all well mate, but when you actually create an instance and assign all the variables, youve set 'menuitems' but youre never using that variable to do anything with it. its just sitting there doing nothing at all. So mate it's no problem at all as I can still run your program but im just warning you that the 'menuitems' variable is doing ** all as you're never using the variable itself. Just warning you bro :D other than that have a good day
So its just a warning to let you know you have a variable no being used for any specific reason other than storing a value in there but never accessing it to do something useful. So either comment it out since youre not actually doing anything with it.. or use it, or just enjoy reading the warning but it wont affect the way your program runs.
The warnings get displayed mainly to get the developer more aware of their own code and whats happening.

Related

Passing an array to a function - Different values - Segfault

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.

destroying buttons from a vcontainer

I have a vcontainer which is populated with a gtk_combo_box and several buttons
i would like to clear the buttons only from within the vcontainer, I tried the following code:
GList *vcontainer_children, *iter;
vcontainer_children = gtk_container_get_children(GTK_CONTAINER(container));
for(iter = vcontainer_children; iter != NULL; iter = g_list_next(iter))
{
if (gtk_button_get_label(iter));
gtk_widget_destroy(GTK_WIDGET(iter->data));
}
the code clears all widgets in the vcontainer, one possibility would be to replace the if with a function that checks whether iter is a button or not, but I do not know how that is done
if (gtk_button_get_label(iter));
The semicolon at the end is wrong; this is the same as saying
if (gtk_button_get_label(iter))
/* do nothing */;
and as such the gtk_widget_destroy() always runs.
Simply remove the semicolon or switch to using braces for everything (or some other option I didn't think of).
Your condition is also wrong for two reasons. First, it uses iter instead of iter->data. Second, it will crash and burn spectacularly if the widget isn't a button. Fortunately there's a macro GTK_IS_BUTTON() you can use instead:
if (GTK_IS_BUTTON(iter->data))
gtk_widget_destroy(GTK_WIDGET(iter->data));

Memory leaks from splitting and duplicating strings

I am working on a fairly simple application written in C with GTK+ that is leaking memory badly. It has a few basic functions on timers that check the clock and poll an external networked device, parsing the string returned. The application runs on a small touch panel, and through TOP I can watch the available memory be eaten up as it runs.
I'm pretty new to C, so not surprised that I'm doing something wrong, I just can't seem to figure out what. I've been trying to use Valgrind to narrow it down, but honestly the output is a little over my head (10k+ line log file generated from running the application less than a minute). But in digging through that log I did find some functions repeatedly showing up with permanently lost blocks, all using some similar structure.
Example 1:
This is a short function that gets called when an option is selected. The last line with the g_strdup_printf is the one called out by Valgrind. select_next_show and select_show_five_displayed are both global variables.
static void show_box_five_clicked ()
{
g_timer_start(lock_timer);
gtk_image_set_from_file (GTK_IMAGE(select_show_1_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_2_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_3_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_4_cb_image), "./images/checkbox_clear.png");
gtk_image_set_from_file (GTK_IMAGE(select_show_5_cb_image), "./images/checkbox_checked.png");
select_next_show = g_strdup_printf("%i",select_show_five_displayed);
}
Example 2:
This is another function that gets called often and came up a lot in the Valgrind log. It takes the incoming response from the networked device, parses it into two strings, then returns one.
static gchar* parse_incoming_value(gchar* incoming_message)
{
gchar *ret;
GString *incoming = g_string_new(incoming_message);
gchar **messagePieces = g_strsplit((char *)incoming->str, "=", 2);
ret = g_strdup(messagePieces[1]);
g_strfreev(messagePieces);
g_string_free(incoming, TRUE);
return ret;
}
In all the cases like these which are causing problems I'm freeing everything I can without causing segmentation faults, but I must be missing something else or doing something wrong.
UPDATE:
To answer questions in comments, here is an example (trimmed down) of how I'm using the parse function and where the return is freed:
static void load_schedule ()
{
...other code...
gchar *holder;
gchar *holder2;
holder = read_a_line(schedListenSocket);
holder2 = parse_incoming_value(holder);
schedule_info->regShowNumber = holder2;
holder = read_a_line(schedListenSocket);
holder2 = parse_incoming_value(holder);
schedule_info->holidayShowNumber = holder2;
...other code....
g_free(holder);
g_free(holder2);
}
Any help is greatly appreciated!!
It looks like you free 'ret' once when calling g_free(holder2), but you've done multiple allocations for that one free - you call parse_incoming_value multiple times, each time causing an allocation, but you only free once right at the end.
As you copy the holder2 pointer into schedule_info elements each time, they actually have the "leaked" memory at the end.
If you do not free holder2 anywhere, but just free all the elements in schedule_info at the end of the code. I presume that shows no leak?
e.g.
holder2 = <result of dynamic alloc>;
schedule_info->a = holder2;
...
holder2 = <result of dynamic alloc>;
schedule_info->b = holder2;
...
// instead of g_free(holder2) at the end, do this...
g_free(schedule_info->a);
g_free(schedule_info->a);

Issues with LB_GETCURSEL

I am having some issues with lb_getcursel and what it returns (if it does even return anything)
heres my message handler...
case IDT_TESTLIST1:
if(HIWORD(wParam) == LBN_DBLCLK) {
int ret = 0;
double TimeOut = 60.0;
int Lng = 1;
unsigned char Param[255] = {0};
unsigned char Port1 = port1;
int iCurSel = SendDlgItemMessage(hwnd,IDT_TESTLIST1,LB_GETCURSEL,0.0);
ret = PSB30_Open(Port1,16);
ret = PSB30_SendOrder(Port1,test1[iCurSel].testNumber, &Param[0],&Lng,&TimeOut);
ret = PSB30_Close(Port1);
}
break;
I am using Visual Studio 2010 and whenever i run the program iCurSel doesn't look like it even gets assigned a value, defaults to 0, when i step into the case statement, not all variables are visible in the autos section, when i add a watch to iCurSel i get a CXX0017: Error message.
hwnd is the handle to my main window and is correct
any help would be appreciated
Cheers
i find it funny that none of my variables in the message are showing anything by hovering over them
That's because they don't exist. Your program cannot compile, it has an error. SendDlgItemMessage() takes 5 arguments, you pass 4. The last one got morphed into a floating point value by a typo.
Clearly you'll need to pay attention to compile error messages. And change a setting so this cannot happen again. Tools + Options, Projects and Solution, Build and Run. Change the "On Run, when build or deployment error occurs" setting to "Do not launch".

SetProp problem

Can anybody tell me why the following code doesn't work? I don't get any compiler errors.
short value = 10;
SetProp(hCtl, "value", (short*) value);
The third parameter is typed as a HANDLE, so IMO to meet the explicit contract of the function you should save the property as a HANDLE by allocating a HGLOBAL memory block. However, as noted in the comments below, MSDN states that any value can be specified, and indeed when I try it on Windows 7 using...
SetProp(hWnd, _T("TestProp"), (HANDLE)(10)); // or (HANDLE)(short*)(10)
...
(short)GetProp(hWnd, _T("TestProp"));
... I get back 10 from GetProp. I suspect somewhere between your SetProp and GetProp one of two things happens: (1) the value of hWnd is different -- you're checking a different window or (2) a timing issue -- the property hasn't been set yet or had been removed.
If you wanted to use an HGLOBAL instead to follow the specific types of the function signature, you can follow this example in MSDN.
Even though a HANDLE is just a pointer, it's a specific data type that is allocated by calls into the Windows API. Lots of things have handles: icons, cursors, files, ... Unless the documentation explicitly states otherwise, to use a blob of data such as a short when the function calls for a HANDLE, you need a memory handle (an HGLOBAL).
The sample code linked above copies data as a string, but you can instead set it as another data type:
// TODO: Add error handling
hMem = GlobalAlloc(GPTR, sizeof(short));
lpMem = GlobalLock(hMem);
if (lpMem != NULL)
{
*((short*)lpMem) = 10;
GlobalUnlock(hMem);
}
To read it back, when you GetProp to get the HANDLE you must lock it to read the memory:
// TODO: Add error handling
short val;
hMem = (HGLOBAL)GetProp(hwnd, ...);
if (hMem)
{
lpMem = GlobalLock(hMem);
if (lpMem)
{
val = *((short*)lpMem);
}
}
I would create the short on the heap, so that it continues to exist, or perhaps make it global, which is perhaps what you did. Also the cast for the short address needs to be void *, or HANDLE.

Resources