1/** 2 * FreeRDP: A Remote Desktop Protocol Implementation 3 * MacFreeRDP 4 * 5 * Copyright 2012 Thomas Goddard 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20#include <winpr/windows.h> 21 22#include "mf_client.h" 23#import "mfreerdp.h" 24#import "MRDPView.h" 25#import "MRDPCursor.h" 26#import "Clipboard.h" 27#import "PasswordDialog.h" 28#import "CertificateDialog.h" 29 30#include <winpr/crt.h> 31#include <winpr/input.h> 32#include <winpr/synch.h> 33#include <winpr/sysinfo.h> 34 35#include <freerdp/constants.h> 36 37#import "freerdp/freerdp.h" 38#import "freerdp/types.h" 39#import "freerdp/channels/channels.h" 40#import "freerdp/gdi/gdi.h" 41#import "freerdp/gdi/dc.h" 42#import "freerdp/gdi/region.h" 43#import "freerdp/graphics.h" 44#import "freerdp/client/file.h" 45#import "freerdp/client/cmdline.h" 46#import "freerdp/log.h" 47 48#import <CoreGraphics/CoreGraphics.h> 49 50#define TAG CLIENT_TAG("mac") 51 52static BOOL mf_Pointer_New(rdpContext *context, rdpPointer *pointer); 53static void mf_Pointer_Free(rdpContext *context, rdpPointer *pointer); 54static BOOL mf_Pointer_Set(rdpContext *context, const rdpPointer *pointer); 55static BOOL mf_Pointer_SetNull(rdpContext *context); 56static BOOL mf_Pointer_SetDefault(rdpContext *context); 57static BOOL mf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y); 58 59static BOOL mac_begin_paint(rdpContext *context); 60static BOOL mac_end_paint(rdpContext *context); 61static BOOL mac_desktop_resize(rdpContext *context); 62 63static void input_activity_cb(freerdp *instance); 64 65static DWORD WINAPI mac_client_thread(void *param); 66 67@implementation MRDPView 68 69@synthesize is_connected; 70 71- (int)rdpStart:(rdpContext *)rdp_context 72{ 73 rdpSettings *settings; 74 EmbedWindowEventArgs e; 75 [self initializeView]; 76 context = rdp_context; 77 mfc = (mfContext *)rdp_context; 78 instance = context->instance; 79 settings = context->settings; 80 EventArgsInit(&e, "mfreerdp"); 81 e.embed = TRUE; 82 e.handle = (void *)self; 83 PubSub_OnEmbedWindow(context->pubSub, context, &e); 84 NSScreen *screen = [[NSScreen screens] objectAtIndex:0]; 85 NSRect screenFrame = [screen frame]; 86 87 if (instance->settings->Fullscreen) 88 { 89 instance->settings->DesktopWidth = screenFrame.size.width; 90 instance->settings->DesktopHeight = screenFrame.size.height; 91 [self enterFullScreenMode:[NSScreen mainScreen] withOptions:nil]; 92 } 93 else 94 { 95 [self exitFullScreenModeWithOptions:nil]; 96 } 97 98 mfc->client_height = instance->settings->DesktopHeight; 99 mfc->client_width = instance->settings->DesktopWidth; 100 101 if (!(mfc->thread = 102 CreateThread(NULL, 0, mac_client_thread, (void *)context, 0, &mfc->mainThreadId))) 103 { 104 WLog_ERR(TAG, "failed to create client thread"); 105 return -1; 106 } 107 108 return 0; 109} 110 111static DWORD WINAPI mac_client_input_thread(LPVOID param) 112{ 113 int status; 114 wMessage message; 115 wMessageQueue *queue; 116 rdpContext *context = (rdpContext *)param; 117 status = 1; 118 queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); 119 120 while (MessageQueue_Wait(queue)) 121 { 122 while (MessageQueue_Peek(queue, &message, TRUE)) 123 { 124 status = freerdp_message_queue_process_message(context->instance, 125 FREERDP_INPUT_MESSAGE_QUEUE, &message); 126 127 if (!status) 128 break; 129 } 130 131 if (!status) 132 break; 133 } 134 135 ExitThread(0); 136 return 0; 137} 138 139DWORD WINAPI mac_client_thread(void *param) 140{ 141 @autoreleasepool 142 { 143 int status; 144 DWORD rc; 145 HANDLE events[16]; 146 HANDLE inputEvent; 147 HANDLE inputThread = NULL; 148 DWORD nCount; 149 DWORD nCountTmp; 150 DWORD nCountBase; 151 rdpContext *context = (rdpContext *)param; 152 mfContext *mfc = (mfContext *)context; 153 freerdp *instance = context->instance; 154 MRDPView *view = mfc->view; 155 rdpSettings *settings = context->settings; 156 status = freerdp_connect(context->instance); 157 158 if (!status) 159 { 160 [view setIs_connected:0]; 161 return 0; 162 } 163 164 [view setIs_connected:1]; 165 nCount = 0; 166 events[nCount++] = mfc->stopEvent; 167 168 if (settings->AsyncInput) 169 { 170 if (!(inputThread = CreateThread(NULL, 0, mac_client_input_thread, context, 0, NULL))) 171 { 172 WLog_ERR(TAG, "failed to create async input thread"); 173 goto disconnect; 174 } 175 } 176 else 177 { 178 if (!(inputEvent = freerdp_get_message_queue_event_handle(instance, 179 FREERDP_INPUT_MESSAGE_QUEUE))) 180 { 181 WLog_ERR(TAG, "failed to get input event handle"); 182 goto disconnect; 183 } 184 185 events[nCount++] = inputEvent; 186 } 187 188 nCountBase = nCount; 189 190 while (!freerdp_shall_disconnect(instance)) 191 { 192 nCount = nCountBase; 193 { 194 if (!(nCountTmp = freerdp_get_event_handles(context, &events[nCount], 16 - nCount))) 195 { 196 WLog_ERR(TAG, "freerdp_get_event_handles failed"); 197 break; 198 } 199 200 nCount += nCountTmp; 201 } 202 rc = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); 203 204 if (rc >= (WAIT_OBJECT_0 + nCount)) 205 { 206 WLog_ERR(TAG, "WaitForMultipleObjects failed (0x%08X)", rc); 207 break; 208 } 209 210 if (rc == WAIT_OBJECT_0) 211 { 212 /* stop event triggered */ 213 break; 214 } 215 216 if (!settings->AsyncInput) 217 { 218 if (WaitForSingleObject(inputEvent, 0) == WAIT_OBJECT_0) 219 { 220 input_activity_cb(instance); 221 } 222 } 223 224 { 225 if (!freerdp_check_event_handles(context)) 226 { 227 WLog_ERR(TAG, "freerdp_check_event_handles failed"); 228 break; 229 } 230 } 231 } 232 233 disconnect: 234 [view setIs_connected:0]; 235 freerdp_disconnect(instance); 236 237 if (settings->AsyncInput && inputThread) 238 { 239 wMessageQueue *inputQueue = 240 freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); 241 242 if (inputQueue) 243 { 244 MessageQueue_PostQuit(inputQueue, 0); 245 WaitForSingleObject(inputThread, INFINITE); 246 } 247 248 CloseHandle(inputThread); 249 } 250 251 ExitThread(0); 252 return 0; 253 } 254} 255 256- (id)initWithFrame:(NSRect)frame 257{ 258 self = [super initWithFrame:frame]; 259 260 if (self) 261 { 262 // Initialization code here. 263 } 264 265 return self; 266} 267 268- (void)viewDidLoad 269{ 270 [self initializeView]; 271} 272 273- (void)initializeView 274{ 275 if (!initialized) 276 { 277 cursors = [[NSMutableArray alloc] initWithCapacity:10]; 278 // setup a mouse tracking area 279 NSTrackingArea *trackingArea = [[NSTrackingArea alloc] 280 initWithRect:[self visibleRect] 281 options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | 282 NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | 283 NSTrackingActiveWhenFirstResponder 284 owner:self 285 userInfo:nil]; 286 [self addTrackingArea:trackingArea]; 287 // Set the default cursor 288 currentCursor = [NSCursor arrowCursor]; 289 initialized = YES; 290 } 291} 292 293- (void)setCursor:(NSCursor *)cursor 294{ 295 self->currentCursor = cursor; 296 dispatch_async(dispatch_get_main_queue(), ^{ 297 [[self window] invalidateCursorRectsForView:self]; 298 }); 299} 300 301- (void)resetCursorRects 302{ 303 [self addCursorRect:[self visibleRect] cursor:currentCursor]; 304} 305 306- (BOOL)acceptsFirstResponder 307{ 308 return YES; 309} 310 311- (void)mouseMoved:(NSEvent *)event 312{ 313 [super mouseMoved:event]; 314 315 if (!self.is_connected) 316 return; 317 318 NSPoint loc = [event locationInWindow]; 319 int x = (int)loc.x; 320 int y = (int)loc.y; 321 mf_scale_mouse_event(context, instance->input, PTR_FLAGS_MOVE, x, y); 322} 323 324- (void)mouseDown:(NSEvent *)event 325{ 326 [super mouseDown:event]; 327 328 if (!self.is_connected) 329 return; 330 331 NSPoint loc = [event locationInWindow]; 332 int x = (int)loc.x; 333 int y = (int)loc.y; 334 mf_press_mouse_button(context, instance->input, 0, x, y, TRUE); 335} 336 337- (void)mouseUp:(NSEvent *)event 338{ 339 [super mouseUp:event]; 340 341 if (!self.is_connected) 342 return; 343 344 NSPoint loc = [event locationInWindow]; 345 int x = (int)loc.x; 346 int y = (int)loc.y; 347 mf_press_mouse_button(context, instance->input, 0, x, y, FALSE); 348} 349 350- (void)rightMouseDown:(NSEvent *)event 351{ 352 [super rightMouseDown:event]; 353 354 if (!self.is_connected) 355 return; 356 357 NSPoint loc = [event locationInWindow]; 358 int x = (int)loc.x; 359 int y = (int)loc.y; 360 mf_press_mouse_button(context, instance->input, 1, x, y, TRUE); 361} 362 363- (void)rightMouseUp:(NSEvent *)event 364{ 365 [super rightMouseUp:event]; 366 367 if (!self.is_connected) 368 return; 369 370 NSPoint loc = [event locationInWindow]; 371 int x = (int)loc.x; 372 int y = (int)loc.y; 373 mf_press_mouse_button(context, instance->input, 1, x, y, FALSE); 374} 375 376- (void)otherMouseDown:(NSEvent *)event 377{ 378 [super otherMouseDown:event]; 379 380 if (!self.is_connected) 381 return; 382 383 NSPoint loc = [event locationInWindow]; 384 int x = (int)loc.x; 385 int y = (int)loc.y; 386 int pressed = [event buttonNumber]; 387 mf_press_mouse_button(context, instance->input, pressed, x, y, TRUE); 388} 389 390- (void)otherMouseUp:(NSEvent *)event 391{ 392 [super otherMouseUp:event]; 393 394 if (!self.is_connected) 395 return; 396 397 NSPoint loc = [event locationInWindow]; 398 int x = (int)loc.x; 399 int y = (int)loc.y; 400 int pressed = [event buttonNumber]; 401 mf_press_mouse_button(context, instance->input, pressed, x, y, FALSE); 402} 403 404- (void)scrollWheel:(NSEvent *)event 405{ 406 UINT16 flags; 407 [super scrollWheel:event]; 408 409 if (!self.is_connected) 410 return; 411 412 float dx = [event deltaX]; 413 float dy = [event deltaY]; 414 /* 1 event = 120 units */ 415 UINT16 units = 0; 416 417 if (fabsf(dy) > FLT_EPSILON) 418 { 419 flags = PTR_FLAGS_WHEEL; 420 units = fabsf(dy) * 120; 421 422 if (dy < 0) 423 flags |= PTR_FLAGS_WHEEL_NEGATIVE; 424 } 425 else if (fabsf(dx) > FLT_EPSILON) 426 { 427 flags = PTR_FLAGS_HWHEEL; 428 units = fabsf(dx) * 120; 429 430 if (dx > 0) 431 flags |= PTR_FLAGS_WHEEL_NEGATIVE; 432 } 433 else 434 return; 435 436 /* Wheel rotation steps: 437 * 438 * positive: 0 ... 0xFF -> slow ... fast 439 * negative: 0 ... 0xFF -> fast ... slow 440 */ 441 UINT16 step = units; 442 if (step > 0xFF) 443 step = 0xFF; 444 445 /* Negative rotation, so count down steps from top 446 * 9bit twos complement */ 447 if (flags & PTR_FLAGS_WHEEL_NEGATIVE) 448 step = 0x100 - step; 449 450 mf_scale_mouse_event(context, instance->input, flags | step, 0, 0); 451} 452 453- (void)mouseDragged:(NSEvent *)event 454{ 455 [super mouseDragged:event]; 456 457 if (!self.is_connected) 458 return; 459 460 NSPoint loc = [event locationInWindow]; 461 int x = (int)loc.x; 462 int y = (int)loc.y; 463 // send mouse motion event to RDP server 464 mf_scale_mouse_event(context, instance->input, PTR_FLAGS_MOVE, x, y); 465} 466 467DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) 468{ 469 /** 470 * In 99% of cases, the given key code is truly keyboard independent. 471 * This function handles the remaining 1% of edge cases. 472 * 473 * Hungarian Keyboard: This is 'QWERTZ' and not 'QWERTY'. 474 * The '0' key is on the left of the '1' key, where '~' is on a US keyboard. 475 * A special 'i' letter key with acute is found on the right of the left shift key. 476 * On the hungarian keyboard, the 'i' key is at the left of the 'Y' key 477 * Some international keyboards have a corresponding key which would be at 478 * the left of the 'Z' key when using a QWERTY layout. 479 * 480 * The Apple Hungarian keyboard sends inverted key codes for the '0' and 'i' keys. 481 * When using the US keyboard layout, key codes are left as-is (inverted). 482 * When using the Hungarian keyboard layout, key codes are swapped (non-inverted). 483 * This means that when using the Hungarian keyboard layout with a US keyboard, 484 * the keys corresponding to '0' and 'i' will effectively be inverted. 485 * 486 * To fix the '0' and 'i' key inversion, we use the corresponding output character 487 * provided by OS X and check for a character to key code mismatch: for instance, 488 * when the output character is '0' for the key code corresponding to the 'i' key. 489 */ 490#if 0 491 switch (keyChar) 492 { 493 case '0': 494 case 0x00A7: /* section sign */ 495 if (keyCode == APPLE_VK_ISO_Section) 496 keyCode = APPLE_VK_ANSI_Grave; 497 498 break; 499 500 case 0x00ED: /* latin small letter i with acute */ 501 case 0x00CD: /* latin capital letter i with acute */ 502 if (keyCode == APPLE_VK_ANSI_Grave) 503 keyCode = APPLE_VK_ISO_Section; 504 505 break; 506 } 507 508#endif 509 510 /* Perform keycode correction for all ISO keyboards */ 511 512 if (type == APPLE_KEYBOARD_TYPE_ISO) 513 { 514 if (keyCode == APPLE_VK_ANSI_Grave) 515 keyCode = APPLE_VK_ISO_Section; 516 else if (keyCode == APPLE_VK_ISO_Section) 517 keyCode = APPLE_VK_ANSI_Grave; 518 } 519 520 return keyCode; 521} 522 523- (void)keyDown:(NSEvent *)event 524{ 525 DWORD keyCode; 526 DWORD keyFlags; 527 DWORD vkcode; 528 DWORD scancode; 529 unichar keyChar; 530 NSString *characters; 531 532 if (!is_connected) 533 return; 534 535 keyFlags = KBD_FLAGS_DOWN; 536 keyCode = [event keyCode]; 537 characters = [event charactersIgnoringModifiers]; 538 539 if ([characters length] > 0) 540 { 541 keyChar = [characters characterAtIndex:0]; 542 keyCode = fixKeyCode(keyCode, keyChar, mfc->appleKeyboardType); 543 } 544 545 vkcode = GetVirtualKeyCodeFromKeycode(keyCode + 8, KEYCODE_TYPE_APPLE); 546 scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4); 547 keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; 548 scancode &= 0xFF; 549 vkcode &= 0xFF; 550#if 0 551 WLog_ERR(TAG, 552 "keyDown: keyCode: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", 553 keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); 554#endif 555 sync_keyboard_state(instance); 556 freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode); 557} 558 559- (void)keyUp:(NSEvent *)event 560{ 561 DWORD keyCode; 562 DWORD keyFlags; 563 DWORD vkcode; 564 DWORD scancode; 565 unichar keyChar; 566 NSString *characters; 567 568 if (!is_connected) 569 return; 570 571 keyFlags = KBD_FLAGS_RELEASE; 572 keyCode = [event keyCode]; 573 characters = [event charactersIgnoringModifiers]; 574 575 if ([characters length] > 0) 576 { 577 keyChar = [characters characterAtIndex:0]; 578 keyCode = fixKeyCode(keyCode, keyChar, mfc->appleKeyboardType); 579 } 580 581 vkcode = GetVirtualKeyCodeFromKeycode(keyCode + 8, KEYCODE_TYPE_APPLE); 582 scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4); 583 keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; 584 scancode &= 0xFF; 585 vkcode &= 0xFF; 586#if 0 587 WLog_DBG(TAG, 588 "keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", 589 keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); 590#endif 591 freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode); 592} 593 594- (void)flagsChanged:(NSEvent *)event 595{ 596 int key; 597 DWORD keyFlags; 598 DWORD vkcode; 599 DWORD scancode; 600 DWORD modFlags; 601 602 if (!is_connected) 603 return; 604 605 keyFlags = 0; 606 key = [event keyCode] + 8; 607 modFlags = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; 608 vkcode = GetVirtualKeyCodeFromKeycode(key, KEYCODE_TYPE_APPLE); 609 scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4); 610 keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; 611 scancode &= 0xFF; 612 vkcode &= 0xFF; 613#if 0 614 WLog_DBG(TAG, 615 "flagsChanged: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X extended: %d name: %s modFlags: 0x%04X", 616 key - 8, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode), modFlags); 617 618 if (modFlags & NSAlphaShiftKeyMask) 619 WLog_DBG(TAG, "NSAlphaShiftKeyMask"); 620 621 if (modFlags & NSShiftKeyMask) 622 WLog_DBG(TAG, "NSShiftKeyMask"); 623 624 if (modFlags & NSControlKeyMask) 625 WLog_DBG(TAG, "NSControlKeyMask"); 626 627 if (modFlags & NSAlternateKeyMask) 628 WLog_DBG(TAG, "NSAlternateKeyMask"); 629 630 if (modFlags & NSCommandKeyMask) 631 WLog_DBG(TAG, "NSCommandKeyMask"); 632 633 if (modFlags & NSNumericPadKeyMask) 634 WLog_DBG(TAG, "NSNumericPadKeyMask"); 635 636 if (modFlags & NSHelpKeyMask) 637 WLog_DBG(TAG, "NSHelpKeyMask"); 638 639#endif 640 641 if ((modFlags & NSAlphaShiftKeyMask) && !(kbdModFlags & NSAlphaShiftKeyMask)) 642 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); 643 else if (!(modFlags & NSAlphaShiftKeyMask) && (kbdModFlags & NSAlphaShiftKeyMask)) 644 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); 645 646 if ((modFlags & NSShiftKeyMask) && !(kbdModFlags & NSShiftKeyMask)) 647 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); 648 else if (!(modFlags & NSShiftKeyMask) && (kbdModFlags & NSShiftKeyMask)) 649 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); 650 651 if ((modFlags & NSControlKeyMask) && !(kbdModFlags & NSControlKeyMask)) 652 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); 653 else if (!(modFlags & NSControlKeyMask) && (kbdModFlags & NSControlKeyMask)) 654 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); 655 656 if ((modFlags & NSAlternateKeyMask) && !(kbdModFlags & NSAlternateKeyMask)) 657 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); 658 else if (!(modFlags & NSAlternateKeyMask) && (kbdModFlags & NSAlternateKeyMask)) 659 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); 660 661 if ((modFlags & NSCommandKeyMask) && !(kbdModFlags & NSCommandKeyMask)) 662 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); 663 else if (!(modFlags & NSCommandKeyMask) && (kbdModFlags & NSCommandKeyMask)) 664 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); 665 666 if ((modFlags & NSNumericPadKeyMask) && !(kbdModFlags & NSNumericPadKeyMask)) 667 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); 668 else if (!(modFlags & NSNumericPadKeyMask) && (kbdModFlags & NSNumericPadKeyMask)) 669 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); 670 671 if ((modFlags & NSHelpKeyMask) && !(kbdModFlags & NSHelpKeyMask)) 672 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); 673 else if (!(modFlags & NSHelpKeyMask) && (kbdModFlags & NSHelpKeyMask)) 674 freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); 675 676 kbdModFlags = modFlags; 677} 678 679- (void)releaseResources 680{ 681 int i; 682 683 for (i = 0; i < argc; i++) 684 free(argv[i]); 685 686 if (!is_connected) 687 return; 688 689 free(pixel_data); 690} 691 692- (void)drawRect:(NSRect)rect 693{ 694 if (!context) 695 return; 696 697 if (self->bitmap_context) 698 { 699 CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort]; 700 CGImageRef cgImage = CGBitmapContextCreateImage(self->bitmap_context); 701 CGContextSaveGState(cgContext); 702 CGContextClipToRect( 703 cgContext, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); 704 CGContextDrawImage(cgContext, 705 CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), 706 cgImage); 707 CGContextRestoreGState(cgContext); 708 CGImageRelease(cgImage); 709 } 710 else 711 { 712 /* Fill the screen with black */ 713 [[NSColor blackColor] set]; 714 NSRectFill([self bounds]); 715 } 716} 717 718- (void)onPasteboardTimerFired:(NSTimer *)timer 719{ 720 const BYTE *data; 721 UINT32 size; 722 UINT32 formatId; 723 BOOL formatMatch; 724 int changeCount; 725 NSData *formatData; 726 const char *formatType; 727 NSPasteboardItem *item; 728 changeCount = (int)[pasteboard_rd changeCount]; 729 730 if (changeCount == pasteboard_changecount) 731 return; 732 733 pasteboard_changecount = changeCount; 734 NSArray *items = [pasteboard_rd pasteboardItems]; 735 736 if ([items count] < 1) 737 return; 738 739 item = [items objectAtIndex:0]; 740 /** 741 * System-Declared Uniform Type Identifiers: 742 * https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html 743 */ 744 formatMatch = FALSE; 745 746 for (NSString *type in [item types]) 747 { 748 formatType = [type UTF8String]; 749 750 if (strcmp(formatType, "public.utf8-plain-text") == 0) 751 { 752 formatData = [item dataForType:type]; 753 formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING"); 754 size = (UINT32)[formatData length]; 755 data = [formatData bytes]; 756 /* size is the string length without the terminating NULL terminator */ 757 ClipboardSetData(mfc->clipboard, formatId, data, size + 1); 758 formatMatch = TRUE; 759 break; 760 } 761 } 762 763 if (!formatMatch) 764 ClipboardEmpty(mfc->clipboard); 765 766 if (mfc->clipboardSync) 767 mac_cliprdr_send_client_format_list(mfc->cliprdr); 768} 769 770- (void)pause 771{ 772 dispatch_async(dispatch_get_main_queue(), ^{ 773 [self->pasteboard_timer invalidate]; 774 }); 775 NSArray *trackingAreas = self.trackingAreas; 776 777 for (NSTrackingArea *ta in trackingAreas) 778 { 779 [self removeTrackingArea:ta]; 780 } 781} 782 783- (void)resume 784{ 785 if (!self.is_connected) 786 return; 787 788 dispatch_async(dispatch_get_main_queue(), ^{ 789 self->pasteboard_timer = 790 [NSTimer scheduledTimerWithTimeInterval:0.5 791 target:self 792 selector:@selector(onPasteboardTimerFired:) 793 userInfo:nil 794 repeats:YES]; 795 796 NSTrackingArea *trackingArea = [[NSTrackingArea alloc] 797 initWithRect:[self visibleRect] 798 options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | 799 NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | 800 NSTrackingActiveWhenFirstResponder 801 owner:self 802 userInfo:nil]; 803 [self addTrackingArea:trackingArea]; 804 [trackingArea release]; 805 }); 806} 807 808- (void)setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height 809{ 810 mfc->yCurrentScroll = yOffset; 811 mfc->xCurrentScroll = xOffset; 812 mfc->client_height = height; 813 mfc->client_width = width; 814} 815 816void mac_OnChannelConnectedEventHandler(void *context, ChannelConnectedEventArgs *e) 817{ 818 mfContext *mfc = (mfContext *)context; 819 rdpSettings *settings = mfc->context.settings; 820 821 if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) 822 { 823 } 824 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) 825 { 826 if (settings->SoftwareGdi) 827 gdi_graphics_pipeline_init(mfc->context.gdi, (RdpgfxClientContext *)e->pInterface); 828 } 829 else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) 830 { 831 mac_cliprdr_init(mfc, (CliprdrClientContext *)e->pInterface); 832 } 833 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) 834 { 835 } 836} 837 838void mac_OnChannelDisconnectedEventHandler(void *context, ChannelDisconnectedEventArgs *e) 839{ 840 mfContext *mfc = (mfContext *)context; 841 rdpSettings *settings = mfc->context.settings; 842 843 if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) 844 { 845 } 846 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) 847 { 848 if (settings->SoftwareGdi) 849 gdi_graphics_pipeline_uninit(mfc->context.gdi, (RdpgfxClientContext *)e->pInterface); 850 } 851 else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) 852 { 853 mac_cliprdr_uninit(mfc, (CliprdrClientContext *)e->pInterface); 854 } 855 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) 856 { 857 } 858} 859 860BOOL mac_pre_connect(freerdp *instance) 861{ 862 rdpSettings *settings; 863 instance->update->BeginPaint = mac_begin_paint; 864 instance->update->EndPaint = mac_end_paint; 865 instance->update->DesktopResize = mac_desktop_resize; 866 settings = instance->settings; 867 868 if (!settings->ServerHostname) 869 { 870 WLog_ERR(TAG, "error: server hostname was not specified with /v:<server>[:port]"); 871 return FALSE; 872 } 873 874 settings->OsMajorType = OSMAJORTYPE_MACINTOSH; 875 settings->OsMinorType = OSMINORTYPE_MACINTOSH; 876 PubSub_SubscribeChannelConnected(instance->context->pubSub, mac_OnChannelConnectedEventHandler); 877 PubSub_SubscribeChannelDisconnected(instance->context->pubSub, 878 mac_OnChannelDisconnectedEventHandler); 879 880 if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) 881 return FALSE; 882 883 return TRUE; 884} 885 886BOOL mac_post_connect(freerdp *instance) 887{ 888 rdpGdi *gdi; 889 rdpSettings *settings; 890 rdpPointer rdp_pointer; 891 mfContext *mfc = (mfContext *)instance->context; 892 MRDPView *view = (MRDPView *)mfc->view; 893 ZeroMemory(&rdp_pointer, sizeof(rdpPointer)); 894 rdp_pointer.size = sizeof(rdpPointer); 895 rdp_pointer.New = mf_Pointer_New; 896 rdp_pointer.Free = mf_Pointer_Free; 897 rdp_pointer.Set = mf_Pointer_Set; 898 rdp_pointer.SetNull = mf_Pointer_SetNull; 899 rdp_pointer.SetDefault = mf_Pointer_SetDefault; 900 rdp_pointer.SetPosition = mf_Pointer_SetPosition; 901 settings = instance->settings; 902 903 if (!gdi_init(instance, PIXEL_FORMAT_BGRX32)) 904 return FALSE; 905 906 gdi = instance->context->gdi; 907 view->bitmap_context = mac_create_bitmap_context(instance->context); 908 graphics_register_pointer(instance->context->graphics, &rdp_pointer); 909 /* setup pasteboard (aka clipboard) for copy operations (write only) */ 910 view->pasteboard_wr = [NSPasteboard generalPasteboard]; 911 /* setup pasteboard for read operations */ 912 dispatch_async(dispatch_get_main_queue(), ^{ 913 view->pasteboard_rd = [NSPasteboard generalPasteboard]; 914 view->pasteboard_changecount = -1; 915 }); 916 [view resume]; 917 mfc->appleKeyboardType = mac_detect_keyboard_type(); 918 return TRUE; 919} 920 921void mac_post_disconnect(freerdp *instance) 922{ 923 mfContext *mfc; 924 MRDPView *view; 925 if (!instance || !instance->context) 926 return; 927 928 mfc = (mfContext *)instance->context; 929 view = (MRDPView *)mfc->view; 930 931 [view pause]; 932 933 PubSub_UnsubscribeChannelConnected(instance->context->pubSub, 934 mac_OnChannelConnectedEventHandler); 935 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub, 936 mac_OnChannelDisconnectedEventHandler); 937 gdi_free(instance); 938} 939 940static BOOL mac_authenticate_int(NSString *title, freerdp *instance, char **username, 941 char **password, char **domain) 942{ 943 mfContext *mfc = (mfContext *)instance->context; 944 MRDPView *view = (MRDPView *)mfc->view; 945 PasswordDialog *dialog = [PasswordDialog new]; 946 dialog.serverHostname = title; 947 948 if (*username) 949 dialog.username = [NSString stringWithCString:*username encoding:NSUTF8StringEncoding]; 950 951 if (*password) 952 dialog.password = [NSString stringWithCString:*password encoding:NSUTF8StringEncoding]; 953 954 if (*domain) 955 dialog.domain = [NSString stringWithCString:*domain encoding:NSUTF8StringEncoding]; 956 957 dispatch_sync(dispatch_get_main_queue(), ^{ 958 [dialog performSelectorOnMainThread:@selector(runModal:) 959 withObject:[view window] 960 waitUntilDone:TRUE]; 961 }); 962 BOOL ok = dialog.modalCode; 963 964 if (ok) 965 { 966 size_t ulen, plen, dlen; 967 const char *submittedUsername = [dialog.username cStringUsingEncoding:NSUTF8StringEncoding]; 968 ulen = (strlen(submittedUsername) + 1) * sizeof(char); 969 *username = malloc(ulen); 970 971 if (!(*username)) 972 return FALSE; 973 974 sprintf_s(*username, ulen, "%s", submittedUsername); 975 const char *submittedPassword = [dialog.password cStringUsingEncoding:NSUTF8StringEncoding]; 976 plen = (strlen(submittedPassword) + 1) * sizeof(char); 977 *password = malloc(plen); 978 979 if (!(*password)) 980 return FALSE; 981 982 sprintf_s(*password, plen, "%s", submittedPassword); 983 const char *submittedDomain = [dialog.domain cStringUsingEncoding:NSUTF8StringEncoding]; 984 dlen = (strlen(submittedDomain) + 1) * sizeof(char); 985 *domain = malloc(dlen); 986 987 if (!(*domain)) 988 return FALSE; 989 990 sprintf_s(*domain, dlen, "%s", submittedDomain); 991 } 992 993 return ok; 994} 995 996BOOL mac_authenticate(freerdp *instance, char **username, char **password, char **domain) 997{ 998 NSString *title = 999 [NSString stringWithFormat:@"%@:%u", 1000 [NSString stringWithCString:instance->settings->ServerHostname 1001 encoding:NSUTF8StringEncoding], 1002 instance -> settings -> ServerPort]; 1003 return mac_authenticate_int(title, instance, username, password, domain); 1004} 1005 1006BOOL mac_gw_authenticate(freerdp *instance, char **username, char **password, char **domain) 1007{ 1008 NSString *title = 1009 [NSString stringWithFormat:@"%@:%u", 1010 [NSString stringWithCString:instance->settings->GatewayHostname 1011 encoding:NSUTF8StringEncoding], 1012 instance -> settings -> GatewayPort]; 1013 return mac_authenticate_int(title, instance, username, password, domain); 1014} 1015 1016DWORD mac_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port, 1017 const char *common_name, const char *subject, const char *issuer, 1018 const char *fingerprint, DWORD flags) 1019{ 1020 mfContext *mfc = (mfContext *)instance->context; 1021 MRDPView *view = (MRDPView *)mfc->view; 1022 CertificateDialog *dialog = [CertificateDialog new]; 1023 const char *type = "RDP-Server"; 1024 char hostname[8192]; 1025 1026 if (flags & VERIFY_CERT_FLAG_GATEWAY) 1027 type = "RDP-Gateway"; 1028 1029 if (flags & VERIFY_CERT_FLAG_REDIRECT) 1030 type = "RDP-Redirect"; 1031 1032 sprintf_s(hostname, sizeof(hostname), "%s %s:%" PRIu16, type, host, port); 1033 dialog.serverHostname = [NSString stringWithCString:hostname]; 1034 dialog.commonName = [NSString stringWithCString:common_name encoding:NSUTF8StringEncoding]; 1035 dialog.subject = [NSString stringWithCString:subject encoding:NSUTF8StringEncoding]; 1036 dialog.issuer = [NSString stringWithCString:issuer encoding:NSUTF8StringEncoding]; 1037 dialog.fingerprint = [NSString stringWithCString:fingerprint encoding:NSUTF8StringEncoding]; 1038 1039 if (flags & VERIFY_CERT_FLAG_MISMATCH) 1040 dialog.hostMismatch = TRUE; 1041 1042 if (flags & VERIFY_CERT_FLAG_CHANGED) 1043 dialog.changed = TRUE; 1044 1045 [dialog performSelectorOnMainThread:@selector(runModal:) 1046 withObject:[view window] 1047 waitUntilDone:TRUE]; 1048 return dialog.result; 1049} 1050 1051DWORD mac_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port, 1052 const char *common_name, const char *subject, 1053 const char *issuer, const char *fingerprint, 1054 const char *old_subject, const char *old_issuer, 1055 const char *old_fingerprint, DWORD flags) 1056{ 1057 mfContext *mfc = (mfContext *)instance->context; 1058 MRDPView *view = (MRDPView *)mfc->view; 1059 CertificateDialog *dialog = [CertificateDialog new]; 1060 const char *type = "RDP-Server"; 1061 char hostname[8192]; 1062 1063 if (flags & VERIFY_CERT_FLAG_GATEWAY) 1064 type = "RDP-Gateway"; 1065 1066 if (flags & VERIFY_CERT_FLAG_REDIRECT) 1067 type = "RDP-Redirect"; 1068 1069 sprintf_s(hostname, sizeof(hostname), "%s %s:%" PRIu16, type, host, port); 1070 dialog.serverHostname = [NSString stringWithCString:hostname]; 1071 dialog.commonName = [NSString stringWithCString:common_name encoding:NSUTF8StringEncoding]; 1072 dialog.subject = [NSString stringWithCString:subject encoding:NSUTF8StringEncoding]; 1073 dialog.issuer = [NSString stringWithCString:issuer encoding:NSUTF8StringEncoding]; 1074 dialog.fingerprint = [NSString stringWithCString:fingerprint encoding:NSUTF8StringEncoding]; 1075 1076 if (flags & VERIFY_CERT_FLAG_MISMATCH) 1077 dialog.hostMismatch = TRUE; 1078 1079 if (flags & VERIFY_CERT_FLAG_CHANGED) 1080 dialog.changed = TRUE; 1081 1082 [dialog performSelectorOnMainThread:@selector(runModal:) 1083 withObject:[view window] 1084 waitUntilDone:TRUE]; 1085 return dialog.result; 1086} 1087 1088int mac_logon_error_info(freerdp *instance, UINT32 data, UINT32 type) 1089{ 1090 const char *str_data = freerdp_get_logon_error_info_data(data); 1091 const char *str_type = freerdp_get_logon_error_info_type(type); 1092 // TODO: Error message dialog 1093 WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); 1094 return 1; 1095} 1096 1097BOOL mf_Pointer_New(rdpContext *context, rdpPointer *pointer) 1098{ 1099 rdpGdi *gdi; 1100 NSRect rect; 1101 NSImage *image; 1102 NSPoint hotSpot; 1103 NSCursor *cursor; 1104 BYTE *cursor_data; 1105 NSMutableArray *ma; 1106 NSBitmapImageRep *bmiRep; 1107 MRDPCursor *mrdpCursor = [[MRDPCursor alloc] init]; 1108 mfContext *mfc = (mfContext *)context; 1109 MRDPView *view; 1110 UINT32 format; 1111 1112 if (!mfc || !context || !pointer) 1113 return FALSE; 1114 1115 view = (MRDPView *)mfc->view; 1116 gdi = context->gdi; 1117 1118 if (!gdi || !view) 1119 return FALSE; 1120 1121 rect.size.width = pointer->width; 1122 rect.size.height = pointer->height; 1123 rect.origin.x = pointer->xPos; 1124 rect.origin.y = pointer->yPos; 1125 cursor_data = (BYTE *)malloc(rect.size.width * rect.size.height * 4); 1126 1127 if (!cursor_data) 1128 return FALSE; 1129 1130 mrdpCursor->cursor_data = cursor_data; 1131 format = PIXEL_FORMAT_RGBA32; 1132 1133 if (!freerdp_image_copy_from_pointer_data(cursor_data, format, 0, 0, 0, pointer->width, 1134 pointer->height, pointer->xorMaskData, 1135 pointer->lengthXorMask, pointer->andMaskData, 1136 pointer->lengthAndMask, pointer->xorBpp, NULL)) 1137 { 1138 free(cursor_data); 1139 mrdpCursor->cursor_data = NULL; 1140 return FALSE; 1141 } 1142 1143 /* store cursor bitmap image in representation - required by NSImage */ 1144 bmiRep = [[NSBitmapImageRep alloc] 1145 initWithBitmapDataPlanes:(unsigned char **)&cursor_data 1146 pixelsWide:rect.size.width 1147 pixelsHigh:rect.size.height 1148 bitsPerSample:8 1149 samplesPerPixel:4 1150 hasAlpha:YES 1151 isPlanar:NO 1152 colorSpaceName:NSDeviceRGBColorSpace 1153 bitmapFormat:0 1154 bytesPerRow:rect.size.width * GetBytesPerPixel(format) 1155 bitsPerPixel:0]; 1156 mrdpCursor->bmiRep = bmiRep; 1157 /* create an image using above representation */ 1158 image = [[NSImage alloc] initWithSize:[bmiRep size]]; 1159 [image addRepresentation:bmiRep]; 1160 [image setFlipped:NO]; 1161 mrdpCursor->nsImage = image; 1162 /* need hotspot to create cursor */ 1163 hotSpot.x = pointer->xPos; 1164 hotSpot.y = pointer->yPos; 1165 cursor = [[NSCursor alloc] initWithImage:image hotSpot:hotSpot]; 1166 mrdpCursor->nsCursor = cursor; 1167 mrdpCursor->pointer = pointer; 1168 /* save cursor for later use in mf_Pointer_Set() */ 1169 ma = view->cursors; 1170 [ma addObject:mrdpCursor]; 1171 return TRUE; 1172} 1173 1174void mf_Pointer_Free(rdpContext *context, rdpPointer *pointer) 1175{ 1176 mfContext *mfc = (mfContext *)context; 1177 MRDPView *view = (MRDPView *)mfc->view; 1178 NSMutableArray *ma = view->cursors; 1179 1180 for (MRDPCursor *cursor in ma) 1181 { 1182 if (cursor->pointer == pointer) 1183 { 1184 cursor->nsImage = nil; 1185 cursor->nsCursor = nil; 1186 cursor->bmiRep = nil; 1187 free(cursor->cursor_data); 1188 [ma removeObject:cursor]; 1189 return; 1190 } 1191 } 1192} 1193 1194BOOL mf_Pointer_Set(rdpContext *context, const rdpPointer *pointer) 1195{ 1196 mfContext *mfc = (mfContext *)context; 1197 MRDPView *view = (MRDPView *)mfc->view; 1198 NSMutableArray *ma = view->cursors; 1199 1200 for (MRDPCursor *cursor in ma) 1201 { 1202 if (cursor->pointer == pointer) 1203 { 1204 [view setCursor:cursor->nsCursor]; 1205 return TRUE; 1206 } 1207 } 1208 1209 NSLog(@"Cursor not found"); 1210 return TRUE; 1211} 1212 1213BOOL mf_Pointer_SetNull(rdpContext *context) 1214{ 1215 return TRUE; 1216} 1217 1218BOOL mf_Pointer_SetDefault(rdpContext *context) 1219{ 1220 mfContext *mfc = (mfContext *)context; 1221 MRDPView *view = (MRDPView *)mfc->view; 1222 [view setCursor:[NSCursor arrowCursor]]; 1223 return TRUE; 1224} 1225 1226static BOOL mf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y) 1227{ 1228 mfContext *mfc = (mfContext *)context; 1229 1230 if (!mfc) 1231 return FALSE; 1232 1233 /* TODO: Set pointer position */ 1234 return TRUE; 1235} 1236 1237CGContextRef mac_create_bitmap_context(rdpContext *context) 1238{ 1239 CGContextRef bitmap_context; 1240 rdpGdi *gdi = context->gdi; 1241 UINT32 bpp = GetBytesPerPixel(gdi->dstFormat); 1242 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 1243 1244 if (bpp == 2) 1245 { 1246 bitmap_context = CGBitmapContextCreate( 1247 gdi->primary_buffer, gdi->width, gdi->height, 5, gdi->stride, colorSpace, 1248 kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst); 1249 } 1250 else 1251 { 1252 bitmap_context = CGBitmapContextCreate( 1253 gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->stride, colorSpace, 1254 kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst); 1255 } 1256 1257 CGColorSpaceRelease(colorSpace); 1258 return bitmap_context; 1259} 1260 1261BOOL mac_begin_paint(rdpContext *context) 1262{ 1263 rdpGdi *gdi = context->gdi; 1264 1265 if (!gdi) 1266 return FALSE; 1267 1268 gdi->primary->hdc->hwnd->invalid->null = TRUE; 1269 return TRUE; 1270} 1271 1272BOOL mac_end_paint(rdpContext *context) 1273{ 1274 rdpGdi *gdi; 1275 HGDI_RGN invalid; 1276 NSRect newDrawRect; 1277 int ww, wh, dw, dh; 1278 mfContext *mfc = (mfContext *)context; 1279 MRDPView *view = (MRDPView *)mfc->view; 1280 gdi = context->gdi; 1281 1282 if (!gdi) 1283 return FALSE; 1284 1285 ww = mfc->client_width; 1286 wh = mfc->client_height; 1287 dw = mfc->context.settings->DesktopWidth; 1288 dh = mfc->context.settings->DesktopHeight; 1289 1290 if ((!context) || (!context->gdi)) 1291 return FALSE; 1292 1293 if (context->gdi->primary->hdc->hwnd->invalid->null) 1294 return TRUE; 1295 1296 invalid = gdi->primary->hdc->hwnd->invalid; 1297 newDrawRect.origin.x = invalid->x; 1298 newDrawRect.origin.y = invalid->y; 1299 newDrawRect.size.width = invalid->w; 1300 newDrawRect.size.height = invalid->h; 1301 1302 if (mfc->context.settings->SmartSizing && (ww != dw || wh != dh)) 1303 { 1304 newDrawRect.origin.y = newDrawRect.origin.y * wh / dh - 1; 1305 newDrawRect.size.height = newDrawRect.size.height * wh / dh + 1; 1306 newDrawRect.origin.x = newDrawRect.origin.x * ww / dw - 1; 1307 newDrawRect.size.width = newDrawRect.size.width * ww / dw + 1; 1308 } 1309 else 1310 { 1311 newDrawRect.origin.y = newDrawRect.origin.y - 1; 1312 newDrawRect.size.height = newDrawRect.size.height + 1; 1313 newDrawRect.origin.x = newDrawRect.origin.x - 1; 1314 newDrawRect.size.width = newDrawRect.size.width + 1; 1315 } 1316 1317 windows_to_apple_cords(mfc->view, &newDrawRect); 1318 dispatch_sync(dispatch_get_main_queue(), ^{ 1319 [view setNeedsDisplayInRect:newDrawRect]; 1320 }); 1321 gdi->primary->hdc->hwnd->ninvalid = 0; 1322 return TRUE; 1323} 1324 1325BOOL mac_desktop_resize(rdpContext *context) 1326{ 1327 ResizeWindowEventArgs e; 1328 mfContext *mfc = (mfContext *)context; 1329 MRDPView *view = (MRDPView *)mfc->view; 1330 rdpSettings *settings = context->settings; 1331 1332 if (!context->gdi) 1333 return TRUE; 1334 1335 /** 1336 * TODO: Fix resizing race condition. We should probably implement a message to be 1337 * put on the update message queue to be able to properly flush pending updates, 1338 * resize, and then continue with post-resizing graphical updates. 1339 */ 1340 CGContextRef old_context = view->bitmap_context; 1341 view->bitmap_context = NULL; 1342 CGContextRelease(old_context); 1343 mfc->width = settings->DesktopWidth; 1344 mfc->height = settings->DesktopHeight; 1345 1346 if (!gdi_resize(context->gdi, mfc->width, mfc->height)) 1347 return FALSE; 1348 1349 view->bitmap_context = mac_create_bitmap_context(context); 1350 1351 if (!view->bitmap_context) 1352 return FALSE; 1353 1354 mfc->client_width = mfc->width; 1355 mfc->client_height = mfc->height; 1356 [view setFrameSize:NSMakeSize(mfc->width, mfc->height)]; 1357 EventArgsInit(&e, "mfreerdp"); 1358 e.width = settings->DesktopWidth; 1359 e.height = settings->DesktopHeight; 1360 PubSub_OnResizeWindow(context->pubSub, context, &e); 1361 return TRUE; 1362} 1363 1364void input_activity_cb(freerdp *instance) 1365{ 1366 int status; 1367 wMessage message; 1368 wMessageQueue *queue; 1369 status = 1; 1370 queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); 1371 1372 if (queue) 1373 { 1374 while (MessageQueue_Peek(queue, &message, TRUE)) 1375 { 1376 status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, 1377 &message); 1378 1379 if (!status) 1380 break; 1381 } 1382 } 1383 else 1384 { 1385 WLog_ERR(TAG, "input_activity_cb: No queue!"); 1386 } 1387} 1388 1389/** 1390 * given a rect with 0,0 at the top left (windows cords) 1391 * convert it to a rect with 0,0 at the bottom left (apple cords) 1392 * 1393 * Note: the formula works for conversions in both directions. 1394 * 1395 */ 1396 1397void windows_to_apple_cords(MRDPView *view, NSRect *r) 1398{ 1399 dispatch_sync(dispatch_get_main_queue(), ^{ 1400 r->origin.y = [view frame].size.height - (r->origin.y + r->size.height); 1401 }); 1402} 1403 1404void sync_keyboard_state(freerdp *instance) 1405{ 1406 mfContext *context = (mfContext *)instance->context; 1407 UINT32 flags = 0; 1408 CGEventFlags currentFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState); 1409 1410 if (context->kbdFlags != currentFlags) 1411 { 1412 if (currentFlags & kCGEventFlagMaskAlphaShift) 1413 flags |= KBD_SYNC_CAPS_LOCK; 1414 1415 if (currentFlags & kCGEventFlagMaskNumericPad) 1416 flags |= KBD_SYNC_NUM_LOCK; 1417 1418 freerdp_input_send_synchronize_event(instance->input, flags); 1419 context->kbdFlags = currentFlags; 1420 } 1421} 1422 1423@end 1424