Ejemplo n.º 1
0
//----------------------------------------------------------------------------
static pascal OSStatus ProcessKeyModifierChanged (EventHandlerCallRef,
        EventRef evt, void*)
{
	static UInt32 sLastState = 0;

	UInt32 currState;
	GetEventParameter(evt, kEventParamKeyModifiers, typeUInt32, 0,
	                  sizeof(currState), 0, &currState);
	currState &= 0x0000FFFF;

	if (currState != sLastState)
	{
		WindowApplication* theApp =
		    (WindowApplication*)Application::TheApplication;

		CGrafPtr currPort;
		GetPort(&currPort);
		SetPortWindowPort((WindowRef)(theApp->GetWindowID()));
		Point mouseLoc;
		GetMouse(&mouseLoc);
		SetPort(currPort);

		ProcessModifier(theApp, shiftKey, mouseLoc, currState, sLastState);
		ProcessModifier(theApp, controlKey, mouseLoc, currState, sLastState);
		ProcessModifier(theApp, optionKey, mouseLoc, currState, sLastState);
		ProcessModifier(theApp, cmdKey, mouseLoc, currState, sLastState);

		sLastState = currState;
	}

	// Allow standard handler to run.
	return eventNotHandledErr;
}
Ejemplo n.º 2
0
void WindowManager::Render()
{
    list<WindowApplication*>::reverse_iterator windowIt = _windows.rbegin();
    list<WindowApplication*>::reverse_iterator finalWindow = _windows.rend();
    WindowApplication* ontop = 0;
    while (windowIt != finalWindow)
    {
        WindowApplication* window = (WindowApplication*)*windowIt;
        if (window->Settings->Enabled == 1)
        {
            window->Render();
            if (window->Settings->Fullscreen)
            {
                window->RenderFullscreen();
                FullScreenEnabled = 1;
                break;
            }

            if (window->Settings->OnTop == 1)
                ontop = window;
            else
                RenderWindow(window);
        }
        windowIt++;
    }
    if (ontop)
        RenderWindow(ontop);
    ontop = 0;
}
Ejemplo n.º 3
0
//----------------------------------------------------------------------------
static pascal OSStatus ProcessMouseDragged (EventHandlerCallRef, EventRef evt,
        void*)
{
	Point mouseLoc;
	GetEventParameter(evt, kEventParamMouseLocation, typeQDPoint, 0,
	                  sizeof(mouseLoc), 0, &mouseLoc);

	EventMouseButton mouseButton;
	GetEventParameter(evt, kEventParamMouseButton, typeMouseButton, 0,
	                  sizeof(mouseButton), 0, &mouseButton);

	UInt32 modifiers;
	GetEventParameter(evt, kEventParamKeyModifiers, typeUInt32, 0,
	                  sizeof(modifiers), 0, &modifiers);

	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	CGrafPtr currPort;
	GetPort(&currPort);
	SetPortWindowPort((WindowRef)(theApp->GetWindowID()));
	GlobalToLocal(&mouseLoc);
	SetPort(currPort);

	theApp->OnMotion(mouseButton, mouseLoc.h, mouseLoc.v, modifiers);

	// Allow standard handler to run.
	return eventNotHandledErr;
}
Ejemplo n.º 4
0
//----------------------------------------------------------------------------
static pascal void ProcessTimer (EventLoopTimerRef, void*)
{
	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	theApp->OnIdle();
}
Ejemplo n.º 5
0
//----------------------------------------------------------------------------
static pascal OSStatus ProcessWindowBoundsChange (EventHandlerCallRef,
        EventRef evt, void*)
{
	UInt32 attributes;
	GetEventParameter(evt, kEventParamAttributes, typeUInt32, 0,
	                  sizeof(attributes), 0, &attributes);

	Rect rect;
	GetEventParameter(evt, kEventParamCurrentBounds, typeQDRectangle, 0,
	                  sizeof(rect), 0, &rect);

	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	if (attributes & kWindowBoundsChangeUserDrag
	        ||  attributes & kWindowBoundsChangeOriginChanged)
	{
		// Bounds are changing due to window moving.
		theApp->OnMove(rect.top, rect.left);
	}
	else if (attributes & kWindowBoundsChangeUserResize
	         ||  attributes & kWindowBoundsChangeSizeChanged)
	{
		// Bounds are changing due to window resizing.
		theApp->OnResize(rect.right - rect.left, rect.bottom - rect.top);
	}

	// Allow standard handler to run.
	return eventNotHandledErr;
}
Ejemplo n.º 6
0
//----------------------------------------------------------------------------
static void PassiveMotionCallback (int x, int y)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnPassiveMotion(x, y);
    }
}
Ejemplo n.º 7
0
//----------------------------------------------------------------------------
static void MotionCallback (int x, int y)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnMotion(gsButton, x, y, gsGLUTModifiers);
    }
}
Ejemplo n.º 8
0
//----------------------------------------------------------------------------
static void SpecialKeyUpCallback (int key, int x, int y)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnSpecialKeyUp(key, x, y);
    }
}
Ejemplo n.º 9
0
//----------------------------------------------------------------------------
static void KeyUpCallback (unsigned char key, int x, int y)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnKeyUp(key, x, y);
    }
}
Ejemplo n.º 10
0
//----------------------------------------------------------------------------
static void IdleCallback ()
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnIdle();
    }
}
Ejemplo n.º 11
0
//----------------------------------------------------------------------------
static void DisplayCallback ()
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnDisplay();
    }
}
Ejemplo n.º 12
0
//----------------------------------------------------------------------------
static void ReshapeCallback (int width, int height)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnResize(width, height);
        theApp->OnDisplay();
    }
}
Ejemplo n.º 13
0
//----------------------------------------------------------------------------
static pascal OSStatus ProcessWindowRedraw (EventHandlerCallRef, EventRef,
        void*)
{
	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	theApp->OnDisplay();

	// Allow standard handler to run.
	return eventNotHandledErr;
}
Ejemplo n.º 14
0
//----------------------------------------------------------------------------
static void Terminate ()
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        theApp->OnTerminate();
        glutDestroyWindow(theApp->GetWindowID());
        Renderer* renderer = (Renderer*)theApp->GetRenderer();
        delete0(renderer);
    }
}
Ejemplo n.º 15
0
//----------------------------------------------------------------------------
static void KeyDownCallback (unsigned char key, int x, int y)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        if (key == theApp->KEY_TERMINATE)
        {
            exit(0);
        }

        theApp->OnKeyDown(key, x, y);
    }
}
Ejemplo n.º 16
0
//----------------------------------------------------------------------------
void WindowApplication::GetMousePosition (int& x, int& y) const
{
	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	CGrafPtr currPort;
	GetPort(&currPort);
	SetPortWindowPort((WindowRef)(theApp->GetWindowID()));
	Point mouseLoc;
	GetMouse(&mouseLoc);
	SetPort(currPort);

	x = (int)mouseLoc.h;
	y = (int)mouseLoc.v;
}
Ejemplo n.º 17
0
//----------------------------------------------------------------------------
static pascal OSStatus ProcessKeyDown (EventHandlerCallRef, EventRef evt,
                                       void*)
{
	char charCode;
	GetEventParameter(evt, kEventParamKeyMacCharCodes, typeChar, 0,
	                  sizeof(charCode), 0, &charCode);

	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	CGrafPtr currPort;
	GetPort(&currPort);
	SetPortWindowPort((WindowRef)(theApp->GetWindowID()));
	Point mouseLoc;
	GetMouse(&mouseLoc);
	SetPort(currPort);

	if (charCode == kEscapeCharCode)
	{
		// Quit the application when 'esc' is pressed.
		QuitApplicationEventLoop();
		return eventNotHandledErr;
	}

	if (isalnum(charCode) || isprint(charCode))
	{
		theApp->OnKeyDown(charCode, mouseLoc.h, mouseLoc.v);
	}
	else
	{
		if (charCode == kFunctionKeyCharCode)
		{
			// Function key - get key identity.
			UInt32 keyCode;
			GetEventParameter(evt, kEventParamKeyCode, typeUInt32, 0,
			                  sizeof(keyCode), 0, &keyCode);

			charCode = keyCode & 0x000000FF;
		}

		// Do not filter for specific keys.  This allows for keys such as tab,
		// delete, enter.
		theApp->OnSpecialKeyDown(charCode, mouseLoc.h, mouseLoc.v);
	}

	// Allow standard handler to run.
	return eventNotHandledErr;
}
Ejemplo n.º 18
0
//----------------------------------------------------------------------------
void WindowApplication::SetMousePosition (int x, int y)
{
	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	CGrafPtr currPort;
	GetPort(&currPort);
	SetPortWindowPort((WindowRef)(theApp->GetWindowID()));
	Point mouseLoc;
	mouseLoc.h = (short)x;
	mouseLoc.v = (short)y;
	LocalToGlobal(&mouseLoc);
	SetPort(currPort);

	CGPoint point = CGPointMake((float)mouseLoc.h, (float)mouseLoc.v);
	CGPostMouseEvent(point, true, 1, false, 0);
}
Ejemplo n.º 19
0
//----------------------------------------------------------------------------
static pascal OSStatus ProcessWindowZoomed (EventHandlerCallRef,
        EventRef evt, void*)
{
	WindowRef window;
	GetEventParameter(evt, kEventParamDirectObject, typeWindowRef, 0,
	                  sizeof(window), 0, &window);

	Rect rect;
	GetWindowBounds(window, kWindowContentRgn, &rect);

	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	theApp->OnResize(rect.right - rect.left, rect.bottom - rect.top);

	// Allow standard handler to run.
	return eventNotHandledErr;
}
Ejemplo n.º 20
0
void WindowManager::HandleController()
{
    if (_windows.size() > 0)
    {
        WindowApplication* window = _windows.front();

        if ((Interface::IsWithinWindowContent(_controller->CursorX, _controller->CursorY, window) || _isActive) && window->Settings->Enabled == 1)
        {
            if (!window->Settings->Fullscreen)
                window->HandleController(_controller->CursorX - window->ContentX, _controller->CursorY - window->ContentY);
            else
                window->HandleController(_controller->CursorX, _controller->CursorY);
            _controller->Handled = 1;
        }
        else
            _isActive = 0;
    }
}
Ejemplo n.º 21
0
//----------------------------------------------------------------------------
static void MouseClickCallback (int button, int state, int x, int y)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (theApp)
    {
        int modifiers = glutGetModifiers();
        gsGLUTModifiers = *(unsigned int*)&modifiers;
        if (state == WindowApplication::MOUSE_DOWN)
        {
            gsButton = button;
        }
        else
        {
            gsButton = -1;
        }

        theApp->OnMouseClick(button, state, x, y, gsGLUTModifiers);
    }
}
Ejemplo n.º 22
0
//----------------------------------------------------------------------------
static pascal OSStatus ProcessMouseMoved (EventHandlerCallRef, EventRef evt,
        void*)
{
	Point mouseLoc;
	GetEventParameter(evt,kEventParamMouseLocation, typeQDPoint, 0,
	                  sizeof(mouseLoc), 0, &mouseLoc);

	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;

	CGrafPtr currPort;
	GetPort(&currPort);
	SetPortWindowPort((WindowRef)(theApp->GetWindowID()));
	GlobalToLocal(&mouseLoc);
	SetPort(currPort);

	theApp->OnPassiveMotion(mouseLoc.h, mouseLoc.v);

	// Allow standard handler to run.
	return eventNotHandledErr;
}
Ejemplo n.º 23
0
//----------------------------------------------------------------------------
int WindowApplication::Main (int, char**)
{
	// Initialize the extra data.  TODO:  Port the extra-data system of WM4
	// to WM5.
	memset(gsExtraData, 0, APP_EXTRA_DATA_QUANTITY*sizeof(char));

	InitCursor();

	WindowApplication* theApp =
	    (WindowApplication*)Application::TheApplication;
	theApp->KEY_TERMINATE = WindowApplication::KEY_ESCAPE;

	// OpenGL uses a projection matrix for depth in [-1,1].
	Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE);

	// Allocate temporary back buffer to be used for font management.
	GDHandle device = GetGDevice();
	PixMapHandle pixmap = (**device).gdPMap;
	Rect area;
	GetPixBounds(pixmap, &area);
	int depth = GetPixDepth(pixmap);
	GWorldPtr back;
	OSErr error = NewGWorld(&back, depth, &area, 0, 0, useTempMem | pixPurge);
	if (error != noErr || !back)
	{
		return -1;
	}

	SetExtraData(AGLAPP_BACK, sizeof(GWorldPtr), &back);

	// Assign desired font settings to back buffer.
	const int fontSize = 9;
	unsigned char fontName[256];
	fontName[0] = 6;
	strcpy((char*)&fontName[1], "Monaco");
	short fontNum;
	GetFNum(fontName, &fontNum);
	SetExtraData(AGLAPP_FONT, sizeof(short), &fontNum);

	GWorldPtr currentWorld;
	GDHandle currentDevice;
	GetGWorld(&currentWorld, &currentDevice);
	SetGWorld(back, 0);

	TextFont(fontNum);
	TextSize(fontSize);
	TextFace(normal);
	SetGWorld(currentWorld, currentDevice);

	// Add standard window menu.
	MenuRef menu = 0;
	CreateStandardWindowMenu(0, &menu);
	InsertMenu(menu, 0);

	// Change current directory into application bundle.
	FSRef processRef;
	FSCatalogInfo processInfo;
	ProcessSerialNumber serial = { 0, kCurrentProcess };
	GetProcessBundleLocation(&serial, &processRef);
	FSSpec fileSpec;
	FSGetCatalogInfo(&processRef, kFSCatInfoNodeFlags, &processInfo, 0,
	                 &fileSpec, 0);
	std::string appFile = GetStringPathname(fileSpec);
	const int maxPathLen = 1024;
	char path[maxPathLen];
	strcpy(path, appFile.c_str());
	char* last = strrchr(path, '/');
	*last = 0;
	int result = chdir(path);
	assertion(result == 0, "Cannot change directory.\n");

	// If the application is packaged, we have to get back up a couple of
	// levels such that the current working directory is the same as the
	// application's directory.
	char buffer[maxPathLen];
	char* currentDirectory = getcwd(buffer, maxPathLen);
	if (strstr(currentDirectory, "/Contents/MacOS"))
	{
		result = chdir("../../..");
		assertion(result == 0, "Cannot change directory.\n");
		currentDirectory = getcwd(buffer, maxPathLen);
	}

