Drawing in a graphics window from a second thread in C - c

I am creating my first graphics program in C, using Codeblocks. I am trying to run two graphics loops simultaneously using two threads. One is for keyboard controls and the other is to move a rectangle vertically.
I have been trying to pass a graphics command from ObstacleHandler to the graphics window that main opens, using this condensed bit of code. When I run it, it will just crash as soon as it tries to draw the rectangle. If I initalise a window from the ObstacleHandler and then draw the rectangle, it will be fine. However, I need ObstacleHandler to draw the rectangle in the window that is initalised by the main.
Working example of the issue:
#include <pthread.h>
#include <semaphore.h>
#define NUM_THREADS 2
void *ObstacleHandler(void *threadid)
{
filled_rectangle(100, 120, 100, 120);
update_display();
pthread_exit(NULL);
return 0;
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
long t;
for(t=0;t<NUM_THREADS;t++)
{
printf("In main: creating thread %ld\n", t + 1);
}
pthread_create(&threads[1], NULL, ObstacleHandler, (void *)1);
initwindow(640, 480);
pthread_exit(NULL);
return 0;
}
The window has to be opened using the main function as the keyboard commands are in there. I cannot move them to the ObstacleHandler as that thread will be moving the obstacle.
Also, is there a way that you can have two graphics windows open and each one has a unique identification? I.e graph1 & graph2.
I am using allegro as the graphics library. However, not in the sample code.
I am new to programming so...! Any help would be appreciated!
Thanks

I use Borland/Embarcadero VCL so this could not be your case !!!
but my experience is that if you are accessing any Windows Visual stuff from different then owner window thread then somethings goes terribly wrong in the OS that creates:
visual artifacts
random unrelated crashes
unexpected behavior of the whole Application
this apply for any:
winapi call related to visual components of the window
drawing to window
any access to visual components (like adding line to memo,changing color of something,...)
I code win32 apps and this behavior is present on XP/SP3 x86,W7 x86,W7 x64(WoW64). I did not test different OS versions but suspect this behavior is present also there ...
What to do?
create your global message que
just a list of command you want to support
threads will fill your que
just add appropriate command to que like: redraw window, draw line ...,add to log ...
main window will read and execute it
inside OnTimer or OnIdle event
[Notes]
If you use threads to enhance rendering speed then you should render to thread local bitmap instead and when done add command to copy its contents to target visual component. Do not forget that the que has to be thread safe so add locks to it !!!

Related

Same GLUT application using single and double buffer?

Can I have a GLUT program with one of the windows with single buffer while the other uses double buffer?
The display mode can be set using the glutInitDisplayMode() but how to set it differently to different windows?
I tried using the glutSetWindow(), but either one of the two windows does not work.
glutInitDisplayMode sets the mode that will be used for the next window that is created. Therefore you can call it multiple times, once for each window:
glutInitDisplayMode(GLUT_DOUBLE);
int id0 = glutCreateWindow("double buffered");
glutInitDisplayMode(GLUT_SINGLE);
int id1 = glutCreateWindow("single buffered");
Alternatively, you can temporarily turn off double buffering by directly drawing onto the front buffer.
glDrawBuffer(GL_FRONT);
// ... single buffered drawing ...
glDrawBuffer(GL_BACK); // switch back to double buffered

How to use Notepad++ as editor for 7zip, without showing a console window?

