Emit custom gtk signal with variable as user data - c

I want to send a custom signal with user data. The user data (coming from a GtkEntry) is not filled upon connecting the signal, but is when the signal is emitted.
How can I emit a signal with the content of a GtkEntry as user data?
Right now I have a signal handler for the "standard" signal button_press_event. This handler reads the GtkEntry's and emits the custom signal. This is where I want de GtkEntry data to be sent as user data.
I do not want to send a pointer to GtkEntry, since the GtkEntry belongs to login_credentials_screen.c
I have a UI file:
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkWindow">
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="height-request">80</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="label" translatable="yes">Enter the correct user code
and company code to log in</property>
<property name="justify">center</property>
<style>
<class name="text_large"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="height-request">40</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin-top">5</property>
<property name="spacing">20</property>
<child>
<object class="GtkEntry" id="user_code_input">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">User code</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="company_code_input">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Company code</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkEventBox" id="login_button">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel">
<property name="width-request">250</property>
<property name="height-request">60</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="margin-top">15</property>
<property name="label" translatable="yes">Log in</property>
<style>
<class name="login_buttons"/>
<class name="text_normal"/>
</style>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
I have main.c:
#include <glib.h>
#include <gtk/gtk.h>
#include "login_credentials_screen.h"
void on_button_clicked(GtkWidget *widget, GdkEvent *event, gpointer data);
void main(void)
{
login_cred_subscribe_login_button_callback(on_button_clicked);
}
void on_button_clicked(GtkWidget *widget, GdkEvent *event, gpointer data)
{
printf("Userdata: %s\n", data);
}
And login_credentials_screen.c:
GtkBuilder *login_credentials_builder;
GObject *login_credentials_screen;
GObject *user_code_entry;
GObject *company_code_entry;
void init_login_credentials_screen(void)
{
login_credentials_builder = gtk_builder_new_from_file("login_credentials_screen.ui");
login_credentials_screen = gtk_builder_get_object(login_credentials_builder, "login_credentials_screen");
user_code_entry = gtk_builder_get_object(login_credentials_builder, "user_code_input");
company_code_entry = gtk_builder_get_object(login_credentials_builder, "company_code_input");
g_signal_connect(gtk_builder_get_object(login_credentials_builder, "login_button"), "button_press_event", G_CALLBACK(on_login_button_clicked), "login_button");
g_signal_new("login-button-clicked", G_TYPE_OBJECT, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
}
void login_cred_subscribe_login_button_callback(void *function)
{
g_signal_connect(gtk_builder_get_object(login_credentials_builder, "login_button"), "login-button-clicked", G_CALLBACK(function), NULL); //NULL needs to be something else?
}
void on_login_button_clicked(GtkWidget *widget, GdkEvent *event, gpointer data)
{
printf("%s\n", gtk_entry_get_text(GTK_ENTRY(user_code_entry)));
printf("%s\n", gtk_entry_get_text(GTK_ENTRY(company_code_entry)));
g_signal_emit_by_name(widget, "login-button-clicked", gtk_entry_get_text(GTK_ENTRY(company_code_entry)));
}

user_data is NULL because it's set during connection (that null in login_cred_subscribe_login_button_callback) and user_data doesn't hold any of signal's data or arguments. It's ususally a way of passing "receiver" to callback, take a look at this pseudo-code example:
Emitter struct{}
Receiver struct{}
emitter_emit(Emitter *self) {
g_signal_emit(self, "name")
}
receiver_new(Emitter *emitter) {
receiver = g_object_new(...)
g_signal_connect (emitter, "name", G_CALLBACK(receiver_receive), receiver)
}
receiver_receive(Emitter *emitter, gpointer user_data) {
receiver = (*Receiver)user_data;
}
The last argument of g_signal_connect is passed during the signal emission as the last argument of callback function.
Now, take a look at these lines from your code:
g_signal_connect(gtk_builder_get_object(login_credentials_builder, "login_button"), "login-button-clicked", G_CALLBACK(function), NULL); // 1
g_signal_emit_by_name(widget, "login-button-clicked", "text"); // 2
on_button_clicked(GtkWidget *widget, GdkEvent *event, gpointer data) // 3
when you emit your custom signal, the arguments are: widget from line 2, then "text" from line 2 and then NULL from line 1. They are passed in that order to a function which signature is on line 3 (obviously, it's wrong: the 2nd argument is not a GdkEvent*, it's const char*). Your string is in the second argument of the function.

I noticed that the g_signal_connect can be called with a variable (char * in this case) as user_data parameter, and the variable does not need to be set untill calling the emit.
This results in the following:
char user_code_string[20];
void login_cred_subscribe_login_button_callback(void *function)
{
g_signal_connect(gtk_builder_get_object(login_credentials_builder, "login_button"), "login-button-clicked", G_CALLBACK(function), user_code_string);
}
void on_login_button_clicked(GtkWidget *widget, GdkEvent *event, gpointer data)
{
strncpy(user_code_string, gtk_entry_get_text(GTK_ENTRY(user_code_entry)), 20);
g_signal_emit_by_name(widget, "login-button-clicked");
}
Upon connecting (g_signal_connect) the login-button-clicked-signal, the variable does not need to be set.
Before emitting the signal (g_signal_emit_by_name), the variable can be set.

Related

Binding Toggle Buttons to each other using Glade & GTK+ (in C)

I have two toggle buttons named RUN and KILL. When I toggle on (i.e. depress) the RUN button, I only want it to toggle off by depressing the KILL toggle button (NOT by toggling off the RUN button). I want any subsequent mouse clicks on the RUN button to do nothing unless the KILL button is depressed. Likewise, when the KILL button is toggled on, I only want it to toggle off by depressing the RUN button (again, NOT by toggling off the KILL button). I am not sure how to construct the event handlers that would bind the action of these two toggle buttons together. I am using GTK+ together with Glade and programming in C.
Since the GtkToggleButton is a generic button and it will toggle with all user interactions we must prevent it from toggling under certain conditions. In this case, the button after being toggled can't be toggled again on itself but via another toggle button. To achieve this, you must:
Prevent button events from toggling the button under certain conditions
Bind both buttons with inverted logic (mutually exclusive)
To achieve 1) we can connect a callback to the GtkWidget "button-press-event" signal and return according to the wanted conditions, with TRUE preventing the signal from propagating and FALSE otherwise.
Then, to handle 2), we can use g_object_bind_property for the GtkToggleButton "active" property with G_BINDING_INVERTED_BOOLEAN flag to get the desired behavior. Notice that we must set one of them active as a start condition.
So, a simple example could be:
#include <gtk/gtk.h>
gboolean on_toggle_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) {
return TRUE;
}
return FALSE;
}
void on_run_toggle_active(GObject *obj, GParamSpec *pspec, gpointer user_data) {
g_return_if_fail (user_data != NULL);
GtkLabel *label = GTK_LABEL(user_data);
GtkToggleButton *button = GTK_TOGGLE_BUTTON(obj);
if (gtk_toggle_button_get_active(button) == TRUE) {
gtk_label_set_text (label, "Running...");
} else {
gtk_label_set_text (label, "Idle");
}
}
gint main(gint argc, gchar **argv) {
GtkLabel *status;
GtkWindow *window;
GtkBuilder *builder;
GtkToggleButton *run_toggle;
GtkToggleButton *kill_toggle;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("gui.ui");
window = GTK_WINDOW(gtk_builder_get_object(builder, "window1"));
status = GTK_LABEL(gtk_builder_get_object(builder, "status"));
run_toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "toggle"));
kill_toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "kill"));
g_object_bind_property (G_OBJECT(run_toggle), "active", G_OBJECT(kill_toggle), "active", G_BINDING_INVERT_BOOLEAN);
g_object_bind_property (G_OBJECT(kill_toggle), "active", G_OBJECT(run_toggle), "active", G_BINDING_INVERT_BOOLEAN);
g_signal_connect(G_OBJECT(run_toggle), "button-press-event", G_CALLBACK(on_toggle_button_press_event), NULL);
g_signal_connect(G_OBJECT(kill_toggle), "button-press-event", G_CALLBACK(on_toggle_button_press_event), NULL);
g_signal_connect(G_OBJECT(run_toggle), "notify::active", G_CALLBACK(on_run_toggle_active), status);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
To simplify, I've outlined the user interface with glade (gui.ui):
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.18"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="row_spacing">20</property>
<child>
<object class="GtkLabel" id="status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Idle</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToggleButton" id="toggle">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="receives_default">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">media-playback-start-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Run</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="kill">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="active">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">user-trash-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Kill</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
<object class="GtkSizeGroup">
<widgets>
<widget name="label1"/>
<widget name="label2"/>
</widgets>
</object>
</interface>
Compile with:
gcc -o main main.c `pkg-config --cflags --libs gtk+-3.0`
And the output should be something like this:
The Toggle Buttons are mutually exclusive and pressing them while active won't have any visual effect.
PS: No keyboard handling is assumed, otherwise we must handle those signals and act accordingly.

