Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
269
third_party/FreeRDP/server/Mac/mf_mountain_lion.c
vendored
Normal file
269
third_party/FreeRDP/server/Mac/mf_mountain_lion.c
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* 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>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOSurface/IOSurface.h>
|
||||
|
||||
#include "mf_mountain_lion.h"
|
||||
|
||||
dispatch_semaphore_t region_sem;
|
||||
dispatch_semaphore_t data_sem;
|
||||
dispatch_queue_t screen_update_q;
|
||||
CGDisplayStreamRef stream;
|
||||
|
||||
CGDisplayStreamUpdateRef lastUpdate = nullptr;
|
||||
|
||||
BYTE* localBuf = nullptr;
|
||||
|
||||
BOOL ready = FALSE;
|
||||
|
||||
void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef,
|
||||
CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status,
|
||||
uint64_t displayTime, IOSurfaceRef frameSurface,
|
||||
CGDisplayStreamUpdateRef updateRef) {
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
// may need to move this down
|
||||
if (ready == TRUE)
|
||||
{
|
||||
|
||||
RFX_RECT rect;
|
||||
unsigned long offset_beg;
|
||||
unsigned long stride;
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = 0;
|
||||
rect.height = 0;
|
||||
mf_mlion_peek_dirty_region(&rect);
|
||||
|
||||
// lock surface
|
||||
IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, nullptr);
|
||||
// get pointer
|
||||
void* baseAddress = IOSurfaceGetBaseAddress(frameSurface);
|
||||
// copy region
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// unlock surface
|
||||
IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, nullptr);
|
||||
|
||||
ready = FALSE;
|
||||
dispatch_semaphore_signal(data_sem);
|
||||
}
|
||||
|
||||
if (status != kCGDisplayStreamFrameStatusFrameComplete)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case kCGDisplayStreamFrameStatusFrameIdle:
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusStopped:
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusFrameBlank:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (lastUpdate == nullptr)
|
||||
{
|
||||
CFRetain(updateRef);
|
||||
lastUpdate = updateRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGDisplayStreamUpdateRef tmpRef;
|
||||
tmpRef = lastUpdate;
|
||||
lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
|
||||
CFRelease(tmpRef);
|
||||
}
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
};
|
||||
|
||||
int mf_mlion_display_info(UINT32* disp_width, UINT32* disp_height, UINT32* scale)
|
||||
{
|
||||
CGDirectDisplayID display_id;
|
||||
|
||||
display_id = CGMainDisplayID();
|
||||
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
|
||||
|
||||
size_t pixelWidth = CGDisplayModeGetPixelWidth(mode);
|
||||
// size_t pixelHeight = CGDisplayModeGetPixelHeight(mode);
|
||||
|
||||
size_t wide = CGDisplayPixelsWide(display_id);
|
||||
size_t high = CGDisplayPixelsHigh(display_id);
|
||||
|
||||
CGDisplayModeRelease(mode);
|
||||
|
||||
*disp_width = wide; // pixelWidth;
|
||||
*disp_height = high; // pixelHeight;
|
||||
*scale = pixelWidth / wide;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_screen_updates_init()
|
||||
{
|
||||
CGDirectDisplayID display_id;
|
||||
|
||||
display_id = CGMainDisplayID();
|
||||
|
||||
screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", nullptr);
|
||||
|
||||
region_sem = dispatch_semaphore_create(1);
|
||||
data_sem = dispatch_semaphore_create(1);
|
||||
|
||||
UINT32 pixelWidth;
|
||||
UINT32 pixelHeight;
|
||||
UINT32 scale;
|
||||
|
||||
mf_mlion_display_info(&pixelWidth, &pixelHeight, &scale);
|
||||
|
||||
localBuf = malloc(pixelWidth * pixelHeight * 4);
|
||||
if (!localBuf)
|
||||
return -1;
|
||||
|
||||
CFDictionaryRef opts;
|
||||
|
||||
void* keys[2];
|
||||
void* values[2];
|
||||
|
||||
keys[0] = (void*)kCGDisplayStreamShowCursor;
|
||||
values[0] = (void*)kCFBooleanFalse;
|
||||
|
||||
opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1,
|
||||
nullptr, nullptr);
|
||||
|
||||
stream = CGDisplayStreamCreateWithDispatchQueue(display_id, pixelWidth, pixelHeight, 'BGRA',
|
||||
opts, screen_update_q, streamHandler);
|
||||
|
||||
CFRelease(opts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_start_getting_screen_updates()
|
||||
{
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStart(stream);
|
||||
|
||||
if (err != kCGErrorSuccess)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mf_mlion_stop_getting_screen_updates()
|
||||
{
|
||||
CGError err;
|
||||
|
||||
err = CGDisplayStreamStop(stream);
|
||||
|
||||
if (err != kCGErrorSuccess)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_get_dirty_region(RFX_RECT* invalid)
|
||||
{
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (lastUpdate != nullptr)
|
||||
{
|
||||
mf_mlion_peek_dirty_region(invalid);
|
||||
}
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_peek_dirty_region(RFX_RECT* invalid)
|
||||
{
|
||||
size_t num_rects;
|
||||
CGRect dirtyRegion;
|
||||
|
||||
const CGRect* rects =
|
||||
CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects);
|
||||
|
||||
if (num_rects == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
dirtyRegion = *rects;
|
||||
for (size_t i = 0; i < num_rects; i++)
|
||||
{
|
||||
dirtyRegion = CGRectUnion(dirtyRegion, *(rects + i));
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
CFRelease(lastUpdate);
|
||||
lastUpdate = nullptr;
|
||||
|
||||
dispatch_semaphore_signal(region_sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData)
|
||||
{
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user