Related
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 am writing an app on raspberry in gtk+3/C which requires a virtual numpad (e.g 0-9, backspace and enter). I will use it with a touch screen, so no keyboard or mouse available (just like a kiosk).
I am adopting this code which allows me to use button press to emulate the number and display to an entry, however I am stuck at giving it the backspace function (go back and delete one previous char) and enter function (e.g when I'm done with input, press that button will help me to get back to the main screen).
/*
gcc -Wall keyboard1.c -o keyboard1 `pkg-config --cflags --libs gtk+-3.0`
Tested with GTK3.22 and GTK3.22 on Ubuntu18.04
*/
#include<gtk/gtk.h>
struct key{
gint id;
GtkWidget *button;
};
static const gchar letters[18]="QWERTYASDFGHZXCVBN";
//Need single chars as strings.
static gchar single_char[2]={'A', '\0'};
static void button_clicked(GtkWidget *button, gpointer *user_data)
{
gpointer *button_index=g_hash_table_lookup((GHashTable*)user_data[0], button);
g_print("Button index %i\n", (gint)(*button_index));
gint index=(gint)(*button_index);
single_char[0]=letters[index];
gchar *string=g_strdup_printf("%s%s", gtk_entry_get_text(GTK_ENTRY(user_data[1])), single_char);
gtk_entry_set_text(GTK_ENTRY(user_data[1]), string);
g_free(string);
}
int main(int argc, char *argv[])
{
gtk_init (&argc, &argv);
gint i=0;
gint j=0;
GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Keyboard");
gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *entry=gtk_entry_new();
gtk_widget_set_hexpand(entry, TRUE);
//Save buttons in an array.
struct key k1;
GArray *keyboard=g_array_new(FALSE, FALSE, sizeof(struct key));
for(i=0;i<18;i++)
{
single_char[0]=letters[i];
k1.id=i;
k1.button=gtk_button_new_with_label(single_char);
g_array_append_val(keyboard, k1);
}
//A hash table to look up array index values.
struct key *p1=NULL;
GHashTable *hash_table=g_hash_table_new(NULL, NULL);
for(i=0;i<18;i++)
{
p1=&g_array_index(keyboard, struct key, i);
g_hash_table_insert(hash_table, p1->button, &(p1->id));
}
gpointer user_data[2]={hash_table, entry};
GtkWidget *grid1=gtk_grid_new();
for(i=0;i<3;i++)
{
for(j=0;j<6;j++)
{
p1=&g_array_index(keyboard, struct key, i*6+j);
gtk_grid_attach(GTK_GRID(grid1), p1->button, j, i, 1, 1);
g_signal_connect(p1->button, "clicked", G_CALLBACK(button_clicked), user_data);
}
}
GtkWidget *scroll=gtk_scrolled_window_new(NULL, NULL);
gtk_widget_set_vexpand(scroll, TRUE);
gtk_widget_set_hexpand(scroll, TRUE);
gtk_container_add(GTK_CONTAINER(scroll), grid1);
GtkWidget *expander=gtk_expander_new("Keyboard");
gtk_widget_set_vexpand(expander, TRUE);
gtk_widget_set_hexpand(expander, TRUE);
gtk_container_add(GTK_CONTAINER(expander), scroll);
GtkWidget *grid2=gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid2), expander, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid2), entry, 0, 1, 1, 1);
gtk_container_add(GTK_CONTAINER(window), grid2);
gtk_widget_show_all(window);
gtk_main();
g_hash_table_destroy(hash_table);
g_array_free(keyboard, TRUE);
return 0;
}
Here is the link to the post.
I have tried to replace a char in the gchar letters[18]="QWERTYASDFGHZXCVBN"; with \b, \n and \t as to replace backspace, newline and tab, but only \t works. \b gave me a strange symbol:
Could you give me suggestions on how to do it. Thank you very much!
You seem to confuse two things: gtk_entry_set_text sets the caption of a GTK element to a string of characters. It does not interpret it's characters.
That's why gtk_entry_set_text works well with non-control characters but stuck at \b. You had to send a GtkEvent using gtk_propagate_event to handle this properly (see here and here). \n is not a control character is this manner: It's possible that the GTK element your writing to just doesn't support newlines and Return would be interpreted as confirmation.
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!
I have an application that is attempting to do the following:
Create a GTK2 top level main window
Add a fixed frame into the main window for absolute positioning of widgets
Create a matrix of GtkImages that will be used to display animated GIFS and static JPEGS
On start-up the static JPEGS picked randomly from a list will fill the matrix
When an event happens the matrix will be filled with animated GIFS
When the animation is over possibly different JPEGS will again be displayed in the matrix
Run time errors are happening only when two or more of the randomly selected JPEGS are placed in a row of the matrix.
Here is an example of such a run time error:
(wrong:3909): Gtk-WARNING **: Can't set a parent on widget which has a parent
If each image of the row are unique no run time errors occur.
Code snippets and run time output are as follows:
/*
* Compile me with:
* gcc -Wall -o wrong wrong.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)
*/
/* header includes */
/**** prototypes ****/
/********************/
typedef struct
{
unsigned int pixel_width, pixel_height;
gchar fileName[20];
GtkWidget *image;
}symbol_t;
symbol_t symbols[] =
{
{ 118, 107, "images/LO.jpg", NULL },
{ 118, 107, "images/L1.jpg", NULL },
{ 118, 107, "images/L2.jpg", NULL },
{ 118, 107, "images/L3.jpg", NULL },
{ 118, 107, "images/H1.jpg", NULL },
{ 118, 107, "images/H2.jpg", NULL },
{ 118, 107, "images/H3.jpg", NULL },
{ 118, 107, "images/H4.jpg", NULL },
{ 118, 107, "images/H5.jpg", NULL }
};
GtkWidget *frame; /* for absolute positioning of widgets */
GtkWidget *window;
int Init( void )
{
/* initialize random number generator */
}
static void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
GtkWidget *SetupWindow(gchar *data, const gchar *filename)
{
/* setup top-level window setting the background to the image contained
in *filename and return window widget
*/
return(window);
}
int main (int argc, char *argv[])
{
unsigned int y, i, pos_x, pos_y;
gtk_init (&argc, &argv);
Init(); // init random number generator
window = SetupWindow("Broken", "images/background.jpg");
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
frame = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), frame);
/* setup symbol jpgs */
for( i = 0; i < 9; i++ )
{
/* load each symbol image into memory */
symbols[i].image = gtk_image_new_from_file( symbols[i].fileName );
}
/* display some symbols */
pos_y = 150;
pos_x = 187;
for( y = 0; y < 5 ; y++ ) /* first row - 5 symbols */
{
i = (unsigned int)(random()%9);
printf("Symbol[%d] [%s]\n", i, symbols[i].fileName);
gtk_fixed_put(GTK_FIXED(frame), symbols[i].image, pos_x, pos_y);
pos_x += symbols[i].pixel_width;
}
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
Run time errors when two or more matching symbols ( images ) are placed on the row:
[chim] ~/source/matrix > ./wrong
Symbol[1] [images/L1.jpg]
Symbol[7] [images/H4.jpg]
Symbol[0] [images/LO.jpg]
Symbol[7] [images/H4.jpg]
(wrong:3909): Gtk-WARNING **: Can't set a parent on widget which has a parent
Symbol[5] [images/H2.jpg]
(wrong:3909): Gtk-CRITICAL **: gtk_widget_destroy: assertion `GTK_IS_WIDGET (widget)' failed
(wrong:3909): Gtk-CRITICAL **: gtk_widget_destroy: assertion `GTK_IS_WIDGET (widget)' failed
When this occurs some of the images in the row are empty ( white ).
Output when no matching symbols ( images ) are placed on the row:
[chim] ~/source/matrix > ./wrong
Symbol[1] [images/L1.jpg]
Symbol[6] [images/H3.jpg]
Symbol[3] [images/L3.jpg]
Symbol[0] [images/LO.jpg]
Symbol[4] [images/H1.jpg]
And in this case all images are displayed properly.
Any suggestions about how to fix and what I might be doing wrong?
Once you place the image into another widget, it becomes owned and managed by that (parent) widget -- you can't add it to more than one widget.
The simple way to get this to work is to load the image with gtk_image_new_from_file() each time you want to add it to the window. If you don't want to do that, maybe you can use something like gtk_image_new_from_image() to copy the image prior to adding it to the widget.