MacFreeRDP: connection now starts asynchronously.

Replaced RunLoop implementation with standard pthreads.
This commit is contained in:
Benoît LeBlanc 2013-07-18 15:41:28 -04:00
parent a7f61bb98d
commit bbfdb853f6
4 changed files with 119 additions and 155 deletions

View File

@ -41,10 +41,6 @@
@interface MRDPView : NSView @interface MRDPView : NSView
{ {
CFRunLoopSourceRef run_loop_src_channels;
CFRunLoopSourceRef run_loop_src_update;
CFRunLoopSourceRef run_loop_src_input;
NSBitmapImageRep* bmiRep; NSBitmapImageRep* bmiRep;
NSMutableArray* cursors; NSMutableArray* cursors;
NSMutableArray* windows; NSMutableArray* windows;
@ -98,7 +94,7 @@
- (void) rdpRemoteAppError; - (void) rdpRemoteAppError;
- (void) onPasteboardTimerFired :(NSTimer *) timer; - (void) onPasteboardTimerFired :(NSTimer *) timer;
- (void) releaseResources; - (void) releaseResources;
- (void) setViewSize : (int) width : (int) height; - (void) setViewSize : (int) w : (int) h;
@property (assign) int is_connected; @property (assign) int is_connected;
@ -118,3 +114,4 @@ BOOL mac_pre_connect(freerdp* instance);
BOOL mac_post_connect(freerdp* instance); BOOL mac_post_connect(freerdp* instance);
BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain); BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain);
int mac_receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); int mac_receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size);
DWORD mac_client_thread(void* param);

View File

