diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index 863ec827a..8f0aca4dc 100644 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -32,6 +32,7 @@ set(${MODULE_PREFIX}_OBJECTIVE_SOURCES MRDPCursor.m MRDPView.m Keyboard.m + Clipboard.m PasswordDialog.m) list(APPEND ${MODULE_PREFIX}_SOURCES ${${MODULE_PREFIX}_OBJECTIVE_SOURCES}) @@ -42,6 +43,7 @@ set(${MODULE_PREFIX}_HEADERS MRDPCursor.h MRDPView.h Keyboard.h + Clipboard.h PasswordDialog.h) set(${MODULE_PREFIX}_RESOURCES "en.lproj/InfoPlist.strings") diff --git a/client/Mac/Clipboard.h b/client/Mac/Clipboard.h new file mode 100644 index 000000000..2445ab8e9 --- /dev/null +++ b/client/Mac/Clipboard.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 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. + */ + +#import "mfreerdp.h" +#import "mf_client.h" + +#import "freerdp/freerdp.h" +#import "freerdp/channels/channels.h" +#import "freerdp/client/cliprdr.h" + +int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr); + +void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr); +void mac_cliprdr_uninit(mfContext* mfc, CliprdrClientContext* cliprdr); diff --git a/client/Mac/Clipboard.m b/client/Mac/Clipboard.m new file mode 100644 index 000000000..d0e9575b0 --- /dev/null +++ b/client/Mac/Clipboard.m @@ -0,0 +1,328 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 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. + */ + +#import "Clipboard.h" + +int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) +{ + UINT32 index; + UINT32 formatId; + UINT32 numFormats; + UINT32* pFormatIds; + const char* formatName; + CLIPRDR_FORMAT* formats; + CLIPRDR_FORMAT_LIST formatList; + mfContext* mfc = (mfContext*) cliprdr->custom; + + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); + + pFormatIds = NULL; + numFormats = ClipboardGetFormatIds(mfc->clipboard, &pFormatIds); + + formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)); + + if (!formats) + return -1; + + for (index = 0; index < numFormats; index++) + { + formatId = pFormatIds[index]; + formatName = ClipboardGetFormatName(mfc->clipboard, formatId); + + formats[index].formatId = formatId; + formats[index].formatName = NULL; + + if ((formatId > CF_MAX) && formatName) + formats[index].formatName = _strdup(formatName); + } + + formatList.msgFlags = CB_RESPONSE_OK; + formatList.numFormats = numFormats; + formatList.formats = formats; + + mfc->cliprdr->ClientFormatList(mfc->cliprdr, &formatList); + + free(pFormatIds); + free(formats); + + return 1; +} + +int mac_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr, UINT32 formatId) +{ + CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; + mfContext* mfc = (mfContext*) cliprdr->custom; + + ZeroMemory(&formatDataRequest, sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); + + formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; + formatDataRequest.msgFlags = 0; + + formatDataRequest.requestedFormatId = formatId; + mfc->requestedFormatId = formatId; + ResetEvent(mfc->clipboardRequestEvent); + + cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest); + + return 1; +} + +int mac_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr) +{ + CLIPRDR_CAPABILITIES capabilities; + CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; + + capabilities.cCapabilitiesSets = 1; + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); + + generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; + generalCapabilitySet.capabilitySetLength = 12; + + generalCapabilitySet.version = CB_CAPS_VERSION_2; + generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES; + + cliprdr->ClientCapabilities(cliprdr, &capabilities); + + return 1; +} + +int mac_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, CLIPRDR_MONITOR_READY* monitorReady) +{ + mfContext* mfc = (mfContext*) cliprdr->custom; + + mfc->clipboardSync = TRUE; + mac_cliprdr_send_client_capabilities(cliprdr); + mac_cliprdr_send_client_format_list(cliprdr); + + return 1; +} + +int mac_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, CLIPRDR_CAPABILITIES* capabilities) +{ + UINT32 index; + CLIPRDR_CAPABILITY_SET* capabilitySet; + mfContext* mfc = (mfContext*) cliprdr->custom; + + for (index = 0; index < capabilities->cCapabilitiesSets; index++) + { + capabilitySet = &(capabilities->capabilitySets[index]); + + if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) && + (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN)) + { + CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet + = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet; + + mfc->clipboardCapabilities = generalCapabilitySet->generalFlags; + break; + } + } + + return 1; +} + +int mac_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST* formatList) +{ + UINT32 index; + CLIPRDR_FORMAT* format; + mfContext* mfc = (mfContext*) cliprdr->custom; + + if (mfc->serverFormats) + { + for (index = 0; index < mfc->numServerFormats; index++) + { + free(mfc->serverFormats[index].formatName); + } + + free(mfc->serverFormats); + mfc->serverFormats = NULL; + mfc->numServerFormats = 0; + } + + if (formatList->numFormats < 1) + return 1; + + mfc->numServerFormats = formatList->numFormats; + mfc->serverFormats = (CLIPRDR_FORMAT*) calloc(mfc->numServerFormats, sizeof(CLIPRDR_FORMAT)); + + if (!mfc->serverFormats) + return -1; + + for (index = 0; index < mfc->numServerFormats; index++) + { + mfc->serverFormats[index].formatId = formatList->formats[index].formatId; + mfc->serverFormats[index].formatName = NULL; + + if (formatList->formats[index].formatName) + mfc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName); + } + + for (index = 0; index < mfc->numServerFormats; index++) + { + format = &(mfc->serverFormats[index]); + + if (format->formatId == CF_UNICODETEXT) + { + mac_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT); + break; + } + else if (format->formatId == CF_TEXT) + { + mac_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT); + break; + } + } + + return 1; +} + +int mac_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +{ + return 1; +} + +int mac_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +{ + return 1; +} + +int mac_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + return 1; +} + +int mac_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +{ + BYTE* data; + UINT32 size; + UINT32 formatId; + CLIPRDR_FORMAT_DATA_RESPONSE response; + mfContext* mfc = (mfContext*) cliprdr->custom; + + ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); + + formatId = formatDataRequest->requestedFormatId; + data = (BYTE*) ClipboardGetData(mfc->clipboard, formatId, &size); + + response.msgFlags = CB_RESPONSE_OK; + response.dataLen = size; + response.requestedFormatData = data; + + if (!data) + { + response.msgFlags = CB_RESPONSE_FAIL; + response.dataLen = 0; + response.requestedFormatData = NULL; + } + + cliprdr->ClientFormatDataResponse(cliprdr, &response); + + free(data); + + return 1; +} + +int mac_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +{ + BYTE* data; + UINT32 size; + UINT32 index; + UINT32 formatId; + CLIPRDR_FORMAT* format = NULL; + mfContext* mfc = (mfContext*) cliprdr->custom; + MRDPView* view = (MRDPView*) mfc->view; + + for (index = 0; index < mfc->numServerFormats; index++) + { + if (mfc->requestedFormatId == mfc->serverFormats[index].formatId) + format = &(mfc->serverFormats[index]); + } + + if (!format) + { + SetEvent(mfc->clipboardRequestEvent); + return -1; + } + + if (format->formatName) + formatId = ClipboardRegisterFormat(mfc->clipboard, format->formatName); + else + formatId = format->formatId; + + size = formatDataResponse->dataLen; + data = (BYTE*) malloc(size); + CopyMemory(data, formatDataResponse->requestedFormatData, size); + + ClipboardSetData(mfc->clipboard, formatId, data, size); + + SetEvent(mfc->clipboardRequestEvent); + + if ((formatId == CF_TEXT) || (formatId == CF_UNICODETEXT)) + { + formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING"); + + data = (void*) ClipboardGetData(mfc->clipboard, formatId, &size); + NSString* str = [[NSString alloc] initWithBytes: (void*) data length:size encoding:NSUTF8StringEncoding]; + free(data); + + NSArray* types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; + [view->pasteboard_wr declareTypes:types owner:view]; + [view->pasteboard_wr setString:str forType:NSStringPboardType]; + } + + return 1; +} + +int mac_cliprdr_server_file_contents_request(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + return 1; +} + +int mac_cliprdr_server_file_contents_response(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) +{ + return 1; +} + +void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr) +{ + cliprdr->custom = (void*) mfc; + mfc->cliprdr = cliprdr; + + mfc->clipboard = ClipboardCreate(); + mfc->clipboardRequestEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + cliprdr->MonitorReady = mac_cliprdr_monitor_ready; + cliprdr->ServerCapabilities = mac_cliprdr_server_capabilities; + cliprdr->ServerFormatList = mac_cliprdr_server_format_list; + cliprdr->ServerFormatListResponse = mac_cliprdr_server_format_list_response; + cliprdr->ServerLockClipboardData = mac_cliprdr_server_lock_clipboard_data; + cliprdr->ServerUnlockClipboardData = mac_cliprdr_server_unlock_clipboard_data; + cliprdr->ServerFormatDataRequest = mac_cliprdr_server_format_data_request; + cliprdr->ServerFormatDataResponse = mac_cliprdr_server_format_data_response; + cliprdr->ServerFileContentsRequest = mac_cliprdr_server_file_contents_request; + cliprdr->ServerFileContentsResponse = mac_cliprdr_server_file_contents_response; +} + +void mac_cliprdr_uninit(mfContext* mfc, CliprdrClientContext* cliprdr) +{ + cliprdr->custom = NULL; + mfc->cliprdr = NULL; + + ClipboardDestroy(mfc->clipboard); + CloseHandle(mfc->clipboardRequestEvent); +} diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h index 70ef3130d..7231d0657 100644 --- a/client/Mac/MRDPView.h +++ b/client/Mac/MRDPView.h @@ -51,8 +51,8 @@ BOOL skipMoveWindowOnce; @public - NSPasteboard* pasteboard_rd; /* for reading from clipboard */ - NSPasteboard* pasteboard_wr; /* for writing to clipboard */ + NSPasteboard* pasteboard_rd; + NSPasteboard* pasteboard_wr; int pasteboard_changecount; int pasteboard_format; int is_connected; @@ -63,6 +63,8 @@ - (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height; - (void) onPasteboardTimerFired :(NSTimer *) timer; +- (void) pause; +- (void) resume; - (void) releaseResources; @property (assign) int is_connected; diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index ded7f9b9a..4d963253b 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -23,6 +23,7 @@ #import "mfreerdp.h" #import "MRDPView.h" #import "MRDPCursor.h" +#import "Clipboard.h" #import "PasswordDialog.h" #include @@ -39,8 +40,6 @@ #import "freerdp/gdi/dc.h" #import "freerdp/gdi/region.h" #import "freerdp/graphics.h" -#import "freerdp/utils/event.h" -#import "freerdp/client/cliprdr.h" #import "freerdp/client/file.h" #import "freerdp/client/cmdline.h" #import "freerdp/log.h" @@ -59,39 +58,9 @@ void mac_desktop_resize(rdpContext* context); static void update_activity_cb(freerdp* instance); static void input_activity_cb(freerdp* instance); -static void channel_activity_cb(freerdp* instance); - -int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data); -int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); - -void process_cliprdr_event(freerdp* instance, wMessage* event); -void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event); -void cliprdr_send_data_request(freerdp* instance, UINT32 format); -void cliprdr_process_cb_monitor_ready_event(freerdp* inst); -void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event); -void cliprdr_process_text(freerdp* instance, BYTE* data, int len); -void cliprdr_send_supported_format_list(freerdp* instance); -int register_channel_fds(int* fds, int count, freerdp* instance); DWORD mac_client_thread(void* param); -struct cursor -{ - rdpPointer* pointer; - BYTE* cursor_data; - void* bmiRep; /* NSBitmapImageRep */ - void* nsCursor; /* NSCursor */ - void* nsImage; /* NSImage */ -}; - -struct rgba_data -{ - char red; - char green; - char blue; - char alpha; -}; - @implementation MRDPView @synthesize is_connected; @@ -183,43 +152,6 @@ DWORD mac_client_input_thread(void* param) return 0; } -DWORD mac_client_channels_thread(void* param) -{ - int status; - wMessage* event; - HANDLE channelsEvent; - rdpChannels* channels; - rdpContext* context = (rdpContext*) param; - - channels = context->channels; - channelsEvent = freerdp_channels_get_event_handle(context->instance); - - while (WaitForSingleObject(channelsEvent, INFINITE) == WAIT_OBJECT_0) - { - status = freerdp_channels_process_pending_messages(context->instance); - - if (!status) - break; - - event = freerdp_channels_pop_event(context->channels); - - if (event) - { - switch (GetMessageClass(event->id)) - { - case CliprdrChannel_Class: - process_cliprdr_event(context->instance, event); - break; - } - - freerdp_event_free(event); - } - } - - ExitThread(0); - return 0; -} - DWORD mac_client_thread(void* param) { @autoreleasepool @@ -231,7 +163,6 @@ DWORD mac_client_thread(void* param) HANDLE updateEvent; HANDLE updateThread; HANDLE channelsEvent; - HANDLE channelsThread; DWORD nCount; rdpContext* context = (rdpContext*) param; @@ -272,14 +203,7 @@ DWORD mac_client_thread(void* param) events[nCount++] = inputEvent = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); } - if (settings->AsyncChannels) - { - channelsThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) mac_client_channels_thread, context, 0, NULL); - } - else - { - events[nCount++] = channelsEvent = freerdp_channels_get_event_handle(instance); - } + events[nCount++] = channelsEvent = freerdp_channels_get_event_handle(instance); while (1) { @@ -307,12 +231,9 @@ DWORD mac_client_thread(void* param) } } - if (!settings->AsyncChannels) + if (WaitForSingleObject(channelsEvent, 0) == WAIT_OBJECT_0) { - if (WaitForSingleObject(channelsEvent, 0) == WAIT_OBJECT_0) - { - channel_activity_cb(instance); - } + freerdp_channels_process_pending_messages(instance); } } @@ -332,12 +253,6 @@ DWORD mac_client_thread(void* param) CloseHandle(inputThread); } - if (settings->AsyncChannels) - { - WaitForSingleObject(channelsThread, INFINITE); - CloseHandle(channelsThread); - } - ExitThread(0); return 0; } @@ -798,21 +713,87 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) - (void) onPasteboardTimerFired :(NSTimer*) timer { - int i; - NSArray* types; + BYTE* data; + UINT32 size; + UINT32 formatId; + BOOL formatMatch; + int changeCount; + NSData* formatData; + const char* formatType; + NSPasteboardItem* item; - i = (int) [pasteboard_rd changeCount]; + changeCount = (int) [pasteboard_rd changeCount]; - if (i != pasteboard_changecount) + if (changeCount == pasteboard_changecount) + return; + + pasteboard_changecount = changeCount; + + NSArray* items = [pasteboard_rd pasteboardItems]; + + if ([items count] < 1) + return; + + item = [items objectAtIndex:0]; + + /** + * System-Declared Uniform Type Identifiers: + * https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html + */ + + formatMatch = FALSE; + + for (NSString* type in [item types]) { - pasteboard_changecount = i; - types = [NSArray arrayWithObject:NSStringPboardType]; - NSString *str = [pasteboard_rd availableTypeFromArray:types]; - if (str != nil) + formatType = [type UTF8String]; + + if (strcmp(formatType, "public.utf8-plain-text") == 0) { - cliprdr_send_supported_format_list(instance); + formatData = [item dataForType:type]; + formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING"); + + size = (UINT32) [formatData length]; + + data = (BYTE*) malloc(size); + [formatData getBytes:data length:size]; + + ClipboardSetData(mfc->clipboard, formatId, (void*) data, size); + formatMatch = TRUE; + + break; } } + + if (!formatMatch) + ClipboardEmpty(mfc->clipboard); + + if (mfc->clipboardSync) + mac_cliprdr_send_client_format_list(mfc->cliprdr); +} + +- (void) pause +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self->pasteboard_timer invalidate]; + }); + + NSArray* trackingAreas = self.trackingAreas; + + for (NSTrackingArea* ta in trackingAreas) + { + [self removeTrackingArea:ta]; + } +} + +- (void)resume +{ + dispatch_async(dispatch_get_main_queue(), ^{ + self->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + }); + + NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil]; + [self addTrackingArea:trackingArea]; + [trackingArea release]; } - (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height @@ -826,6 +807,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) { rdpSettings* settings = context->settings; + mfContext* mfc = (mfContext*) context; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -836,6 +818,10 @@ void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEve if (settings->SoftwareGdi) gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + mac_cliprdr_init(mfc, (CliprdrClientContext*) e->pInterface); + } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { @@ -845,6 +831,7 @@ void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEve void mac_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) { rdpSettings* settings = context->settings; + mfContext* mfc = (mfContext*) context; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -855,6 +842,10 @@ void mac_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnec if (settings->SoftwareGdi) gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + mac_cliprdr_uninit(mfc, (CliprdrClientContext*) e->pInterface); + } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { @@ -963,9 +954,12 @@ BOOL mac_post_connect(freerdp* instance) view->pasteboard_wr = [NSPasteboard generalPasteboard]; /* setup pasteboard for read operations */ - view->pasteboard_rd = [NSPasteboard generalPasteboard]; - view->pasteboard_changecount = (int) [view->pasteboard_rd changeCount]; - view->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:mfc->view selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + dispatch_async(dispatch_get_main_queue(), ^{ + view->pasteboard_rd = [NSPasteboard generalPasteboard]; + view->pasteboard_changecount = -1; + }); + + [view resume]; mfc->appleKeyboardType = mac_detect_keyboard_type(); @@ -1272,212 +1266,6 @@ static void input_activity_cb(freerdp* instance) } } -static void channel_activity_cb(freerdp* instance) -{ - wMessage* event; - - freerdp_channels_process_pending_messages(instance); - event = freerdp_channels_pop_event(instance->context->channels); - - if (event) - { - WLog_DBG(TAG, "channel_activity_cb: message %d", event->id); - - switch (GetMessageClass(event->id)) - { - case CliprdrChannel_Class: - process_cliprdr_event(instance, event); - break; - } - - freerdp_event_free(event); - } -} - -int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data) -{ - rdpChannels* channels = (rdpChannels*) user_data; - - freerdp_channels_load_plugin(channels, settings, name, plugin_data); - - return 1; -} - -/* - * stuff related to clipboard redirection - */ - -void cliprdr_process_cb_data_request_event(freerdp* instance) -{ - int len; - NSArray* types; - RDP_CB_DATA_RESPONSE_EVENT* event; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataResponse, NULL, NULL); - - types = [NSArray arrayWithObject:NSStringPboardType]; - NSString* str = [view->pasteboard_rd availableTypeFromArray:types]; - - if (str == nil) - { - event->data = NULL; - event->size = 0; - } - else - { - NSString* data = [view->pasteboard_rd stringForType:NSStringPboardType]; - len = (int) ([data length] * 2 + 2); - event->data = malloc(len); - [data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding]; - event->size = len; - } - - freerdp_channels_send_event(instance->context->channels, (wMessage*) event); -} - -void cliprdr_send_data_request(freerdp* instance, UINT32 format) -{ - RDP_CB_DATA_REQUEST_EVENT* event; - - event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataRequest, NULL, NULL); - - event->format = format; - freerdp_channels_send_event(instance->context->channels, (wMessage*) event); -} - -/** - * at the moment, only the following formats are supported - * CF_TEXT - * CF_UNICODETEXT - */ - -void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event) -{ - NSString* str; - NSArray* types; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (event->size == 0) - return; - - if (view->pasteboard_format == CF_TEXT || view->pasteboard_format == CF_UNICODETEXT) - { - str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2]; - types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; - [view->pasteboard_wr declareTypes:types owner:mfc->view]; - [view->pasteboard_wr setString:str forType:NSStringPboardType]; - } -} - -void cliprdr_process_cb_monitor_ready_event(freerdp* instance) -{ - wMessage* event; - RDP_CB_FORMAT_LIST_EVENT* format_list_event; - - event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL); - - format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event; - format_list_event->num_formats = 0; - - freerdp_channels_send_event(instance->context->channels, event); -} - -/** - * list of supported clipboard formats; currently only the following are supported - * CF_TEXT - * CF_UNICODETEXT - */ - -void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event) -{ - int i; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (event->num_formats == 0) - return; - - for (i = 0; i < event->num_formats; i++) - { - switch (event->formats[i]) - { - case CF_TEXT: - case CF_UNICODETEXT: - view->pasteboard_format = CF_UNICODETEXT; - cliprdr_send_data_request(instance, CF_UNICODETEXT); - return; - break; - } - } -} - -void process_cliprdr_event(freerdp* instance, wMessage* event) -{ - if (event) - { - switch (GetMessageType(event->id)) - { - /* - * Monitor Ready PDU is sent by server to indicate that it has been - * initialized and is ready. This PDU is transmitted by the server after it has sent - * Clipboard Capabilities PDU - */ - case CliprdrChannel_MonitorReady: - cliprdr_process_cb_monitor_ready_event(instance); - break; - - /* - * The Format List PDU is sent either by the client or the server when its - * local system clipboard is updated with new clipboard data. This PDU - * contains the Clipboard Format ID and name pairs of the new Clipboard - * Formats on the clipboard - */ - case CliprdrChannel_FormatList: - cliprdr_process_cb_format_list_event(instance, (RDP_CB_FORMAT_LIST_EVENT*) event); - break; - - /* - * The Format Data Request PDU is sent by the receipient of the Format List PDU. - * It is used to request the data for one of the formats that was listed in the - * Format List PDU - */ - case CliprdrChannel_DataRequest: - cliprdr_process_cb_data_request_event(instance); - break; - - /* - * The Format Data Response PDU is sent as a reply to the Format Data Request PDU. - * It is used to indicate whether processing of the Format Data Request PDU - * was successful. If the processing was successful, the Format Data Response PDU - * includes the contents of the requested clipboard data - */ - case CliprdrChannel_DataResponse: - cliprdr_process_cb_data_response_event(instance, (RDP_CB_DATA_RESPONSE_EVENT*) event); - break; - - default: - WLog_ERR(TAG, "process_cliprdr_event: unknown event type %d", GetMessageType(event->id)); - break; - } - } -} - -void cliprdr_send_supported_format_list(freerdp* instance) -{ - RDP_CB_FORMAT_LIST_EVENT* event; - - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL); - - event->formats = (UINT32*) malloc(sizeof(UINT32) * 1); - event->num_formats = 1; - event->formats[0] = CF_UNICODETEXT; - - freerdp_channels_send_event(instance->context->channels, (wMessage*) event); -} - /** * given a rect with 0,0 at the top left (windows cords) * convert it to a rect with 0,0 at the bottom left (apple cords) diff --git a/client/Mac/mf_client.m b/client/Mac/mf_client.m index 9b22e94c8..9b5427792 100644 --- a/client/Mac/mf_client.m +++ b/client/Mac/mf_client.m @@ -99,10 +99,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context) settings = instance->settings; settings->AsyncTransport = TRUE; - settings->AsyncUpdate = TRUE; settings->AsyncInput = TRUE; - settings->AsyncChannels = TRUE; return 0; } diff --git a/client/Mac/mfreerdp.h b/client/Mac/mfreerdp.h index 37eb3b4a6..a84a5d559 100644 --- a/client/Mac/mfreerdp.h +++ b/client/Mac/mfreerdp.h @@ -19,11 +19,13 @@ typedef struct mf_context mfContext; #include #include #include +#include #include #include #include #include +#include #include "MRDPView.h" #include "Keyboard.h" @@ -63,6 +65,15 @@ struct mf_context DWORD keyboardThreadId; BOOL disconnect; BOOL sw_gdi; + + BOOL clipboardSync; + wClipboard* clipboard; + UINT32 numServerFormats; + UINT32 requestedFormatId; + HANDLE clipboardRequestEvent; + CLIPRDR_FORMAT* serverFormats; + CliprdrClientContext* cliprdr; + UINT32 clipboardCapabilities; rdpFile* connectionRdpFile;