return filename from G_CALLBACK in GTK - c

Hey guys so I would like to return value of filename from function (or pointer) but Im to sure how to do it. My filename stores path to file name /home/username/file. So here is my main
gchar *filename = NULL;
button = GTK_WIDGET( gtk_builder_get_object( builder, "button1" ) );
g_signal_connect (button, "clicked", G_CALLBACK (show_dialog), &filename);
And show dialog look like this
static void
show_dialog ( GtkWidget *button,
gint response_id,
gpointer user_data )
/* Init filechoosedialog, builder etc */
{
gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechoosedialog));
}
Do I need to change static void show_dialog to gchar show_dialog and at end do I need to do return filename; and what else do I need to declare because Im getting compile error
warning: return makes integer from pointer without a cast
So I would like to add code like this to my main and to get value of filename
if filename != NULL
g_print ("Selected filename: %s\n", filename);

This sounds like a misunderstanding of event driven programming. You don't do things like this in main(), you do it in the event handler. In your example you would call g_print() from show_dialog().
If you want to do something more complex you'll need to know some application state: that's what the g_signal_connect() userdata pointer is for. As an example, if you want to set the filename as the text of a label, you would set a pointer to the label as the user data pointer and can then set the label text in the event handler.
More generically, the userdata pointer can be anything: e.g. a data structure that you can use to store the filename string. Typical usage is an application data struct that is allocated in main: The struct contains all "application global" variables (like filename) and a pointer to the struct is given to all GTK+ callbacks so all functions can access and modify the struct contents.
If the problem was using the userdata pointer, here's an example using just a pointer to the filename as userdata:
g_signal_connect (button, "clicked", G_CALLBACK (button_clicked_cb), &filename);
static void
button_clicked_cb (GtkWidget *button,
gint response_id,
gpointer user_data)
{
char **filename_ptr = (char**)user_data;
*filename_ptr = g_strdup ("newly allocated string that the filename pointer in main() stack will now point to");
}

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

Get text from GtkEntry with property "text"

I need to get text from a bunch of GtkEntries when a button click. I create a custom struct and pass it to the button's click callback. I don't want to use gtk_entry_get_text(*entry) since I need to pass the struct of GtkEntries.
typedef struct{
const gchar* id1;
const gchar* id2;
} EntryData;
static void on_click(GtkWidget *widget,
gpointer data) {
EntryData* d= (EntryData*)data;
printf ("Entry contents: %s\n", d->id1);
printf ("Entry contents: %s\n", d->id2);
}
int main(int argc,char *argv[]) {
// ....
GtkButton *button_create_hp;
GtkEntry *entry_id1;
GtkEntry *entry_id2;
gtk_init(&argc, &argv);
//...... widget and object initialization
gtk_entry_set_text(entry_ssd,"");
gchar *strval1="sl";
gchar *strval2="sl";
g_object_get(G_OBJECT (entry_id1), "text", &strval1,NULL);
g_object_get(G_OBJECT (entry_id2), "text", &strval2,NULL);
EntryData entryData={
.id1= strval1,
.id2= strval2
};
g_signal_connect (button_create_hp, "clicked", G_CALLBACK(on_click),&entryData);
gtk_main();
return 0;
}
I also tried with g_object_get_property (G_OBJECT (entry_id), "text", &val);
In both cases changed values not printed when the button clicked.
Can you suggest a proper way to get values and pass it from GtkEntries
It's not very obvious from the docs, but when you somehow modify text it may be moved to another location, making previous pointer invalid.
If you don't want to pass GtkEntries to your structures, you can update pointers when EntryBuffer emits "deleted-text" or "inserted-text" (or connect to GtkEntry's "notify::text")

Changing GTK label in C using signal_connect

Hello I am making GUI in GTK I have some menu items, and I am trying to change main label after clicking a mouse on specific menu element.
widgets[i][0] = gtk_menu_item_new_with_label(arrayOfStrings[i]);
//arrayOfStrings is : char** arrayOfStrings
gtk_menu_shell_append(GTK_MENU_SHELL(indicator_menu), widgets[i][0]);
I was trying this:
void set_main_label(GtkWidget *widget)
{
app_indicator_set_label(indicator, arrayOfString[2],arrayOfString[2]);
}
and after this I call it like:
g_signal_connect(widgets[i][0], "activate",G_CALLBACK(set_main_label), widgets[i][0]);
But my problem is that void set_main_label(void) must have void argument. And I need to pass there string (char*) which is stored in arrayOfStrings. What do you suggest? Now I can change label only to one specific string set in set_main_label function, but I cannot pass it as an argument into function, what do you suggest? .
This is what the user_data parameter is for. set_main_label() does not have a void argument list - check the documentation:
void
user_function (GtkMenuItem *widget,
gpointer user_data)
You can pass any argument you like into the callback via the user_data parameter. But it must be known at the time you connect the signal.
So you could do something like this:
void
set_main_label(GtkMenuItem *widget, gpointer user_data)
{
const char *label = (const char *)user_data;
app_indicator_set_label(indicator, label, label);
}
g_signal_connect(widgets[i][0], "activate",
G_CALLBACK(set_main_label), arrayOfString[2]);

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

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.

Resources