#if 0
	// TODO.  We had this in Wild Magic 4.  Add it to Wild Magic 5.
	//
	// Launch a file dialog, if requested, when the application needs to
	// select an input file.  The derived-class application should set
	// mLaunchFileDialog to 'true' in its constructor when the dialog is
	// needed.
	if (theApp->LaunchFileDialog())
	{
		char* arguments = GetCommandLine();
		if (arguments)
		{
			delete0(theApp->TheCommand);
			theApp->TheCommand = new0 Command(arguments);
			delete1(arguments);
		}
	}
#endif

	if (!theApp->OnPrecreate())
	{
		return -2;
	}

	// Require the window to have the specified client area.
	short windowTop = 60, windowLeft = 40;
	Rect rect = { windowTop, windowLeft, theApp->GetHeight() + windowTop - 1,
	              theApp->GetWidth() + windowLeft - 1
	            };

	// Create the application window.
	WindowRef window = 0;
	OSStatus status = CreateNewWindow(kDocumentWindowClass,
	                                  kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute,
	                                  &rect, &window);
	if (status != noErr)
	{
		assertion(false, "Error in creating window.\n");
		return -3;
	}

	// Grab GD from kRect - based on FindGDHandleFromRect in Carbon SetupGL.
	GDHandle hGD = 0;
	GDHandle hgdNthDevice = GetDeviceList();
	unsigned int greatestArea = 0;

	// Check window against all gdRects in gDevice list and remember which
	// gdRect contains largest area of window.
	while (hgdNthDevice)
	{
		if (TestDeviceAttribute(hgdNthDevice, screenDevice)
		        &&  TestDeviceAttribute(hgdNthDevice, screenActive))
		{
			// The SectRect routine calculates the intersection of the window
			// rectangle and this gDevice rectangle and returns TRUE if the
			// rectangles intersect, FALSE if they don't.
			Rect rectSect;
			SectRect(&rect, &(**hgdNthDevice).gdRect, &rectSect);

			// Determine which screen holds greatest window area first.
			// Calculate area of rectangle on current device.
			unsigned int sectArea =
			    (unsigned int)(rectSect.right - rectSect.left) *
			    (rectSect.bottom - rectSect.top);
			if (sectArea > greatestArea)
			{
				greatestArea = sectArea; // set greatest area so far
				hGD = hgdNthDevice; // set zoom device
			}
			hgdNthDevice = GetNextDevice(hgdNthDevice);
		}
	}

	// Set window title.
	CFStringRef windowTitle = CFStringCreateWithCString(0,
	                          theApp->GetWindowTitle(), kCFStringEncodingASCII);
	SetWindowTitleWithCFString(window, windowTitle);
	CFRelease(windowTitle);

	theApp->SetWindowID((int)window);
	SetPortWindowPort(window);

	// Create the renderer.
	RendererInput input;
	input.mDevice = (AGLDevice)hGD;
	input.mWindow = window;
	mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(),
	                          mColorFormat, mDepthStencilFormat, mNumMultisamples);

	// Install quit apple event handler.
	error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
	                              NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0,
	                              false);
	if (error != noErr)
	{
		ExitToShell();
	}

	// Install window close handler.
	EventTypeSpec eventType;
	eventType.eventClass = kEventClassWindow;
	eventType.eventKind = kEventWindowClose;
	EventHandlerUPP handlerUPP = NewEventHandlerUPP(ProcessWindowClose);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Install window bounds change handler.
	eventType.eventKind = kEventWindowBoundsChanged;
	handlerUPP = NewEventHandlerUPP(ProcessWindowBoundsChange);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Install window zoomed handler.
	eventType.eventKind = kEventWindowZoomed;
	handlerUPP = NewEventHandlerUPP(ProcessWindowZoomed);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Install window redraw handler.
	eventType.eventKind = kEventWindowDrawContent;
	handlerUPP = NewEventHandlerUPP(ProcessWindowRedraw);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Install key down handler.
	EventTypeSpec eventTypes[2];
	eventTypes[0].eventClass = kEventClassKeyboard;
	eventTypes[0].eventKind = kEventRawKeyDown;
	eventTypes[1].eventClass = kEventClassKeyboard;
	eventTypes[1].eventKind = kEventRawKeyRepeat;
	handlerUPP = NewEventHandlerUPP(ProcessKeyDown);
	InstallWindowEventHandler(window, handlerUPP, 2, eventTypes, 0, 0);

	// Install key up handler.
	eventTypes[0].eventClass = kEventClassKeyboard;
	eventTypes[0].eventKind = kEventRawKeyUp;
	handlerUPP = NewEventHandlerUPP(ProcessKeyUp);
	InstallWindowEventHandler(window, handlerUPP, 1, eventTypes, 0, 0);

	// Install key-modifier-changed handler.
	eventTypes[0].eventClass = kEventClassKeyboard;
	eventTypes[0].eventKind = kEventRawKeyModifiersChanged;
	handlerUPP = NewEventHandlerUPP(ProcessKeyModifierChanged);
	InstallWindowEventHandler(window, handlerUPP, 1, eventTypes, 0, 0);

	// Install mouse down handler.
	eventType.eventClass = kEventClassMouse;
	eventType.eventKind = kEventMouseDown;
	handlerUPP = NewEventHandlerUPP(ProcessMouseDown);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Install mouse up handler.
	eventType.eventKind = kEventMouseUp;
	handlerUPP = NewEventHandlerUPP(ProcessMouseUp);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Install mouse drag handler.
	eventType.eventKind = kEventMouseDragged;
	handlerUPP = NewEventHandlerUPP(ProcessMouseDragged);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Install mouse move handler.
	eventType.eventKind = kEventMouseMoved;
	handlerUPP = NewEventHandlerUPP(ProcessMouseMoved);
	InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0);

	// Create timer.
	EventLoopTimerRef timer;
	InstallEventLoopTimer(GetMainEventLoop(), 0, kEventDurationMillisecond,
	                      NewEventLoopTimerUPP(ProcessTimer), 0, &timer);

	if (!theApp->OnInitialize())
	{
		return -4;
	}

	// Set auto-repeat key timing.
	short keyRepeatThresh = LMGetKeyRepThresh();
	short keyThresh = LMGetKeyThresh();
	LMSetKeyRepThresh(1);
	LMSetKeyThresh(30);

	// The default OnPreidle() clears the buffers.  Allow the application to
	// fill them before the window is shown and before the event loop starts.
	theApp->OnPreidle();

	// Display the window.
	ShowWindow(window);

	// Run event loop.
	RunApplicationEventLoop();

	// Reset auto-repeat key timing to initial value.
	LMSetKeyRepThresh(keyRepeatThresh);
	LMSetKeyThresh(keyThresh);

	theApp->OnTerminate();
	delete0(mRenderer);

	RemoveEventLoopTimer(timer);
	DisposeMenu(menu);
	return 0;
}
Ejemplo n.º 24
0
//----------------------------------------------------------------------------
int WindowApplication::Main (int, char**)
{
    WindowApplication* theApp = (WindowApplication*)TheApplication;
    theApp->KEY_TERMINATE = WindowApplication::KEY_ESCAPE;

    // OpenGL uses a projection matrix for depth in [-1,1].
    Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE);

    // Register the termination function so that we can destroy the window
    // after GLUT abnormally calls 'exit'.
    if (atexit(Terminate) != 0)
    {
        return -1;
    }

    // Give GLUT dummy arguments, because we are not allowing control to
    // GLUT via command-line parameters.
    int numArguments = 1;
    char* arguments[1];
    arguments[0] = new char[6];
    strcpy(arguments[0], "dummy");
    glutInit(&numArguments, arguments);
    delete[] arguments[0];

    // We will always use double buffering, 32-bit RGBA front buffer,
    // depth buffer, and stencil buffer.
    if (mNumMultisamples == 0)
    {
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    }
    else
    {
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL
            | GLUT_MULTISAMPLE);
        mNumMultisamples = glutGet(GLUT_WINDOW_NUM_SAMPLES);
    }

    // Allow work to be done before the window is created.
    if (!theApp->OnPrecreate())
    {
        return -2;
    }

    // Create window and renderer.  Multisampling is not supported.
    glutInitWindowSize(theApp->GetWidth(), theApp->GetHeight());
    RendererInput input;
    input.mWindowID = glutCreateWindow(theApp->GetWindowTitle());
    input.mDisableVerticalSync = true;
    mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(),
        mColorFormat, mDepthStencilFormat, mNumMultisamples);

    // Save the handle as an 'int' for portable handle storage.
    theApp->SetWindowID(input.mWindowID);

    // Set the callbacks for event handling.
    glutReshapeFunc(ReshapeCallback);
    glutDisplayFunc(DisplayCallback);
    glutIdleFunc(IdleCallback);
    glutKeyboardFunc(KeyDownCallback);
    glutKeyboardUpFunc(KeyUpCallback);
    glutSpecialFunc(SpecialKeyDownCallback);
    glutSpecialUpFunc(SpecialKeyUpCallback);
    glutMouseFunc(MouseClickCallback);
    glutMotionFunc(MotionCallback);
    glutPassiveMotionFunc(PassiveMotionCallback);

    if (theApp->OnInitialize())
    {
        // The default OnPreidle() clears the buffers.  Allow the application
        // to fill them before the window is shown and before the event loop
        // starts.
        theApp->OnPreidle();

        glutMainLoop();
    }

    // Because glutMainLoop never exits, the clean-up is handled via the
    // static Terminate in this file (registered with 'atexit').
    return 0;
}
Ejemplo n.º 25
0
//----------------------------------------------------------------------------
LRESULT CALLBACK MsWindowEventHandler (HWND handle, UINT message,
    WPARAM wParam, LPARAM lParam)
{
    WindowApplication* theApp =
        (WindowApplication*)Application::TheApplication;

    if (!theApp || !theApp->GetWindowID())
    {
        return DefWindowProc(handle, message, wParam, lParam);
    }

    switch (message) 
    {
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            BeginPaint(handle, &ps);
            theApp->OnDisplay();
            EndPaint(handle, &ps);
            return 0;
        }
        case WM_ERASEBKGND:
        {
            // This tells Windows not to erase the background (and that the
            // application is doing so).
            return 1;
        }
        case WM_MOVE:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            theApp->OnMove(xPos, yPos);
            return 0;
        }
        case WM_SIZE:
        {
            int width = (int)(LOWORD(lParam));
            int height = (int)(HIWORD(lParam));
            theApp->OnResize(width, height);
            return 0;
        }
        case WM_CHAR:
        {
            unsigned char key = (unsigned char)(char)wParam;

            // Quit the application if the KEY_TERMINATE key is pressed.
            if (key == theApp->KEY_TERMINATE)
            {
                PostQuitMessage(0);
                return 0;
            }

            // Get the cursor position in client coordinates.
            POINT point;
            GetCursorPos(&point);
            ScreenToClient(handle, &point);
            int xPos = (int)point.x;
            int yPos = (int)point.y;

            theApp->OnKeyDown(key, xPos, yPos);
            return 0;
        }
        case WM_KEYDOWN:
        {
            int virtKey = (int)wParam;

            // Get cursor position client coordinates.
            POINT point;
            GetCursorPos(&point);
            ScreenToClient(handle, &point);
            int xPos = (int)point.x;
            int yPos = (int)point.y;

            if ((VK_F1 <= virtKey && virtKey <= VK_F12)
            ||  (VK_PRIOR <= virtKey && virtKey <= VK_DOWN)
            ||  (virtKey == VK_INSERT) || (virtKey == VK_DELETE)
            ||  (virtKey == VK_SHIFT) || (virtKey == VK_CONTROL))
            {
                theApp->OnSpecialKeyDown(virtKey, xPos, yPos);
            }
            return 0;
        }
        case WM_KEYUP:
        {
            int virtKey = (int)wParam;

            // get the cursor position in client coordinates
            POINT point;
            GetCursorPos(&point);
            ScreenToClient(handle, &point);
            int xPos = (int)point.x;
            int yPos = (int)point.y;

            if ((VK_F1 <= virtKey && virtKey <= VK_F12)
            ||  (VK_PRIOR <= virtKey && virtKey <= VK_DOWN)
            ||  (virtKey == VK_INSERT) || (virtKey == VK_DELETE)
            ||  (virtKey == VK_SHIFT) || (virtKey == VK_CONTROL))
            {
                theApp->OnSpecialKeyUp(virtKey, xPos, yPos);
            }
            else
            {
                theApp->OnKeyUp((unsigned char)virtKey, xPos, yPos);
            }
            return 0;
        }
        case WM_LBUTTONDOWN:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            theApp->OnMouseClick(WindowApplication::MOUSE_LEFT_BUTTON,
                WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam));
            return 0;
        }
        case WM_LBUTTONUP:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            theApp->OnMouseClick(WindowApplication::MOUSE_LEFT_BUTTON,
                WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam));
            return 0;
        }
        case WM_MBUTTONDOWN:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            theApp->OnMouseClick(WindowApplication::MOUSE_MIDDLE_BUTTON,
                WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam));
            return 0;
        }
        case WM_MBUTTONUP:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            theApp->OnMouseClick(WindowApplication::MOUSE_MIDDLE_BUTTON,
                WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam));
            return 0;
        }
        case WM_RBUTTONDOWN:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            theApp->OnMouseClick(WindowApplication::MOUSE_RIGHT_BUTTON,
                WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam));
            return 0;
        }
        case WM_RBUTTONUP:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            theApp->OnMouseClick(WindowApplication::MOUSE_RIGHT_BUTTON,
                WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam));
            return 0;
        }
        case WM_MOUSEMOVE:
        {
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));

            int button = -1;
            if (wParam & MK_LBUTTON)
            {
                button = WindowApplication::MOUSE_LEFT_BUTTON;
            }
            else if (wParam & MK_MBUTTON)
            {
                button = WindowApplication::MOUSE_MIDDLE_BUTTON;
            }
            else if (wParam & MK_RBUTTON)
            {
                button = WindowApplication::MOUSE_RIGHT_BUTTON;
            }

            if (button >= 0)
            {
                theApp->OnMotion(button, xPos, yPos, PtrToUint(wParam));
            }
            else
            {
                theApp->OnPassiveMotion(xPos, yPos);
            }

            return 0;
        }
        case WM_MOUSEWHEEL:
        {
            short sWParam = (short)(HIWORD(wParam));
            int delta = ((int)sWParam)/WHEEL_DELTA;
            int xPos = (int)(LOWORD(lParam));
            int yPos = (int)(HIWORD(lParam));
            unsigned int modifiers = (unsigned int)(LOWORD(wParam));
            theApp->OnMouseWheel(delta, xPos, yPos, modifiers);
            return 0;
        }
        case WM_DESTROY:
        {
            // The DestroyWindow call when recreating the window for
            // multisampling causes the application to terminate.  It is
            // not clear why the same problem did not occur in WM4.
            if (!gsIgnoreWindowDestroy)
            {
                PostQuitMessage(0);
            }
            gsIgnoreWindowDestroy = false;
            return 0;
        }
    }

    return DefWindowProc(handle, message, wParam, lParam);
}
Ejemplo n.º 26
0
//----------------------------------------------------------------------------
int WindowApplication::Main (int, char**)
{
    WindowApplication* theApp = (WindowApplication*)TheApplication;
    theApp->KEY_TERMINATE = WindowApplication::KEY_ESCAPE;

#ifdef WM5_USE_DX9
    // DirectX uses a projection matrix for depth in [0,1].
    Camera::SetDefaultDepthType(Camera::PM_DEPTH_ZERO_TO_ONE);
#endif

#ifdef WM5_USE_OPENGL
    // OpenGL uses a projection matrix for depth in [-1,1].
    Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE);
