/* --- Copyright University of Sussex 1996. All rights reserved. ----------
 * File:			C.win32/extern/src/windows.c
 * Purpose:			Bits and pieces for running Ved in a window
 * Author:			Robert John Duncan, Jul 14 1994 (see revisions)
 */

#include "popcore.h"
#include "popwin.h"

BOOL popwin_get_message(POP_MSG *pmsg)
	/*	Retrieves a message posted to this thread by a window procedure.
		Returns TRUE for successful return or FALSE if interrupted by a
		Poplog AST or by some (unspecified) error.
	*/
{
	for (;;) {
		MSG msg;

		if (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE)) {
			/* thread message -- return to Poplog */
			pmsg->hwnd = msg.hwnd;
			pmsg->message = msg.message;
			pmsg->wParam = msg.wParam;
			pmsg->lParam = msg.lParam;
			return TRUE;
		}
		else if (MsgWaitForMultipleObjects(
					1, &pop_ast_queue_non_empty,	/* pop AST event */
					FALSE, INFINITE, QS_ALLINPUT)	/* or any message */
				 != WAIT_OBJECT_0+1) {
			/* interrupt or error */
			return FALSE;
		}
	}
}

LRESULT popwin_send_message(POP_MSG *pmsg)
	/*	Send a message to a window
	*/
{
	return SendMessage(pmsg->hwnd, pmsg->message, pmsg->wParam, pmsg->lParam);
}

HWND popwin_get_window(HWND hwnd, UINT cmd)
	/*	Get a window with the specified relationship to another
	*/
{
	return GetWindow(hwnd, cmd);
}


/***************************************************************************
*                                                                          *
*	Start a base window for Ved                                            *
*                                                                          *
***************************************************************************/

static HANDLE window_created;
	/*	Auto-reset event indicating completion of window creation
	*/

static HWND last_window;
	/*	Handle of last window created
	*/

static DWORD base_window_manager(DWORD pop_thread_id)
	/*	Creates and manages the base window. Runs in a separate thread so
		that events can be processed even while Poplog is busy. Events of
		significance to Poplog are posted to the Poplog thread.
	*/
{
	HWND hwnd;
	MSG msg;

	/* create a base window */
	hwnd = CreateWindow(
			POP_BASE_CLASS_NAME,		/* name */
			TEXT("Poplog"),				/* window title */
			WS_OVERLAPPEDWINDOW			/* window style */
				|WS_CLIPCHILDREN,
			CW_USEDEFAULT,				/* X coord -- default */
			CW_USEDEFAULT,				/* Y coord -- default */
			CW_USEDEFAULT,				/* width -- default */
			CW_USEDEFAULT,				/* height -- default */
			NULL,						/* parent window */
			NULL,						/* menu */
			GetModuleHandle(NULL),		/* application instance */
			&pop_thread_id				/* creation data */
		);

	/* say it's done */
	last_window = hwnd;
	SetEvent(window_created);
	if (hwnd == NULL)
		return (DWORD)-1;

	/* display the window */
	ShowWindow(hwnd, SW_SHOWDEFAULT);
	UpdateWindow(hwnd);

	/* message loop */
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

HWND popwin_create_base_window(void)
	/*	Starts a new thread to create and manage a base window. Returns
		once window creation has been completed.
	*/
{
	HANDLE thread;
	DWORD thread_id;
	static int init_state = 0;

	if (init_state == 0) {
		/* initialise the window_created event */
		window_created = CreateEvent(NULL, FALSE, FALSE, NULL);
		if (window_created == NULL)
			return NULL;
		init_state++;
	}

	if (init_state == 1) {
		/* initialise the base window class */
		if (popwin_init_base_window_class() == 0)
			return NULL;
		init_state++;
	}

	if (init_state == 2) {
		/* initialise the edit window class */
		if (popwin_init_edit_window_class() == 0)
			return NULL;
		init_state++;
	}

	/* spawn a thread to create and manage the new window */
	last_window = NULL;
	thread = CreateThread(
			NULL,						/* thread security */
			4096,						/* stack size */
			(LPTHREAD_START_ROUTINE)base_window_manager,
										/* start address */
			(LPVOID)GetCurrentThreadId(),
										/* argument */
			0,							/* create flags */
			&thread_id					/* thread ID */
		);
	if (thread == NULL)
		return NULL;
	CloseHandle(thread);

	/* wait for it to create the window (or not!) */
	WaitForSingleObject(window_created, INFINITE);

	return last_window;
}

/*******************************************************************************
New Interface as of 30/01/96
*******************************************************************************/

static BOOL in_message_wait = FALSE;

__inline
BOOL DoMessageWait()
{
	// Wait for a message or Pop AST; return TRUE for message, FALSE otherwise
	DWORD result;
	in_message_wait = TRUE;
	result = MsgWaitForMultipleObjects(1, &pop_ast_queue_non_empty,
				FALSE, INFINITE, QS_ALLINPUT);
	in_message_wait = FALSE;
	return result == WAIT_OBJECT_0+1;
}

BOOL popwin_try_message(BOOL wait)
{
	if (!wait || (GetQueueStatus(QS_ALLINPUT) != 0) || DoMessageWait()) {
		MSG msg;
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
			if (msg.message == WM_QUIT)
				return FALSE;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return TRUE;
}

BOOL pop_in_message_wait()
{
	return in_message_wait;
}

/* --- Revision History ---------------------------------------------------
--- Robert John Duncan, Feb  7 1996
		Added support for new (experimental MDI) interface.
 */