This question could be generalized as: How to launch a given process with any intermediate process spawned having the same lifetime as the launched process, and without showing a console window. Specific arguments must be passed to the final process, but no arguments can be passed in the initial call.
To use Notepad++ as editor for 7zip you would need to launch notepad++.exe with the -multiInst command line parameter, otherwise it instantly closes and forwards arguments to the existing instance. Since 7zip picks up the changes you did to its temp file when the invoked program closes, you never get a chance to edit it.
Problem is, 7zip doesn't allow you to enter arguments for whatever program you're configuring as editor.
Obvious solutions that don't work, already tried:
Call a batch file, but then I'm stuck with an unsightly (and easy to close accidentally) console window for the duration of the edition - not acceptable.
Call a batch file which uses start to call Notepad++ : the console window does close, but unfortunately the batch executor process which is what Notepad++ was watching is gone, so it thinks you're already done editing, i.e. back to the initial problem.
Use wscript, which doesn't show a console window. Tracking the process lifetime is complex however (Wait for program to complete) and it makes you rely on old tech in maintenance mode that has a malware connotation.
How would you go about this? No solution I've tried myself or read about has been fully satisfying.
Note: this is not exactly the same question as Execute Batch File without Command line visible since this has the added requirement that whatever launcher used must stay open for the whole lifetime of the launched process, and that you can't pass command line arguments to the launcher.
I ended up writing my own utility which I'm tentatively calling NoConsoleProgramLauncher to serve as an intermediate between 7z and Notepad++. It's rough first draft code, but I thought sharing it might still be useful since this question has been without answer for three years.
#include <fstream>
#include <string>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <filesystem>
HINSTANCE hInst;
void launchProcess(std::wstring commandLine);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
//Get current executable's location
HMODULE hModule = GetModuleHandleW(NULL);
WCHAR executableFolder[MAX_PATH];
GetModuleFileNameW(hModule, executableFolder, MAX_PATH);
std::experimental::filesystem::v1::path path(executableFolder);
path.remove_filename();
path.append(L"NoConsoleProgramLauncher_Arguments.txt");
std::wifstream infile(path);
std::wstring commandLine;
std::getline(infile, commandLine);
commandLine += L" ";
commandLine += lpCmdLine;
launchProcess(commandLine);
}
void launchProcess(std::wstring commandLine)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
&commandLine[0], // Command line - C++ 11 guarantees that string's internal buffer is contiguous and null-terminated.
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Basically, if you've done a minimum of C++ coding before, it's a matter of pasting this into a new Visual Studio 2017 Windows Desktop Application project, fixing up the includes if needed, and building.
As you can see in the source code, when launched the executable looks for a file in the same folder as itself named "NoConsoleProgramLauncher_Arguments.txt", and calls the command line it finds in there. As specified in the question, no console window will be shown, and the program will wait for the spawned process to terminate before exiting, so 7zip keeps waiting to pick up the changes.
This is what I put in my NoConsoleProgramLauncher_Arguments.txt file:
"C:\Program Files (x86)\Notepad++\notepad++.exe" -multiInst -nosession
And in the 7zip configuration, I've set the editor to point to my NoConsoleProgramLauncher.exe program.
The real solution would of course be to gently pester the 7z authors about this, or better, submit a pull request to 7z to implement passing arguments to your editor of choice.

Simulated Mouseevents ignored on macOS in OpenGL

I have a larger project for which I want to have function that if run, clicks 10 times as fast as possible at the current cursor location.
This kind of works on my desktop, for example I tried running the program in my terminal and had my cursor on the menu bar. But if I switch to another application however (I tried it with a game in window mode) (I first let my program sleep for 4 seconds so I have enough time to switch), it just clicks once. The game is a shooter, so it should fire a couple of times fast but it just fires once and ignores all other events.
If I let my program sleep for 1 sec between cycles, it works.
Maybe I used the CGEvents wrong? Is there a difference between using MouseEvents and actually clicking? I mean shouldn't it be exactly the same for the game?
Here is my isolated code:
// Compile with: gcc -o click test.c -Wall -framework ApplicationServices
#include <ApplicationServices/ApplicationServices.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
// To click on current position (seems to work)
CGEventRef event = CGEventCreate(NULL);
CGPoint cursor = CGEventGetLocation(event);
CGEventRef click_down = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cursor, kCGMouseButtonLeft);
CGEventRef click_up = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, cursor, kCGMouseButtonLeft);
// Tried adding usleep between both events but anything under 1s doesnt work
for(int i = 0; i < 10; i++){
CGEventPost(kCGSessionEventTap, click_down);
// usleep(500);
CGEventPost(kCGSessionEventTap, click_up);
// usleep(500);
}
// Release the events
CFRelease(event);
CFRelease(click_down);
CFRelease(click_up);
}
What I read and tried but didn't help:
Simulate mouse on Mac
Simulating mouse clicks on Mac OS X does not work for some applications
-> Unfortunately didn't help or fix the problem
Synthetic click doesn't switch application's menu bar (Mac OS X)
I found the solution myself and it is really simple:
First of all I forgot that usleep is in microseconds and not miliseconds.
Furthermore apparently macOS buffers the clicks or keyboard inputs in the native environment but OpenGL doesn't. So of course it works if you pause for 1 second between clicks/keyboard presses but in OpenGL it just discards them if they are too fast. The solution is to wait the a small amount between clicks or keypresses. For me worked 100ms, that means usleep(100000), before and after the press down.