#endif

    // Allow work to be done before the window is created.
    if (!theApp->OnPrecreate())
    {
        return -1;
    }

    // === Create the window for rendering. ===

    // Register the window class.
    static char sWindowClass[] = "Wild Magic 5 Application";
    WNDCLASS wc;
    wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc   = MsWindowEventHandler;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = 0;
    wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszClassName = sWindowClass;
    wc.lpszMenuName  = 0;
    RegisterClass(&wc);

    DWORD dwStyle;
    if (mAllowResize)
    {
        dwStyle = WS_OVERLAPPEDWINDOW;
    }
    else
    {
        // This removes WS_THICKFRAME and WS_MAXIMIZEBOX, both of which allow
        // resizing of windows.
        dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
    }

    // Require the window to have the specified client area.
    RECT rect = { 0, 0, theApp->GetWidth()-1, theApp->GetHeight()-1 };
    AdjustWindowRect(&rect, dwStyle, FALSE);

    // Create the application window.
    HWND handle = CreateWindow(sWindowClass, theApp->GetWindowTitle(),
        dwStyle, theApp->GetXPosition(), theApp->GetYPosition(),
        rect.right - rect.left + 1, rect.bottom - rect.top + 1, 0, 0, 0, 0);

    // Save the handle as an 'int' for portable handle storage.
    theApp->SetWindowID(PtrToInt(handle));

    // ===

