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