gtk+ 3.x key bindings - struggling - c

I've tried a few things and may be nearing a solution but here goes ...
on a (possibly realised) widget, has anyone got a good example of say an
GtkEntry widget receiving a ALT+ Down or CTRL + n key press which will raise
a "new" signal e.g. SIG-NEW on the widget. which I know how to catch with g_signal_connect.

I appended a minimal working example.
The important point is to connect the key-press-event of an GtkEntry-instance to a suitable callback. In that callback you have to extract the GdkEventKey struct that is a member of the GdkEvent struct which is a parameter of the callback function.
GdkEventKey contains all information you need to check which key+modifier was pressed.
Since i tested the code with gtk+-3.0 you may have to modify the GdkEventMask of the widget to receive key-press-event's. For gtk+-3.0 it seems that is already the default setting. If the callback isn't invoked you should enable it with gdk_window_set_events () (of course you have to invoke it upon the gdk window of the widget).
#include <gtk/gtk.h>
#include <glib.h>
gboolean
key_press_event_cb (GtkWidget * widget, GdkEvent * event,
gpointer data)
{
GdkEventKey key = event->key;
/* check modifier key */
/* on most keyboards GDK_MOD1_MASK is the Alt key */
if (key.state == GDK_MOD1_MASK) {
/* check for key that was pressed */
switch (key.keyval) {
case GDK_KEY_d:
g_print
("`Alt-d` deletes the content in the entry box\n");
gtk_entry_set_text (GTK_ENTRY (widget), "");
break;
}
}
/* check for unmodified key presses */
switch (key.keyval) {
case GDK_KEY_x:
g_print
("`x` deletes the content in the entry box\n");
gtk_entry_set_text (GTK_ENTRY (widget), "");
return TRUE;
break;
}
return FALSE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *entry;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
entry = gtk_entry_new ();
gtk_container_add (GTK_CONTAINER (window), entry);
gtk_widget_show_all (window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (entry, "key-press-event",
G_CALLBACK (key_press_event_cb), NULL);
gtk_main ();
return 0;
}

Related

Getting an error Xlib: extension "RANDR" missing on display ":24.0". gtk

I am receiving this error and not sure why...Please take a look at my buttons array, maybe I messed smth there, I am not sure...
The error i get is: Xlib: extension "RANDR" missing on display ":24.0".
and nothing happens after that, meaning my program doesnt run at all....
#include <gtk/gtk.h>
/* Our new improved callback. The data passed to this function
* is printed to stdout. */
static void callback (GtkWidget *widget, gpointer data)
{
system ((gchar *) data);
}
/* another callback */
static gboolean delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit ();
return FALSE;
}
int main (int argc, char *argv[])
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *box1;
/* This is called in all GTK applications. Arguments are parsed
* from the command line and are returned to the application. */
gtk_init (&argc, &argv);
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* This is a new call, which just sets the title of our
* new window to "My Assignments" */
gtk_window_set_title (GTK_WINDOW (window), "My Assignments");
/* Here we just set a handler for delete_event that immediately
* exits GTK. */
g_signal_connect (window, "delete-event",
G_CALLBACK (delete_event), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 50);
/* We create a box to pack widgets into. This is described in detail
* in the "packing" section. The box is not really visible, it
* is just used as a tool to arrange widgets. */
box1 = gtk_vbox_new (FALSE,0);
/* Put the box into the main window. */
gtk_container_add (GTK_CONTAINER (window), box1);
/*array is here*/
GtkWidget *button[2];
int i;
for (i=0; i<2; i++)
{
button[i]=gtk_button_new();
}
button[0] = gtk_button_new_with_label ("Run shellscript");
g_signal_connect (button[0], "clicked",
G_CALLBACK (callback), "shellscript");
gtk_box_pack_start (GTK_BOX (box1), button[0], TRUE, TRUE, 0);
gtk_widget_show(button[0]);
button[1] = gtk_button_new_with_label ("Run program2 ");
g_signal_connect (button[1], "clicked",
G_CALLBACK (callback), "program");
gtk_box_pack_start (GTK_BOX (box1), button[1], TRUE, TRUE, 0);
gtk_widget_show(button[1]);
gtk_widget_show (box1);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return 0;
}

How to use g_timeout_add?

