20#include <winpr/synch.h> 
   21#include <winpr/input.h> 
   22#include <winpr/sysinfo.h> 
   24#include <freerdp/server/server-common.h> 
   25#include <freerdp/codec/color.h> 
   26#include <freerdp/codec/region.h> 
   27#include <freerdp/log.h> 
   29#include "mac_shadow.h" 
   31#define TAG SERVER_TAG("shadow.mac") 
   33static macShadowSubsystem* g_Subsystem = NULL;
 
   35static BOOL mac_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
 
   36                                               rdpShadowClient* client, UINT32 flags)
 
   38  if (!subsystem || !client)
 
   44static BOOL mac_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
 
   45                                            UINT16 flags, UINT8 code)
 
   51  CGEventSourceRef source;
 
   52  extended = (flags & KBD_FLAGS_EXTENDED) ? TRUE : FALSE;
 
   54  if (!subsystem || !client)
 
   60  vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4);
 
   65  keycode = GetKeycodeFromVirtualKeyCode(vkcode, WINPR_KEYCODE_TYPE_APPLE);
 
   67  source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
 
   69  if (flags & KBD_FLAGS_DOWN)
 
   71    kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keycode, TRUE);
 
   72    CGEventPost(kCGHIDEventTap, kbdEvent);
 
   75  else if (flags & KBD_FLAGS_RELEASE)
 
   77    kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keycode, FALSE);
 
   78    CGEventPost(kCGHIDEventTap, kbdEvent);
 
   86static BOOL mac_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem,
 
   87                                                    rdpShadowClient* client, UINT16 flags,
 
   90  if (!subsystem || !client)
 
   96static BOOL mac_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
 
   97                                         UINT16 flags, UINT16 x, UINT16 y)
 
   99  macShadowSubsystem* mac = (macShadowSubsystem*)subsystem;
 
  102  CGWheelCount wheelCount = 2;
 
  104  if (!subsystem || !client)
 
  107  if (flags & PTR_FLAGS_WHEEL)
 
  109    scrollY = flags & WheelRotationMask;
 
  111    if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
 
  113      scrollY = -(flags & WheelRotationMask) / 392;
 
  117      scrollY = (flags & WheelRotationMask) / 120;
 
  120    CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
 
  121    CGEventRef scroll = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitLine,
 
  122                                                      wheelCount, scrollY, scrollX);
 
  123    CGEventPost(kCGHIDEventTap, scroll);
 
  129    CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
 
  130    CGEventType mouseType = kCGEventNull;
 
  131    CGMouseButton mouseButton = kCGMouseButtonLeft;
 
  133    if (flags & PTR_FLAGS_MOVE)
 
  135      if (mac->mouseDownLeft)
 
  136        mouseType = kCGEventLeftMouseDragged;
 
  137      else if (mac->mouseDownRight)
 
  138        mouseType = kCGEventRightMouseDragged;
 
  139      else if (mac->mouseDownOther)
 
  140        mouseType = kCGEventOtherMouseDragged;
 
  142        mouseType = kCGEventMouseMoved;
 
  145          CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton);
 
  146      CGEventPost(kCGHIDEventTap, move);
 
  150    if (flags & PTR_FLAGS_BUTTON1)
 
  152      mouseButton = kCGMouseButtonLeft;
 
  154      if (flags & PTR_FLAGS_DOWN)
 
  156        mouseType = kCGEventLeftMouseDown;
 
  157        mac->mouseDownLeft = TRUE;
 
  161        mouseType = kCGEventLeftMouseUp;
 
  162        mac->mouseDownLeft = FALSE;
 
  165    else if (flags & PTR_FLAGS_BUTTON2)
 
  167      mouseButton = kCGMouseButtonRight;
 
  169      if (flags & PTR_FLAGS_DOWN)
 
  171        mouseType = kCGEventRightMouseDown;
 
  172        mac->mouseDownRight = TRUE;
 
  176        mouseType = kCGEventRightMouseUp;
 
  177        mac->mouseDownRight = FALSE;
 
  180    else if (flags & PTR_FLAGS_BUTTON3)
 
  182      mouseButton = kCGMouseButtonCenter;
 
  184      if (flags & PTR_FLAGS_DOWN)
 
  186        mouseType = kCGEventOtherMouseDown;
 
  187        mac->mouseDownOther = TRUE;
 
  191        mouseType = kCGEventOtherMouseUp;
 
  192        mac->mouseDownOther = FALSE;
 
  196    CGEventRef mouseEvent =
 
  197        CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton);
 
  198    CGEventPost(kCGHIDEventTap, mouseEvent);
 
  199    CFRelease(mouseEvent);
 
  206static BOOL mac_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
 
  207                                                  rdpShadowClient* client, UINT16 flags, UINT16 x,
 
  210  if (!subsystem || !client)
 
  216static int mac_shadow_detect_monitors(macShadowSubsystem* subsystem)
 
  220  CGDirectDisplayID displayId;
 
  221  displayId = CGMainDisplayID();
 
  222  CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
 
  223  subsystem->pixelWidth = CGDisplayModeGetPixelWidth(mode);
 
  224  subsystem->pixelHeight = CGDisplayModeGetPixelHeight(mode);
 
  225  wide = CGDisplayPixelsWide(displayId);
 
  226  high = CGDisplayPixelsHigh(displayId);
 
  227  CGDisplayModeRelease(mode);
 
  228  subsystem->retina = ((subsystem->pixelWidth / wide) == 2) ? TRUE : FALSE;
 
  230  if (subsystem->retina)
 
  232    subsystem->width = wide;
 
  233    subsystem->height = high;
 
  237    subsystem->width = subsystem->pixelWidth;
 
  238    subsystem->height = subsystem->pixelHeight;
 
  241  subsystem->common.numMonitors = 1;
 
  242  monitor = &(subsystem->common.monitors[0]);
 
  245  monitor->right = subsystem->width;
 
  246  monitor->bottom = subsystem->height;
 
  251static int mac_shadow_capture_start(macShadowSubsystem* subsystem)
 
  254  err = CGDisplayStreamStart(subsystem->stream);
 
  256  if (err != kCGErrorSuccess)
 
  262static int mac_shadow_capture_stop(macShadowSubsystem* subsystem)
 
  265  err = CGDisplayStreamStop(subsystem->stream);
 
  267  if (err != kCGErrorSuccess)
 
  273static int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
 
  278  rdpShadowSurface* surface = subsystem->common.server->surface;
 
  279  rects = CGDisplayStreamUpdateGetRects(subsystem->lastUpdate, kCGDisplayStreamUpdateDirtyRects,
 
  285  for (
size_t index = 0; index < numRects; index++)
 
  287    invalidRect.left = (UINT16)rects[index].origin.x;
 
  288    invalidRect.top = (UINT16)rects[index].origin.y;
 
  289    invalidRect.right = invalidRect.left + (UINT16)rects[index].size.width;
 
  290    invalidRect.bottom = invalidRect.top + (UINT16)rects[index].size.height;
 
  292    if (subsystem->retina)
 
  295      invalidRect.left /= 2;
 
  296      invalidRect.top /= 2;
 
  297      invalidRect.right /= 2;
 
  298      invalidRect.bottom /= 2;
 
  301    region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
 
  307static int freerdp_image_copy_from_retina(BYTE* pDstData, DWORD DstFormat, 
int nDstStep, 
int nXDst,
 
  308                                          int nYDst, 
int nWidth, 
int nHeight, BYTE* pSrcData,
 
  309                                          int nSrcStep, 
int nXSrc, 
int nYSrc)
 
  316  int srcBytesPerPixel;
 
  318  int dstBytesPerPixel;
 
  319  srcBitsPerPixel = 24;
 
  320  srcBytesPerPixel = 8;
 
  323    nSrcStep = srcBytesPerPixel * nWidth;
 
  325  dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
 
  326  dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
 
  329    nDstStep = dstBytesPerPixel * nWidth;
 
  331  nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel));
 
  332  nDstPad = (nDstStep - (nWidth * dstBytesPerPixel));
 
  333  pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
 
  334  pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)];
 
  336  for (
int y = 0; y < nHeight; y++)
 
  338    for (
int x = 0; x < nWidth; x++)
 
  343      B = pSrcPixel[0] + pSrcPixel[4] + pSrcPixel[nSrcStep + 0] + pSrcPixel[nSrcStep + 4];
 
  344      G = pSrcPixel[1] + pSrcPixel[5] + pSrcPixel[nSrcStep + 1] + pSrcPixel[nSrcStep + 5];
 
  345      R = pSrcPixel[2] + pSrcPixel[6] + pSrcPixel[nSrcStep + 2] + pSrcPixel[nSrcStep + 6];
 
  347      color = FreeRDPGetColor(DstFormat, R >> 2, G >> 2, B >> 2, 0xFF);
 
  348      FreeRDPWriteColor(pDstPixel, DstFormat, color);
 
  349      pDstPixel += dstBytesPerPixel;
 
  352    pSrcPixel = &pSrcPixel[nSrcPad + nSrcStep];
 
  353    pDstPixel = &pDstPixel[nDstPad];
 
  359static void (^mac_capture_stream_handler)(
 
  360    CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef,
 
  361    CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status, uint64_t displayTime,
 
  362                                  IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) {
 
  372  macShadowSubsystem* subsystem = g_Subsystem;
 
  373  rdpShadowServer* server = subsystem->common.server;
 
  374  rdpShadowSurface* surface = server->surface;
 
  375  count = ArrayList_Count(server->clients);
 
  380  EnterCriticalSection(&(surface->lock));
 
  381  mac_shadow_capture_get_dirty_region(subsystem);
 
  382  surfaceRect.left = 0;
 
  384  surfaceRect.right = surface->width;
 
  385  surfaceRect.bottom = surface->height;
 
  386  region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
 
  387  empty = region16_is_empty(&(surface->invalidRegion));
 
  388  LeaveCriticalSection(&(surface->lock));
 
  392    extents = region16_extents(&(surface->invalidRegion));
 
  395    width = extents->right - extents->left;
 
  396    height = extents->bottom - extents->top;
 
  397    IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
 
  398    pSrcData = (BYTE*)IOSurfaceGetBaseAddress(frameSurface);
 
  399    nSrcStep = (int)IOSurfaceGetBytesPerRow(frameSurface);
 
  401    if (subsystem->retina)
 
  403      freerdp_image_copy_from_retina(surface->data, surface->format, surface->scanline, x, y,
 
  404                                   width, height, pSrcData, nSrcStep, x, y);
 
  408      freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline, x, y,
 
  409                                  width, height, pSrcData, PIXEL_FORMAT_BGRX32, nSrcStep, x,
 
  410                                  y, NULL, FREERDP_FLIP_NONE);
 
  412    LeaveCriticalSection(&(surface->lock));
 
  414    IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
 
  415    ArrayList_Lock(server->clients);
 
  416    count = ArrayList_Count(server->clients);
 
  417    shadow_subsystem_frame_update(&subsystem->common);
 
  421      rdpShadowClient* client;
 
  422      client = (rdpShadowClient*)ArrayList_GetItem(server->clients, 0);
 
  426        subsystem->common.captureFrameRate = shadow_encoder_preferred_fps(client->encoder);
 
  430    ArrayList_Unlock(server->clients);
 
  431    EnterCriticalSection(&(surface->lock));
 
  432    region16_clear(&(surface->invalidRegion));
 
  433    LeaveCriticalSection(&(surface->lock));
 
  436  if (status != kCGDisplayStreamFrameStatusFrameComplete)
 
  440      case kCGDisplayStreamFrameStatusFrameIdle:
 
  443      case kCGDisplayStreamFrameStatusStopped:
 
  446      case kCGDisplayStreamFrameStatusFrameBlank:
 
  453  else if (!subsystem->lastUpdate)
 
  456    subsystem->lastUpdate = updateRef;
 
  460    CGDisplayStreamUpdateRef tmpRef = subsystem->lastUpdate;
 
  461    subsystem->lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
 
  466static int mac_shadow_capture_init(macShadowSubsystem* subsystem)
 
  470  CFDictionaryRef opts;
 
  471  CGDirectDisplayID displayId;
 
  472  displayId = CGMainDisplayID();
 
  473  subsystem->captureQueue = dispatch_queue_create(
"mac.shadow.capture", NULL);
 
  474  keys[0] = (
void*)kCGDisplayStreamShowCursor;
 
  475  values[0] = (
void*)kCFBooleanFalse;
 
  476  opts = CFDictionaryCreate(kCFAllocatorDefault, (
const void**)keys, (
const void**)values, 1,
 
  478  subsystem->stream = CGDisplayStreamCreateWithDispatchQueue(
 
  479      displayId, subsystem->pixelWidth, subsystem->pixelHeight, 
'BGRA', opts,
 
  480      subsystem->captureQueue, mac_capture_stream_handler);
 
  485static int mac_shadow_screen_grab(macShadowSubsystem* subsystem)
 
  490static int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message)
 
  492  rdpShadowServer* server = subsystem->common.server;
 
  493  rdpShadowSurface* surface = server->surface;
 
  497    case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
 
  498      EnterCriticalSection(&(surface->lock));
 
  499      shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem);
 
  500      LeaveCriticalSection(&(surface->lock));
 
  504      WLog_ERR(TAG, 
"Unknown message id: %" PRIu32 
"", message->id);
 
  509    message->Free(message);
 
  514static DWORD WINAPI mac_shadow_subsystem_thread(LPVOID arg)
 
  516  macShadowSubsystem* subsystem = (macShadowSubsystem*)arg;
 
  526  MsgPipe = subsystem->common.MsgPipe;
 
  528  events[nCount++] = MessageQueue_Event(MsgPipe->In);
 
  529  subsystem->common.captureFrameRate = 16;
 
  530  dwInterval = 1000 / subsystem->common.captureFrameRate;
 
  531  frameTime = GetTickCount64() + dwInterval;
 
  535    cTime = GetTickCount64();
 
  536    dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime;
 
  537    status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
 
  539    if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0)
 
  541      if (MessageQueue_Peek(MsgPipe->In, &message, TRUE))
 
  543        if (message.id == WMQ_QUIT)
 
  546        mac_shadow_subsystem_process_message(subsystem, &message);
 
  550    if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
 
  552      mac_shadow_screen_grab(subsystem);
 
  553      dwInterval = 1000 / subsystem->common.captureFrameRate;
 
  554      frameTime += dwInterval;
 
  562static UINT32 mac_shadow_enum_monitors(
MONITOR_DEF* monitors, UINT32 maxMonitors)
 
  566  UINT32 numMonitors = 0;
 
  568  CGDirectDisplayID displayId;
 
  569  displayId = CGMainDisplayID();
 
  570  CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
 
  571  wide = CGDisplayPixelsWide(displayId);
 
  572  high = CGDisplayPixelsHigh(displayId);
 
  573  CGDisplayModeRelease(mode);
 
  576  monitor = &monitors[index];
 
  579  monitor->right = (int)wide;
 
  580  monitor->bottom = (int)high;
 
  585static int mac_shadow_subsystem_init(rdpShadowSubsystem* rdpsubsystem)
 
  587  macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem;
 
  588  g_Subsystem = subsystem;
 
  590  mac_shadow_detect_monitors(subsystem);
 
  591  mac_shadow_capture_init(subsystem);
 
  595static int mac_shadow_subsystem_uninit(rdpShadowSubsystem* rdpsubsystem)
 
  597  macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem;
 
  601  if (subsystem->lastUpdate)
 
  603    CFRelease(subsystem->lastUpdate);
 
  604    subsystem->lastUpdate = NULL;
 
  610static int mac_shadow_subsystem_start(rdpShadowSubsystem* rdpsubsystem)
 
  612  macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem;
 
  618  mac_shadow_capture_start(subsystem);
 
  620  if (!(thread = CreateThread(NULL, 0, mac_shadow_subsystem_thread, (
void*)subsystem, 0, NULL)))
 
  622    WLog_ERR(TAG, 
"Failed to create thread");
 
  629static int mac_shadow_subsystem_stop(rdpShadowSubsystem* subsystem)
 
  637static void mac_shadow_subsystem_free(rdpShadowSubsystem* subsystem)
 
  642  mac_shadow_subsystem_uninit(subsystem);
 
  646static rdpShadowSubsystem* mac_shadow_subsystem_new(
void)
 
  648  macShadowSubsystem* subsystem = calloc(1, 
sizeof(macShadowSubsystem));
 
  653  subsystem->common.SynchronizeEvent = mac_shadow_input_synchronize_event;
 
  654  subsystem->common.KeyboardEvent = mac_shadow_input_keyboard_event;
 
  655  subsystem->common.UnicodeKeyboardEvent = mac_shadow_input_unicode_keyboard_event;
 
  656  subsystem->common.MouseEvent = mac_shadow_input_mouse_event;
 
  657  subsystem->common.ExtendedMouseEvent = mac_shadow_input_extended_mouse_event;
 
  658  return &subsystem->common;
 
  661FREERDP_API 
const char* ShadowSubsystemName(
void)
 
  666FREERDP_API 
int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
 
  668  char name[] = 
"mac shadow subsystem";
 
  669  char* arg[] = { name };
 
  671  freerdp_server_warn_unmaintained(ARRAYSIZE(arg), arg);
 
  672  pEntryPoints->New = mac_shadow_subsystem_new;
 
  673  pEntryPoints->Free = mac_shadow_subsystem_free;
 
  674  pEntryPoints->Init = mac_shadow_subsystem_init;
 
  675  pEntryPoints->Uninit = mac_shadow_subsystem_uninit;
 
  676  pEntryPoints->Start = mac_shadow_subsystem_start;
 
  677  pEntryPoints->Stop = mac_shadow_subsystem_stop;
 
  678  pEntryPoints->EnumMonitors = mac_shadow_enum_monitors;