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