GTK - How to pass an argument to a GtkEventBox - c

This code make a program that create a window with label, if you click the label, the program executes an fprintf of buffer passed as an argument of g_signal_connect(G_OBJECT(eventbox), "button_press_event", G_CALLBACK(on_event_clicked), buffer). Previously the program put in buffer the string "Hello Word" and then the program should print this message, but maybe the program print only garbled char. Where I'm wrong?
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
void on_event_clicked (GtkWidget* widget, gpointer user_data);
int main (int argc, char **argv) {
GtkWidget *window;
GtkWidget *eventbox;
GtkWidget *label;
char* buffer = malloc(sizeof(char)*10);
strcpy(buffer, "Hello Word\0");
gtk_init (&argc,&argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
label = gtk_label_new ("Hello Word");
eventbox = gtk_event_box_new ();
gtk_container_add (GTK_CONTAINER(eventbox), label);
gtk_container_add (GTK_CONTAINER(window), eventbox);
gtk_widget_show_all (window);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(eventbox), "button_press_event",
G_CALLBACK(on_event_clicked), buffer);
gtk_main();
return 0;
}
void on_event_clicked (GtkWidget *widget, gpointer user_data) {
char* pn = user_data;
fprintf(stderr, "%s\n", pn);
}

Your prototype for on_event_clicked() is wrong, it doesn't match what GTK+ expects.
It should be:
gboolean user_function (GtkWidget *widget, GdkEvent *event, gpointer user_data);
You need to add the missing argument to your function, and also deal with the requirement for a return value. Remember to read the signal documentation seriously.

Related

"key-release-event" not triggered

Consider the following code:
#include <gtk/gtk.h>
static void stop(GtkWidget *window, GdkEventKey *key, gboolean *key_held)
{
*key_held = FALSE;
g_print("stopped!\n");
}
static void counter(GtkWidget *window, GdkEventKey *key, gpointer user_data)
{
gboolean key_held = TRUE;
gulong signal_ID = g_signal_connect(window, "key-release-event", G_CALLBACK(stop), &key_held);
for (unsigned long int i = 0;key_held;i++)
{
g_print("%li\n", i);
}
g_signal_handler_disconnect(window, signal_ID);
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_add_events(window, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "key-press-event", G_CALLBACK(counter), NULL);
gtk_widget_show(window);
gtk_main();
}
It's simple: the counter starts to count from 0 when the user presses a key and continues to count until the user release the key...
Or that's at least how it's supposed to work. What actually happens is that when a user presses a key, the counter starts and doesn't stop when the user release the key. The only way to stop counting is to terminate the program. Also, not only the "key-release-event" is not triggered but "delete-event" isn't too: I have to press Ctrl+C to terminate the program.

gtk+ 3.x key bindings - struggling

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;
}

gtk+ vte scrollback not working

gtk+ ver 2.24.8
vte ver 0.28.2
I just starting out creating a terminal application, however, none of the examples I have found online (5) have working scrollback. Is there a problem with scrollback in vte or is it something I'm not seeing? Here is one example:
#include <gtk/gtk.h>
#include <vte/vte.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <gdk/gdkkeysyms.h> // includes GDK_q
/* gcc -Wall -g term.c -o term `pkg-config --cflags --libs gtk+-2.0 vte` */
long size;
char *buf;
char *ptr;
gboolean key_press_win_main (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
void quit_activated();
static gboolean delete_event(GtkWidget *,GdkEvent *);
int main( int argc, char *argv[] )
{
size = pathconf(".", _PC_PATH_MAX);
if ((buf = (char *)malloc((size_t)size)) != NULL) ptr = getcwd(buf, (size_t)size);
GtkWidget *window_main;
GtkWidget *vbox;
GtkWidget *vte;
GtkWidget *notebook;
GtkWidget *scrolled_window;
GtkWidget *label;
gtk_init (&argc, &argv);
window_main = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window_main), "Caraterm v0.0.1");
vbox = gtk_vbox_new(FALSE,0);
gtk_container_add (GTK_CONTAINER (window_main), vbox);
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);
gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
label = gtk_label_new ("term1");
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled_window, label);
vte = vte_terminal_new();
vte_terminal_set_background_transparent(VTE_TERMINAL(vte), FALSE);
vte_terminal_set_size(VTE_TERMINAL(vte), 80, 45);
vte_terminal_set_scrollback_lines(VTE_TERMINAL (vte), -1); /* infinite scrollback */
vte_terminal_fork_command(VTE_TERMINAL(vte), NULL, NULL, NULL, ptr, TRUE, TRUE,TRUE);
vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL (vte), TRUE);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), vte);
printf("%s\n", vte_terminal_get_emulation(VTE_TERMINAL (vte)));
g_signal_connect(G_OBJECT(window_main),"destroy",G_CALLBACK(quit_activated),NULL);
g_signal_connect(G_OBJECT(window_main),"delete_event",G_CALLBACK(delete_event),NULL);
g_signal_connect (G_OBJECT (window_main), "key_press_event", G_CALLBACK (key_press_win_main), NULL);
gtk_widget_show (label);
gtk_widget_show (notebook);
gtk_widget_show (scrolled_window);
gtk_widget_show (vte);
gtk_widget_show (vbox);
gtk_widget_show (window_main);
gtk_main ();
return 0;
}
gboolean key_press_win_main (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
switch (event->keyval)
{
case GDK_q:
if (event -> state & GDK_CONTROL_MASK)
{
printf("entered q\n");
quit_activated();
}
break;
default:
return FALSE;
}
return FALSE;
}
void quit_activated()
{
gtk_main_quit();
}
static gboolean delete_event(GtkWidget *window_main,GdkEvent *event)
{
return FALSE;
}
This example will scroll but only to accomodate the original size of the vte set via vte_terminal_set_size(VTE_TERMINAL(vte), 80, 45); If more lines are added to the terminal by simply hitting return or producing output from a program the scrollback buffer does not expand. It is fixed at 45 lines despite the fact that an unlimited scrollback was specified vte_terminal_set_scrollback_lines(VTE_TERMINAL (vte), -1); /* infinite scrollback */
What am I missing? Thanks.
In order to get scrollback to work the line that needed to be changed was:
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
to:
scrolled_window = gtk_scrolled_window_new (NULL, terminal->adjustment);
where terminal is defined as:
VteTerminal *terminal;
vte = vte_terminal_new();
terminal = VTE_TERMINAL (vte);
I'm not all that confident since I haven't worked with VTE before. However, it looks like the vte_terminal is itself a scrollable widget. I'd suggest you try to get rid of the scrolled_window and see.
Also, here is what I've found as an example.
try this it's works
//gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), vte);
gtk_container_add (GTK_CONTAINER(scrolled_window),vte);

