Blame server/Mac/mf_mountain_lion.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * OS X Server Event Handling
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#include <dispatch/dispatch.h>
Packit 1fb8d4
#include <CoreGraphics/CoreGraphics.h>
Packit 1fb8d4
#include <CoreVideo/CoreVideo.h>
Packit 1fb8d4
#include <IOKit/IOKitLib.h>
Packit 1fb8d4
#include <IOSurface/IOSurface.h>
Packit 1fb8d4
Packit 1fb8d4
#include "mf_mountain_lion.h"
Packit 1fb8d4
Packit 1fb8d4
dispatch_semaphore_t region_sem;
Packit 1fb8d4
dispatch_semaphore_t data_sem;
Packit 1fb8d4
dispatch_queue_t screen_update_q;
Packit 1fb8d4
CGDisplayStreamRef stream;
Packit 1fb8d4
Packit 1fb8d4
CGDisplayStreamUpdateRef lastUpdate = NULL;
Packit 1fb8d4
Packit 1fb8d4
BYTE* localBuf = NULL;
Packit 1fb8d4
Packit 1fb8d4
BOOL ready = FALSE;
Packit 1fb8d4
Packit 1fb8d4
void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef) =  ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef)
Packit 1fb8d4
{
Packit 1fb8d4
	
Packit 1fb8d4
	dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
Packit 1fb8d4
	
Packit 1fb8d4
	//may need to move this down
Packit 1fb8d4
	if(ready == TRUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		
Packit 1fb8d4
		RFX_RECT rect;
Packit 1fb8d4
		unsigned long offset_beg;
Packit 1fb8d4
		unsigned long stride;
Packit 1fb8d4
		int i;
Packit 1fb8d4
		
Packit 1fb8d4
		rect.x = 0;
Packit 1fb8d4
		rect.y = 0;
Packit 1fb8d4
		rect.width = 0;
Packit 1fb8d4
		rect.height = 0;
Packit 1fb8d4
		mf_mlion_peek_dirty_region(&rect);
Packit 1fb8d4
		
Packit 1fb8d4
		
Packit 1fb8d4
		//lock surface
Packit 1fb8d4
		IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
Packit 1fb8d4
		//get pointer
Packit 1fb8d4
		void* baseAddress = IOSurfaceGetBaseAddress(frameSurface);
Packit 1fb8d4
		//copy region
Packit 1fb8d4
		
Packit 1fb8d4
		stride = IOSurfaceGetBytesPerRow(frameSurface);
Packit 1fb8d4
		//memcpy(localBuf, baseAddress + offset_beg, surflen);
Packit 1fb8d4
		for(i = 0; i < rect.height; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			offset_beg = (stride * (rect.y + i) + (rect.x * 4));
Packit 1fb8d4
			memcpy(localBuf + offset_beg,
Packit 1fb8d4
			       baseAddress + offset_beg,
Packit 1fb8d4
			       rect.width * 4);
Packit 1fb8d4
		}
Packit 1fb8d4
		
Packit 1fb8d4
		//unlock surface
Packit 1fb8d4
		IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
Packit 1fb8d4
		
Packit 1fb8d4
		ready = FALSE;
Packit 1fb8d4
		dispatch_semaphore_signal(data_sem);
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	if (status != kCGDisplayStreamFrameStatusFrameComplete)
Packit 1fb8d4
	{
Packit 1fb8d4
		switch(status)
Packit 1fb8d4
		{
Packit 1fb8d4
			case kCGDisplayStreamFrameStatusFrameIdle:
Packit 1fb8d4
				break;
Packit 1fb8d4
				
Packit 1fb8d4
			case kCGDisplayStreamFrameStatusStopped:
Packit 1fb8d4
				break;
Packit 1fb8d4
				
Packit 1fb8d4
			case kCGDisplayStreamFrameStatusFrameBlank:
Packit 1fb8d4
				break;
Packit 1fb8d4
				
Packit 1fb8d4
			default:
Packit 1fb8d4
				break;
Packit 1fb8d4
				
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (lastUpdate == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		CFRetain(updateRef);
Packit 1fb8d4
		lastUpdate = updateRef;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		CGDisplayStreamUpdateRef tmpRef;
Packit 1fb8d4
		tmpRef = lastUpdate;
Packit 1fb8d4
		lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
Packit 1fb8d4
		CFRelease(tmpRef);
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	dispatch_semaphore_signal(region_sem);
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_display_info(UINT32* disp_width, UINT32* disp_height, UINT32* scale)
Packit 1fb8d4
{
Packit 1fb8d4
	CGDirectDisplayID display_id;
Packit 1fb8d4
	
Packit 1fb8d4
	display_id = CGMainDisplayID();
Packit 1fb8d4
	
Packit 1fb8d4
	CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
Packit 1fb8d4
	
Packit 1fb8d4
	size_t pixelWidth = CGDisplayModeGetPixelWidth(mode);
Packit 1fb8d4
	//size_t pixelHeight = CGDisplayModeGetPixelHeight(mode);
Packit 1fb8d4
	
Packit 1fb8d4
	size_t wide = CGDisplayPixelsWide(display_id);
Packit 1fb8d4
	size_t high = CGDisplayPixelsHigh(display_id);
Packit 1fb8d4
	
Packit 1fb8d4
	CGDisplayModeRelease(mode);
Packit 1fb8d4
	
Packit 1fb8d4
	*disp_width = wide;//pixelWidth;
Packit 1fb8d4
	*disp_height = high;//pixelHeight;
Packit 1fb8d4
	*scale = pixelWidth / wide;
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_screen_updates_init()
Packit 1fb8d4
{
Packit 1fb8d4
	CGDirectDisplayID display_id;
Packit 1fb8d4
	
Packit 1fb8d4
	display_id = CGMainDisplayID();
Packit 1fb8d4
	
Packit 1fb8d4
	screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL);
Packit 1fb8d4
	
Packit 1fb8d4
	region_sem = dispatch_semaphore_create(1);
Packit 1fb8d4
	data_sem = dispatch_semaphore_create(1);
Packit 1fb8d4
	
Packit 1fb8d4
	UINT32 pixelWidth;
Packit 1fb8d4
	UINT32 pixelHeight;
Packit 1fb8d4
	UINT32 scale;
Packit 1fb8d4
	
Packit 1fb8d4
	mf_mlion_display_info(&pixelWidth, &pixelHeight, &scale);
Packit 1fb8d4
	
Packit 1fb8d4
	localBuf = malloc(pixelWidth * pixelHeight * 4);
Packit 1fb8d4
	if (!localBuf)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	
Packit 1fb8d4
	CFDictionaryRef opts;
Packit 1fb8d4
	
Packit 1fb8d4
	void * keys[2];
Packit 1fb8d4
	void * values[2];
Packit 1fb8d4
	
Packit 1fb8d4
	keys[0] = (void *) kCGDisplayStreamShowCursor;
Packit 1fb8d4
	values[0] = (void *) kCFBooleanFalse;
Packit 1fb8d4
	
Packit 1fb8d4
	opts = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 1, NULL, NULL);
Packit 1fb8d4
	
Packit 1fb8d4
	
Packit 1fb8d4
	stream = CGDisplayStreamCreateWithDispatchQueue(display_id,
Packit 1fb8d4
							pixelWidth,
Packit 1fb8d4
							pixelHeight,
Packit 1fb8d4
							'BGRA',
Packit 1fb8d4
							opts,
Packit 1fb8d4
							screen_update_q,
Packit 1fb8d4
							streamHandler);
Packit 1fb8d4
	
Packit 1fb8d4
	CFRelease(opts);
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
	
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_start_getting_screen_updates()
Packit 1fb8d4
{
Packit 1fb8d4
	CGError err;
Packit 1fb8d4
	
Packit 1fb8d4
	err = CGDisplayStreamStart(stream);
Packit 1fb8d4
	
Packit 1fb8d4
	if (err != kCGErrorSuccess)
Packit 1fb8d4
	{
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
	
Packit 1fb8d4
}
Packit 1fb8d4
int mf_mlion_stop_getting_screen_updates()
Packit 1fb8d4
{
Packit 1fb8d4
	CGError err;
Packit 1fb8d4
	
Packit 1fb8d4
	err = CGDisplayStreamStop(stream);
Packit 1fb8d4
	
Packit 1fb8d4
	if (err != kCGErrorSuccess)
Packit 1fb8d4
	{
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_get_dirty_region(RFX_RECT* invalid)
Packit 1fb8d4
{
Packit 1fb8d4
	dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
Packit 1fb8d4
	
Packit 1fb8d4
	if (lastUpdate != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		mf_mlion_peek_dirty_region(invalid);
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	dispatch_semaphore_signal(region_sem);
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_peek_dirty_region(RFX_RECT* invalid)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t num_rects, i;
Packit 1fb8d4
	CGRect dirtyRegion;
Packit 1fb8d4
	
Packit 1fb8d4
	const CGRect * rects = CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects);
Packit 1fb8d4
		
Packit 1fb8d4
	if (num_rects == 0) {
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	dirtyRegion = *rects;
Packit 1fb8d4
	for (i = 0; i < num_rects; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		dirtyRegion = CGRectUnion(dirtyRegion, *(rects+i));
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	invalid->x = dirtyRegion.origin.x;
Packit 1fb8d4
	invalid->y = dirtyRegion.origin.y;
Packit 1fb8d4
	invalid->height = dirtyRegion.size.height;
Packit 1fb8d4
	invalid->width = dirtyRegion.size.width;
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_clear_dirty_region()
Packit 1fb8d4
{
Packit 1fb8d4
	dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
Packit 1fb8d4
	
Packit 1fb8d4
	CFRelease(lastUpdate);
Packit 1fb8d4
	lastUpdate = NULL;
Packit 1fb8d4
	
Packit 1fb8d4
	dispatch_semaphore_signal(region_sem);
Packit 1fb8d4
	
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData)
Packit 1fb8d4
{
Packit 1fb8d4
	dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
Packit 1fb8d4
	ready = TRUE;
Packit 1fb8d4
	dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
Packit 1fb8d4
	dispatch_semaphore_signal(region_sem);
Packit 1fb8d4
	
Packit 1fb8d4
	//this second wait allows us to block until data is copied... more on this later
Packit 1fb8d4
	dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
Packit 1fb8d4
	*pxData = localBuf;
Packit 1fb8d4
	dispatch_semaphore_signal(data_sem);
Packit 1fb8d4
	
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}