gtk_widget_set_sensitive crashes program - c

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.

Related

How to pass 2 or more GTK widget to callback function

I have seen people pass a widget like this
static void on_button_click(GtkWidget *button, gpointer data) {
gtk_label_set_label(GTK_LABEL(data), "Hello, World!");
}
...
g_signal_connect(button, "clicked", G_CALLBACK(on_button_click), label);
but how do you pass 2 widgets like a label and an entry?
I want to write a calculator so I need to read from the entry, parse and write the results to the label when the user click (on) the button.
Thanks in advance for helping this noob.
The last argument (gpointer data) can point to whatever you want, so options are basically limitless.
I think in order from "quick hack for a demo app" up to "scalable/maintainable for large, complex applications", some of these options might be:
For a simple program with only a handful of widgets, I might be inclined to just store the GtkWidget pointers in global memory:
GtkWidget *window;
GtkWidget *label;
GtkWidget *btnEnter;
GtkWidget *btnClear;
GtkWidget *entry;
// copy entry to label for simple demo purposes
static void on_enter_button_click(GtkWidget *button, gpointer data) {
// data unused, just get global references to label + entry
gtk_label_set_label(GTK_LABEL(label), gtk_entry_get_text(entry));
}
// clear the label. maybe this is another function your calculator has
static void on_clear_button_click(GtkWidget *button, gpointer data) {
// data unused, just get global references...
gtk_label_set_label(GTK_LABEL(label), "");
}
int main(int argc, char**argv){
// Initialize all the widgets here
// register unique callbacks
g_signal_connect(btnEnter, "clicked", G_CALLBACK(on_enter_button_click), NULL);
g_signal_connect(btnClear, "clicked", G_CALLBACK(on_clear_button_click), NULL);
}
You can group these into a struct if uncomfortable using global memory or want slightly more ability to scale/refactor/reuse your code:
struct MyWidgets {
GtkWidget *window;
GtkWidget *label;
GtkWidget *btnEnter;
GtkWidget *btnClear;
GtkWidget *entry;
};
// copy entry to label for simple demo purposes
static void on_enter_button_click(GtkWidget *button, gpointer data) {
struct MyWidgets *widgets = (struct MyWidgets*) data;
gtk_label_set_label(GTK_LABEL(widgets->label), gtk_entry_get_text(widgets->entry));
}
// clear the label... maybe this is another function your calculator has?
static void on_clear_button_click(GtkWidget *button, gpointer data) {
struct MyWidgets *widgets = (struct MyWidgets*) data;
// data unused, just get global references...
gtk_label_set_label(GTK_LABEL(widgets->label), "");
}
int main(int argc, char**argv){
struct MyWidgets widgets;
// Initialize all the widgets here
// register unique callbacks
g_signal_connect(btnEnter, "clicked", G_CALLBACK(on_enter_button_click), &widgets);
g_signal_connect(btnClear, "clicked", G_CALLBACK(on_clear_button_click), &widgets);
}
But for something really simple, above is basically same as first example, but with extra steps :).
Another alternative could be to group widgets within any GtkContainer "class",which may fall out naturally in grouping objects into a particular layout, and then use something like gtk_widget_get_parent() to get parent container, then any one of the several methods on GtkContainer that allows iterating through children.
ANOTHER alternative is composite widgets. This tutorial demonstrates some of the concepts there and implements a single callback function for handling multiple widgets: https://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-20.html

GTK+ 2.0 C weird structure and g_signal_connect_swapped

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");

GtkButton to emit GDK_KEY_PRESS

I'm attempting to attach to a toolbar button a signal associated with a keystroke supported by GtkTextView (CTRL+a, CTRL+x, etc) using the following widget structure, signal connect, and callback:
typedef struct
{
GtkWidget *window;
GtkWidget *text_view;
}EditorWidgets;
//...
g_signal_connect(cut, "clicked", G_CALLBACK(cut_button_press), editor_widgets);
//...
static void cut_button_press(GtkWidget *button, EditorWidgets *editor_widgets)
{
UNUSED(button);
GdkEvent *event = gdk_event_new(GDK_KEY_PRESS);
event->key.window = gtk_widget_get_window(editor_widgets->window);
event->key.send_event = FALSE;
event->key.time = 0;
event->key.state = GDK_CONTROL_MASK;
event->key.keyval = GDK_KEY_x;
event->key.string = g_strdup("x");
event->key.length = strlen(event->key.string);
gtk_main_do_event(event);
gdk_event_free(event);
}
When run, GDK complains with the following:
(ex1:7856): Gdk-WARNING **: Event with type 8 not holding a GdkDevice. It is most likely synthesized outside Gdk/GTK+
Which lets me know I've created the signal improperly (I assume). However, there's very little out there about having buttons emit GDK signals, so I'm at a loss for what's missing here.
As a secondary question, I remember reading somewhere that there was a GDK #define for TIME_NOW or something, but I couldn't find it again. Any hints there?
1.use "key-press-event" instead of clicked, clicked was associated with mouse pointer and keyboard enter key, something like (in python):
def on_key_press (self, widget, event):
if event.keyval == 120:
print ('test')
2.GDK_CURRENT_TIME, define at Gdk.Event class

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.

Resources