11#include <winpr/assert.h>
12#import <winpr/clipboard.h>
14#import <freerdp/gdi/gdi.h>
15#import <freerdp/codec/color.h>
16#import <freerdp/channels/channels.h>
17#import <freerdp/client/channels.h>
18#import <freerdp/client/cmdline.h>
19#import <freerdp/freerdp.h>
20#import <freerdp/gdi/gfx.h>
21#import <freerdp/client/cliprdr.h>
23#import "ios_freerdp.h"
24#import "ios_freerdp_ui.h"
25#import "ios_freerdp_events.h"
26#import "ios_cliprdr.h"
34#define TAG FREERDP_TAG("iOS")
42#pragma mark Connection helpers
44static void ios_OnChannelConnectedEventHandler(
void *context,
const ChannelConnectedEventArgs *e)
46 WLog_INFO(TAG,
"ios_OnChannelConnectedEventHandler, channel %s", e->name);
47 rdpSettings *settings;
52 WLog_FATAL(TAG,
"(context=%p, EventArgs=%p", context, (
void *)e);
57 settings = afc->_p.settings;
59 if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
63 gdi_graphics_pipeline_init(afc->_p.gdi, (RdpgfxClientContext *)e->pInterface);
67 WLog_WARN(TAG,
"GFX without software GDI requested. "
68 " This is not supported, add /gdi:sw");
71 else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
73 ios_cliprdr_init(afc, (CliprdrClientContext *)e->pInterface);
77static void ios_OnChannelDisconnectedEventHandler(
void *context,
78 const ChannelDisconnectedEventArgs *e)
80 WLog_INFO(TAG,
"ios_OnChannelConnectedEventHandler, channel %s", e->name);
81 rdpSettings *settings;
86 WLog_FATAL(TAG,
"(context=%p, EventArgs=%p", context, (
void *)e);
91 settings = afc->_p.settings;
93 if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
97 gdi_graphics_pipeline_uninit(afc->_p.gdi, (RdpgfxClientContext *)e->pInterface);
101 WLog_WARN(TAG,
"GFX without software GDI requested. "
102 " This is not supported, add /gdi:sw");
105 else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
107 ios_cliprdr_uninit(afc, (CliprdrClientContext *)e->pInterface);
111static BOOL ios_pre_connect(freerdp *instance)
114 rdpSettings *settings;
116 if (!instance || !instance->context)
119 settings = instance->context->settings;
120 WINPR_ASSERT(settings);
124 Password && (Password && (strlen(Password) > 0))))
136 NSLog(
@"%s: invalid dimensions %d %d", __func__,
142 rc = PubSub_SubscribeChannelConnected(instance->context->pubSub,
143 ios_OnChannelConnectedEventHandler);
145 if (rc != CHANNEL_RC_OK)
147 WLog_ERR(TAG,
"Could not subscribe to connect event handler [0x%08X]", (
unsigned)rc);
151 rc = PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
152 ios_OnChannelDisconnectedEventHandler);
154 if (rc != CHANNEL_RC_OK)
156 WLog_ERR(TAG,
"Could not subscribe to disconnect event handler [0x%08X]", (
unsigned)rc);
160 if (!freerdp_client_load_addins(instance->context->channels, settings))
162 WLog_ERR(TAG,
"Failed to load addins [0x%08X]", (
unsigned)GetLastError());
169static BOOL ios_Pointer_New(rdpContext *context, rdpPointer *pointer)
171 if (!context || !pointer || !context->gdi)
175 iosPointer *ptr = (iosPointer *)pointer;
176 const size_t size = 4 * pointer->width * pointer->height;
177 BYTE *data = winpr_aligned_malloc(size, 16);
182 if (!freerdp_image_copy_from_pointer_data(
183 data, PIXEL_FORMAT_RGBA32, 0, 0, 0, pointer->width, pointer->height,
184 pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData,
185 pointer->lengthAndMask, pointer->xorBpp, &context->gdi->palette))
187 winpr_aligned_free(data);
191 ptr->cursor = [[
RDPCursor alloc] initWithRGBABytes:data
193 height:pointer->height
194 hotspot:CGPointMake(pointer->xPos, pointer->yPos)];
195 winpr_aligned_free(data);
202static void ios_Pointer_Free(rdpContext *context, rdpPointer *pointer)
204 if (!context || !pointer)
207 iosPointer *ptr = (iosPointer *)pointer;
208 [ptr->cursor release];
212static BOOL ios_Pointer_Set(rdpContext *context, rdpPointer *pointer)
214 if (!context || !context->instance || !pointer)
217 mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
218 iosPointer *ptr = (iosPointer *)pointer;
219 if (!mfi || !mfi->session || !ptr->cursor)
222 [mfi->session performSelectorOnMainThread:@selector(setRemoteCursor:)
223 withObject:ptr->cursor
229static BOOL ios_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y)
231 if (!context || !context->instance)
234 mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
235 if (!mfi || !mfi->session)
238 NSValue *position = [NSValue valueWithCGPoint:CGPointMake(x, y)];
239 [mfi->session performSelectorOnMainThread:@selector(setRemoteCursorPositionValue:)
246static BOOL ios_Pointer_SetNull(rdpContext *context)
248 if (!context || !context->instance)
251 mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
252 if (!mfi || !mfi->session)
255 [mfi->session performSelectorOnMainThread:@selector(hideRemoteCursor)
262static BOOL ios_Pointer_SetDefault(rdpContext *context)
264 if (!context || !context->instance)
267 mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
268 if (!mfi || !mfi->session)
271 [mfi->session performSelectorOnMainThread:@selector(setDefaultRemoteCursor)
278static BOOL ios_register_pointer(rdpGraphics *graphics)
280 rdpPointer pointer = WINPR_C_ARRAY_INIT;
285 pointer.size =
sizeof(iosPointer);
286 pointer.New = ios_Pointer_New;
287 pointer.Free = ios_Pointer_Free;
288 pointer.Set = ios_Pointer_Set;
289 pointer.SetNull = ios_Pointer_SetNull;
290 pointer.SetDefault = ios_Pointer_SetDefault;
291 pointer.SetPosition = ios_Pointer_SetPosition;
292 graphics_register_pointer(graphics, &pointer);
296static BOOL ios_post_connect(freerdp *instance)
303 mfi = MFI_FROM_INSTANCE(instance);
308 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
311 if (!ios_register_pointer(instance->context->graphics))
314 ios_allocate_display_buffer(mfi);
315 instance->context->update->BeginPaint = ios_ui_begin_paint;
316 instance->context->update->EndPaint = ios_ui_end_paint;
317 instance->context->update->DesktopResize = ios_ui_resize_window;
318 [mfi->session performSelectorOnMainThread:@selector(sessionDidConnect)
324static void ios_post_disconnect(freerdp *instance)
330#pragma mark Running the connection
332int ios_run_freerdp(freerdp *instance)
335 mfInfo *mfi = context->mfi;
336 rdpChannels *channels = instance->context->channels;
337 mfi->connection_state = TSXConnectionConnecting;
339 if (!freerdp_connect(instance))
341 NSLog(
@"%s: inst->rdp_connect failed", __func__);
342 return mfi->unwanted ? MF_EXIT_CONN_CANCELED : MF_EXIT_CONN_FAILED;
346 return MF_EXIT_CONN_CANCELED;
348 mfi->connection_state = TSXConnectionConnected;
350 NSAutoreleasePool *pool;
352 while (!freerdp_shall_disconnect_context(instance->context))
356 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
357 pool = [[NSAutoreleasePool alloc] init];
359 nCount = freerdp_get_event_handles(instance->context, handles, ARRAYSIZE(handles));
362 NSLog(
@"%s: freerdp_get_event_handles failed", __func__);
366 handles[nCount++] = ios_events_get_handle(mfi);
368 status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
370 if (WAIT_FAILED == status)
372 NSLog(
@"%s: WaitForMultipleObjects failed!", __func__);
377 if (!freerdp_check_event_handles(instance->context))
379 NSLog(
@"%s: freerdp_check_event_handles failed.", __func__);
384 if (ios_events_check_handle(mfi) != TRUE)
395 CGContextRelease(mfi->bitmap_context);
396 mfi->bitmap_context =
nullptr;
397 mfi->connection_state = TSXConnectionDisconnected;
399 freerdp_disconnect(instance);
403 return MF_EXIT_SUCCESS;
407#pragma mark Context callbacks
409static BOOL ios_client_new(freerdp *instance, rdpContext *context)
413 if (!instance || !context)
416 if ((ctx->mfi = calloc(1,
sizeof(mfInfo))) ==
nullptr)
419 ctx->mfi->context = (
mfContext *)context;
420 ctx->mfi->_context = context;
421 ctx->mfi->instance = instance;
423 if (!ios_events_create_pipe(ctx->mfi))
426 instance->PreConnect = ios_pre_connect;
427 instance->PostConnect = ios_post_connect;
428 instance->PostDisconnect = ios_post_disconnect;
429 instance->AuthenticateEx = ios_ui_authenticate_ex;
430 instance->VerifyCertificateEx = ios_ui_verify_certificate_ex;
431 instance->VerifyChangedCertificateEx = ios_ui_verify_changed_certificate_ex;
432 instance->LogonErrorInfo =
nullptr;
436static void ios_client_free(freerdp *instance, rdpContext *context)
444 ios_events_free_pipe(mfi);
448static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS *pEntryPoints)
450 WINPR_ASSERT(pEntryPoints);
452 ZeroMemory(pEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
453 pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
454 pEntryPoints->Size =
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
455 pEntryPoints->GlobalInit =
nullptr;
456 pEntryPoints->GlobalUninit =
nullptr;
457 pEntryPoints->ContextSize =
sizeof(
mfContext);
458 pEntryPoints->ClientNew = ios_client_new;
459 pEntryPoints->ClientFree = ios_client_free;
460 pEntryPoints->ClientStart =
nullptr;
461 pEntryPoints->ClientStop =
nullptr;
466#pragma mark Initialization and cleanup
468freerdp *ios_freerdp_new()
471 RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
472 RdpClientEntry(&clientEntryPoints);
473 context = freerdp_client_context_new(&clientEntryPoints);
478 return context->instance;
481void ios_freerdp_free(freerdp *instance)
483 if (!instance || !instance->context)
486 freerdp_client_context_free(instance->context);
489void ios_init_freerdp()
491 signal(SIGPIPE, SIG_IGN);
494void ios_uninit_freerdp()
499size_t fwrite$UNIX2003(
const void *ptr,
size_t size,
size_t nmemb, FILE *stream)
501 return fwrite(ptr, size, nmemb, stream);
504void ios_send_clipboard_data(
void *context,
const void *data, UINT32 size)
507 ClipboardLock(afc->clipboard);
508 UINT32 formatId = ClipboardRegisterFormat(afc->clipboard,
"UTF8_STRING");
511 if (!ClipboardSetData(afc->clipboard, formatId, data, size))
513 ClipboardUnlock(afc->clipboard);
514 WLog_ERR(TAG,
"ClipboardSetData failed");
519 ClipboardEmpty(afc->clipboard);
520 ClipboardUnlock(afc->clipboard);
521 ios_cliprdr_send_client_format_list(afc->cliprdr);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.