Blame server/Mac/mf_mountain_lion.c

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