GTK+ Threading with OpenGL's GLUT/FreeGLUT - c

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).

Related

Create and save a file in GTK2 using C

I'm following the instructions of the official Raspberry Pi book called An introduction to C & GUI Programming (link).
It uses GTK2 to create a gui in C.
I encountered some problems trying the code that should save a file. Here the code of the book (same I used):
#include <gtk/gtk.h>
static void save_file (GtkWidget *btn, gpointer ptr)
{
GtkWidget *sch = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (ptr), GTK_FILE_CHOOSER_ACTION_SAVE, "Cancel", 0, "OK", 1, NULL);
if (gtk_dialog_run (GTK_DIALOG (sch)) == 1)
{
printf ("%s selected\n", gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (sch)));
}
gtk_widget_destroy (sch);
}
void end_program (GtkWidget *wid, gpointer ptr)
{
gtk_main_quit ();
}
int main (int argc, char * argv[])
{
gtk_init (&argc, &argv);
GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget *btn = gtk_button_new_with_label ("Close window");
g_signal_connect (btn, "clicked", G_CALLBACK (end_program), NULL);
g_signal_connect (win, "delete_event", G_CALLBACK (end_program), NULL);
GtkWidget *vbox = gtk_vbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (win), box);
GtkWidget *fc_btn = gtk_button_new_with_label ("Save file");
g_signal_connect (fc_btn, "clicked", G_CALLBACK (save_file), win);
gtk_box_pack_start (GTK_BOX (vbox), fc_btn, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), btn, TRUE, TRUE, 0);
gtk_widget_show_all (win);
gtk_main ();
return 0;
}
The books says that this program should open a window with a button that, if clicked, opens a new window where I can insert the name of the file and with OK I should be able to save it.
The resulting file path is printed correctly inside the terminal.
If I enter inside the path where I saved the file, the file doesn't exist! It's not hidded neither saved with a different name.
Is there something missing in this piece of code?
I left you a comment above. As noted, I reviewed the sample code in the PDF version of the book in your link. The purpose of that code is to present a file chooser dialog widget and confirm the name of the file you either select or type in by printing the full path in the console. The program, as is, has no mechanism for actually writing a file out to your storage medium. So that is why you do not see a file when you view the folder on your system. If you want as a minimum, a file actually written, a little more code needs to be added. Just to give you one really simple example of what that might look like, I made a revision to the "save_file" function in your sample program as noted in the following code snippet.
static void save_file (GtkWidget *btn, gpointer ptr)
{
GtkWidget *sch = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (ptr), GTK_FILE_CHOOSER_ACTION_SAVE, "Cancel", 0, "OK", 1, NULL);
if (gtk_dialog_run (GTK_DIALOG (sch)) == 1)
{
printf ("%s selected\n", gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (sch)));
char cmd[1024];
strcpy(cmd, "touch ");
strcat(cmd, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (sch)));
system(cmd);
}
gtk_widget_destroy (sch);
}
FYI, I built this revised program on a Linux system using the "touch" command which will either update an existing file's timestamp or create a new empty file and the "system" command which allows one to execute a program as though one was using a terminal. You mentioned a Raspberry Pi system, which I believe uses Linux or a Linux like operating system, so these commands should work.
For further examples and tutorials, you might want to check out some videos out on the web. The following link is not a specific recommendation, but it was one of the first videos I found out on the web that walks through the various steps of C coding with GTK including references to the GTK file chooser dialog.
"https://www.youtube.com/watch?v=EdJVkr87LSk&list=PLMkSWKN9VsZH562FmV8sMvMu_sVZsYAt6"
You might want to review those videos to see if they might help you.
I hope that clarifies things for you.
Regards.

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.

How to create a cairo_t on a Gtk 2 window

