if I close the app with the esc key, both the opengl screen and the command-line terminal are closed, but if I do it with the X key (using OF_WINDOW instead of OF_FULLSCREEN), the command-line remains running. I have to close it manually…
thanks for pointing that out… I think that’s a feature of glut, because in glut you can open and close windows, as well as iconify them. Since we aren’t using that functionality of glut, it might make sense to take the window close as a cue to exit -
The FreeGLUT for OS X from Fink works with OS X X11 but Xcode wasn’t able to launch it correctly. i.e. FreeGLUT from Fink doesn’t work with quartz OS X windows yet. It’ll be sweet when the FreeGLUT creators build that in.
We currently use freeglut in linux OF, regular glut in windows / osx OF.
hmm - I am wondering if we couldn’t get the window HWND using the same trick for fake fullscreen and then override the close button behavior - this would be nice because it would completely bypass having to hack glut.
some stuff I found seems to imply that you can both remove the button altogether as well as catching the WM_CLOSE message:
Okay I got it working. Basically we get the window handle, use the window handle to get the glut message handler, we then store that message handler and give the window our new message handler. Ourmessage handler listens for the close and destroy messages and calls OF_EXIT_APP - all other messages are passed onto the glut message handler.
D O P E!
The only issue is that the way we get the window handle is by looking for either the GLUT process name or the openFrameworks window title - both of which could exist for more than one app. I am sure there is a better way to get the window handle of a current process. But here is the code for now.
#ifdef TARGET_WIN32
WNDPROC currentWndProc;
LRESULT CALLBACK winProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_CLOSE:
//printf("I am being closed\n");
OF_EXIT_APP(0);
break;
case WM_DESTROY:
//printf("I am being destroyed\n");
OF_EXIT_APP(0);
break;
default:
//we give all other messages back to glut - aren't we nice :)
return currentWndProc(hwnd, Msg, wParam, lParam);
break;
}
return 0;
}
//--------------------------------------
static void fixCloseWindow(){
//find our window handle - we should find a better way of doing this
HWND vWnd = FindWindow(L"GLUT", NULL);
//store the current message handler
currentWndProc = (WNDPROC)::GetWindowLong(vWnd, GWL_WNDPROC);
//tell it to use our message handler instead
SetWindowLong(vWnd, GWL_WNDPROC, (long)winProc);
}
#endif
since the window you create is the top-most after OF starts up you could do this:
HWND wnd = WindowFromDC(wglGetCurrentDC());
to get the window (and avoid conflicts, I’d bet) as compared to using the title. this is what I use when I need to hook up libraries like the wacom library that need to talk to the window at a low level…
Nice - I imagine that is more foolproof than the method I am using.
Looks like the sure method is to get the processID of your app and then use that to return the window handle. There is no direct way to do this but the general method is to go through every window in the system and check the windows process id till it matches your apps process id.
we are working on it, and it could wind up (at least for windows) in 0.05. this solution is only for windows, we need to work on mac and linux too. for now, of course, ESC will quit the app just fine - z
Okay so I got the working code. Seems to work well!
Tested on VS in debug mode - need to test CW and DevC++
Learned some interesting things.
There are three windows associated with the openFrameworks process.
The console window, the glut window and an invisible openGL context.
This code enumerates through all windows and when it finds ones matching the process id it checks to make sure it gets the handle to just the glut window.
As a fallback if it can’t get the handle this way it gets the topmost window handle which should also be the glut app.
This code works for both clicking on the [x] button and control clicking on the tasking bar and selecting close.
#ifdef TARGET_WIN32
static WNDPROC currentWndProc;
static HWND handle = NULL;
static bool CALLBACK EnumWindowsProc(HWND hWnd, LPARAM processID){
//get the process id for each window
DWORD tempID = 0;
GetWindowThreadProcessId(hWnd, &tempID);
if( tempID == (DWORD)processID){
//three windows are associated with our id
//a console window, the glut window and an invisible gl context
//we get the name of each window to determin which is the one we want
wchar_t name[256];
GetClassName(hWnd, name, 255);
//if you want to see the process names
//wprintf(L"class name is %s \n", name);
//we check the process name to see if it GLUT
//if so we store the handle and then stop the search
if( wcsncmp(name, L"GLUT", 4) == 0 ){
handle = hWnd;
return false;
}
}
return true;
}
static LRESULT CALLBACK winProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam){
//we catch close and destroy messages
//and send them to OF
switch(Msg){
case WM_CLOSE:
OF_EXIT_APP(0);
break;
case WM_DESTROY:
OF_EXIT_APP(0);
break;
default:
//all other messages our handled by glut
return currentWndProc(hwnd, Msg, wParam, lParam);
break;
}
return 0;
}
//--------------------------------------
static void fixCloseWindow(){
//we get our current process id
DWORD ourProcessID = GetCurrentProcessId();
//we run through all windows and look for windows matching
//our process id
EnumWindows((WNDENUMPROC)EnumWindowsProc, ourProcessID);
//a fallback incase no window handle is found
//we use the top most.
if(handle == NULL){
handle = WindowFromDC(wglGetCurrentDC());
}
//store the current message event handler for the window
currentWndProc = (WNDPROC)::GetWindowLong(handle, GWL_WNDPROC);
//tell the window to now use our event handler!
SetWindowLong(handle, GWL_WNDPROC, (long)winProc);
}
#endif
Hi,
Where we might put the code Theo has posted?
I’ve tried in testApp.cpp and the application just hangs.
I’m using CodeBlocks, release mode, running in Windows.
Thanks,
Anna
I force the application to close at certain time.
Maybe it’s ugly code :? but getting the ProcessID and using TerminateProcess does it.
Ugly code but it works!
Thanks for your help.
Anna.