How to Implement a button-press-event on GtkTable - c

Searching the web for answers dosen't get me through my problem:
I wan't my GtkTable to throw an event, if i click one cell.
Since there is no click event, accept for GtkButton's, i wanted to implement a GDK_BUTTON_PRESS_MASK and GDK_BUTTON_RELEASE_MASK to catch the position of the mouse on the Table during click.
Works great with GtkDrawingArea!
Tryed the snipet bellow, but nothing happend, maybe someone can give me a clue :)
little sample:
static void table_press(GtkWidget *widget, GdkEventButton *event)
{
printf("table pressed");
}
int main(int argc, char **argv)
{
GtkWidget *window;
GtkWidget* table;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW (window), "table click");
table = gtk_table_new(2, 5, TRUE);
gtk_container_add(GTK_CONTAINER (window), table);
gtk_widget_add_events(table, GDK_BUTTON_PRESS_MASK);
g_signal_connect(GTK_OBJECT (table), "button-press-event",
G_CALLBACK (table_press), NULL);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(window));
gtk_widget_show_all(window);
gtk_main();
main_exit();
return 0;
}

You don't receive events because GtkTable does not have a GdkWindow associated with it. You can use GtkEventBox which lets you accept events on widgets that would not normally accept events. This is derived from GtkBin so the interesting code would look like this.
table = gtk_table_new(2, 5, TRUE);
event_box = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER (window), event_box);
gtk_container_add(GTK_CONTAINER (event_box), table);
g_signal_connect(GTK_OBJECT (event_box), "button-press-event",
G_CALLBACK (table_press), NULL);

Related

How can I configure a GtkWidget signal that runs every time a widget is shown?

The show signal seems to only be called the first time a widget is shown. If I call gtk_widget_show on the widget in question, if it has already been shown, any functions passed to g_signal_connect to the widget in question with the show signal will not be called. I attempted to use the show signal for a button whose text is determined by an external state that the button changes, so when the button first becomes visible it successfully shows the initial state, but even though I change the state in the button handler then call gtk_widget_show, the text is not updated when the button is clicked. How can I configure a widget to run on EVERY show event, not just the first.
Requirement:
update button label based on state
state change happen on button click
One solution could be to update the status when the button is clicked, and then set the button's label, e.g. like this:
update_state();
gtk_button_set_label(button, state);
If more parts of the user interface than just the button should be updated, one could think about introducing a separate function updateUI.
A small demo could look like this:
#include <gtk/gtk.h>
static int cnt;
static char state[16];
static void update_state() {
snprintf(state, sizeof(state), "clicked %d", cnt++);
}
static void button_show(__unused GtkWidget *widget, __unused gpointer data) {
g_print("show\n");
}
static void button_clicked(GtkButton *button, __unused gpointer data) {
g_print("clicked\n");
update_state();
gtk_button_set_label(button, state);
}
static void buildUI(GApplication *app, __unused gpointer data) {
GtkWidget *window = gtk_application_window_new(GTK_APPLICATION(app));
gtk_window_set_title(GTK_WINDOW(window), "GtkButton");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
gtk_container_set_border_width(GTK_CONTAINER(window), 15);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
GtkWidget *button = gtk_button_new();
gtk_button_set_label(GTK_BUTTON(button), state);
gtk_widget_set_size_request(button, 80, 32);
gtk_widget_set_halign(button, GTK_ALIGN_START);
gtk_widget_set_valign(button, GTK_ALIGN_START);
gtk_container_add(GTK_CONTAINER(window), button);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(button_clicked), NULL);
g_signal_connect(G_OBJECT(button), "show",
G_CALLBACK(button_show), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
}
int main(int argc, char *argv[]) {
GtkApplication *app = gtk_application_new("com.example.MyApp", G_APPLICATION_FLAGS_NONE);
update_state();
g_signal_connect(app, "activate", G_CALLBACK(buildUI), NULL);
g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return 0;
}
It updates the label whenever the button is clicked.

