I have seen a rare amount of programs, having animated window icons.
From a distant vantage point, this could be rather beneficially isn't it..
I took the rudder in the process of inventing one function to do so.
It does what you probably thought of and using Sleep() to simulate intervals after each "frame".
I don't have to say that using WinAPI in major programs is a bad idea as well as the fact that the program will freeze until the function terminates.
Back on track. I am looking for a possibility to avoid this behavior.
It is understandable, hence no one wants a non-functional but take a note WITH ANIMATED ICON program.
You are probably calling your function from the Main Event Loop. This is the thread where all sort of GUI events are handled, including mouse clicks and key presses. If you call Sleep from within this thread, all these processing tasks will be pending and your program will freeze.
To avoid this behavior, use g_timeout_add. This function will call a function at regular intervals from within the Main Event Loop (so no need to do it yourself). You need to define a function like this:
// define this function somewhere
gboolean animate(gpointer user_data) {
// cast user_data to appropriate type
// supposing you have a AnimationParameters class with everything you need...
AnimationParameters* animParams = (AnimationParameters*)user_data;
// update animation
// ...
return TRUE; // return TRUE to call function again, FALSE to stop
}
Elsewhere in your code, to start the animation:
AnimationParameters* animationParameters = new AnimationParameters(...);
g_timeout_add (30, // call every 30 milliseconds
animate,
animationParameters);
Hope it helps.
Related
I'm having issues with my termbox program rendering the screen and handling keyboard events. Recently, I've finished a C and C++ class at my university. I wanted to demonstrate my knowledge by creating a basic Snake game. The first steps, I wanted to get a simple render loop going and have a block of text simply move leftward and exit the game upon reaching the 0th x-coordinate. The issue arises when continuing to the next render frame, because the game is running single-threaded the next frame won't be rendered until a new keyboard event is accepted. Ordinarily, I would expect the game to continue rendering regardless of events, new events affecting the new frame.
As for potential solutions, I thought about using multiple threads to run the game loop and handle keyboard events. But, I think this would be overkill for such a small problem, there are likely easier alternatives than having to manage multiple threads for a simple snake game.
As for the code, it's as simple as:
while (1)
{
tb_clear();
draw(gameState);
tb_present();
struct tb_event event;
tb_poll_event(&event);
if (event.ch == 'q')
break;
}
After digging through the header file a bit more I found a method which doesn't wait forever.
/* Wait for an event up to 'timeout' milliseconds and fill the 'event'
* structure with it, when the event is available. Returns the type of the
* event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
* there were no event during 'timeout' period.
*/
SO_IMPORT int tb_peek_event(struct tb_event *event, int timeout);
I'm working on a library that creates transparent X windows and uses cairo to draw on them. There is an event loop implemented in the main thread, while the drawing operations take place in a separate thread within a loop. The latter looks like this
while (self->_running) {
PyGILState_Release(gstate);
usleep(1000); // Sleep 1 ms
gstate = PyGILState_Ensure();
if (self->_expiry <= gettime()) {
draw(self, args_tuple); // All the cairo code is in here
self->_expiry += interval;
interval = self->interval;
}
}
The event loop calls XNextEvent periodically to trap key/button presses only. The window is mapped before the new UI thread is started from the main thread.
When the interval between iterations on the UI thread (the self->inteval value above) is large (order of seconds), the window stays transparent on the first iteration of the loop, and it only gets painted on from the second iteration onward. Calling draw right before the while loop doesn't help, unless there is a pause of some milliseconds in between calls to draw. For example, if I put interval = 25 right before the while loop, then the second call to draw paints on the window in most of the executions of the application implementing this code.
Things that I have tried:
cairo_surface_flush and XFlush right after draw don't seem to work
Sending an Expose event doesn't seem to help either.
How can I make sure that my loop starts painting on the window from the first iteration?
What I'm missing is the ExposureMask flag in the call to XSelectInput. With this flag set, one then has to look for Expose events in the event loop with the following pattern:
switch (e.type) {
case Expose:
if (e.xexpose.count == 0) {
BaseCanvas__redraw(canvas);
}
return;
}
The redraw operation doesn't need to be the full set of draw operations. Having modified the cairo context, it is enough to repaint it on the destination with no more than this
void
BaseCanvas__redraw(BaseCanvas * self) {
cairo_save(self->context);
cairo_set_operator(self->context, CAIRO_OPERATOR_SOURCE);
cairo_paint(self->context);
cairo_restore(self->context);
}
To me it looks like you are mapping the window and then immediately starting a thread that tries to draw to the window. Thus, if you try to draw before the window manager actually made the window visible, your drawing goes nowhere. If the window manager wins the race and the window actually becomes visible before your draw, the drawing actually works.
Your own answer is not an answer to your question. The question is "why does it stay transparent in the first iteration?" while your answer is (basically) "Don't use threads, just do all drawing in the main loop".
(Of course, handling Expose events is the right thing to do, but that's not what the question asked.)
I will keep it simple
I have the function inside_thread that runs a while loop and calls the function update_progressbar that simply updates a GtkStatusBar.
I am calling inside_thread in a thread using g_thread_new("processing", GThreadFunc, NULL); from a callback function on_starter_clicked.
It tends to do the job, it works fast and it updates the status bar according to the progress of the while loop.
The problem is that sometimes (at unspecified place) the progress bar gets stuck and it gets unstuck if I mouseenter or mouseleave a button in the application. Very strange behavior I must admit
What could be wrong?
No, you can't update the GtkProgressBar from another thread. There are two solutions to your problem, and both involve gdk_threads_idle_add():
1. Wait for the Idle Callback
In this case,your thread would schedule the progress bar update with gdk_threads_add_idle(), then wait for it to finish. I don't know what the best way to do this with GLib is, but there's probably something you can do (GMutex?). The idea is this:
gboolean updateProgressBar(gpointer data)
{
gtk_progress_bar_set_fraction(progressbar, value);
tellOtherThreadToContinue();
return G_SOURCE_REMOVE; // == FALSE
}
gpointer otherThread(gpointer data)
{
while (condition) {
doStep();
gdk_threads_idle_add(updateProgressBar, NULL);
waitForProgressBarToBeUpdated();
}
return (gpointer) 0;
}
2. Forego the Thread Entirely and Loop the Idle Callback
If the idle callback returns G_SOURCE_CONTINUE (== TRUE), GTK+ will schedule your function again for the next idle period. You can take advantage of this to rewrite your while loop as an idle callback:
gboolean loop(gpointer data)
{
if (condition)
return G_SOURCE_REMOVE;
doStep();
gtk_progress_bar_set_fraction(progressbar, value);
return G_SOURCE_CONTINUE;
}
// in your code, start the loop going with
gdk_threads_idle_add(loop, NULL);
Regardless of what you choose, you can take advantage of the data parameter to both the idle callback and the thread to pass data those functions would need around. Just be careful not to pass a pointer to a local variable to the idle callback, as that might run after your function returns (and the variable goes out of scope/ceases to exist).
Note that regardless of what you do, you'll be waiting for the progress bar to update (and in the latter case, redraw). If things become too slow, you may want to look into updating the progress bar in chunks. This, however, depends entirely on how many steps you have.
The answer to this question is very specific. Assuming you want to update your progress bar according to the progress of a loop you have to do 3 things.
Create a thread in which you will run your loop
Ensure the loop with debugging and if there is a need for mutexes
[a] Schedule the progress bar update when GTK is able to using gdk_threads_add_idle ()
and do note that this function will call the progress bar updating function with G_PRIORITY_DEFAULT_IDLE and let it be. Otherwise if your curious look at g_idle_add_full ()
[b] Terminate the thread when it is no longer needed (progress 100%)
GTK+ is not multithreading safe. It can not always re-draw components, especially if it is busy, deadlocked in an unspecified iteration of the main-loop. It is a matter of synchronization, which is why you need to schedule the update.
[a] Since you have values to give to the progress bar updating functions in order to do your interval arithmetics, you have to pass them as an array to give to the function.
[b] The other problem occurs at the end of the whole process. Your application will crash unless you ensure to no longer update the progress bar. You can imply a mutex or any sort of restrictions you come up with.
IMPORTANT: This could not be the only reason for crash after the processing. As the other answer clearly states.. you can not just update gtk component through another thread. To omit this, simply call gtk_main_iteration() after the loop, before the thread terminates so it iterates one more time to update the progress bar properly and on time.
A simple exemplification with pseudo-code implementation of the whole thing:
gboolean on_starter_clicked () // callback function
{
g_thread_new("processing", proceed_thread, NULL);
}
gpointer proceed_thread (gpointer data) // processing-thread
{
while(1)
{
// Process whatever needs to be processed
// break when it needs to be breaked
gint data[] = { partial, full };
gdk_threads_add_idle(update_progressbar, data);
}
gtk_main_teration();
}
gboolean update_progressbar (gpointer data) // updating function
{
gint *d = (gint*)data;
gdouble fraction = ( (d[0] * 100.0) / d[1] ); // Calculating your interval
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(...), fraction / 100.0 );
}
One more thing. You may notice that there will be a slightly decrease of the movement smoothness of the progress indicator. That because GTK+ schedules the update, which is fully understandable that doesn't mean "immediately".
I've got a little GTK-Application with two buttons (A, B) and a drawing area (C).
When I click on A, C's size should be recalculated and set with gtk_widget_set_size_request(). This will cause an expose-event, whose handler will calculate some data. Further, the click on A will emit a clicked signal at B, whose handler needs the data calculated by C's expose-event.
In fact everything works fine, but the expose-event delays somehow, and the clicked handler is called before and the data (you may guess it) is missing.
a_handler() {
new_size = calculate_size();
gtk_widget_set_size_request(C, new_size); //Will cause expose-event
g_signal_emit_by_name(B, "clicked");
}
b_handler() {
calculate_something(data); //Error
}
c_handler() {
draw_something();
data = calcluate_data();
}
What can I do?
Gtk (and most other GUI toolkits) does the painting and event handling all in one thread. Therefore when the expose event is emitted, it goes into a queue and will be handled only after a_handler returns.
The best approach in my opinion would be to move the calculation somewhere else, if there is not some good reason to tie it into GUI drawing. For example, there could be a separate method calculate_data that is called both from b_handler and c_handler.
The next best way is to call gdk_window_process_updates to force the expose event to be handled immediately:
http://developer.gnome.org/gdk/stable/gdk-Windows.html#gdk-window-process-updates
The ugly fix is typically to add calls to gtk_main_iteration(), for instance between the call to gtk_widget_set_size_request() and the signal-emission.
I'm extending a GTK-application that does a group of operations that takes high CPU loads. I want to include the possibility to stop this operation by clicking on a button in the GUI.
The problem is that, as expected, the signal coming from the button is actually fired just after the operation is completed.
For now, the code kinda looks like this:
[...]
// code snippet to show the dialog and to enable user interactions with the buttons on the lower side of the window
while(TRUE) {
gint run = gtk_dialog_run (window_main);
if (run == GTK_RESPONSE_APPLY) {
gboolean success = start_long_operation();
}
else if (run == GTK_RESPONSE_HELP) {
open_about();
}
else if (run == GTK_RESPONSE_CANCEL) {
stop_long_operation();
}
else {
gtk_widget_destroy (window_main);
return;
}
}
I've declared a global variable busy_state that is checked by the long operation's function: if it is TRUE, simply the inner loop continues to cycle. Else, the loop exits and the function returns a result.
stop_long_operation() simply sets this global var to FALSE.
As written before, I can't press the "stop" button and "send" GTK_RESPONSE_CANCEL until the operation finishes, because it blocks the entire window.
I've tried the use of while (g_main_context_iteration(NULL, FALSE)) trick inside the stop_long_operation() function, as explained in the gtk's docs, but without results.
Do I really need to set up a multithread functionality? Can I avoid this?
Thanks for the help.
If you can break up your long operation into multiple smaller tasks you may be able to avoid using threads. The easiest way would be to just create a callback that you would pass to g_idle_add (or g_idle_add_full). Each time the callback runs it does a small amount of work, then returns TRUE. When the the task is completed, return FALSE and the callback not be run again. When you would like to interrupt the task, simply remove the callback by passing the value returned by g_idle_add to g_source_remove.
If you can't break up the operation then threads are pretty much your only choice. g_thread_new is the low-level way to do that, but it's generally easier to use a GThreadPool. A more advanced option would be to use g_simple_async_result_run_in_thread.
Here's another option if you don't want to use threads (although you should use threads and this is very insecure):
Use processes. Processes are much simpler, and can allow you some greater flexibility. Here's what you need to do:
Create another C/C++/Any language you want program that does the task
Spawn it using spawn() or popen()
(Optional) Pass arguments using the command line, or IPC
When the button is pressed, use either the kill() call on UNIX, or the Win32 kill function to kill the process. You can use SIGTERM on UNIX and register a handler so that you can have a controlled shutdown.