#ifdef WM5_USE_DX9
    // Create the device for rendering.
    RendererInput input;
    input.mWindowHandle = handle;
    input.mDriver = Direct3DCreate9(D3D_SDK_VERSION);
    assertion(input.mDriver != 0, "Failed to create Direct3D9\n");
    mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(),
        mColorFormat, mDepthStencilFormat, mNumMultisamples);
#endif

#ifdef WM5_USE_OPENGL
    // The pixelFormat variable is used to support creation of a window that
    // supports multisampling.  This process requires creating a normal window,
    // and then querying whether the renderer supports multisampling.  The
    // renderer creates a device context for the window which we then need to
    // create a second window that supports multisampling.  The device context
    // rendererDC is set by the renderer during the process.
    RendererInput input;
    input.mWindowHandle = handle;
    input.mPixelFormat = 0;
    input.mRendererDC = 0;
    input.mDisableVerticalSync = true;
    mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(),
        mColorFormat, mDepthStencilFormat, mNumMultisamples);

    // To determine whether multisampling is supported, it is necessary to
    // create a window, an OpenGL context, and query the driver for the
    // multisampling extensions.  If it is, a new window must be created
    // because the renderer creation involves SetPixelFormat(...) that can
    // be called only once for a window.
    int numMultisamples = mRenderer->GetNumMultisamples();
    if (numMultisamples > 0)
    {
        int attributes[256], pos = 0;
        attributes[pos++] = WGL_SUPPORT_OPENGL_ARB;
        attributes[pos++] = 1;
        attributes[pos++] = WGL_DRAW_TO_WINDOW_ARB;
        attributes[pos++] = 1;
        attributes[pos++] = WGL_ACCELERATION_ARB;
        attributes[pos++] = WGL_FULL_ACCELERATION_ARB;
        attributes[pos++] = WGL_PIXEL_TYPE_ARB;
        attributes[pos++] = WGL_TYPE_RGBA_ARB;
        attributes[pos++] = WGL_RED_BITS_ARB;
        attributes[pos++] = 8;
        attributes[pos++] = WGL_GREEN_BITS_ARB;
        attributes[pos++] = 8;
        attributes[pos++] = WGL_BLUE_BITS_ARB;
        attributes[pos++] = 8;
        attributes[pos++] = WGL_ALPHA_BITS_ARB;
        attributes[pos++] = 8;
        attributes[pos++] = WGL_DEPTH_BITS_ARB;
        attributes[pos++] = 24;
        attributes[pos++] = WGL_STENCIL_BITS_ARB;
        attributes[pos++] = 8;
        attributes[pos++] = WGL_DOUBLE_BUFFER_ARB;
        attributes[pos++] = 1;
        attributes[pos++] = WGL_SAMPLE_BUFFERS_ARB;
        attributes[pos++] = 1;
        attributes[pos++] = WGL_SAMPLES_ARB;
        attributes[pos++] = numMultisamples;
        attributes[pos++] = 0; // list is zero-terminated

        unsigned int numFormats = 0;
        BOOL successful = wglChoosePixelFormatARB(input.mRendererDC,
            attributes, 0, 1, &input.mPixelFormat, &numFormats);
        if (successful && numFormats > 0)
        {
            // The card supports multisampling with the requested number of
            // samples.  Recreate the window and renderer.
            delete0(mRenderer);

            gsIgnoreWindowDestroy = true;
            DestroyWindow(handle);

            handle = CreateWindow(sWindowClass, theApp->GetWindowTitle(),
                WS_OVERLAPPEDWINDOW, theApp->GetXPosition(),
                theApp->GetYPosition(), rect.right - rect.left + 1,
                rect.bottom - rect.top + 1, 0, 0, 0, 0);

            theApp->SetWindowID(PtrToInt(handle));

            input.mWindowHandle = handle;
            mRenderer = new0 Renderer(input, theApp->GetWidth(),
                theApp->GetHeight(), mColorFormat, mDepthStencilFormat,
                mNumMultisamples);
        }
    }