GTK in C: Segmentation Fault when using key-release or key-press

For context, I'm trying to make a program that changes stylized label text in response to some physical inputs on a beaglebone black (eg. get a signal, if high/low, show this text). In lieu of those inputs, which I don't have access to right now, I decided to use key-release as a substitute.
I've been basing my code off of this combo-box tutorial, which changes label text based on the text of a combo-box selection. I've modified that code to use stylized text as in the code below.
#include <gtk/gtk.h>
void combo_selected(GtkWidget *widget, gpointer window) {
gchar *text = g_strjoin(NULL,"<span font='48' weight='bold' color='#DDDDDD'>",gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)),"</span>",NULL); //label text, uses pango markup
gtk_label_set_markup(GTK_LABEL(window), text);
g_free(text);
}
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *combo;
GtkWidget *label;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GtkComboBox");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(window), 15);
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
hbox = gtk_hbox_new(FALSE, 0);
vbox = gtk_vbox_new(FALSE, 15);
combo = gtk_combo_box_new_text();
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Ubuntu");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Arch");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Fedora");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mint");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Gentoo");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Debian");
gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
gchar *str = "<span font='48' weight='bold' color='#DDDDDD'>Not Initialized</span>"; //label text, uses pango markup
label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label), str); //add pango str to label
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), hbox);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(combo), "changed",
G_CALLBACK(combo_selected), (gpointer) label);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
That works, however when attempting to use a key-release or key-press instead of the combo box options, I get a segmentation fault. Below is the further-modified code (with some things commented out).
#include <gtk/gtk.h>
#include <unistd.h>
#include <stdio.h>
void fpcheck(GtkWidget *window, gpointer lbl) {
gchar *text = "<span font='48' weight='bold' color='#DDDDDD'>Press index finger firmly on sensor.</span>";
gtk_label_set_markup(GTK_LABEL(lbl), text);
//sleep(2); //placeholder -> fp detection
//text = "<span font='48' weight='bold' color='#DDDDDD'>Fingerprint recognized!</span>";
//gtk_label_set_markup(GTK_LABEL(lbl), text);
g_free(text);
}
int main(int argc, char *argv[]) {
GtkWidget *window; //main window
GtkWidget *align; //alignment settings
GtkWidget *lbl; //text
GdkColor color = {0, 0x0, 0x0, 0x0}; //window color
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //init window
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); //window pos on screen
gtk_window_set_default_size(GTK_WINDOW(window), 800, 480); //window size
//gtk_window_set_resizable(GTK_WINDOW(window), FALSE); //user cant resize
gtk_window_set_title(GTK_WINDOW(window),"User Display"); //window title
gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); //set color to window
align = gtk_alignment_new(.5,.5,0,0); //x,y alignment
lbl = gtk_label_new(NULL); //label init
gchar *str = "<span font='48' weight='bold' color='#DDDDDD'>Not Initialized</span>"; //label text, uses pango markup
gtk_container_add(GTK_CONTAINER(align), lbl); //add label to alignment
gtk_container_add(GTK_CONTAINER(window), align); //add label to window
gtk_label_set_markup(GTK_LABEL(lbl), str); //add pango str to label
g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(fpcheck), (gpointer) lbl); //calls fpcheck to change label
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window); //build the window all at once
gtk_main();
return 0;
}
If I comment out the gtk_label_set_markup line and g_free(text) line in fpcheck, there's no error but it doesn't do anything, of course. From looking at other online resources, I think this error is being cause by trying to access the GTK_LABEL(lbl) because of the first argument in fpcheck being incorrect, but thats just a guess and I don't know what I'd put there instead. In the example, it's just "Widget," referring to the combo-box, I think, since it gets the text from the selected option.
On that note, I tried removing that argument, and now instead of a segmentation error, I get the following error without even pressing/releasing.
(test:6698): GLib-GObject-WARNING **: invalid cast from 'GtkWindow' to 'GtkLabel'
(test:6698): Gtk-CRITICAL **: IA__gtk_label_set_markup: assertion 'GTK_IS_LABEL (label)' failed
I did a few gdb backtraces, but none of them seem to be particularly helpful. If anyone wants 'em, I can post them.
Any ideas on the problems I'm having?
Thanks.
key-release-event handler has this signature
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
Your fpcheck() needs to look like that.
It's easier to find problems like this early if you learn the habit of doing e.g. g_assert (GTK_IS_LABEL (user_data)) as the first thing in every handler where the userdata definitely always has to be a label.

