bool
CCondVarBase::wait(CStopwatch& timer, double timeout) const
{
	// check timeout against timer
	if (timeout >= 0.0) {
		timeout -= timer.getTime();
		if (timeout < 0.0)
			return false;
	}
	return wait(timeout);
}
void
CFileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarget)
{
	std::fstream file(reinterpret_cast<char*>(filename), std::ios::in | std::ios::binary);

	if (!file.is_open()) {
		throw runtime_error("failed to open file");
	}

	// check file size
	file.seekg (0, std::ios::end);
	size_t size = (size_t)file.tellg();

	// send first message (file size)
	CString fileSize = intToString(size);
	size_t sizeLength = fileSize.size();
	CFileChunk* sizeMessage = new CFileChunk(sizeLength + 2);
	char* chunkData = sizeMessage->m_chunk;

	chunkData[0] = kFileStart;
	memcpy(&chunkData[1], fileSize.c_str(), sizeLength);
	chunkData[sizeLength + 1] = '\0';
	events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, sizeMessage));

	// send chunk messages with a fixed chunk size
	size_t sentLength = 0;
	size_t chunkSize = m_chunkSize;
	CStopwatch stopwatch;
	stopwatch.start();
	file.seekg (0, std::ios::beg);
	while (true) {
		if (stopwatch.getTime() > PAUSE_TIME_HACK) {
			// make sure we don't read too much from the mock data.
			if (sentLength + chunkSize > size) {
				chunkSize = size - sentLength;
			}

			// for fileChunk->m_chunk, the first byte is the chunk mark, last is \0
			CFileChunk* fileChunk = new CFileChunk(chunkSize + 2);
			char* chunkData = fileChunk->m_chunk;

			chunkData[0] = kFileChunk;
			file.read(&chunkData[1], chunkSize);
			chunkData[chunkSize + 1] = '\0';
			events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, fileChunk));

			sentLength += chunkSize;
			file.seekg (sentLength, std::ios::beg);

			if (sentLength == size) {
				break;
			}

			stopwatch.reset();
		}
	}

	// send last message
	CFileChunk* transferFinished = new CFileChunk(2);
	chunkData = transferFinished->m_chunk;

	chunkData[0] = kFileEnd;
	chunkData[1] = '\0';
	events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, transferFinished));

	file.close();
}
bool
CXWindowsPrimaryScreen::showWindow()
{
	assert(m_window != None);

	CDisplayLock display(m_screen);

	// raise and show the input window
	XMapRaised(display, m_window);

	// grab the mouse and keyboard.  keep trying until we get them.
	// if we can't grab one after grabbing the other then ungrab
	// and wait before retrying.  give up after s_timeout seconds.
	static const double s_timeout = 1.0;
	int result;
	CStopwatch timer;
	do {
		// keyboard first
		do {
			result = XGrabKeyboard(display, m_window, True,
								GrabModeAsync, GrabModeAsync, CurrentTime);
			assert(result != GrabNotViewable);
			if (result != GrabSuccess) {
				LOG((CLOG_DEBUG2 "waiting to grab keyboard"));
				ARCH->sleep(0.05);
				if (timer.getTime() >= s_timeout) {
					LOG((CLOG_DEBUG2 "grab keyboard timed out"));
					XUnmapWindow(display, m_window);
					return false;
				}
			}
		} while (result != GrabSuccess);
		LOG((CLOG_DEBUG2 "grabbed keyboard"));

		// now the mouse
		result = XGrabPointer(display, m_window, True, 0,
								GrabModeAsync, GrabModeAsync,
								m_window, None, CurrentTime);
		assert(result != GrabNotViewable);
		if (result != GrabSuccess) {
			// back off to avoid grab deadlock
			XUngrabKeyboard(display, CurrentTime);
			LOG((CLOG_DEBUG2 "ungrabbed keyboard, waiting to grab pointer"));
			ARCH->sleep(0.05);
			if (timer.getTime() >= s_timeout) {
				LOG((CLOG_DEBUG2 "grab pointer timed out"));
				XUnmapWindow(display, m_window);
				return false;
			}
		}
	} while (result != GrabSuccess);
	LOG((CLOG_DEBUG1 "grabbed pointer and keyboard"));

	return true;
}