2012-11-16 03:09:20 +04:00
|
|
|
/**
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
* OS X Server Event Handling
|
|
|
|
*
|
|
|
|
* Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <dispatch/dispatch.h>
|
|
|
|
#include <CoreGraphics/CoreGraphics.h>
|
2012-12-10 02:40:37 +04:00
|
|
|
#include <CoreVideo/CoreVideo.h>
|
|
|
|
#include <IOKit/IOKitLib.h>
|
|
|
|
#include <IOSurface/IOSurface.h>
|
2012-11-16 03:09:20 +04:00
|
|
|
|
|
|
|
#include "mf_mountain_lion.h"
|
|
|
|
|
|
|
|
dispatch_semaphore_t region_sem;
|
2012-12-10 02:40:37 +04:00
|
|
|
dispatch_semaphore_t data_sem;
|
2012-11-16 03:09:20 +04:00
|
|
|
dispatch_queue_t screen_update_q;
|
|
|
|
CGDisplayStreamRef stream;
|
|
|
|
|
2012-11-16 21:59:16 +04:00
|
|
|
CGDisplayStreamUpdateRef lastUpdate = NULL;
|
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
BYTE* localBuf = NULL;
|
2012-11-16 03:09:20 +04:00
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
//CVPixelBufferRef pxbuffer = NULL;
|
|
|
|
//void *baseAddress = NULL;
|
2012-12-06 00:35:11 +04:00
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
//CGContextRef bitmapcontext = NULL;
|
|
|
|
|
|
|
|
//CGImageRef image = NULL;
|
|
|
|
|
|
|
|
BOOL ready = FALSE;
|
2012-11-16 03:09:20 +04:00
|
|
|
|
|
|
|
void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef)
|
|
|
|
{
|
2012-11-16 21:59:16 +04:00
|
|
|
|
|
|
|
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
//may need to move this down
|
2012-12-10 07:17:53 +04:00
|
|
|
if(ready == TRUE)
|
2012-12-10 02:40:37 +04:00
|
|
|
{
|
2012-12-10 07:17:53 +04:00
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
RFX_RECT rect;
|
|
|
|
unsigned long offset_beg;
|
2012-12-10 07:17:53 +04:00
|
|
|
unsigned long surflen;
|
|
|
|
unsigned long stride;
|
2012-12-10 02:40:37 +04:00
|
|
|
|
|
|
|
rect.x = 0;
|
|
|
|
rect.y = 0;
|
2012-12-10 07:17:53 +04:00
|
|
|
rect.width = 0;
|
|
|
|
rect.height = 0;
|
|
|
|
mf_mlion_peek_dirty_region(&rect);
|
2012-12-10 02:40:37 +04:00
|
|
|
|
|
|
|
|
|
|
|
//lock surface
|
|
|
|
IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
|
|
|
|
//get pointer
|
|
|
|
void* baseAddress = IOSurfaceGetBaseAddress(frameSurface);
|
|
|
|
//copy region
|
2012-12-10 07:17:53 +04:00
|
|
|
|
|
|
|
stride = IOSurfaceGetBytesPerRow(frameSurface);
|
|
|
|
//memcpy(localBuf, baseAddress + offset_beg, surflen);
|
|
|
|
for(int i = 0; i < rect.height; i++)
|
|
|
|
{
|
|
|
|
offset_beg = (stride * (rect.y + i) + (rect.x * 4));
|
|
|
|
memcpy(localBuf + offset_beg,
|
|
|
|
baseAddress + offset_beg,
|
|
|
|
rect.width * 4);
|
|
|
|
}
|
2012-12-10 02:40:37 +04:00
|
|
|
|
|
|
|
//unlock surface
|
|
|
|
IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
|
2012-12-10 07:17:53 +04:00
|
|
|
|
|
|
|
ready = FALSE;
|
2012-12-10 02:40:37 +04:00
|
|
|
dispatch_semaphore_signal(data_sem);
|
|
|
|
}
|
|
|
|
|
2012-11-16 21:59:16 +04:00
|
|
|
if (lastUpdate == NULL)
|
|
|
|
{
|
|
|
|
CFRetain(updateRef);
|
|
|
|
lastUpdate = updateRef;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CGDisplayStreamUpdateRef tmpRef;
|
|
|
|
tmpRef = lastUpdate;
|
|
|
|
lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
|
|
|
|
CFRelease(tmpRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch_semaphore_signal(region_sem);
|
2012-11-16 03:09:20 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
int mf_mlion_screen_updates_init()
|
|
|
|
{
|
2012-11-16 03:34:33 +04:00
|
|
|
printf("mf_mlion_screen_updates_init()\n");
|
2012-11-16 03:09:20 +04:00
|
|
|
CGDirectDisplayID display_id;
|
|
|
|
|
|
|
|
display_id = CGMainDisplayID();
|
|
|
|
|
|
|
|
screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL);
|
|
|
|
|
|
|
|
region_sem = dispatch_semaphore_create(1);
|
2012-12-10 02:40:37 +04:00
|
|
|
data_sem = dispatch_semaphore_create(1);
|
2012-11-16 03:09:20 +04:00
|
|
|
|
|
|
|
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
|
|
|
|
|
|
|
|
size_t pixelWidth = CGDisplayModeGetPixelWidth(mode);
|
|
|
|
size_t pixelHeight = CGDisplayModeGetPixelHeight(mode);
|
|
|
|
|
|
|
|
CGDisplayModeRelease(mode);
|
2012-12-10 02:40:37 +04:00
|
|
|
|
|
|
|
localBuf = malloc(pixelWidth * pixelHeight * 4);
|
2012-11-16 03:09:20 +04:00
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
|
2012-11-16 03:09:20 +04:00
|
|
|
stream = CGDisplayStreamCreateWithDispatchQueue(display_id,
|
|
|
|
pixelWidth,
|
|
|
|
pixelHeight,
|
|
|
|
'BGRA',
|
|
|
|
NULL,
|
|
|
|
screen_update_q,
|
|
|
|
streamHandler);
|
2012-12-10 02:40:37 +04:00
|
|
|
/*
|
2012-12-06 00:35:11 +04:00
|
|
|
|
|
|
|
CFDictionaryRef opts;
|
|
|
|
|
|
|
|
long ImageCompatibility;
|
|
|
|
long BitmapContextCompatibility;
|
|
|
|
|
|
|
|
void * keys[3];
|
|
|
|
keys[0] = (void *) kCVPixelBufferCGImageCompatibilityKey;
|
|
|
|
keys[1] = (void *) kCVPixelBufferCGBitmapContextCompatibilityKey;
|
|
|
|
keys[2] = NULL;
|
|
|
|
|
|
|
|
void * values[3];
|
|
|
|
values[0] = (void *) &ImageCompatibility;
|
|
|
|
values[1] = (void *) &BitmapContextCompatibility;
|
|
|
|
values[2] = NULL;
|
|
|
|
|
|
|
|
opts = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 2, NULL, NULL);
|
|
|
|
|
|
|
|
if (opts == NULL)
|
|
|
|
{
|
|
|
|
printf("failed to create dictionary\n");
|
|
|
|
//return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, pixelWidth,
|
|
|
|
pixelHeight, kCVPixelFormatType_32ARGB, opts,
|
|
|
|
&pxbuffer);
|
|
|
|
|
|
|
|
if (status != kCVReturnSuccess)
|
|
|
|
{
|
|
|
|
printf("Failed to create pixel buffer! \n");
|
|
|
|
//return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease(opts);
|
|
|
|
|
|
|
|
CVPixelBufferLockBaseAddress(pxbuffer, 0);
|
|
|
|
baseAddress = CVPixelBufferGetBaseAddress(pxbuffer);
|
|
|
|
|
|
|
|
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
|
|
|
|
|
|
|
|
bitmapcontext = CGBitmapContextCreate(baseAddress,
|
|
|
|
pixelWidth,
|
|
|
|
pixelHeight, 8, 4*pixelWidth, rgbColorSpace,
|
|
|
|
kCGImageAlphaNoneSkipLast);
|
|
|
|
|
|
|
|
if (bitmapcontext == NULL) {
|
|
|
|
printf("context = null!!!\n\n\n");
|
|
|
|
}
|
|
|
|
CGColorSpaceRelease(rgbColorSpace);
|
2012-12-10 02:40:37 +04:00
|
|
|
*/
|
2012-12-06 00:35:11 +04:00
|
|
|
|
2012-11-16 03:09:20 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int mf_mlion_start_getting_screen_updates()
|
|
|
|
{
|
2012-12-10 02:40:37 +04:00
|
|
|
CGError err;
|
|
|
|
|
|
|
|
err = CGDisplayStreamStart(stream);
|
|
|
|
if(err != kCGErrorSuccess)
|
|
|
|
{
|
|
|
|
printf("Failed to start displaystream!! err = %d\n", err);
|
|
|
|
return 1;
|
|
|
|
}
|
2012-11-16 03:09:20 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
int mf_mlion_stop_getting_screen_updates()
|
|
|
|
{
|
2012-12-10 02:40:37 +04:00
|
|
|
CGError err;
|
|
|
|
|
|
|
|
err = CGDisplayStreamStop(stream);
|
|
|
|
if(err != kCGErrorSuccess)
|
|
|
|
{
|
|
|
|
printf("Failed to stop displaystream!! err = %d\n", err);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2012-11-16 03:09:20 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mf_mlion_get_dirty_region(RFX_RECT* invalid)
|
|
|
|
{
|
2012-12-10 02:40:37 +04:00
|
|
|
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
2012-11-16 21:59:16 +04:00
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
if (lastUpdate != NULL)
|
|
|
|
{
|
|
|
|
mf_mlion_peek_dirty_region(invalid);
|
|
|
|
|
2012-12-10 07:17:53 +04:00
|
|
|
//CFRelease(lastUpdate);
|
2012-12-10 02:40:37 +04:00
|
|
|
|
2012-12-10 07:17:53 +04:00
|
|
|
//lastUpdate = NULL;
|
2012-12-10 02:40:37 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-11-16 03:09:20 +04:00
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
dispatch_semaphore_signal(region_sem);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2012-11-16 03:09:20 +04:00
|
|
|
|
2012-12-10 02:40:37 +04:00
|
|
|
int mf_mlion_peek_dirty_region(RFX_RECT* invalid)
|
|
|
|
{
|
|
|
|
size_t num_rects;
|
|
|
|
CGRect dirtyRegion;
|
|
|
|
|
2012-11-16 21:59:16 +04:00
|
|
|
const CGRect * rects = CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects);
|
|
|
|
|
|
|
|
printf("\trectangles: %zd\n", num_rects);
|
|
|
|
|
|
|
|
if (num_rects == 0) {
|
2012-12-10 02:40:37 +04:00
|
|
|
//dispatch_semaphore_signal(region_sem);
|
2012-11-16 21:59:16 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dirtyRegion = *rects;
|
|
|
|
for (size_t i = 0; i < num_rects; i++)
|
2012-12-10 02:40:37 +04:00
|
|
|
{
|
2012-11-16 21:59:16 +04:00
|
|
|
dirtyRegion = CGRectUnion(dirtyRegion, *(rects+i));
|
|
|
|
}
|
|
|
|
|
2012-11-16 03:09:20 +04:00
|
|
|
invalid->x = dirtyRegion.origin.x;
|
|
|
|
invalid->y = dirtyRegion.origin.y;
|
|
|
|
invalid->height = dirtyRegion.size.height;
|
|
|
|
invalid->width = dirtyRegion.size.width;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mf_mlion_clear_dirty_region()
|
|
|
|
{
|
2012-11-16 21:59:16 +04:00
|
|
|
/* dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
2012-11-16 03:09:20 +04:00
|
|
|
|
|
|
|
clean = TRUE;
|
|
|
|
dirtyRegion.size.width = 0;
|
|
|
|
dirtyRegion.size.height = 0;
|
|
|
|
|
|
|
|
dispatch_semaphore_signal(region_sem);
|
2012-11-16 21:59:16 +04:00
|
|
|
*/
|
2012-12-10 07:17:53 +04:00
|
|
|
|
|
|
|
CFRelease(lastUpdate);
|
|
|
|
lastUpdate = NULL;
|
|
|
|
|
|
|
|
|
2012-11-16 03:09:20 +04:00
|
|
|
return 0;
|
2012-12-06 00:35:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData)
|
|
|
|
{
|
2012-12-10 02:40:37 +04:00
|
|
|
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
|
|
|
ready = TRUE;
|
|
|
|
dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
|
|
|
|
dispatch_semaphore_signal(region_sem);
|
|
|
|
|
|
|
|
//this second wait allows us to block until data is copied... more on this later
|
|
|
|
dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
|
|
|
|
*pxData = localBuf;
|
|
|
|
dispatch_semaphore_signal(data_sem);
|
|
|
|
|
|
|
|
/*
|
2012-12-06 00:35:11 +04:00
|
|
|
if (image != NULL) {
|
|
|
|
CGImageRelease(image);
|
|
|
|
}
|
|
|
|
image = CGDisplayCreateImageForRect(
|
|
|
|
kCGDirectMainDisplay,
|
|
|
|
CGRectMake(x, y, width, height) );
|
|
|
|
|
|
|
|
CGContextDrawImage(
|
|
|
|
bitmapcontext,
|
|
|
|
CGRectMake(0, 1800 - height, width, height),
|
|
|
|
image);
|
|
|
|
|
|
|
|
*pxData = baseAddress;
|
2012-12-10 02:40:37 +04:00
|
|
|
|
|
|
|
*/
|
2012-12-06 00:35:11 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|