Gtk+ Callback functions and signals help

I have the following example from here, it shows this under the "Increase - Decrease" title.
#include <gtk/gtk.h>
gint count = 0;
char buf[5];
void increase(GtkWidget *widget, gpointer label)
{
count++;
sprintf(buf, "%d", count);
gtk_label_set_text(label, buf);
}
void decrease(GtkWidget *widget, gpointer label)
{
count--;
sprintf(buf, "%d", count);
gtk_label_set_text(label, buf);
}
int main(int argc, char** argv) {
GtkWidget *label;
GtkWidget *window;
GtkWidget *frame;
GtkWidget *plus;
GtkWidget *minus;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 180);
gtk_window_set_title(GTK_WINDOW(window), "+-");
frame = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), frame);
plus = gtk_button_new_with_label("+");
gtk_widget_set_size_request(plus, 80, 35);
gtk_fixed_put(GTK_FIXED(frame), plus, 50, 20);
minus = gtk_button_new_with_label("-");
gtk_widget_set_size_request(minus, 80, 35);
gtk_fixed_put(GTK_FIXED(frame), minus, 50, 80);
label = gtk_label_new("0");
gtk_fixed_put(GTK_FIXED(frame), label, 190, 58);
gtk_widget_show_all(window);
g_signal_connect(window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect(plus, "clicked",
G_CALLBACK(increase), label);
g_signal_connect(minus, "clicked",
G_CALLBACK(decrease), label);
gtk_main();
return 0;
}
what I'm wondering is, the g_signal_connect(plus, "clicked",G_CALLBACK(increase), label); function sends the "label" to the function increase, where its arguments are void increase(GtkWidget *widget, gpointer label). Now in the increase function the gtk_label_set_text() function requires a data type of GtkLabel as its first argument but I only see a GtkWidget variable and a void pointer label as the arguments to the increase function. If that is so how does the gtk_label_set_text() work?.
In C (but not C++), you can implicitly cast a void* to a pointer to any other type. It's very commonly seen when allocating memory with malloc, which returns a void*:
int *myIntArray = malloc(10 * sizeof(int)); // allocate array of 10 ints
Your code is doing the same thing, just with parameter passing:
void gtk_label_set_text(GtkLabel *label, const char *text);
void *label = ...;
gtk_label_set_text(label, "some string"); // label is implicitly cast from
// void* to GtkLabel*

Sending data in a GTK Callback

How can I send data through a GTK callback? I've Googled, and with the information I found created this:
#include <gtk/gtk.h>
#include <stdio.h>
void button_clicked( GtkWidget *widget, GdkEvent *event, gchar *data);
int main( int argc, char *argv[]){
GtkWidget *window;
GtkWidget *button;
gtk_init (&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("Go!");
gtk_container_add(GTK_CONTAINER(window), button);
g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked),"test" );
gtk_widget_show(window);
gtk_widget_show(button);
gtk_main();
return 0;
}
void button_clicked( GtkWidget *widget, GdkEvent *event, gchar *data){
printf("%s \n", (gchar *) data);
return;
}
But it just Segfaults when I press the button. What is the right way to do this?
It segfaults because "clicked" doesn't have a GdkEvent parameter. If you remove the second argument in button_clicked() it should work.
Install Devhelp application from where you can easily browse GTK+ and GNOME documentation, including signal definitions.

Resources