Trouble hiding and showing widgets in response to event

Problem
I have a problem where closing a widget with the delete event, via gtk_widget_hide_on_delete fails to show the menu widget again via a swapped gtk_widget_show_all with the corresponding widget passed to it as an argument.
Background
I'm creating a program consisting of a selection menu with a number of button widgets. Pressing one button will hide the menu, and show a window widget containing a label and a TextEntry, the delete event of this window widget will hide the widget, and show the menu again.
Example program
I've created a minimal example for this problem. The code simply loads the ui via GtkBuilder and then enters the main gtk loop.
I rely on gtk_widget_show_all, gtk_widget_hide and gtk_widget_hide_on_delete, but when I close the exercise widget using the delete-event, the window disappears, but the menu widget isn't shown.
#include <gtk/gtk.h>
#include <stdio.h>
int main(int argc, char **argv)
{
GtkBuilder * builder;
GtkWidget * menu;
GError *error = NULL;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
if (!gtk_builder_add_from_file(builder, "example.glade", &error)) {
g_warning("%s", error->message);
g_free(error);
fprintf(stderr, "Failed to load build file");
}
menu = (GtkWidget *) gtk_builder_get_object(builder, "menu");
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(menu);
gtk_main();
return 0;
}
The XML file example.glade has been created using Glade.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="exercise">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
<child>
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="label" translatable="yes">A window where stuff will happen.</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="menu">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">button2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
The problem is in these two lines of your Glade file:
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
Looking at the manual page of gtk_widget_hide_on_delete(), we see:
Utility function; intended to be connected to the “delete-event” signal on a GtkWindow. The function calls gtk_widget_hide() on its argument, then returns TRUE.
If we look at the delete-event signal, we see:
Returns
TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
This means that after the gtk_widget_hide_on_delete() is called, TRUE is returned, and this stops the GTK runtime from calling gtk_widget_show_all().
To achieve what you want, you can use a custom-defined handler, as shown below:
Remove that two lines and replace with the following:
<signal name="delete-event" handler="my_custom_func" object="menu" swapped="no"/>
Add your custom handler to the C file:
G_MODULE_EXPORT gboolean
my_custom_func(GtkWidget *w, GdkEvent *e, gpointer u) {
gtk_widget_hide(w);
gtk_widget_show_all(GTK_WIDGET(u));
return TRUE;
}

