/*	XGAppCore_win.cpp
 *
 *		Windows specific implementation of various XGAppCore methods
 */

/**********************************************************************

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

**********************************************************************/

#include <XConfig.h>			// must be first to optimize compile on MSVC++

#if OPT_WINOS

#include <XApplication.h>
#include <XWindow.h>
#include <XMessages.h>
#include <XMenu.h>
#include <XError.h>
#include <XModifiers.h>
#include <XDataUtil.h>
#include <XFile.h>

#include <commctrl.h>
#include <string.h>
#include <ctype.h>

/************************************************************************/
/*																		*/
/*	Globals																*/
/*																		*/
/************************************************************************/

UINT GTimerID;
UINT _GUpActive;

MSG XGAppCore::gLastMessage;

/************************************************************************/
/*																		*/
/*	OS Init/Shutdown													*/
/*																		*/
/************************************************************************/

/*	XGAppCore::InitOS
 *
 *		Initialize the OS. I don't need to do very much here, just kick
 *  off a periodic event. I don't need to process this with any special
 *	code because my code automagically fires the periodic event handling
 *	code anyways.
 */

void XGAppCore::InitOS()
{
	InitCommonControls();
	OleInitialize(NULL);
	GTimerID = ::SetTimer(NULL,0,50,NULL);
}

/*	XGAppCore::KillOS
 *
 *		Kill the OS. I don't need to do much here, either...
 */

void XGAppCore::KillOS()
{
	::KillTimer(NULL,GTimerID);
	OleUninitialize();
}

/*	XGAppCore::GetAppArgs
 *
 *		Called right before the event pump is run, this parses
 *	the arguments on the command line and passes them to my app
 */

void XGAppCore::GetAppArgs()
{
	char *ptr;
	char *arg[32];
	int i;
	int j;
	char buffer[256];
	XGFileSpecifier fspec;
	
	/*
	 *	Convert into argv pairs
	 */
	
	strcpy(buffer,_GArgString);
	ptr = buffer;
	i = 0;
	for (;;) {
		while (isspace(*ptr)) ptr++;
		if (*ptr == '\0') break;
		if (*ptr == '\"') {
			/*
			 *	Escaped with quotes
			 */
			
			ptr++;
			arg[i++] = ptr;
			while ((*ptr != '\"') && (*ptr != '\0')) ptr++;
			if (*ptr == '\0') break;
			*ptr++ = 0;
		} else {
			/*
			 *	Not escaped
			 */
			
			arg[i++] = ptr;
			while (!isspace(*ptr) && (*ptr != '\0')) ptr++;
			if (*ptr == '\0') break;
			*ptr++ = 0;
		}
		if (i >= 32) break;
	}
	
	/*
	 *	Now start passing open document messages
	 */
	
	if (i > 0) {
		for (j = 0; j < i; j++) {
			fspec = arg[j];
			XGDispatch::SendDispatch(KXGDoOpenDocument,0,(void *)&fspec);
		}
	} else {
		XGDispatch::SendDispatch(KXGOpenApplication,0,NULL);
	}
}

/************************************************************************/
/*																		*/
/*	Internal Stuff														*/
/*																		*/
/************************************************************************/

/*	XGAppCore::MarkSingleInstance
 *
 *		Mark this application as single instance. If another instance
 *	of this application is running, this throws an abort, preventing
 *	this application from running
 */
 
void XGAppCore::MarkSingleInstance(char *name)
{
	char buffer[256];
	
	strcpy(buffer,name);
	strcat(buffer,"_MESSAGE");
	_GUpActive = ::RegisterWindowMessage(buffer);
	
	strcpy(buffer,name);
	strcat(buffer,"_MUTEX");
	fMutex = CreateMutex(NULL,FALSE,buffer);
	if ((fMutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS)) {
		/*
		 *	Send up message and quit.
		 */
		
		::PostMessage(HWND_BROADCAST,_GUpActive,0,0);
		throw XGAbort();
	}
}

/*	XGAppCore::DDEAppName
 *
 *		Note the application name for the purposes of handling DDE
 *	shell transactions. This also gives the topic name, usually 'file'
 */
 
void XGAppCore::DDEAppName(char *name, char *topic)
{
	extern char _GDDEAppName[];
	extern char _GDDETopicName[];
	
	strcpy(_GDDEAppName,name);
	if (topic) strcpy(_GDDETopicName,topic);
	else strcpy(_GDDETopicName,"files");
}

/************************************************************************/
/*																		*/
/*	Event Processing													*/
/*																		*/
/************************************************************************/

/*	XGAppCore::DoEvent
 *
 *		Do one pass through my event loop.
 */

void XGAppCore::DoEvent()
{
	POINT where;
	
	// Determine where the mouse is in order to handle 'leave events',
	// including when the cursor has totally left my application
	if (XGWindow::gLastHWND) {
		HWND w;
		
		GetCursorPos(&where);
		w = WindowFromPoint(where);
		if (XGWindow::gLastHWND != w) {
			XGPopWindow *pop;
			
			pop = XGPopWindow::GetPopWindow(w);
			if ((pop == NULL) || (XGWindow::gLastView != pop->GetBase())) {
				/*
				 *	Cursor is definitely no longer in this view.
				 */
				
				XGWindow::ProcessMouseLeave();
			}
		}
	}
	
	// Get the message
	if (!GetMessage(&gLastMessage,NULL,0,0)) {
		fQuitFlag = true;
		return;
	}
	
	// Process and dispatch
	if (!_GMDIWindow || !TranslateMDISysAccel(_GMDIWindow,&gLastMessage)) {
		if (!GetCurMenu()->TranslateAccelerator(_GMainWindow,&gLastMessage)) {
			XGWindow *w;
			
			w = XGWindow::GetXGWindow(gLastMessage.hwnd);
			if (w) fEventOwner = w;
			
			// Dispatch to allow me to intercept it
			if (FilterEvent((void *)&gLastMessage)) {
				/* Event was processed. Bail. */
				return;
			}
			if (1 == XGDispatch::SendDispatch(KXGAppEvent,0,(void *)&gLastMessage)) {
				return;
			}
			
			// Trap WM_CHAR, WM_KEYDOWN messages. This allows me
			// to process these messages and skim out the 'tab'
			// keys and the like.
			
			if (-1 != ProcKeyboardCommon(gLastMessage.message,gLastMessage.wParam,gLastMessage.lParam)) {
				return;
			}
			
			// Note: TranslateMessage is called after ProcKeyboardCommon
			// in order to prevent me from resending WM_CHAR commands
			// for keyboard events that I already handled.
	
			TranslateMessage(&gLastMessage);
			DispatchMessage(&gLastMessage);
			
			fEventOwner = NULL;
		}
	}
}

/*	XGAppCore::CancelCheck
 *
 *		This checks for a cancel key on Windows; this checks to make
 *	sure the 'escape' key is not pressed to stop this operation.
 */

bool XGAppCore::CancelCheck(void)
{
	short keystate = GetAsyncKeyState(VK_ESCAPE);
	if (keystate & 0x8000) return true;
	return false;
}

#endif // OPT_WINOS

