2013-02-22 08:52:51 +04:00
|
|
|
/**
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
* MacFreeRDP
|
|
|
|
*
|
|
|
|
* Copyright 2012 Thomas Goddard
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2012-05-03 07:15:27 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO
|
2012-06-20 20:57:20 +04:00
|
|
|
* + provide a UI for configuring optional parameters, but keep cmd line args
|
|
|
|
* + audio redirection is delayed considerably
|
|
|
|
* + caps lock key needs to be sent in func flagsChanged()
|
|
|
|
* + libfreerdp-utils.1.0.dylib needs to be installed to /usr/local/lib
|
|
|
|
*
|
|
|
|
* - MRDPView implementation is incomplete
|
|
|
|
* - all variables should have consistent nameing scheme - camel case
|
|
|
|
* - all funcs same as above
|
|
|
|
* - PolygonSc seems to create a transparent rect
|
|
|
|
* - ensure mouse cursor changes are working ok after moving to NSTracking area
|
2013-02-22 06:42:47 +04:00
|
|
|
* - RAIL:
|
|
|
|
* -
|
|
|
|
* -
|
2012-06-20 20:57:20 +04:00
|
|
|
* - tool tips to be correctly positioned
|
|
|
|
* - dragging is slightly of
|
|
|
|
* - resize after dragging not working
|
|
|
|
* - dragging app from macbook to monitor gives exec/access err
|
|
|
|
* - unable to drag rect out of monitor boundaries
|
2013-02-22 06:42:47 +04:00
|
|
|
* -
|
|
|
|
* -
|
|
|
|
* -
|
2012-05-03 07:15:27 +04:00
|
|
|
*/
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-06-18 20:03:22 +04:00
|
|
|
#include "mf_client.h"
|
2013-06-18 22:30:21 +04:00
|
|
|
#import "mfreerdp.h"
|
2012-05-03 07:15:27 +04:00
|
|
|
#import "MRDPView.h"
|
|
|
|
#import "MRDPCursor.h"
|
2013-03-11 05:32:05 +04:00
|
|
|
#import "PasswordDialog.h"
|
2013-03-11 07:14:40 +04:00
|
|
|
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#include <winpr/input.h>
|
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
#include <freerdp/constants.h>
|
2012-05-03 07:15:27 +04:00
|
|
|
|
2013-05-31 20:48:40 +04:00
|
|
|
#import "freerdp/freerdp.h"
|
|
|
|
#import "freerdp/types.h"
|
|
|
|
#import "freerdp/channels/channels.h"
|
|
|
|
#import "freerdp/gdi/gdi.h"
|
|
|
|
#import "freerdp/graphics.h"
|
|
|
|
#import "freerdp/utils/event.h"
|
|
|
|
#import "freerdp/client/cliprdr.h"
|
|
|
|
#import "freerdp/client/file.h"
|
|
|
|
#import "freerdp/client/cmdline.h"
|
|
|
|
|
2013-06-18 05:21:42 +04:00
|
|
|
|
2013-05-31 20:48:40 +04:00
|
|
|
/******************************************
|
|
|
|
Forward declarations
|
|
|
|
******************************************/
|
|
|
|
|
|
|
|
|
|
|
|
void mf_Pointer_New(rdpContext* context, rdpPointer* pointer);
|
|
|
|
void mf_Pointer_Free(rdpContext* context, rdpPointer* pointer);
|
|
|
|
void mf_Pointer_Set(rdpContext* context, rdpPointer* pointer);
|
|
|
|
void mf_Pointer_SetNull(rdpContext* context);
|
|
|
|
void mf_Pointer_SetDefault(rdpContext* context);
|
|
|
|
// int rdp_connect(void);
|
|
|
|
void mac_set_bounds(rdpContext* context, rdpBounds* bounds);
|
|
|
|
void mac_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap);
|
|
|
|
void mac_begin_paint(rdpContext* context);
|
|
|
|
void mac_end_paint(rdpContext* context);
|
|
|
|
void mac_save_state_info(freerdp* instance, rdpContext* context);
|
2013-06-21 04:55:49 +04:00
|
|
|
static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info);
|
|
|
|
static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info);
|
|
|
|
static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info);
|
2013-06-20 18:03:20 +04:00
|
|
|
int register_update_fds(freerdp* instance);
|
2013-06-21 04:55:49 +04:00
|
|
|
int register_input_fds(freerdp* instance);
|
2013-05-31 20:48:40 +04:00
|
|
|
int invoke_draw_rect(rdpContext* context);
|
|
|
|
int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data);
|
|
|
|
int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size);
|
2013-06-18 00:44:44 +04:00
|
|
|
|
2013-05-31 20:48:40 +04:00
|
|
|
void process_cliprdr_event(freerdp* instance, wMessage* event);
|
|
|
|
void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event);
|
|
|
|
void cliprdr_send_data_request(freerdp* instance, UINT32 format);
|
|
|
|
void cliprdr_process_cb_monitor_ready_event(freerdp* inst);
|
|
|
|
void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event);
|
|
|
|
void cliprdr_process_text(freerdp* instance, BYTE* data, int len);
|
|
|
|
void cliprdr_send_supported_format_list(freerdp* instance);
|
2013-06-18 05:21:42 +04:00
|
|
|
int register_channel_fds(int* fds, int count, freerdp* instance);
|
2013-05-31 20:48:40 +04:00
|
|
|
|
|
|
|
struct cursor
|
|
|
|
{
|
|
|
|
rdpPointer* pointer;
|
|
|
|
BYTE* cursor_data;
|
|
|
|
void* bmiRep; /* NSBitmapImageRep */
|
|
|
|
void* nsCursor; /* NSCursor */
|
|
|
|
void* nsImage; /* NSImage */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rgba_data
|
|
|
|
{
|
|
|
|
char red;
|
|
|
|
char green;
|
|
|
|
char blue;
|
|
|
|
char alpha;
|
|
|
|
};
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
@implementation MRDPView
|
|
|
|
|
|
|
|
@synthesize is_connected;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
- (int) rdpStart:(rdpContext*) rdp_context
|
2013-05-31 20:48:40 +04:00
|
|
|
{
|
|
|
|
int status;
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc;
|
2013-06-18 05:21:42 +04:00
|
|
|
rdpSettings* settings;
|
2013-06-23 04:27:23 +04:00
|
|
|
EmbedWindowEventArgs e;
|
2013-06-18 22:30:21 +04:00
|
|
|
|
2013-06-26 21:45:12 +04:00
|
|
|
[self initializeView];
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
context = rdp_context;
|
|
|
|
mfc = (mfContext*) rdp_context;
|
|
|
|
instance = context->instance;
|
2013-06-18 22:30:21 +04:00
|
|
|
settings = context->settings;
|
2013-06-20 19:47:28 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
EventArgsInit(&e, "mfreerdp");
|
|
|
|
e.embed = TRUE;
|
|
|
|
e.handle = (void*) self;
|
|
|
|
PubSub_OnEmbedWindow(context->pubSub, context, &e);
|
|
|
|
|
2013-07-04 22:42:40 +04:00
|
|
|
status = freerdp_connect(context->instance);
|
2013-05-31 20:48:40 +04:00
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
if (!status)
|
2013-05-31 20:48:40 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
[self setIs_connected:0];
|
|
|
|
[self rdpConnectError];
|
|
|
|
return 1;
|
2013-05-31 20:48:40 +04:00
|
|
|
}
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
/* register update message queue with the RunLoop */
|
|
|
|
register_update_fds(context->instance);
|
|
|
|
|
|
|
|
/* register update message queue with the RunLoop */
|
|
|
|
register_input_fds(context->instance);
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
/* register channel events with the RunLoop */
|
|
|
|
register_channels_fds(context->instance);
|
2013-06-20 23:00:50 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
freerdp_check_fds(context->instance);
|
2013-06-20 18:03:20 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
[self setIs_connected:1];
|
|
|
|
|
|
|
|
return 0;
|
2013-05-31 20:48:40 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
/************************************************************************
|
2013-02-22 06:42:47 +04:00
|
|
|
methods we override
|
|
|
|
************************************************************************/
|
2012-05-03 07:15:27 +04:00
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* create MRDPView with specified rectangle
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (id)initWithFrame:(NSRect)frame
|
|
|
|
{
|
2013-06-26 21:45:12 +04:00
|
|
|
self = [super initWithFrame:frame];
|
2013-02-22 07:04:09 +04:00
|
|
|
|
|
|
|
if (self)
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
// Initialization code here.
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when MRDPView has been successfully created from the NIB
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-06-20 23:00:50 +04:00
|
|
|
//TODO - Expose this code as a public method, because awakeFromNib
|
|
|
|
// won't be called if the view is created dynamically
|
2013-06-26 00:05:37 +04:00
|
|
|
- (void) viewDidLoad
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-06-26 21:45:12 +04:00
|
|
|
[self initializeView];
|
|
|
|
}
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-06-26 21:45:12 +04:00
|
|
|
- (void) initializeView
|
|
|
|
{
|
|
|
|
if (!initialized)
|
|
|
|
{
|
|
|
|
// store our window dimensions
|
|
|
|
width = [self frame].size.width;
|
|
|
|
height = [self frame].size.height;
|
|
|
|
titleBarHeight = 22;
|
|
|
|
|
|
|
|
[[self window] becomeFirstResponder];
|
|
|
|
[[self window] setAcceptsMouseMovedEvents:YES];
|
|
|
|
|
|
|
|
cursors = [[NSMutableArray alloc] initWithCapacity:10];
|
|
|
|
|
|
|
|
// setup a mouse tracking area
|
|
|
|
NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil];
|
|
|
|
|
|
|
|
[self addTrackingArea:trackingArea];
|
2013-07-16 20:16:44 +04:00
|
|
|
|
|
|
|
// Set the default cursor
|
|
|
|
currentCursor = [NSCursor arrowCursor];
|
2013-06-26 21:45:12 +04:00
|
|
|
|
|
|
|
mouseInClientArea = YES;
|
2013-07-16 20:16:44 +04:00
|
|
|
NSLog(@"SET mouseInClientArea: %d", mouseInClientArea);
|
2013-06-26 21:45:12 +04:00
|
|
|
|
|
|
|
initialized = YES;
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-07-16 20:16:44 +04:00
|
|
|
- (void) setCursor: (NSCursor*) cursor
|
|
|
|
{
|
|
|
|
NSLog(@"Setcursor %@", cursor);
|
|
|
|
self->currentCursor = cursor;
|
|
|
|
[[self window] invalidateCursorRectsForView:self];
|
|
|
|
|
|
|
|
[imageView setImage:[currentCursor image]];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Set the current cursor
|
|
|
|
- (void) resetCursorRects
|
|
|
|
{
|
|
|
|
[self addCursorRect:[self visibleRect] cursor:currentCursor];
|
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* become first responder so we can get keyboard and mouse events
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
- (BOOL)acceptsFirstResponder
|
|
|
|
{
|
|
|
|
return YES;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when a mouse move event occurrs
|
2013-02-22 06:42:47 +04:00
|
|
|
*
|
2012-05-03 07:15:27 +04:00
|
|
|
* ideally we want to be called when the mouse moves over NSView client area,
|
|
|
|
* but in reality we get called any time the mouse moves anywhere on the screen;
|
|
|
|
* we could use NSTrackingArea class to handle this but this class is available
|
|
|
|
* on Mac OS X v10.5 and higher; since we want to be compatible with older
|
2013-02-22 06:42:47 +04:00
|
|
|
* versions, we do this manually.
|
2012-05-03 07:15:27 +04:00
|
|
|
*
|
|
|
|
* TODO: here is how it can be done using legacy methods
|
|
|
|
* http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/MouseTrackingEvents/MouseTrackingEvents.html#//apple_ref/doc/uid/10000060i-CH11-SW1
|
|
|
|
***********************************************************************/
|
2012-06-20 20:57:20 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
- (void) mouseMoved:(NSEvent *)event
|
|
|
|
{
|
|
|
|
[super mouseMoved:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
|
|
|
// send mouse motion event to RDP server
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_MOVE, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when left mouse button is pressed down
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void)mouseDown:(NSEvent *) event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[super mouseDown:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when left mouse button is released
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) mouseUp:(NSEvent *) event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[super mouseUp:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_BUTTON1, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when right mouse button is pressed down
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) rightMouseDown:(NSEvent *)event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[super rightMouseDown:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when right mouse button is released
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) rightMouseUp:(NSEvent *)event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[super rightMouseUp:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_BUTTON2, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when middle mouse button is pressed
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) otherMouseDown:(NSEvent *)event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[super otherMouseDown:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when middle mouse button is released
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) otherMouseUp:(NSEvent *)event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[super otherMouseUp:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_BUTTON3, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) scrollWheel:(NSEvent *)event
|
|
|
|
{
|
2013-02-22 08:07:35 +04:00
|
|
|
UINT16 flags;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
|
|
|
[super scrollWheel:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
|
|
|
flags = PTR_FLAGS_WHEEL;
|
2013-02-22 07:04:09 +04:00
|
|
|
|
|
|
|
if ([event deltaY] < 0)
|
2013-02-22 06:42:47 +04:00
|
|
|
flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088;
|
2013-02-22 07:04:09 +04:00
|
|
|
else
|
2013-02-22 06:42:47 +04:00
|
|
|
flags |= 0x0078;
|
2013-02-22 07:04:09 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
x += (int) [event deltaX];
|
|
|
|
y += (int) [event deltaY];
|
2013-02-22 07:04:09 +04:00
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, flags, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when mouse is moved with left button pressed
|
|
|
|
* note: invocation order is: mouseDown, mouseDragged, mouseUp
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) mouseDragged:(NSEvent *)event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[super mouseDragged:event];
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSPoint loc = [event locationInWindow];
|
|
|
|
int x = (int) loc.x;
|
|
|
|
int y = (int) loc.y;
|
|
|
|
|
|
|
|
y = height - y;
|
|
|
|
|
|
|
|
// send mouse motion event to RDP server
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->MouseEvent(instance->input, PTR_FLAGS_MOVE, x, y);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when a key is pressed
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) keyDown:(NSEvent *) event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
int key;
|
2013-03-15 23:03:48 +04:00
|
|
|
USHORT extended;
|
2013-03-11 07:14:40 +04:00
|
|
|
DWORD vkcode;
|
|
|
|
DWORD scancode;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-02-22 07:04:09 +04:00
|
|
|
if (!is_connected)
|
2013-02-22 06:42:47 +04:00
|
|
|
return;
|
|
|
|
|
2013-03-11 07:14:40 +04:00
|
|
|
key = [event keyCode] + 8;
|
|
|
|
|
|
|
|
vkcode = GetVirtualKeyCodeFromKeycode(key, KEYCODE_TYPE_APPLE);
|
|
|
|
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4);
|
|
|
|
extended = (scancode & KBDEXT) ? KBDEXT : 0;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, extended | KBD_FLAGS_DOWN, scancode & 0xFF);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when a key is released
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) keyUp:(NSEvent *) event
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
int key;
|
2013-03-15 23:03:48 +04:00
|
|
|
USHORT extended;
|
2013-03-11 07:14:40 +04:00
|
|
|
DWORD vkcode;
|
|
|
|
DWORD scancode;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-02-22 07:04:09 +04:00
|
|
|
if (!is_connected)
|
2013-02-22 06:42:47 +04:00
|
|
|
return;
|
|
|
|
|
2013-03-11 07:14:40 +04:00
|
|
|
key = [event keyCode] + 8;
|
|
|
|
|
|
|
|
vkcode = GetVirtualKeyCodeFromKeycode(key, KEYCODE_TYPE_APPLE);
|
|
|
|
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4);
|
|
|
|
extended = (scancode & KBDEXT) ? KBDEXT : 0;
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, extended | KBD_FLAGS_RELEASE, scancode & 0xFF);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when shift, control, alt and meta keys are pressed/released
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
- (void) flagsChanged:(NSEvent*) event
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
NSUInteger mf = [event modifierFlags];
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
if (!is_connected)
|
2013-02-22 06:42:47 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
// caps lock
|
|
|
|
if (mf == 0x10100) {
|
|
|
|
printf("TODO: caps lock is on\n");
|
|
|
|
kdcapslock = 1;
|
|
|
|
}
|
|
|
|
if (kdcapslock && (mf == 0x100)) {
|
|
|
|
kdcapslock = 0;
|
|
|
|
printf("TODO: caps lock is off\n");
|
|
|
|
}
|
|
|
|
// left shift
|
|
|
|
if ((kdlshift == 0) && ((mf & 2) != 0)) {
|
|
|
|
// left shift went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_DOWN, 0x2a);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlshift = 1;
|
|
|
|
}
|
|
|
|
if ((kdlshift != 0) && ((mf & 2) == 0)) {
|
|
|
|
// left shift went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_RELEASE, 0x2a);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlshift = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// right shift
|
|
|
|
if ((kdrshift == 0) && ((mf & 4) != 0)) {
|
|
|
|
// right shift went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_DOWN, 0x36);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdrshift = 1;
|
|
|
|
}
|
|
|
|
if ((kdrshift != 0) && ((mf & 4) == 0)) {
|
|
|
|
// right shift went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_RELEASE, 0x36);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdrshift = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// left ctrl
|
|
|
|
if ((kdlctrl == 0) && ((mf & 1) != 0)) {
|
|
|
|
// left ctrl went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_DOWN, 0x1d);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlctrl = 1;
|
|
|
|
}
|
|
|
|
if ((kdlctrl != 0) && ((mf & 1) == 0)) {
|
|
|
|
// left ctrl went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_RELEASE, 0x1d);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlctrl = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// right ctrl
|
|
|
|
if ((kdrctrl == 0) && ((mf & 0x2000) != 0)) {
|
|
|
|
// right ctrl went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_DOWN, 0x1d);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdrctrl = 1;
|
|
|
|
}
|
|
|
|
if ((kdrctrl != 0) && ((mf & 0x2000) == 0)) {
|
|
|
|
// right ctrl went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_RELEASE, 0x1d);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdrctrl = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// left alt
|
|
|
|
if ((kdlalt == 0) && ((mf & 0x20) != 0)) {
|
|
|
|
// left alt went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_DOWN, 0x38);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlalt = 1;
|
|
|
|
}
|
|
|
|
if ((kdlalt != 0) && ((mf & 0x20) == 0)) {
|
|
|
|
// left alt went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, KBD_FLAGS_RELEASE, 0x38);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlalt = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// right alt
|
|
|
|
if ((kdralt == 0) && ((mf & 0x40) != 0)) {
|
|
|
|
// right alt went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_DOWN, 0x38);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdralt = 1;
|
|
|
|
}
|
|
|
|
if ((kdralt != 0) && ((mf & 0x40) == 0)) {
|
|
|
|
// right alt went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_RELEASE, 0x38);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdralt = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// left meta
|
|
|
|
if ((kdlmeta == 0) && ((mf & 0x08) != 0)) {
|
|
|
|
// left meta went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_DOWN, 0x5b);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlmeta = 1;
|
|
|
|
}
|
|
|
|
if ((kdlmeta != 0) && ((mf & 0x08) == 0)) {
|
|
|
|
// left meta went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_RELEASE, 0x5b);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdlmeta = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// right meta
|
|
|
|
if ((kdrmeta == 0) && ((mf & 0x10) != 0)) {
|
|
|
|
// right meta went down
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_DOWN, 0x5c);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdrmeta = 1;
|
|
|
|
}
|
|
|
|
if ((kdrmeta != 0) && ((mf & 0x10) == 0)) {
|
|
|
|
// right meta went up
|
2013-06-23 06:55:51 +04:00
|
|
|
instance->input->KeyboardEvent(instance->input, 1 | KBD_FLAGS_RELEASE, 0x5c);
|
2013-02-22 06:42:47 +04:00
|
|
|
kdrmeta = 0;
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) releaseResources
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
{
|
|
|
|
if (argv[i])
|
|
|
|
free(argv[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_connected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
freerdp_channels_global_uninit();
|
|
|
|
|
|
|
|
if (pixel_data)
|
|
|
|
free(pixel_data);
|
2013-06-20 18:03:20 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
if (run_loop_src_update != 0)
|
2013-06-20 18:03:20 +04:00
|
|
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_update, kCFRunLoopDefaultMode);
|
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
if (run_loop_src_input != 0)
|
|
|
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_input, kCFRunLoopDefaultMode);
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-20 18:03:20 +04:00
|
|
|
if (run_loop_src_channels != 0)
|
2013-02-22 06:42:47 +04:00
|
|
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when our view needs refreshing
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
- (void) drawRect:(NSRect)rect
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-06-23 06:55:51 +04:00
|
|
|
if (!context)
|
2013-02-22 06:42:47 +04:00
|
|
|
return;
|
2013-03-11 05:35:06 +04:00
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
if (self->bitmap_context)
|
2013-06-23 04:27:23 +04:00
|
|
|
{
|
2013-06-23 06:55:51 +04:00
|
|
|
CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort];
|
2013-06-23 04:27:23 +04:00
|
|
|
CGImageRef cgImage = CGBitmapContextCreateImage(self->bitmap_context);
|
|
|
|
|
2013-06-23 06:55:51 +04:00
|
|
|
CGContextClipToRect(cgContext, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height));
|
|
|
|
CGContextDrawImage(cgContext, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), cgImage);
|
2013-06-23 04:27:23 +04:00
|
|
|
|
|
|
|
CGImageRelease(cgImage);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// just clear the screen with black
|
|
|
|
[[NSColor redColor] set];
|
|
|
|
NSRectFill([self bounds]);
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2013-02-22 06:42:47 +04:00
|
|
|
instance methods
|
|
|
|
************************************************************************/
|
2012-05-03 07:15:27 +04:00
|
|
|
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when we fail to connect to a RDP server
|
|
|
|
***********************************************************************/
|
|
|
|
|
2012-06-20 20:57:20 +04:00
|
|
|
- (void) rdpConnectError
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
NSString* message = @"Error connecting to server";
|
|
|
|
if (connectErrorCode == AUTHENTICATIONERROR)
|
|
|
|
{
|
|
|
|
message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."];
|
|
|
|
}
|
2013-03-11 05:35:06 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
2013-03-11 05:35:06 +04:00
|
|
|
[alert setMessageText:message];
|
2013-06-18 05:21:42 +04:00
|
|
|
[alert beginSheetModalForWindow:[self window]
|
2013-06-23 04:27:23 +04:00
|
|
|
modalDelegate:self
|
|
|
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
|
|
|
|
contextInfo:nil];
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2012-06-20 20:57:20 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* called when we fail to launch remote app on RDP server
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
- (void) rdpRemoteAppError
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
|
|
|
[alert setMessageText:@"Error starting remote app on specified server"];
|
2013-06-18 05:21:42 +04:00
|
|
|
[alert beginSheetModalForWindow:[self window]
|
2013-06-23 04:27:23 +04:00
|
|
|
modalDelegate:self
|
|
|
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
|
|
|
|
contextInfo:nil];
|
2012-06-20 20:57:20 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* just a terminate selector for above call
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
[NSApp terminate:nil];
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
- (void) onPasteboardTimerFired :(NSTimer*) timer
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 08:07:35 +04:00
|
|
|
int i;
|
|
|
|
NSArray* types;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
|
|
|
i = (int) [pasteboard_rd changeCount];
|
2013-02-22 07:04:09 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
if (i != pasteboard_changecount)
|
|
|
|
{
|
|
|
|
pasteboard_changecount = i;
|
|
|
|
types = [NSArray arrayWithObject:NSStringPboardType];
|
|
|
|
NSString *str = [pasteboard_rd availableTypeFromArray:types];
|
|
|
|
if (str != nil)
|
|
|
|
{
|
2013-06-23 06:55:51 +04:00
|
|
|
cliprdr_send_supported_format_list(instance);
|
2013-02-22 06:42:47 +04:00
|
|
|
}
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2012-06-20 20:57:20 +04:00
|
|
|
- (void) setViewSize : (int) w : (int) h
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
// store current dimensions
|
|
|
|
width = w;
|
|
|
|
height = h;
|
|
|
|
|
|
|
|
// compute difference between window and client area
|
2013-06-18 05:21:42 +04:00
|
|
|
NSRect outerRect = [[self window] frame];
|
|
|
|
NSRect innerRect = [self frame];
|
2013-02-22 06:42:47 +04:00
|
|
|
|
|
|
|
int widthDiff = outerRect.size.width - innerRect.size.width;
|
|
|
|
int heightDiff = outerRect.size.height - innerRect.size.height;
|
|
|
|
|
2013-06-18 00:44:44 +04:00
|
|
|
// we are not in RemoteApp mode, disable resizing
|
|
|
|
outerRect.size.width = w + widthDiff;
|
|
|
|
outerRect.size.height = h + heightDiff;
|
2013-06-18 05:21:42 +04:00
|
|
|
[[self window] setMaxSize:outerRect.size];
|
|
|
|
[[self window] setMinSize:outerRect.size];
|
2013-07-03 00:13:43 +04:00
|
|
|
|
|
|
|
@try
|
|
|
|
{
|
|
|
|
[[self window] setFrame:outerRect display:YES];
|
|
|
|
}
|
|
|
|
@catch (NSException * e) {
|
|
|
|
NSLog(@"Exception: %@", e);
|
|
|
|
}
|
|
|
|
@finally {
|
|
|
|
}
|
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
// set client area to specified dimensions
|
2013-06-18 00:44:44 +04:00
|
|
|
innerRect.size.width = w;
|
|
|
|
innerRect.size.height = h;
|
2013-06-18 05:21:42 +04:00
|
|
|
[self setFrame:innerRect];
|
2012-06-20 20:57:20 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
/************************************************************************
|
|
|
|
* *
|
|
|
|
* C functions *
|
|
|
|
* *
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* a callback given to freerdp_connect() to process the pre-connect operations.
|
|
|
|
*
|
2013-02-22 06:42:47 +04:00
|
|
|
* @param inst - pointer to a rdp_freerdp struct that contains the connection's parameters, and
|
2012-05-03 07:15:27 +04:00
|
|
|
* will be filled with the appropriate informations.
|
|
|
|
*
|
|
|
|
* @return true if successful. false otherwise.
|
|
|
|
************************************************************************/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
BOOL mac_pre_connect(freerdp* instance)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-03-11 05:35:06 +04:00
|
|
|
rdpSettings* settings;
|
|
|
|
BOOL bitmap_cache;
|
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
// setup callbacks
|
2013-02-22 08:07:35 +04:00
|
|
|
instance->update->BeginPaint = mac_begin_paint;
|
|
|
|
instance->update->EndPaint = mac_end_paint;
|
|
|
|
instance->update->SetBounds = mac_set_bounds;
|
2013-03-11 05:35:06 +04:00
|
|
|
//instance->update->BitmapUpdate = mac_bitmap_update;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext *mfc = (mfContext*) instance->context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
|
|
|
|
|
|
|
settings = instance->settings;
|
|
|
|
|
|
|
|
if (!settings->ServerHostname)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "error: server hostname was not specified with /v:<server>[:port]\n");
|
|
|
|
[NSApp terminate:nil];
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
freerdp_client_load_addins(instance->context->channels, instance->settings);
|
2013-03-11 05:35:06 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
settings = instance->settings;
|
2013-03-11 05:35:06 +04:00
|
|
|
bitmap_cache = settings->BitmapCacheEnabled;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
instance->settings->ColorDepth = 32;
|
|
|
|
instance->settings->SoftwareGdi = TRUE;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
settings->OsMajorType = OSMAJORTYPE_UNIX;
|
2013-03-11 05:35:06 +04:00
|
|
|
settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_MEMBLT_INDEX] = bitmap_cache;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
settings->OrderSupport[NEG_MEM3BLT_INDEX] = (settings->SoftwareGdi) ? TRUE : FALSE;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
|
|
|
|
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
|
|
|
|
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
|
|
|
|
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = (settings->SoftwareGdi) ? FALSE : TRUE;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 05:35:06 +04:00
|
|
|
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
|
|
|
|
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-07-03 00:13:43 +04:00
|
|
|
[view setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight];
|
2013-02-22 08:07:35 +04:00
|
|
|
freerdp_channels_pre_connect(instance->context->channels, instance);
|
2013-03-11 08:35:15 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
return TRUE;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* a callback registered with freerdp_connect() to perform post-connection operations.
|
2013-02-22 06:42:47 +04:00
|
|
|
* we get called only if the connection was initialized properly, and will continue
|
2012-05-03 07:15:27 +04:00
|
|
|
* the initialization based on the newly created connection.
|
|
|
|
*
|
|
|
|
* @param inst - pointer to a rdp_freerdp struct
|
|
|
|
*
|
|
|
|
* @return true on success, false on failure
|
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
BOOL mac_post_connect(freerdp* instance)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 08:07:35 +04:00
|
|
|
UINT32 flags;
|
2013-02-22 06:42:47 +04:00
|
|
|
rdpPointer rdp_pointer;
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext *mfc = (mfContext*) instance->context;
|
|
|
|
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
ZeroMemory(&rdp_pointer, sizeof(rdpPointer));
|
2013-02-22 06:42:47 +04:00
|
|
|
rdp_pointer.size = sizeof(rdpPointer);
|
2013-03-11 20:14:44 +04:00
|
|
|
rdp_pointer.New = mf_Pointer_New;
|
|
|
|
rdp_pointer.Free = mf_Pointer_Free;
|
|
|
|
rdp_pointer.Set = mf_Pointer_Set;
|
|
|
|
rdp_pointer.SetNull = mf_Pointer_SetNull;
|
|
|
|
rdp_pointer.SetDefault = mf_Pointer_SetDefault;
|
2013-03-11 05:35:06 +04:00
|
|
|
|
2013-07-16 20:16:44 +04:00
|
|
|
flags = CLRBUF_32BPP | CLRCONV_ALPHA;
|
2013-02-22 08:07:35 +04:00
|
|
|
gdi_init(instance, flags, NULL);
|
2013-03-11 05:35:06 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
rdpGdi* gdi = instance->context->gdi;
|
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
2013-06-18 22:30:21 +04:00
|
|
|
view->bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->width * 4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
|
2013-03-11 05:35:06 +04:00
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
pointer_cache_register_callbacks(instance->update);
|
|
|
|
graphics_register_pointer(instance->context->graphics, &rdp_pointer);
|
2013-06-23 04:27:23 +04:00
|
|
|
|
|
|
|
freerdp_channels_post_connect(instance->context->channels, instance);
|
2013-05-31 20:48:40 +04:00
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
/* setup pasteboard (aka clipboard) for copy operations (write only) */
|
2013-06-18 22:30:21 +04:00
|
|
|
view->pasteboard_wr = [NSPasteboard generalPasteboard];
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
/* setup pasteboard for read operations */
|
2013-06-18 22:30:21 +04:00
|
|
|
view->pasteboard_rd = [NSPasteboard generalPasteboard];
|
|
|
|
view->pasteboard_changecount = (int) [view->pasteboard_rd changeCount];
|
|
|
|
view->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:mfc->view selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES];
|
2013-06-20 18:03:20 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
return TRUE;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:03:20 +04:00
|
|
|
|
2013-03-11 05:32:05 +04:00
|
|
|
BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain)
|
|
|
|
{
|
2013-03-11 20:14:44 +04:00
|
|
|
PasswordDialog* dialog = [PasswordDialog new];
|
2013-03-11 05:32:05 +04:00
|
|
|
|
2013-03-11 22:59:50 +04:00
|
|
|
dialog.serverHostname = [NSString stringWithCString:instance->settings->ServerHostname encoding:NSUTF8StringEncoding];
|
2013-03-11 05:32:05 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
if (*username)
|
2013-03-11 22:59:50 +04:00
|
|
|
dialog.username = [NSString stringWithCString:*username encoding:NSUTF8StringEncoding];
|
2013-03-11 05:32:05 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
if (*password)
|
|
|
|
dialog.password = [NSString stringWithCString:*password encoding:NSUTF8StringEncoding];
|
2013-03-11 05:32:05 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
BOOL ok = [dialog runModal];
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
if (ok)
|
|
|
|
{
|
2013-03-11 22:59:50 +04:00
|
|
|
const char* submittedUsername = [dialog.username cStringUsingEncoding:NSUTF8StringEncoding];
|
2013-03-11 08:35:15 +04:00
|
|
|
*username = malloc((strlen(submittedUsername) + 1) * sizeof(char));
|
|
|
|
strcpy(*username, submittedUsername);
|
2013-03-11 05:32:05 +04:00
|
|
|
|
2013-03-11 08:35:15 +04:00
|
|
|
const char* submittedPassword = [dialog.password cStringUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
*password = malloc((strlen(submittedPassword) + 1) * sizeof(char));
|
|
|
|
strcpy(*password, submittedPassword);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
2013-03-11 05:32:05 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* create a new mouse cursor
|
|
|
|
*
|
|
|
|
* @param context our context state
|
|
|
|
* @param pointer information about the cursor to create
|
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
void mf_Pointer_New(rdpContext* context, rdpPointer* pointer)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-03-11 20:14:44 +04:00
|
|
|
NSRect rect;
|
|
|
|
NSImage* image;
|
|
|
|
NSPoint hotSpot;
|
|
|
|
NSCursor* cursor;
|
2013-02-22 08:07:35 +04:00
|
|
|
BYTE* cursor_data;
|
2013-03-11 20:14:44 +04:00
|
|
|
NSMutableArray* ma;
|
|
|
|
NSBitmapImageRep* bmiRep;
|
|
|
|
MRDPCursor* mrdpCursor = [[MRDPCursor alloc] init];
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc = (mfContext*) context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
|
|
|
rect.size.width = pointer->width;
|
|
|
|
rect.size.height = pointer->height;
|
|
|
|
rect.origin.x = pointer->xPos;
|
|
|
|
rect.origin.y = pointer->yPos;
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
cursor_data = (BYTE*) malloc(rect.size.width * rect.size.height * 4);
|
2013-02-22 06:42:47 +04:00
|
|
|
mrdpCursor->cursor_data = cursor_data;
|
|
|
|
|
2013-07-16 20:16:44 +04:00
|
|
|
if (pointer->xorBpp > 24)
|
|
|
|
{
|
|
|
|
freerdp_image_swap_color_order(pointer->xorMaskData, pointer->width, pointer->height);
|
|
|
|
}
|
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
freerdp_alpha_cursor_convert(cursor_data, pointer->xorMaskData, pointer->andMaskData,
|
|
|
|
pointer->width, pointer->height, pointer->xorBpp, context->gdi->clrconv);
|
|
|
|
|
|
|
|
// TODO if xorBpp is > 24 need to call freerdp_image_swap_color_order
|
|
|
|
// see file df_graphics.c
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
/* store cursor bitmap image in representation - required by NSImage */
|
2013-02-22 06:42:47 +04:00
|
|
|
bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data
|
2013-06-23 04:27:23 +04:00
|
|
|
pixelsWide:rect.size.width
|
|
|
|
pixelsHigh:rect.size.height
|
|
|
|
bitsPerSample:8
|
|
|
|
samplesPerPixel:4
|
|
|
|
hasAlpha:YES
|
|
|
|
isPlanar:NO
|
|
|
|
colorSpaceName:NSDeviceRGBColorSpace
|
|
|
|
bitmapFormat:0
|
|
|
|
bytesPerRow:rect.size.width * 4
|
|
|
|
bitsPerPixel:0];
|
2013-02-22 06:42:47 +04:00
|
|
|
mrdpCursor->bmiRep = bmiRep;
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
/* create an image using above representation */
|
|
|
|
image = [[NSImage alloc] initWithSize:[bmiRep size]];
|
2013-02-22 06:42:47 +04:00
|
|
|
[image addRepresentation: bmiRep];
|
|
|
|
[image setFlipped:NO];
|
|
|
|
mrdpCursor->nsImage = image;
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
/* need hotspot to create cursor */
|
2013-02-22 06:42:47 +04:00
|
|
|
hotSpot.x = pointer->xPos;
|
|
|
|
hotSpot.y = pointer->yPos;
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
cursor = [[NSCursor alloc] initWithImage: image hotSpot:hotSpot];
|
2013-02-22 06:42:47 +04:00
|
|
|
mrdpCursor->nsCursor = cursor;
|
|
|
|
mrdpCursor->pointer = pointer;
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
/* save cursor for later use in mf_Pointer_Set() */
|
2013-06-18 22:30:21 +04:00
|
|
|
ma = view->cursors;
|
2013-02-22 06:42:47 +04:00
|
|
|
[ma addObject:mrdpCursor];
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* release resources on specified cursor
|
|
|
|
************************************************************************/
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
void mf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc = (mfContext*) context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
2013-06-18 22:30:21 +04:00
|
|
|
NSMutableArray* ma = view->cursors;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
for (MRDPCursor* cursor in ma)
|
2013-02-22 06:42:47 +04:00
|
|
|
{
|
2013-02-22 07:04:09 +04:00
|
|
|
if (cursor->pointer == pointer)
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
cursor->nsImage = nil;
|
|
|
|
cursor->nsCursor = nil;
|
|
|
|
cursor->bmiRep = nil;
|
|
|
|
free(cursor->cursor_data);
|
|
|
|
[ma removeObject:cursor];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* set specified cursor as the current cursor
|
|
|
|
************************************************************************/
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
void mf_Pointer_Set(rdpContext* context, rdpPointer* pointer)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc = (mfContext*) context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
|
|
|
|
2013-06-18 22:30:21 +04:00
|
|
|
NSMutableArray* ma = view->cursors;
|
2013-03-19 07:28:19 +04:00
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
for (MRDPCursor* cursor in ma)
|
2013-02-22 06:42:47 +04:00
|
|
|
{
|
2013-02-22 07:04:09 +04:00
|
|
|
if (cursor->pointer == pointer)
|
|
|
|
{
|
2013-07-16 20:16:44 +04:00
|
|
|
[view setCursor:cursor->nsCursor];
|
2013-02-22 06:42:47 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-07-16 20:16:44 +04:00
|
|
|
|
|
|
|
NSLog(@"Cursor not found");
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* do not display any mouse cursor
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
void mf_Pointer_SetNull(rdpContext* context)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-03-19 07:28:19 +04:00
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* display default mouse cursor
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
void mf_Pointer_SetDefault(rdpContext* context)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-07-16 20:16:44 +04:00
|
|
|
mfContext* mfc = (mfContext*) context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
|
|
|
[view setCursor:[NSCursor arrowCursor]];
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* clip drawing surface so nothing is drawn outside specified bounds
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void mac_set_bounds(rdpContext* context, rdpBounds* bounds)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-03-19 07:28:19 +04:00
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* we don't do much over here
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void mac_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-03-19 07:28:19 +04:00
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* we don't do much over here
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void mac_begin_paint(rdpContext* context)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
rdpGdi* gdi = context->gdi;
|
|
|
|
gdi->primary->hdc->hwnd->invalid->null = 1;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* RDP server wants us to draw new data in the view
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
void mac_end_paint(rdpContext* context)
|
|
|
|
{
|
2013-02-22 08:07:35 +04:00
|
|
|
int i;
|
|
|
|
rdpGdi* gdi;
|
|
|
|
NSRect drawRect;
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc = (mfContext*) context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
2013-02-22 06:42:47 +04:00
|
|
|
|
|
|
|
if ((context == 0) || (context->gdi == 0))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (context->gdi->primary->hdc->hwnd->invalid->null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (context->gdi->drawing != context->gdi->primary)
|
|
|
|
return;
|
|
|
|
|
2013-06-18 05:21:42 +04:00
|
|
|
gdi = context->gdi;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++)
|
|
|
|
{
|
2013-07-11 22:19:21 +04:00
|
|
|
drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x - 1;
|
|
|
|
drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y - 1;
|
|
|
|
drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w + 1;
|
|
|
|
drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h + 1;
|
2013-06-18 05:21:42 +04:00
|
|
|
windows_to_apple_cords(mfc->view, &drawRect);
|
2013-06-18 22:30:21 +04:00
|
|
|
[view setNeedsDisplayInRect:drawRect];
|
2013-02-22 06:42:47 +04:00
|
|
|
}
|
2013-02-22 07:04:09 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
gdi->primary->hdc->hwnd->ninvalid = 0;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:03:20 +04:00
|
|
|
|
|
|
|
/** *********************************************************************
|
2013-06-21 04:55:49 +04:00
|
|
|
* called when update data is available
|
2013-06-20 18:03:20 +04:00
|
|
|
***********************************************************************/
|
|
|
|
|
2013-06-20 23:00:50 +04:00
|
|
|
static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
|
2013-06-20 18:03:20 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
int status;
|
|
|
|
wMessage message;
|
|
|
|
wMessageQueue* queue;
|
|
|
|
freerdp* instance = (freerdp*) info;
|
|
|
|
|
|
|
|
status = 1;
|
|
|
|
queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
|
|
|
|
|
|
|
|
if (queue)
|
|
|
|
{
|
|
|
|
while (MessageQueue_Peek(queue, &message, TRUE))
|
|
|
|
{
|
|
|
|
status = freerdp_message_queue_process_message(instance, FREERDP_UPDATE_MESSAGE_QUEUE, &message);
|
|
|
|
|
|
|
|
if (!status)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease(fdref);
|
|
|
|
register_update_fds(instance);
|
2013-06-20 18:03:20 +04:00
|
|
|
}
|
|
|
|
|
2013-06-21 04:55:49 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* called when input data is available
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
|
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
int status;
|
|
|
|
wMessage message;
|
|
|
|
wMessageQueue* queue;
|
|
|
|
freerdp* instance = (freerdp*) info;
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
status = 1;
|
|
|
|
queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
if (queue)
|
|
|
|
{
|
|
|
|
while (MessageQueue_Peek(queue, &message, TRUE))
|
|
|
|
{
|
|
|
|
fprintf(stderr, "input_activity_cb: message %d\n", message.id);
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, &message);
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
if (!status)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-06-21 04:55:49 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
CFRelease(fdref);
|
|
|
|
register_input_fds(instance);
|
2013-06-21 04:55:49 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* called when data is available on a virtual channel
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-06-21 04:55:49 +04:00
|
|
|
static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info)
|
2013-02-22 06:42:47 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
wMessage* event;
|
2013-02-22 08:07:35 +04:00
|
|
|
freerdp* instance = (freerdp*) info;
|
2013-06-20 23:00:50 +04:00
|
|
|
|
2013-06-23 04:27:23 +04:00
|
|
|
freerdp_channels_process_pending_messages(instance);
|
|
|
|
event = freerdp_channels_pop_event(instance->context->channels);
|
|
|
|
if (event)
|
|
|
|
{
|
|
|
|
switch (GetMessageClass(event->id))
|
|
|
|
{
|
|
|
|
case CliprdrChannel_Class:
|
|
|
|
process_cliprdr_event(instance, event);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
freerdp_event_free(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease(fdref);
|
|
|
|
register_channels_fds(instance);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:03:20 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* setup callbacks for data availability on update message queue
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
int register_update_fds(freerdp* instance)
|
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
int fd_update_event;
|
|
|
|
HANDLE update_event;
|
|
|
|
CFFileDescriptorRef fdref;
|
|
|
|
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
|
|
|
|
mfContext* mfc = (mfContext*) instance->context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
|
|
|
|
|
|
|
if (instance->settings->AsyncUpdate)
|
|
|
|
{
|
|
|
|
update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE);
|
|
|
|
fd_update_event = GetEventFileDescriptor(update_event);
|
|
|
|
|
|
|
|
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_update_event, true, update_activity_cb, &fd_context);
|
|
|
|
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
|
|
|
|
view->run_loop_src_update = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
|
|
|
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_update, kCFRunLoopDefaultMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2013-06-20 18:03:20 +04:00
|
|
|
}
|
|
|
|
|
2013-06-21 04:55:49 +04:00
|
|
|
/** *********************************************************************
|
|
|
|
* setup callbacks for data availability on input message queue
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
int register_input_fds(freerdp* instance)
|
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
int fd_input_event;
|
|
|
|
HANDLE input_event;
|
|
|
|
CFFileDescriptorRef fdref;
|
|
|
|
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
|
|
|
|
mfContext* mfc = (mfContext*) instance->context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
|
|
|
|
|
|
|
if (instance->settings->AsyncInput)
|
|
|
|
{
|
|
|
|
input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE);
|
|
|
|
fd_input_event = GetEventFileDescriptor(input_event);
|
|
|
|
|
|
|
|
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_input_event, true, input_activity_cb, &fd_context);
|
|
|
|
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
|
|
|
|
view->run_loop_src_input = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
|
|
|
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_input, kCFRunLoopDefaultMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2013-06-21 04:55:49 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
/** *********************************************************************
|
2013-02-22 06:42:47 +04:00
|
|
|
* setup callbacks for data availability on channels
|
2012-05-03 07:15:27 +04:00
|
|
|
***********************************************************************/
|
|
|
|
|
2013-06-20 23:00:50 +04:00
|
|
|
int register_channels_fds(freerdp* instance)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
int fd_channel_event;
|
|
|
|
HANDLE channel_event;
|
|
|
|
CFFileDescriptorRef fdref;
|
|
|
|
CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL };
|
|
|
|
mfContext* mfc = (mfContext*) instance->context;
|
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
|
|
|
|
|
|
|
if (instance->settings->AsyncChannels)
|
|
|
|
{
|
|
|
|
channel_event = freerdp_channels_get_event_handle(instance);
|
|
|
|
fd_channel_event = GetEventFileDescriptor(channel_event);
|
|
|
|
|
|
|
|
fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_channel_event, true, channel_activity_cb, &fd_context);
|
|
|
|
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
|
|
|
|
view->run_loop_src_channels = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
|
|
|
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_channels, kCFRunLoopDefaultMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** *********************************************************************
|
|
|
|
* called when channel data is available
|
|
|
|
***********************************************************************/
|
|
|
|
|
2013-06-21 00:45:27 +04:00
|
|
|
int mac_receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 08:07:35 +04:00
|
|
|
return freerdp_channels_data(instance, chan_id, data, size, flags, total_size);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
/**
|
2012-05-03 07:15:27 +04:00
|
|
|
* Used to load plugins based on the commandline parameters.
|
|
|
|
* This function is provided as a parameter to freerdp_parse_args(), that will call it
|
|
|
|
* each time a plugin name is found on the command line.
|
|
|
|
* This function just calls freerdp_channels_load_plugin() for the given plugin, and always returns 1.
|
2013-02-22 06:42:47 +04:00
|
|
|
*
|
2012-05-03 07:15:27 +04:00
|
|
|
* @param settings
|
|
|
|
* @param name
|
|
|
|
* @param plugin_data
|
|
|
|
* @param user_data
|
2013-02-22 06:42:47 +04:00
|
|
|
*
|
2012-05-03 07:15:27 +04:00
|
|
|
* @return 1
|
|
|
|
*/
|
|
|
|
|
|
|
|
int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data)
|
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
rdpChannels* channels = (rdpChannels*) user_data;
|
|
|
|
|
|
|
|
freerdp_channels_load_plugin(channels, settings, name, plugin_data);
|
2013-02-22 08:07:35 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
return 1;
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* stuff related to clipboard redirection
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* remote system has requested clipboard data from local system
|
|
|
|
*/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void cliprdr_process_cb_data_request_event(freerdp* instance)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 08:07:35 +04:00
|
|
|
int len;
|
|
|
|
NSArray* types;
|
|
|
|
RDP_CB_DATA_RESPONSE_EVENT* event;
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc = (mfContext*) instance->context;
|
2013-06-18 22:30:21 +04:00
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-03-29 08:15:29 +04:00
|
|
|
event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataResponse, NULL, NULL);
|
2013-02-22 07:04:09 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
types = [NSArray arrayWithObject:NSStringPboardType];
|
2013-06-18 22:30:21 +04:00
|
|
|
NSString* str = [view->pasteboard_rd availableTypeFromArray:types];
|
2013-02-22 07:04:09 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
if (str == nil)
|
|
|
|
{
|
|
|
|
event->data = NULL;
|
|
|
|
event->size = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-18 22:30:21 +04:00
|
|
|
NSString* data = [view->pasteboard_rd stringForType:NSStringPboardType];
|
2013-02-22 06:42:47 +04:00
|
|
|
len = (int) ([data length] * 2 + 2);
|
|
|
|
event->data = malloc(len);
|
|
|
|
[data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding];
|
|
|
|
event->size = len;
|
|
|
|
}
|
2013-02-22 07:04:09 +04:00
|
|
|
|
2013-03-29 08:15:29 +04:00
|
|
|
freerdp_channels_send_event(instance->context->channels, (wMessage*) event);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void cliprdr_send_data_request(freerdp* instance, UINT32 format)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
RDP_CB_DATA_REQUEST_EVENT* event;
|
|
|
|
|
2013-03-29 08:15:29 +04:00
|
|
|
event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataRequest, NULL, NULL);
|
2013-02-22 08:07:35 +04:00
|
|
|
|
2013-02-22 06:42:47 +04:00
|
|
|
event->format = format;
|
2013-03-29 08:15:29 +04:00
|
|
|
freerdp_channels_send_event(instance->context->channels, (wMessage*) event);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* at the moment, only the following formats are supported
|
|
|
|
* CB_FORMAT_TEXT
|
|
|
|
* CB_FORMAT_UNICODETEXT
|
|
|
|
*/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 08:07:35 +04:00
|
|
|
NSString* str;
|
|
|
|
NSArray* types;
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc = (mfContext*) instance->context;
|
2013-06-18 22:30:21 +04:00
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-02-22 07:04:09 +04:00
|
|
|
if (event->size == 0)
|
2013-02-22 06:42:47 +04:00
|
|
|
return;
|
|
|
|
|
2013-06-18 22:30:21 +04:00
|
|
|
if (view->pasteboard_format == CB_FORMAT_TEXT || view->pasteboard_format == CB_FORMAT_UNICODETEXT)
|
2013-02-22 07:04:09 +04:00
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2];
|
|
|
|
types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil];
|
2013-06-18 22:30:21 +04:00
|
|
|
[view->pasteboard_wr declareTypes:types owner:mfc->view];
|
|
|
|
[view->pasteboard_wr setString:str forType:NSStringPboardType];
|
2013-02-22 06:42:47 +04:00
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void cliprdr_process_cb_monitor_ready_event(freerdp* instance)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-03-29 08:15:29 +04:00
|
|
|
wMessage* event;
|
2013-02-22 06:42:47 +04:00
|
|
|
RDP_CB_FORMAT_LIST_EVENT* format_list_event;
|
|
|
|
|
2013-03-29 08:15:29 +04:00
|
|
|
event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL);
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-03-11 20:14:44 +04:00
|
|
|
format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event;
|
2013-02-22 06:42:47 +04:00
|
|
|
format_list_event->num_formats = 0;
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
freerdp_channels_send_event(instance->context->channels, event);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* list of supported clipboard formats; currently only the following are supported
|
|
|
|
* CB_FORMAT_TEXT
|
|
|
|
* CB_FORMAT_UNICODETEXT
|
|
|
|
*/
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
int i;
|
2013-06-23 04:27:23 +04:00
|
|
|
mfContext* mfc = (mfContext*) instance->context;
|
2013-06-18 22:30:21 +04:00
|
|
|
MRDPView* view = (MRDPView*) mfc->view;
|
2013-06-23 04:27:23 +04:00
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
if (event->num_formats == 0)
|
2013-02-22 06:42:47 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < event->num_formats; i++)
|
|
|
|
{
|
|
|
|
switch (event->formats[i])
|
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
case CB_FORMAT_RAW:
|
|
|
|
printf("CB_FORMAT_RAW: not yet supported\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_FORMAT_TEXT:
|
|
|
|
case CB_FORMAT_UNICODETEXT:
|
|
|
|
view->pasteboard_format = CB_FORMAT_UNICODETEXT;
|
|
|
|
cliprdr_send_data_request(instance, CB_FORMAT_UNICODETEXT);
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_FORMAT_DIB:
|
|
|
|
printf("CB_FORMAT_DIB: not yet supported\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_FORMAT_HTML:
|
|
|
|
printf("CB_FORMAT_HTML\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_FORMAT_PNG:
|
|
|
|
printf("CB_FORMAT_PNG: not yet supported\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_FORMAT_JPEG:
|
|
|
|
printf("CB_FORMAT_JPEG: not yet supported\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CB_FORMAT_GIF:
|
|
|
|
printf("CB_FORMAT_GIF: not yet supported\n");
|
|
|
|
break;
|
2013-02-22 06:42:47 +04:00
|
|
|
}
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-03-29 08:15:29 +04:00
|
|
|
void process_cliprdr_event(freerdp* instance, wMessage* event)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 07:04:09 +04:00
|
|
|
if (event)
|
|
|
|
{
|
2013-03-29 08:15:29 +04:00
|
|
|
switch (GetMessageType(event->id))
|
2013-02-22 06:42:47 +04:00
|
|
|
{
|
2013-06-23 04:27:23 +04:00
|
|
|
/*
|
2013-03-11 20:14:44 +04:00
|
|
|
* Monitor Ready PDU is sent by server to indicate that it has been
|
|
|
|
* initialized and is ready. This PDU is transmitted by the server after it has sent
|
|
|
|
* Clipboard Capabilities PDU
|
|
|
|
*/
|
2013-06-23 04:27:23 +04:00
|
|
|
case CliprdrChannel_MonitorReady:
|
|
|
|
cliprdr_process_cb_monitor_ready_event(instance);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
2013-03-11 20:14:44 +04:00
|
|
|
* The Format List PDU is sent either by the client or the server when its
|
|
|
|
* local system clipboard is updated with new clipboard data. This PDU
|
|
|
|
* contains the Clipboard Format ID and name pairs of the new Clipboard
|
|
|
|
* Formats on the clipboard
|
|
|
|
*/
|
2013-06-23 04:27:23 +04:00
|
|
|
case CliprdrChannel_FormatList:
|
|
|
|
cliprdr_process_cb_format_list_event(instance, (RDP_CB_FORMAT_LIST_EVENT*) event);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
2013-03-11 20:14:44 +04:00
|
|
|
* The Format Data Request PDU is sent by the receipient of the Format List PDU.
|
|
|
|
* It is used to request the data for one of the formats that was listed in the
|
|
|
|
* Format List PDU
|
|
|
|
*/
|
2013-06-23 04:27:23 +04:00
|
|
|
case CliprdrChannel_DataRequest:
|
|
|
|
cliprdr_process_cb_data_request_event(instance);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
2013-03-11 20:14:44 +04:00
|
|
|
* The Format Data Response PDU is sent as a reply to the Format Data Request PDU.
|
|
|
|
* It is used to indicate whether processing of the Format Data Request PDU
|
|
|
|
* was successful. If the processing was successful, the Format Data Response PDU
|
|
|
|
* includes the contents of the requested clipboard data
|
|
|
|
*/
|
2013-06-23 04:27:23 +04:00
|
|
|
case CliprdrChannel_DataResponse:
|
|
|
|
cliprdr_process_cb_data_response_event(instance, (RDP_CB_DATA_RESPONSE_EVENT*) event);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
printf("process_cliprdr_event: unknown event type %d\n", GetMessageType(event->id));
|
|
|
|
break;
|
2013-02-22 06:42:47 +04:00
|
|
|
}
|
|
|
|
}
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
void cliprdr_send_supported_format_list(freerdp* instance)
|
2012-05-03 07:15:27 +04:00
|
|
|
{
|
2013-02-22 06:42:47 +04:00
|
|
|
RDP_CB_FORMAT_LIST_EVENT* event;
|
|
|
|
|
2013-03-29 08:15:29 +04:00
|
|
|
event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL);
|
2013-02-22 06:42:47 +04:00
|
|
|
|
2013-02-22 08:07:35 +04:00
|
|
|
event->formats = (UINT32*) malloc(sizeof(UINT32) * 1);
|
2013-02-22 06:42:47 +04:00
|
|
|
event->num_formats = 1;
|
|
|
|
event->formats[0] = CB_FORMAT_UNICODETEXT;
|
2013-02-22 08:07:35 +04:00
|
|
|
|
2013-03-29 08:15:29 +04:00
|
|
|
freerdp_channels_send_event(instance->context->channels, (wMessage*) event);
|
2012-05-03 07:15:27 +04:00
|
|
|
}
|
|
|
|
|
2012-06-20 20:57:20 +04:00
|
|
|
/**
|
|
|
|
* given a rect with 0,0 at the top left (windows cords)
|
|
|
|
* convert it to a rect with 0,0 at the bottom left (apple cords)
|
2013-07-16 20:16:44 +04:00
|
|
|
*
|
|
|
|
* Note: the formula works for conversions in both directions.
|
|
|
|
*
|
2012-06-20 20:57:20 +04:00
|
|
|
*/
|
|
|
|
|
2013-06-18 05:21:42 +04:00
|
|
|
void windows_to_apple_cords(MRDPView* view, NSRect* r)
|
2012-06-20 20:57:20 +04:00
|
|
|
{
|
2013-06-18 05:21:42 +04:00
|
|
|
r->origin.y = view->height - (r->origin.y + r->size.height);
|
2012-06-20 20:57:20 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 07:15:27 +04:00
|
|
|
@end
|