GTK2+ error: GTK_IS_CONTAINER & GTK_IS_WIDGET failed - c

It's my first post here, I made this account because I'm kind of stumped.
I'm trying to practise passing structures as arguments to callbacks, and for that purpose I created a simple program with a button in a window. In the first iteration, pressing the button with label "Button 1" will change it into a different button with label "Button 2", while in the second the change is done by hovering over the buttons.
Below is the code for the first iteration
#include <gtk/gtk.h>
typedef struct {
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *window;
} example;
void callback_func (GtkWidget *ignored, example *test) {
GtkWidget *window=test->window;
GtkWidget *changebutton1=test->button1;
GtkWidget *changebutton2=test->button2;
gtk_container_remove(GTK_CONTAINER(window),changebutton1);
gtk_container_add(GTK_CONTAINER(window),changebutton2);
gtk_widget_show_all(window);
}
void callback_func2 (GtkWidget *ignored, example *test) {
GtkWidget *window=test->window;
GtkWidget *changebutton1=test->button1;
GtkWidget *changebutton2=test->button2;
gtk_container_remove(GTK_CONTAINER(window),changebutton2);
gtk_container_add(GTK_CONTAINER(window),changebutton1);
gtk_widget_show_all(window);
}
int main(int argc, char *argv[]) {
example test;
gtk_init(&argc,&argv);
GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget *changebutton1=gtk_button_new_with_label("Button 1");
GtkWidget *changebutton2=gtk_button_new_with_label("Button 2");
test.window=window;
test.button1=changebutton1;
test.button2=changebutton2;
g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(window),changebutton1);
g_signal_connect (G_OBJECT (changebutton1), "clicked", G_CALLBACK (callback_func), (gpointer*)&test);
g_signal_connect (G_OBJECT (changebutton2),"clicked",G_CALLBACK(callback_func2),(gpointer*)&test);
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
When running the above code, by clicking the button once, the buttons switch properly, but when I click it again (now calling callback_func2 instead of callback_func, which are essentially identical save for the buttons switching place) I get this:
(gtktesting.exe:92024): Gtk-CRITICAL **: gtk_container_add: assertion `GTK_IS_WIDGET (widget)' failed
If I replace the "clicked" events with "enter_notify_event" and "leave_notify_event", the first change fails as well, now yielding more errors.
Anybody know what's going on?
Also, a bonus question. I pretty much copied and pasted the base of this code from another post, since I had been trying to write it by myself unsuccessfully and I wanted to test if it works at all. I noticed that the second argument in the callbacks is "example *test". Can anybody explain the "example" type? It's only the name of the stucture, and I've no idea what it's doing there.

tl;dr
Try:
test.window = g_object_ref(window);
test.button1 = g_object_ref(changebutton1);
test.button2 = g_object_ref(changebutton2);
Full explaination
Objects (i.e. subclasses of GObject) in GTK+ are reference counted. That means, every object (e.g. Widget) has "reference count" - number of pointers that point to it. When number reaches 0 - object is deallocated. Objects are created with reference count of 1. As C does not have smart pointers C++ does nor anything similar, reference counting has to be done manually. User has to call g_object_ref in order to retain a reference (I use words "pointer" and "reference" interchangeably), and g_object_unref when user is done with a reference. That ensures that no object is destroyed while being in use.
GtkWidget is special, as it begins life with "floating" reference. That means that first time widget is referenced its reference count does not increase - its "floating" reference is "sunk". After that it behaves like any other GObject.
When you create your buttons, they are created with reference count 1 ("floating"). When they are added to their container, their references are still 1 (but "sunk"). This means, buttons are owned by the container that they're added to.
Now, when you remove button from container:
gtk_container_remove(GTK_CONTAINER(window),changebutton1);
reference count for changebutton1 is decreased, drops to 0, which forces object destruction, and test.button1 is now dangling pointer.
To overcome this, use g_object_ref anytime you want to store pointer to GObject. That way you express "test participates in ownership of changebutton1" (or, "test is interested in keeping changebutton1 alive).
When you are done with window, button1 and button2, call g_object_unref on them.
Bonus question
Also, a bonus question. I pretty much copied and pasted the base of
this code from another post, since I had been trying to write it by
myself unsuccessfully and I wanted to test if it works at all. I
noticed that the second argument in the callbacks is "example *test".
Can anybody explain the "example" type? It's only the name of the
stucture, and I've no idea what it's doing there.
example is defined here:
typedef struct {
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *window;
} example; // declares type "example"
GObject signal system is designed in a sucha way that it allows passing arbitrary pointer as a last argument to callback, so a programmer can pass extra information from place where signal connection is created (g_signal_connect), to a callback.

Related

How to use images in GTK Stack Switcher using C

I'm making application in gtk using C. I have a GtkStack with GtkStackSwitcher and I don't know how to set images/icons to buttons in stack switcher. I had similar problem with application in gtkmm and C++ but I was able to find required function in the documentation. This time, after searching the documentation for GtkStack, GtkStackSwitcher and GtkContainer, I didn't find anything useful in GtkStack and GtkStackSwitcher. In GtkContainer there is function gtk_container_child_set_property (). It may be the function I'm looking for but I have no idea how to put an icon-name into GValue and if it's possible.
To sum up - can I set icon to GtkStackSwitcher's button with mentioned functions or using any other method?
Edit:
Maybe it's possible to achieve this with css? Setting background-image for GtkStack and GtkStackSwticher doesn't work but setting background_image for buttons works. Works very bad but works. The image doesn't fit the button and button doesn't resize to be the image size (If i set button new from pixbuf the button does resize). So is it possible with css or is it a dead end?
From the GtkStack documentation, at Child Properties, you can see the property "icon-name":
The “icon-name” child property
“icon-name” gchar *
The icon name of the child page.
Flags: Read / Write
Default value: NULL
As you pointed out, we can use gtk_container_child_set_property on the GtkStack (a GtkContainer) and set the icon. The problem is that the stack uses the icon or the title, not both.
Here is a simple example in C code:
#include <gtk/gtk.h>
int main (int argc, char** argv) {
GtkBox *box;
GtkStack *stack;
GtkLabel *label1;
GtkLabel *label2;
GtkWindow *window;
GtkStackSwitcher *switcher;
GValue iconval1 = G_VALUE_INIT;
GValue iconval2 = G_VALUE_INIT;
gtk_init (&argc, &argv);
g_value_init (&iconval1, G_TYPE_STRING);
g_value_init (&iconval2, G_TYPE_STRING);
window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 6));
stack = GTK_STACK(gtk_stack_new ());
switcher = GTK_STACK_SWITCHER(gtk_stack_switcher_new ());
label1 = GTK_LABEL(gtk_label_new("Stack Page 1"));
label2 = GTK_LABEL(gtk_label_new("Stack Page 2"));
gtk_stack_add_titled(stack, GTK_WIDGET(label1), "Page 1", "Page 1");
gtk_stack_add_titled(stack, GTK_WIDGET(label2), "Page 2", "Page 2");
gtk_widget_set_halign (GTK_WIDGET(switcher), GTK_ALIGN_CENTER);
g_value_set_string(&iconval1, "zoom-in-symbolic.symbolic");
g_value_set_string(&iconval2, "zoom-out-symbolic.symbolic");
gtk_container_child_set_property(GTK_CONTAINER(stack), GTK_WIDGET(label1), "icon-name", &iconval1);
gtk_container_child_set_property(GTK_CONTAINER(stack), GTK_WIDGET(label2), "icon-name", &iconval2);
gtk_stack_switcher_set_stack (switcher, stack);
gtk_box_pack_start (box, GTK_WIDGET(switcher), FALSE, FALSE, 6);
gtk_box_pack_start (box, GTK_WIDGET(stack), TRUE, TRUE, 6);
gtk_container_add (GTK_CONTAINER(window), GTK_WIDGET(box));
g_signal_connect(G_OBJECT(window), "destroy", gtk_main_quit, NULL);
gtk_widget_show_all (GTK_WIDGET(window));
gtk_main ();
return 0;
}
Compile it with:
gcc -o test main.c `pkg-config --cflags --libs gtk+-3.0`
and the result should be:
EDIT:
As requested in the comments:
Can you tell me also how to change icon sizes of stack switcher icons?
I see that stack switcher has property "icon-size"...
GtkStackSwitcher has the property "icon-size" but it was introduced in Gtk+ 3.20. So, in order to use this property there is this requirement.
To set a property to which Gtk+ does not provide a setter/getter you should use g_object_set (or set_full).
Using the code above:
...
switcher = GTK_STACK_SWITCHER(gtk_stack_switcher_new ());
g_object_set(G_OBJECT(switcher), "icon-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
label1 = GTK_LABEL(gtk_label_new("Stack Page 1"));
...
The property is a gint value so you can try out some values and verify the size. There is also a enumerated type containing default sizes for icons, it's GtkIconSize. In the example i've used GTK_ICON_SIZE_LARGE_TOOLBAR (24px).

Why do I get a segmentation fault in my GTK+ signal callback?

I am trying to measure the size of a GTK label:
#include <gtk/gtk.h>
static void map_event(GtkWidget *window, gpointer lab) {
g_print( "In the callback..\n" );
GtkWidget *label = GTK_WIDGET(lab);
g_print( "Everything is ok..\n" );
}
static void activate (GtkApplication* app, gpointer user_data)
{
GtkWidget *window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window1");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 280);
GtkWidget *grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
GtkWidget *label = gtk_label_new("Hello world!");
gtk_grid_attach(GTK_GRID (grid), label, 0,0,1,1);
g_signal_connect (window, "map-event", G_CALLBACK(map_event), label);
gtk_widget_show_all (window);
}
int main (int argc, char **argv) {
GtkApplication *app = gtk_application_new (
"org.gtk.example", G_APPLICATION_FLAGS_NONE );
g_signal_connect( app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref (app);
return status;
}
This gives output:
In the callback..
Segmentation fault (core dumped)
If I comment out the line:
GtkWidget *label = GTK_WIDGET(lab);
there is no segmentation fault, the label shows up and the output is:
In the callback..
Everything is ok..
What am I missing here?
map-event has following signature, so you are missing GdkEvent* argument:
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
Unfortunately, GTK+ is written in C, so it lacks type-safe callback functions, so it's easy to make mistakes such as this.
You don't respect the signal signature. Each signal is associated with a pre-defined function prototype you must respect, otherwise you'll just read garbage. Here you just made up out of your mind the callback signature so things won't work as expected.
The signal is like a delicious fruit delivery service. By connecting to that signal, you signed a contract that subscribe you to the fruit delivery service. Fruit will be delivered only when the fruit is ripe. The delivery man will:
come in front of your home
drop some fruit boxes for you
knock at your door
go back to its truck
The contract also specifies that:
box #1 will contain bananas
box #2 will contain apples
box #3 will contain oranges
Those boxes are like the arguments of your callback. The map-event takes 3 arguments, thus the 3 boxes.
One day, you hear knocking at the door. You open the door, see the boxes, open box #2 and get annoyed saying "damn, I said I wanted oranges!". The thing is that you're mixing apples and oranges: by contract, oranges are in box #3 and you're looking for them in box #2.
So give a look at the documentation of each signal you want to connect to. That's the only way to write the right callback. Here you forgot one input parameter as well as the return value. In the case of map-event, that return value can be seen as you going to the truck to say if you want to continue or stop the deliveries.

GTK Linux C Get Input from Entry Box via Button Widget

I have a table that is filled with entry boxes, labels, and buttons.
Currently, if I compile the code, I can get input from a text box but only if the users presses the enter key, and the text only comes from the box they are currently typing in.
I would like to be able to get input from both text boxes when the "Login" button is pushed. I've tried using the same callback function that's used for enter key on the entry box, but GTK gives me an error.
If anyone could show me some code that would allow for me to get text from my entry boxes that are within tables (I know the method for retrieving data from tables and v/boxes is different) it would be greatly appreciated, as I can't seem to find it in any tutorials.
Will update w/working code.
Error when trying to attach status bar to table:
(Entry:5526): Gtk-CRITICAL **: gtk_table_attach: assertion `child->parent == NULL' failed
(Entry:5526): GLib-GObject-WARNING **: invalid cast from GtkTable' toGtkStatusbar'
Your callback function (named callback) needs to access both GtkEntry widgets in order to obtain their values. There are several ways this can be accomplished. Many GTK C programs use global variables, or global variables with file scope (ie a variable declared as static outside of any function within a file).
Remove your entry1 and entry2 variables near the top of the file before any functions:
static GtkWidget *entry1 = 0;
static GtkWidget *entry2 = 0;
And then modify the callback like so:
/* Our callback.
* The data passed to this function is printed to stdout */
static void callback( GtkWidget *widget, gpointer data)
{
const gchar *entry_text1;
const gchar *entry_text2;
g_print ("Hello again - %s was pressed\n", (char *) data);
entry_text1 = gtk_entry_get_text (GTK_ENTRY (entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
You should additionally make similar modifications to the enter_callback function, and don't forget to remove the GtkWidget pointers to both GtkEntry from main.
As an alternative to using (static) global variables, create a data structure to hold the entries:
typedef struct login_data
{
GtkWidget *entry1;
GtkWidget *entry2;
} login_data;
This then gets passed to the callback (rather than text string as before), and the callback changes like so:
static void callback( GtkWidget *widget, gpointer data)
{
login_data* ld = (login_data*)data;
const gchar *entry_text1;
const gchar *entry_text2;
entry_text1 = gtk_entry_get_text (GTK_ENTRY (ld->entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (ld->entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
The data structure is dynamically allocated to prevent it going out of scope (not strictly necessary in simple applications) and this is done before using g_signal_connect to connect the callback to the entries:
login_data* ld = g_malloc(sizeof(*ld));
// callback function to execute when login is clicked
g_signal_connect (LoginButton, "clicked", G_CALLBACK (callback), (gpointer) ld);
Using this method, you must change all references to entry1 and entry2 to ld->entry1 and ld->entry2. Lastly, before the program exits, you should call g_free on the dynamically allocated struct ie g_free(ld).
BTW, for this program you don't need two separate callbacks, remove enter_callback and just use callback for both.

What's the GTK header I need to include so I can use lookup_widget?

As shown in the example below, this callback function is when the user clicks an OK button. I can get window (the top level widget) from button by using gtk_widget_get_toplevel, but I'm stuck trying to get a widget pointer for a GtkEntry widget with name ENTRY.
/* Called when OK button is clicked */
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
//The line directly below is the one I get an error on
GtkWidget *entry = lookup_widget( GTK_WIDGET(button), "ENTRY" );
gchar *text1, *text2;
text1 = gtk_entry_get_text( GTK_ENTRY(entry));
text2 = g_strconcat("Hello, ", text1, NULL);
GtkWidget *window = gtk_widget_get_toplevel (GTK_WIDGET(button));
GtkWidget *dialog = gtk_message_dialog_new( window,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
text2);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
But I get the error "undefined reference to lookup_widget." I can find a billion examples of snippets of code using lookup_widget, but not a single one full source code example showing the headers that enable the use of it. I'm using Anjuta3.2.0 and the latest Glade plugin.
As Basile Starynkevitch says, lookup_widget() was a function generated by Glade 2. However, code generation by Glade has been deprecated for quite a long time now, in favor of (first) libglade and (later) GtkBuilder. In fact, Glade 3 won't even do it.
The preferred solution is to pass a pointer to your ENTRY as the user data pointer when you connect the signal, or, if you're using gtk_builder_connect_signals(), store a pointer to ENTRY in your class and pass the class as the user data pointer.
However, if you must use lookup_widget(), here's the source that Glade 2 generated as of about 6 years ago:
GtkWidget*
lookup_widget (GtkWidget *widget,
const gchar *widget_name)
{
GtkWidget *parent, *found_widget;
for (;;)
{
if (GTK_IS_MENU (widget))
parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
else
parent = widget->parent;
if (!parent)
parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
if (parent == NULL)
break;
widget = parent;
}
found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
widget_name);
if (!found_widget)
g_warning ("Widget not found: %s", widget_name);
return found_widget;
}
For this to work, you have to do the following for every widget contained within a toplevel window:
g_object_set_data_full (G_OBJECT (toplevel), "name-of-widget", gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref);
and then the following once for each toplevel window:
g_object_set_data (G_OBJECT (toplevel), "name-of-toplevel", toplevel);
Seems to me to be more trouble than it's worth.
Glade-2 implements lookup_widget() in support.c and the header is support.h
Once the GLADE GUI is converted to C codes these files are generated automatically.

Detect which key is pressed in C

I'm trying to find a way to find out which key is pressed down in C. This will be in a graphical environment, written in GTK2, but I don't think the answer lies there. I think I might be able to do this using Xlib, but I haven't been able to find anything conclusive on this.
Does anyone have any suggestions on how to do this?
I've managed to catch a keypress using the follow code:
GtkWidget *window;
void gtk_widget_set_events(window,GDK_KEY_RELEASE_MASK);
g_signal_connect(window,"key_release_event",G_CALLBACK(hello),NULL);
However, I would like to identify which key is pressed. From the link posted by Aditya Kumar, I know the answer lies with using GdkEventKey, since it is a structure which has a keyval field, but I cannot seem to get the syntax right. What is the correct way of getting this number?
This is a method I've tried:
static void hello( GtkWidget *widget,
guint data ){
g_print ("Hello World, %d was pressed\n",data);}
I tried supplying "data" by doing this when I catch the key_release_event:
g_signal_connect(window,"key_release_event",G_CALLBACK(hello),GdkEventKey.keyval);
However, I get a compiler error like so:
hello.c:85:5: error: expected ‘)’ before ‘.’ token
hello.c:85:5: error: expected expression before ‘,’ token
You are correct with your original syntax.
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
Where the key_event function looks something like (note I am using the gdk_keyval_name to convert the keyval int value to a string for printing):
static gboolean
key_event(GtkWidget *widget,
GdkEventKey *event)
{
g_printerr("%s\n",
gdk_keyval_name (event->keyval));
return FALSE;
}
Here's a complete example program:
#include <gtk/gtk.h>
static gboolean
key_event(GtkWidget *widget,
GdkEventKey *event)
{
g_printerr("%s\n",
gdk_keyval_name (event->keyval));
return FALSE;
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
gtk_widget_show (window);
gtk_main ();
return 0;
}
while looking at the gdk reference manual i think you can capture the keyboard events using this unless you specifically want to have a 'C' program.
Here is the link to help you out.
http://www.gtk.org/api/2.6/gdk/gdk-Keyboard-Handling.html
event->keyval is a pointer to a struct, where keyval contains a integer value for the key pressed, this has been used above in a function gdk_keyval_name (event->keyval) which gets a actual name for the key.

Resources