I'm working with GLFW3 + OpenGL in C under Windows 7 64-bit. Since responsive resizing is very important to my application I'm using a secondary thread for logic + rendering loops so rendering won't be interrupted when the UI thread blocks (e.g. when the user holds down the mouse on the window frame).
This works great except that it sometimes causes the contents of my window to flicker while the user is resizing the window. I suspect there's something I still don't fully understand about the consequences of rendering from a secondary thread and the possible interactions with window resizing - this is my first time working with multithreading.
Here's a minimal code sample that reproduces the problem:
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
#include <pthread.h>
GLFWwindow* window;
void *threadfun(void *arg);
int main () {
pthread_t mythread;
glfwInit();
window = glfwCreateWindow(640, 480, "Test", NULL, NULL);
pthread_create(&mythread, NULL, &threadfun, (void *)NULL);
while (!glfwWindowShouldClose(window)) glfwWaitEvents();
pthread_join(mythread, NULL);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
void *threadfun (void *arg) {
glfwMakeContextCurrent(window);
gl3wInit();
glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
}
}
(I'm compiling with mingw-w64 x86_64-6.3.0-posix-seh-rt_v5-rev1 in case that's relevant.)
Related
A simple opengl application makes a creaking sound.
#include <windows.h>
#include <GLFW/glfw3.h>
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
OpenGL is only a specification it is up to the driver manufacturer to implement the specification to a driver that the specific graphics card supports.Developers need to retrieve the location of the functions and store them in function pointers.
Library's like glew or glad manages this task , so before calling any opengl function we need to initilize them.
The squeaking sound is due to increased power consumption of the card.
Enabling v-sync locks the framerate and thus reduces the GPU cycles, and lowers power consumption.
It can be either done from the property panel of the card or through code , in case of GLFW.
glfwSwapInterval( 1 )
I am trying to create an application in which I need to draw on a transparent window which stays above all other windows and invisible to the window manager, hence trying to set the override redirect of a window to true .But setting the override redirect for a GdkWindow causes segmentation fault.
#include <gtk/gtk.h>
void activate(GtkApplication *app) {
GtkWidget *window = gtk_application_window_new(app);
GdkWindow *gdk_window = gtk_widget_get_window(window);
gdk_window_set_override_redirect(gdk_window, TRUE);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("com.github.application.name",
G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run(G_APPLICATION (app), argc, argv);
g_object_unref(app);
return status;
}
compiling with gcc using
gcc -o out main.c `pkg-config --cflags --libs gtk+-3.0`
what am I missing here? any help is appreciated. Thanks.
gtk_widget_get_window() can return NULL. The reason your code is segfaulting is probably because you're calling gdk_window_set_override_redirect() on a NULL pointer.
For the underlying reason why gtk_widget_get_window() can return NULL: a GdkWindow maps to the concept of a surface; in X11 this is called an XWindow, hence the name. To let the compositor show your surface/XWindow, you have to explicitly map it.
GTK does the mapping operation the moment the GtkWindow widget is told to show itself (ie when you call gtk_window_present() or gtk_widget_show()). Once it actually associates with an underlying GdkWindow, it will emit the "realize" signal to which you can connect to .
So, in other words, you can either:
Call gdk_window_set_override_redirect(); after showing the window
Connect to the "realize" signal of your window variable, and call gdk_window_set_override_redirect(); inside the callback
Your code fails because gdk_window is NULL.
You can ask the window to be created with gtk_window_present:
void activate(GtkApplication *app) {
GtkWidget *window = gtk_application_window_new(app);
GdkWindow *gdk_window = gtk_widget_get_window(window);
gtk_window_present(GTK_WINDOW(window));
gdk_window_set_override_redirect(gdk_window, TRUE);
gtk_widget_show_all(window);
}
The following program always works OK — shows the menu with one item — if launched from the terminal, but not if launched by the i3 window manager directly (when bound to a key).
In the latter case, most of the time it does print “Entering gtk main loop.”, but then simply does not get shdown; though approximately once per 20 key presses it does get shown!
Why?
#include <gtk/gtk.h>
#include <stdio.h>
static
void
deactivate_handler(GtkMenuShell *instance, gpointer user_data)
{
(void) instance; (void) user_data; // unused parameters
gtk_main_quit();
}
int
main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *menu = gtk_menu_new();
GtkWidget *item = gtk_menu_item_new_with_label("Test");
gtk_menu_attach(GTK_MENU(menu), item, 0, 1, 0, 1);
g_signal_connect(menu, "deactivate", G_CALLBACK(deactivate_handler), NULL);
gtk_widget_show_all(menu);
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
fprintf(stderr, "Entering gtk main loop.\n");
gtk_main();
return 0;
}
I suspect calling gtk_menu_popup before gtk_main will lead to weird behavior. You're not changing data, like gtk_widget_show_all that changes a flag, you're actually trying to do actions.
One trick I see is switching to GtkApplication and run gtk_menu_popup in response to the GtkApplication's activate signal. At that time you're already in the main loop.
I need to get webcam video feed using C, GTK2/3, Cairo.
However can't find any references about it.
Below shows how did I try using opencv. It is unsuccessful.I need to know some other method using gstreamer, cairo.
I'm expecting simple code to get video to GTK window. Really appreciate if someone can provide example code.
/*
gcc -o weby3 att3.c `pkg-config --libs --cflags gtk+-2.0 opencv`
*/
#include "highgui.h"
#include <gtk/gtk.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
GdkPixbuf* pix;
IplImage* frame;
CvCapture* capture;
gboolean
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
while(1) {
frame = cvQueryFrame( capture );
if(!frame) break;
pix = gdk_pixbuf_new_from_data((guchar*) frame->imageData,
GDK_COLORSPACE_RGB, FALSE, frame->depth, frame->width,
frame->height, (frame->widthStep), NULL, NULL);
gdk_draw_pixbuf(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pix, 0, 0, 0, 0,
-1, -1, GDK_RGB_DITHER_NONE, 0, 0); /* Other possible values are GDK_RGB_DITHER_MAX, GDK_RGB_DITHER_NORMAL */
char c = cvWaitKey(33);
if( c == 27 ) break;
}
cvReleaseCapture( &capture );
return TRUE;
}
int main( int argc, char** argv ) {
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *drawing_area;
gtk_init (&argc, &argv);
CvCapture* capture = cvCreateCameraCapture(0);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Hello WebCam and OpenCV!");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Now add a child widget to the aspect frame */
drawing_area = gtk_drawing_area_new();
/* window since we are forcing a aspect ratio */
gtk_widget_set_size_request(drawing_area, 600, 400);
gtk_container_add(GTK_CONTAINER (window), drawing_area);
gtk_widget_show(drawing_area);
g_signal_connect (G_OBJECT (drawing_area), "expose_event",
G_CALLBACK (expose_event_callback), NULL);
/* and the window */
gtk_widget_show (window);
/* All GTK applications must have a gtk_main(). Control ends here
* and waits for an event to occur (like a key press or
* mouse event). */
gtk_main ();
return 0;
}
The main problem I see here is that you're not properly integrating your opencv code into the GTK event model.
GTK basically works with a message pump. Messages are sent in a queue, and GTK reads and unqueue them to react to those messages. In GTK 2, the expose-event event is emitted when a widget or portion of it needs to be drawn (in GTK 3, the draw event is used). You're suposed to connect a callback to that event to catch the event. Then in your callback, you draw a single frame, and then give the control back to GTK. It will call your callback again when it needs the next frame.
The problem here is that you never give the hand back to GTK, as your opencv code is enclosed in an infinite while(1) loop. You should instead just draw a single frame, and return.
The key event logic should also be handled using GTK, and not in your expose-event callback. Just call gtk_main_quit once you have seen the keystroke you're waiting for.
EDIT:
Once you can display one frame, you have to display them all. Call gtk_widget_queue_draw to tell GTK that the widget needs to be redrawn.
Once this is done, you'll see that you need some way of calling gtk_widget_queue_draw periodically. This is easilly done with GLib functions like g_timeout_add or g_idle_add. These functions tell the main event loop (what I called "message pump" above") to call a callback after a determined amount of time (for g_timeout_add) or just when there is no other events to process (for g_idle_add). Call gtk_widget_queue_draw in that callback and you're done.
Be aware that g_timeout_add doesn't allow to have a perfect timing, so the time between each frame may be too different from one frame to another. You may avoid this by augmenting the priority passed to g_timeout_add. You may also use a GTimer to compute in your timeout callback the time elapsed between the last frame and the current time, and deduce time remaining until your next frame. Then call g_timeout_add with that more accurate time. Don't forget to return FALSE instead of TRUE at the end of the timeout callback if you use the GTimer trick, otherwise you'll have n timeout callbacks running at frame n.
I have a simple multithreaded Gtk+2.0 application that acquires data from multiple sources (microphone, webcam, temperature sensor), and displays data from these as images on screen (webcam frame grabs, microphone data represented as oscilloscope renders, text, etc).
It's to my understanding from the Gtk manual and various articles that only the main processing thread should use any Gtk functions/calls that affect the UI. However, the main() entry point blocks on gtk_main() until I close the UI. With the exception of event handlers that are mapped to things like when I click on a button or slider in my UI, it seems the only option left open to me is to spawn a few pthreads and have them do the periodic sampling of data and updating information on-screen in the UI.
I remember from doing some MFC GUI development a long ways back that a similar principle applied: only a single specific thread should be updating the UI elements. How do I accomplish this in C with Gtk+2.0?
Thank you.
According to the documentation, the main even loop can accept sources from different threads:
A GMainContext can only be running in a single thread, but sources can
be added to it and removed from it from other threads.
So you can inject the code in the UI thread from your working thread by:
creating a GSource (e.g., by using g_idle_source_new);
adding the code you want to be executed with g-source-set-callback;
attaching it to the UI thread context with g_source_attach().
Here is a sample program for GTK+2 and GLib >= 2.32:
#include <gtk/gtk.h>
#define N_THREADS 100
#define N_ITERATIONS 100
GtkWidget *bar;
GMainContext *context;
static gboolean
update_progress_bar(gpointer user_data)
{
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar),
g_random_double_range(0, 1));
return G_SOURCE_REMOVE;
}
static gpointer
thread_func(gpointer user_data)
{
int n_thread = GPOINTER_TO_INT(user_data);
int n;
GSource *source;
g_print("Starting thread %d\n", n_thread);
for (n = 0; n < N_ITERATIONS; ++n) {
/* If you want to see anything you should add a delay
* to let the main loop update the UI, e.g.:
* g_usleep(g_random_int_range(1234, 567890));
*/
source = g_idle_source_new();
g_source_set_callback(source, update_progress_bar, NULL, NULL);
g_source_attach(source, context);
g_source_unref(source);
}
g_print("Ending thread %d\n", n_thread);
return NULL;
}
gint
main(gint argc, gchar *argv[])
{
GtkWidget *window;
GThread *thread[N_THREADS];
int n;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
bar = gtk_progress_bar_new();
gtk_container_add(GTK_CONTAINER(window), bar);
context = g_main_context_default();
for (n = 0; n < N_THREADS; ++n)
thread[n] = g_thread_new(NULL, thread_func, GINT_TO_POINTER(n));
gtk_widget_show_all(window);
gtk_main();
for (n = 0; n < N_THREADS; ++n)
g_thread_join(thread[n]);
return 0;
}
I would do your sampling in separate threads, as you suggest. The question then is how you update the UI. What I would do is to use a 'self-pipe'. This is normally done to communicate from signal handlers, but it works just fine between threads when one of the threads can't wait on a condition variable. What you do here is set up a dedicated pipe, write one character to the pipe in the thread that has got the data, and select() on the read end of the pipe in the main program's select() loop. Details here: Using self-pipe, how can I avoid that the event loop stalls on read()? - useful background on its origins here.
You can then make GTK+ listen on the read end of the pipe. Your problem is thus reduced to making GTK+ respond to something on an FD - see here (first answer) for how.