From a9bcc81f821d7c66f623779fa5147e728eb3c388 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 03:24:41 +0200 Subject: Adding upstream version 3.3.0+dfsg1. Signed-off-by: Daniel Baumann --- server/shadow/Mac/CMakeLists.txt | 31 ++ server/shadow/Mac/mac_shadow.c | 680 +++++++++++++++++++++++++++++++++++++++ server/shadow/Mac/mac_shadow.h | 64 ++++ 3 files changed, 775 insertions(+) create mode 100644 server/shadow/Mac/CMakeLists.txt create mode 100644 server/shadow/Mac/mac_shadow.c create mode 100644 server/shadow/Mac/mac_shadow.h (limited to 'server/shadow/Mac') diff --git a/server/shadow/Mac/CMakeLists.txt b/server/shadow/Mac/CMakeLists.txt new file mode 100644 index 0000000..20c9a7b --- /dev/null +++ b/server/shadow/Mac/CMakeLists.txt @@ -0,0 +1,31 @@ + +include (WarnUnmaintained) +warn_unmaintained("mac shadow server subsystem") + +find_library(IOKIT IOKit REQUIRED) +find_library(IOSURFACE IOSurface REQUIRED) +find_library(CARBON Carbon REQUIRED) +find_package(PAM) + +set(LIBS + ${IOKIT} + ${IOSURFACE} + ${CARBON} +) + +if(PAM_FOUND) + add_definitions(-DWITH_PAM) + include_directories(${PAM_INCLUDE_DIR}) + list(APPEND LIBS ${PAM_LIBRARY}) +else() + message("building without PAM authentication support") +endif() + +add_definitions(-DWITH_SHADOW_MAC) +add_library(freerdp-shadow-subsystem-impl STATIC + mac_shadow.h + mac_shadow.c +) +target_link_libraries(freerdp-shadow-subsystem-impl PRIVATE + ${LIBS} +) diff --git a/server/shadow/Mac/mac_shadow.c b/server/shadow/Mac/mac_shadow.c new file mode 100644 index 0000000..ba6d2b0 --- /dev/null +++ b/server/shadow/Mac/mac_shadow.c @@ -0,0 +1,680 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2011-2014 Marc-Andre Moreau + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include "mac_shadow.h" + +#define TAG SERVER_TAG("shadow.mac") + +static macShadowSubsystem* g_Subsystem = NULL; + +static BOOL mac_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem, + rdpShadowClient* client, UINT32 flags) +{ + if (!subsystem || !client) + return FALSE; + + return TRUE; +} + +static BOOL mac_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client, + UINT16 flags, UINT8 code) +{ + DWORD vkcode; + DWORD keycode; + BOOL extended; + CGEventRef kbdEvent; + CGEventSourceRef source; + extended = (flags & KBD_FLAGS_EXTENDED) ? TRUE : FALSE; + + if (!subsystem || !client) + return FALSE; + + if (extended) + code |= KBDEXT; + + vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4); + + if (extended) + vkcode |= KBDEXT; + + keycode = GetKeycodeFromVirtualKeyCode(vkcode, WINPR_KEYCODE_TYPE_APPLE); + + source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + + 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); + return TRUE; +} + +static BOOL mac_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem, + rdpShadowClient* client, UINT16 flags, + UINT16 code) +{ + if (!subsystem || !client) + return FALSE; + + return TRUE; +} + +static BOOL mac_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client, + UINT16 flags, UINT16 x, UINT16 y) +{ + macShadowSubsystem* mac = (macShadowSubsystem*)subsystem; + UINT32 scrollX = 0; + UINT32 scrollY = 0; + CGWheelCount wheelCount = 2; + + if (!subsystem || !client) + return FALSE; + + if (flags & PTR_FLAGS_WHEEL) + { + scrollY = flags & WheelRotationMask; + + if (flags & PTR_FLAGS_WHEEL_NEGATIVE) + { + scrollY = -(flags & WheelRotationMask) / 392; + } + else + { + scrollY = (flags & WheelRotationMask) / 120; + } + + CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + CGEventRef scroll = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitLine, + wheelCount, scrollY, scrollX); + CGEventPost(kCGHIDEventTap, scroll); + CFRelease(scroll); + CFRelease(source); + } + else + { + CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + CGEventType mouseType = kCGEventNull; + CGMouseButton mouseButton = kCGMouseButtonLeft; + + if (flags & PTR_FLAGS_MOVE) + { + if (mac->mouseDownLeft) + mouseType = kCGEventLeftMouseDragged; + else if (mac->mouseDownRight) + mouseType = kCGEventRightMouseDragged; + else if (mac->mouseDownOther) + mouseType = kCGEventOtherMouseDragged; + else + mouseType = kCGEventMouseMoved; + + CGEventRef move = + CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton); + CGEventPost(kCGHIDEventTap, move); + CFRelease(move); + } + + if (flags & PTR_FLAGS_BUTTON1) + { + mouseButton = kCGMouseButtonLeft; + + if (flags & PTR_FLAGS_DOWN) + { + mouseType = kCGEventLeftMouseDown; + mac->mouseDownLeft = TRUE; + } + else + { + mouseType = kCGEventLeftMouseUp; + mac->mouseDownLeft = FALSE; + } + } + else if (flags & PTR_FLAGS_BUTTON2) + { + mouseButton = kCGMouseButtonRight; + + if (flags & PTR_FLAGS_DOWN) + { + mouseType = kCGEventRightMouseDown; + mac->mouseDownRight = TRUE; + } + else + { + mouseType = kCGEventRightMouseUp; + mac->mouseDownRight = FALSE; + } + } + else if (flags & PTR_FLAGS_BUTTON3) + { + mouseButton = kCGMouseButtonCenter; + + if (flags & PTR_FLAGS_DOWN) + { + mouseType = kCGEventOtherMouseDown; + mac->mouseDownOther = TRUE; + } + else + { + mouseType = kCGEventOtherMouseUp; + mac->mouseDownOther = FALSE; + } + } + + CGEventRef mouseEvent = + CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton); + CGEventPost(kCGHIDEventTap, mouseEvent); + CFRelease(mouseEvent); + CFRelease(source); + } + + return TRUE; +} + +static BOOL mac_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem, + rdpShadowClient* client, UINT16 flags, UINT16 x, + UINT16 y) +{ + if (!subsystem || !client) + return FALSE; + + return TRUE; +} + +static int mac_shadow_detect_monitors(macShadowSubsystem* subsystem) +{ + size_t wide, high; + MONITOR_DEF* monitor; + CGDirectDisplayID displayId; + displayId = CGMainDisplayID(); + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); + subsystem->pixelWidth = CGDisplayModeGetPixelWidth(mode); + subsystem->pixelHeight = CGDisplayModeGetPixelHeight(mode); + wide = CGDisplayPixelsWide(displayId); + high = CGDisplayPixelsHigh(displayId); + CGDisplayModeRelease(mode); + subsystem->retina = ((subsystem->pixelWidth / wide) == 2) ? TRUE : FALSE; + + if (subsystem->retina) + { + subsystem->width = wide; + subsystem->height = high; + } + else + { + subsystem->width = subsystem->pixelWidth; + subsystem->height = subsystem->pixelHeight; + } + + subsystem->common.numMonitors = 1; + monitor = &(subsystem->common.monitors[0]); + monitor->left = 0; + monitor->top = 0; + monitor->right = subsystem->width; + monitor->bottom = subsystem->height; + monitor->flags = 1; + return 1; +} + +static int mac_shadow_capture_start(macShadowSubsystem* subsystem) +{ + CGError err; + err = CGDisplayStreamStart(subsystem->stream); + + if (err != kCGErrorSuccess) + return -1; + + return 1; +} + +static int mac_shadow_capture_stop(macShadowSubsystem* subsystem) +{ + CGError err; + err = CGDisplayStreamStop(subsystem->stream); + + if (err != kCGErrorSuccess) + return -1; + + return 1; +} + +static int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem) +{ + size_t numRects; + const CGRect* rects; + RECTANGLE_16 invalidRect; + rdpShadowSurface* surface = subsystem->common.server->surface; + rects = CGDisplayStreamUpdateGetRects(subsystem->lastUpdate, kCGDisplayStreamUpdateDirtyRects, + &numRects); + + if (!numRects) + return -1; + + for (size_t index = 0; index < numRects; index++) + { + invalidRect.left = (UINT16)rects[index].origin.x; + invalidRect.top = (UINT16)rects[index].origin.y; + invalidRect.right = invalidRect.left + (UINT16)rects[index].size.width; + invalidRect.bottom = invalidRect.top + (UINT16)rects[index].size.height; + + if (subsystem->retina) + { + /* scale invalid rect */ + invalidRect.left /= 2; + invalidRect.top /= 2; + invalidRect.right /= 2; + invalidRect.bottom /= 2; + } + + region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); + } + + return 0; +} + +static int freerdp_image_copy_from_retina(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst, + int nYDst, int nWidth, int nHeight, BYTE* pSrcData, + int nSrcStep, int nXSrc, int nYSrc) +{ + BYTE* pSrcPixel; + BYTE* pDstPixel; + int nSrcPad; + int nDstPad; + int srcBitsPerPixel; + int srcBytesPerPixel; + int dstBitsPerPixel; + int dstBytesPerPixel; + srcBitsPerPixel = 24; + srcBytesPerPixel = 8; + + if (nSrcStep < 0) + nSrcStep = srcBytesPerPixel * nWidth; + + dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat); + dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat); + + if (nDstStep < 0) + nDstStep = dstBytesPerPixel * nWidth; + + nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel)); + nDstPad = (nDstStep - (nWidth * dstBytesPerPixel)); + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (int y = 0; y < nHeight; y++) + { + for (int x = 0; x < nWidth; x++) + { + UINT32 R, G, B; + UINT32 color; + /* simple box filter scaling, could be improved with better algorithm */ + B = pSrcPixel[0] + pSrcPixel[4] + pSrcPixel[nSrcStep + 0] + pSrcPixel[nSrcStep + 4]; + G = pSrcPixel[1] + pSrcPixel[5] + pSrcPixel[nSrcStep + 1] + pSrcPixel[nSrcStep + 5]; + R = pSrcPixel[2] + pSrcPixel[6] + pSrcPixel[nSrcStep + 2] + pSrcPixel[nSrcStep + 6]; + pSrcPixel += 8; + color = FreeRDPGetColor(DstFormat, R >> 2, G >> 2, B >> 2, 0xFF); + FreeRDPWriteColor(pDstPixel, DstFormat, color); + pDstPixel += dstBytesPerPixel; + } + + pSrcPixel = &pSrcPixel[nSrcPad + nSrcStep]; + pDstPixel = &pDstPixel[nDstPad]; + } + + return 1; +} + +static void (^mac_capture_stream_handler)( + CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, + CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, + IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) { + int x, y; + int count; + int width; + int height; + int nSrcStep; + BOOL empty; + BYTE* pSrcData; + RECTANGLE_16 surfaceRect; + const RECTANGLE_16* extents; + macShadowSubsystem* subsystem = g_Subsystem; + rdpShadowServer* server = subsystem->common.server; + rdpShadowSurface* surface = server->surface; + count = ArrayList_Count(server->clients); + + if (count < 1) + return; + + EnterCriticalSection(&(surface->lock)); + mac_shadow_capture_get_dirty_region(subsystem); + surfaceRect.left = 0; + surfaceRect.top = 0; + surfaceRect.right = surface->width; + surfaceRect.bottom = surface->height; + region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); + empty = region16_is_empty(&(surface->invalidRegion)); + LeaveCriticalSection(&(surface->lock)); + + if (!empty) + { + extents = region16_extents(&(surface->invalidRegion)); + x = extents->left; + y = extents->top; + width = extents->right - extents->left; + height = extents->bottom - extents->top; + IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL); + pSrcData = (BYTE*)IOSurfaceGetBaseAddress(frameSurface); + nSrcStep = (int)IOSurfaceGetBytesPerRow(frameSurface); + + if (subsystem->retina) + { + freerdp_image_copy_from_retina(surface->data, surface->format, surface->scanline, x, y, + width, height, pSrcData, nSrcStep, x, y); + } + else + { + freerdp_image_copy(surface->data, surface->format, surface->scanline, x, y, width, height, + pSrcData, PIXEL_FORMAT_BGRX32, nSrcStep, x, y, NULL, + FREERDP_FLIP_NONE); + } + LeaveCriticalSection(&(surface->lock)); + + IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL); + ArrayList_Lock(server->clients); + count = ArrayList_Count(server->clients); + shadow_subsystem_frame_update(&subsystem->common); + + if (count == 1) + { + rdpShadowClient* client; + client = (rdpShadowClient*)ArrayList_GetItem(server->clients, 0); + + if (client) + { + subsystem->common.captureFrameRate = shadow_encoder_preferred_fps(client->encoder); + } + } + + ArrayList_Unlock(server->clients); + EnterCriticalSection(&(surface->lock)); + region16_clear(&(surface->invalidRegion)); + LeaveCriticalSection(&(surface->lock)); + } + + if (status != kCGDisplayStreamFrameStatusFrameComplete) + { + switch (status) + { + case kCGDisplayStreamFrameStatusFrameIdle: + break; + + case kCGDisplayStreamFrameStatusStopped: + break; + + case kCGDisplayStreamFrameStatusFrameBlank: + break; + + default: + break; + } + } + else if (!subsystem->lastUpdate) + { + CFRetain(updateRef); + subsystem->lastUpdate = updateRef; + } + else + { + CGDisplayStreamUpdateRef tmpRef = subsystem->lastUpdate; + subsystem->lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef); + CFRelease(tmpRef); + } +}; + +static int mac_shadow_capture_init(macShadowSubsystem* subsystem) +{ + void* keys[2]; + void* values[2]; + CFDictionaryRef opts; + CGDirectDisplayID displayId; + displayId = CGMainDisplayID(); + subsystem->captureQueue = dispatch_queue_create("mac.shadow.capture", NULL); + keys[0] = (void*)kCGDisplayStreamShowCursor; + values[0] = (void*)kCFBooleanFalse; + opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1, + NULL, NULL); + subsystem->stream = CGDisplayStreamCreateWithDispatchQueue( + displayId, subsystem->pixelWidth, subsystem->pixelHeight, 'BGRA', opts, + subsystem->captureQueue, mac_capture_stream_handler); + CFRelease(opts); + return 1; +} + +static int mac_shadow_screen_grab(macShadowSubsystem* subsystem) +{ + return 1; +} + +static int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message) +{ + rdpShadowServer* server = subsystem->common.server; + rdpShadowSurface* surface = server->surface; + + switch (message->id) + { + case SHADOW_MSG_IN_REFRESH_REQUEST_ID: + EnterCriticalSection(&(surface->lock)); + shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem); + LeaveCriticalSection(&(surface->lock)); + break; + + default: + WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id); + break; + } + + if (message->Free) + message->Free(message); + + return 1; +} + +static DWORD WINAPI mac_shadow_subsystem_thread(LPVOID arg) +{ + macShadowSubsystem* subsystem = (macShadowSubsystem*)arg; + DWORD status; + DWORD nCount; + UINT64 cTime; + DWORD dwTimeout; + DWORD dwInterval; + UINT64 frameTime; + HANDLE events[32]; + wMessage message; + wMessagePipe* MsgPipe; + MsgPipe = subsystem->common.MsgPipe; + nCount = 0; + events[nCount++] = MessageQueue_Event(MsgPipe->In); + subsystem->common.captureFrameRate = 16; + dwInterval = 1000 / subsystem->common.captureFrameRate; + frameTime = GetTickCount64() + dwInterval; + + while (1) + { + cTime = GetTickCount64(); + dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime; + status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout); + + if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0) + { + 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 / subsystem->common.captureFrameRate; + frameTime += dwInterval; + } + } + + ExitThread(0); + return 0; +} + +static UINT32 mac_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors) +{ + int index; + size_t wide, high; + UINT32 numMonitors = 0; + MONITOR_DEF* monitor; + CGDirectDisplayID displayId; + displayId = CGMainDisplayID(); + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); + wide = CGDisplayPixelsWide(displayId); + high = CGDisplayPixelsHigh(displayId); + CGDisplayModeRelease(mode); + index = 0; + numMonitors = 1; + monitor = &monitors[index]; + monitor->left = 0; + monitor->top = 0; + monitor->right = (int)wide; + monitor->bottom = (int)high; + monitor->flags = 1; + return numMonitors; +} + +static int mac_shadow_subsystem_init(rdpShadowSubsystem* rdpsubsystem) +{ + macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem; + g_Subsystem = subsystem; + + mac_shadow_detect_monitors(subsystem); + mac_shadow_capture_init(subsystem); + return 1; +} + +static int mac_shadow_subsystem_uninit(rdpShadowSubsystem* rdpsubsystem) +{ + macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem; + if (!subsystem) + return -1; + + if (subsystem->lastUpdate) + { + CFRelease(subsystem->lastUpdate); + subsystem->lastUpdate = NULL; + } + + return 1; +} + +static int mac_shadow_subsystem_start(rdpShadowSubsystem* rdpsubsystem) +{ + macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem; + HANDLE thread; + + if (!subsystem) + return -1; + + mac_shadow_capture_start(subsystem); + + if (!(thread = CreateThread(NULL, 0, mac_shadow_subsystem_thread, (void*)subsystem, 0, NULL))) + { + WLog_ERR(TAG, "Failed to create thread"); + return -1; + } + + return 1; +} + +static int mac_shadow_subsystem_stop(rdpShadowSubsystem* subsystem) +{ + if (!subsystem) + return -1; + + return 1; +} + +static void mac_shadow_subsystem_free(rdpShadowSubsystem* subsystem) +{ + if (!subsystem) + return; + + mac_shadow_subsystem_uninit(subsystem); + free(subsystem); +} + +static rdpShadowSubsystem* mac_shadow_subsystem_new(void) +{ + macShadowSubsystem* subsystem = calloc(1, sizeof(macShadowSubsystem)); + + if (!subsystem) + return NULL; + + subsystem->common.SynchronizeEvent = mac_shadow_input_synchronize_event; + subsystem->common.KeyboardEvent = mac_shadow_input_keyboard_event; + subsystem->common.UnicodeKeyboardEvent = mac_shadow_input_unicode_keyboard_event; + subsystem->common.MouseEvent = mac_shadow_input_mouse_event; + subsystem->common.ExtendedMouseEvent = mac_shadow_input_extended_mouse_event; + return &subsystem->common; +} + +FREERDP_API const char* ShadowSubsystemName(void) +{ + return "Mac"; +} + +FREERDP_API int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) +{ + char name[] = "mac shadow subsystem"; + char* arg[] = { name }; + + freerdp_server_warn_unmaintained(ARRAYSIZE(arg), arg); + pEntryPoints->New = mac_shadow_subsystem_new; + pEntryPoints->Free = mac_shadow_subsystem_free; + pEntryPoints->Init = mac_shadow_subsystem_init; + pEntryPoints->Uninit = mac_shadow_subsystem_uninit; + pEntryPoints->Start = mac_shadow_subsystem_start; + pEntryPoints->Stop = mac_shadow_subsystem_stop; + pEntryPoints->EnumMonitors = mac_shadow_enum_monitors; + return 1; +} diff --git a/server/shadow/Mac/mac_shadow.h b/server/shadow/Mac/mac_shadow.h new file mode 100644 index 0000000..2c31572 --- /dev/null +++ b/server/shadow/Mac/mac_shadow.h @@ -0,0 +1,64 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2011-2014 Marc-Andre Moreau + * + * 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. + */ + +#ifndef FREERDP_SERVER_SHADOW_MAC_SHADOW_H +#define FREERDP_SERVER_SHADOW_MAC_SHADOW_H + +#include + +typedef struct mac_shadow_subsystem macShadowSubsystem; + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct mac_shadow_subsystem +{ + rdpShadowSubsystem common; + + int width; + int height; + BOOL retina; + int pixelWidth; + int pixelHeight; + BOOL mouseDownLeft; + BOOL mouseDownRight; + BOOL mouseDownOther; + CGDisplayStreamRef stream; + dispatch_queue_t captureQueue; + CGDisplayStreamUpdateRef lastUpdate; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SERVER_SHADOW_MAC_SHADOW_H */ -- cgit v1.2.3