Cannot toggle check boxes in tree view

I'm having a simple dialog with a table with 2 columns, one of which is a check box. I have added a GtkCellRendererToggle but that one is not clickable. I have added a onToggle-function which is never called, it seems.
The cell renderer is activatable and I have added a call to activate it a second time in the C code to be on the safe side but nothing helps. What am I doing wrong?
Here's the code:
void
on_button_delete_files_click (GtkTreeSelection * widget, gpointer user_data)
{
GtkDialog * dialog = NULL;
GtkWidget * file_choser;
char * msg = NULL;
GtkListStore * liststore = NULL;
GtkTreeIter iter;
GDir * dir = NULL;
char * filename = NULL;
if (!builder_delete_files_dialog) {
GError * error = NULL;
builder_delete_files_dialog = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder_delete_files_dialog, "deletedlg.glade", &error)) {
g_warning ("%s", error->message);
g_free (error);
exit (1);
}
}
//
// Get list store
//
liststore = GTK_LIST_STORE (gtk_builder_get_object (builder_delete_files_dialog, "podcast_file_liststore"));
//gtk_list_store_clear (liststore);
//
// Add all files
//
dir = g_dir_open (download_directory, 0, NULL);
if (NULL == dir) {
}
while (NULL != (filename = g_dir_read_name (dir))) {
if (NULL == g_strrstr (filename, ".mp3"))
continue;
gtk_list_store_append(liststore, &iter);
gtk_list_store_set (liststore, &iter,
TO_BE_DELETED, FALSE,
FILENAME, filename,
-1);
}
//
// nice try since stuff is not activatable
//
GtkCellRendererToggle * toggle = GTK_CELL_RENDERER_TOGGLE(gtk_builder_get_object (builder_delete_files_dialog, "cellrenderertoggle1"));
gtk_cell_renderer_toggle_set_activatable (toggle, TRUE);
dialog = GTK_WIDGET(gtk_builder_get_object (builder_delete_files_dialog, "dialog_delete_files"));
int rc = gtk_dialog_run (GTK_DIALOG(dialog));
switch (rc) {
case GTK_RESPONSE_OK:
case GTK_RESPONSE_CANCEL:
default:
break;
}
gtk_widget_hide (dialog);
__error:
FREE_POINTER(g_dir_close, dir);
}
void on_toggle_renderer_click (GtkCellRendererToggle * cell, char * tree_path, gpointer data)
{
g_print ("=====> Dingens clicked !!! <=====\n");
GtkTreeModel *model = (GtkTreeModel *)data;
GtkTreeIter iter;
GtkTreePath *path = gtk_tree_path_new_from_string (tree_path);
gboolean fixed;
/* get toggled iter */
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, TO_BE_DELETED, &fixed, -1);
/* do something with the value */
fixed ^= 1;
/* set new value */
gtk_list_store_set (GTK_LIST_STORE (model), &iter, TO_BE_DELETED, fixed, -1);
/* clean up */
gtk_tree_path_free (path);
}
And here's the XML file:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkImage" id="imageApply">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
<object class="GtkImage" id="imageDelete">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-delete</property>
</object>
<object class="GtkListStore" id="podcast_file_liststore">
<columns>
<!-- column-name TO_BE_DELETED -->
<column type="gboolean"/>
<!-- column-name FILENAME -->
<column type="gchararray"/>
<!-- column-name < -->
<column type="< Neue Spalte definieren >"/>
</columns>
</object>
<object class="GtkDialog" id="dialog_delete_files">
<property name="width_request">320</property>
<property name="height_request">300</property>
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="btnDelete">
<property name="label" translatable="yes">Delete Selected</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">imageDelete</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="btnClose">
<property name="label" translatable="yes">Close</property>
<property name="name">btnClose</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">imageApply</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="file_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
<property name="model">podcast_file_liststore</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection2"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
<property name="title" translatable="yes">Delete</property>
<child>
<object class="GtkCellRendererToggle" id="cellrenderertoggle1">
<signal name="toggled" handler="on_toggle_renderer_click" object="podcast_file_liststore" swapped="no"/>
</object>
<attributes>
<attribute name="active">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn2">
<property name="title" translatable="yes">File name</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-5">btnDelete</action-widget>
<action-widget response="-6">btnClose</action-widget>
</action-widgets>
</object>
</interface>
Again: The onToggle-Event handler is not being called when I click a check box. This makes me think that the cell is somehow not active.
Many thanks for every hint.
Greets
Kai
I got it working by making the GtkCellRendererToggle 'activatable' - ie adding the 'activatable' property with value True. – alexmurray
I found this question when searching for how to toggle the checkboxes in a GtkTreeView.
For those in the same boat, clicking on the checkbox in the rendered tree view will not automatically toggle the box, but it will emit the "toggled" signal.
Connect this signal to a callback function and in that function do whatever functionality should happen when the row is toggled.
/* Toggle callback */
void toggle_row(GtkCellRendererToggle *cell_render, gchar *path,
gpointer tree_view)
{
GtkTreeModel *model;
GtkTreeIter iter;
GValue toggle_state = G_VALUE_INIT;
g_value_init(&toggle_state, G_TYPE_INT);
model = gtk_tree_view_get_model(tree_view);
if(gtk_tree_model_get_iter_from_string(model, &iter, path))
{
if(gtk_cell_renderer_toggle_get_active(cell_renderer))
{
printf("Active\n");
g_value_set_int(&toggle_state, 0);
gtk_tree_store_set_value(GTK_TREE_STORE(model), &iter, IN_COL_TICK,
&toggle_state);
}
else
{
printf("Inactive\n");
g_value_set_int(&toggle_state, 1);
gtk_tree_store_set_value(GTK_TREE_STORE(model), &iter, IN_COL_TICK,
&toggle_state);
}
}
}
/* In the tree view creation function */
{
...
GtkTreeStore *tree_store;
GtkWidget *tree_view;
GtkCellRenderer *render;
GtkTreeViewColumn *column;
...
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store));
render = gtk_cell_renderer_toggle_new();
column = gtk_tree_view_column_new();
gtk_tree_view_column_pack_start(column, render, FALSE);
/* connect the active signal to the column in your model that stores
the checkbox state */
gtk_tree_view_column_add_attribute(column, render, "active",
CHECKBOX_COLUMN);
/* Give the callback the tree view
g_signal_connect(render, "toggled", G_CALLBACK(toggle_row), tree_view);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
...
}

GTK pass user data to callback using Glade

I notice that Glade only allows you to set an object to be passed within the user data part of a GTK callback.
Is there any way I can pass an integer value instead?
I have a set of menu items which I would like to point at the same callback function, however for a small section of the code I need to identify which menu item was the one which called the callback.
Note:
All my signals are setup automatically with glade_xml_signal_autoconnect, and I would perfer to keep it this way.
In my opinion with respect to glade and callbacks one have to say goodbye to the notion of passing just one single element to callbacks. And thus stop using glade in order to configure the user data that is passed to a specific callback.
I get used to pass a struct named App to all callbacks that contains a pointer to every ui element that is loaded from the ui definitions file and already instantiated by GtkBuilder. This also stops the tedious task in glade of clicking back and forth between widgets only to set up the user data of the callbacks. In addition to the ui elements, most of the time this struct contains further elements that are important at runtime on application level.
A benefit of this approach is that you are not tempted to think about how to implement an individual callback that should act upon more than one element which is often the case. Some people tackle this by grouping the widgets of interest into a container. In order to pass all widgets to the callback they just pass the container. Then in the callback they get the widgets by calling gtk_container_get_children or similar functions. This approach makes callbacks illegible and reduce the fun while editing the code.
If every callback has all elements available that should be manipulated at runtime you don't have to care about implementing a single callback since every callback shares the same structure.
Further i created a helper macro that defines a pointer to an already instantiated element with the name of its glade id. This way the elements definitions in the code are always in sync with those that are displayed in glade. That makes renaming of widgets very easy (substitute the name in all sources + the glade file).
To illustrate this approach i have appended files of a sample program. Don't be scared of the number of files. Dividing a program into logical units/modules makes programming much simpler. To get a quick view of the whole project i created a git repository on github:
https://github.com/o8i12398z12h9h/gtk-sample-app
Just compare my callbacks.c with your callback file(s). I would be interested to know how they compare with respect to legibility and structure and taking into account that you may have the element-ids from glade still in mind.
callbacks.c:
#include "app.h"
void
button1_clicked_cb (GtkButton * button, App * app)
{
GET_UI_ELEMENT (GtkEntry, entry1);
if (gtk_entry_get_text_length (entry1) == 0)
gtk_entry_set_text (entry1, "test");
else
gtk_entry_set_text (entry1, "");
}
void
button2_clicked_cb (GtkButton * button, App * app)
{
gboolean active;
GET_UI_ELEMENT (GtkSpinner, spinner1);
GET_UI_ELEMENT (GtkWidget, eventbox1);
g_object_get (G_OBJECT (spinner1), "active", &active,
NULL);
if (active) {
gtk_spinner_stop (spinner1);
gtk_widget_override_background_color (eventbox1,
GTK_STATE_FLAG_NORMAL,
app->
active_color);
}
else {
gtk_spinner_start (spinner1);
gtk_widget_override_background_color (eventbox1,
GTK_STATE_FLAG_NORMAL,
app->
inactive_color);
}
}
void
button3_clicked_cb (GtkButton * button, App * app)
{
GdkRGBA bg = { 0, 0, 1, 1 };
GET_UI_ELEMENT (GtkWidget, eventbox1);
gtk_widget_override_background_color (eventbox1,
GTK_STATE_FLAG_NORMAL,
&bg);
}
void
button4_clicked_cb (GtkButton * button, App * app)
{
const gchar *str;
GET_UI_ELEMENT (GtkLabel, label1);
str = gtk_label_get_text (label1);
if (strcmp (str, "label") == 0) {
gtk_label_set_text (label1, "NewText");
}
else {
gtk_label_set_text (label1, "label");
}
}
void
button5_clicked_cb (GtkButton * button, App * app)
{
GET_UI_ELEMENT (GtkWidget, button1);
GET_UI_ELEMENT (GtkWidget, button2);
GET_UI_ELEMENT (GtkWidget, button4);
g_signal_emit_by_name (button1, "clicked", app);
g_signal_emit_by_name (button2, "clicked", app);
g_signal_emit_by_name (button4, "clicked", app);
}
main.c:
#include "app.h"
int
main (int argc, char *argv[])
{
App *app;
app = (App *) g_new (App, 1);
gtk_init (&argc, &argv);
app_init (app);
GET_UI_ELEMENT (GtkWidget, window1);
gtk_widget_show_all (window1);
gtk_main ();
return 0;
}
app.c:
#include "app.h"
GObject *
app_get_ui_element (App * app, const gchar * name)
{
const gchar *s;
GSList *list;
list = app->objects;
do {
s = gtk_buildable_get_name (list->data);
if (strcmp (s, name) == 0) {
return list->data;
}
} while (list = g_slist_next (list));
return NULL;
}
void
app_init_colors (App * app)
{
GdkRGBA active_color = { 1, 0, 0, 1 };
GdkRGBA inactive_color = { 0, 1, 0, 1 };
app->active_color = g_new0 (GdkRGBA, 1);
app->inactive_color = g_new0 (GdkRGBA, 1);
app->active_color = gdk_rgba_copy (&active_color);
app->inactive_color = gdk_rgba_copy (&inactive_color);
}
void
app_init (App * app)
{
GError *err = NULL;
app->definitions = gtk_builder_new ();
gtk_builder_add_from_file (app->definitions,
UI_DEFINITIONS_FILE, &err);
if (err != NULL) {
g_printerr
("Error while loading app definitions file: %s\n",
err->message);
g_error_free (err);
gtk_main_quit ();
}
gtk_builder_connect_signals (app->definitions, app);
app->objects = gtk_builder_get_objects (app->definitions);
app_init_colors (app);
}
app.h:
#ifndef __APP__
#define __APP__
#include <gtk/gtk.h>
#define UI_DEFINITIONS_FILE "ui.glade"
#define GET_UI_ELEMENT(TYPE, ELEMENT) TYPE *ELEMENT = (TYPE *) \
app_get_ui_element(app, #ELEMENT);
typedef struct app_
{
GtkBuilder *definitions;
GSList *objects;
GdkRGBA *active_color;
GdkRGBA *inactive_color;
} App;
void app_init (App * );
GObject * app_get_ui_element (App * , const gchar * );
#endif
ui.glade:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="border_width">20</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">10</property>
<property name="column_spacing">20</property>
<child>
<object class="GtkSpinner" id="spinner1">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="width">2</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkEventBox" id="eventbox1">
<property name="height_request">50</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
<property name="width">2</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="width">2</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">label</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
<property name="width">2</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">10</property>
<property name="layout_style">center</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">toggle entry</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="button1_clicked_cb" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">toggle spinner + bg</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="button2_clicked_cb" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button3">
<property name="label" translatable="yes">set bg</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="button3_clicked_cb" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button4">
<property name="label" translatable="yes">toggle label</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="button4_clicked_cb" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button5">
<property name="label" translatable="yes">toggle everything</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="button5_clicked_cb" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
<property name="width">4</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator1">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
<property name="width">4</property>
<property name="height">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</interface>

Programmatically Adding Data to a GtkTreeView/GtkListStore Created in Glade 3.12.1

I've been teaching myself how to code in C and utilize GTK for writing applications in Linux, using Glade to design the UI before implementing it. I've been trying to utilize a GtkTreeView coupled with a GtkListStore to display data, but I seem to be running into issues. I can get my application to launch fine and it shows the window and dialog correctly, but I cannot figure out how to add rows of data to the List Store programmatically and have them appear in the Tree View; most tutorials I find seem to prefer to make the rows in Glade, or to design the whole interface through the code. With the code as it is I receive no errors when running the program, but I cannot see anything being added in GtkTreeView. I don't see any blank rows being added either.
By writing some code to forcibly generate an error, I can see that the signal for postingButton is being connected (I think) so that should be fine. I'm just missing something in my actual implementation of GtkTreeView. If anyone can help me out, I'd greatly appreciate it!
Edit: The GtkEntries that are present will be implemented later; I'm just trying to get data to show up at all.
C Code:
/* I'd give objects better names normally, no worries!
* Just goofing around for now.*/
#include <gtk-3.0/gtk/gtk.h> // Needed for interface.
#include <gtk-3.0/gdk/gdk.h>
#include <glib-2.0/glib-object.h>
void on_mainWindow_destroy(GObject *object, gpointer user_data)
{
gtk_main_quit();
}
void on_stupidButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_dialog_run(GTK_DIALOG(user_data));
}
void on_postingButton_clicked(GtkButton *button, gpointer *user_data)
{
GtkListStore *liststore1;
GtkWidget *treeview1; // I've tried defining this as a GtkTreeView as well.
GtkTreeIter iter;
GtkBuilder *listStoreBuilder;
listStoreBuilder = gtk_builder_new();
gtk_builder_add_from_file(listStoreBuilder,
"../testing_interface.glade", 0);
treeview1 = GTK_WIDGET(gtk_builder_get_object(listStoreBuilder,
"treeview1")); // I'd change this to GTK_TREE_VIEW if the
// above is a GtkTreeView.
liststore1 = GTK_LIST_STORE(
gtk_tree_view_get_model((GtkTreeView *)treeview1));
gtk_list_store_append(liststore1, &iter);
gtk_list_store_set(liststore1, &iter, 0, "c", 1, "d", -1);
gtk_builder_connect_signals(listStoreBuilder, 0);
g_object_unref(G_OBJECT(listStoreBuilder));
g_object_unref(G_OBJECT(liststore1));
}
void on_cancelButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_widget_destroy((GtkWidget *)user_data);
}
int main(int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *mainWindow, *dumbDialog;
GtkButton *stupidButton;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "../testing_interface.glade",
0);
mainWindow = GTK_WIDGET(gtk_builder_get_object(builder, "mainWindow"));
stupidButton = GTK_BUTTON(gtk_builder_get_object(builder, "stupidButton"));
dumbDialog = GTK_WIDGET(gtk_builder_get_object(builder, "dumbDialog"));
gtk_builder_connect_signals(builder, 0);
g_object_unref(G_OBJECT(builder));
gtk_widget_show(mainWindow);
gtk_main();
return 0;
}
Glade File (testing_interface.glade):
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="dumbDialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="postingButton">
<property name="label" translatable="yes">Post</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_postingButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancelButton">
<property name="label" translatable="yes">Cancel</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_cancelButton_clicked" object="dumbDialog" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">postingButton</action-widget>
<action-widget response="0">cancelButton</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name Testing -->
<column type="gchararray"/>
<!-- column-name Testing1 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="mainWindow">
<property name="can_focus">False</property>
<signal name="destroy" handler="on_mainWindow_destroy" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="height_request">183</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore1</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="testing1Col">
<property name="title" translatable="yes">column</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="testing2Col">
<property name="title" translatable="yes">column</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="stupidButton">
<property name="label" translatable="yes">button</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_stupidButton_clicked" object="dumbDialog" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Your code that appends rows to the tree view is basically okay, but several problems prevent it from working.
You are creating and populating a new builder on each entry to on_postingButton_clicked. This is obviously incorrect, because it means that you're creating a new tree and a new store on each click of the Post button. This is easily fixed by sending treeview1 as user_data to the on_postingButton_clicked callback. You do that already in dialog, so I simply modified <signal name="clicked" handler="on_postingButton_clicked" ...> in your XML to also include object="treeview1".
You are being too liberal with g_object_unref. gtk_tree_view_get_model doesn't increase the refcount of its model, so you shouldn't unref the liststore you get. Unrefing the builder in main is probably a bad idea if you want to pass it around and retrieve objects from it (and it's a singleton anyway).
You're supposed to #include <gtk/gtk.h>, without the intervening gtk-3.0 directory. If your compilation fails without that, you are probably not setting up pkg-flags correctly.
Here is a modified version of your code that works for me. It requires XML to be modified as described above.
/* compile with:
gcc -O2 -Wall glade-test.c $(pkg-config gtk+-3.0 gmodule-export-2.0 --cflags --libs) */
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib-object.h>
void on_mainWindow_destroy(GObject *object, gpointer user_data)
{
gtk_main_quit();
}
void on_stupidButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_dialog_run(GTK_DIALOG(user_data));
}
void on_postingButton_clicked(GtkButton *button, gpointer *user_data)
{
GtkTreeIter iter;
GtkTreeView *treeview1 = GTK_TREE_VIEW(user_data);
GtkListStore *liststore1 = GTK_LIST_STORE(gtk_tree_view_get_model(treeview1));
gtk_list_store_append(liststore1, &iter);
gtk_list_store_set(liststore1, &iter, 0, "c", 1, "d", -1);
}
void on_cancelButton_clicked(GtkButton *button, gpointer *user_data)
{
gtk_widget_destroy((GtkWidget *)user_data);
}
int main(int argc, char *argv[])
{
GtkBuilder *builder;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "testing_interface.glade", 0);
gtk_builder_connect_signals(builder, 0);
gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "mainWindow")));
g_object_unref(G_OBJECT(builder));
gtk_main();
return 0;
}

Resources