How to create gtk+ windows without title bar with resize and move properties working

How to create gtk+ windows without title bar with resize and move properties working.
I checked gtk_window_set_decorated function, but it disable resize and move features of window. I found this answer already, but I don't think it has anything to do with it.
I tried to set resizeable true after gtk_window_set_decorated but still not working
Please check code
#include <gtk/gtk.h>
int main (int argc,
char *argv[])
{
GtkWidget *window;
/* Initialize GTK+ and all of its supporting libraries. */
gtk_init (&argc, &argv);
/* Create a new window, give it a title and display it to the user. */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Hello World");
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
//gtk_window_set_gravity(GTK_WINDOW (window), GDK_GRAVITY_NORTH_EAST);
//gtk_window_set_deletable (GTK_WINDOW (window), FALSE);
gtk_widget_show (window);
/* Hand control over to the main loop. */
gtk_main ();
return 0;
}
So what I found to work is to remove the header with gtk_window_set_decorated set to FALSE. Then manually change the cursor and call gtk_window_begin_resize_drag() to begin a resize on mousedown.
How I implemented this was to check if the mouse was near a border on a mousemove callback and if so change the cursor with gdk_window_set_cursor().
On a mousedown event near a border I call gtk_window_begin_resize_drag() with the appropriate border.
you can use GTK_WINDOW_POPUP :
#include <gtk/gtk.h>
int main (int argc,
char *argv[])
{
GtkWidget *window;
/* Initialize GTK+ and all of its supporting libraries. */
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_show (window);
gtk_main ();
return 0;
}
You should not use GTK_WINDOW_POPUP if you only want window manager decorations turned off
for the window. Instead, use gtk_window_set_decorated (GtkWindow *window, gboolean show)
to turn off window decorations.

GTK+ Threading with OpenGL's GLUT/FreeGLUT