#endif

    if (theApp->OnInitialize())
    {
        // The default OnPreidle() clears the buffers.  Allow the application
        // to fill them before the window is shown and before the event loop
        // starts.
        theApp->OnPreidle();

        // Display the window.
        ShowWindow(handle, SW_SHOW);
        UpdateWindow(handle);

        // Start the message pump.
        bool applicationRunning = true;
        while (applicationRunning)
        {
            MSG msg;
            if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
            {
                if (msg.message == WM_QUIT)
                {
                    applicationRunning = false;
                    continue;
                }

                HACCEL accel = 0;
                if (!TranslateAccelerator(handle, accel, &msg))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            else
            {
                theApp->OnIdle();
            }
        }
    }
    theApp->OnTerminate();
    delete0(mRenderer);

#ifdef WM5_USE_DX9
    input.mDriver->Release();
#endif

    return 0;
}
Ejemplo n.º 27
0
//----------------------------------------------------------------------------
int WindowApplication::Main (int numArguments, char** arguments)
{
    // Initialize the extra data.  TODO:  Port the extra-data system of WM4
    // to WM5.
    memset(gsExtraData, 0, APP_EXTRA_DATA_QUANTITY*sizeof(char));

    WindowApplication* theApp = (WindowApplication*)TheApplication;
    theApp->KEY_TERMINATE = KEY_ESCAPE;

    // OpenGL uses a projection matrix for depth in [-1,1].
    Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE);

    // Allow work to be done before the window is created.
    if (!theApp->OnPrecreate())
    {
        return -1;
    }

    // Connect to the X server.
    const char* displayName = 0;
    Display* display = XOpenDisplay(displayName);
    if (!display)
    {
        return -2;
    }

    // Make sure the X server has OpenGL GLX extensions.
    int errorBase, eventBase;
    Bool success = glXQueryExtension(display, &errorBase, &eventBase);
    assertion(success == True, "GLX extensions not found.\n");
    if (!success)
    {
        return -3;
    }

    // Partial construction of a GLX renderer.  The window for the renderer
    // is not yet constructed.  When it is, the window identifier is supplied
    // to the renderer to complete its construction.
    RendererInput input;
    input.mDisplay = display;
    input.mVisual = 0;
    input.mContext = 0;
    mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(),
        mColorFormat, mDepthStencilFormat, mNumMultisamples);
    if (!input.mVisual || !input.mContext)
    {
        return -4;
    }

    // Create an X Window with the visual information created by the renderer
    // constructor.  The visual information might not be the default, so
    // create an X colormap to use.
    Window rootWindow = RootWindow(display, input.mVisual->screen);
    Colormap cMap = XCreateColormap(display, rootWindow,
        input.mVisual->visual, AllocNone);

    // Set the event mask to include exposure (paint), button presses (mouse),
    // and key presses (keyboard).
    XSetWindowAttributes windowAttributes;
    windowAttributes.colormap = cMap;
    windowAttributes.border_pixel = 0;
    windowAttributes.event_mask =
        ButtonPressMask |
        ButtonReleaseMask |
        PointerMotionMask |
        Button1MotionMask |
        Button2MotionMask |
        Button3MotionMask |
        KeyPressMask |
        KeyReleaseMask |
        ExposureMask |
        StructureNotifyMask;

    int xPos = theApp->GetXPosition();
    int yPos = theApp->GetYPosition();
    unsigned int width = (unsigned int)theApp->GetWidth();
    unsigned int height = (unsigned int)theApp->GetHeight();
    unsigned int borderWidth = 0;
    unsigned long valueMask = CWBorderPixel | CWColormap | CWEventMask;
    Window window = XCreateWindow(display, rootWindow, xPos, yPos, width,
        height, borderWidth, input.mVisual->depth, InputOutput,
        input.mVisual->visual, valueMask, &windowAttributes);

    XSizeHints hints;
    hints.flags = PPosition | PSize;
    hints.x = xPos;
    hints.y = yPos;
    hints.width = width;
    hints.height = height;
    XSetNormalHints(display, window, &hints);

    const char* iconName = theApp->GetWindowTitle();
    Pixmap iconPixmap = None;
    XSetStandardProperties(display, window, theApp->GetWindowTitle(),
        iconName, iconPixmap, arguments, numArguments, &hints);

    // Intercept the close-window event when the user selects the
    // window close button.  The event is a "client message".
    Atom wmDelete = XInternAtom(display, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(display, window, &wmDelete, 1);

    // Finish the construction of the renderer.
    GlxRendererData* data = (GlxRendererData*)mRenderer->mData;
    if (!data->FinishConstruction(window, mRenderer))
    {
        return -5;
    }

    if (theApp->OnInitialize())
    {
        // The default OnPreidle() clears the buffers. Allow the application
        // to fill them before the window is shown and before the event loop
        // starts.
        theApp->OnPreidle();

        // Display the window.
        XMapWindow(display, window);

        // Start the message pump.
        bool applicationRunning = true;
        while (applicationRunning)
        {
            if (!XPending(display))
            {
                theApp->OnIdle();
                continue;
            }

            XEvent evt;
            XNextEvent(display, &evt);
            int index;
            bool state;

            if (evt.type == ButtonPress || evt.type == ButtonRelease)
            {
                theApp->OnMouseClick(evt.xbutton.button, evt.xbutton.type,
                    evt.xbutton.x, evt.xbutton.y, evt.xbutton.state);

                if (evt.type == ButtonPress)
                {
                    index = GLXAPP_BUTTONDOWN + evt.xbutton.button;
                    state = true;
                    SetExtraData(index, sizeof(bool), &state);
                }
                else
                {
                    index = GLXAPP_BUTTONDOWN + evt.xbutton.button;
                    state = false;
                    SetExtraData(index, sizeof(bool), &state);
                }

                continue;
            }

            if (evt.type == MotionNotify)
            {
                int button = 0;

                index = GLXAPP_BUTTONDOWN + 1;
                GetExtraData(index, sizeof(bool), &state);
                if (state)
                {
                    button = MOUSE_LEFT_BUTTON;
                }
                else
                {
                    index = GLXAPP_BUTTONDOWN + 2;
                    GetExtraData(index, sizeof(bool), &state);
                    if (state)
                    {
                        button = MOUSE_MIDDLE_BUTTON;
                    }
                    else
                    {
                        index = GLXAPP_BUTTONDOWN + 3;
                        GetExtraData(index, sizeof(bool), &state);
                        if (state)
                        {
                            button = MOUSE_RIGHT_BUTTON;
                        }
                    }
                }

                if (button > 0)
                {
                    theApp->OnMotion(button, evt.xmotion.x, evt.xmotion.y,
                        evt.xmotion.state);
                }
                else
                {
                    theApp->OnPassiveMotion(evt.xmotion.x, evt.xmotion.y);
                }
                continue;
            }

            if (evt.type == KeyPress || evt.type == KeyRelease)
            {
                KeySym keySym = XKeycodeToKeysym(display,
                    evt.xkey.keycode, 0);

                int key = (keySym & 0x00FF);

                // Quit application if the KEY_TERMINATE key is pressed.
                if (key == theApp->KEY_TERMINATE)
                {
                    XDestroyWindow(display, window);
                    applicationRunning = false;
                    continue;
                }

                // Adjust for special keys that exist on the key pad and on
                // the number pad.
                if ((keySym & 0xFF00) != 0)
                {
                    if (0x50 <= key && key <= 0x57)
                    {
                        // keypad Home, {L,U,R,D}Arrow, Pg{Up,Dn}, End
                        key += 0x45;
                    }
                    else if (key == 0x63)
                    {
                        // keypad Insert
                        key = 0x9e;
                    }
                    else if (key == 0xFF)
                    {
                        // keypad Delete
                        key = 0x9f;
                    }
                    else if (key == 0xE1 || key == 0xE2)
                    {
                        // L-shift or R-shift
                        key = KEY_SHIFT;
                        state = (evt.type == KeyPress);
                        SetExtraData(GLXAPP_SHIFTDOWN, sizeof(bool), &state);
                    }
                    else if (key == 0xE3 || key == 0xE4)
                    {
                        // L-ctrl or R-ctrl
                        key = KEY_CONTROL;
                    }
                    else if (key == 0xE9 || key == 0xEA)
                    {
                        // L-alt or R-alt
                        key = KEY_ALT;
                    }
                    else if (key == 0xEB || key == 0xEC)
                    {
                        key = KEY_COMMAND;
                    }
                }

                if ((KEY_HOME <= key &&  key <= KEY_END)
                ||  (KEY_F1 <= key   &&  key <= KEY_F12)
                ||  (KEY_SHIFT <= key && key <= KEY_COMMAND))
                {
                    if (evt.type == KeyPress)
                    {
                        theApp->OnSpecialKeyDown(key, evt.xbutton.x,
                            evt.xbutton.y);
                    }
                    else
                    {
                        theApp->OnSpecialKeyUp(key, evt.xbutton.x,
                            evt.xbutton.y);
                    }
                }
                else
                {
                    // Get key-modifier state.  Adjust for shift state.
                    unsigned char ucKey = (unsigned char)key;
                    GetExtraData(GLXAPP_SHIFTDOWN, sizeof(bool), &state);
                    if (state && 'a' <= ucKey && ucKey <= 'z')
                    {
                        ucKey = (unsigned char)(key - 32);
                    }

                    if (evt.type == KeyPress)
                    {
                        theApp->OnKeyDown(ucKey, evt.xbutton.x,
                            evt.xbutton.y);
                    }
                    else
                    {
                        theApp->OnKeyUp(ucKey, evt.xbutton.x,
                            evt.xbutton.y);
                    }
                }
                continue;
            }

            if (evt.type == Expose)
            {
                theApp->OnDisplay();
                continue;
            }

            if (evt.type == ConfigureNotify)
            {
                theApp->OnMove(evt.xconfigure.x, evt.xconfigure.y);
                theApp->OnResize(evt.xconfigure.width,
                    evt.xconfigure.height);
                continue;
            }

            if (evt.type == ClientMessage
            &&  evt.xclient.data.l[0] == wmDelete)
            {
                XDestroyWindow(display, window);
                applicationRunning = false;
                continue;
            }
        }
    }

    theApp->OnTerminate();
    XCloseDisplay(display);
    return 0;
}