// // AppDelegate.m // MacClient2 // // Created by BenoƮt et Kathy on 2013-05-08. // // #import "AppDelegate.h" #import "MacFreeRDP/mfreerdp.h" #import "MacFreeRDP/mf_client.h" #import "MacFreeRDP/MRDPView.h" #import static AppDelegate* _singleDelegate = nil; void AppDelegate_ConnectionResultEventHandler(void* context, ConnectionResultEventArgs* e); void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e); void AppDelegate_EmbedWindowEventHandler(void* context, EmbedWindowEventArgs* e); void AppDelegate_ResizeWindowEventHandler(void* context, ResizeWindowEventArgs* e); void mac_set_view_size(rdpContext* context, MRDPView* view); @implementation AppDelegate - (void)dealloc { [super dealloc]; } @synthesize window = window; @synthesize context = context; - (void) applicationDidFinishLaunching:(NSNotification*)aNotification { int status; mfContext* mfc; _singleDelegate = self; [self CreateContext]; status = [self ParseCommandLineArguments]; mfc = (mfContext*) context; mfc->view = (void*) mrdpView; if (status < 0) { NSString* winTitle; winTitle = [[NSString alloc] initWithCString:"ERROR"]; [window setTitle:winTitle]; } else { NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; NSRect screenFrame = [screen frame]; if (context->instance->settings->Fullscreen) { context->instance->settings->DesktopWidth = screenFrame.size.width; context->instance->settings->DesktopHeight = screenFrame.size.height; } PubSub_SubscribeConnectionResult(context->pubSub, AppDelegate_ConnectionResultEventHandler); PubSub_SubscribeErrorInfo(context->pubSub, AppDelegate_ErrorInfoEventHandler); PubSub_SubscribeEmbedWindow(context->pubSub, AppDelegate_EmbedWindowEventHandler); PubSub_SubscribeResizeWindow(context->pubSub, AppDelegate_ResizeWindowEventHandler); freerdp_client_start(context); NSString* winTitle; if (mfc->context.settings->WindowTitle && mfc->context.settings->WindowTitle[0]) { winTitle = [[NSString alloc] initWithCString: mfc->context.settings->WindowTitle]; } else { winTitle = [[NSString alloc] initWithFormat:@"%@:%u", [NSString stringWithCString:mfc->context.settings->ServerHostname encoding: NSUTF8StringEncoding], mfc->context.settings->ServerPort]; } [window setTitle:winTitle]; } } - (void) applicationWillTerminate:(NSNotification*)notification { NSLog(@"Stopping...\n"); freerdp_client_stop(context); [mrdpView releaseResources]; _singleDelegate = nil; NSLog(@"Stopped.\n"); } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { return YES; } - (int) ParseCommandLineArguments { int i; int length; int status; char* cptr; NSArray* args = [[NSProcessInfo processInfo] arguments]; context->argc = (int) [args count]; context->argv = malloc(sizeof(char*) * context->argc); i = 0; for (NSString * str in args) { /* filter out some arguments added by XCode */ if ([str isEqualToString:@"YES"]) continue; if ([str isEqualToString:@"-NSDocumentRevisionsDebugMode"]) continue; length = (int)([str length] + 1); cptr = (char*) malloc(length); strcpy(cptr, [str UTF8String]); context->argv[i++] = cptr; } context->argc = i; status = freerdp_client_settings_parse_command_line(context->settings, context->argc, context->argv, FALSE); status = freerdp_client_settings_command_line_status_print(context->settings, status, context->argc, context->argv); return status; } - (void) CreateContext { RDP_CLIENT_ENTRY_POINTS clientEntryPoints; ZeroMemory(&clientEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS)); clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS); clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION; RdpClientEntry(&clientEntryPoints); context = freerdp_client_context_new(&clientEntryPoints); } - (void) ReleaseContext { mfContext* mfc; MRDPView* view; mfc = (mfContext*) context; view = (MRDPView*) mfc->view; [view exitFullScreenModeWithOptions:nil]; [view releaseResources]; [view release]; mfc->view = nil; freerdp_client_context_free(context); context = nil; } /** ********************************************************************* * called when we fail to connect to a RDP server - Make sure this is called from the main thread. ***********************************************************************/ - (void) rdpConnectError : (NSString*) withMessage { mfContext* mfc; MRDPView* view; mfc = (mfContext*) context; view = (MRDPView*) mfc->view; [view exitFullScreenModeWithOptions:nil]; NSString* message = withMessage ? withMessage : @"Error connecting to server"; NSAlert* alert = [[NSAlert alloc] init]; [alert setMessageText:message]; [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil]; } /** ********************************************************************* * just a terminate selector for above call ***********************************************************************/ - (void) alertDidEnd:(NSAlert*)a returnCode:(NSInteger)rc contextInfo:(void*)ci { [NSApp terminate:nil]; } @end /** ********************************************************************* * On connection error, display message and quit application ***********************************************************************/ void AppDelegate_ConnectionResultEventHandler(void* ctx, ConnectionResultEventArgs* e) { NSLog(@"ConnectionResult event result:%d\n", e->result); if (_singleDelegate) { if (e->result != 0) { NSString* message = nil; if (connectErrorCode == AUTHENTICATIONERROR) { message = [NSString stringWithFormat:@"%@", @"Authentication failure, check credentials."]; } // Making sure this should be invoked on the main UI thread. [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:FALSE]; } } } void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e) { NSLog(@"ErrorInfo event code:%d\n", e->code); if (_singleDelegate) { // Retrieve error message associated with error code NSString* message = nil; if (e->code != ERRINFO_NONE) { const char* errorMessage = freerdp_get_error_info_string(e->code); message = [[NSString alloc] initWithUTF8String:errorMessage]; } // Making sure this should be invoked on the main UI thread. [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:TRUE]; [message release]; } } void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e) { rdpContext* context = (rdpContext*) ctx; if (_singleDelegate) { mfContext* mfc = (mfContext*) context; _singleDelegate->mrdpView = mfc->view; if (_singleDelegate->window) { [[_singleDelegate->window contentView] addSubview:mfc->view]; } mac_set_view_size(context, mfc->view); } } void AppDelegate_ResizeWindowEventHandler(void* ctx, ResizeWindowEventArgs* e) { rdpContext* context = (rdpContext*) ctx; fprintf(stderr, "ResizeWindowEventHandler: %d %d\n", e->width, e->height); if (_singleDelegate) { mfContext* mfc = (mfContext*) context; mac_set_view_size(context, mfc->view); } } void mac_set_view_size(rdpContext* context, MRDPView* view) { // set client area to specified dimensions NSRect innerRect; innerRect.origin.x = 0; innerRect.origin.y = 0; innerRect.size.width = context->settings->DesktopWidth; innerRect.size.height = context->settings->DesktopHeight; [view setFrame:innerRect]; // calculate window of same size, but keep position NSRect outerRect = [[view window] frame]; outerRect.size = [[view window] frameRectForContentRect:innerRect].size; // we are not in RemoteApp mode, disable larger than resolution [[view window] setContentMaxSize:innerRect.size]; // set window to given area [[view window] setFrame:outerRect display:YES]; if (context->settings->Fullscreen) [[view window] toggleFullScreen:nil]; }