I am fairly new to C/C++ programming, so please excuse me if something sounds stupid to you...
I am currently working on a Visual Studio C++ 2010 project that involves opengl, glut/freeglut, and gtk+.
The OpenGL is used to take an input image, manipulate its pixels based on various parameters before calling glDrawPixels() to draw the pixels from buffer for display in a glut/freeglut window.
Now I am trying to make a UI so user can adjust the parameters and see the resulting image at runtime.
What I have so far is one GTK window that contains all of the GTK widgets, and a glut/freeglut window that houses the OpenGL image. How it works is that when the button on the UI is clicked, a new GTK thread is created to display the glut/freeglut window (that contains the OpenGL rendered image.
My question is, how do I make glut/freeglut to render updated OpenGL image and display it in the same glut/freeglut window? I am not sure if it has to do with GTK threading or it's just glut/freeglut, or both. Does anyone have any advice?
Here's the stripped down code I have:
#include<freeglut.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <gtk/gtk.h>
GtkWidget *window;
GtkWidget *vbox, *hbox;
GtkWidget *button;
gint tmp_pos;
GThread *thread;
gint progress = 0;
G_LOCK_DEFINE_STATIC(progress);
GError *error = NULL;
void display()
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glRasterPos2i(x_offset,y_offset);
glDrawPixels(x2-x1+1,y2-y1+1,GL_LUMINANCE,GL_UNSIGNED_BYTE,tmp_buf);
glFlush();
}
static gpointer runGL(gpointer data)
{
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
if(Running_Mode==0)
glutInitWindowSize(3*Test_Size,Test_Size); /* 500 x 500 pixel window */
else
glutInitWindowSize(Test_Size,Test_Size); /* 500 x 500 pixel window */
glutInitWindowPosition(600,0); /* place window top left on display */
glutCreateWindow("Simulation"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
return (NULL);
}
/* create a g_thread for glut window */
void GLThread()
{
thread = g_thread_create(runGL, (gpointer)button, TRUE, &error);
g_print("Thread created");
if(!thread)
{
g_print("Error: %s\n", error->message);
return(-1);
}
}
int main(int argc,char **argv)
{
glutInit(&argc,argv);
if(! g_thread_supported())
g_thread_init( NULL );
gdk_threads_init();
/* Obtain gtk's global lock */
gdk_threads_enter();
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
gtk_window_set_title (GTK_WINDOW (window), "GTK Entry");
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect_swapped (window, "delete-event",
G_CALLBACK (gtk_widget_destroy),
window);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show (vbox);
hbox = gtk_hbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
gtk_widget_show (hbox);
button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
/* call the GLThread function when the button is clicked */
g_signal_connect_swapped (button, "clicked", G_CALLBACK (GLThread), window);
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
gtk_widget_set_can_default (button, TRUE);
gtk_widget_show (button);
gtk_widget_show(window);
gtk_main();
gdk_threads_leave();
}
First things first: Free-/GLUT is not a part of OpenGL. It's a 3rd party library with a similar scope (just much more simpler) like GTK+. If you're using GTK+ you don't need GLUT. Instead you should use the GTK+ OpenGL Widget provided by GTKGlExt.
I am currently working on a Visual Studio C++ 2010 project that involves opengl, glut/freeglut, and gtk+.
Why would you want to mix GLUT and GTK+? There's absolutely no sane reason to do this. GLUT is a simple application framework (creates windows, provides the event loop), GTK+ is an application framework (creates windows, provides the event loop, has widgets).
Choose one, don't mix them.
I am not sure if it has to do with GTK threading or it's just glut/freeglut, or both. Does anyone have any advice?
The problem is, that you have two libraries fighting to do the same thing (processing user input events).

How to center a dialog window on the main window in GTK?

I want to print small warning messages. To achieve that, I'm creating a new window and I want it to be centered on the main window. So far I've tried setting its parent with gtk_widget_set_parent, using GTK_WINDOW_POPUP and GTK_WINDOW_TOPLEVEL but nothing worked.
How to center the window on the main window?
Here's the code for the function:
static void pop_warning(char *title, char *text)
{
GtkWidget *warning_window;
GtkWidget *box;
GtkWidget *label;
GtkWidget *button;
warning_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(warning_window), title);
g_signal_connect(GTK_WINDOW(warning_window), "destroy", G_CALLBACK(gtk_widget_destroy), NULL);
gtk_container_set_border_width(GTK_CONTAINER(warning_window), 20);
gtk_window_set_resizable(GTK_WINDOW(warning_window), FALSE);
//window is the main window
gtk_widget_set_parent(warning_window, window);
gtk_window_set_position(GTK_WINDOW(warning_window), GTK_WIN_POS_CENTER_ON_PARENT);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
gtk_container_add(GTK_CONTAINER(warning_window), box);
label = gtk_label_new(text);
gtk_box_pack_start(GTK_BOX(box), label, TRUE, FALSE, 0);
button = gtk_button_new_with_label("Ok");
g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), warning_window);
gtk_box_pack_start(GTK_BOX(box), button, TRUE, FALSE, 0);
gtk_widget_show_all(warning_window);
}
gtk_window_set_position(GTK_WINDOW(warning_window), GTK_WIN_POS_CENTER_ON_PARENT);
only works if you first call
gtk_window_set_transient_for(GtkWindow *window, GtkWindow *parent);
as mentioned explicitly in the documentation.
You could also try to use GTK_WIN_POS_CENTER_ALWAYS that has not the above mentioned constrain - at least not according the docs.

Resources