I am making a program in C with GTK and Glade for a serial communication. I am having problem using g_timeout_add. For example I have a function serial_data() which contain my serial data and I have a button handler on_update_button_clicked(). So till now I have done that if update button is clicked, gtk_timeout should run. But it running just for one time.
on_update_button_clicked(GtkButton *Update_Button)
{
//2nd argument is serial_data function which contain actual data
g_timeout_add(250,serial_data,NULL);
}
where I am missing the point?
I have another button stop button. So i want that timeout should stop when stop button handler is clicked. How to do that.??
One more question to ask, I want to count the number of times timeout is running like a counter. So that I can display the numbers of counter. How is this possible.?
Please help thanks.
From the documentation, The function is called repeatedly until it returns FALSE. You can call on_update_button with a boolean argument to toggle the timeout call from being continually called, set it running when argument evaluates to TRUE, and delete the thread with g_source_remove(threadID) if argument is FALSE. Here's a demonstration:
// compiling with: gcc test.c `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0` -o test
#include <stdio.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
guint threadID = 0;
guint serial_counter = 0;
static gboolean
serial_data (gpointer user_data)
{
// do something
printf("counter: %d\n", serial_counter);
serial_counter++;
return user_data;
}
static void
on_update_button_clicked (GtkButton* button, gpointer user_data)
{
if (user_data == 1)
{
threadID = g_timeout_add(250, serial_data, user_data);
}
else if (user_data == 0)
{
g_source_remove(threadID);
threadID = 0;
}
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
gtk_init (&argc, &argv);
GtkWidget *update_button;
GtkWidget *stop_button;
GtkWidget *box;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "test.c");
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
update_button = gtk_button_new_with_label (_("Update"));
stop_button = gtk_button_new_with_label (_("Stop"));
gtk_box_pack_start (GTK_BOX (box), update_button, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box), stop_button, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box);
g_signal_connect (update_button, "clicked", G_CALLBACK (on_update_button_clicked), 1);
g_signal_connect (stop_button, "clicked", G_CALLBACK (on_update_button_clicked), 0);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
g_timeout_add() returns an event source id that you should store. You can use g_source_remove() with that id in your stop button handler to stop the timeout.
check the developer site
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-timeout-add
its quite explicit.
you can have a gpointer to a gboolean STOP, finish the serial_data func in return STOP, and make your stop button change that STOP = FALSE and it will stop calling on that function. Or something like that.

Print variable in GTK+ assistant

I want to ask the user in a GTK+ assistant for his name, save this name in a global variable and use this variable in the same assistant on a different site. My problem is that the assistant is completly created and changes on new sites have no effect.
Example:
I initialisize the global variable "name" with "empty". Now, the assistant create all sites but displays only the first site. The user writes down his name in the "entryfield" and the variable "name" now contains his name.
The assistant now displays the second site which should contain the users name, but it displays the string "empty".
I need to "refresh" this already created entry with the new variable.
Sorry for my bad english, I hope I can explain my problem a little bit. :)
Complete sample code:
#include <gtk/gtk.h>
#include <string.h>
static void entry_changed (GtkEditable*, GtkAssistant*);
static void assistant_cancel (GtkAssistant*, gpointer);
static void assistant_close (GtkAssistant*, gpointer);
char *name = "empty";
typedef struct {
GtkWidget *widget;
gint index;
const gchar *title;
GtkAssistantPageType type;
gboolean complete;
} PageInfo;
int main (int argc,
char *argv[])
{
GtkWidget *assistant, *entry, *label;
guint i;
PageInfo page[5] = {
{ NULL, -1, "Introduction", GTK_ASSISTANT_PAGE_INTRO, TRUE},
{ NULL, -1, NULL, GTK_ASSISTANT_PAGE_CONTENT, FALSE},
{ NULL, -1, NULL, GTK_ASSISTANT_PAGE_CONTENT, TRUE},
{ NULL, -1, "Confirmation", GTK_ASSISTANT_PAGE_CONFIRM, TRUE},
};
gtk_init (&argc, &argv);
/* Create a new assistant widget with no pages. */
assistant = gtk_assistant_new ();
gtk_widget_set_size_request (assistant, 450, 300);
gtk_window_set_title (GTK_WINDOW (assistant), "GtkAssistant Example");
g_signal_connect (G_OBJECT (assistant), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
page[0].widget = gtk_label_new ("This is an example of a GtkAssistant. By\n"\
"clicking the forward button, you can continue\n"\
"to the next section!");
page[1].widget = gtk_hbox_new (FALSE, 5);
page[2].widget = gtk_entry_new();
page[3].widget = gtk_label_new ("finish!");
/* Create the necessary widgets for the second page. */
label = gtk_label_new ("Your Name: ");
entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (page[1].widget), label, FALSE, FALSE, 5);
gtk_box_pack_start (GTK_BOX (page[1].widget), entry, FALSE, FALSE, 5);
gtk_entry_set_text(GTK_ENTRY(page[2].widget), name);
/* Add four pages to the GtkAssistant dialog. */
for (i = 0; i < 4; i++)
{
page[i].index = gtk_assistant_append_page (GTK_ASSISTANT (assistant),
page[i].widget);
gtk_assistant_set_page_title (GTK_ASSISTANT (assistant),
page[i].widget, page[i].title);
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant),
page[i].widget, page[i].type);
/* Set the introduction and conclusion pages as complete so they can be
* incremented or closed. */
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant),
page[i].widget, page[i].complete);
}
/* Update whether pages 2 through 4 are complete based upon whether there is
* text in the GtkEntry, the check button is active, or the progress bar
* is completely filled. */
g_signal_connect (G_OBJECT (entry), "changed",
G_CALLBACK (entry_changed), (gpointer) assistant);
g_signal_connect (G_OBJECT (assistant), "cancel",
G_CALLBACK (assistant_cancel), NULL);
g_signal_connect (G_OBJECT (assistant), "close",
G_CALLBACK (assistant_close), NULL);
gtk_widget_show_all (assistant);
gtk_main ();
return 0;
}
/* If there is text in the GtkEntry, set the page as complete. Otherwise,
* stop the user from progressing the next page. */
static void
entry_changed (GtkEditable *entry,
GtkAssistant *assistant)
{
const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
gint num = gtk_assistant_get_current_page (assistant);
GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
gtk_assistant_set_page_complete (assistant, page, (strlen (text) > 0));
name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
}
/* If the dialog is cancelled, delete it from memory and then clean up after
* the Assistant structure. */
static void
assistant_cancel (GtkAssistant *assistant,
gpointer data)
{
gtk_widget_destroy (GTK_WIDGET (assistant));
}
/* This function is where you would apply the changes and destroy the assistant. */
static void
assistant_close (GtkAssistant *assistant,
gpointer data)
{
g_print ("You would apply your changes now!\n");
gtk_widget_destroy (GTK_WIDGET (assistant));
}
in entry_changed, you will have to call gtk_entry_set_text(GTK_ENTRY(page[2].widget), name); again, as you only set the entry text once, which is the only thing that matters. Otherwise the default value you set when setting up the 3rd page sticks.