How can I have skinnier pthreads?

I have a really basic ncurses program to monitor machine statistics and launch remote xterms. It just sits on a window all day and helps me choose a not-heavily-loaded machine to work on. It works fine, and I love it dearly. But it's really fat. Much fatter than it needs to be, I think.
The program basically is as follows:
void * run(void * task) {
// once per minute:
popen( /* stats checking command */ )
// save output to global var
pclose
}
int main() {
// setup ncurses with halfdelay
for ( /* each machine */ )
pthread_create(somethread, NULL, run, (void *)somestruct);
while ( ( c = getch() ) != 'q' )
for ( /* each machine */ )
// print machine stats
// maybe launch an xterm
// die gracefully
}
And as stated above, it works just fine. The problem is that each thread has all the ncurses baloney tucked in private memory leading to one very fat process with a boatload of wasted bits.
The question, then, is this: how can I re-write or re-arrange this program so that each pthread doesn't carry around all the unnecessary ncurses stuff?
Side-question: You'll have to really sell me on it, but does anyone know of a better method than ncurses to do this? I want the stats on fixed positions in the terminal window, not scrolling text.

TTF_OpenFont fails on Nth attempt

I'm trying to make a game in C using SDL_ttf to display the score every time the diplay is refreshed. The code looks like :
SDL_Surface *score = NULL;
TTF_Font *font;
SDL_Color color = { 255, 255, 255 };
font = TTF_OpenFont( "/home/sophie/Bureau/snake/data/ubuntu.ttf", 28 );
if (font == NULL) {
printf("%s\n", TTF_GetError());
}
score = TTF_RenderText_Solid( font, "score to display", color );
SDL_BlitSurface( score, NULL, screen, NULL );
SDL_Flip(screen);
When I launch the game, everything works properly, but after a while the game crashes and I get the following error :
Couldn't open /home/sophie/Bureau/snake/data/ubuntu.ttf
libgcc_s.so.1 must be installed for pthread_cancel to work
Abandon (core dumped)
I tried different fonts but I still have this problem.
Then I used a counter in the main loop of the game and found that the game always crashes after the 1008th time, regardless of the speed I wanted it to work at (in snake everything goes faster when you score points).
I don't know where does the problem comes from, nor what exactly does the error message mean.
Please tell me if you have any ideas, or if my question is poorly formulated. I looked on several forums and found nothing corresponding to my case, I could use any help now !
Thanks in advance
It looks like you're repeatedly opening the font every time you go through this function:
font = TTF_OpenFont( "/home/sophie/Bureau/snake/data/ubuntu.ttf", 28 );
While it may not be in the main game loop as Jongware suspected, you mentioned that after 1008 executions through this code path, the code crashes.
What is happening is that some resource is being leaked. Either the resource needs to be released by calling TTF_CloseFont() or (more efficient) hold onto the handle after the first time you open it and re-use it each time. Use a static declaration for the font and initialize to NULL:
static TTF_Font *font = NULL;
Then, if it hasn't been opened yet, open it:
if (!font) {
font = TTF_OpenFont( "/home/sophie/Bureau/snake/data/ubuntu.ttf", 28 );
}
This will initialize font the first time while subsequent iterations over the code will not unnecessarily re-do the process and leak the resource.
You mentioned that the code crashes after 1008 times through this function. That's pretty close to 1024. As memory serves, Linux has a limit of 1024 file handles per process (this is probably tunable in the kernel but I have run into this limitation in debugging resource leaks before). There are probably 16 other file handles open by your process and then 1 process being leaked by each invocation of TTF_OpenFont. Once you go above 1024, boom.
You can check the number of open file handles of a particular process (<pid>) by inspecting the number of file descriptors in /proc/<pid>/fd/.

Resources