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 Service 5a9772
void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef,
Packit Service 5a9772
                      CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status,
Packit Service 5a9772
                                                    uint64_t displayTime, IOSurfaceRef frameSurface,
Packit Service 5a9772
                                                    CGDisplayStreamUpdateRef updateRef) {
Packit Service 5a9772
  dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
Packit Service 5a9772
Packit Service 5a9772
  // may need to move this down
Packit Service 5a9772
  if (ready == TRUE)
Packit Service 5a9772
  {
Packit Service 5a9772
Packit Service 5a9772
	  RFX_RECT rect;
Packit Service 5a9772
	  unsigned long offset_beg;
Packit Service 5a9772
	  unsigned long stride;
Packit Service 5a9772
	  int i;
Packit Service 5a9772
Packit Service 5a9772
	  rect.x = 0;
Packit Service 5a9772
	  rect.y = 0;
Packit Service 5a9772
	  rect.width = 0;
Packit Service 5a9772
	  rect.height = 0;
Packit Service 5a9772
	  mf_mlion_peek_dirty_region(&rect);
Packit Service 5a9772
Packit Service 5a9772
	  // lock surface
Packit Service 5a9772
	  IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
Packit Service 5a9772
	  // get pointer
Packit Service 5a9772
	  void* baseAddress = IOSurfaceGetBaseAddress(frameSurface);
Packit Service 5a9772
	  // copy region
Packit Service 5a9772
Packit Service 5a9772
	  stride = IOSurfaceGetBytesPerRow(frameSurface);
Packit Service 5a9772
	  // memcpy(localBuf, baseAddress + offset_beg, surflen);
Packit Service 5a9772
	  for (i = 0; i < rect.height; i++)
Packit Service 5a9772
	  {
Packit Service 5a9772
		  offset_beg = (stride * (rect.y + i) + (rect.x * 4));
Packit Service 5a9772
		  memcpy(localBuf + offset_beg, baseAddress + offset_beg, rect.width * 4);
Packit Service 5a9772
	  }
Packit Service 5a9772
Packit Service 5a9772
	  // unlock surface
Packit Service 5a9772
	  IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
Packit Service 5a9772
Packit Service 5a9772
	  ready = FALSE;
Packit Service 5a9772
	  dispatch_semaphore_signal(data_sem);
Packit Service 5a9772
  }
Packit Service 5a9772
Packit Service 5a9772
  if (status != kCGDisplayStreamFrameStatusFrameComplete)
Packit Service 5a9772
  {
Packit Service 5a9772
	  switch (status)
Packit Service 5a9772
	  {
Packit Service 5a9772
		  case kCGDisplayStreamFrameStatusFrameIdle:
Packit Service 5a9772
			  break;
Packit Service 5a9772
Packit Service 5a9772
		  case kCGDisplayStreamFrameStatusStopped:
Packit Service 5a9772
			  break;
Packit Service 5a9772
Packit Service 5a9772
		  case kCGDisplayStreamFrameStatusFrameBlank:
Packit Service 5a9772
			  break;
Packit Service 5a9772
Packit Service 5a9772
		  default:
Packit Service 5a9772
			  break;
Packit Service 5a9772
	  }
Packit Service 5a9772
  }
Packit Service 5a9772
  else if (lastUpdate == NULL)
Packit Service 5a9772
  {
Packit Service 5a9772
	  CFRetain(updateRef);
Packit Service 5a9772
	  lastUpdate = updateRef;
Packit Service 5a9772
  }
Packit Service 5a9772
  else
Packit Service 5a9772
  {
Packit Service 5a9772
	  CGDisplayStreamUpdateRef tmpRef;
Packit Service 5a9772
	  tmpRef = lastUpdate;
Packit Service 5a9772
	  lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
Packit Service 5a9772
	  CFRelease(tmpRef);
Packit Service 5a9772
  }
Packit Service 5a9772
Packit Service 5a9772
  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 Service 5a9772
Packit 1fb8d4
	display_id = CGMainDisplayID();
Packit Service 5a9772
Packit 1fb8d4
	CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
Packit Service 5a9772
Packit 1fb8d4
	size_t pixelWidth = CGDisplayModeGetPixelWidth(mode);
Packit Service 5a9772
	// size_t pixelHeight = CGDisplayModeGetPixelHeight(mode);
Packit Service 5a9772
Packit 1fb8d4
	size_t wide = CGDisplayPixelsWide(display_id);
Packit 1fb8d4
	size_t high = CGDisplayPixelsHigh(display_id);
Packit Service 5a9772
Packit 1fb8d4
	CGDisplayModeRelease(mode);
Packit Service 5a9772
Packit Service 5a9772
	*disp_width = wide;  // pixelWidth;
Packit Service 5a9772
	*disp_height = high; // pixelHeight;
Packit 1fb8d4
	*scale = pixelWidth / wide;
Packit Service 5a9772
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_screen_updates_init()
Packit 1fb8d4
{
Packit 1fb8d4
	CGDirectDisplayID display_id;
Packit Service 5a9772
Packit 1fb8d4
	display_id = CGMainDisplayID();
Packit Service 5a9772
Packit 1fb8d4
	screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL);
Packit Service 5a9772
Packit 1fb8d4
	region_sem = dispatch_semaphore_create(1);
Packit 1fb8d4
	data_sem = dispatch_semaphore_create(1);
Packit Service 5a9772
Packit 1fb8d4
	UINT32 pixelWidth;
Packit 1fb8d4
	UINT32 pixelHeight;
Packit 1fb8d4
	UINT32 scale;
Packit Service 5a9772
Packit 1fb8d4
	mf_mlion_display_info(&pixelWidth, &pixelHeight, &scale);
Packit Service 5a9772
Packit 1fb8d4
	localBuf = malloc(pixelWidth * pixelHeight * 4);
Packit 1fb8d4
	if (!localBuf)
Packit 1fb8d4
		return -1;
Packit Service 5a9772
Packit 1fb8d4
	CFDictionaryRef opts;
Packit Service 5a9772
Packit Service 5a9772
	void* keys[2];
Packit Service 5a9772
	void* values[2];
Packit Service 5a9772
Packit Service 5a9772
	keys[0] = (void*)kCGDisplayStreamShowCursor;
Packit Service 5a9772
	values[0] = (void*)kCFBooleanFalse;
Packit Service 5a9772
Packit Service 5a9772
	opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1,
Packit Service 5a9772
	                          NULL, NULL);
