I use g_thread_new() to create a new thread to implement a flash image effect but only to show the later image but not to flash the 2 images.
And this is the code in the GThreadFunc function:
gdk_threads_enter();
draw_effect(background_map[mbullet.x][mbullet.y +1]);
g_usleep(110000);
draw_background(background_map[mbullet.x][mbullet.y +1]);
gdk_threads_leave();
And this is draw_**()function:
void draw_effect(GtkWidget *widget)
{
gtk_image_set_from_pixbuf(widget,fire_effect);
};
But the program can only show the image that draw_background()draws not draw_effct() does.
Unless I remove the gdk_threads_enter() andgdk_threads_leave() code,can the image flash as I wish.
What's wrong with my code?Can anybody help me?
You're modifying a widget from a thread other than the main thread, which usually leads to all kinds of problems and unexpected behaviors in many GUI libraries, not only gtk.
I do understand the motivation to use a thread here though, since you need to wait a while before redrawing the background.
I recommend that you call draw_effect directly instead of creating a thread, and then use g_timeout_add to schedule a call to a function that will redraw the background.
It should be something like this (please modify as needed and do read the docs):
Define this function:
gboolean
redraw_background (gpointer user_data) {
// ... get references to background_map and mbullet here ...
draw_background(background_map[mbullet.x][mbullet.y +1]);
return FALSE; // so it isn't called again
}
And elsewhere:
// Draw what you need to draw
draw_effect(background_map[mbullet.x][mbullet.y +1]);
// Schedule draw_background 110 ms from now
// user_data will be passed as a parameter to redraw_background
g_timeout_add (110, // milliseconds
redraw_background,
user_data);
Related
Within my GTK+ application, an instance of GtkFileChooserWidget is permanently visible. By selecting files (single click), the user might process a file. This is done by the callback function switch_file().
g_signal_connect (chooser, "selection-changed", G_CALLBACK (switch_file), gs);
The function switch_file() is sometimes slow as it waits for user response in modal dialogs. Everything works fine unless a file which is currently selected in the FileChooser is deleted (by the application itself or any other process on the system). The FileChooser, which obviously runs in an own thread, submits then a secondary call to switch_file() which leads to a mess. I tried to prevent the multiple calls by using a mutex:
static void switch_file (GtkWidget *widget, gpointer data)
{
info_t *gs = data;
int err;
if ((err = pthread_mutex_lock (&gs->mutex)))
DebugExit ("pthread_mutex_lock(): %s", strerror (err));
/* ... */
}
However, all calls to the callback function are done within the same thread on the same stack. So, the second call to pthread_mutex_lock() fails (PTHREAD_MUTEX_ERRORCHECK_NP is used) and lets the process exit.
Is there a possibility to postpone the calls to the callback function while switch_file() is working? For user events (key presses) it already works but not for signals caused in parallel by deletes files.
If the signals cannot be postponed: What would be a signal-safe solution to collect all selected files and process them subsequently (within the main thread)?
I found that the best solution is to ignore the signal. I am not sure whether the following solution is absolutely safe but it works.
static int switch_ignore = false;
static void switch_file (GtkWidget *widget, gpointer data)
{
info_t *gs = data;
if (switch_ignore)
return;
switch_ignore = true;
/* Do some work on the file system. */
switch_ignore = false;
}
Do graphics cards typically write their output to some place in memory which I can access? Do I have to use the driver? If so, can I use OpenGL?
I want to know if it's possible to "capture" the output of a VM on Linux which has direct access to a GPU, and is running Windows. Ideally, I could access the output from memory directly, without touching the GPU, since this code would be able to run on the Linux host.
The other option is to maybe write a Windows driver which reads the output of the GPU and writes it to some place in memory. Then, on the Linux side, a program can read this memory. This seems somewhat impossible, since I'm not really sure how to get a process on the host to share memory with a process on the guest.
Is it possible to do option 1 and simply read the output from memory?
I do not code under Linux but in Windows (you are running it in emulator anyway) you can use WinAPI to directly access canvas of any window or even desktop from 3th party App. Some GPU overlays could be problematic to catch (especially DirectX based) but I had no problems with mine GL/GLSL for now.
If you got access to App source you can use glReadPixels for image extraction from GL directly (but that works only for current GL based rendering).
Using glReadPixels
As mentioned this must be implemented directly in the targeted app so you need to have it source code or inject your code in the right place/time. I use for screenshoting this code:
void OpenGLscreen::screenshot(Graphics::TBitmap *bmp)
{
if (bmp==NULL) return;
int *dat=new int[xs*ys],x,y,a,*p;
if (dat==NULL) return;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
if ((bmp->Width!=xs)||(bmp->Height!=ys)) bmp->SetSize(xs,ys);
if ((bmp->Width==xs)&&(bmp->Height==ys))
{
glReadPixels(0,0,xs,ys,GL_BGRA,GL_UNSIGNED_BYTE,dat);
glFinish();
for (a=0,y=ys-1;y>=0;y--)
for (p=(int*)bmp->ScanLine[y],x=0;x<xs;x++,a++)
p[x]=dat[a];
}
delete[] dat;
}
where xs,ys is OpenGL window resolution, you can ignore the whole bmp stuff (it is VCL bitmap I use to store screenshot) and also can ignore the for it just copy the image from buffer to bitmap. So the important stuff is just this:
int *dat=new int[xs*ys]; // each pixel is 32bit int
glReadPixels(0,0,xs,ys,GL_BGRA,GL_UNSIGNED_BYTE,dat);
glFinish();
You need to execute this code after the rendering is done otherwise you will obtain unfinished or empty buffer. I use it after redraw/repaint events. As mentioned before this will obtain only the GL rendered stuff so if your App combines GDI+OpenGL it is better to use the next approach.
WinAPI approach
To obtain Canvas image of any window I wrote this class:
//---------------------------------------------------------------------------
//--- screen capture ver: 1.00 ----------------------------------------------
//---------------------------------------------------------------------------
class scrcap
{
public:
HWND hnd,hnda;
TCanvas *scr;
Graphics::TBitmap *bmp;
int x0,y0,xs,ys;
scrcap()
{
hnd=NULL;
hnda=NULL;
scr=new TCanvas();
bmp=new Graphics::TBitmap;
#ifdef _mmap_h
mmap_new('scrc',scr,sizeof(TCanvas() ));
mmap_new('scrc',bmp,sizeof(Graphics::TBitmap));
#endif
if (bmp)
{
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
}
x0=0; y0=0; xs=1; ys=1;
hnd=GetDesktopWindow();
}
~scrcap()
{
#ifdef _mmap_h
mmap_del('scrc',scr);
mmap_del('scrc',bmp);
#endif
if (scr) delete scr; scr=NULL;
if (bmp) delete bmp; bmp=NULL;
}
void init(HWND _hnd=NULL)
{
RECT r;
if (scr==NULL) return;
if (bmp==NULL) return;
bmp->SetSize(1,1);
if (!IsWindow(_hnd)) _hnd=hnd;
scr->Handle=GetDC(_hnd);
hnda=_hnd;
resize();
}
void resize()
{
if (!IsWindow(hnda)) return;
RECT r;
// GetWindowRect(hnda,&r);
GetClientRect(hnda,&r);
x0=r.left; xs=r.right-x0;
y0=r.top; ys=r.bottom-y0;
bmp->SetSize(xs,ys);
xs=bmp->Width;
ys=bmp->Height;
}
void capture()
{
if (scr==NULL) return;
if (bmp==NULL) return;
bmp->Canvas->CopyRect(Rect(0,0,xs,ys),scr,TRect(x0,y0,x0+xs,y0+ys));
}
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
Again it uses VCL so rewrite bitmap bmp and canvas scr to your programing environment style. Also igneore the _mmap_h chunks of code they are just for debugging/tracing of memory pointers related to some nasty compiler bug I was facing at that time I wrote this.
The usage is simple:
// globals
scrcap cap;
// init
cap.init();
// on screenshot
cap.capture();
// here use cap.bmp
If you call cap.init() it will lock on the whole windows desktop. If you call cap.init(window_handle) it will lock on specific visual window/component instead. To obtain window handle from 3th app side see:
is ther a way an app can display a message without the use of messagebox API?
Sorry it is on SE/RE instead of here on SE/SO but My answer here covering this topic was deleted. I use this for video capture ... all of the animated GIFs in my answers where created by this code. Another example could be seen on the bottom of this answer of mine:
Image to ASCII art conversion
As you can see it works also for DirectX overlay with media player classic (even Windows PrintScreen function cant do it right). As I wrote I got no problems with this yet.
Beware visual stuff WinAPI calls MUST BE CALLED FROM APP MAIN THREAD (WNDPROC) otherwise serious problems could occur leading to random unrelated WinAPI calls exceptions anywhere in the App.
I am new to Gtk and this is my very first Gtk project. I am using C and Gtk+ 2 on Code::Blocks on Windows 7. In my project, I have a main window which initially shows a home screen, holding a button to "Run" the project and some other buttons ("Exit", "About" etc). When this "Run" button is clicked, the program has to read and write some large text files, and then show a new screen with some new data (I am creating this new screen by destroying all the previous children of the main window and putting in new stuff into it).
Now due to large sizes of those text files, the program lags for some time when Run is clicked, so I want to show an intermediate screen having some message like "Loading...". But I am unable to do it, because this intermediate screen is never shown.
Here is what I have; I hope the code makes it clear:
GtkWidget *windowMain = NULL;
GtkWidget *vboxMain = NULL;
//These 2 are global.
void home_screen() //Works well
{
//...Created new main window...
//...Created new main vbox...
//...Added vboxMain to windowMain...
GtkWidget *menuButton = gtk_button_new_with_label("Run");
g_signal_connect (menuButton, "clicked", G_CALLBACK (intermediate_screen), NULL);
gtk_box_pack_start (GTK_BOX (vboxMain), menuButton, TRUE, TRUE, 0); //Add button to vboxMain.
gtk_widget_show_all (windowMain);
}
void intermediate_screen() //Is not shown at correct time
{
// CLEAR MAIN WINDOW:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
GtkWidget *label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label1), "<b>Loading...</b>");
gtk_container_add (GTK_CONTAINER (windowMain), label);
gtk_widget_show_all(windowMain);
prepare_files(); //Function to work with the text files
}
void prepare_files() //Starts working before "Loading..." is shown
{
//Some file handling which takes some time to complete.
next_screen();
}
void next_screen()
{
// CLEAR MAIN WINDOW AGAIN TO CLEAR THE "Loading..." LABEL:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
vboxMain = gtk_vbox_new (FALSE, 5);
gtk_widget_set_size_request (vboxMain, 600, 600);
gtk_container_add (GTK_CONTAINER (windowMain), vboxMain);
//Add components to the vboxMain
gtk_widget_show_all(windowMain);
}
Problem is that intermediate_screen() shows the "Loading" message only after the prepare_files() function has been completed - and hence it is of no use. During all that time, only homescreen is being shown... In fact, the next_screen() is shown immediately after, so "Loading" does not even show up. But shouldn't it show the loading message during all that lag, as the prepare_files() function is called later?
What am I doing wrong and how should I correctly do it?
Sorry if this was something obvious. As I said I am a beginner in Gtk+ .
Gtk+ drawing happens on a timer that fires in the same thread as your code. In other words the drawing code can only run when your code is not running: when "Run" is clicked, the next draw can only happen after intermediate_screen() has returned (and "Loading..." screen has already been replaced).
You could add some hacks in intermediate_screen() that runs a few iterations of the main loop so at least one draw would happen but that would still be bad and unresponsive design. There are 2 possible better solutions:
Use an asynchronous API like GIO to read and write to files: this means no function in your code ever runs long enough to disrupt drawing or interacting with the UI. Implementing this is a little more complex than synchronous reads (like the ones you probably use now), one possible short version is: Create a GFile, call g_file_read_async(), in the callback call g_file_read_finish(), create a GDataInputStream from the GFileInputStream you get, then use g_data_input_stream_read_*_async() functions to start reading lines or other chunks of the file, and in that callback get the data with g_data_input_stream_read_*_finish().
Alternatively create a new thread and read the data in that thread using the same reading code you now use. The down side is that you now have to deal with thread-safety yourself -- this can be difficult, and threading bugs are the hardest to debug.
In my opinion option #1 is the best compromise in almost all situations where an asynchronous API is available. Note that if your own processing of the file contents takes a long time, you should do that in small chunks as well (usually it works out nicely so you can e.g. read one line or larger chunk asynchronously and process the line/chunk in the callback).
I'm working on a project in c, where I'm going to make some heavy physics calculations, and I want the ability to see the results when I'm finished. The way it works now is that I run GLUT on the main thread, and use a seperate thread (pthread) to do input (from terminal) and calculations. I currently use glutTimerFunc to do the animation, but the problem is that that function will fire every given time intervall no matter what. I can stop the animation by using an if statement in the animation function, stopping the variables from being updatet, but this uses a lot of unnecessary resources (I think).
To fix this problem I was thinking that I could use an extra thread with a custom timer function that I could controll myself (without glutMainLoop messing things up). Currently this is my test function to check if this would work (meaning that the function itself is in no way finished). It runs in a seperate thread createt just before glutMainLoop:
void *threadAnimation() {
while (1) {
if (animationRun) {
rotate = rotate+0.00001;
if (rotate>360) {
rotate = rotate-360;
}
glutSetWindow(window);
glutPostRedisplay();
}
}
}
The specific problem I have is that the animation just runs for a couple of seconds, and then stops. Does anybody know how I can fix this? I am planning to use timers and so on later, but what I'm looking for is a way to ensure that glutPostRedisplay will be sent the right place. I tought glutSetWindow(window) was the solution, but apparently not. If I remove glutSetWindow(window) the animation still works, just not for as long, but runs much faster (so maybe glutSetWindow(window) takes a lot of resources?)
btw the variable "window" is created like this:
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(854, 540);
glutInitWindowPosition(100, 100);
window = glutCreateWindow("Animation View");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
timerInt = pthread_create(&timerThread, NULL, &threadAnimation, NULL);
glutMainLoop();
I don't acctually know if this is correct, but it compiles just fine. Any help is greatly appriciated!
Here's a little idea, create class that will contain all dynamic settings:
class DynamicInfo {
public int vertexCount;
public float *vertexes;
...
DynamicInfo &operator=( const DynamicInfo &origin);
};
And than main application will contain those:
DynamicInfo buffers[2];
int activeBuffer = 0;
In animation thread just draw (maybe use some threads locks for one variable):
DynamicInfo *current = buffers + activeBuffer; // Or rather use reference
In calculations:
// Store currently used buffer as current (for future manipulation)
DynamicInfo *current = buffers + activeBuffer;
// We finished calculations on activeBuffer[1] so we may propagate it to application
activeBuffer = (activeBuffer + 1)%2;
// Let actual data propagate to current buffer
(*current) = buffers[activeBuffer];
Again it's locking one variable.
g_timeout_add (100, (GSourceFunc) read_next_packets, NULL);
I can feel the GUI response is slow because of the above statement.
How can I make it work asynchronously so that it doesn't affect the GUI response?
Callbacks of these functions are called in the main thread. If read_next_packets is slow or blocks for I/O, you should instead create a separate thread for it that doesn't interfere with GUI. When that thread needs to inform the main thread of something, then it can use g_idle_add to transfer execution to the main thread scope.
In pseudocode:
// In a dedicated thread:
while (...) {
Package* package = do_read (); // This call is slow or blocks.
if (package)
g_idle_add ((GSourceFunc) process_package, package);
}
// This is called in the main thread. Should be fast to not freeze GUI.
gboolean
process_package (Package* package)
{
...
package_free (package);
}