how to incorporate the "enter key" to a button press event

I've looked all over the place. Either I didn't look hard enough, or it is my lack of knowledge in C and GTK+. I am making a program similar to the program invoked when Alt+F2 is pressed. This is just for the learning experience. I have made a button called "button" in which you click it after typing in the program you want to run. I've been trying all day to program the button to also work when the "enter key" is pressed. Here is a part of my program responsible for invoking action to assigned widgets.
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
static GtkWidget *entry;
static gboolean kill_window(GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit();
return FALSE;
}
static void button_press(GtkWidget *widget, gpointer data)
{
const char *text = gtk_entry_get_text(GTK_ENTRY(entry));
//system("cd" text);
//printf("%s\n", text);
const char *text2 = "&";
char *concatenation;
concatenation = malloc(strlen(text)+2);
strcpy(concatenation, text);
strcat(concatenation, text2);
system(concatenation);
gtk_main_quit();
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button1;
GtkWidget *hbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("Run");
button1 = gtk_button_new_with_label("Cancel");
entry = gtk_entry_new();
hbox = gtk_vbox_new(FALSE, 2);
gtk_window_set_title(GTK_WINDOW(window), "Run");
g_signal_connect(window, "delete_event", G_CALLBACK(kill_window), NULL)
g_signal_connect(button, "clicked", G_CALLBACK(button_press), NULL);
g_signal_connect(button1, "clicked", G_CALLBACK(kill_window), NULL);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 100);
gtk_window_set_decorated(GTK_WINDOW(window), TRUE);
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 2);
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 2);
gtk_box_pack_start(GTK_BOX(hbox), button1, FALSE, FALSE, 2);
gtk_container_add(GTK_CONTAINER(window), hbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
All I need now is to get "button" to be invoked when pressing the "enter key". (Sorry if i sound redundant.)
So as I see you need to add "Enter Button" signal handler to the text box, not to the button.
Try to add
g_signal_connect(entry, "activate", G_CALLBACK(button_press), NULL);
(Sorry I cant check it right now)
You should catch the activate signal of your entry, and have the callback do the same as your button click handler.
g_signal_connect(entry, "activate", G_CALLBACK(button_press), NULL);
When you have a dialog like this GTK provides the concept of a default widget which is activated when you press Enter on any GtkEntry that has the activates-default property set to true. There is no need to explicitly connect a signal and the default widget is highlighted so the user can see which button will be activated when they press enter. To set it up add the following
g_object_set (G_OBJECT (button), "can-default", TRUE, "has-default", TRUE, NULL);
g_object_set (G_OBJECT (entry), "activates-default", TRUE, NULL);
/* Could do this instead of the second g_object_set
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); */
You could also use gtk_button_new_from_stock rather than gtk_button_new. You might want to check out g_spawn_command_line_async as well.
Maybe I am misunderstanding the question but capturing the "enter key" in C. Is done in the following way.
int enter_key = getch(stdin);
if(enter_key == '\r')
{
//Do whatever is necessary.
}
The '\r' is called a carriage return and can also be referenced using it's octagonal value '\015'. Also a newline('\n' '\012') may be returned instead of a carriage return so you might want to do the following instead.
if(enter_key == '\r' || enter_key == '\n')
{
//Do whatever is necessary
}

How to get the text of a button in GTK?

I am developing an application that has a numeric keypad and a text box when clicked on a button, text box shows the number.
I need to write a function to each button? Or you can pass a text and a widget as parameter?
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
void callback( GtkWidget *widget,
gpointer data )
{
gtk_entry_append_text(entry, text);
}
void create_button(GtkWidget* table,GtkWidget* entry,
int start_r,int end_r,
int start_c,int end_c,
char* label)
{
GtkWidget *button;
button = gtk_button_new_with_label (label);
g_object_set_data( G_OBJECT( button ),
"char", (gpointer)label );
g_signal_connect (button, "clicked",
G_CALLBACK (callback), entry);
gtk_table_attach_defaults (GTK_TABLE(table), button, start_c, end_c, start_r, end_r);
gtk_widget_show (button);
}
gint delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
gtk_main_quit ();
return(FALSE);
}
int main(int argc,char* argv[]){
GtkWidget *window;
//GtkWidget *button;
GtkWidget *table;
GtkWidget *entry;
//GtkWidget *label;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Armario");
g_signal_connect (GTK_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 20);
table = gtk_table_new (2, 2, TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
entry = gtk_entry_new();
gtk_entry_set_max_length(GTK_ENTRY(entry),10);
gtk_entry_set_placeholder_text(GTK_ENTRY(entry),"Teste");
gtk_table_attach_defaults (GTK_TABLE(table), entry, 0, 2, 1, 2);
gtk_widget_show(entry);
create_button(table,entry,0,1,0,1,"Botao");
gtk_widget_show (table);
gtk_widget_show (window);
gtk_main ();
return 0;
}
The answer to your question is yes, you can pass a widget in Gtk+ to a callback. Actually, the first parameter of the callback for the clicked signal is the button which received the signal (ie. usually the button that was clicked). As you can see in the sample code below, you can extract from the button its label and use it as text.
[...] /* In create_button... */
/* Make your buttons be notified when they are clicked */
g_signal_connect (button, "clicked", G_CALLBACK (on_button_clicked), entry);
[...]
/* Append the text in the button to the text entry */
void on_button_clicked (GtkButton *button, gpointer user_data)
{
GtkEntry *entry = user_data;
const gchar *text = gtk_button_get_label (button);
gint position = 0;
gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &position);
}
I'm using gtk_editable_insert_text because gtk_entry_append_text has been deprecated for a long time. Passing the "entry" parameter to the callback is possible by using the last parameter of g_signal_connect which allows you to specify some data that you need to access in your callback. This info is then made available to the callback in the "user_data" parameter.
Your exemple could also be improved by using gtk_widget_show_all, and I also don't see the point in calling g_object_set_data on the "char" property, as the text is already set in the label property (and retrieved with gtk_button_get_label).
Two options, that I can think of:
GTK widgets are really GObjects, so you can attach to them arbitrary pieces of data. See the functions g_object_set_data/g_object_set_data_full/g_object_get_data. So you can just add the text to the button as an attached data and retrieve it when needed.
You can pass any data you need to a callback by defining a struct with all the fields, and passing a pointer to it. If the struct cannot be declared statically, you can malloc it and use g_signal_connect_data to specify the function to release the data:
For example:
struct entry_and_text;
{
GtkWidget *w;
char *text;
};
void free_data(gpointer data, GClosure *closure)
{
free(data);
}
entry_and_text *data = (entry_and_text *)malloc(sizeof(entry_and_text));
data->w = entry;
data->text = label;
g_signal_connect_data (button, "clicked",
G_CALLBACK (callback), data, free_data, 0);

Resources