I find these functions can register a callback for event from hardware(maybe? I'm not sure).
Like following functions.
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
I'm curious that how are these functions called. Does GLFW create a new thread by glfwInit to loop these functions? Or does GLFW register some listeners to listen these event from different hardware?
I track the running program and find that the function is called in the main thread. And I find that the function is called in glfwPollEvents. And it means that the hardware input is saved in the buffer and opengl will get the input and do the callback.
Related
I am fairly new to GTK development, not very much aware if GTK supports custom / user-defined events. I am building an application where GUI layout (i.e. the size and position of GtkWidgets) needs to be read from memory and using that data the UI can be created and shown for user interaction.
The GTK Main event loop runs on the Main thread, whereas another (non-main) thread processes the GUI layout and updates the memory. The goal is to send a trigger from the non-main thread to the main thread when the memory is ready for reading. One way this may be achieved is by making the main thread wait in an infinite while loop until the memory is ready with the help of some shared flag. But due to some application architecture specific constraints, we want the main thread to enter the GTK event loop as early as possible.
Therefore, I tried to define and use a Custom GdkEvent (CREATE_WINDOW). In the main thread I have created a GTK_EVENT_BOX (since we don't want any visible window to be created until memory is read) and attached a callback function to it, before it enters the GTK event loop (gtk_main()). The intention is to post a custom event from the non-main thread that would eventually result into the callback function being invoked. The callback function in-turn shall read the memory and create the actual GUI.
The main-thread implementation is as below -
eventbox = gtk_event_box_new ();
gtk_event_box_set_above_child (GTK_EVENT_BOX (eventbox), true);
g_signal_connect (G_OBJECT (eventbox), "event", G_CALLBACK (InternalWindowLifecycleHandler), nullptr);
gtk_widget_set_realized (eventbox, true);
gtk_widget_show_all (eventbox);
gtk_main ();
The non-main thread code is pretty simple (skipped the memory preparation code) -
GdkEvent * createwinevent;
createwinevent = gdk_event_new ((GdkEventType) custEvent::CREATE_WINDOW);
gdk_event_put (createwinevent);
Note - custEvent is an Enum defined by me.
On contrary to our expectations, posting this custom event does not trigger the callback function InternalWindowLifecycleHandler.
I wonder, is it possible to achieve my goal in GTK, with or without custom / user-defined events?
The solution to the problem is to use g_idle_add() / g_idle_add_full() in the main thread instead of using GtkEventBox and the callback function.
My problem was once the main thread enters GTK's event loop, the custom event posted by other thread was not being processed as it was not emitting the signal required by GTK to invoke the callback function. However, any function passed to g_idle_add() / g_idle_add_full() is called by the GTK even after entering main event loop if there are no high priority events pending action.
Hence, the modified main-thread code becomes much simpler -
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, InternalWindowLifecycleHandler, data, nullptr);
gtk_main ();
The event posted by the non-main thread could easily be captured and processed inside the InternalWindowLifecycleHandler function -
gboolean
InternalWindowLifecycleHandler (gpointer data)
{
GdkEvent * gevent;
gevent = gdk_event_peek ();
if (gevent) {
switch ((int) gevent->type)
{
...
...
}
}
return true;
}
Does the Window Procedure specified as lpfnWndProc by window class during registration runs in a separate thread ?
There is an important concept in windows called the message loop.
It is usually inside the main function (aka: WinMain) and can be characterized in the following manner:
while (true) {
// blocks until there's a new message to process
GetMessage()
TranslateMessage()
// ends up calling the propper WndProc callback
DispatchMessage()
}
Update: When you create a window, the thread on which the window is created owns the windows (and the its message queue). Therefor, it must provide the message loop process. This is usually done in the application's main thread but, as other user stated, it can also be done in a separate thread.
The function DispatchMessage takes care of executing the WindowProc procedure of the window targeted by the message (as specified by the message's hwnd parameter).
So, when you create a window, the lpfnWndProc parameter specifies where you want to be notified for events (mouse clicks, keyboard presses, etc). And it is always called in the same thread (the application's main thread or the one which owns the window).
A word of advice: If you need to perform a potentially long operation as the result of an event, you must create a new thread (aka background worker) for the task, and perform some kind of IPC to notify the main thread when the function is finished.
You can find instructions about how to write a windows procedure here. Also, there is some info about the main loop in this wikipedia page.
Does the Window Procedure specified as lpfnWndProc by window class during registration runs in a separate thread ?
No, it is called (as a callback) when events (aka messages) are dispatched by your message loop. In this way - the so-called 'event-driven' model - your program is able to react to user input as and when it happens without having to deal with any multi-threading or re-entrancy issues.
You might have more than one thread, but if it has windows associated with it (i.e. CreateWindowEx was called by that thread) then it would need to have its own message loop.
I'm using glutMouseFunc(mouseFunction); as a callback however I keep getting the Access violation reading location 0x000000b0 at this line glutMouseFunc(mouseFunction);
I'm not using any of the glutInit functions because they interfere with the program and they are not essential anyways.
Does anyone know why I'm getting this error when at this callback?
Here is my initialize function:
int Initialize()
{
/* Bunch of code here that is irrelevant to the problem.......*/
glutMouseFunc(mouseFunction); // Error occurs here.
}
And here is my mouseFunction:
void mouseFunction(int button, int state, int x, int y){
if(button==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN)
{
printf("Pressed middle mouse button!");
}
}
I've noticed one thing though, there error does not occur when I call the mouseFunction() as a normal function call in my Initialize method however once I try to use the mouseFunction with glutMouseFunc(mouseFunction), than the error happens so I believe this is more of an error with glutMouseFunc.
I'm not using any of the glutInit functions because they interfere with the program and they are not essential anyways.
This is your problem. If you're going to use GLUT, use it correctly.
The glutInit() function is essential - part of what it does is initializing internal state within GLUT. As you've discovered, with this state not properly initialized, other parts of GLUT (such as mouse event handling!) may not work properly.
Given your comments to the other questions your problem is simply, that you call glutMouseFunc without a GLUT window. Trying to register GLUT event callbacks without proper initialization or without a GLUT window created will crash your program.
You also say "GLUT interferes" with your actual window. So why would you try to register a GLUT callback at all if you don't have a window that could actually receive the events for GLUT to dispatch?
You should use the mouse event handling of the window you've already got. And what are you using GLUT for then anyway? The whole purpose of GLUT is to create a window for you and do event management. If you don't use GLUT for that, then don't use GLUT at all.
If it's for the teapot, well, you can have that without GLUT as well.
I know that in order to write a GTK application, I write a bunch of code which describes what is put in the main window, then I call:
gtk_main();
Any code statements after this do not get executed.
Now let's suppose I'd like my GTK app to display something I wrote with glut, which itself contains a bunch of statements about what graphics need to be set etc. then ends with the statement:
glutMainLoop();
Anything after this is not executed.
So my problem is that either of these two statements prevents me from calling the other.
Is there a way to execute a glut main loop inside a GTK widget ?
Is there a way to write a code that could somehow simultaneously call both a GTK main loop and a glut main loop (but called from the main program and rendered in a separate X window, not within a widget)? I've got a feeling this could be done with "threads"...
You don't. There's generally no point to it.
GLUT is a library for creating and managing OpenGL windows. GTK already has an OpenGL window in it. If you're using GTK, then there's no point in using GLUT. It's like having two vector math libraries or something.
You are running the main loops. gtk_main() runs until gtk_quit() is called.
gtk_main() at GTK.org
Runs the main loop until gtk_main_quit() is called. You can nest calls to gtk_main(). In that case gtk_main_quit() will make the innermost invocation of the main loop return.
Also, glutMainLoop() works the same way, it processes GL events forever.
glutMainLoop() at OpenGL.org
glutMainLoop() enters the GLUT event processing loop. This routine should be called at most once in a GLUT program. Once called, this routine will never return. It will call as necessary any callbacks that have been registered.
So, you you wan't both of these things to execute at the same time (I think they might interfere with each other so you might get unexpected results) then you will need to call gtk_main_iteration() from inside glut.
gtk_main_iteration() at GTK.org
Runs a single iteration of the mainloop. If no events are waiting to be processed GTK+ will block until the next event is noticed. If you don't want to block look at gtk_main_iteration_do() or check if any events are pending with gtk_events_pending() first.
Now.. GLUT doesn't have an equivalent to gtk_main_iteration() so you are going to need to register GLUT callbacks.
You could register a callback with GLUT that runs gtk_main_iteration() using glutIdleFunc(void (*func)(void)) which will run a callback for every frame - glutIdleFunc()..
Or you could give a callback to glutTimerFunc(unsigned int msecs,
void (*func)(int value), value) to call and check the return value of gtk_main_iteration() every 200msec or so.
I'd probably experiment with both, glutIdleFunc() might not always get called regularly enough for good responsiveness.
It really is worth looking at driving GTK's GL support though.
I have a program that uses GLUT for its OpenGL rendering. Now I need it to be inside of a MFC project so that it can work with another program component.
I've followed this tutorial: http://www.codeguru.com/cpp/g-m/opengl/openfaq/article.php/c10975__1/Setting-Up-OpenGL-in-an-MFC-Control.htm
I am calling the function that was the GLUT display callback when the timer fires, but that's not working because the rendering depends on something that happens in the GLUT idle callback. I don't understand where I should call the GLUT idle callback in my MFC program. Is there a separate event handler I should make for it, and if so, which event? Or am I doing something else completely wrong? I'm fairly familiar with OpenGL but this is my first experience with MFC so I am probably erring on that side.
Thanks so much for your time; I really appreciate it!
I just browsed the tutorial you've linked to; on page two, something along the following lines can be found (I cleaned up the code a little bit):
void COpenGLControl::OnTimer(UINT nIDEvent)
{
if(nIDEvent==1)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
oglDrawScene();
// try to insert your idle function code here
SwapBuffers(hdc);
}
CWnd::OnTimer(nIDEvent);
}
So, basically this is the replacement for glutIdleFunc suggested by the tutorial. I'd simply try to insert the code called in your idle function before the call to SwapBuffers.
I hope that helps.