#include <freerdp/codec/region.h>
#include "../shadow_screen.h"
+#include "../shadow_client.h"
#include "../shadow_surface.h"
#include "../shadow_capture.h"
+#include "../shadow_encoder.h"
#include "../shadow_subsystem.h"
#include "mac_shadow.h"
if (extended)
vkcode |= KBDEXT;
- keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_APPLE) - 8;
+ keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_APPLE);
- if (keycode)
- {
- source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
+ if (keycode < 8)
+ return;
- if (flags & KBD_FLAGS_DOWN)
- {
- kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, TRUE);
- CGEventPost(kCGHIDEventTap, kbdEvent);
- CFRelease(kbdEvent);
- }
- else if (flags & KBD_FLAGS_RELEASE)
- {
- kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, FALSE);
- CGEventPost(kCGHIDEventTap, kbdEvent);
- CFRelease(kbdEvent);
- }
+ keycode -= 8;
+
+ source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
- CFRelease(source);
+ if (flags & KBD_FLAGS_DOWN)
+ {
+ kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, TRUE);
+ CGEventPost(kCGHIDEventTap, kbdEvent);
+ CFRelease(kbdEvent);
+ }
+ else if (flags & KBD_FLAGS_RELEASE)
+ {
+ kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, FALSE);
+ CGEventPost(kCGHIDEventTap, kbdEvent);
+ CFRelease(kbdEvent);
}
+
+ CFRelease(source);
}
void mac_shadow_input_unicode_keyboard_event(macShadowSubsystem* subsystem, UINT16 flags, UINT16 code)
return 1;
}
-int mac_shadow_capture_peek_dirty_region(macShadowSubsystem* subsystem)
+int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
{
size_t index;
size_t numRects;
return 0;
}
-int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
-{
- dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
-
- if (subsystem->lastUpdate)
- {
- mac_shadow_capture_peek_dirty_region(subsystem);
- }
-
- dispatch_semaphore_signal(subsystem->regionSemaphore);
-
- return 1;
-}
-
-int mac_shadow_capture_clear_dirty_region(macShadowSubsystem* subsystem)
-{
- dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
-
- CFRelease(subsystem->lastUpdate);
- subsystem->lastUpdate = NULL;
-
- dispatch_semaphore_signal(subsystem->regionSemaphore);
-
- return 1;
-}
-
-int mac_shadow_capture_surface_copy(macShadowSubsystem* subsystem)
-{
- dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
- subsystem->updateReady = TRUE;
-
- dispatch_semaphore_wait(subsystem->dataSemaphore, DISPATCH_TIME_FOREVER);
- dispatch_semaphore_signal(subsystem->regionSemaphore);
-
- dispatch_semaphore_wait(subsystem->dataSemaphore, DISPATCH_TIME_FOREVER);
- dispatch_semaphore_signal(subsystem->dataSemaphore);
-
- return 1;
-}
-
void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef) =
^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef)
{
rdpShadowServer* server = subsystem->server;
rdpShadowSurface* surface = server->surface;
- if (ArrayList_Count(server->clients) < 1)
- {
- region16_clear(&(subsystem->invalidRegion));
- return;
- }
+ count = ArrayList_Count(server->clients);
- dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
+ if (count < 1)
+ return;
- if (!subsystem->updateReady)
- {
- dispatch_semaphore_signal(subsystem->regionSemaphore);
+ if ((count == 1) && subsystem->suppressOutput)
return;
- }
- mac_shadow_capture_peek_dirty_region(subsystem);
+ mac_shadow_capture_get_dirty_region(subsystem);
- surfaceRect.left = surface->x;
- surfaceRect.top = surface->y;
- surfaceRect.right = surface->x + surface->width;
- surfaceRect.bottom = surface->y + surface->height;
+ surfaceRect.left = 0;
+ surfaceRect.top = 0;
+ surfaceRect.right = surface->width;
+ surfaceRect.bottom = surface->height;
region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect);
-
- if (region16_is_empty(&(subsystem->invalidRegion)))
+
+ if (!region16_is_empty(&(subsystem->invalidRegion)))
{
+ extents = region16_extents(&(subsystem->invalidRegion));
- }
+ x = extents->left;
+ y = extents->top;
+ width = extents->right - extents->left;
+ height = extents->bottom - extents->top;
- extents = region16_extents(&(subsystem->invalidRegion));
-
- x = extents->left;
- y = extents->top;
- width = extents->right - extents->left;
- height = extents->bottom - extents->top;
+ IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
- IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
-
- pSrcData = (BYTE*) IOSurfaceGetBaseAddress(frameSurface);
- nSrcStep = (int) IOSurfaceGetBytesPerRow(frameSurface);
+ pSrcData = (BYTE*) IOSurfaceGetBaseAddress(frameSurface);
+ nSrcStep = (int) IOSurfaceGetBytesPerRow(frameSurface);
- if (subsystem->retina)
- {
- freerdp_image_copy_from_retina(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
- x, y, width, height, pSrcData, nSrcStep, x, y);
- }
- else
- {
- freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
- x, y, width, height, pSrcData, PIXEL_FORMAT_XRGB32, nSrcStep, x, y, NULL);
- }
-
- IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
-
- subsystem->updateReady = FALSE;
- dispatch_semaphore_signal(subsystem->dataSemaphore);
-
- ArrayList_Lock(server->clients);
-
- count = ArrayList_Count(server->clients);
-
- InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1);
-
- SetEvent(subsystem->updateEvent);
+ if (subsystem->retina)
+ {
+ freerdp_image_copy_from_retina(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
+ x, y, width, height, pSrcData, nSrcStep, x, y);
+ }
+ else
+ {
+ freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
+ x, y, width, height, pSrcData, PIXEL_FORMAT_XRGB32, nSrcStep, x, y, NULL);
+ }
- EnterSynchronizationBarrier(&(subsystem->barrier), 0);
- ResetEvent(subsystem->updateEvent);
+ IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
+
+ ArrayList_Lock(server->clients);
+
+ count = ArrayList_Count(server->clients);
+
+ InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1);
+
+ SetEvent(subsystem->updateEvent);
+
+ EnterSynchronizationBarrier(&(subsystem->barrier), 0);
- DeleteSynchronizationBarrier(&(subsystem->barrier));
+ DeleteSynchronizationBarrier(&(subsystem->barrier));
- ArrayList_Unlock(server->clients);
+ if (count == 1)
+ {
+ rdpShadowClient* client;
+
+ client = (rdpShadowClient*) ArrayList_GetItem(server->clients, 0);
+
+ if (client)
+ {
+ subsystem->captureFrameRate = client->encoder->fps;
+ }
+ }
- region16_clear(&(subsystem->invalidRegion));
+ ResetEvent(subsystem->updateEvent);
+
+ ArrayList_Unlock(server->clients);
+
+ region16_clear(&(subsystem->invalidRegion));
+ }
if (status != kCGDisplayStreamFrameStatusFrameComplete)
{
subsystem->lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
CFRelease(tmpRef);
}
-
- dispatch_semaphore_signal(subsystem->regionSemaphore);
};
int mac_shadow_capture_init(macShadowSubsystem* subsystem)
displayId = CGMainDisplayID();
- subsystem->regionSemaphore = dispatch_semaphore_create(1);
- subsystem->dataSemaphore = dispatch_semaphore_create(1);
-
subsystem->updateBuffer = (BYTE*) malloc(subsystem->pixelWidth * subsystem->pixelHeight * 4);
+ if (!subsystem->updateBuffer)
+ return -1;
+
subsystem->captureQueue = dispatch_queue_create("mac.shadow.capture", NULL);
keys[0] = (void*) kCGDisplayStreamShowCursor;
int mac_shadow_screen_grab(macShadowSubsystem* subsystem)
{
- mac_shadow_capture_get_dirty_region(subsystem);
- mac_shadow_capture_surface_copy(subsystem);
+ return 1;
+}
+
+int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message)
+{
+ if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
+ {
+ UINT32 index;
+ SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
+
+ if (msg->numRects)
+ {
+ for (index = 0; index < msg->numRects; index++)
+ {
+ region16_union_rect(&(subsystem->invalidRegion),
+ &(subsystem->invalidRegion), &msg->rects[index]);
+ }
+ }
+ else
+ {
+ RECTANGLE_16 refreshRect;
+
+ refreshRect.left = 0;
+ refreshRect.top = 0;
+ refreshRect.right = subsystem->width;
+ refreshRect.bottom = subsystem->height;
+
+ region16_union_rect(&(subsystem->invalidRegion),
+ &(subsystem->invalidRegion), &refreshRect);
+ }
+ }
+ else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
+ {
+ SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
+
+ subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
+
+ if (msg->allow)
+ {
+ region16_union_rect(&(subsystem->invalidRegion),
+ &(subsystem->invalidRegion), &(msg->rect));
+ }
+ }
+
+ if (message->Free)
+ message->Free(message);
return 1;
}
void* mac_shadow_subsystem_thread(macShadowSubsystem* subsystem)
{
- int fps;
DWORD status;
DWORD nCount;
UINT64 cTime;
DWORD dwInterval;
UINT64 frameTime;
HANDLE events[32];
- HANDLE StopEvent;
+ wMessage message;
+ wMessagePipe* MsgPipe;
- StopEvent = subsystem->server->StopEvent;
+ MsgPipe = subsystem->MsgPipe;
nCount = 0;
- events[nCount++] = StopEvent;
+ events[nCount++] = MessageQueue_Event(MsgPipe->In);
- fps = 16;
- dwInterval = 1000 / fps;
+ subsystem->captureFrameRate = 16;
+ dwInterval = 1000 / subsystem->captureFrameRate;
frameTime = GetTickCount64() + dwInterval;
while (1)
status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
- if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
+ if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0)
{
- break;
+ if (MessageQueue_Peek(MsgPipe->In, &message, TRUE))
+ {
+ if (message.id == WMQ_QUIT)
+ break;
+
+ mac_shadow_subsystem_process_message(subsystem, &message);
+ }
}
if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
{
mac_shadow_screen_grab(subsystem);
- dwInterval = 1000 / fps;
+ dwInterval = 1000 / subsystem->captureFrameRate;
frameTime += dwInterval;
}
}
{
if (!subsystem)
return -1;
+
+ if (subsystem->lastUpdate)
+ {
+ CFRelease(subsystem->lastUpdate);
+ subsystem->lastUpdate = NULL;
+ }
return 1;
}