I have an old app, now compiling on Gtk 2, but I need to introduce the use of Cairo. I can't figure out how to create the necessary cairo context (cairo_t) from my Widgets.
Here's the code I'm trying to learn with so far, modified (*ahem* cribbed) from a Gtk 3 tutorial. The crux of the matter is creating a cairo surface from the window widget. As it stands, that call is a sketch and it won't compile, let alone run. Remember, my target is Gtk2, not 3, at least at this point.
/* Snitched from http://zetcode.com/gfx/cairo/cairobackends/ on 13 Jan 2014 */
#include <cairo.h>
#include <cairo-xlib.h>
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
cairo_surface_t *surface;
cairo_t *cr;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), darea);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 90);
gtk_window_set_title(GTK_WINDOW(window), "GTK window");
surface = cairo_xlib_surface_create(
gtk_widget_get_display(window), /* must be Display *, not struct GdkDisplay * */
window, /* must be Drawable (no star) */
gtk_widget_get_visual(window), /* must be Visual * */
gtk_widget_get_width(window), /* int */
gtk_widget_get_height(window) /* int */
);
cr = cairo_create(surface);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 40.0);
cairo_move_to(cr, 10.0, 50.0);
cairo_show_text(cr, "Discipline is power.");
gtk_widget_show_all(window);
gtk_main();
return 0;
}
I hope the tutorial did not do cairo drawing in main()... The meaningful place to draw onto a GTK2 widget is in the expose-event (and if you want to force a redraw from somewhere else, just call gtk_widget_queue_draw()). It is easier to use gdk_cairo_create() to get a cairo context.
Something like this:
static gboolean
on_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create (gtk_widget_get_window (widget));
cairo_move_to (cr, 30, 30);
cairo_show_text (cr, "Text");
cairo_destroy (cr);
return FALSE;
}
g_signal_connect(darea, "expose-event",
G_CALLBACK(on_expose_event), NULL);
Jan Bodnar has a more complete example (in the end).
This is all a lot nicer in GTK3 in my opinion. Still, even if your goal is to port to GTK3 it may make sense to change the drawing to use cairo first as you're doing -- changing to GTK3 afterwards should just simplify the code.

clutter stage in gtk can't not handle stage mouse press event

I have tried to use the clutter-gtk. I wrote a small piece of code that create a gtk window with a clutter stage in it. I try to get mouse button press event on the stage but there is nothing.
Here is the code:
#include <clutter/clutter.h>
#include <clutter-gtk/clutter-gtk.h>
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
/*gcc 3_clutter_app_clickable_text_in_gtk.c -o 3_clutter_app_clickable_text_in_gtk `pkg-config clutter-1.0 clutter-gtk-1.0 glib --cflags --libs`*/
/*mouse clic handler*/
void on_stage_button_press( ClutterStage *stage, ClutterEvent *event, gpointer data)
{
printf("ok\n");
}
int main(int argc, char *argv[])
{
if (gtk_clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
/*create the window*/
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
/*destroy from window close all*/
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
/*vertical box, 0 spacing*/
GtkWidget * box = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
/*add box in the window*/
gtk_container_add(GTK_CONTAINER(window), box);
/*create the cutter widget*/
GtkWidget *clutter_widget = gtk_clutter_embed_new ();
gtk_widget_set_size_request (clutter_widget, 200, 200);
ClutterActor *stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(clutter_widget));
clutter_stage_set_use_alpha(CLUTTER_STAGE(stage), TRUE);
ClutterColor stage_color ;
GString * bg_color = g_string_new("#555753ff");
clutter_color_from_string(&stage_color,bg_color->str);
clutter_actor_set_background_color(stage, &stage_color);
/*add the cutter widget in the box expand and fill are TRUE and spacing is 0*/
gtk_box_pack_start (GTK_BOX (box), clutter_widget, TRUE, TRUE, 0);
/*create line text*/
ClutterColor text_color;
GString * fg_color = g_string_new("#00000055");
clutter_color_from_string(&text_color, fg_color->str);
ClutterActor *some_text = clutter_text_new_full("Sans 24", "Hello, world", &text_color);
clutter_actor_set_size(some_text, 256, 128);
clutter_actor_set_position(some_text, 128, 128);
clutter_actor_add_child(CLUTTER_ACTOR(stage), some_text);
clutter_text_set_editable(CLUTTER_TEXT(some_text), TRUE);
/*define clic event*/
g_signal_connect(stage, "button-press-event", G_CALLBACK(on_stage_button_press), NULL);
/* Show the window and all its widgets: */
gtk_widget_show_all (GTK_WIDGET (window));
/* Start the main loop, so we can respond to events: */
gtk_main ();
return EXIT_SUCCESS;
}
Nothing happens when I click on the stage. I have made some tests and I can handle click event on the main windows, on the clutter_widget but not directly on the clutter stage.
This code is modified one from http://www.openismus.com/documents/clutter_tutorial/0.9/docs/tutorial/html/sec-stage-widget.html. In this one the author connect the signal directly on the stage but this example is for clutter 0.9 and don't compile anymore with clutter v > 1.0.
Any ideas on what I am doing wrong?
Edit
I have made some test with "key-press-event" which are handled. So the problem seems to come from the events mask of the stage.
Does anyone know how to change the event mask of the stage in order to force the stage to react on mouse events?
I close this question because :
clutter-gtk is just a proof of concept
clutter-gtk will not be used in the future
see https://mail.gnome.org/archives/clutter-list/2013-February/msg00059.html
so I don't want to loose more time with this.
For information,the same example using juste clutter works as expected.
CLUTTER_BACKEND=gdk ./yourexecutable

How to Implement a button-press-event on GtkTable

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

Resources