I have a gtk scale with range, and my goal is to capture when the user releases the click from the scale. (value-changed is called even when the slider is still changing, that's why it's not useful in my case).
so I used this signal.
The signal callback is working correctly, it's called when the mouse click is released, the problem is that the user pointer is kinda random. and changes at every call.
Here's my code:
static gboolean callback(GtkWidget *widget, GdkEventButton event, gpointer data) {
int *n = (int *)data;
printf("Pointer: %p\n", n);
printf("Value: %d\n", *n);
return FALSE;
}
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button_box;
GtkWidget *slider;
int *n = malloc(sizeof(int));
*n = 1000;
printf("Initialized pointer: %p\n", n);
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Window");
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_container_add(GTK_CONTAINER(window), button_box);
gtk_widget_add_events(window, GDK_BUTTON_RELEASE_MASK);
slider = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 0, 100, 1);
g_signal_connect(slider, "button-release-event", G_CALLBACK(callback), n);
gtk_container_add(GTK_CONTAINER(button_box), slider);
gtk_widget_show_all(window);
}
The output is:
Initialized pointer: 0x5594c31e5de0
Pointer: 0x5594c30a3e40
Value: 7
Pointer: 0x5594c30a3e40
Value: 7
Pointer: 0x5594c30a3da0
Value: 7
Pointer: 0x5594c30a3b20
Value: 7
Pointer: 0x5594c30a3bc0
Value: 7
Pointer: 0x5594c30a3bc0
Value: 7
Pointer: 0x5594c30a3bc0
Value: 7
Pointer: 0x5594c30a3c60
Value: 7
it's also the same case if I replace n with NULL like this:
g_signal_connect(slider, "button-release-event", G_CALLBACK(callback), NULL);
is still passes random pointers when it should've been (nil)
it doesn't make any sense.
Edit: the only messing function is main, that's the whole code:
int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
My main suspect is that GdkEventButton event should have been GdkEventButton *event
It is very rare that you pass full structures as parameters in C (and in Gtk)
Background
This is part of an exercise, in which I am creating a small network packet analyzer "as Wireshark".
Aim
I'm trying to store the Data of packets in a gtk_tree_store which can be revealed:
Code
structures used:
packet's data is stored in a trame.
typedef struct trame_{
unsigned int *tab;
int id;
int nb_ligne_erreur;
int nb_octet_erreur;
//couche ethernet
char *mac_dest;
char *mac_source;
char *ip_type;
//couche ip
char *version;
char *header_length;
int *total_length;
int *identification;
int *flags_frag_offset;
int TTL;
int protocol;
int *header_checksum;
int *ip_source;
int *ip_dest;
//couche tcp
int source_port;
int destination_port;
int stream_index;
int tcp_seg_len;
char* sequence_number;
int sequence_number_raw;
char *next_sequence_number;
char *acknowledgment_number;
int acknowledgment_number_raw;
char *tcp_header_length;
}trame;
chained list of trames with buttons (upper window, arbre (revealers on the lower window)
typedef struct cell_{
trame *obj;
GtkWidget *arbre;
GtkWidget *bouton;
struct cell_ *suiv;
int status_bouton_ip;
}cell;
this function create a new gtk_store_tree with all the data collected in a packet
void remplir_arbre(GtkWidget *pWidget, gpointer pData){
cell *tmp_cell=(cell *)pData;
GtkTreeStore *arbre=gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
GtkTreeIter header_ethernet;
GtkTreeIter contenu_ethernet;
GtkTreeIter header_IP;
GtkTreeIter contenu_IP;
gtk_tree_store_insert (arbre,&header_ethernet,NULL,-1);
gtk_tree_store_set(arbre, &header_ethernet,0,"Ethernet II",1,NULL, -1);
gtk_tree_store_insert (arbre,&contenu_ethernet,&header_ethernet,-1);
gtk_tree_store_set(arbre,&contenu_ethernet, 0, "Source:",1,tmp_cell->obj->mac_source, -1);
gtk_tree_store_insert (arbre,&contenu_ethernet,&header_ethernet,-1);
gtk_tree_store_set(arbre,&contenu_ethernet, 0, "Destination:",1,tmp_cell->obj->mac_dest, -1);
gtk_tree_store_insert (arbre,&contenu_ethernet,&header_ethernet,-1);
gtk_tree_store_set(arbre,&contenu_ethernet, 0, "type:",1,tmp_cell->obj->ip_type, -1);
gtk_tree_store_insert(arbre,&header_IP,NULL,-1);
gtk_tree_store_set(arbre,&header_IP,0,"Internet Protocol",1,"", -1);
gtk_tree_store_insert(arbre,&contenu_IP,&header_IP,-1);
gtk_tree_store_set(arbre,&contenu_IP,0,"IP Version:",1,tmp_cell->obj->version, -1);
gtk_tree_store_insert(arbre,&contenu_IP,&header_IP,-1);
gtk_tree_store_set(arbre,&contenu_IP,0,"IP Version:",1,tmp_cell->obj->version, -1);
gtk_tree_store_insert(arbre,&contenu_IP,&header_IP,-1);
gtk_tree_store_set(arbre,&contenu_IP,0,"IP Version:",1,tmp_cell->obj->version, -1);
tmp_cell->arbre = gtk_tree_view_new_with_model(GTK_TREE_MODEL(arbre));
GtkCellRenderer *renderer_col1;
GtkCellRenderer *renderer_col2;
GtkTreeViewColumn *column;
GtkTreeViewColumn *column_2;
char label[20];
sprintf(label,"trame n°%d",tmp_cell->obj->id);
renderer_col1 = gtk_cell_renderer_text_new();
renderer_col2 = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(label, renderer_col1, "text", 0, NULL);
column_2 = gtk_tree_view_column_new_with_attributes(NULL, renderer_col2, "text",1, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tmp_cell->arbre), column);
gtk_tree_view_append_column(GTK_TREE_VIEW(tmp_cell->arbre), column_2);
return;
}
this Function call remplir_arbre() and create and new revealer which is going to be stacked in the lower window
void ajout_liste(cell **liste,trame *elem,GtkWidget* box_haut, GtkWidget* box_bas){
char label[80];
sprintf(label,"%d\t%d:%d:%d:%d\t%d:%d:%d:%d",elem->id,(elem->ip_source)[0],(elem->ip_source)[1],(elem->ip_source)[2],(elem->ip_source)[3],(elem->ip_dest)[0],(elem->ip_dest)[1],(elem->ip_dest)[2],(elem->ip_dest)[3]);
GtkWidget* tmp_bouton=gtk_toggle_button_new_with_label(label);
if (elem->nb_ligne_erreur==-1){
gtk_widget_set_name(tmp_bouton,"button_dark_mode");
}else {
gtk_widget_set_name(tmp_bouton,"button_dark_mode_erreur");
}
cell *new_cell=(cell *) malloc(sizeof(cell));
GtkWidget *revealer = gtk_revealer_new();
new_cell->obj=elem;
new_cell->arbre=NULL;
new_cell->bouton=tmp_bouton;
new_cell->suiv=(*liste);
new_cell->status_bouton_ip=0;
*liste=new_cell;
remplir_arbre(NULL, new_cell);
gtk_widget_set_name(new_cell->arbre,"tree_dark_mode");
gtk_container_add(GTK_CONTAINER(revealer), new_cell->arbre);
gtk_revealer_set_reveal_child(GTK_REVEALER(revealer), FALSE);
gtk_box_pack_start(GTK_BOX(box_haut),tmp_bouton, FALSE,TRUE, 0);
gtk_box_pack_start(GTK_BOX(box_bas),revealer, FALSE, FALSE, 0); #box_bas is a gtk_box were all revealers are stacked ( the lower box on the screen)
gtk_widget_show (tmp_bouton);
gtk_widget_show_all(box_bas);
g_signal_connect(G_OBJECT(tmp_bouton), "clicked", G_CALLBACK(action_bouton_ip),new_cell);
g_object_bind_property(tmp_bouton, "active", revealer, "reveal-child", 1);
}
problem
Revealers don't show all of the rows of their child until all of the revealers are not activated:
all revealers activated
activated revealers hide non-activated other ones:
a revealer hiding another one
-all revealers non-activated
I was wondering if it was because i was using a gtk_box to stack revealers but it does not seems to be it.
Edit
I removed the revealer to see if i could at first , try to see all of the tree's childs and then find a solution to hide them.
i noticed some things :
i can always see all the childs of the second child of the tree ( Internet Protocol)
sometimes i can see all of the first child (Ethernet II ) rows without activating the second child ( Internet Protocol )
Solved
Finally i found another structure provided by GTK which fits to my needs.
Instead of using gtk_trees , i'm using some gtk_expanders combined with gtk_box to stack widgets into.
https://developer.gnome.org/gtk3/stable/GtkExpander.html
here is how it looks:
void remplir_ethernet(GtkWidget *box_ethernet,cell *tmp_cell){
char label[80];
GtkWidget *tmp_label=NULL;
sprintf(label,"\tSource\t\t: %s\n",(tmp_cell->obj->mac_source));
tmp_label=gtk_label_new(label);
gtk_label_set_xalign (GTK_LABEL(tmp_label),0);
gtk_box_pack_start(GTK_BOX(box_ethernet),tmp_label, FALSE, FALSE, 0);
sprintf(label,"\tDestination\t: %s\n",(tmp_cell->obj->mac_dest));
tmp_label=gtk_label_new(label);
gtk_label_set_xalign (GTK_LABEL(tmp_label),0);
gtk_box_pack_start(GTK_BOX(box_ethernet),tmp_label, FALSE, FALSE, 0);
sprintf(label,"\ttype\t\t: %s\n",(tmp_cell->obj->ip_type));
tmp_label=gtk_label_new(label);
gtk_label_set_xalign (GTK_LABEL(tmp_label),0);
gtk_box_pack_start(GTK_BOX(box_ethernet),tmp_label, FALSE, FALSE, 0);
}
void remplir_ip(GtkWidget *box_ip,cell *tmp_cell){
char label[80];
GtkWidget *tmp_label=NULL;
sprintf(label,"\tVersion\t\t: %s\n",(tmp_cell->obj->version));
tmp_label=gtk_label_new(label);
gtk_label_set_xalign (GTK_LABEL(tmp_label),0);
gtk_box_pack_start(GTK_BOX(box_ip),tmp_label, FALSE, FALSE, 0);
}
void remplir_arbre(GtkWidget *new_box, gpointer pData){
cell *tmp_cell=(cell *)pData;
GtkWidget *ethernet=gtk_expander_new ("Ethernet II");
gtk_expander_set_resize_toplevel (GTK_EXPANDER(ethernet),FALSE);
gtk_box_pack_start (GTK_BOX(new_box),ethernet,FALSE,FALSE,0);
GtkWidget *box_ethernet=gtk_box_new(FALSE,0);
gtk_orientable_set_orientation (GTK_ORIENTABLE (box_ethernet),GTK_ORIENTATION_VERTICAL);
gtk_container_add(GTK_CONTAINER(ethernet),box_ethernet);
remplir_ethernet(box_ethernet,tmp_cell);
GtkWidget *IP=gtk_expander_new ("Internet Protocol");
gtk_expander_set_resize_toplevel (GTK_EXPANDER(IP),FALSE);
gtk_box_pack_start (GTK_BOX(new_box),IP,FALSE,FALSE,0);
GtkWidget *box_ip=gtk_box_new(FALSE,0);
gtk_orientable_set_orientation (GTK_ORIENTABLE (box_ip),GTK_ORIENTATION_VERTICAL);
gtk_container_add(GTK_CONTAINER(IP),box_ip);
remplir_ip(box_ip,tmp_cell);
return;
}
I still don't know why gtk_tree did not work.
I get the contents of my textview and I want to display the contents in the terminal using the printf function. But have stange symbols (Why?):
// get textbuffer from textview end print value in terminal
void on_lower_button_clicked(GtkWidget *lower_button, GtkTextView *textview_1)
{
GtkTextBuffer *textbuffer_1;
textbuffer_1 = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_1));
printf("%s\n", textbuffer_1); // strange symbols from my buffer ...
}
int main(int argc, char *argv[])
{
GtkWidget *lower_button;
GtkBuilder *builder;
GtkWidget *window;
GError *error = NULL;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
if(!gtk_builder_add_from_file(builder, "template.ui", &error)) {
g_printerr("Error loading file: %s\n", error->message);
g_clear_error(&error);
return 1;
}
window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
lower_button = GTK_WIDGET(gtk_builder_get_object(builder, "lower_button"));
gtk_builder_connect_signals(builder, NULL);
// when I click on the button (lower_button) call
// on_lower_button_clicked function and transferred to her textview_1
g_object_unref(G_OBJECT(builder));
gtk_widget_show(window);
gtk_main();
return 0;
}
GtkTextBuffer is not a character array, it is a GTK object that can not be simply printed as text.
You need to extract the text from it if you want to print it or write it to file.
To do this, you will need to get a couple of GtkTextIter objects, and then use gtk_text_buffer_get_text.
Note, that if you have non English characters in your text, you may still have issues using printf, because the resulting text is UTF-8 encoded.
Here is an example code:
GtkTextIter start, end;
gchar *text;
gtk_text_buffer_get_start_iter(textview_1, &start);
gtk_text_buffer_get_end_iter(textview_1, &end);
text = gtk_text_buffer_get_text(textview_1, &start, &end, FALSE);
printf("%s\n",text);
g_free(text); //you need to clean up this buffer!
I am new on GTK...
I want to do hide the label at first and when I will click on the "click" button it will show the label.I used gtk_widget_hide(label)...bt it is not working.and will use fixed container don't change it.
here is my code ==>
#include <gtk/gtk.h>
void destroy(GtkWidget* widget,gpointer *data){
/*gtk_main_quit();*/
g_print ("hide\n");
}
int main(int argc, char *argv[])
{
GtkWidget *window,*button,*label,*fixed;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Demo");
gtk_widget_set_size_request(window,200,400);
gtk_container_set_border_width(GTK_CONTAINER(window),10);
fixed = gtk_fixed_new();
button = gtk_button_new_with_mnemonic("Click");
gtk_widget_set_size_request(button,20,20);
label = gtk_label_new("BOOM!!");
gtk_widget_hide(label);
g_signal_connect_swapped(G_OBJECT(button),"clicked",G_CALLBACK(destroy),NULL);
gtk_fixed_put(GTK_FIXED(fixed),button,0,0);
gtk_fixed_put(GTK_FIXED(fixed),label,30,30);
gtk_container_add(GTK_CONTAINER(window),fixed);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
use gtk_widget_hide() at end of gtk_widget_show_all(window)
because u have taken label in Fixed container and Fixed contain is in window.and then u called gtk_widget_show_all(window)thats means show the all contents that have in window....thats why have to use like this===>
#include <gtk/gtk.h>
void destroy(GtkWidget* label,gpointer *data){
/*gtk_main_quit();*/
g_print ("hide\n");
gtk_widget_show(label);
}
int main(int argc, char *argv[])
{
GtkWidget *window,*button,*label,*fixed;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Demo");
gtk_widget_set_size_request(window,200,400);
gtk_container_set_border_width(GTK_CONTAINER(window),10);
fixed = gtk_fixed_new();
button = gtk_button_new_with_mnemonic("Click");
gtk_widget_set_size_request(button,20,20);
label = gtk_label_new("BOOM!!");
g_signal_connect_swapped(G_OBJECT(button),"clicked",G_CALLBACK(destroy),label);
gtk_fixed_put(GTK_FIXED(fixed),button,0,0);
gtk_fixed_put(GTK_FIXED(fixed),label,30,30);
gtk_container_add(GTK_CONTAINER(window),fixed);
gtk_widget_show_all(window);
gtk_widget_hide(label);
gtk_main();
return 0;
}
I am using GTK in C and I would like to make a form in order to collect input from user. I use GTK_ENTRY in order to collect user's input.
Unfortunately I don't know how I can put the execution is "pause" in order to wait that user enters its input and resume it as soon as the input is ready.
Can you help me, please?
Thanks
#include <gtk/gtk.h>
static void on_button_clicked(GtkButton *button,gpointer data);
static void on_entry_activate(GtkEntry *entry,gpointer data);
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *entry;
GtkWidget *button;
GtkWidget *hbox;
gtk_init(&argc,&argv);
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"entry");
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(window),5);
hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5);
gtk_container_add(GTK_CONTAINER(window),hbox);
entry=gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox),entry,TRUE,TRUE,5);
button=gtk_button_new_with_label("Ok");
gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,0);
g_signal_connect(G_OBJECT(window),"destroy",
G_CALLBACK(gtk_main_quit),NULL);
g_signal_connect(G_OBJECT(button),"clicked",
G_CALLBACK(on_button_clicked),entry);
g_signal_connect(G_OBJECT(entry),"activate",/* when you press ENTER */
G_CALLBACK(on_entry_activate),NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static void on_button_clicked(GtkButton *button,gpointer data)
{
GtkWidget *entry=(GtkWidget *)data;
GtkWidget *dialog;
gchar buff[1024];
g_snprintf(buff,1024,"You input '%s' !",
gtk_entry_get_text(GTK_ENTRY(entry)));
dialog=gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,GTK_BUTTONS_OK,"%s",buff);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
gtk_entry_set_text(GTK_ENTRY(entry),"");
}
static void on_entry_activate(GtkEntry *entry,gpointer data)
{
g_printf("%s\n",gtk_entry_get_text(GTK_ENTRY(entry)));
}
This example is very simple. Input is ready when user press ENTER in entry or click OK BUTTON
The code is very easy to read, i think. Good luck!