Packit Service 5a9772
Packit Service 5a9772
	stream = CGDisplayStreamCreateWithDispatchQueue(display_id, pixelWidth, pixelHeight, 'BGRA',
Packit Service 5a9772
	                                                opts, screen_update_q, streamHandler);
Packit Service 5a9772
Packit 1fb8d4
	CFRelease(opts);
Packit Service 5a9772
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int mf_mlion_start_getting_screen_updates()
Packit 1fb8d4
{
Packit 1fb8d4
	CGError err;
Packit Service 5a9772
Packit 1fb8d4
	err = CGDisplayStreamStart(stream);
Packit Service 5a9772
Packit 1fb8d4
	if (err != kCGErrorSuccess)
Packit 1fb8d4
	{
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
int mf_mlion_stop_getting_screen_updates()
Packit 1fb8d4
{
Packit 1fb8d4
	CGError err;
Packit Service 5a9772
Packit 1fb8d4
	err = CGDisplayStreamStop(stream);
Packit Service 5a9772
Packit 1fb8d4
	if (err != kCGErrorSuccess)
Packit 1fb8d4
	{
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit Service 5a9772
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 Service 5a9772
Packit 1fb8d4
	if (lastUpdate != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		mf_mlion_peek_dirty_region(invalid);
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
	dispatch_semaphore_signal(region_sem);
Packit Service 5a9772
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 Service 5a9772
Packit Service 5a9772
	const CGRect* rects =
Packit Service 5a9772
	    CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects);
Packit Service 5a9772
Packit Service 5a9772
	if (num_rects == 0)
Packit Service 5a9772
	{
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
	dirtyRegion = *rects;
Packit 1fb8d4
	for (i = 0; i < num_rects; i++)
Packit 1fb8d4
	{
Packit Service 5a9772
		dirtyRegion = CGRectUnion(dirtyRegion, *(rects + i));
Packit 1fb8d4
	}
Packit Service 5a9772
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 Service 5a9772
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 Service 5a9772
Packit 1fb8d4
	CFRelease(lastUpdate);
Packit 1fb8d4
	lastUpdate = NULL;
Packit Service 5a9772
Packit 1fb8d4
	dispatch_semaphore_signal(region_sem);
Packit Service 5a9772
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 Service 5a9772
Packit Service 5a9772
	// 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 Service 5a9772
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}