@ -82,11 +82,9 @@ void mac_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap);
void mac_begin_paint(rdpContext* context); void mac_begin_paint(rdpContext* context);
void mac_end_paint(rdpContext* context); void mac_end_paint(rdpContext* context);
void mac_save_state_info(freerdp* instance, rdpContext* context); void mac_save_state_info(freerdp* instance, rdpContext* context);
static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); static void update_activity_cb(freerdp* instance);
static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); static void input_activity_cb(freerdp* instance);
static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); static void channel_activity_cb(freerdp* instance);
int register_update_fds(freerdp* instance);
int register_input_fds(freerdp* instance);
int invoke_draw_rect(rdpContext* context); int invoke_draw_rect(rdpContext* context);
int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data); 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); int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size);
@ -101,7 +99,7 @@ void cliprdr_send_supported_format_list(freerdp* instance);
int register_channel_fds(int* fds, int count, freerdp* instance); int register_channel_fds(int* fds, int count, freerdp* instance);
DWORD mf_client_thread(void* param); DWORD mac_client_thread(void* param);
struct cursor struct cursor
{ {
@ -141,42 +139,93 @@ struct rgba_data
e.embed = TRUE; e.embed = TRUE;
e.handle = (void*) self; e.handle = (void*) self;
PubSub_OnEmbedWindow(context->pubSub, context, &e); PubSub_OnEmbedWindow(context->pubSub, context, &e);
[self setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight];
/* register update message queue with the RunLoop */ mfc->thread = CreateThread(NULL, 0, mac_client_thread, (void*) context, 0, &mfc->mainThreadId);
register_update_fds(context->instance);
/* register update message queue with the RunLoop */
register_input_fds(context->instance);
/* register channel events with the RunLoop */
register_channels_fds(context->instance);
freerdp_check_fds(context->instance);
mfc->thread = CreateThread(NULL, 0, mf_client_thread, (void*) context, 0, &mfc->mainThreadId);
return 0; return 0;
} }
DWORD mf_client_thread(void* param) DWORD mac_client_thread(void* param)
{ {
int status; int status;
rdpContext* context = (rdpContext*) param; HANDLE events[4];
mfContext* mfc = (mfContext*) context; HANDLE input_event;
MRDPView* view = mfc->view; HANDLE update_event;
HANDLE channels_event;
DWORD nCount;
rdpContext* context = (rdpContext*) param;
mfContext* mfc = (mfContext*) context;
freerdp* instance = context->instance;
MRDPView* view = mfc->view;
status = freerdp_connect(context->instance); status = freerdp_connect(context->instance);
if (!status) if (!status)
{ {
[view setIs_connected:0]; [view setIs_connected:0];
[view rdpConnectError]; [view rdpConnectError];
return 0; return 0;
} }
[view setIs_connected:1]; [view setIs_connected:1];
return 0; nCount = 0;
events[nCount++] = mfc->stopEvent;
if (instance->settings->AsyncUpdate)
{
events[nCount++] = update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
}
if (instance->settings->AsyncInput)
{
events[nCount++] = input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
}
if (instance->settings->AsyncChannels)
{
events[nCount++] = channels_event = freerdp_channels_get_event_handle(instance);
}
while (1)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (WaitForSingleObject(mfc->stopEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if (instance->settings->AsyncUpdate)
{
if (WaitForSingleObject(update_event, 0) == WAIT_OBJECT_0)
{
update_activity_cb(instance);
}
}
if (instance->settings->AsyncInput)
{
if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0)
{
input_activity_cb(instance);
}
}
if (instance->settings->AsyncChannels)
{
if (WaitForSingleObject(channels_event, 0) == WAIT_OBJECT_0)
{
channel_activity_cb(instance);
}
}
}
ExitThread(0);
return 0;
} }
/************************************************************************ /************************************************************************
@ -627,6 +676,15 @@ DWORD mf_client_thread(void* param)
{ {
int i; int i;
mfContext* mfc = (mfContext*) context;
if (mfc && mfc->thread)
{
WaitForSingleObject(mfc->thread, INFINITE);
CloseHandle(mfc->thread);
mfc->thread = NULL;
}
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
{ {
if (argv[i]) if (argv[i])
@ -640,15 +698,6 @@ DWORD mf_client_thread(void* param)
if (pixel_data) if (pixel_data)
free(pixel_data); free(pixel_data);
if (run_loop_src_update != 0)
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_update, kCFRunLoopDefaultMode);
if (run_loop_src_input != 0)
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_input, kCFRunLoopDefaultMode);
if (run_loop_src_channels != 0)
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode);
} }
/** ********************************************************************* /** *********************************************************************
@ -858,7 +907,6 @@ BOOL mac_pre_connect(freerdp* instance)
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
[view setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight];
freerdp_channels_pre_connect(instance->context->channels, instance); freerdp_channels_pre_connect(instance->context->channels, instance);
return TRUE; return TRUE;
@ -1152,12 +1200,11 @@ void mac_end_paint(rdpContext* context)
* called when update data is available * called when update data is available
***********************************************************************/ ***********************************************************************/
static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) static void update_activity_cb(freerdp* instance)
{ {
int status; int status;
wMessage message; wMessage message;
wMessageQueue* queue; wMessageQueue* queue;
freerdp* instance = (freerdp*) info;
status = 1; status = 1;
queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
@ -1172,21 +1219,21 @@ static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBack
break; break;
} }
} }
else
CFRelease(fdref); {
register_update_fds(instance); fprintf(stderr, "update_activity_cb: No queue!\n");
}
} }
/** ********************************************************************* /** *********************************************************************
* called when input data is available * called when input data is available
***********************************************************************/ ***********************************************************************/
static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) static void input_activity_cb(freerdp* instance)
{ {
int status; int status;
wMessage message; wMessage message;
wMessageQueue* queue; wMessageQueue* queue;
freerdp* instance = (freerdp*) info;
status = 1; status = 1;
queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
@ -1195,33 +1242,32 @@ static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackT
{ {
while (MessageQueue_Peek(queue, &message, TRUE)) while (MessageQueue_Peek(queue, &message, TRUE))
{ {
fprintf(stderr, "input_activity_cb: message %d\n", message.id);
status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, &message); status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, &message);
if (!status) if (!status)
break; break;
} }
} }
else
CFRelease(fdref); {
register_input_fds(instance); fprintf(stderr, "input_activity_cb: No queue!\n");
}
} }
/** ********************************************************************* /** *********************************************************************
* called when data is available on a virtual channel * called when data is available on a virtual channel
***********************************************************************/ ***********************************************************************/
static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) static void channel_activity_cb(freerdp* instance)
{ {
wMessage* event; wMessage* event;
freerdp* instance = (freerdp*) info;
freerdp_channels_process_pending_messages(instance); freerdp_channels_process_pending_messages(instance);
event = freerdp_channels_pop_event(instance->context->channels); event = freerdp_channels_pop_event(instance->context->channels);
if (event) if (event)
{ {
switch (GetMessageClass(event->id)) fprintf(stderr, "channel_activity_cb: message %d\n", event->id);
switch (GetMessageClass(event->id))
{ {
case CliprdrChannel_Class: case CliprdrChannel_Class:
process_cliprdr_event(instance, event); process_cliprdr_event(instance, event);
@ -1230,90 +1276,6 @@ static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBac
freerdp_event_free(event); freerdp_event_free(event);
} }
CFRelease(fdref);
register_channels_fds(instance);
}
/** *********************************************************************
* setup callbacks for data availability on update message queue
***********************************************************************/
int register_update_fds(freerdp* instance)
{
int fd_update_event;
HANDLE update_event;
CFFileDescriptorRef fdref;
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
mfContext* mfc = (mfContext*) instance->context;
MRDPView* view = (MRDPView*) mfc->view;
if (instance->settings->AsyncUpdate)
{
update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
fd_update_event = GetEventFileDescriptor(update_event);
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_update_event, true, update_activity_cb, &fd_context);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
view->run_loop_src_update = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_update, kCFRunLoopDefaultMode);
}
return 0;
}
/** *********************************************************************
* setup callbacks for data availability on input message queue
***********************************************************************/
int register_input_fds(freerdp* instance)
{
int fd_input_event;
HANDLE input_event;
CFFileDescriptorRef fdref;
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
mfContext* mfc = (mfContext*) instance->context;
MRDPView* view = (MRDPView*) mfc->view;
if (instance->settings->AsyncInput)
{
input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
fd_input_event = GetEventFileDescriptor(input_event);
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_input_event, true, input_activity_cb, &fd_context);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
view->run_loop_src_input = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_input, kCFRunLoopDefaultMode);
}
return 0;
}
/** *********************************************************************
* setup callbacks for data availability on channels
***********************************************************************/
int register_channels_fds(freerdp* instance)
{
int fd_channel_event;
HANDLE channel_event;
CFFileDescriptorRef fdref;
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
mfContext* mfc = (mfContext*) instance->context;
MRDPView* view = (MRDPView*) mfc->view;
if (instance->settings->AsyncChannels)
{
channel_event = freerdp_channels_get_event_handle(instance);
fd_channel_event = GetEventFileDescriptor(channel_event);
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_channel_event, true, channel_activity_cb, &fd_context);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
view->run_loop_src_channels = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_channels, kCFRunLoopDefaultMode);
}
return 0;
} }
/** ********************************************************************* /** *********************************************************************

View File

@ -88,6 +88,8 @@ int mfreerdp_client_stop(rdpContext* context)
mfc->disconnect = TRUE; mfc->disconnect = TRUE;
} }
SetEvent(mfc->stopEvent);
if (mfc->view_ownership) if (mfc->view_ownership)
{ {
MRDPView* view = (MRDPView*) mfc->view; MRDPView* view = (MRDPView*) mfc->view;
@ -106,6 +108,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context)
mfc = (mfContext*) instance->context; mfc = (mfContext*) instance->context;
mfc->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
context->instance->PreConnect = mac_pre_connect; context->instance->PreConnect = mac_pre_connect;
context->instance->PostConnect = mac_post_connect; context->instance->PostConnect = mac_post_connect;
context->instance->ReceiveChannelData = mac_receive_channel_data; context->instance->ReceiveChannelData = mac_receive_channel_data;
@ -115,8 +119,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context)
settings = instance->settings; settings = instance->settings;
settings->AsyncUpdate = TRUE; settings->AsyncUpdate = TRUE;
// TODO settings->AsyncInput = TRUE; settings->AsyncInput = TRUE;
settings->AsyncChannels = TRUE; settings->AsyncChannels = TRUE;
settings->AsyncTransport = TRUE; settings->AsyncTransport = TRUE;
settings->RedirectClipboard = TRUE; settings->RedirectClipboard = TRUE;

View File

@ -44,6 +44,7 @@ struct mf_context
int client_height; int client_height;
HANDLE keyboardThread; HANDLE keyboardThread;
HANDLE stopEvent;
HGDI_DC hdc; HGDI_DC hdc;
UINT16 srcBpp; UINT16 srcBpp;