I'm trying to make a test version of a C program in which the user can load a game level using the GTK file selector. It seems to work, and does open the fileselector window, but crashes when the user tries to select a file. The issue seems to be that the GtkWindow is not being recognized as a GtkWindow, despite being declared as:
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //initialize window
I then save it to the window pointer in the gui struct:
typedef struct gui gui_t;
struct gui {
GtkWidget *window;
GtkWidget *frame;
GtkWidget *menu_bar;
GtkWidget *drawing_area;
GtkWidget *vbox;
level_t *game;
};
Which is then passed to the load_menu callback below, which currently just attempts to print the selected filename:
void gui_load_menu(gpointer data) {
gui_t *gui = (gui_t *)data;
GtkWindow *window = (GtkWindow *)(gui->window);
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new("Load Level", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
fprintf(stdout, "%s", filename);
}
}
These were the particular runtime errors:
(guitest:4445): GLib-GObject-WARNING **: invalid uninstantiatable type guchar' in cast toGtkWindow'
(guitest:4445): Gtk-CRITICAL **: gtk_window_set_transient_for: assertion `parent == NULL || GTK_IS_WINDOW (parent)' failed
Any ideas?
Thanks!
You need to use the correct signature for the callback, which should be
void gui_load_menu(GtkWidget *widget, gpointer data)
Each callback can have a different signature and you need to look at the documentation for the signal you use to see what it is. I'm presuming in this case load is a GtkMenuItem, the documentation is here: http://developer.gnome.org/gtk3/3.2/GtkMenuItem.html#GtkMenuItem-activate
Related
I'm setting up a login window for something I need in a school project using GTK, CodeBlocks and Glade. It's just a simple form, username, password and a connect button. The problem is I can't get the value of the inputs because I can't send my builder to another function using the callbacks. I try to explain it as simple as I can, sorry for my bad English.
void verifyConnect(GtkButton *button, gpointer *builder){
GtkWidget *passwordInput;
GtkWidget *usernameInput;
passwordInput = GTK_WIDGET(gtk_builder_get_object(*builder, "passwordInput"));
usernameInput = GTK_WIDGET(gtk_builder_get_object(*builder, "usernameInput"));
const gchar *text1 = gtk_entry_get_text(GTK_ENTRY(passwordInput));
const gchar *text2 = gtk_entry_get_text(GTK_ENTRY(usernameInput));
g_print("Username : %s\n",text2);
g_print("Password : %s\n",text1);
}
void connectUser(){
GtkWidget *window;
GtkWidget *connectButton;
GtkBuilder *gtkBuilder = gtk_builder_new();
gtk_builder_add_from_file(gtkBuilder, "loginWindow.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(gtkBuilder, "loginWindow"));
connectButton = GTK_WIDGET(gtk_builder_get_object(gtkBuilder, "connectButton"));
g_signal_connect (connectButton, "clicked",G_CALLBACK(verifyConnect),>kBuilder);
g_object_unref(G_OBJECT(gtkBuilder));
gtk_widget_show(GTK_WIDGET(window));
}
For now I'm getting this error when clicking on the connect button.
I know what this error is, I just don't know how I can get my builder in the verifyConnect function:
(projet_c_gtk.exe:9928): Gtk-CRITICAL **: gtk_builder_get_object: assertion `GTK_IS_BUILDER (builder)' failed
(projet_c_gtk.exe:9928): Gtk-CRITICAL **: gtk_builder_get_object: assertion `GTK_IS_BUILDER (builder)' failed
(projet_c_gtk.exe:9928): Gtk-CRITICAL **: gtk_entry_get_text: assertion `GTK_IS_ENTRY (entry)' failed
(projet_c_gtk.exe:9928): Gtk-CRITICAL **: gtk_entry_get_text: assertion `GTK_IS_ENTRY (entry)' failed
Username : (null)
Password : (null)
The culprit is here:
g_signal_connect (connectButton, "clicked",G_CALLBACK(verifyConnect),>kBuilder);
The gtkBuilder variable is already a pointer, so passing its address to g_signal_connect() eventually makes the corresponding callback argument a pointer to a pointer. That would be all nice and dandy, except for one little detail: the memory address you passed points to an automatic variable. Automatic vars are stored on the stack, and are deallocated when the function that uses them returns. After that, other functions may allocate the same space for their needs and rewrite the hell out of it.
This is what you need to do to resolve that:
void verifyConnect(GtkButton *button, GtkBuilder *builder){
GtkWidget *passwordInput;
GtkWidget *usernameInput;
passwordInput = GTK_WIDGET(gtk_builder_get_object(builder, "passwordInput"));
usernameInput = GTK_WIDGET(gtk_builder_get_object(builder, "usernameInput"));
const gchar *text1 = gtk_entry_get_text(GTK_ENTRY(passwordInput));
const gchar *text2 = gtk_entry_get_text(GTK_ENTRY(usernameInput));
g_print("Username : %s\n",text2);
g_print("Password : %s\n",text1);
}
void connectUser(){
GtkWidget *window;
GtkWidget *connectButton;
GtkBuilder *gtkBuilder = gtk_builder_new();
gtk_builder_add_from_file(gtkBuilder, "loginWindow.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(gtkBuilder, "loginWindow"));
connectButton = GTK_WIDGET(gtk_builder_get_object(gtkBuilder, "connectButton"));
g_signal_connect(connectButton, "clicked", G_CALLBACK(verifyConnect), gtkBuilder);
g_object_unref(G_OBJECT(gtkBuilder));
gtk_widget_show(GTK_WIDGET(window));
}
When the argument is passed by value it ceases to depend on whatever is stored in its former location.
…aaaand BTW, are you really sure you need to free gtkBuilder inside connectUser()? You are using it in verifyConnect() as well, so you probably have to free it at the end of verifyConnect(), not at the end of connectUser().
I have a program written in C using the GTK library. In the GUI I have a set of radio buttons, and depending on what button is selected changes if an entry can be edited (or sensitive as gtk calls it).
I have made a struct with all the widgets that I need to pass to my signal handlers. It looks like this (with other widgets removed for simplicity).
typedef struct _gui_ctx {
// more widgets in here
GtkWidget *entry;
} gui_ctx;
And in main I define one like so
gui_ctx ctx;
My entry looks like
GtkWidget *entry = gtk_entry_new();
ctx.entry = entry; //add it to the ctx
My radio buttons look like
GtkWidget *radio_key = gtk_radio_button_new_with_label(NULL, "Key");
GtkWidget *radio_password = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_key), "Password");
GtkWidget *radio_random = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_key), "Random");
I attach the signal handlers as such
g_signal_connect(radio_key, "toggled", G_CALLBACK(use_key), &ctx);
g_signal_connect(radio_password, "toggled", G_CALLBACK(use_password), &ctx);
g_signal_connect(radio_random, "toggled", G_CALLBACK(use_random), &ctx);
The signal handlers are all basically the same. They are all the same type like so
void use_key(GtkWidget *widget, GdkEvent *event, gpointer data){
gui_ctx *ctx = (gui_ctx *) data;
GtkWidget *entry = ctx->entry;
gtk_widget_set_sensitive(entry, TRUE); // crashes here
}
The program crashes on the last line of the handler function. It says
Segmentation fault (core dumped)
I have tried to find why the issue is happening but it always crashes on that line. Both data and entry are not null so I don't know what's going wrong.
Here a short MCV to illustrate the problem I meet :
I call a dialog box from my main window.
I click on one of the buttons from the dialog (usual way I think)
If I click again on one button, dialog will not display again (I got a bunch of errors instead).
This doesn't happen of I use gtk_widget_hide instead.
(interfaces are designed with Glade3)
typedef struct {
GtkBuilder *builder;
gchar *stuff;
} Context;
void conDisplay(GtkWidget *g, gpointer userdata) {
GtkWidget *dlg, *parent;
Context *ctx=(Context *)userdata;
int ret=0;
g_printerr("clicked\n");
parent=GTK_WIDGET(gtk_builder_get_object(ctx->builder,(gchar *)"MCV"));
if (ctx->stuff) {
g_printerr("Already connected\n");
dlg=GTK_WIDGET(gtk_builder_get_object(ctx->builder,(gchar *)"question"));
gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(parent));
ret=gtk_dialog_run(dlg);
if (ret==-3) { // OK clicked
g_printerr("OK from Already connected\n");
}
else { g_printerr("Unknown\n"); }
gtk_window_set_transient_for(GTK_WINDOW(dlg),NULL);
gtk_widget_destroy(GTK_WIDGET(dlg));
} else {
dlg=GTK_WIDGET(gtk_builder_get_object(ctx->builder,(gchar *)"connect"));
gtk_window_set_transient_for(GTK_WINDOW(dlg),GTK_WINDOW(parent));
ret=gtk_dialog_run(dlg);
if (ret==-1) { // GO clicked
g_printerr("GO\n");
ctx->stuff="Hello";
}
else { g_printerr("Cancel\n"); }
gtk_window_set_transient_for(GTK_WINDOW(dlg),NULL);
gtk_widget_destroy(GTK_WIDGET(dlg));
}
}
int main(int argc, char **argv)
{
Context ctx;
GtkWidget *mainwin;
GtkWidget *btnCon;
GError *error=NULL;
/* Init GTK+ */
gtk_init(&argc,&argv);
ctx.builder=gtk_builder_new();
ctx.stuff=NULL;
// Load UI from file.
gtk_builder_add_from_file(ctx.builder,"mcv.glade",&error);
mainwin=GTK_WIDGET(gtk_builder_get_object(ctx.builder,(gchar *)"MCV"));
btnCon=GTK_WIDGET(gtk_builder_get_object(ctx.builder,(gchar *)"con"));
g_signal_connect(btnCon, "clicked", (GCallback)conDisplay, &ctx);
gtk_widget_show_all(mainwin);
gtk_main();
return 0;
}
Thanks for your help !
Best regards.
V.
From GtkBuilder:
A GtkBuilder holds a reference to all objects that it has constructed and drops these references when it is finalized. This finalization can cause the destruction of non-widget objects or widgets which are not contained in a toplevel window. For toplevel windows constructed by a builder, it is the responsibility of the user to call gtk_widget_destroy() to get rid of them and all the widgets they contain.
Since GtkDialog inherits from GtkWindow I would suggest separating mainwin and dlg GtkBuilders and gladefiles and use temporary GtkBuilder in conDisplay:
void conDisplay(GtkWidget *g, gpointer userdata) {
GtkWidget *dlg, *parent;
Context *ctx=(Context *)userdata;
GtkBuilder *builder = gtk_builder_new_from_file("dlg.glade"); //or even pass glade filename in Context
/* rest of the code */
gtk_widget_destroy(GTK_WIDGET(dlg));
g_object_unref(G_OBJECT(builder));
}
I have following declarations:
typedef struct window_and_search_entry
{
GtkWidget *window;
GtkWidget *search_entry;
} WINDOW_AND_SEARCH_ENTRY;
and then in main:
GtkWidget *window;
GtkWidget *search_entry;
...
WINDOW_AND_SEARCH_ENTRY window_and_search_entry;
window_and_search_entry.window = window;
window_and_search_entry.search_entry = search_entry;
and that two:
g_signal_connect_swapped(G_OBJECT(search_entry), "activate", G_CALLBACK(analyse), (gpointer) &window_and_search_entry);
g_signal_connect_swapped(G_OBJECT(do_it_button), "clicked", G_CALLBACK(analyse), (gpointer) &window_and_search_entry);
And I want to create function which takes text, and window, makes some operations on it and if an error occurs print it out with other function which takes window as parameter
ELEMENT *analyse(GtkWidget *widget, gpointer user_data)
{
//((WINDOW_AND_SEARCH_ENTRY *) user_data)->search_entry;
GtkWidget *a = ((WINDOW_AND_SEARCH_ENTRY*)(user_data))->search_entry;
const char *text = gtk_entry_get_text(GTK_ENTRY(a));
g_print("%s\n", text);
ELEMENT *heap[100];
int index = 0;
return heap[1];
}
I tried many variants but I get "Segmentation fault" after having something typed in entry_box followed by enter or button. I want to print the text to console. Please help me, thanks.
Your analyse callback requires g_signal_connect, not g_signal_connect_swapped. Also there is no need to cast pointers: the G_CALLBACK() macro already cast the whole function, so this would suffice:
ELEMENT *analyse(GtkWidget *widget, WINDOW_AND_SEARCH_ENTRY *data)
With g_signal_connect_swapped it would be:
ELEMENT *analyse(WINDOW_AND_SEARCH_ENTRY *data, GtkWidget *widget);
This swapped version is only a C convenience for already existing functions, e.g. you can do something like this:
g_signal_connect_swapped(G_OBJECT(search_entry), "activate",
G_CALLBACK(g_print), "Activate signal called");
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.