I create popup context menu with rightclick at runtime, from treeview, based on words in selected sentence. Code:
//---- inpropper ------------
gboolean
menu_RELEASE(GtkWidget *menu, gpointer *user_data)
{
printf("released at %s\n", (char*)user_data);
return FALSE;
}
//---------------------------
//---- propper [SOLVED] -----
gboolean
menu_RELEASE(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
gtk_entry_set_text(GTK_ENTRY(entry1), (char*)user_data);
gtk_widget_grab_focus(entry1);
return FALSE;
}
//--------------------------
GtkWidget *create_art_menu(GtkWidget *button)
{
char *ntext;
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
if (gtk_tree_selection_get_selected(treesel, &model ,&iter))
{
gtk_tree_model_get(model, &iter, cNaziv, &ntext, -1);
GtkWidget *menu, *menu_item;
menu = gtk_menu_new();
char *sresult = NULL;
sresult = strtok(ntext, " ");
while(sresult != NULL)
{
if (strlen(sresult)>1)
{
menu_item = gtk_menu_item_new_with_label(sresult);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
g_signal_connect(G_OBJECT(menu_item), "button-release-event", G_CALLBACK(menu_RELEASE), (gpointer)sresult);
}
sresult = strtok(NULL, " ");
}
gtk_menu_attach_to_widget(GTK_MENU(menu), button, NULL);
gtk_widget_show_all(menu);
return menu;
}
return 0;
}
Signals are triggered and passes OK but I can't get string of clicked menu item in menu_RELEASE handler from user_data which I need for further action.
Q: How to get string of released menu item in menu_RELEASE handler based on showed code.
The reason is that the signature of callback which is connected to button-release-event is incorrect. The signature should be gboolean user_function(GtkWidget *widget,GdkEvent *event, gpointer user_data). Try changing gboolean menu_RELEASE(GtkWidget *menu, gpointer *user_data) to gboolean menu_RELEASE(GtkWidget *menu, GdkEvent *event, gpointer *user_data).
Alternatively, you can use g_signal_connect_swapped instead of g_signal_connect & change gboolean menu_RELEASE(GtkWidget *menu, gpointer *user_data) to gboolean menu_RELEASE(gpointer *user_data)
Additonally, be wary of what #Joachim Pileborg has already mention regarding strtok.
Hope this helps!
The result returned by the strtok function is a pointer to an internal static buffer, that will get overwritten on each call. If you want to save the result for use later, you have to create a duplicate (e.g. with the strdup function).
But watch out, doing this needs you to free the new string when done with it. for example if you remove the menu item, you need to free this buffer as well.
Related
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)
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 have a gtk2+ code in which I have a running button and a stopping one. I want that the stop button pause the RUN function (not to leave it) in a specific point until run button is pressed again, continuing in the same point.
The problem is that while loops block any kind of interaction with program interfaces and freezes.
void STOP(GtkWidget *widget, GObject *context_object_stop)
{
stop=1;
}
void RUN(GtkWidget *widget, GObject *context_object_run)
{
GtkEntry *buffer= g_object_get_data (context_object_run, "buffer");
GtkTextIter iter;
GtkTextMark *marker;
marker = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &iter, marker);
stop=0;
int i=0;
for (i=0; i<5000000; i=i+1)
{
while (stop==1)
{
//here is my problem
}
gchar * stuff = g_strdup_printf("%d""\n", i);
gtk_text_buffer_insert(buffer, &iter, stuff, -1);
g_free(stuff);
while (gtk_events_pending())
gtk_main_iteration();
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(wins), marker);
}
}
Any ideas to approach the solution?
EDIT; An approach of multithreading that does not stop running the main function:
stop=0;
int i=0;
pthread_t th1;
for (i=0; i<5000000; i=i+1)
{
void *StopRun(void *arg)
{
while (stop==1)
{
//here is my problem
}
}
if (stop==1)
{
pthread_create(&th1, NULL, (void*)StopRun, NULL);
}
gchar * stuff = g_strdup_printf("%d""\n", i);
gtk_text_buffer_insert(buffer, &iter, stuff, -1);
g_free(stuff);
while (gtk_events_pending())
gtk_main_iteration();
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(wins), marker);
}
Have a look the documentation and examples of gtk_events_pending. It says:
This can be used to update the UI and invoke timeouts etc. while doing some time intensive computation.
Could anyone help me? I have programming skills in C and I'm trying to program gui's using gtk. I wish, from firing an action (a callback function) from a widget (eg a button), I can change any condition or characteristic belonging to any other widget. Ie something like allow full visibility from within the callback function as if all variables in all gui widgets (say a single main application window) were global. How can I address the closest way to accomplish this? So far, the steps I tried to discover underlying concepts in programming with gtk were frustrating me, when I try to make something more complex than simple Hello World tutorial.I also tried using:
/* out of main */
struct data_widgets
{
struct data_widgets * myp;
gchar **loc ; // LOCAL name
gchar **rem ; // REMOTE name
gchar **pmte ; // Plain message to encrypt filename
gchar **lem ; // Local encrypted message filename
gchar **emr ; // Encrypted message received filename
gchar **pmr ; // Plain message received filename
gchar **lopk ; // Local owner public key filename
gchar **crpk ; // Current remote public key filename
};
int main(int argc, char *argv[])
{
gchar loc_str[100] = "*"; /* LOCAL name for filechoose filter */
gchar rem_str[100] = "*"; /* REMOTE name idem */
gchar pmte_str[100]= "plainmsgtoencrypt"; /* Plain message to encrypt filename */
gchar lem_str[100] = "localencmsg"; /* Local encrypted message filename */
gchar emr_str[100] = "encmsgreceiv"; /* Encrypted message received filename */
gchar pmr_str[100] = "plainreceiv"; /* Plain message received filename */
gchar lopk_str[100]= "locownpubkey"; /* Local owner public key filename */
gchar crpk_str[100]= "remotpubkey"; /* Current remote public key filename */
struct data_widgets mydata;
mydata.loc = &loc_str;
mydata.rem = &rem_str;
mydata.pmte = &pmte_str;
mydata.lem = &lem_str;
mydata.emr = &emr_str;
mydata.pmr = &pmr_str;
mydata.lopk = &lopk_str;
mydata.crpk = &crpk_str;
mydata.myp = &mydata;
/* in main */
....
/* in my callback */
struct data_widgets *pp = (struct data_widgets *) data;
/*passing gpointer data as &mydata.myp, and doing (*pp)->(any pointer) this try fail*/
From what I understood you want to access widgets from within the callback without having to carry around a bunch of globals. You have some option.
You can pack data and widgets inside a single struct and pass it as user_data to the callback.
struct snapshot {
struct data_widgets data;
GtkWidget *entry;
GtkWidget *box;
GtkWidget *label;
GtkWidget *whatever;
};
/* Now fill and use the above struct as user_data */
The GtkWidget fields should be initialized in the code you use to create the UI stuff.
You can also set a name for each relevant widget with gtk_widget_set_name() (Glade automatically sets a name on every element). Once you need a widget, just get it with gtk_widget_get_name().
static void a_callback(GtkWidget *widget, gpointer user_data)
GtkWidget *an_entry = NULL;
GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
if (gtk_widget_is_toplevel(toplevel))
an_entry = gtk_widget_get_name(toplevel, "name of the entry");
g_return_if_fail(an_entry != NULL);
/* ... do something with an_entry ... */
}
You can also traverse the widget hierarchy as if it was a DOM or directly bind your data to the widgets with g_object_set_data() or any valid mixture of the above.
Addendum
With g_object_set_data() you can attach arbitrary data to any GObject instance, e.g.:
gchar *text;
/* Bind some data to widget */
g_object_set_data(G_OBJECT(widget), "pmte", "plainmsgtoencrypt");
g_object_set_data(G_OBJECT(widget), "lem", "localencmsg");
text = g_object_get_data(G_OBJECT(widget), "pmte");
g_print("%s\n", text); /* Print "plainmsgtoencrypt" */
g_free(text);
text = g_object_get_data(G_OBJECT(widget), "lme");
g_print("%s\n", text); /* Print "localencmsg" */
g_free(text);
Code cleanup
Your code is messy in many ways: I suggest you forget what you learnt for C and restart from zero. Your data has one level of indirection more than what it is needed, myp is bogus, you are specifying size of arrays and initializing it.
Answering your comment: the following code is self-contained and does not throw the error you see.
#include <gtk/gtk.h>
struct data_widgets {
gchar **crpk;
};
void callback(GtkWidget *widget, gpointer user_data) {
struct data_widgets *data = user_data;
g_print("%s\n", data->crpk); /* Prints remotpubkey */
}
int main(int argc, char *argv[]) {
gchar crpk_str[100] = "remotpubkey";
struct data_widgets mydata;
mydata.crpk = &crpk_str;
callback(NULL, &mydata);
return 0;
}
The same code, cleaned up in a sane way:
#include <gtk/gtk.h>
typedef struct {
gchar *crpk;
} data_t;
void callback(GtkWidget *widget, gpointer user_data) {
data_t *data = user_data;
g_print("%s\n", data->crpk); /* Prints remotpubkey */
}
int main() {
data_t mydata;
mydata.crpk = "remotpubkey";
callback(NULL, &mydata);
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!