From 1cbf3dab21428d144c2f6ddb2579412053f61eae Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Wed, 2 May 2012 20:15:27 -0700 Subject: [PATCH 01/27] Initial push for the native Mac FreeRDP client --- CMakeLists.txt | 1 + channels/rdpsnd/CMakeLists.txt | 4 + channels/rdpsnd/mac_audio/CMakeLists.txt | 36 + channels/rdpsnd/mac_audio/rdpsnd_audio_q.c | 241 ++++ channels/rdpsnd/rdpsnd_main.c | 7 +- client/Mac/MRDPCursor.h | 25 + client/Mac/MRDPCursor.m | 12 + client/Mac/MRDPView.h | 144 ++ client/Mac/MRDPView.m | 1519 ++++++++++++++++++++ client/Mac/README.txt | 140 ++ freerdp.spec | 1 + 11 files changed, 2129 insertions(+), 1 deletion(-) create mode 100644 channels/rdpsnd/mac_audio/CMakeLists.txt create mode 100644 channels/rdpsnd/mac_audio/rdpsnd_audio_q.c create mode 100644 client/Mac/MRDPCursor.h create mode 100644 client/Mac/MRDPCursor.m create mode 100644 client/Mac/MRDPView.h create mode 100644 client/Mac/MRDPView.m create mode 100644 client/Mac/README.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e5d96325..71d133634 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,7 @@ endif() if(NOT WIN32) find_required_package(ZLIB) find_optional_package(PulseAudio) + find_optional_package(MacAudio) find_optional_package(PCSC) find_suggested_package(Cups) diff --git a/channels/rdpsnd/CMakeLists.txt b/channels/rdpsnd/CMakeLists.txt index 3065ac63e..c7d6a7054 100644 --- a/channels/rdpsnd/CMakeLists.txt +++ b/channels/rdpsnd/CMakeLists.txt @@ -37,3 +37,7 @@ if(WITH_PULSEAUDIO) add_subdirectory(pulse) endif() +if(WITH_MACAUDIO) + add_subdirectory(mac_audio) +endif() + diff --git a/channels/rdpsnd/mac_audio/CMakeLists.txt b/channels/rdpsnd/mac_audio/CMakeLists.txt new file mode 100644 index 000000000..63cb82b95 --- /dev/null +++ b/channels/rdpsnd/mac_audio/CMakeLists.txt @@ -0,0 +1,36 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP cmake build script +# +# Copyright 2012 Laxmikant Rashinkar +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# 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. + +set(RDPSND_MACAUDIO_SRCS + rdpsnd_audio_q.c +) + +include_directories(..) +include_directories(${MACAUDIO_INCLUDE_DIRS}) + +add_library(rdpsnd_macaudio ${RDPSND_MACAUDIO_SRCS}) +set_target_properties(rdpsnd_macaudio PROPERTIES PREFIX "") + +target_link_libraries(rdpsnd_macaudio freerdp-utils) +target_link_libraries(rdpsnd_macaudio ${MAC_AUDIOTOOLBOX_LIBRARY_PATH}) +target_link_libraries(rdpsnd_macaudio ${MAC_COREFOUNDATION_LIBRARY_PATH}) + +install(TARGETS rdpsnd_macaudio DESTINATION ${FREERDP_PLUGIN_PATH}) + diff --git a/channels/rdpsnd/mac_audio/rdpsnd_audio_q.c b/channels/rdpsnd/mac_audio/rdpsnd_audio_q.c new file mode 100644 index 000000000..b982e54c9 --- /dev/null +++ b/channels/rdpsnd/mac_audio/rdpsnd_audio_q.c @@ -0,0 +1,241 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Audio Output Virtual Channel + * + * Copyright 2012 Laxmikant Rashinkar + * + * 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. + */ + +/** + * Use AudioQueue to implement audio redirection + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rdpsnd_main.h" + +#define GOT_HERE printf(">>>>> got here: %s %s %d\n", __FILE__, __func__, __LINE__) + +#define AQ_NUM_BUFFERS 10 +#define AQ_BUF_SIZE (32 * 1024) + +static void aq_playback_cb(void *user_data, + AudioQueueRef aq_ref, + AudioQueueBufferRef aq_buf_ref + ); + +struct rdpsnd_audio_q_plugin +{ + rdpsndDevicePlugin device; + + /* audio queue player state */ + int is_open; // true when audio_q has been inited + char * device_name; + int is_playing; + int buf_index; + + AudioStreamBasicDescription data_format; + AudioQueueRef aq_ref; + AudioQueueBufferRef buffers[AQ_NUM_BUFFERS]; +}; +typedef struct rdpsnd_audio_q_plugin rdpsndAudioQPlugin; + +static void rdpsnd_audio_close(rdpsndDevicePlugin* device) +{ + rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin*) device; + + GOT_HERE; + + AudioQueueStop(aq_plugin_p->aq_ref, 0); + aq_plugin_p->is_open = 0; +} + +static void rdpsnd_audio_open(rdpsndDevicePlugin* device, rdpsndFormat* format, int latency) +{ + int rv; + int i; + + GOT_HERE; + + rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; + if (aq_plugin_p->is_open) { + return; + } + + aq_plugin_p->buf_index = 0; + + // setup AudioStreamBasicDescription + aq_plugin_p->data_format.mSampleRate = 44100; + aq_plugin_p->data_format.mFormatID = kAudioFormatLinearPCM; + aq_plugin_p->data_format.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; + + // until we know better, assume that one packet = one frame + // one frame = bytes_per_sample x number_of_channels + aq_plugin_p->data_format.mBytesPerPacket = 4; + aq_plugin_p->data_format.mFramesPerPacket = 1; + aq_plugin_p->data_format.mBytesPerFrame = 4; + aq_plugin_p->data_format.mChannelsPerFrame = 2; + aq_plugin_p->data_format.mBitsPerChannel = 16; + + rv = AudioQueueNewOutput(&aq_plugin_p->data_format, // audio stream basic desc + aq_playback_cb, // callback when more data is required + aq_plugin_p, // data to pass to callback + CFRunLoopGetCurrent(), // The current run loop, and the one on + // which the audio queue playback callback + // will be invoked + kCFRunLoopCommonModes, // run loop modes in which callbacks can + // be invoked + 0, // flags - reserved + &aq_plugin_p->aq_ref + ); + if (rv != 0) { + printf("rdpsnd_audio_open: AudioQueueNewOutput() failed with error %d\n", rv); + aq_plugin_p->is_open = 1; + return; + } + + for (i = 0; i < AQ_NUM_BUFFERS; i++) + { + rv = AudioQueueAllocateBuffer(aq_plugin_p->aq_ref, AQ_BUF_SIZE, &aq_plugin_p->buffers[i]); + } + + aq_plugin_p->is_open = 1; +} + +static void rdpsnd_audio_free(rdpsndDevicePlugin* device) +{ + GOT_HERE; +} + +static boolean rdpsnd_audio_format_supported(rdpsndDevicePlugin* device, rdpsndFormat* format) +{ + GOT_HERE; + + switch (format->wFormatTag) + { + case 1: /* PCM */ + if (format->cbSize == 0 && + (format->nSamplesPerSec <= 48000) && + (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && + (format->nChannels == 1 || format->nChannels == 2)) + { + return 1; + } + break; + } + return 0; +} + +static void rdpsnd_audio_set_format(rdpsndDevicePlugin* device, rdpsndFormat* format, int latency) +{ + GOT_HERE; +} + +static void rdpsnd_audio_set_volume(rdpsndDevicePlugin* device, uint32 value) +{ + GOT_HERE; +} + +static void rdpsnd_audio_play(rdpsndDevicePlugin* device, uint8* data, int size) +{ + rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; + AudioQueueBufferRef aq_buf_ref; + int len; + + GOT_HERE; + + if (!aq_plugin_p->is_open) { + return; + } + + /* get next empty buffer */ + aq_buf_ref = aq_plugin_p->buffers[aq_plugin_p->buf_index]; + + // fill aq_buf_ref with audio data + len = size > AQ_BUF_SIZE ? AQ_BUF_SIZE : size; + + memcpy(aq_buf_ref->mAudioData, (char *) data, len); + aq_buf_ref->mAudioDataByteSize = len; + + // add buffer to audioqueue + AudioQueueEnqueueBuffer(aq_plugin_p->aq_ref, aq_buf_ref, 0, 0); + + // update buf_index + aq_plugin_p->buf_index++; + if (aq_plugin_p->buf_index >= AQ_NUM_BUFFERS) { + aq_plugin_p->buf_index = 0; + } +} + +static void rdpsnd_audio_start(rdpsndDevicePlugin* device) +{ + GOT_HERE; + + rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device; + + AudioQueueStart(aq_plugin_p->aq_ref, NULL); +} + +/** + * AudioQueue Playback callback + * + * our job here is to fill aq_buf_ref with audio data and enqueue it + */ + +static void aq_playback_cb(void *user_data, + AudioQueueRef aq_ref, + AudioQueueBufferRef aq_buf_ref + ) +{ + GOT_HERE; +} + +int FreeRDPRdpsndDeviceEntry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) +{ + rdpsndAudioQPlugin* aqPlugin; + RDP_PLUGIN_DATA* data; + + GOT_HERE; + + aqPlugin = xnew(rdpsndAudioQPlugin); + + aqPlugin->device.Open = rdpsnd_audio_open; + aqPlugin->device.FormatSupported = rdpsnd_audio_format_supported; + aqPlugin->device.SetFormat = rdpsnd_audio_set_format; + aqPlugin->device.SetVolume = rdpsnd_audio_set_volume; + aqPlugin->device.Play = rdpsnd_audio_play; + aqPlugin->device.Start = rdpsnd_audio_start; + aqPlugin->device.Close = rdpsnd_audio_close; + aqPlugin->device.Free = rdpsnd_audio_free; + + data = pEntryPoints->plugin_data; + + if (data && strcmp((char *)data->data[0], "macaudio") == 0) { + if(strlen((char *)data->data[1]) > 0) + aqPlugin->device_name = strdup((char *)data->data[1]); + else + aqPlugin->device_name = NULL; + } + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)aqPlugin); + return 0; +} + diff --git a/channels/rdpsnd/rdpsnd_main.c b/channels/rdpsnd/rdpsnd_main.c index 2d9fe27de..fa6e02d21 100644 --- a/channels/rdpsnd/rdpsnd_main.c +++ b/channels/rdpsnd/rdpsnd_main.c @@ -525,7 +525,12 @@ static void rdpsnd_process_connect(rdpSvcPlugin* plugin) { default_data[0].data[0] = "alsa"; default_data[0].data[1] = "default"; - rdpsnd_load_device_plugin(rdpsnd, "alsa", default_data); + if (!rdpsnd_load_device_plugin(rdpsnd, "alsa", default_data)) + { + default_data[0].data[0] = "macaudio"; + default_data[0].data[1] = "default"; + rdpsnd_load_device_plugin(rdpsnd, "macaudio", default_data); + } } } if (rdpsnd->device == NULL) diff --git a/client/Mac/MRDPCursor.h b/client/Mac/MRDPCursor.h new file mode 100644 index 000000000..844769ef8 --- /dev/null +++ b/client/Mac/MRDPCursor.h @@ -0,0 +1,25 @@ +// +// MRDPCursor.h +// MacFreeRDP +// +// Created by Laxmikant Rashinkar on 3/28/12. +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +#import + +#define boolean int + +#include "freerdp/graphics.h" + +@interface MRDPCursor : NSObject +{ +@public + rdpPointer *pointer; + uint8 *cursor_data; // bitmapped pixel data + NSBitmapImageRep *bmiRep; + NSCursor *nsCursor; + NSImage *nsImage; +} + +@end diff --git a/client/Mac/MRDPCursor.m b/client/Mac/MRDPCursor.m new file mode 100644 index 000000000..849d575ef --- /dev/null +++ b/client/Mac/MRDPCursor.m @@ -0,0 +1,12 @@ +// +// MRDPCursor.m +// MacFreeRDP +// +// Created by Laxmikant Rashinkar on 3/28/12. +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +#import "MRDPCursor.h" + +@implementation MRDPCursor +@end diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h new file mode 100644 index 000000000..43c523263 --- /dev/null +++ b/client/Mac/MRDPView.h @@ -0,0 +1,144 @@ +// +// MRDPView.h +// MacFreeRDP +// +// Created by Laxmikant Rashinkar on 3/28/12. +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +#import + +typedef int boolean; + +#include "freerdp/freerdp.h" +#include "freerdp/types.h" +#include "freerdp/channels/channels.h" +#include "freerdp/gdi/gdi.h" +#include "freerdp/graphics.h" +#include "freerdp/utils/event.h" +#include "freerdp/plugins/cliprdr.h" +#include "freerdp/utils/args.h" + +@interface MRDPView : NSView +{ + CFRunLoopSourceRef run_loop_src; + CFRunLoopSourceRef run_loop_src_channels; + NSBitmapImageRep *bmiRep; + NSMutableArray *cursors; + NSTimer *pasteboard_timer; + NSRect rect; + freerdp *rdp_instance; + rdpContext *rdp_context; + boolean mouseInClientArea; + char *pixel_data; + int width; + int height; + int argc; + char **argv; + + // store state info for some keys + int kdlshift; + int kdrshift; + int kdlctrl; + int kdrctrl; + int kdlalt; + int kdralt; + int kdlmeta; + int kdrmeta; + int kdcapslock; + +@public + NSWindow *ourMainWindow; + NSPasteboard *pasteboard_rd; // for reading from clipboard + NSPasteboard *pasteboard_wr; // for writing to clipboard + int pasteboard_changecount; + int pasteboard_format; + int is_connected; // true when connected to RDP server +} + +- (void) rdpConnectEror; +- (void) saveStateInfo :(freerdp *) instance :(rdpContext *) context; +- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr; +- (void) onPasteboardTimerFired :(NSTimer *) timer; +- (void) my_draw_rect :(void *) context; +- (void) releaseResources; + +@property (assign) int is_connected; + +@end + +/* Pointer Flags */ +#define PTR_FLAGS_WHEEL 0x0200 +#define PTR_FLAGS_WHEEL_NEGATIVE 0x0100 +#define PTR_FLAGS_MOVE 0x0800 +#define PTR_FLAGS_DOWN 0x8000 +#define PTR_FLAGS_BUTTON1 0x1000 +#define PTR_FLAGS_BUTTON2 0x2000 +#define PTR_FLAGS_BUTTON3 0x4000 +#define WheelRotationMask 0x01FF + +void pointer_new(rdpContext* context, rdpPointer* pointer); +void pointer_free(rdpContext* context, rdpPointer* pointer); +void pointer_set(rdpContext* context, rdpPointer* pointer); +void pointer_setNull(rdpContext* context); +void pointer_setDefault(rdpContext* context); +int rdp_connect(); +boolean mac_pre_connect(freerdp *inst); +boolean mac_post_connect(freerdp *inst); +void mac_context_new(freerdp *inst, rdpContext *context); +void mac_context_free(freerdp *inst, rdpContext *context); +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 *inst, rdpContext *context); +void skt_activity_cb(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info); +void channel_activity_cb(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info); +int register_fds(int *fds, int count, void *inst); +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 *inst, int chan_id, uint8 *data, int size, int flags, int total_size); +void process_cliprdr_event(freerdp *inst); +void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVENT* event); +void cliprdr_send_data_request(freerdp *inst, uint32 format); +void cliprdr_process_cb_monitor_ready_event(freerdp* inst); +void cliprdr_process_cb_data_response_event(freerdp *inst, RDP_CB_DATA_RESPONSE_EVENT *event); +void cliprdr_process_text(freerdp *inst, uint8 *data, int len); +void cliprdr_send_supported_format_list(freerdp *inst); +int register_channel_fds(int *fds, int count, void *inst); + +/* LK_TODO +int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, + ProcessPluginArgs plugin_callback, void* plugin_user_data, +ProcessUIArgs ui_callback, void* ui_user_data); +*/ + +struct mac_context +{ + // *must* have this - do not delete + rdpContext _p; +}; + +struct cursor +{ + rdpPointer *pointer; + uint8 *cursor_data; // bitmapped pixel data + void *bmiRep; // NSBitmapImageRep + void *nsCursor; // NSCursor + void *nsImage; // NSImage +}; + +struct rgba_data +{ + char red; + char green; + char blue; + char alpha; +}; + +struct kkey +{ + int key_code; + int flags; +}; + diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m new file mode 100644 index 000000000..df2a9754f --- /dev/null +++ b/client/Mac/MRDPView.m @@ -0,0 +1,1519 @@ +// +// MRDPView.m +// MacFreeRDP +// +// Created by Laxmikant Rashinkar on 3/28/12. +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +/* + * TODO + * + 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 + */ + +#import "MRDPView.h" +#import "MRDPCursor.h" + +#define __RUN_IN_XCODE + +@implementation MRDPView + +MRDPView *g_mrdpview; + +@synthesize is_connected; + +/************************************************************************ + methods we override +************************************************************************/ + +/** ********************************************************************* + * create MRDPView with specified rectangle + ***********************************************************************/ + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + + return self; +} + +/** ********************************************************************* + * called when MRDPView has been successfully created from the NIB + ***********************************************************************/ + +- (void) awakeFromNib +{ + g_mrdpview = self; + + // store our window dimensions + width = [self bounds].size.width; + height = [self bounds].size.height; + + [[self window] becomeFirstResponder]; + [[self window] setAcceptsMouseMovedEvents:YES]; + + cursors = [[NSMutableArray alloc] initWithCapacity:10]; + mouseInClientArea = YES; +} + +/** ********************************************************************* + * become first responder so we can get keyboard and mouse events + ***********************************************************************/ + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +/** ********************************************************************* + * called when a mouse move event occurrs + * + * 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 + * versions, we do this manually. + * + * 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 + ***********************************************************************/ + + - (void) mouseMoved:(NSEvent *)event +{ + int x; + int y; + + [super mouseMoved:event]; + + if (!is_connected) { + return; + } + + // send mouse motion event to RDP server + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); + } +} + +/** ********************************************************************* + * called when left mouse button is pressed down + ***********************************************************************/ + +- (void)mouseDown:(NSEvent *) event +{ + int x; + int y; + + [super mouseDown:event]; + + if (!is_connected) { + return; + } + + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); + } +} + +/** ********************************************************************* + * called when left mouse button is released + ***********************************************************************/ + +- (void) mouseUp:(NSEvent *) event +{ + int x; + int y; + + [super mouseUp:event]; + + if (!is_connected) { + return; + } + + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); + } +} + +/** ********************************************************************* + * called when right mouse button is pressed down + ***********************************************************************/ + +- (void) rightMouseDown:(NSEvent *)event +{ + int x; + int y; + + [super rightMouseDown:event]; + + if (!is_connected) { + return; + } + + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y); + } +} + +/** ********************************************************************* + * called when right mouse button is released + ***********************************************************************/ + +- (void) rightMouseUp:(NSEvent *)event +{ + int x; + int y; + + [super rightMouseUp:event]; + + if (!is_connected) { + return; + } + + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON2, x, y); + } +} + +/** ********************************************************************* + * called when middle mouse button is pressed + ***********************************************************************/ + +- (void) otherMouseDown:(NSEvent *)event +{ + int x; + int y; + + [super otherMouseDown:event]; + + if (!is_connected) { + return; + } + + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y); + } +} + +/** ********************************************************************* + * called when middle mouse button is released + ***********************************************************************/ + +- (void) otherMouseUp:(NSEvent *)event +{ + int x; + int y; + + [super otherMouseUp:event]; + + if (!is_connected) { + return; + } + + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON3, x, y); + } +} + +- (void) scrollWheel:(NSEvent *)event +{ + uint16 flags; + int x; + int y; + + [super scrollWheel:event]; + + if (!is_connected) { + return; + } + + if ([self eventIsInClientArea :event :&x :&y]) { + flags = PTR_FLAGS_WHEEL; + if ([event deltaY] < 0) { + flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; + } + else { + flags |= 0x0078; + } + x += (int) [event deltaX]; + y += (int) [event deltaY]; + rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); + } +} + +/** ********************************************************************* + * called when mouse is moved with left button pressed + * note: invocation order is: mouseDown, mouseDragged, mouseUp + ***********************************************************************/ + +- (void) mouseDragged:(NSEvent *)event +{ + int x; + int y; + + [super mouseDragged:event]; + + if (!is_connected) { + return; + } + + // send mouse motion event to RDP server + if ([self eventIsInClientArea :event :&x :&y]) { + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); + } +} + +/** ********************************************************************* + * called when a key is pressed + ***********************************************************************/ + +- (void) keyDown:(NSEvent *) event +{ + int key; + + if (!is_connected) { + return; + } + + key = [event keyCode]; + rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_DOWN, g_keys[key].key_code); +} + +/** ********************************************************************* + * called when a key is released + ***********************************************************************/ + +- (void) keyUp:(NSEvent *) event +{ + int key; + + if (!is_connected) { + return; + } + + key = [event keyCode]; + rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_RELEASE, g_keys[key].key_code); +} + +/** ********************************************************************* + * called when shift, control, alt and meta keys are pressed/released + ***********************************************************************/ + +- (void) flagsChanged:(NSEvent *) event +{ + NSUInteger mf = [event modifierFlags]; + + if (!is_connected) { + 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 + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x2a); + kdlshift = 1; + } + if ((kdlshift != 0) && ((mf & 2) == 0)) { + // left shift went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x2a); + kdlshift = 0; + } + + // right shift + if ((kdrshift == 0) && ((mf & 4) != 0)) { + // right shift went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x36); + kdrshift = 1; + } + if ((kdrshift != 0) && ((mf & 4) == 0)) { + // right shift went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x36); + kdrshift = 0; + } + + // left ctrl + if ((kdlctrl == 0) && ((mf & 1) != 0)) { + // left ctrl went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x1d); + kdlctrl = 1; + } + if ((kdlctrl != 0) && ((mf & 1) == 0)) { + // left ctrl went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x1d); + kdlctrl = 0; + } + + // right ctrl + if ((kdrctrl == 0) && ((mf & 0x2000) != 0)) { + // right ctrl went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x1d); + kdrctrl = 1; + } + if ((kdrctrl != 0) && ((mf & 0x2000) == 0)) { + // right ctrl went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x1d); + kdrctrl = 0; + } + + // left alt + if ((kdlalt == 0) && ((mf & 0x20) != 0)) { + // left alt went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x38); + kdlalt = 1; + } + if ((kdlalt != 0) && ((mf & 0x20) == 0)) { + // left alt went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x38); + kdlalt = 0; + } + + // right alt + if ((kdralt == 0) && ((mf & 0x40) != 0)) { + // right alt went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x38); + kdralt = 1; + } + if ((kdralt != 0) && ((mf & 0x40) == 0)) { + // right alt went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x38); + kdralt = 0; + } + + // left meta + if ((kdlmeta == 0) && ((mf & 0x08) != 0)) { + // left meta went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5b); + kdlmeta = 1; + } + if ((kdlmeta != 0) && ((mf & 0x08) == 0)) { + // left meta went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5b); + kdlmeta = 0; + } + + // right meta + if ((kdrmeta == 0) && ((mf & 0x10) != 0)) { + // right meta went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5c); + kdrmeta = 1; + } + if ((kdrmeta != 0) && ((mf & 0x10) == 0)) { + // right meta went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5c); + kdrmeta = 0; + } +} + +- (void) releaseResources +{ + for (int 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); + + if (run_loop_src != 0) + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode); + + if (run_loop_src != 0) + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src, kCFRunLoopDefaultMode); +} + +/** ********************************************************************* + * called when our view needs refreshing + ***********************************************************************/ + +- (void)drawRect:(NSRect)dirtyRect +{ +#if 1 + [bmiRep drawInRect:rect]; +#else + // do not delete - may need this soon + NSImage *image = [[NSImage alloc] initWithSize:[bmiRep size]]; + [image addRepresentation:bmiRep]; + [image setFlipped:0]; + [image drawInRect:dirtyRect fromRect:rect operation:NSCompositeSourceOver fraction:1.0]; +#endif +} + +/************************************************************************ + instance methods +************************************************************************/ + +/** ********************************************************************* + * called when RDP server wants us to update a rect with new data + ***********************************************************************/ + +- (void) my_draw_rect:(void *)context +{ + rdpContext *ctx = (rdpContext *) context; + + struct rgba_data { + char red; + char green; + char blue; + char alpha; + }; + + rect.size.width = ctx->gdi->width; + rect.size.height = ctx->gdi->height; + rect.origin.x = 0; + rect.origin.y = 0; + + if (!bmiRep) { + pixel_data = (char *) malloc(rect.size.width * rect.size.height * sizeof(struct rgba_data)); + bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixel_data + pixelsWide:rect.size.width + pixelsHigh:rect.size.height + bitsPerSample:8 + samplesPerPixel:sizeof(struct rgba_data) + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 //NSAlphaFirstBitmapFormat + bytesPerRow:rect.size.width * sizeof(struct rgba_data) + bitsPerPixel:0]; + } + + cvt_argb_to_rgba(pixel_data, (char *) ctx->gdi->primary_buffer, rect.size.width * rect.size.height * sizeof(struct rgba_data)); + + [self setNeedsDisplayInRect:rect]; // TODO: do only for reqd rect +} + +/** ********************************************************************* + * save state info for use by other methods later on + ***********************************************************************/ + +- (void) saveStateInfo:(freerdp *) instance:(rdpContext *) context +{ + rdp_instance = instance; + rdp_context = context; +} + +/** ********************************************************************* + * double check that a mouse event occurred in our client view + ***********************************************************************/ + +- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr +{ + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + if ((x < 0) || (y < 0)) { + if (mouseInClientArea) { + // set default cursor before leaving client area + mouseInClientArea = NO; + NSCursor *cur = [NSCursor arrowCursor]; + [cur set]; + } + return NO; + } + if ((x > width) || (y > height)) { + if (mouseInClientArea) { + // set default cursor before leaving client area + mouseInClientArea = NO; + NSCursor *cur = [NSCursor arrowCursor]; + [cur set]; + } + return NO; + } + + // on Mac origin is at lower left, but we want it on upper left + y = height - y; + + *xptr = x; + *yptr = y; + mouseInClientArea = YES; + return YES; +} + +/** ********************************************************************* + * called when we fail to connect to a RDP server + ***********************************************************************/ + +- (void) rdpConnectEror +{ + + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Error connecting to server"]; + [alert beginSheetModalForWindow:[g_mrdpview window] + modalDelegate:g_mrdpview + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + +/** ********************************************************************* + * just a terminate selector for above call + ***********************************************************************/ + +- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci +{ + [NSApp terminate:nil]; +} + +- (void) onPasteboardTimerFired :(NSTimer *) timer +{ + NSArray *types; + int i; + + i = [pasteboard_rd changeCount]; + if (i != pasteboard_changecount) + { + pasteboard_changecount = i; + types = [NSArray arrayWithObject:NSStringPboardType]; + NSString *str = [pasteboard_rd availableTypeFromArray:types]; + if (str != nil) + { + cliprdr_send_supported_format_list(rdp_instance); + } + } +} + +/************************************************************************ + * * + * C functions * + * * + ***********************************************************************/ + +/** ********************************************************************* + * connect to RDP server + * + * @return 0 on success, -1 on failure + ***********************************************************************/ + +int rdp_connect() +{ + freerdp *inst; + int status; + + freerdp_channels_global_init(); + + inst = freerdp_new(); + inst->PreConnect = mac_pre_connect; + inst->PostConnect = mac_post_connect; + inst->context_size = sizeof(struct mac_context); + inst->ContextNew = mac_context_new; + inst->ContextFree = mac_context_free; + inst->ReceiveChannelData = receive_channel_data; + freerdp_context_new(inst); + + status = freerdp_connect(inst); + if(status) { + freerdp_check_fds(inst); + [g_mrdpview setIs_connected:1]; + return 0; + } + [g_mrdpview setIs_connected:0]; + [g_mrdpview rdpConnectEror]; + return -1; +} + +/** ********************************************************************* + * a callback given to freerdp_connect() to process the pre-connect operations. + * + * @param inst - pointer to a rdp_freerdp struct that contains the connection's parameters, and + * will be filled with the appropriate informations. + * + * @return true if successful. false otherwise. + ************************************************************************/ + +boolean mac_pre_connect(freerdp *inst) +{ + char *cptr; + int len; + int i; + + inst->settings->offscreen_bitmap_cache = false; + inst->settings->glyph_cache = true; + inst->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; + inst->settings->order_support[NEG_GLYPH_INDEX_INDEX] = true; + inst->settings->order_support[NEG_FAST_GLYPH_INDEX] = false; + inst->settings->order_support[NEG_FAST_INDEX_INDEX] = false; + inst->settings->order_support[NEG_SCRBLT_INDEX] = true; + inst->settings->order_support[NEG_SAVEBITMAP_INDEX] = false; + + inst->settings->bitmap_cache = true; + inst->settings->order_support[NEG_MEMBLT_INDEX] = true; + inst->settings->order_support[NEG_MEMBLT_V2_INDEX] = true; + inst->settings->order_support[NEG_MEM3BLT_INDEX] = false; + inst->settings->order_support[NEG_MEM3BLT_V2_INDEX] = false; + inst->settings->bitmapCacheV2NumCells = 3; // 5; + inst->settings->bitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; + inst->settings->bitmapCacheV2CellInfo[0].persistent = false; + inst->settings->bitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; + inst->settings->bitmapCacheV2CellInfo[1].persistent = false; + inst->settings->bitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; + inst->settings->bitmapCacheV2CellInfo[2].persistent = false; + inst->settings->bitmapCacheV2CellInfo[3].numEntries = 0; // 4096; + inst->settings->bitmapCacheV2CellInfo[3].persistent = false; + inst->settings->bitmapCacheV2CellInfo[4].numEntries = 0; // 2048; + inst->settings->bitmapCacheV2CellInfo[4].persistent = false; + + inst->settings->order_support[NEG_MULTIDSTBLT_INDEX] = false; + inst->settings->order_support[NEG_MULTIPATBLT_INDEX] = false; + inst->settings->order_support[NEG_MULTISCRBLT_INDEX] = false; + inst->settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false; + inst->settings->order_support[NEG_POLYLINE_INDEX] = false; + inst->settings->color_depth = 24; + inst->settings->sw_gdi = 1; + + // setup callbacks + inst->update->BeginPaint = mac_begin_paint; + inst->update->EndPaint = mac_end_paint; + inst->update->SetBounds = mac_set_bounds; + inst->update->BitmapUpdate = mac_bitmap_update; + + NSArray *args = [[NSProcessInfo processInfo] arguments]; + +#ifdef RUN_IN_XCODE + // if you add any additional hard coded + // cmd line args, update this first + g_mrdpview->argc = 10; +#else + g_mrdpview->argc = [args count]; +#endif + + g_mrdpview->argv = malloc(sizeof(char *) * g_mrdpview->argc); + if (g_mrdpview->argv == NULL) { + return false; + } + +#ifdef RUN_IN_XCODE + // create our own cmd line args + i = 0; + + // argv[0] + NSString *sptr = [args objectAtIndex:0]; + len = [sptr length] + 1; + cptr = (char *) malloc(len); + strcpy(cptr, [sptr UTF8String]); + g_mrdpview->argv[i++] = cptr; + + // argv[1] + cptr = (char *)malloc(80); + strcpy(cptr, "-g"); + g_mrdpview->argv[i++] = cptr; + + // argv[2] + cptr = (char *)malloc(80); + strcpy(cptr, "800x600"); + g_mrdpview->argv[i++] = cptr; + + // argv[3] + cptr = (char *)malloc(80); + strcpy(cptr, "--ignore-certificate"); + g_mrdpview->argv[i++] = cptr; + + // argv[4] + cptr = (char *)malloc(80); + strcpy(cptr, "--no-nla"); + g_mrdpview->argv[i++] = cptr; + + // argv[5] + cptr = (char *)malloc(80); + strcpy(cptr, "--plugin"); + g_mrdpview->argv[i++] = cptr; + + // argv[6] + cptr = (char *)malloc(80); + strcpy(cptr, "cliprdr"); + g_mrdpview->argv[i++] = cptr; + + // argv[7] + cptr = (char *)malloc(80); + strcpy(cptr, "--plugin"); + g_mrdpview->argv[i++] = cptr; + + // argv[8] + cptr = (char *)malloc(80); + strcpy(cptr, "rdpsnd"); + g_mrdpview->argv[i++] = cptr; + + // argv[9] + cptr = (char *)malloc(80); + strcpy(cptr, "23.20.8.223"); + g_mrdpview->argv[i++] = cptr; +#else + // MacFreeRDP was not run in Xcode + i = 0; + for (NSString *str in args) + { + len = [str length] + 1; + cptr = (char *) malloc(len); + strcpy(cptr, [str UTF8String]); + g_mrdpview->argv[i++] = cptr; + } +#endif + + freerdp_parse_args(inst->settings, g_mrdpview->argc, g_mrdpview->argv, process_plugin_args, inst->context->channels, NULL, NULL); + if ((strcmp(g_mrdpview->argv[1], "-h") == 0) || (strcmp(g_mrdpview->argv[1], "--help") == 0)) { + [NSApp terminate:nil]; + return true; + } + + // set window size based on cmd line arguments + g_mrdpview->width = inst->settings->width; + g_mrdpview->height = inst->settings->height; + + NSRect rect; + rect.origin.x = 0; + rect.origin.y = 0; + rect.size.width = g_mrdpview->width; + rect.size.height = g_mrdpview->height; + + [[g_mrdpview window] setMaxSize:rect.size]; + [[g_mrdpview window] setMinSize:rect.size]; + [[g_mrdpview window] setFrame:rect display:YES]; + + freerdp_channels_pre_connect(inst->context->channels, inst); + return true; +} + +/** ********************************************************************* + * a callback registered with freerdp_connect() to perform post-connection operations. + * we get called only if the connection was initialized properly, and will continue + * the initialization based on the newly created connection. + * + * @param inst - pointer to a rdp_freerdp struct + * + * @return true on success, false on failure + * + ************************************************************************/ + +boolean mac_post_connect(freerdp *inst) +{ + uint32 flags; + rdpPointer rdp_pointer; + void *rd_fds[32]; + void *wr_fds[32]; + int rd_count = 0; + int wr_count = 0; + int index; + int fds[32]; + + memset(&rdp_pointer, 0, sizeof(rdpPointer)); + rdp_pointer.size = sizeof(rdpPointer); + rdp_pointer.New = pointer_new; + rdp_pointer.Free = pointer_free; + rdp_pointer.Set = pointer_set; + rdp_pointer.SetNull = pointer_setNull; + rdp_pointer.SetDefault = pointer_setDefault; + + flags = CLRCONV_ALPHA; + flags |= CLRBUF_32BPP; + + gdi_init(inst, flags, NULL); + pointer_cache_register_callbacks(inst->update); + graphics_register_pointer(inst->context->graphics, &rdp_pointer); + + // register file descriptors with the RunLoop + if (!freerdp_get_fds(inst, rd_fds, &rd_count, 0, 0)) + { + printf("mac_post_connect: freerdp_get_fds() failed!\n"); + } + + for (index = 0; index < rd_count; index++) + { + fds[index] = (int)(long)rd_fds[index]; + } + register_fds(fds, rd_count, inst); + + // register channel manager file descriptors with the RunLoop + if (!freerdp_channels_get_fds(inst->context->channels, inst, rd_fds, &rd_count, wr_fds, &wr_count)) + { + printf("ERROR: freerdp_channels_get_fds() failed\n"); + } + for (index = 0; index < rd_count; index++) + { + fds[index] = (int)(long)rd_fds[index]; + } + register_channel_fds(fds, rd_count, inst); + freerdp_channels_post_connect(inst->context->channels, inst); + + // setup pasteboard (aka clipboard) for copy operations (write only) + g_mrdpview->pasteboard_wr = [NSPasteboard generalPasteboard]; + + // setup pasteboard for read operations + g_mrdpview->pasteboard_rd = [NSPasteboard generalPasteboard]; + g_mrdpview->pasteboard_changecount = [g_mrdpview->pasteboard_rd changeCount]; + g_mrdpview->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:g_mrdpview selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + return true; +} + +/** ********************************************************************* + * create a new mouse cursor + * + * @param context our context state + * @param pointer information about the cursor to create + * + ************************************************************************/ + +void pointer_new(rdpContext* context, rdpPointer* pointer) +{ + MRDPCursor *mrdpCursor = [[MRDPCursor alloc] init]; + uint8 *cursor_data; + + NSRect rect; + rect.size.width = pointer->width; + rect.size.height = pointer->height; + rect.origin.x = pointer->xPos; + rect.origin.y = pointer->yPos; + + cursor_data = (uint8 *) malloc(rect.size.width * rect.size.height * 4); + mrdpCursor->cursor_data = cursor_data; + + 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 + + // store cursor bitmap image in representation - required by NSImage + NSBitmapImageRep *bmiRep; + bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data + pixelsWide:rect.size.width + pixelsHigh:rect.size.height + bitsPerSample:8 + samplesPerPixel:sizeof(struct rgba_data) + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 + bytesPerRow:rect.size.width * 4 + bitsPerPixel:0]; + mrdpCursor->bmiRep = bmiRep; + + // create an image using above representation + NSImage *image = [[NSImage alloc] initWithSize:[bmiRep size]]; + [image addRepresentation: bmiRep]; + [image setFlipped:NO]; + mrdpCursor->nsImage = image; + + // need hotspot to create cursor + NSPoint hotSpot; + hotSpot.x = pointer->xPos; + hotSpot.y = pointer->yPos; + + NSCursor *cursor = [[NSCursor alloc] initWithImage: image hotSpot:hotSpot]; + mrdpCursor->nsCursor = cursor; + mrdpCursor->pointer = pointer; + + // save cursor for later use in pointer_set() + NSMutableArray *ma = g_mrdpview->cursors; + [ma addObject:mrdpCursor]; +} + +/** ********************************************************************* + * release resources on specified cursor + ************************************************************************/ + +void pointer_free(rdpContext* context, rdpPointer* pointer) +{ + NSMutableArray *ma = g_mrdpview->cursors; + + for (MRDPCursor *cursor in ma) + { + if (cursor->pointer == pointer) { + cursor->nsImage = nil; + cursor->nsCursor = nil; + cursor->bmiRep = nil; + free(cursor->cursor_data); + [ma removeObject:cursor]; + return; + } + } +} + +/** ********************************************************************* + * set specified cursor as the current cursor + ************************************************************************/ + +void pointer_set(rdpContext* context, rdpPointer* pointer) +{ + NSMutableArray *ma = g_mrdpview->cursors; + + if (!g_mrdpview->mouseInClientArea) + { + return; // not in client area + } + + for (MRDPCursor *cursor in ma) + { + if (cursor->pointer == pointer) { + [cursor->nsCursor set]; + return; + } + } +} + +/** ********************************************************************* + * do not display any mouse cursor + ***********************************************************************/ + +void pointer_setNull(rdpContext* context) +{ +} + +/** ********************************************************************* + * display default mouse cursor + ***********************************************************************/ + +void pointer_setDefault(rdpContext* context) +{ +} + +/** ********************************************************************* + * create a new context - but all we really need to do is save state info + ***********************************************************************/ + +void mac_context_new(freerdp *inst, rdpContext *context) +{ + [g_mrdpview saveStateInfo:inst :context]; + context->channels = freerdp_channels_new(); +} + +/** ********************************************************************* + * we don't do much over here + ***********************************************************************/ + +void mac_context_free(freerdp *inst, rdpContext *context) +{ +} + +/** ********************************************************************* + * clip drawing surface so nothing is drawn outside specified bounds + ***********************************************************************/ + +void mac_set_bounds(rdpContext *context, rdpBounds *bounds) +{ +} + +/** ********************************************************************* + * we don't do much over here + ***********************************************************************/ + +void mac_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) +{ +} + +/** ********************************************************************* + * we don't do much over here + ***********************************************************************/ + +void mac_begin_paint(rdpContext *context) +{ +} + +/** ********************************************************************* + * RDP server wants us to draw new data in the view + ***********************************************************************/ + +void mac_end_paint(rdpContext* context) +{ + if ((context == 0) || (context->gdi == 0)) { + return; + } + [g_mrdpview my_draw_rect:(void *) context]; +} + +/** ********************************************************************* + * called when data is available on a socket + ***********************************************************************/ + +void skt_activity_cb( + CFSocketRef s, + CFSocketCallBackType callbackType, + CFDataRef address, + const void *data, + void *info + ) +{ + if (!freerdp_check_fds(info)) { + // lost connection or did not connect + [NSApp terminate:nil]; + } +} + +/** ********************************************************************* + * called when data is available on a virtual channel + ***********************************************************************/ + +void channel_activity_cb( + CFSocketRef s, + CFSocketCallBackType callbackType, + CFDataRef address, + const void *data, + void *info + ) +{ + freerdp *inst = (freerdp *) info; + + freerdp_channels_check_fds(inst->context->channels, inst); + process_cliprdr_event(inst); +} + +/** ********************************************************************* + * setup callbacks for data availability on sockets + ***********************************************************************/ + +int register_fds(int *fds, int count, void *inst) +{ + int i; + CFSocketRef skt_ref; + CFSocketContext skt_context = { 0, inst, NULL, NULL, NULL }; + + for (i = 0; i < count; i++) + { + skt_ref = CFSocketCreateWithNative(NULL, fds[i], kCFSocketReadCallBack, skt_activity_cb, &skt_context); + g_mrdpview->run_loop_src = CFSocketCreateRunLoopSource(NULL, skt_ref, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), g_mrdpview->run_loop_src, kCFRunLoopDefaultMode); + CFRelease(skt_ref); + } + return 0; +} + +/** ********************************************************************* + * setup callbacks for data availability on channels + ***********************************************************************/ + +int register_channel_fds(int *fds, int count, void *inst) +{ + int i; + CFSocketRef skt_ref; + CFSocketContext skt_context = { 0, inst, NULL, NULL, NULL }; + + for (i = 0; i < count; i++) + { + skt_ref = CFSocketCreateWithNative(NULL, fds[i], kCFSocketReadCallBack, channel_activity_cb, &skt_context); + g_mrdpview->run_loop_src_channels = CFSocketCreateRunLoopSource(NULL, skt_ref, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), g_mrdpview->run_loop_src_channels, kCFRunLoopDefaultMode); + CFRelease(skt_ref); + } + return 0; +} + +/** ********************************************************************* + * called when channel data is available + ***********************************************************************/ + +int receive_channel_data(freerdp *inst, int chan_id, uint8 *data, int size, int flags, int total_size) +{ + return freerdp_channels_data(inst, chan_id, data, size, flags, total_size); +} + +/** ********************************************************************* + * convert an array containing ARGB data to RGBA + ***********************************************************************/ + +void cvt_argb_to_rgba(char *dest, char *src, int len) +{ + int i; + + for (i = 0; i < len; i += 4) + { + dest[i ] = src[i + 2]; + dest[i + 1] = src[i + 1]; + dest[i + 2] = src[i + 0]; + dest[i + 3] = src[i + 3]; + } +} + +/** + * 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. + * + * @param settings + * @param name + * @param plugin_data + * @param user_data + * + * @return 1 + */ + +int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data) +{ + rdpChannels* channels = (rdpChannels*) user_data; + + freerdp_channels_load_plugin(channels, settings, name, plugin_data); + return 1; +} + +/* + * stuff related to clipboard redirection + */ + +/** + * remote system has requested clipboard data from local system + */ + +void cliprdr_process_cb_data_request_event(freerdp *inst) +{ + RDP_CB_DATA_RESPONSE_EVENT *event; + NSArray *types; + int len; + + event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, + RDP_EVENT_TYPE_CB_DATA_RESPONSE, NULL, NULL); + types = [NSArray arrayWithObject:NSStringPboardType]; + NSString *str = [g_mrdpview->pasteboard_rd availableTypeFromArray:types]; + if (str == nil) + { + event->data = NULL; + event->size = 0; + } + else + { + NSString *data = [g_mrdpview->pasteboard_rd stringForType:NSStringPboardType]; + len = [data length] * 2 + 2; + event->data = malloc(len); + [data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding]; + event->size = len; + } + freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); +} + +void cliprdr_send_data_request(freerdp *inst, uint32 format) +{ + RDP_CB_DATA_REQUEST_EVENT* event; + + event = (RDP_CB_DATA_REQUEST_EVENT *) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, + RDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL); + event->format = format; + freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); +} + +/** + * at the moment, only the following formats are supported + * CB_FORMAT_TEXT + * CB_FORMAT_UNICODETEXT + */ + +void cliprdr_process_cb_data_response_event(freerdp *inst, RDP_CB_DATA_RESPONSE_EVENT *event) +{ + NSString *str; + NSArray *types; + + if (event->size == 0) { + return; + } + + if (g_mrdpview->pasteboard_format == CB_FORMAT_TEXT || g_mrdpview->pasteboard_format == CB_FORMAT_UNICODETEXT) { + str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2]; + types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; + [g_mrdpview->pasteboard_wr declareTypes:types owner:g_mrdpview]; + [g_mrdpview->pasteboard_wr setString:str forType:NSStringPboardType]; + } +} + +void cliprdr_process_cb_monitor_ready_event(freerdp* inst) +{ + RDP_EVENT* event; + RDP_CB_FORMAT_LIST_EVENT* format_list_event; + + event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); + + format_list_event = (RDP_CB_FORMAT_LIST_EVENT*)event; + format_list_event->num_formats = 0; + + freerdp_channels_send_event(inst->context->channels, event); +} + +/** + * list of supported clipboard formats; currently only the following are supported + * CB_FORMAT_TEXT + * CB_FORMAT_UNICODETEXT + */ + +void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVENT* event) +{ + int i; + + if (event->num_formats == 0) { + return; + } + + for (i = 0; i < event->num_formats; i++) + { + switch (event->formats[i]) + { + case CB_FORMAT_RAW: + printf("CB_FORMAT_RAW: not yet supported\n"); + break; + + case CB_FORMAT_TEXT: + case CB_FORMAT_UNICODETEXT: + g_mrdpview->pasteboard_format = CB_FORMAT_UNICODETEXT; + cliprdr_send_data_request(inst, 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; + } + } +} + +void process_cliprdr_event(freerdp *inst) +{ + RDP_EVENT* event; + + event = freerdp_channels_pop_event(inst->context->channels); + + if (event) { + switch (event->event_type) + { + // Monitor Ready PDU is sent by server to indicate that it has been + // inited and is ready. This PDU is transmitted by the server after it has sent + // Clipboard Capabilities PDU + case RDP_EVENT_TYPE_CB_MONITOR_READY: + cliprdr_process_cb_monitor_ready_event(inst); + break; + + // 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 + case RDP_EVENT_TYPE_CB_FORMAT_LIST: + cliprdr_process_cb_format_list_event(inst, (RDP_CB_FORMAT_LIST_EVENT*) event); + break; + + // 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 + case RDP_EVENT_TYPE_CB_DATA_REQUEST: + cliprdr_process_cb_data_request_event(inst); + break; + + // 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 + case RDP_EVENT_TYPE_CB_DATA_RESPONSE: + cliprdr_process_cb_data_response_event(inst, (RDP_CB_DATA_RESPONSE_EVENT*) event); + break; + + default: + printf("process_cliprdr_event: unknown event type %d\n", event->event_type); + break; + } + freerdp_event_free(event); + } +} + +void cliprdr_send_supported_format_list(freerdp *inst) +{ + RDP_CB_FORMAT_LIST_EVENT* event; + + event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, + RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); + + event->formats = (uint32 *) malloc(sizeof(uint32) * 1); + event->num_formats = 1; + event->formats[0] = CB_FORMAT_UNICODETEXT; + freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); +} + +struct kkey g_keys[256] = +{ + { 0x1e, 0 }, // a 0 + { 0x1f, 0 }, // s + { 0x20, 0 }, // d + { 0x21, 0 }, // f + { 0x23, 0 }, // h + { 0x22, 0 }, // g + { 0x2c, 0 }, // z + { 0x2d, 0 }, // x + { 0x2e, 0 }, // c + { 0x2f, 0 }, // v + { 0x00, 0 }, // 10 + { 0x30, 0 }, // b + { 0x10, 0 }, // q + { 0x11, 0 }, // w + { 0x12, 0 }, // e + { 0x13, 0 }, // r + { 0x15, 0 }, // y + { 0x14, 0 }, // t + { 0x02, 0 }, // 1 + { 0x03, 0 }, // 2 + { 0x04, 0 }, // 3 20 + { 0x05, 0 }, // 4 + { 0x07, 0 }, // 6 + { 0x06, 0 }, // 5 + { 0x0d, 0 }, // = or + + { 0x0a, 0 }, // 9 + { 0x08, 0 }, // 7 + { 0x0c, 0 }, // - or _ + { 0x09, 0 }, // 8 + { 0x0b, 0 }, // 0 + { 0x1b, 0 }, // ] or } 30 + { 0x18, 0 }, // o + { 0x16, 0 }, // u + { 0x1a, 0 }, // [ or { + { 0x17, 0 }, // i + { 0x19, 0 }, // p + { 0x1c, 0 }, // enter + { 0x26, 0 }, // l + { 0x24, 0 }, // j + { 0x28, 0 }, // ' or " + { 0x25, 0 }, // k 40 + { 0x27, 0 }, // ; or : + { 0x2b, 0 }, // \ or | + { 0x33, 0 }, // , or < + { 0x35, 0 }, // / or ? + { 0x31, 0 }, // n + { 0x32, 0 }, // m + { 0x34, 0 }, // . or > + { 0x0f, 0 }, // tab + { 0x39, 0 }, // space + { 0x29, 0 }, // ` or ~ 50 + { 0x0e, 0 }, // backspace + { 0x00, 0 }, // + { 0x01, 0 }, // esc + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 60 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x53, 0 }, // KP. + { 0x00, 0 }, + { 0x37, 0 }, // KP* + { 0x00, 0 }, + { 0x4e, 0 }, // KP+ + { 0x00, 0 }, // 70 + { 0x45, 0 }, // num lock + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x35, 1 }, // KP/ + { 0x1c, 1 }, // KPEnter + { 0x00, 0 }, + { 0x4a, 0 }, // KP- + { 0x00, 0 }, + { 0x00, 0 }, // 80 + { 0x00, 0 }, + { 0x52, 0 }, // KP0 + { 0x4f, 0 }, // KP1 + { 0x50, 0 }, // KP2 + { 0x51, 0 }, // KP3 + { 0x4b, 0 }, // KP4 + { 0x4c, 0 }, // KP5 + { 0x4d, 0 }, // KP6 + { 0x47, 0 }, // KP7 + { 0x00, 0 }, // 90 + { 0x48, 0 }, // KP8 + { 0x49, 0 }, // KP9 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 100 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x5d, 1 }, // menu 110 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x52, 1 }, // Insert + { 0x47, 1 }, // Home + { 0x49, 1 }, // PgUp + { 0x53, 1 }, // Delete + { 0x00, 0 }, + { 0x4f, 1 }, // End + { 0x00, 0 }, // 120 + { 0x51, 1 }, // PgDown + { 0x3b, 0 }, // f1 + { 0x4b, 1 }, // left + { 0x4d, 1 }, // right + { 0x50, 1 }, // down + { 0x48, 1 }, // up + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, +}; + +@end diff --git a/client/Mac/README.txt b/client/Mac/README.txt new file mode 100644 index 000000000..e523d02b4 --- /dev/null +++ b/client/Mac/README.txt @@ -0,0 +1,140 @@ + +------------------------------------------------------------------------- + Building FreeRDP on Mac OS X +------------------------------------------------------------------------- + +Platform: Lion with Xcode 4.3.2 + +------------------ + installing cmake +------------------ + +first install macports by googling for it, the run the following command +sudo port install cmake + +---------------- + installing gcc +---------------- +Click on Xcode->Preferences->Downloads +Click on Components +Click on Install Command line tools + +You will be prompted for your Apple Developer userid and password + +---------------------------------------- + download FreeRDP source code using git +---------------------------------------- + +mkdir ~/projects/A8 +cd ~/projects/A8 +git clone git://github.com/FreeRDP/FreeRDP.git + +------------------ + building FreeRDP +------------------ + +cd ~projects/A8/FreeRDP +cmake -DWITH_MACAUDIO=ON -DCMAKE_INSTALL_PREFIX="" +make +make install + +------------------------ + creating Xcode project +------------------------ + +Start xcode +Select 'Create a new xcode project' +In 'Choose a template for your new project', click on Mac OS X -> application +Click on 'Cocoa Application' +Click on next +I used the following: +Product Name: Mac +Company Identifier: com.freerdp +Check 'Automatic Reference Counting' +Create the project in your directory of choice + +------------------------------- + Adding files to your projects +------------------------------- + +Add the following files to your project: + +cd ~/projects/A8/FreeRDP/client/Mac/MRDPCursor.h +cd ~/projects/A8/FreeRDP/client/Mac/MRDPCursor.m +cd ~/projects/A8/FreeRDP/client/Mac/MRDPView.h +cd ~/projects/A8/FreeRDP/client/Mac/MRDPView.m + +This is what your AppDelegate.h file should like like + +#import +#import "MRDPView.h" + +@interface AppDelegate : NSObject + +@property (assign) IBOutlet NSWindow *window; +@property (assign) IBOutlet MRDPView *mrdpView; + +int rdp_connect(); + +@end + +This is what your AppDelegate.m file should like like + +#import "AppDelegate.h" + +@implementation AppDelegate + +@synthesize window = _window; +@synthesize mrdpView; + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + rdp_connect(); +} + +- (void) applicationWillTerminate:(NSNotification *)notification +{ + [mrdpView releaseResources]; +} + +@end + +---------------------------------- + Modifying your MainMenu.xib file +---------------------------------- + +In your project select MainMenu.xib and drag a NSView object intot the main window +Name the class MRDPView +In Interface Builder, select the Application Delegate and tie the mrdpview outlet to the NSView +Set the default size of the main window to 1024x768. This is FreeRDP's default resolution + +---------------------------- + Configuring build settings +---------------------------- + +In Project Navigator, click on Mac +Click on Targets -> Mac +Click on Build Phases +Click on 'Link Binary With Libraries' and click on the + button, then click on the 'Add Other' button to add the following dynamic libraries +~/projects/A8/FreeRDP/libfreerdp-core/libfreerdp-core.dylib +~/projects/A8/FreeRDP/libfreerdp-channels/libfreerdp-channels.dylilb +~/projects/A8/FreeRDP/libfreerdp-utils/libfreerdp-utils.dylib +~/projects/A8/FreeRDP/libfreerdp-codec/libfreerdp-codec.dylib +~/projects/A8/FreeRDP/libfreerdp-cache/libfreerdp-cache.dylib +~/projects/A8/FreeRDP/libfreerdp-gdi/libfreerdp-gdi.dylib + +Click on 'Build Settings' +In 'Search Paths -> Library Search Paths' set the following + Header Search Path Debug: ~/projects/A8/FreeRDP/include + Header Search Path Release: ~/projects/A8/FreeRDP/include + +TODO: in build settings, set strip build product to yes when done debugging + +--------------------------- + To deploy the application +--------------------------- + +in xcode, click on Product->Archive +Click on Distribute button +Select Export As -> application + diff --git a/freerdp.spec b/freerdp.spec index 96c655e61..4eac7c005 100644 --- a/freerdp.spec +++ b/freerdp.spec @@ -97,6 +97,7 @@ cmake \ -DWITH_CUPS:BOOL=ON \ -DWITH_PCSC:BOOL=ON \ -DWITH_PULSEAUDIO:BOOL=ON \ + -DWITH_MACAUDIO:BOOL=ON \ -DWITH_X11:BOOL=ON \ -DWITH_XCURSOR:BOOL=ON \ -DWITH_XEXT:BOOL=ON \ From b01e6947c83f6c2b5739b765819a610efdfcf9c2 Mon Sep 17 00:00:00 2001 From: Thomas Goddard Date: Thu, 10 May 2012 13:18:29 -0700 Subject: [PATCH 02/27] Adding cmake Xcode project generation. This will work for generating an Xcode project from cmake. Still in progress, but initial working version. --- client/Mac/AppDelegate.h | 19 + client/Mac/AppDelegate.m | 26 ++ client/Mac/CMakeLists.txt | 137 +++++++ client/Mac/Credits.rtf | 21 + client/Mac/Info.plist | 34 ++ client/Mac/MRDPCursor.h | 2 +- client/Mac/MRDPView.m | 324 ++++++++-------- client/Mac/MainMenu.xib | 796 ++++++++++++++++++++++++++++++++++++++ client/Mac/main.m | 14 + 9 files changed, 1211 insertions(+), 162 deletions(-) create mode 100644 client/Mac/AppDelegate.h create mode 100644 client/Mac/AppDelegate.m create mode 100644 client/Mac/CMakeLists.txt create mode 100755 client/Mac/Credits.rtf create mode 100644 client/Mac/Info.plist create mode 100755 client/Mac/MainMenu.xib create mode 100644 client/Mac/main.m diff --git a/client/Mac/AppDelegate.h b/client/Mac/AppDelegate.h new file mode 100644 index 000000000..5af060d1c --- /dev/null +++ b/client/Mac/AppDelegate.h @@ -0,0 +1,19 @@ +// +// AppDelegate.h +// MacFreeRDP +// +// Created by Thomas Goddard on 5/8/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import +#import "MRDPView.h" + +@interface AppDelegate : NSObject + +@property (assign) IBOutlet MRDPView *mrdpView; +@property (assign) IBOutlet NSWindow *window; + + +int rdp_connect(); +@end diff --git a/client/Mac/AppDelegate.m b/client/Mac/AppDelegate.m new file mode 100644 index 000000000..3b7658d80 --- /dev/null +++ b/client/Mac/AppDelegate.m @@ -0,0 +1,26 @@ +// +// AppDelegate.m +// MacFreeRDP +// +// Created by Thomas Goddard on 5/8/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "AppDelegate.h" + +@implementation AppDelegate + +//@synthesize window = _window; +//@synthesize mrdpView; + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + rdp_connect(); +} + +- (void) applicationWillTerminate:(NSNotification *)notification +{ + //[mrdpView releaseResources]; +} + +@end diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt new file mode 100644 index 000000000..3a6f477d3 --- /dev/null +++ b/client/Mac/CMakeLists.txt @@ -0,0 +1,137 @@ + +cmake_minimum_required (VERSION 2.8) +project (MacFreeRDP) +set(CMAKE_COLOR_MAKEFILE ON) + +include(CheckIncludeFiles) +include(CheckLibraryExists) +include(CheckStructHasMember) +include(FindPkgConfig) +include(TestBigEndian) + +# Include our extra modules +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../../cmake/) + +include(AutoVersioning) +include(ConfigOptions) +include(FindOptionalPackage) +include(CheckCCompilerFlag) +include(GNUInstallDirsWrapper) + +# Default to release build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# Default to build shared libs +if(NOT DEFINED BUILD_SHARED_LIBS) + set(BUILD_SHARED_LIBS ON) +endif() + +# Compiler-specific flags +if(CMAKE_COMPILER_IS_GNUCC) + if(CMAKE_BUILD_TYPE STREQUAL "Release") + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") + endif() + if(WITH_SSE2_TARGET) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2") + endif() +endif() + +# Libraries that we have a hard dependency on +if(NOT DEFINED OPENSSL_INCLUDE_DIR OR NOT DEFINED OPENSSL_LIBRARIES) +find_required_package(OpenSSL) +endif() + +# Mac OS X +if(APPLE) + # Set the include files for FreeRDP to the relative path + set(FREERDP_INCLUDE_PATH ${CMAKE_SOURCE_DIR}/../../include/) + set(FRAMEWORK_HEADERS_PATH /System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/) + include_directories (${FREERDP_INCLUDE_PATH} ${FRAMEWORK_HEADERS_PATH} /System/Library/Frameworks) + + # set(CMAKE_OSX_SYSROOT MacOSX10.7.sdk) uncomment to specify SDK version + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmacosx-version-min=10.4") + set(GUI_TYPE MACOSX_BUNDLE) + + find_library(FOUNDATION_LIBRARY Foundation) + message("+ Using foundation library ${FOUNDATION_LIBRARY}") + find_library(COCOA_LIBRARY Cocoa) + message("+ Using cocoa library ${COCOA_LIBRARY}") + find_library(APPKIT_LIBRARY AppKit) + message("+ Using appkit library ${APPKIT_LIBRARY}") + + message(" Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") + # Set the OS X Bundle specific CMake variables which will be used to populate the plist for + # the application bundle + set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME}") + set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.freerdp.mac") + set(MACOSX_BUNDLE_BUNDLE_IDENTIFIER "FreeRDP.Mac") + set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME} Version 1.0.1") + set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME}) + set(MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0.1) + set(MACOSX_BUNDLE_BUNDLE_VERSION 1.0.1) + set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2012. All Rights Reserved.") + + # These variables are specific to our plist and are NOT standard CMake variables + set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "MainMenu") + set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication") + + + mark_as_advanced(COCOA_LIBRARY + FOUNDATION_LIBRARY + APPKIT_LIBRARY) + set(EXTRA_LIBS ${COCOA_LIBRARY} ${FOUNDATION_LIBRARY} ${APPKIT_LIBRARY}) + set(APP_TYPE MACOSX_BUNDLE) +endif() + +# Configure files +# set(XCODE_ATTRIBUTE_REFCOUNT "Object-C Automatic Reference Counting") + +# these are the OS X Interface Builder Files +set (MacFreeRDP_XIBS + MainMenu.xib + Credits.rtf +) + +# the headers +set (MacFreeRDP_Headers + MRDPCursor.h + MRDPView.h + AppDelegate.h) + +set (MacFreeRDP_Source + MRDPCursor.m + MRDPView.m + AppDelegate.m + main.m) + +add_executable(MacFreeRDP + ${APP_TYPE} + ${MacFreeRDP_Headers} + ${MacFreeRDP_Source} + ${MacFreeRDP_XIBS}) + +# This is necessary for the xib file part below +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) +# This allows for automatic xib to nib ibitool +set_target_properties(MacFreeRDP PROPERTIES RESOURCE "${MacFreeRDP_XIBS}") +set_target_properties(MacFreeRDP PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) +set_target_properties(MacFreeRDP PROPERTIES XCODE_ATTRIBUTE_GCC_VERSION com.apple.compilers.llvmgcc42) + + +set_target_properties(MacFreeRDP PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) + +if(NOT WIN32) + find_optional_package(MacAudio) +endif() + + +target_link_libraries(MacFreeRDP ${EXTRA_LIBS}) +target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-core/Debug/libfreerdp-core.dylib) +target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-channels/Debug/libfreerdp-channels.dylib) +target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-cache/Debug/libfreerdp-cache.dylib) +target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-gdi/Debug/libfreerdp-gdi.dylib) +target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-utils/Debug/libfreerdp-utils.dylib) +target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-codec/Debug/libfreerdp-codec.dylib) diff --git a/client/Mac/Credits.rtf b/client/Mac/Credits.rtf new file mode 100755 index 000000000..41b9f4014 --- /dev/null +++ b/client/Mac/Credits.rtf @@ -0,0 +1,21 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\vieww9600\viewh8400\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 + +\f0\b\fs24 \cf0 Engineering: +\b0 \ + Jay sorg\ + Marc-Andre Moreau\ + Vic Lee\ + Otvaio Salvador \ + Laxmikant Rashinkar\ + and others\ +\ + +\b Human Interface Design: +\b0 \ + Laxmikant Rashinkar\ + Jay Sorg\ +} \ No newline at end of file diff --git a/client/Mac/Info.plist b/client/Mac/Info.plist new file mode 100644 index 000000000..530ecb9a7 --- /dev/null +++ b/client/Mac/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + FreeRDP.Mac + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSHumanReadableCopyright + Copyright © 2012 __MyCompanyName__. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/client/Mac/MRDPCursor.h b/client/Mac/MRDPCursor.h index 844769ef8..56ebe0ce9 100644 --- a/client/Mac/MRDPCursor.h +++ b/client/Mac/MRDPCursor.h @@ -6,7 +6,7 @@ // Copyright (c) 2012 FreeRDP.org All rights reserved. // -#import +#import #define boolean int diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index df2a9754f..c1b0f0ced 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -25,6 +25,166 @@ MRDPView *g_mrdpview; @synthesize is_connected; +struct kkey g_keys[256] = +{ + { 0x1e, 0 }, // a 0 + { 0x1f, 0 }, // s + { 0x20, 0 }, // d + { 0x21, 0 }, // f + { 0x23, 0 }, // h + { 0x22, 0 }, // g + { 0x2c, 0 }, // z + { 0x2d, 0 }, // x + { 0x2e, 0 }, // c + { 0x2f, 0 }, // v + { 0x00, 0 }, // 10 + { 0x30, 0 }, // b + { 0x10, 0 }, // q + { 0x11, 0 }, // w + { 0x12, 0 }, // e + { 0x13, 0 }, // r + { 0x15, 0 }, // y + { 0x14, 0 }, // t + { 0x02, 0 }, // 1 + { 0x03, 0 }, // 2 + { 0x04, 0 }, // 3 20 + { 0x05, 0 }, // 4 + { 0x07, 0 }, // 6 + { 0x06, 0 }, // 5 + { 0x0d, 0 }, // = or + + { 0x0a, 0 }, // 9 + { 0x08, 0 }, // 7 + { 0x0c, 0 }, // - or _ + { 0x09, 0 }, // 8 + { 0x0b, 0 }, // 0 + { 0x1b, 0 }, // ] or } 30 + { 0x18, 0 }, // o + { 0x16, 0 }, // u + { 0x1a, 0 }, // [ or { + { 0x17, 0 }, // i + { 0x19, 0 }, // p + { 0x1c, 0 }, // enter + { 0x26, 0 }, // l + { 0x24, 0 }, // j + { 0x28, 0 }, // ' or " + { 0x25, 0 }, // k 40 + { 0x27, 0 }, // ; or : + { 0x2b, 0 }, // \ or | + { 0x33, 0 }, // , or < + { 0x35, 0 }, // / or ? + { 0x31, 0 }, // n + { 0x32, 0 }, // m + { 0x34, 0 }, // . or > + { 0x0f, 0 }, // tab + { 0x39, 0 }, // space + { 0x29, 0 }, // ` or ~ 50 + { 0x0e, 0 }, // backspace + { 0x00, 0 }, // + { 0x01, 0 }, // esc + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 60 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x53, 0 }, // KP. + { 0x00, 0 }, + { 0x37, 0 }, // KP* + { 0x00, 0 }, + { 0x4e, 0 }, // KP+ + { 0x00, 0 }, // 70 + { 0x45, 0 }, // num lock + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x35, 1 }, // KP/ + { 0x1c, 1 }, // KPEnter + { 0x00, 0 }, + { 0x4a, 0 }, // KP- + { 0x00, 0 }, + { 0x00, 0 }, // 80 + { 0x00, 0 }, + { 0x52, 0 }, // KP0 + { 0x4f, 0 }, // KP1 + { 0x50, 0 }, // KP2 + { 0x51, 0 }, // KP3 + { 0x4b, 0 }, // KP4 + { 0x4c, 0 }, // KP5 + { 0x4d, 0 }, // KP6 + { 0x47, 0 }, // KP7 + { 0x00, 0 }, // 90 + { 0x48, 0 }, // KP8 + { 0x49, 0 }, // KP9 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 100 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x5d, 1 }, // menu 110 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x52, 1 }, // Insert + { 0x47, 1 }, // Home + { 0x49, 1 }, // PgUp + { 0x53, 1 }, // Delete + { 0x00, 0 }, + { 0x4f, 1 }, // End + { 0x00, 0 }, // 120 + { 0x51, 1 }, // PgDown + { 0x3b, 0 }, // f1 + { 0x4b, 1 }, // left + { 0x4d, 1 }, // right + { 0x50, 1 }, // down + { 0x48, 1 }, // up + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, +}; + /************************************************************************ methods we override ************************************************************************/ @@ -292,7 +452,7 @@ MRDPView *g_mrdpview; - (void) keyUp:(NSEvent *) event { int key; - + if (!is_connected) { return; } @@ -421,7 +581,8 @@ MRDPView *g_mrdpview; - (void) releaseResources { - for (int i = 0; i < argc; i++) + int i; + for (i = 0; i < argc; i++) { if (argv[i]) free(argv[i]); @@ -1356,164 +1517,5 @@ void cliprdr_send_supported_format_list(freerdp *inst) freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); } -struct kkey g_keys[256] = -{ - { 0x1e, 0 }, // a 0 - { 0x1f, 0 }, // s - { 0x20, 0 }, // d - { 0x21, 0 }, // f - { 0x23, 0 }, // h - { 0x22, 0 }, // g - { 0x2c, 0 }, // z - { 0x2d, 0 }, // x - { 0x2e, 0 }, // c - { 0x2f, 0 }, // v - { 0x00, 0 }, // 10 - { 0x30, 0 }, // b - { 0x10, 0 }, // q - { 0x11, 0 }, // w - { 0x12, 0 }, // e - { 0x13, 0 }, // r - { 0x15, 0 }, // y - { 0x14, 0 }, // t - { 0x02, 0 }, // 1 - { 0x03, 0 }, // 2 - { 0x04, 0 }, // 3 20 - { 0x05, 0 }, // 4 - { 0x07, 0 }, // 6 - { 0x06, 0 }, // 5 - { 0x0d, 0 }, // = or + - { 0x0a, 0 }, // 9 - { 0x08, 0 }, // 7 - { 0x0c, 0 }, // - or _ - { 0x09, 0 }, // 8 - { 0x0b, 0 }, // 0 - { 0x1b, 0 }, // ] or } 30 - { 0x18, 0 }, // o - { 0x16, 0 }, // u - { 0x1a, 0 }, // [ or { - { 0x17, 0 }, // i - { 0x19, 0 }, // p - { 0x1c, 0 }, // enter - { 0x26, 0 }, // l - { 0x24, 0 }, // j - { 0x28, 0 }, // ' or " - { 0x25, 0 }, // k 40 - { 0x27, 0 }, // ; or : - { 0x2b, 0 }, // \ or | - { 0x33, 0 }, // , or < - { 0x35, 0 }, // / or ? - { 0x31, 0 }, // n - { 0x32, 0 }, // m - { 0x34, 0 }, // . or > - { 0x0f, 0 }, // tab - { 0x39, 0 }, // space - { 0x29, 0 }, // ` or ~ 50 - { 0x0e, 0 }, // backspace - { 0x00, 0 }, // - { 0x01, 0 }, // esc - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, // 60 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x53, 0 }, // KP. - { 0x00, 0 }, - { 0x37, 0 }, // KP* - { 0x00, 0 }, - { 0x4e, 0 }, // KP+ - { 0x00, 0 }, // 70 - { 0x45, 0 }, // num lock - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x35, 1 }, // KP/ - { 0x1c, 1 }, // KPEnter - { 0x00, 0 }, - { 0x4a, 0 }, // KP- - { 0x00, 0 }, - { 0x00, 0 }, // 80 - { 0x00, 0 }, - { 0x52, 0 }, // KP0 - { 0x4f, 0 }, // KP1 - { 0x50, 0 }, // KP2 - { 0x51, 0 }, // KP3 - { 0x4b, 0 }, // KP4 - { 0x4c, 0 }, // KP5 - { 0x4d, 0 }, // KP6 - { 0x47, 0 }, // KP7 - { 0x00, 0 }, // 90 - { 0x48, 0 }, // KP8 - { 0x49, 0 }, // KP9 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, // 100 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x5d, 1 }, // menu 110 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x52, 1 }, // Insert - { 0x47, 1 }, // Home - { 0x49, 1 }, // PgUp - { 0x53, 1 }, // Delete - { 0x00, 0 }, - { 0x4f, 1 }, // End - { 0x00, 0 }, // 120 - { 0x51, 1 }, // PgDown - { 0x3b, 0 }, // f1 - { 0x4b, 1 }, // left - { 0x4d, 1 }, // right - { 0x50, 1 }, // down - { 0x48, 1 }, // up - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, -}; @end diff --git a/client/Mac/MainMenu.xib b/client/Mac/MainMenu.xib new file mode 100755 index 000000000..bff95a9d5 --- /dev/null +++ b/client/Mac/MainMenu.xib @@ -0,0 +1,796 @@ + + + + 1070 + 11D50b + 2177 + 1138.32 + 568.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2177 + + + NSView + NSMenu + NSWindowTemplate + NSMenuItem + NSCustomView + IBNSLayoutConstraint + NSCustomObject + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + + + FreeRDP + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + FreeRDP + + + + About FreeRDP + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide FreeRDP + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit FreeRDP + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + + + + Edit + + 1048576 + 2147483647 + + + + + + Format + + 2147483647 + + + + + + View + + 1048576 + 2147483647 + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + + + Mac Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + 15 + 2 + {{163, 10}, {1024, 768}} + 1954021376 + FreeRDP + NSWindow + + + {1024, 768} + {1024, 768} + + + 256 + + + + 268 + {1024, 768} + + + _NS:9 + MRDPView + + + {1024, 768} + + + + + {{0, 0}, {1366, 746}} + {1024, 790} + {1024, 790} + 128 + YES + + + AppDelegate + + + NSFontManager + + + + + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 568 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + performZoom: + + + + 240 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + showHelp: + + + + 493 + + + + mrdpView + + + + 565 + + + + window + + + + 567 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + + + + + + + + + + + + 19 + + + + + + + + 56 + + + + + + + + 217 + + + + + + 83 + + + + + + 57 + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 236 + + + + + 149 + + + + + 145 + + + + + 24 + + + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + + + + 371 + + + + + + + + 372 + + + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + 8 + 29 + 3 + + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + 8 + 29 + 3 + + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + 8 + 29 + 3 + + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + 8 + 29 + 3 + + + + + + + 375 + + + + + + 420 + + + + + 490 + + + + + + + + 491 + + + + + + + + 492 + + + + + 494 + + + + + 551 + + + + + 561 + + + + + 562 + + + + + 563 + + + + + 564 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + com.apple.InterfaceBuilder.CocoaPlugin + {{380, 496}, {480, 360}} + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 568 + + + + + AppDelegate + NSObject + + MRDPView + NSWindow + + + + mrdpView + MRDPView + + + window + NSWindow + + + + IBProjectSource + ./Classes/AppDelegate.h + + + + MRDPView + NSView + + IBProjectSource + ./Classes/MRDPView.h + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + YES + 3 + + {11, 11} + {10, 3} + + YES + + diff --git a/client/Mac/main.m b/client/Mac/main.m new file mode 100644 index 000000000..a7ee86852 --- /dev/null +++ b/client/Mac/main.m @@ -0,0 +1,14 @@ +// +// main.m +// MacFreeRDP +// +// Created by Thomas Goddard on 5/8/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **)argv); +} From 4cfd9b823080b3439b109e905101261191083000 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Thu, 10 May 2012 17:28:38 -0700 Subject: [PATCH 03/27] Mac: test commit --- client/Mac/MRDPView.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h index 43c523263..b91ffc0f1 100644 --- a/client/Mac/MRDPView.h +++ b/client/Mac/MRDPView.h @@ -35,7 +35,7 @@ typedef int boolean; int height; int argc; char **argv; - + // store state info for some keys int kdlshift; int kdrshift; @@ -46,7 +46,7 @@ typedef int boolean; int kdlmeta; int kdrmeta; int kdcapslock; - + @public NSWindow *ourMainWindow; NSPasteboard *pasteboard_rd; // for reading from clipboard From 3f4c3eba3d7ba465e345803d90caa2d977ab3cdc Mon Sep 17 00:00:00 2001 From: Thomas Goddard Date: Sat, 12 May 2012 17:07:23 -0700 Subject: [PATCH 04/27] Added xcode.sh for automatic Xcode project generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated CMake lists to include additional build settings for automatic reference counting, and added Xcode.sh file for Xcode project generation, compilation, etc… --- .gitignore | 2 ++ client/Mac/CMakeLists.txt | 36 +++++++++++++------- xcode.sh | 71 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 12 deletions(-) create mode 100755 xcode.sh diff --git a/.gitignore b/.gitignore index 00fb8eddc..73c0bf88c 100644 --- a/.gitignore +++ b/.gitignore @@ -39,10 +39,12 @@ Debug *.dylib cunit/test_freerdp client/X11/xfreerdp +client/Mac/xcode client/test/freerdp-test client/DirectFB/dfreerdp server/test/tfreerdp-server server/X11/xfreerdp-server +xcode # Other *~ diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index 3a6f477d3..870a65950 100644 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -18,7 +18,7 @@ include(FindOptionalPackage) include(CheckCCompilerFlag) include(GNUInstallDirsWrapper) -# Default to release build type +# Default to debug build type if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug") endif() @@ -41,7 +41,7 @@ endif() # Libraries that we have a hard dependency on if(NOT DEFINED OPENSSL_INCLUDE_DIR OR NOT DEFINED OPENSSL_LIBRARIES) -find_required_package(OpenSSL) + find_required_package(OpenSSL) endif() # Mac OS X @@ -51,10 +51,11 @@ if(APPLE) set(FRAMEWORK_HEADERS_PATH /System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/) include_directories (${FREERDP_INCLUDE_PATH} ${FRAMEWORK_HEADERS_PATH} /System/Library/Frameworks) - # set(CMAKE_OSX_SYSROOT MacOSX10.7.sdk) uncomment to specify SDK version + # set(CMAKE_OSX_SYSROOT MacOSX10.7.sdk) # uncomment to specify SDK version set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmacosx-version-min=10.4") set(GUI_TYPE MACOSX_BUNDLE) + # Import libraries find_library(FOUNDATION_LIBRARY Foundation) message("+ Using foundation library ${FOUNDATION_LIBRARY}") find_library(COCOA_LIBRARY Cocoa) @@ -74,10 +75,9 @@ if(APPLE) set(MACOSX_BUNDLE_BUNDLE_VERSION 1.0.1) set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2012. All Rights Reserved.") - # These variables are specific to our plist and are NOT standard CMake variables + # Specific plist and NOT standard CMake variables set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "MainMenu") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication") - mark_as_advanced(COCOA_LIBRARY FOUNDATION_LIBRARY @@ -86,21 +86,19 @@ if(APPLE) set(APP_TYPE MACOSX_BUNDLE) endif() -# Configure files -# set(XCODE_ATTRIBUTE_REFCOUNT "Object-C Automatic Reference Counting") - -# these are the OS X Interface Builder Files +# OS X Interface Builder files set (MacFreeRDP_XIBS MainMenu.xib Credits.rtf ) -# the headers +# Headers set (MacFreeRDP_Headers MRDPCursor.h MRDPView.h AppDelegate.h) +# Source set (MacFreeRDP_Source MRDPCursor.m MRDPView.m @@ -115,19 +113,33 @@ add_executable(MacFreeRDP # This is necessary for the xib file part below configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) + # This allows for automatic xib to nib ibitool set_target_properties(MacFreeRDP PROPERTIES RESOURCE "${MacFreeRDP_XIBS}") + +# Automatic ref counting set_target_properties(MacFreeRDP PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) -set_target_properties(MacFreeRDP PROPERTIES XCODE_ATTRIBUTE_GCC_VERSION com.apple.compilers.llvmgcc42) +# Support for automatic reference counting requires non-fragile abi. +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-nonfragile-abi") +# XCode project architecture to native architecture of build machine +# ----------------------------------------------------------------------------------------------------- +# Issue: Had some issues with FreeRDP project building only 64 bit and +# MacFreeRDP attempting to link to both 32 and 64 for dual target. +# In the future the FreeRDP Xcode project should be pulled in for a couple of reasons: +# 1) better step-into debugging 2) automatic dependency compilation and multi-arch compilation + linkage +# If you know the solutions for 1 and 2, please add below. +set_target_properties(MacFreeRDP PROPERTIES XCODE_ATTRIBUTE_ARCHS "$(NATIVE_ARCH_ACTUAL)") + +# Set the info plist to the custom instance set_target_properties(MacFreeRDP PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) if(NOT WIN32) find_optional_package(MacAudio) endif() - +# Add all libraries target_link_libraries(MacFreeRDP ${EXTRA_LIBS}) target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-core/Debug/libfreerdp-core.dylib) target_link_libraries(MacFreeRDP ${CMAKE_SOURCE_DIR}/../../xcode/libfreerdp-channels/Debug/libfreerdp-channels.dylib) diff --git a/xcode.sh b/xcode.sh new file mode 100755 index 000000000..5e8589484 --- /dev/null +++ b/xcode.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# Xcode generated files directory +XCODE_PROJ_DIR=xcode +# MacFreeRDP client directory +CLIENT_MAC_DIR=./client/Mac/ +pushd . + +GEN='Xcode' + +# Build settings +ARCH=-DCMAKE_OSX_ARCHITECTURES="${CMAKE_OSX_ARCHITECTURES:-i386;x86_64}" +BUILDTYPE=-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE:Debug}" +MANPAGES=-DWITH_MANPAGES="${WITHMANPAGES:NO}" + +# Run cmake for FreeRDP and MacFreeRDP +mkdir ${XCODE_PROJ_DIR} >/dev/null 2>&1 +pushd ${XCODE_PROJ_DIR} +cmake ${BUILDTYPE} -G "$GEN" ${ARCH} ../ +popd +mkdir ${CLIENT_MAC_DIR}/${XCODE_PROJ_DIR} >/dev/null 2>&1 +pushd ${CLIENT_MAC_DIR}/${XCODE_PROJ_DIR} +cmake ${BUILDTYPE} -G "$GEN" ${ARCH} ../ +popd + +# Check for errors; otherwise, ask for compile. +if [ "$?" -ne 0 ]; then + echo "CMake failed. Please check error messages" + popd > /dev/null + exit +else + popd + while true + do + echo -n "Compile FreeRDP? (y or n) - (y recommended for MacFreeRDP compilation):" + read CONFIRM + case $CONFIRM in + y|Y|YES|yes|Yes) + pushd ./${XCODE_PROJ_DIR} + xcodebuild + popd + break ;; + n|N|no|NO|No) + echo OK - you entered $CONFIRM + break + ;; + *) echo Please enter only y or n + esac + done + + echo "SUCCESS!" + while true + do + echo -n "Open Xcode projects now? (y or n):" + read CONFIRM + case $CONFIRM in + y|Y|YES|yes|Yes) + open ${CLIENT_MAC_DIR}/${XCODE_PROJ_DIR}/MacFreeRDP.xcodeproj + open ./${XCODE_PROJ_DIR}/FreeRDP.xcodeproj + break ;; + n|N|no|NO|No) + echo OK - $CONFIRM + break + ;; + *) echo Please enter only y or n + esac + done + + echo -n "NOTE: Dragging FreeRDP project from finder +onto the MacFreeRDP project in Xcode will enable code stepping from MacFreeRDP into FreeRDP. +" +fi \ No newline at end of file From bdc617dc033e22e377083a1dff862e2481d7a417 Mon Sep 17 00:00:00 2001 From: Thomas Goddard Date: Sat, 12 May 2012 17:09:50 -0700 Subject: [PATCH 05/27] Cleaned up text a little. --- xcode.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcode.sh b/xcode.sh index 5e8589484..eebfed050 100755 --- a/xcode.sh +++ b/xcode.sh @@ -65,7 +65,7 @@ else esac done - echo -n "NOTE: Dragging FreeRDP project from finder -onto the MacFreeRDP project in Xcode will enable code stepping from MacFreeRDP into FreeRDP. + echo -n "NOTE: Dragging FreeRDP project from finder onto the MacFreeRDP project in Xcode + will enable code stepping from MacFreeRDP into FreeRDP. " fi \ No newline at end of file From a34ecc48b03c445cce604ae0130820a475628747 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Jun 2012 15:32:10 -0700 Subject: [PATCH 06/27] Fix for corruption during color conversion on Windows. --- client/Windows/wf_graphics.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/Windows/wf_graphics.c b/client/Windows/wf_graphics.c index a79628f1a..d6cfeefe0 100644 --- a/client/Windows/wf_graphics.c +++ b/client/Windows/wf_graphics.c @@ -39,18 +39,17 @@ HBITMAP wf_create_dib(wfInfo* wfi, int width, int height, int bpp, uint8* data, */ negHeight = (height < 0) ? height : height * (-1); - hdc = GetDC(NULL); bmi.bmiHeader.biSize = sizeof(BITMAPINFO); bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biHeight = negHeight; bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = bpp; + bmi.bmiHeader.biBitCount = wfi->dstBpp; bmi.bmiHeader.biCompression = BI_RGB; bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &cdata, NULL, 0); if (data != NULL) - freerdp_image_convert(data, cdata, width, height, bpp, bpp, wfi->clrconv); + freerdp_image_convert(data, cdata, width, height, bpp, wfi->dstBpp, wfi->clrconv); if (pdata != NULL) *pdata = cdata; From 924ed187c1eadf38f9f2f3a19a8ed0d82e196bdd Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Wed, 20 Jun 2012 09:57:20 -0700 Subject: [PATCH 07/27] In MacFreerdpClient, added support for the following + clipboard redirection + audio redirection + RAIL support (ongoing) --- client/Mac/MRDPCursor.h | 2 +- client/Mac/MRDPCursor.m | 2 +- client/Mac/MRDPRailView.h | 47 + client/Mac/MRDPRailView.m | 669 +++++++++ client/Mac/MRDPRailWindow.h | 13 + client/Mac/MRDPRailWindow.m | 18 + client/Mac/MRDPView.h | 67 +- client/Mac/MRDPView.m | 1453 ++++++++++++++----- client/Mac/MRDPWindow.h | 15 + client/Mac/MRDPWindow.m | 11 + client/Mac/Mac/MRDPCursor.h | 25 + client/Mac/Mac/MRDPCursor.m | 12 + client/Mac/Mac/MRDPRailWindow.h | 13 + client/Mac/Mac/MRDPRailWindow.m | 18 + client/Mac/Mac/MRDPView.h | 177 +++ client/Mac/Mac/MRDPView.m | 2314 +++++++++++++++++++++++++++++++ 16 files changed, 4508 insertions(+), 348 deletions(-) create mode 100644 client/Mac/MRDPRailView.h create mode 100644 client/Mac/MRDPRailView.m create mode 100644 client/Mac/MRDPRailWindow.h create mode 100644 client/Mac/MRDPRailWindow.m create mode 100644 client/Mac/MRDPWindow.h create mode 100644 client/Mac/MRDPWindow.m create mode 100644 client/Mac/Mac/MRDPCursor.h create mode 100644 client/Mac/Mac/MRDPCursor.m create mode 100644 client/Mac/Mac/MRDPRailWindow.h create mode 100644 client/Mac/Mac/MRDPRailWindow.m create mode 100644 client/Mac/Mac/MRDPView.h create mode 100644 client/Mac/Mac/MRDPView.m diff --git a/client/Mac/MRDPCursor.h b/client/Mac/MRDPCursor.h index 844769ef8..9df734ba4 100644 --- a/client/Mac/MRDPCursor.h +++ b/client/Mac/MRDPCursor.h @@ -2,7 +2,7 @@ // MRDPCursor.h // MacFreeRDP // -// Created by Laxmikant Rashinkar on 3/28/12. +// Created by Laxmikant Rashinkar // Copyright (c) 2012 FreeRDP.org All rights reserved. // diff --git a/client/Mac/MRDPCursor.m b/client/Mac/MRDPCursor.m index 849d575ef..29a93c808 100644 --- a/client/Mac/MRDPCursor.m +++ b/client/Mac/MRDPCursor.m @@ -2,7 +2,7 @@ // MRDPCursor.m // MacFreeRDP // -// Created by Laxmikant Rashinkar on 3/28/12. +// Created by Laxmikant Rashinkar // Copyright (c) 2012 FreeRDP.org All rights reserved. // diff --git a/client/Mac/MRDPRailView.h b/client/Mac/MRDPRailView.h new file mode 100644 index 000000000..7240e6234 --- /dev/null +++ b/client/Mac/MRDPRailView.h @@ -0,0 +1,47 @@ +#import + +#define boolean int + +#import "freerdp/gdi/gdi.h" +#import "freerdp/rail/rail.h" + +@interface MRDPRailView : NSView +{ + freerdp * rdp_instance; + rdpContext * context; + NSBitmapImageRep * bmiRep; + NSPoint savedDragLocation; + char * pixelData; + boolean mouseInClientArea; + int width; + int height; + int savedWindowId; + + // store state info for some keys + int kdlshift; + int kdrshift; + int kdlctrl; + int kdrctrl; + int kdlalt; + int kdralt; + int kdlmeta; + int kdrmeta; + int kdcapslock; + + @public + boolean isMoveSizeInProgress; + boolean saveInitialDragLoc; + boolean skipMoveWindowOnce; +} + +- (void) updateDisplay; +- (void) setRdpInstance:(freerdp *) instance width:(int) w andHeight:(int) h windowID:(int) windowID; +- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr; +- (void) setupBmiRep:(int) width :(int) height; + +void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window); +void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove); +void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param); + +@end + diff --git a/client/Mac/MRDPRailView.m b/client/Mac/MRDPRailView.m new file mode 100644 index 000000000..2cb0b191e --- /dev/null +++ b/client/Mac/MRDPRailView.m @@ -0,0 +1,669 @@ +#include "MRDPRailView.h" + +#define USE_RAIL_CVT + +@implementation MRDPRailView + +MRDPRailView * g_mrdpRailView; + +struct kkey +{ + int key_code; + int flags; +}; + +extern struct kkey g_keys[]; + +- (void) updateDisplay +{ + boolean moveWindow = NO; + int i; + NSRect drawRect; + NSRect srcRectOuter; + NSRect destRectOuter; + + rdpGdi * gdi; + + if ((context == 0) || (context->gdi == 0)) + return; + + if (context->gdi->primary->hdc->hwnd->invalid->null) + return; + + if (context->gdi->drawing != context->gdi->primary) + return; + + gdi = context->gdi; + + srcRectOuter = NSMakeRect(0, 0, self->width, self->height); + destRectOuter = [[self window] frame]; + + // cannot be bigger than our current screen size + NSRect screenSize = [[NSScreen mainScreen] frame]; + if (destRectOuter.size.width > screenSize.size.width) { + destRectOuter.size.width = screenSize.size.width; + moveWindow = YES; + } + + // RAIL_TODO do not hardcode to 22 + if (destRectOuter.size.height > screenSize.size.height) { + destRectOuter.size.height = screenSize.size.height; + moveWindow = YES; + } + + // cannot have negative cords + if (destRectOuter.origin.x < 0) { + destRectOuter.origin.x = 0; + moveWindow = YES; + } + + if (destRectOuter.origin.y < 0) { + destRectOuter.origin.y = 0; + moveWindow = YES; + } + + [self setupBmiRep:destRectOuter.size.width :destRectOuter.size.height]; + + if (moveWindow) { + moveWindow = NO; + RAIL_WINDOW_MOVE_ORDER newWndLoc; + apple_to_windowMove(&destRectOuter, &newWndLoc); + newWndLoc.windowId = savedWindowId; + //skipMoveWindowOnce = TRUE; + //mac_send_rail_client_event(g_mrdpRailView->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &newWndLoc); + } + + //printf("MRDPRailView : updateDisplay : drawing %d rectangles\n", gdi->primary->hdc->hwnd->ninvalid); + + // if src and dest rect are not the same size, copy the entire + // rectangle in one go instead of in many small rectangles + + //if (destRectOuter.size.width != self->width) { + if (1) { + destRectOuter.origin.y = height - destRectOuter.origin.y - destRectOuter.size.height; + rail_convert_color_space1(pixelData, (char *) gdi->primary_buffer, + &destRectOuter, self->width, self->height); + + if (moveWindow) + [self setNeedsDisplayInRect:destRectOuter]; + else + [self setNeedsDisplayInRect:[self frame]]; + + gdi->primary->hdc->hwnd->ninvalid = 0; + + return; + } + + for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++) + { + drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x; + drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y; + drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w; + drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h; + + rail_convert_color_space(pixelData, (char *) gdi->primary_buffer, + &drawRect, &destRectOuter, + &drawRect, &srcRectOuter); + + [self setNeedsDisplayInRect:drawRect]; + } + gdi->primary->hdc->hwnd->ninvalid = 0; +} + +/** ********************************************************************* + * called when our view needs to be redrawn + ***********************************************************************/ + +- (void) drawRect:(NSRect)dirtyRect +{ + [bmiRep drawInRect:dirtyRect fromRect:dirtyRect operation:NSCompositeCopy fraction:1.0 respectFlipped:NO hints:nil]; + if (pixelData) { + free(pixelData); + pixelData = NULL; + } + bmiRep = nil; +} + +/** ********************************************************************* + * become first responder so we can get keyboard and mouse events + ***********************************************************************/ + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +/** ********************************************************************* + * called when a mouse move event occurrs + * + * 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 + * versions, we do this manually. + * + * 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 + ***********************************************************************/ + +- (void) mouseMoved:(NSEvent *)event +{ + [super mouseMoved:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + + y = height - y; + + // send mouse motion event to RDP server + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); +} + +/** ********************************************************************* + * called when left mouse button is pressed down + ***********************************************************************/ + +- (void)mouseDown:(NSEvent *) event +{ + [super mouseDown:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); +} + +/** ********************************************************************* + * called when left mouse button is released + ***********************************************************************/ + +- (void) mouseUp:(NSEvent *) event +{ + [super mouseUp:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); +} + +/** ********************************************************************* + * called when right mouse button is pressed down + ***********************************************************************/ + +- (void) rightMouseDown:(NSEvent *)event +{ + [super rightMouseDown:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y); +} + +/** ********************************************************************* + * called when right mouse button is released + ***********************************************************************/ + +- (void) rightMouseUp:(NSEvent *)event +{ + [super rightMouseUp:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON2, x, y); +} + +/** ********************************************************************* + * called when middle mouse button is pressed + ***********************************************************************/ + +- (void) otherMouseDown:(NSEvent *)event +{ + [super otherMouseDown:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y); +} + +/** ********************************************************************* + * called when middle mouse button is released + ***********************************************************************/ + +- (void) otherMouseUp:(NSEvent *)event +{ + [super otherMouseUp:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON3, x, y); +} + +- (void) scrollWheel:(NSEvent *)event +{ + uint16 flags; + + [super scrollWheel:event]; + + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); + int y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + flags = PTR_FLAGS_WHEEL; + if ([event deltaY] < 0) { + flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; + } + else { + flags |= 0x0078; + } + x += (int) [event deltaX]; + y += (int) [event deltaY]; + rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); +} + +/** ********************************************************************* + * called when mouse is moved with left button pressed + * note: invocation order is: mouseDown, mouseDragged, mouseUp + ***********************************************************************/ + +- (void) mouseDragged:(NSEvent *)event +{ + [super mouseDragged:event]; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + if (isMoveSizeInProgress) { + if (saveInitialDragLoc) { + saveInitialDragLoc = NO; + savedDragLocation.x = x; + savedDragLocation.y = y; + return; + } + + int newX = x - savedDragLocation.x; + int newY = y - savedDragLocation.y; + + NSRect r = [[self window] frame]; + r.origin.x += newX; + r.origin.y += newY; + [[self window] setFrame:r display:YES]; + + return; + } + + NSRect winFrame = [[self window] frame]; + x = (int) (winFrame.origin.x + loc.x); + y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + // send mouse motion event to RDP server + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); +} + +/** ********************************************************************* + * called when a key is pressed + ***********************************************************************/ + +- (void) keyDown:(NSEvent *) event +{ + int key; + + key = [event keyCode]; + rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_DOWN, g_keys[key].key_code); +} + +/** ********************************************************************* + * called when a key is released + ***********************************************************************/ + +- (void) keyUp:(NSEvent *) event +{ + int key; + + key = [event keyCode]; + rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_RELEASE, g_keys[key].key_code); +} + +/** ********************************************************************* + * called when shift, control, alt and meta keys are pressed/released + ***********************************************************************/ + +- (void) flagsChanged:(NSEvent *) event +{ + NSUInteger mf = [event modifierFlags]; + + // 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 + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x2a); + kdlshift = 1; + } + if ((kdlshift != 0) && ((mf & 2) == 0)) { + // left shift went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x2a); + kdlshift = 0; + } + + // right shift + if ((kdrshift == 0) && ((mf & 4) != 0)) { + // right shift went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x36); + kdrshift = 1; + } + if ((kdrshift != 0) && ((mf & 4) == 0)) { + // right shift went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x36); + kdrshift = 0; + } + + // left ctrl + if ((kdlctrl == 0) && ((mf & 1) != 0)) { + // left ctrl went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x1d); + kdlctrl = 1; + } + if ((kdlctrl != 0) && ((mf & 1) == 0)) { + // left ctrl went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x1d); + kdlctrl = 0; + } + + // right ctrl + if ((kdrctrl == 0) && ((mf & 0x2000) != 0)) { + // right ctrl went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x1d); + kdrctrl = 1; + } + if ((kdrctrl != 0) && ((mf & 0x2000) == 0)) { + // right ctrl went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x1d); + kdrctrl = 0; + } + + // left alt + if ((kdlalt == 0) && ((mf & 0x20) != 0)) { + // left alt went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x38); + kdlalt = 1; + } + if ((kdlalt != 0) && ((mf & 0x20) == 0)) { + // left alt went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x38); + kdlalt = 0; + } + + // right alt + if ((kdralt == 0) && ((mf & 0x40) != 0)) { + // right alt went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x38); + kdralt = 1; + } + if ((kdralt != 0) && ((mf & 0x40) == 0)) { + // right alt went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x38); + kdralt = 0; + } + + // left meta + if ((kdlmeta == 0) && ((mf & 0x08) != 0)) { + // left meta went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5b); + kdlmeta = 1; + } + if ((kdlmeta != 0) && ((mf & 0x08) == 0)) { + // left meta went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5b); + kdlmeta = 0; + } + + // right meta + if ((kdrmeta == 0) && ((mf & 0x10) != 0)) { + // right meta went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5c); + kdrmeta = 1; + } + if ((kdrmeta != 0) && ((mf & 0x10) == 0)) { + // right meta went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5c); + kdrmeta = 0; + } +} + +- (void) setRdpInstance:(freerdp *) instance width:(int) w andHeight:(int) h windowID:(int) windowID +{ + rdp_instance = instance; + context = instance->context; + width = w; + height = h; + savedWindowId = windowID; + + NSRect tr = NSMakeRect(0, 0, + [[NSScreen mainScreen] frame].size.width, + [[NSScreen mainScreen] frame].size.height); + + NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:tr options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveAlways owner:self userInfo:nil]; + + [self addTrackingArea:trackingArea]; + + g_mrdpRailView = self; + + [self becomeFirstResponder]; +} + +- (void) setupBmiRep:(int) frameWidth :(int) frameHeight +{ + struct rgba_data + { + char red; + char green; + char blue; + char alpha; + }; + + if (pixelData) + free(pixelData); + + pixelData = (char *) malloc(frameWidth * frameHeight * sizeof(struct rgba_data)); + bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixelData + pixelsWide:frameWidth + pixelsHigh:frameHeight + bitsPerSample:8 + samplesPerPixel:sizeof(struct rgba_data) + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 + bytesPerRow:frameWidth * sizeof(struct rgba_data) + bitsPerPixel:0]; +} + +void rail_cvt_from_rect(char *dest, char *src, NSRect destRect, int destWidth, int destHeight, NSRect srcRect) +{ +} + +/** ********************************************************************* + * color space conversion used specifically in RAIL + ***********************************************************************/ + +int rail_convert_color_space(char * destBuf, char * srcBuf, + NSRect * destRect, NSRect * destRectOuter, + NSRect * srcRect, NSRect * srcRectOuter) +{ + int i; + int j; + int numRows; + int srcX; + int srcY; + int destX; + int destY; + int pixelsPerRow; + int pixel; + int pixel1; + int pixel2; + int * src32; + int * dest32; + + int destWidth = destRectOuter->size.width; + int destHeight = destRectOuter->size.height; + int srcWidth = srcRectOuter->size.width; + int srcHeight = srcRectOuter->size.height; + + if ((!destBuf) || (!srcBuf)) { + return 1; + } + + if ((destRect->size.width != srcRect->size.width) || (destRect->size.height != srcRect->size.height)) { + printf("##### RAIL_TODO: rail_convert_color_space : destRect & srcRect dimensions don't match\n"); + return 1; + } + + numRows = srcRect->size.height; + srcX = srcRect->origin.x; + srcY = srcRect->origin.y; + destX = destRect->origin.x; + destY = destRect->origin.y; + pixelsPerRow = destRect->size.width; + + for (i = 0; i < numRows; i++) + { + src32 = (int *) (srcBuf + ((srcY + i) * srcWidth + srcX) * 4); + dest32 = (int *) (destBuf + ((destY + i) * destWidth + destX) * 4); + + for (j = 0; j < pixelsPerRow; j++) + { + pixel = *src32; + pixel1 = (pixel & 0x00ff0000) >> 16; + pixel2 = (pixel & 0x000000ff) << 16; + pixel = (pixel & 0xff00ff00) | pixel1 | pixel2; + + *dest32 = pixel; + src32++; + dest32++; + } + } + + destRect->origin.y = destHeight - destRect->origin.y - destRect->size.height; + + return 0; +} + +// RAIL_TODO rename this func +void rail_convert_color_space1(char *destBuf, char * srcBuf, + NSRect * destRect, int width, int height) +{ + int i; + int j; + int numRows; + int srcX; + int srcY; + int destX; + int destY; + int pixelsPerRow; + int pixel; + int pixel1; + int pixel2; + int * src32; + int * dest32; + + int destWidth = destRect->size.width; + int destHeight = destRect->size.height; + + if ((!destBuf) || (!srcBuf)) { + return; + } + + numRows = destHeight; + srcX = destRect->origin.x; + srcY = destRect->origin.y; + destX = 0; + destY = 0; + pixelsPerRow = destWidth; + + for (i = 0; i < numRows; i++) + { + src32 = (int *) (srcBuf + ((srcY + i) * width + srcX) * 4); + dest32 = (int *) (destBuf + ((destY + i) * destWidth + destX) * 4); + + for (j = 0; j < pixelsPerRow; j++) + { + pixel = *src32; + pixel1 = (pixel & 0x00ff0000) >> 16; + pixel2 = (pixel & 0x000000ff) << 16; + pixel = (pixel & 0xff00ff00) | pixel1 | pixel2; + + *dest32 = pixel; + + src32++; + dest32++; + } + } + + destRect->origin.y = destHeight - destRect->origin.y - destRect->size.height; + return; +} + +/** + * let RDP server know that window has moved + */ + +void rail_MoveWindow(rdpRail * rail, rdpWindow * window) +{ + if (g_mrdpRailView->isMoveSizeInProgress) { + return; + } + + if (g_mrdpRailView->skipMoveWindowOnce) { + g_mrdpRailView->skipMoveWindowOnce = NO; + return; + } + + // this rect is based on Windows co-ordinates... + NSRect r; + r.origin.x = window->windowOffsetX; + r.origin.y = window->windowOffsetY; + r.size.width = window->windowWidth; + r.size.height = window->windowHeight; + + windows_to_apple_cords(&r); + [[g_mrdpRailView window] setFrame:r display:YES]; +} + +@end + diff --git a/client/Mac/MRDPRailWindow.h b/client/Mac/MRDPRailWindow.h new file mode 100644 index 000000000..629dc819c --- /dev/null +++ b/client/Mac/MRDPRailWindow.h @@ -0,0 +1,13 @@ +// +// MRDPRailWindow.h +// Mac +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +@interface MRDPRailWindow : NSWindow + +@end diff --git a/client/Mac/MRDPRailWindow.m b/client/Mac/MRDPRailWindow.m new file mode 100644 index 000000000..9cab180f4 --- /dev/null +++ b/client/Mac/MRDPRailWindow.m @@ -0,0 +1,18 @@ +// +// MRDPRailWindow.m +// Mac +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "MRDPRailWindow.h" + +@implementation MRDPRailWindow + +- (BOOL) canBecomeKeyWindow +{ + return YES; +} + +@end diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h index 43c523263..b0ecf432f 100644 --- a/client/Mac/MRDPView.h +++ b/client/Mac/MRDPView.h @@ -2,7 +2,7 @@ // MRDPView.h // MacFreeRDP // -// Created by Laxmikant Rashinkar on 3/28/12. +// Created by Laxmikant Rashinkar // Copyright (c) 2012 FreeRDP.org All rights reserved. // @@ -10,14 +10,18 @@ typedef int boolean; -#include "freerdp/freerdp.h" -#include "freerdp/types.h" -#include "freerdp/channels/channels.h" -#include "freerdp/gdi/gdi.h" -#include "freerdp/graphics.h" -#include "freerdp/utils/event.h" -#include "freerdp/plugins/cliprdr.h" -#include "freerdp/utils/args.h" +#import "MRDPWindow.h" +#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/plugins/cliprdr.h" +#import "freerdp/utils/args.h" +#import "freerdp/rail/rail.h" +#import "freerdp/rail.h" +#import "freerdp/utils/rail.h" @interface MRDPView : NSView { @@ -25,17 +29,30 @@ typedef int boolean; CFRunLoopSourceRef run_loop_src_channels; NSBitmapImageRep *bmiRep; NSMutableArray *cursors; + NSMutableArray *windows; NSTimer *pasteboard_timer; NSRect rect; + NSRect prevWinPosition; freerdp *rdp_instance; rdpContext *rdp_context; - boolean mouseInClientArea; char *pixel_data; int width; int height; int argc; + int titleBarHeight; char **argv; + // RAIL stuff + MRDPWindow *currentWindow; + NSPoint savedDragLocation; + boolean mouseInClientArea; + boolean isRemoteApp; + boolean firstCreateWindow; + boolean isMoveSizeInProgress; + boolean skipResizeOnce; + boolean saveInitialDragLoc; + boolean skipMoveWindowOnce; + // store state info for some keys int kdlshift; int kdrshift; @@ -57,11 +74,12 @@ typedef int boolean; } - (void) rdpConnectEror; +- (void) rdpRemoteAppError; - (void) saveStateInfo :(freerdp *) instance :(rdpContext *) context; -- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr; - (void) onPasteboardTimerFired :(NSTimer *) timer; - (void) my_draw_rect :(void *) context; - (void) releaseResources; +- (void) setViewSize : (int) width : (int) height; @property (assign) int is_connected; @@ -98,7 +116,7 @@ int register_fds(int *fds, int count, void *inst); 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 *inst, int chan_id, uint8 *data, int size, int flags, int total_size); -void process_cliprdr_event(freerdp *inst); +void process_cliprdr_event(freerdp *inst, RDP_EVENT *event); void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVENT* event); void cliprdr_send_data_request(freerdp *inst, uint32 format); void cliprdr_process_cb_monitor_ready_event(freerdp* inst); @@ -107,11 +125,26 @@ void cliprdr_process_text(freerdp *inst, uint8 *data, int len); void cliprdr_send_supported_format_list(freerdp *inst); int register_channel_fds(int *fds, int count, void *inst); -/* LK_TODO -int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, - ProcessPluginArgs plugin_callback, void* plugin_user_data, -ProcessUIArgs ui_callback, void* ui_user_data); -*/ +void mac_process_rail_event(freerdp *inst, RDP_EVENT *event); +void mac_rail_register_callbacks(freerdp *inst, rdpRail *rail); +void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window); +void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window); +void mac_rail_ShowWindow(rdpRail *rail, rdpWindow *window, uint8 state); +void mac_rail_SetWindowText(rdpRail *rail, rdpWindow *window); +void mac_rail_SetWindowIcon(rdpRail *rail, rdpWindow *window, rdpIcon *icon); +void mac_rail_SetWindowRects(rdpRail *rail, rdpWindow *window); +void mac_rail_SetWindowVisibilityRects(rdpRail *rail, rdpWindow *window); +void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window); +void mac_process_rail_get_sysparams_event(rdpChannels *channels, RDP_EVENT *event); +void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param); +void mac_on_free_rail_client_event(RDP_EVENT* event); +void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* event); +void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event); +void mac_rail_enable_remoteapp_mode(); +void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event); +void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event); +void apple_center_window(NSRect * r); +void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove); struct mac_context { diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index df2a9754f..9e2f43fc7 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -2,22 +2,45 @@ // MRDPView.m // MacFreeRDP // -// Created by Laxmikant Rashinkar on 3/28/12. +// Created by Laxmikant Rashinkar // Copyright (c) 2012 FreeRDP.org All rights reserved. // /* * TODO - * + 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 + * + 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 + * - RAIL: + * - + * - + * - 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 + * - + * - + * - */ #import "MRDPView.h" #import "MRDPCursor.h" -#define __RUN_IN_XCODE +#define RUN_IN_XCODE + +// LK_TODO +#define GOT_HERE //printf("### got here: %s : %s() : %d\n", __FILE__, __func__, __LINE__) + +// RAIL_TODO DELETE WHEN DONE TESTING +#define MRDP_DRAW_INDIVIDUAL_RECTS @implementation MRDPView @@ -25,6 +48,181 @@ MRDPView *g_mrdpview; @synthesize is_connected; +struct kkey g_keys[]; +void convert_color_space(char *dest, char *src, NSRect* drawRect, int width, int height); + +const char* error_code_names[] = +{ + "RAIL_EXEC_S_OK", + "RAIL_EXEC_E_HOOK_NOT_LOADED", + "RAIL_EXEC_E_DECODE_FAILED", + "RAIL_EXEC_E_NOT_IN_ALLOWLIST", + "RAIL_EXEC_E_FILE_NOT_FOUND", + "RAIL_EXEC_E_FAIL", + "RAIL_EXEC_E_SESSION_LOCKED" +}; + + +struct kkey g_keys[256] = +{ + { 0x1e, 0 }, // a 0 + { 0x1f, 0 }, // s + { 0x20, 0 }, // d + { 0x21, 0 }, // f + { 0x23, 0 }, // h + { 0x22, 0 }, // g + { 0x2c, 0 }, // z + { 0x2d, 0 }, // x + { 0x2e, 0 }, // c + { 0x2f, 0 }, // v + { 0x00, 0 }, // 10 + { 0x30, 0 }, // b + { 0x10, 0 }, // q + { 0x11, 0 }, // w + { 0x12, 0 }, // e + { 0x13, 0 }, // r + { 0x15, 0 }, // y + { 0x14, 0 }, // t + { 0x02, 0 }, // 1 + { 0x03, 0 }, // 2 + { 0x04, 0 }, // 3 20 + { 0x05, 0 }, // 4 + { 0x07, 0 }, // 6 + { 0x06, 0 }, // 5 + { 0x0d, 0 }, // = or + + { 0x0a, 0 }, // 9 + { 0x08, 0 }, // 7 + { 0x0c, 0 }, // - or _ + { 0x09, 0 }, // 8 + { 0x0b, 0 }, // 0 + { 0x1b, 0 }, // ] or } 30 + { 0x18, 0 }, // o + { 0x16, 0 }, // u + { 0x1a, 0 }, // [ or { + { 0x17, 0 }, // i + { 0x19, 0 }, // p + { 0x1c, 0 }, // enter + { 0x26, 0 }, // l + { 0x24, 0 }, // j + { 0x28, 0 }, // ' or " + { 0x25, 0 }, // k 40 + { 0x27, 0 }, // ; or : + { 0x2b, 0 }, // \ or | + { 0x33, 0 }, // , or < + { 0x35, 0 }, // / or ? + { 0x31, 0 }, // n + { 0x32, 0 }, // m + { 0x34, 0 }, // . or > + { 0x0f, 0 }, // tab + { 0x39, 0 }, // space + { 0x29, 0 }, // ` or ~ 50 + { 0x0e, 0 }, // backspace + { 0x00, 0 }, // + { 0x01, 0 }, // esc + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 60 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x53, 0 }, // KP. + { 0x00, 0 }, + { 0x37, 0 }, // KP* + { 0x00, 0 }, + { 0x4e, 0 }, // KP+ + { 0x00, 0 }, // 70 + { 0x45, 0 }, // num lock + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x35, 1 }, // KP/ + { 0x1c, 1 }, // KPEnter + { 0x00, 0 }, + { 0x4a, 0 }, // KP- + { 0x00, 0 }, + { 0x00, 0 }, // 80 + { 0x00, 0 }, + { 0x52, 0 }, // KP0 + { 0x4f, 0 }, // KP1 + { 0x50, 0 }, // KP2 + { 0x51, 0 }, // KP3 + { 0x4b, 0 }, // KP4 + { 0x4c, 0 }, // KP5 + { 0x4d, 0 }, // KP6 + { 0x47, 0 }, // KP7 + { 0x00, 0 }, // 90 + { 0x48, 0 }, // KP8 + { 0x49, 0 }, // KP9 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 100 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x5d, 1 }, // menu 110 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x52, 1 }, // Insert + { 0x47, 1 }, // Home + { 0x49, 1 }, // PgUp + { 0x53, 1 }, // Delete + { 0x00, 0 }, + { 0x4f, 1 }, // End + { 0x00, 0 }, // 120 + { 0x51, 1 }, // PgDown + { 0x3b, 0 }, // f1 + { 0x4b, 1 }, // left + { 0x4d, 1 }, // right + { 0x50, 1 }, // down + { 0x48, 1 }, // up + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, +}; + /************************************************************************ methods we override ************************************************************************/ @@ -52,13 +250,37 @@ MRDPView *g_mrdpview; g_mrdpview = self; // store our window dimensions - width = [self bounds].size.width; - height = [self bounds].size.height; + width = [self frame].size.width; + height = [self frame].size.height; + titleBarHeight = 22; [[self window] becomeFirstResponder]; [[self window] setAcceptsMouseMovedEvents:YES]; cursors = [[NSMutableArray alloc] initWithCapacity:10]; + + firstCreateWindow = TRUE; + skipResizeOnce = YES; + windows = [[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]; + + // windows in RemoteApp (RAIL) mode cannot have title bars + NSArray * args = [[NSProcessInfo processInfo] arguments]; + for (NSString * str in args) + { + if ([str compare:@"--app"] == NSOrderedSame) { + isRemoteApp = TRUE; + break; + } + } + + if (!isRemoteApp) + [self addTrackingArea:trackingArea]; + mouseInClientArea = YES; } @@ -86,19 +308,19 @@ MRDPView *g_mrdpview; - (void) mouseMoved:(NSEvent *)event { - int x; - int y; - [super mouseMoved:event]; - if (!is_connected) { + 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 - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); - } + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); } /** ********************************************************************* @@ -107,18 +329,18 @@ MRDPView *g_mrdpview; - (void)mouseDown:(NSEvent *) event { - int x; - int y; - [super mouseDown:event]; - if (!is_connected) { + if (!is_connected) return; - } - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); - } + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); } /** ********************************************************************* @@ -127,18 +349,18 @@ MRDPView *g_mrdpview; - (void) mouseUp:(NSEvent *) event { - int x; - int y; - [super mouseUp:event]; - if (!is_connected) { + if (!is_connected) return; - } - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); - } + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); } /** ********************************************************************* @@ -147,18 +369,18 @@ MRDPView *g_mrdpview; - (void) rightMouseDown:(NSEvent *)event { - int x; - int y; - [super rightMouseDown:event]; - if (!is_connected) { + if (!is_connected) return; - } - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y); - } + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y); } /** ********************************************************************* @@ -167,18 +389,18 @@ MRDPView *g_mrdpview; - (void) rightMouseUp:(NSEvent *)event { - int x; - int y; - [super rightMouseUp:event]; - if (!is_connected) { + if (!is_connected) return; - } - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON2, x, y); - } + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON2, x, y); } /** ********************************************************************* @@ -187,18 +409,18 @@ MRDPView *g_mrdpview; - (void) otherMouseDown:(NSEvent *)event { - int x; - int y; - [super otherMouseDown:event]; - if (!is_connected) { + if (!is_connected) return; - } - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y); - } + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y); } /** ********************************************************************* @@ -207,44 +429,45 @@ MRDPView *g_mrdpview; - (void) otherMouseUp:(NSEvent *)event { - int x; - int y; - [super otherMouseUp:event]; - if (!is_connected) { + if (!is_connected) return; - } - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON3, x, y); - } + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON3, x, y); } - (void) scrollWheel:(NSEvent *)event { uint16 flags; - int x; - int y; [super scrollWheel:event]; - if (!is_connected) { + if (!is_connected) return; - } + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; - if ([self eventIsInClientArea :event :&x :&y]) { - flags = PTR_FLAGS_WHEEL; - if ([event deltaY] < 0) { - flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; - } - else { - flags |= 0x0078; - } - x += (int) [event deltaX]; - y += (int) [event deltaY]; - rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); + y = height - y; + + flags = PTR_FLAGS_WHEEL; + if ([event deltaY] < 0) { + flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; } + else { + flags |= 0x0078; + } + x += (int) [event deltaX]; + y += (int) [event deltaY]; + rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); } /** ********************************************************************* @@ -254,19 +477,37 @@ MRDPView *g_mrdpview; - (void) mouseDragged:(NSEvent *)event { - int x; - int y; - [super mouseDragged:event]; - if (!is_connected) { + if (!is_connected) return; - } - // send mouse motion event to RDP server - if ([self eventIsInClientArea :event :&x :&y]) { - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + // RAIL_TODO delete this if not reqd + if ((isRemoteApp) && (isMoveSizeInProgress)) { + if (saveInitialDragLoc) { + saveInitialDragLoc = NO; + savedDragLocation.x = x; + savedDragLocation.y = y; + return; + } + + int newX = x - savedDragLocation.x; + int newY = y - savedDragLocation.y; + + NSRect r = [[self window] frame]; + r.origin.x += newX; + r.origin.y += newY; + [[g_mrdpview window] setFrame:r display:YES]; } + + y = height - y; + + // send mouse motion event to RDP server + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); } /** ********************************************************************* @@ -421,12 +662,20 @@ MRDPView *g_mrdpview; - (void) releaseResources { - for (int i = 0; i < argc; i++) + int i; + + for (i = 0; i < argc; i++) { if (argv[i]) free(argv[i]); } + for (MRDPWindow * w in windows) + { + [w setWindow:nil]; + [w setView:nil]; + } + if (!is_connected) return; @@ -446,17 +695,31 @@ MRDPView *g_mrdpview; * called when our view needs refreshing ***********************************************************************/ -- (void)drawRect:(NSRect)dirtyRect +- (void) drawRect:(NSRect)dirtyRect { -#if 1 - [bmiRep drawInRect:rect]; -#else - // do not delete - may need this soon - NSImage *image = [[NSImage alloc] initWithSize:[bmiRep size]]; - [image addRepresentation:bmiRep]; - [image setFlipped:0]; - [image drawInRect:dirtyRect fromRect:rect operation:NSCompositeSourceOver fraction:1.0]; -#endif + if (!rdp_context) + return; + + if (g_mrdpview->isRemoteApp && g_mrdpview->currentWindow) { + return; + } + + if (!bmiRep) { + pixel_data = (char *) malloc(width * height * sizeof(struct rgba_data)); + bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixel_data + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:sizeof(struct rgba_data) + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 //NSAlphaFirstBitmapFormat + bytesPerRow:width * sizeof(struct rgba_data) + bitsPerPixel:0]; + } + + [bmiRep drawInRect:dirtyRect fromRect:dirtyRect operation:NSCompositeCopy fraction:1.0 respectFlipped:NO hints:nil]; } /************************************************************************ @@ -469,38 +732,55 @@ MRDPView *g_mrdpview; - (void) my_draw_rect:(void *)context { - rdpContext *ctx = (rdpContext *) context; + int w; + int h; - struct rgba_data { + rdpContext * ctx = (rdpContext *) context; + + struct rgba_data + { char red; char green; char blue; char alpha; }; - rect.size.width = ctx->gdi->width; - rect.size.height = ctx->gdi->height; + if (isRemoteApp && currentWindow) { + NSRect vrect = [ [currentWindow view] frame]; + [[currentWindow view] setNeedsDisplayInRect:vrect]; + // actual drawing will be done in MRDPRailView:drawRect() + return; + } + + w = width; + h = height; rect.origin.x = 0; rect.origin.y = 0; + rect.size.width = w; + rect.size.height = h; if (!bmiRep) { - pixel_data = (char *) malloc(rect.size.width * rect.size.height * sizeof(struct rgba_data)); + pixel_data = (char *) malloc(w * h * sizeof(struct rgba_data)); bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixel_data - pixelsWide:rect.size.width - pixelsHigh:rect.size.height + pixelsWide:w + pixelsHigh:h bitsPerSample:8 samplesPerPixel:sizeof(struct rgba_data) hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:0 //NSAlphaFirstBitmapFormat - bytesPerRow:rect.size.width * sizeof(struct rgba_data) + bytesPerRow:w * sizeof(struct rgba_data) bitsPerPixel:0]; } - cvt_argb_to_rgba(pixel_data, (char *) ctx->gdi->primary_buffer, rect.size.width * rect.size.height * sizeof(struct rgba_data)); - - [self setNeedsDisplayInRect:rect]; // TODO: do only for reqd rect +#ifdef MRDP_DRAW_INDIVIDUAL_RECTS + [self setNeedsDisplayInRect:rect]; + return; +#endif + + convert_color_space(pixel_data, (char *) ctx->gdi->primary_buffer, &rect, w, h); + [self setNeedsDisplayInRect:rect]; } /** ********************************************************************* @@ -555,7 +835,7 @@ MRDPView *g_mrdpview; * called when we fail to connect to a RDP server ***********************************************************************/ -- (void) rdpConnectEror +- (void) rdpConnectError { NSAlert *alert = [[NSAlert alloc] init]; @@ -566,6 +846,20 @@ MRDPView *g_mrdpview; contextInfo:nil]; } +/** ********************************************************************* + * called when we fail to launch remote app on RDP server + ***********************************************************************/ + +- (void) rdpRemoteAppError +{ + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Error starting remote app on specified server"]; + [alert beginSheetModalForWindow:[g_mrdpview window] + modalDelegate:g_mrdpview + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + /** ********************************************************************* * just a terminate selector for above call ***********************************************************************/ @@ -580,7 +874,7 @@ MRDPView *g_mrdpview; NSArray *types; int i; - i = [pasteboard_rd changeCount]; + i = (int) [pasteboard_rd changeCount]; if (i != pasteboard_changecount) { pasteboard_changecount = i; @@ -593,6 +887,86 @@ MRDPView *g_mrdpview; } } +- (void) setViewSize : (int) w : (int) h +{ + // store current dimensions + width = w; + height = h; + + // compute difference between window and client area + NSRect outerRect = [[g_mrdpview window] frame]; + NSRect innerRect = [g_mrdpview frame]; + + int widthDiff = outerRect.size.width - innerRect.size.width; + int heightDiff = outerRect.size.height - innerRect.size.height; + + if (!g_mrdpview->isRemoteApp) { + // we are not in RemoteApp mode, disable resizing + outerRect.size.width = w + widthDiff; + outerRect.size.height = h + heightDiff; + [[g_mrdpview window] setMaxSize:outerRect.size]; + [[g_mrdpview window] setMinSize:outerRect.size]; + [[g_mrdpview window] setFrame:outerRect display:YES]; + + // set client area to specified dimensions + innerRect.size.width = w; + innerRect.size.height = h; + [g_mrdpview setFrame:innerRect]; + + return; + } + + // we are in RemoteApp mode + + outerRect.origin.x = 0; + outerRect.origin.y = 0; + outerRect.size.width = width + widthDiff; + outerRect.size.height = height + heightDiff; + [[g_mrdpview window] setFrame:outerRect display:YES]; + + // set client area to specified dimensions + innerRect.size.width = width; + innerRect.size.height = height; + [g_mrdpview setFrame:innerRect]; + + // main window displays desktop background - hide it + [[g_mrdpview window] orderOut:g_mrdpview]; +} + +// RAIL_TODO is this func required +- (void) windowDidResize:(NSNotification *) notification +{ + RAIL_WINDOW_MOVE_ORDER windowMove; + + printf("RAIL_TODO: MRDPView: windowDidResize() - not yet implemented\n"); + + return; + + // window resize valid only in RemoteApp mode + if (!g_mrdpview->isRemoteApp) + return; + + // window has resized, let server know + + NSRect r = [[g_mrdpview window] frame]; + printf("----- LK_TODO: MRDPView:windowDidResize (%d,%d %dx%d)\n", + (int) r.origin.x, (int) r.origin.y, + (int) r.size.width, (int) r.size.height); + + + windowMove.windowId = [currentWindow windowID]; + + windowMove.left = (uint16) r.origin.x; // x-cordinate of top left corner + windowMove.right = (uint16) (windowMove.left + r.size.width); // x-cordinate of bottom right corner + windowMove.top = (uint16) r.origin.y; // y-cordinate of top left corner + windowMove.bottom = (uint16) (windowMove.top + r.size.height); // y-cordinate of bottom right corner + + printf("----- LK_TODO: MRDPView:windowDidResize windowID=%d left=%d top=%d right=%d bottom=x%d width=%f height=%f\n", + [currentWindow windowID], windowMove.left, windowMove.top, windowMove.right, windowMove.bottom, r.size.width, r.size.height); + + //mac_send_rail_client_event(g_mrdpview->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); +} + /************************************************************************ * * * C functions * @@ -628,7 +1002,7 @@ int rdp_connect() return 0; } [g_mrdpview setIs_connected:0]; - [g_mrdpview rdpConnectEror]; + [g_mrdpview rdpConnectError]; return -1; } @@ -690,11 +1064,9 @@ boolean mac_pre_connect(freerdp *inst) NSArray *args = [[NSProcessInfo processInfo] arguments]; #ifdef RUN_IN_XCODE - // if you add any additional hard coded - // cmd line args, update this first - g_mrdpview->argc = 10; + g_mrdpview->argc = 30; #else - g_mrdpview->argc = [args count]; + g_mrdpview->argc = (int) [args count]; #endif g_mrdpview->argv = malloc(sizeof(char *) * g_mrdpview->argc); @@ -703,69 +1075,144 @@ boolean mac_pre_connect(freerdp *inst) } #ifdef RUN_IN_XCODE + // create our own cmd line args i = 0; - // argv[0] NSString *sptr = [args objectAtIndex:0]; len = [sptr length] + 1; cptr = (char *) malloc(len); strcpy(cptr, [sptr UTF8String]); g_mrdpview->argv[i++] = cptr; - // argv[1] cptr = (char *)malloc(80); strcpy(cptr, "-g"); g_mrdpview->argv[i++] = cptr; - // argv[2] cptr = (char *)malloc(80); - strcpy(cptr, "800x600"); + strcpy(cptr, "1280x800"); g_mrdpview->argv[i++] = cptr; - // argv[3] cptr = (char *)malloc(80); - strcpy(cptr, "--ignore-certificate"); + strcpy(cptr, "--sec"); g_mrdpview->argv[i++] = cptr; - // argv[4] cptr = (char *)malloc(80); - strcpy(cptr, "--no-nla"); + strcpy(cptr, "rdp"); g_mrdpview->argv[i++] = cptr; - // argv[5] cptr = (char *)malloc(80); strcpy(cptr, "--plugin"); g_mrdpview->argv[i++] = cptr; - // argv[6] cptr = (char *)malloc(80); strcpy(cptr, "cliprdr"); g_mrdpview->argv[i++] = cptr; - // argv[7] cptr = (char *)malloc(80); strcpy(cptr, "--plugin"); g_mrdpview->argv[i++] = cptr; - // argv[8] cptr = (char *)malloc(80); strcpy(cptr, "rdpsnd"); g_mrdpview->argv[i++] = cptr; - - // argv[9] + cptr = (char *)malloc(80); - strcpy(cptr, "23.20.8.223"); + strcpy(cptr, "-u"); g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "lk"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "-p"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "abc@@@123"); + g_mrdpview->argv[i++] = cptr; + +#if 1 + // for RemoteApp (RAIL) testing + cptr = (char *)malloc(80); + strcpy(cptr, "--app"); + g_mrdpview->argv[i++] = cptr; + g_mrdpview->isRemoteApp = TRUE; + + cptr = (char *)malloc(80); + strcpy(cptr, "--plugin"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "rail"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "--data"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "||WordPad"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "--"); + g_mrdpview->argv[i++] = cptr; +#endif + + cptr = (char *)malloc(80); + strcpy(cptr, "192.168.1.69:45990"); + g_mrdpview->argv[i++] = cptr; + + g_mrdpview->argc = i; + #else // MacFreeRDP was not run in Xcode i = 0; - for (NSString *str in args) - { - len = [str length] + 1; - cptr = (char *) malloc(len); - strcpy(cptr, [str UTF8String]); - g_mrdpview->argv[i++] = cptr; + + // in RemoteApp (RAIL) mode, we connect to RDP server at max screen resolution; + // in order to achieve this, we need to modify the cmd line args entered by the user; + + if (g_mrdpview->isRemoteApp) { + boolean gotGeometry = NO; + + // get dimensions of screen that has keyboard focus; + // we use these dimensions when connecting to RDP server + inst->settings->width = [[NSScreen mainScreen] frame].size.width; + inst->settings->height = [[NSScreen mainScreen] frame].size.height - g_mrdpview->titleBarHeight; + g_mrdpview->width = inst->settings->width; + g_mrdpview->height = inst->settings->height; + + for (NSString * str in args) + { + if (gotGeometry) { + gotGeometry = NO; + cptr = (char *) malloc(20); + sprintf(cptr, "%dx%d", g_mrdpview->width, g_mrdpview->height); + g_mrdpview->argv[i++] = cptr; + continue; + } + + len = (int) ([str length] + 1); + cptr = (char *) malloc(len); + strcpy(cptr, [str UTF8String]); + g_mrdpview->argv[i++] = cptr; + + // -g is the cmd line arg to specify screen resolution/geometry + if ([str compare:@"-g"] == NSOrderedSame) { + gotGeometry = YES; + } + } + } + else { + for (NSString * str in args) + { + len = (int) ([str length] + 1); + cptr = (char *) malloc(len); + strcpy(cptr, [str UTF8String]); + g_mrdpview->argv[i++] = cptr; + } } #endif @@ -775,20 +1222,8 @@ boolean mac_pre_connect(freerdp *inst) return true; } - // set window size based on cmd line arguments - g_mrdpview->width = inst->settings->width; - g_mrdpview->height = inst->settings->height; + [g_mrdpview setViewSize:inst->settings->width :inst->settings->height]; - NSRect rect; - rect.origin.x = 0; - rect.origin.y = 0; - rect.size.width = g_mrdpview->width; - rect.size.height = g_mrdpview->height; - - [[g_mrdpview window] setMaxSize:rect.size]; - [[g_mrdpview window] setMinSize:rect.size]; - [[g_mrdpview window] setFrame:rect display:YES]; - freerdp_channels_pre_connect(inst->context->channels, inst); return true; } @@ -854,13 +1289,22 @@ boolean mac_post_connect(freerdp *inst) register_channel_fds(fds, rd_count, inst); freerdp_channels_post_connect(inst->context->channels, inst); + // setup RAIL (remote app) + inst->context->rail = rail_new(inst->settings); + rail_register_update_callbacks(inst->context->rail, inst->update); + mac_rail_register_callbacks(inst, inst->context->rail); + // setup pasteboard (aka clipboard) for copy operations (write only) g_mrdpview->pasteboard_wr = [NSPasteboard generalPasteboard]; // setup pasteboard for read operations g_mrdpview->pasteboard_rd = [NSPasteboard generalPasteboard]; - g_mrdpview->pasteboard_changecount = [g_mrdpview->pasteboard_rd changeCount]; + g_mrdpview->pasteboard_changecount = (int) [g_mrdpview->pasteboard_rd changeCount]; g_mrdpview->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:g_mrdpview selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + + // we want to be notified when window resizes + [[NSNotificationCenter defaultCenter] addObserver:g_mrdpview selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:nil]; + return true; } @@ -1026,6 +1470,8 @@ void mac_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) void mac_begin_paint(rdpContext *context) { + rdpGdi* gdi = context->gdi; + gdi->primary->hdc->hwnd->invalid->null = 1; } /** ********************************************************************* @@ -1034,10 +1480,38 @@ void mac_begin_paint(rdpContext *context) void mac_end_paint(rdpContext* context) { - if ((context == 0) || (context->gdi == 0)) { + int i; + NSRect drawRect; + rdpGdi * gdi; + + if ((context == 0) || (context->gdi == 0)) return; - } - [g_mrdpview my_draw_rect:(void *) context]; + + if (context->gdi->primary->hdc->hwnd->invalid->null) + return; + + if (context->gdi->drawing != context->gdi->primary) + return; + + gdi = g_mrdpview->rdp_context->gdi; + + if (g_mrdpview->isRemoteApp && g_mrdpview->currentWindow) { + [[g_mrdpview->currentWindow view] updateDisplay]; + return; + } + + for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++) + { + drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x; + drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y; + drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w; + drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h; + + convert_color_space(g_mrdpview->pixel_data, (char *) gdi->primary_buffer, &drawRect, g_mrdpview->width, g_mrdpview->height); + + [g_mrdpview setNeedsDisplayInRect:drawRect]; + } + gdi->primary->hdc->hwnd->ninvalid = 0; } /** ********************************************************************* @@ -1071,9 +1545,24 @@ void channel_activity_cb( ) { freerdp *inst = (freerdp *) info; + RDP_EVENT* event; + + GOT_HERE; freerdp_channels_check_fds(inst->context->channels, inst); - process_cliprdr_event(inst); + event = freerdp_channels_pop_event(inst->context->channels); + if (event) { + switch (event->event_class) + { + case RDP_EVENT_CLASS_RAIL: + mac_process_rail_event(inst, event); + break; + + case RDP_EVENT_CLASS_CLIPRDR: + process_cliprdr_event(inst, event); + break; + } + } } /** ********************************************************************* @@ -1129,17 +1618,46 @@ int receive_channel_data(freerdp *inst, int chan_id, uint8 *data, int size, int * convert an array containing ARGB data to RGBA ***********************************************************************/ -void cvt_argb_to_rgba(char *dest, char *src, int len) +void convert_color_space(char *dest, char *src, NSRect* drawRect, int width, int height) { int i; - - for (i = 0; i < len; i += 4) - { - dest[i ] = src[i + 2]; - dest[i + 1] = src[i + 1]; - dest[i + 2] = src[i + 0]; - dest[i + 3] = src[i + 3]; + int j; + int x; + int y; + int cx; + int cy; + int pixel; + int pixel1; + int pixel2; + int* src32; + int* dst32; + + if ((!dest) || (!src)) { + return; } + + x = drawRect->origin.x; + y = drawRect->origin.y; + cx = drawRect->size.width; + cy = drawRect->size.height; + + for (j = 0; j < cy; j++) + { + src32 = (int*)(src + ((y + j) * width + x) * 4); + dst32 = (int*)(dest + ((y + j) * width + x) * 4); + for (i = 0; i < cx; i++) + { + pixel = *src32; + pixel1 = (pixel & 0x00ff0000) >> 16; + pixel2 = (pixel & 0x000000ff) << 16; + pixel = (pixel & 0xff00ff00) | pixel1 | pixel2; + *dst32 = pixel; + src32++; + dst32++; + } + } + + drawRect->origin.y = height - drawRect->origin.y - drawRect->size.height; } /** @@ -1190,7 +1708,7 @@ void cliprdr_process_cb_data_request_event(freerdp *inst) else { NSString *data = [g_mrdpview->pasteboard_rd stringForType:NSStringPboardType]; - len = [data length] * 2 + 2; + len = (int) ([data length] * 2 + 2); event->data = malloc(len); [data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding]; event->size = len; @@ -1296,12 +1814,8 @@ void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVEN } } -void process_cliprdr_event(freerdp *inst) +void process_cliprdr_event(freerdp *inst, RDP_EVENT *event) { - RDP_EVENT* event; - - event = freerdp_channels_pop_event(inst->context->channels); - if (event) { switch (event->event_type) { @@ -1356,164 +1870,445 @@ void cliprdr_send_supported_format_list(freerdp *inst) freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); } -struct kkey g_keys[256] = +/**************************************************************************************** + * * + * * + * RemoteApp (RAIL) related stuff goes here * + * * + * * + ****************************************************************************************/ + +void mac_process_rail_event(freerdp *inst, RDP_EVENT *event) { - { 0x1e, 0 }, // a 0 - { 0x1f, 0 }, // s - { 0x20, 0 }, // d - { 0x21, 0 }, // f - { 0x23, 0 }, // h - { 0x22, 0 }, // g - { 0x2c, 0 }, // z - { 0x2d, 0 }, // x - { 0x2e, 0 }, // c - { 0x2f, 0 }, // v - { 0x00, 0 }, // 10 - { 0x30, 0 }, // b - { 0x10, 0 }, // q - { 0x11, 0 }, // w - { 0x12, 0 }, // e - { 0x13, 0 }, // r - { 0x15, 0 }, // y - { 0x14, 0 }, // t - { 0x02, 0 }, // 1 - { 0x03, 0 }, // 2 - { 0x04, 0 }, // 3 20 - { 0x05, 0 }, // 4 - { 0x07, 0 }, // 6 - { 0x06, 0 }, // 5 - { 0x0d, 0 }, // = or + - { 0x0a, 0 }, // 9 - { 0x08, 0 }, // 7 - { 0x0c, 0 }, // - or _ - { 0x09, 0 }, // 8 - { 0x0b, 0 }, // 0 - { 0x1b, 0 }, // ] or } 30 - { 0x18, 0 }, // o - { 0x16, 0 }, // u - { 0x1a, 0 }, // [ or { - { 0x17, 0 }, // i - { 0x19, 0 }, // p - { 0x1c, 0 }, // enter - { 0x26, 0 }, // l - { 0x24, 0 }, // j - { 0x28, 0 }, // ' or " - { 0x25, 0 }, // k 40 - { 0x27, 0 }, // ; or : - { 0x2b, 0 }, // \ or | - { 0x33, 0 }, // , or < - { 0x35, 0 }, // / or ? - { 0x31, 0 }, // n - { 0x32, 0 }, // m - { 0x34, 0 }, // . or > - { 0x0f, 0 }, // tab - { 0x39, 0 }, // space - { 0x29, 0 }, // ` or ~ 50 - { 0x0e, 0 }, // backspace - { 0x00, 0 }, // - { 0x01, 0 }, // esc - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, // 60 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x53, 0 }, // KP. - { 0x00, 0 }, - { 0x37, 0 }, // KP* - { 0x00, 0 }, - { 0x4e, 0 }, // KP+ - { 0x00, 0 }, // 70 - { 0x45, 0 }, // num lock - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x35, 1 }, // KP/ - { 0x1c, 1 }, // KPEnter - { 0x00, 0 }, - { 0x4a, 0 }, // KP- - { 0x00, 0 }, - { 0x00, 0 }, // 80 - { 0x00, 0 }, - { 0x52, 0 }, // KP0 - { 0x4f, 0 }, // KP1 - { 0x50, 0 }, // KP2 - { 0x51, 0 }, // KP3 - { 0x4b, 0 }, // KP4 - { 0x4c, 0 }, // KP5 - { 0x4d, 0 }, // KP6 - { 0x47, 0 }, // KP7 - { 0x00, 0 }, // 90 - { 0x48, 0 }, // KP8 - { 0x49, 0 }, // KP9 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, // 100 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x5d, 1 }, // menu 110 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x52, 1 }, // Insert - { 0x47, 1 }, // Home - { 0x49, 1 }, // PgUp - { 0x53, 1 }, // Delete - { 0x00, 0 }, - { 0x4f, 1 }, // End - { 0x00, 0 }, // 120 - { 0x51, 1 }, // PgDown - { 0x3b, 0 }, // f1 - { 0x4b, 1 }, // left - { 0x4d, 1 }, // right - { 0x50, 1 }, // down - { 0x48, 1 }, // up - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, -}; + switch (event->event_type) + { + case RDP_EVENT_TYPE_RAIL_CHANNEL_GET_SYSPARAMS: + mac_process_rail_get_sysparams_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_EXEC_RESULTS: + mac_process_rail_exec_result_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_SYSPARAM: + mac_process_rail_server_sysparam_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_MINMAXINFO: + mac_process_rail_server_minmaxinfo_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_LOCALMOVESIZE: + mac_process_rail_server_localmovesize_event(inst, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_APPID_RESP: + GOT_HERE; + //xf_process_rail_appid_resp_event(xfi, channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_LANGBARINFO: + GOT_HERE; + //xf_process_rail_langbarinfo_event(xfi, channels, event); + break; + } +} + +void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window) +{ + boolean centerWindow = NO; + boolean moveWindow = NO; + boolean displayAsModal = NO; + NSMutableArray * ma = g_mrdpview->windows; + + // make sure window fits resolution + if (window->windowWidth > g_mrdpview->width) + window->windowWidth = g_mrdpview->width; + + if (window->windowHeight > g_mrdpview->height) + window->windowHeight = g_mrdpview->height; + + // center main window, which is the first to be created + if ([ma count] == 0) { + centerWindow = YES; + moveWindow = YES; + } + + if ((window->extendedStyle & WS_EX_TOPMOST) || (window->extendedStyle & WS_EX_TOOLWINDOW)) { + [g_mrdpview->currentWindow view]->skipMoveWindowOnce = TRUE; + moveWindow = YES; + } + else if (window->style & WS_POPUP) { + centerWindow = YES; + moveWindow = YES; + } + else { + } + + // create NSWindow + NSRect winFrame = NSMakeRect(window->windowOffsetX, window->windowOffsetY, + window->windowWidth, window->windowHeight); + if (centerWindow) + apple_center_window(&winFrame); + + MRDPRailWindow * newWindow = [[MRDPRailWindow alloc] initWithContentRect:winFrame + styleMask:NSTitledWindowMask | NSResizableWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + + // this does not work if specified during window creation in above code + [newWindow setStyleMask:NSBorderlessWindowMask]; + + if (moveWindow) { + // let RDP server know that window has moved + RAIL_WINDOW_MOVE_ORDER windowMove; + apple_to_windowMove(&winFrame, &windowMove); + windowMove.windowId = window->windowId; + mac_send_rail_client_event(g_mrdpview->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); + } + + // create MRDPRailView and add to above window + NSRect viewFrame = NSMakeRect(window->clientOffsetX, window->clientOffsetY, + window->clientAreaWidth, window->clientAreaHeight); + + MRDPRailView * newView = [[MRDPRailView alloc] initWithFrame:viewFrame]; + [newView setRdpInstance:g_mrdpview->rdp_instance width:g_mrdpview->width andHeight:g_mrdpview->height windowID: window->windowId]; + [newWindow setContentView:newView]; + + // save new window + MRDPWindow * mrdpWindow = [[MRDPWindow alloc] init]; + [mrdpWindow setWindowID:window->windowId]; + [mrdpWindow setWindow:newWindow]; + [mrdpWindow setView:newView]; + + // add to list of windows + [ma addObject:mrdpWindow]; + + // make new window current + g_mrdpview->currentWindow = mrdpWindow; + + if (displayAsModal) { + // display as modal window + NSModalSession session = [NSApp beginModalSessionForWindow:newWindow]; + while (1) + { + if ([NSApp runModalSession:session] != NSRunContinuesResponse) + break; + } + [NSApp endModalSession:session]; + } + else { + [newWindow makeKeyAndOrderFront:NSApp]; + [[g_mrdpview window] resignFirstResponder]; + [g_mrdpview resignFirstResponder]; + [[g_mrdpview window] setNextResponder:newWindow]; + } + + return; +} + +void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window) +{ + if (g_mrdpview->currentWindow) { + rail_MoveWindow(rail, window); + return; + } +} + +void mac_rail_ShowWindow(rdpRail *rail, rdpWindow *window, uint8 state) +{ +} + +void mac_rail_SetWindowText(rdpRail *rail, rdpWindow *window) +{ +} + +void mac_rail_SetWindowIcon(rdpRail *rail, rdpWindow *window, rdpIcon *icon) +{ +} + +void mac_rail_SetWindowRects(rdpRail *rail, rdpWindow *window) +{ +} + +void mac_rail_SetWindowVisibilityRects(rdpRail *rail, rdpWindow *window) +{ +} + +/** ********************************************************************* + * destroy window created in mac_rail_CreateWindow() + ***********************************************************************/ + +void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window) +{ + int count = 0; + + for (MRDPWindow * win in g_mrdpview->windows) + { + if ([win windowID] == window->windowId) { + //[[win window] close]; + [win setView:nil]; + [win setWindow:nil]; + [g_mrdpview->windows removeObject:win]; + count = [g_mrdpview->windows count]; + if (count) { + g_mrdpview->currentWindow = [g_mrdpview->windows objectAtIndex:count - 1]; + //[[g_mrdpview window] makeKeyAndOrderFront:[g_mrdpview->currentWindow window]]; + [[g_mrdpview->currentWindow window] makeKeyAndOrderFront:NSApp]; + } + else { + g_mrdpview->currentWindow = nil; + // RAIL_TODO [[g_mrdpview window] makeKeyAndOrderFront:[g_mrdpview window]]; + [NSApp terminate:nil]; + } + return; + } + } +} + +void mac_rail_register_callbacks(freerdp *inst, rdpRail *rail) +{ + GOT_HERE; + + rail->extra = (void *) inst; + rail->rail_CreateWindow = mac_rail_CreateWindow; + rail->rail_MoveWindow = mac_rail_MoveWindow; + rail->rail_ShowWindow = mac_rail_ShowWindow; + rail->rail_SetWindowText = mac_rail_SetWindowText; + rail->rail_SetWindowIcon = mac_rail_SetWindowIcon; + rail->rail_SetWindowRects = mac_rail_SetWindowRects; + rail->rail_SetWindowVisibilityRects = mac_rail_SetWindowVisibilityRects; + rail->rail_DestroyWindow = mac_rail_DestroyWindow; +} + +/** ********************************************************************* + * set work area size, which is the portion of the screen not obscured + * by the system taskbar or by application desktop toolbars + ************************************************************************/ + +void mac_process_rail_get_sysparams_event(rdpChannels *channels, RDP_EVENT *event) +{ + RAIL_SYSPARAM_ORDER * sysparam; + sysparam = (RAIL_SYSPARAM_ORDER *) event->user_data; + + sysparam->workArea.left = 0; + sysparam->workArea.top = 22; + sysparam->workArea.right = g_mrdpview->width; + sysparam->workArea.bottom = g_mrdpview->height - 22; + + sysparam->taskbarPos.left = 0; + sysparam->taskbarPos.top = 0; + sysparam->taskbarPos.right = 0; + sysparam->taskbarPos.bottom = 0; + + sysparam->dragFullWindows = false; + + mac_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SET_SYSPARAMS, sysparam); +} + +void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* event) +{ + RAIL_SYSPARAM_ORDER* sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data; + + GOT_HERE; + + switch (sysparam->param) + { + case SPI_SET_SCREEN_SAVE_ACTIVE: + break; + + case SPI_SET_SCREEN_SAVE_SECURE: + break; + } +} + +/** ********************************************************************* + * server returned result of exec'ing remote app on server + ************************************************************************/ + +void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event) +{ + RAIL_EXEC_RESULT_ORDER* exec_result; + + GOT_HERE; + + exec_result = (RAIL_EXEC_RESULT_ORDER*) event->user_data; + + if (exec_result->execResult != RAIL_EXEC_S_OK) { + printf("RAIL exec error: execResult=%s NtError=0x%X\n", + error_code_names[exec_result->execResult], exec_result->rawResult); + g_mrdpview->is_connected = FALSE; + [g_mrdpview rdpRemoteAppError]; + } + else { + mac_rail_enable_remoteapp_mode(); + } +} + +/** ********************************************************************* + * sent by server when a window move or resize on the server is being + * initiated. this PDU contains info about the min and max extents + * to which the window can be moved or sized + ************************************************************************/ + +void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event) +{ + RAIL_MINMAXINFO_ORDER * minmax = (RAIL_MINMAXINFO_ORDER*) event->user_data; + +#if 0 + printf("minmax_info: maxPosX=%d maxPosY=%d maxWidth=%d maxHeight=%d minTrackWidth=%d minTrackHeight=%d maxTrackWidth=%d maxTrackHeight=%d\n", + minmax->maxPosX, minmax->maxPosY, minmax->maxWidth, minmax->maxHeight, + minmax->minTrackWidth, minmax->minTrackHeight, minmax->maxTrackWidth, minmax->maxTrackHeight); +#endif +} + +/** ********************************************************************* + * sent by the server when a window on the server is beginning a move or + * resize; use this info to initiate a local move or resize of the + * corresponding local window + ************************************************************************/ + +void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event) +{ + RAIL_LOCALMOVESIZE_ORDER * moveSize = (RAIL_LOCALMOVESIZE_ORDER *) event->user_data; + RAIL_WINDOW_MOVE_ORDER windowMove; + + switch (moveSize->moveSizeType) { + case RAIL_WMSZ_LEFT: + printf("!!!! RAIL_WMSZ_LEFT\n"); + break; + + case RAIL_WMSZ_RIGHT: + printf("!!!! RAIL_WMSZ_RIGHT\n"); + break; + + case RAIL_WMSZ_TOP: + printf("!!!! RAIL_WMSZ_TOP\n"); + break; + + case RAIL_WMSZ_TOPLEFT: + printf("!!!! RAIL_WMSZ_TOPLEFT\n"); + break; + + case RAIL_WMSZ_TOPRIGHT: + printf("!!!! RAIL_WMSZ_TOPRIGHT\n"); + break; + + case RAIL_WMSZ_BOTTOM: + printf("!!!! RAIL_WMSZ_BOTTOM\n"); + break; + + case RAIL_WMSZ_BOTTOMLEFT: + printf("!!!! RAIL_WMSZ_BOTTOMLEFT\n"); + break; + + case RAIL_WMSZ_BOTTOMRIGHT: + printf("!!!! RAIL_WMSZ_BOTTOMRIGHT\n"); + break; + + case RAIL_WMSZ_MOVE: + if (moveSize->isMoveSizeStart) { + // local window move in progress + [g_mrdpview->currentWindow view]->isMoveSizeInProgress = YES; + [g_mrdpview->currentWindow view]->saveInitialDragLoc = YES; + + return; + } + + // local move has completed + [g_mrdpview->currentWindow view]->isMoveSizeInProgress = NO; + [g_mrdpview->currentWindow view]->saveInitialDragLoc = NO; + + //NSRect rect = [[g_mrdpview->currentWindow view] frame]; + NSRect rect = [[[g_mrdpview->currentWindow view] window] frame]; + + // let RDP server know where this window is located + mac_send_rail_client_event(inst->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); + + // the event we just sent will cause an extra MoveWindow() to be invoked which we need to ignore + [g_mrdpview->currentWindow view]->skipMoveWindowOnce = YES; + + break; + + case RAIL_WMSZ_KEYMOVE: + printf("!!!! RAIL_WMSZ_KEYMOVE\n"); + break; + + case RAIL_WMSZ_KEYSIZE: + printf("!!!! RAIL_WMSZ_KEYSIZE\n"); + break; + + default: + break; + } + return; +} + +void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param) +{ + RDP_EVENT *out_event = NULL; + void *payload = NULL; + + GOT_HERE; + + payload = rail_clone_order(event_type, param); + if (payload != NULL) { + out_event = freerdp_event_new(RDP_EVENT_CLASS_RAIL, event_type, + mac_on_free_rail_client_event, payload); + freerdp_channels_send_event(channels, out_event); + } +} + +void mac_on_free_rail_client_event(RDP_EVENT* event) +{ + GOT_HERE; + + if (event->event_class == RDP_EVENT_CLASS_RAIL) + { + rail_free_cloned_order(event->event_type, event->user_data); + } +} + +void mac_rail_enable_remoteapp_mode() +{ + GOT_HERE; + + if (!g_mrdpview->isRemoteApp) + g_mrdpview->isRemoteApp = TRUE; +} + +/** + * given a rect with 0,0 at the bottom left (apple cords) + * convert it to a rect with 0,0 at the top left (windows cords) + */ + +void apple_to_windows_cords(NSRect * r) +{ + r->origin.y = g_mrdpview->height - (r->origin.y + r->size.height); +} + +/** + * 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) + */ + +void windows_to_apple_cords(NSRect * r) +{ + r->origin.y = g_mrdpview->height - (r->origin.y + r->size.height); +} + +void apple_center_window(NSRect * r) +{ + r->origin.x = (g_mrdpview->width - r->size.width) / 2; + r->origin.y = (g_mrdpview->height - r->size.height) / 2; +} + +void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove) +{ + windowMove->left = (uint16) r->origin.x; // x-cord of top left corner + windowMove->top = (uint16) g_mrdpview->height - (r->origin.y + r->size.height); // y-cord of top left corner + windowMove->right = (uint16) (windowMove->left + r->size.width); // x-cord of bottom right corner + windowMove->bottom = (uint16) (windowMove->top + r->size.height); // y-cord of bottom right corner +} @end diff --git a/client/Mac/MRDPWindow.h b/client/Mac/MRDPWindow.h new file mode 100644 index 000000000..cef1ab09e --- /dev/null +++ b/client/Mac/MRDPWindow.h @@ -0,0 +1,15 @@ + +#import +#import "MRDPRailView.h" +#import "MRDPRailWindow.h" + +@interface MRDPWindow : NSObject +{ +} + +@property (assign) int windowID; +@property (retain) MRDPRailWindow * window; +@property (retain) MRDPRailView * view; + +@end + diff --git a/client/Mac/MRDPWindow.m b/client/Mac/MRDPWindow.m new file mode 100644 index 000000000..c99217692 --- /dev/null +++ b/client/Mac/MRDPWindow.m @@ -0,0 +1,11 @@ + +#include "MRDPWindow.h" + +@implementation MRDPWindow + +@synthesize windowID; +@synthesize window; +@synthesize view; + +@end + diff --git a/client/Mac/Mac/MRDPCursor.h b/client/Mac/Mac/MRDPCursor.h new file mode 100644 index 000000000..9df734ba4 --- /dev/null +++ b/client/Mac/Mac/MRDPCursor.h @@ -0,0 +1,25 @@ +// +// MRDPCursor.h +// MacFreeRDP +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +#import + +#define boolean int + +#include "freerdp/graphics.h" + +@interface MRDPCursor : NSObject +{ +@public + rdpPointer *pointer; + uint8 *cursor_data; // bitmapped pixel data + NSBitmapImageRep *bmiRep; + NSCursor *nsCursor; + NSImage *nsImage; +} + +@end diff --git a/client/Mac/Mac/MRDPCursor.m b/client/Mac/Mac/MRDPCursor.m new file mode 100644 index 000000000..29a93c808 --- /dev/null +++ b/client/Mac/Mac/MRDPCursor.m @@ -0,0 +1,12 @@ +// +// MRDPCursor.m +// MacFreeRDP +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +#import "MRDPCursor.h" + +@implementation MRDPCursor +@end diff --git a/client/Mac/Mac/MRDPRailWindow.h b/client/Mac/Mac/MRDPRailWindow.h new file mode 100644 index 000000000..629dc819c --- /dev/null +++ b/client/Mac/Mac/MRDPRailWindow.h @@ -0,0 +1,13 @@ +// +// MRDPRailWindow.h +// Mac +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +@interface MRDPRailWindow : NSWindow + +@end diff --git a/client/Mac/Mac/MRDPRailWindow.m b/client/Mac/Mac/MRDPRailWindow.m new file mode 100644 index 000000000..9cab180f4 --- /dev/null +++ b/client/Mac/Mac/MRDPRailWindow.m @@ -0,0 +1,18 @@ +// +// MRDPRailWindow.m +// Mac +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "MRDPRailWindow.h" + +@implementation MRDPRailWindow + +- (BOOL) canBecomeKeyWindow +{ + return YES; +} + +@end diff --git a/client/Mac/Mac/MRDPView.h b/client/Mac/Mac/MRDPView.h new file mode 100644 index 000000000..b0ecf432f --- /dev/null +++ b/client/Mac/Mac/MRDPView.h @@ -0,0 +1,177 @@ +// +// MRDPView.h +// MacFreeRDP +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +#import + +typedef int boolean; + +#import "MRDPWindow.h" +#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/plugins/cliprdr.h" +#import "freerdp/utils/args.h" +#import "freerdp/rail/rail.h" +#import "freerdp/rail.h" +#import "freerdp/utils/rail.h" + +@interface MRDPView : NSView +{ + CFRunLoopSourceRef run_loop_src; + CFRunLoopSourceRef run_loop_src_channels; + NSBitmapImageRep *bmiRep; + NSMutableArray *cursors; + NSMutableArray *windows; + NSTimer *pasteboard_timer; + NSRect rect; + NSRect prevWinPosition; + freerdp *rdp_instance; + rdpContext *rdp_context; + char *pixel_data; + int width; + int height; + int argc; + int titleBarHeight; + char **argv; + + // RAIL stuff + MRDPWindow *currentWindow; + NSPoint savedDragLocation; + boolean mouseInClientArea; + boolean isRemoteApp; + boolean firstCreateWindow; + boolean isMoveSizeInProgress; + boolean skipResizeOnce; + boolean saveInitialDragLoc; + boolean skipMoveWindowOnce; + + // store state info for some keys + int kdlshift; + int kdrshift; + int kdlctrl; + int kdrctrl; + int kdlalt; + int kdralt; + int kdlmeta; + int kdrmeta; + int kdcapslock; + +@public + NSWindow *ourMainWindow; + NSPasteboard *pasteboard_rd; // for reading from clipboard + NSPasteboard *pasteboard_wr; // for writing to clipboard + int pasteboard_changecount; + int pasteboard_format; + int is_connected; // true when connected to RDP server +} + +- (void) rdpConnectEror; +- (void) rdpRemoteAppError; +- (void) saveStateInfo :(freerdp *) instance :(rdpContext *) context; +- (void) onPasteboardTimerFired :(NSTimer *) timer; +- (void) my_draw_rect :(void *) context; +- (void) releaseResources; +- (void) setViewSize : (int) width : (int) height; + +@property (assign) int is_connected; + +@end + +/* Pointer Flags */ +#define PTR_FLAGS_WHEEL 0x0200 +#define PTR_FLAGS_WHEEL_NEGATIVE 0x0100 +#define PTR_FLAGS_MOVE 0x0800 +#define PTR_FLAGS_DOWN 0x8000 +#define PTR_FLAGS_BUTTON1 0x1000 +#define PTR_FLAGS_BUTTON2 0x2000 +#define PTR_FLAGS_BUTTON3 0x4000 +#define WheelRotationMask 0x01FF + +void pointer_new(rdpContext* context, rdpPointer* pointer); +void pointer_free(rdpContext* context, rdpPointer* pointer); +void pointer_set(rdpContext* context, rdpPointer* pointer); +void pointer_setNull(rdpContext* context); +void pointer_setDefault(rdpContext* context); +int rdp_connect(); +boolean mac_pre_connect(freerdp *inst); +boolean mac_post_connect(freerdp *inst); +void mac_context_new(freerdp *inst, rdpContext *context); +void mac_context_free(freerdp *inst, rdpContext *context); +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 *inst, rdpContext *context); +void skt_activity_cb(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info); +void channel_activity_cb(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info); +int register_fds(int *fds, int count, void *inst); +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 *inst, int chan_id, uint8 *data, int size, int flags, int total_size); +void process_cliprdr_event(freerdp *inst, RDP_EVENT *event); +void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVENT* event); +void cliprdr_send_data_request(freerdp *inst, uint32 format); +void cliprdr_process_cb_monitor_ready_event(freerdp* inst); +void cliprdr_process_cb_data_response_event(freerdp *inst, RDP_CB_DATA_RESPONSE_EVENT *event); +void cliprdr_process_text(freerdp *inst, uint8 *data, int len); +void cliprdr_send_supported_format_list(freerdp *inst); +int register_channel_fds(int *fds, int count, void *inst); + +void mac_process_rail_event(freerdp *inst, RDP_EVENT *event); +void mac_rail_register_callbacks(freerdp *inst, rdpRail *rail); +void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window); +void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window); +void mac_rail_ShowWindow(rdpRail *rail, rdpWindow *window, uint8 state); +void mac_rail_SetWindowText(rdpRail *rail, rdpWindow *window); +void mac_rail_SetWindowIcon(rdpRail *rail, rdpWindow *window, rdpIcon *icon); +void mac_rail_SetWindowRects(rdpRail *rail, rdpWindow *window); +void mac_rail_SetWindowVisibilityRects(rdpRail *rail, rdpWindow *window); +void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window); +void mac_process_rail_get_sysparams_event(rdpChannels *channels, RDP_EVENT *event); +void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param); +void mac_on_free_rail_client_event(RDP_EVENT* event); +void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* event); +void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event); +void mac_rail_enable_remoteapp_mode(); +void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event); +void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event); +void apple_center_window(NSRect * r); +void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove); + +struct mac_context +{ + // *must* have this - do not delete + rdpContext _p; +}; + +struct cursor +{ + rdpPointer *pointer; + uint8 *cursor_data; // bitmapped pixel data + void *bmiRep; // NSBitmapImageRep + void *nsCursor; // NSCursor + void *nsImage; // NSImage +}; + +struct rgba_data +{ + char red; + char green; + char blue; + char alpha; +}; + +struct kkey +{ + int key_code; + int flags; +}; + diff --git a/client/Mac/Mac/MRDPView.m b/client/Mac/Mac/MRDPView.m new file mode 100644 index 000000000..9e2f43fc7 --- /dev/null +++ b/client/Mac/Mac/MRDPView.m @@ -0,0 +1,2314 @@ +// +// MRDPView.m +// MacFreeRDP +// +// Created by Laxmikant Rashinkar +// Copyright (c) 2012 FreeRDP.org All rights reserved. +// + +/* + * TODO + * + 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 + * - RAIL: + * - + * - + * - 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 + * - + * - + * - + */ + +#import "MRDPView.h" +#import "MRDPCursor.h" + +#define RUN_IN_XCODE + +// LK_TODO +#define GOT_HERE //printf("### got here: %s : %s() : %d\n", __FILE__, __func__, __LINE__) + +// RAIL_TODO DELETE WHEN DONE TESTING +#define MRDP_DRAW_INDIVIDUAL_RECTS + +@implementation MRDPView + +MRDPView *g_mrdpview; + +@synthesize is_connected; + +struct kkey g_keys[]; +void convert_color_space(char *dest, char *src, NSRect* drawRect, int width, int height); + +const char* error_code_names[] = +{ + "RAIL_EXEC_S_OK", + "RAIL_EXEC_E_HOOK_NOT_LOADED", + "RAIL_EXEC_E_DECODE_FAILED", + "RAIL_EXEC_E_NOT_IN_ALLOWLIST", + "RAIL_EXEC_E_FILE_NOT_FOUND", + "RAIL_EXEC_E_FAIL", + "RAIL_EXEC_E_SESSION_LOCKED" +}; + + +struct kkey g_keys[256] = +{ + { 0x1e, 0 }, // a 0 + { 0x1f, 0 }, // s + { 0x20, 0 }, // d + { 0x21, 0 }, // f + { 0x23, 0 }, // h + { 0x22, 0 }, // g + { 0x2c, 0 }, // z + { 0x2d, 0 }, // x + { 0x2e, 0 }, // c + { 0x2f, 0 }, // v + { 0x00, 0 }, // 10 + { 0x30, 0 }, // b + { 0x10, 0 }, // q + { 0x11, 0 }, // w + { 0x12, 0 }, // e + { 0x13, 0 }, // r + { 0x15, 0 }, // y + { 0x14, 0 }, // t + { 0x02, 0 }, // 1 + { 0x03, 0 }, // 2 + { 0x04, 0 }, // 3 20 + { 0x05, 0 }, // 4 + { 0x07, 0 }, // 6 + { 0x06, 0 }, // 5 + { 0x0d, 0 }, // = or + + { 0x0a, 0 }, // 9 + { 0x08, 0 }, // 7 + { 0x0c, 0 }, // - or _ + { 0x09, 0 }, // 8 + { 0x0b, 0 }, // 0 + { 0x1b, 0 }, // ] or } 30 + { 0x18, 0 }, // o + { 0x16, 0 }, // u + { 0x1a, 0 }, // [ or { + { 0x17, 0 }, // i + { 0x19, 0 }, // p + { 0x1c, 0 }, // enter + { 0x26, 0 }, // l + { 0x24, 0 }, // j + { 0x28, 0 }, // ' or " + { 0x25, 0 }, // k 40 + { 0x27, 0 }, // ; or : + { 0x2b, 0 }, // \ or | + { 0x33, 0 }, // , or < + { 0x35, 0 }, // / or ? + { 0x31, 0 }, // n + { 0x32, 0 }, // m + { 0x34, 0 }, // . or > + { 0x0f, 0 }, // tab + { 0x39, 0 }, // space + { 0x29, 0 }, // ` or ~ 50 + { 0x0e, 0 }, // backspace + { 0x00, 0 }, // + { 0x01, 0 }, // esc + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 60 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x53, 0 }, // KP. + { 0x00, 0 }, + { 0x37, 0 }, // KP* + { 0x00, 0 }, + { 0x4e, 0 }, // KP+ + { 0x00, 0 }, // 70 + { 0x45, 0 }, // num lock + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x35, 1 }, // KP/ + { 0x1c, 1 }, // KPEnter + { 0x00, 0 }, + { 0x4a, 0 }, // KP- + { 0x00, 0 }, + { 0x00, 0 }, // 80 + { 0x00, 0 }, + { 0x52, 0 }, // KP0 + { 0x4f, 0 }, // KP1 + { 0x50, 0 }, // KP2 + { 0x51, 0 }, // KP3 + { 0x4b, 0 }, // KP4 + { 0x4c, 0 }, // KP5 + { 0x4d, 0 }, // KP6 + { 0x47, 0 }, // KP7 + { 0x00, 0 }, // 90 + { 0x48, 0 }, // KP8 + { 0x49, 0 }, // KP9 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, // 100 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x5d, 1 }, // menu 110 + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x52, 1 }, // Insert + { 0x47, 1 }, // Home + { 0x49, 1 }, // PgUp + { 0x53, 1 }, // Delete + { 0x00, 0 }, + { 0x4f, 1 }, // End + { 0x00, 0 }, // 120 + { 0x51, 1 }, // PgDown + { 0x3b, 0 }, // f1 + { 0x4b, 1 }, // left + { 0x4d, 1 }, // right + { 0x50, 1 }, // down + { 0x48, 1 }, // up + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, + { 0x00, 0 }, +}; + +/************************************************************************ + methods we override +************************************************************************/ + +/** ********************************************************************* + * create MRDPView with specified rectangle + ***********************************************************************/ + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code here. + } + + return self; +} + +/** ********************************************************************* + * called when MRDPView has been successfully created from the NIB + ***********************************************************************/ + +- (void) awakeFromNib +{ + g_mrdpview = self; + + // 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]; + + firstCreateWindow = TRUE; + skipResizeOnce = YES; + windows = [[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]; + + // windows in RemoteApp (RAIL) mode cannot have title bars + NSArray * args = [[NSProcessInfo processInfo] arguments]; + for (NSString * str in args) + { + if ([str compare:@"--app"] == NSOrderedSame) { + isRemoteApp = TRUE; + break; + } + } + + if (!isRemoteApp) + [self addTrackingArea:trackingArea]; + + mouseInClientArea = YES; +} + +/** ********************************************************************* + * become first responder so we can get keyboard and mouse events + ***********************************************************************/ + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +/** ********************************************************************* + * called when a mouse move event occurrs + * + * 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 + * versions, we do this manually. + * + * 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 + ***********************************************************************/ + + - (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 + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); +} + +/** ********************************************************************* + * called when left mouse button is pressed down + ***********************************************************************/ + +- (void)mouseDown:(NSEvent *) event +{ + [super mouseDown:event]; + + if (!is_connected) + return; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); +} + +/** ********************************************************************* + * called when left mouse button is released + ***********************************************************************/ + +- (void) mouseUp:(NSEvent *) event +{ + [super mouseUp:event]; + + if (!is_connected) + return; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); +} + +/** ********************************************************************* + * called when right mouse button is pressed down + ***********************************************************************/ + +- (void) rightMouseDown:(NSEvent *)event +{ + [super rightMouseDown:event]; + + if (!is_connected) + return; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y); +} + +/** ********************************************************************* + * called when right mouse button is released + ***********************************************************************/ + +- (void) rightMouseUp:(NSEvent *)event +{ + [super rightMouseUp:event]; + + if (!is_connected) + return; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON2, x, y); +} + +/** ********************************************************************* + * called when middle mouse button is pressed + ***********************************************************************/ + +- (void) otherMouseDown:(NSEvent *)event +{ + [super otherMouseDown:event]; + + if (!is_connected) + return; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y); +} + +/** ********************************************************************* + * called when middle mouse button is released + ***********************************************************************/ + +- (void) otherMouseUp:(NSEvent *)event +{ + [super otherMouseUp:event]; + + if (!is_connected) + return; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + y = height - y; + + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON3, x, y); +} + +- (void) scrollWheel:(NSEvent *)event +{ + uint16 flags; + + [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; + if ([event deltaY] < 0) { + flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; + } + else { + flags |= 0x0078; + } + x += (int) [event deltaX]; + y += (int) [event deltaY]; + rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); +} + +/** ********************************************************************* + * called when mouse is moved with left button pressed + * note: invocation order is: mouseDown, mouseDragged, mouseUp + ***********************************************************************/ + +- (void) mouseDragged:(NSEvent *)event +{ + [super mouseDragged:event]; + + if (!is_connected) + return; + + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + // RAIL_TODO delete this if not reqd + if ((isRemoteApp) && (isMoveSizeInProgress)) { + if (saveInitialDragLoc) { + saveInitialDragLoc = NO; + savedDragLocation.x = x; + savedDragLocation.y = y; + return; + } + + int newX = x - savedDragLocation.x; + int newY = y - savedDragLocation.y; + + NSRect r = [[self window] frame]; + r.origin.x += newX; + r.origin.y += newY; + [[g_mrdpview window] setFrame:r display:YES]; + } + + y = height - y; + + // send mouse motion event to RDP server + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); +} + +/** ********************************************************************* + * called when a key is pressed + ***********************************************************************/ + +- (void) keyDown:(NSEvent *) event +{ + int key; + + if (!is_connected) { + return; + } + + key = [event keyCode]; + rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_DOWN, g_keys[key].key_code); +} + +/** ********************************************************************* + * called when a key is released + ***********************************************************************/ + +- (void) keyUp:(NSEvent *) event +{ + int key; + + if (!is_connected) { + return; + } + + key = [event keyCode]; + rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_RELEASE, g_keys[key].key_code); +} + +/** ********************************************************************* + * called when shift, control, alt and meta keys are pressed/released + ***********************************************************************/ + +- (void) flagsChanged:(NSEvent *) event +{ + NSUInteger mf = [event modifierFlags]; + + if (!is_connected) { + 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 + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x2a); + kdlshift = 1; + } + if ((kdlshift != 0) && ((mf & 2) == 0)) { + // left shift went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x2a); + kdlshift = 0; + } + + // right shift + if ((kdrshift == 0) && ((mf & 4) != 0)) { + // right shift went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x36); + kdrshift = 1; + } + if ((kdrshift != 0) && ((mf & 4) == 0)) { + // right shift went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x36); + kdrshift = 0; + } + + // left ctrl + if ((kdlctrl == 0) && ((mf & 1) != 0)) { + // left ctrl went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x1d); + kdlctrl = 1; + } + if ((kdlctrl != 0) && ((mf & 1) == 0)) { + // left ctrl went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x1d); + kdlctrl = 0; + } + + // right ctrl + if ((kdrctrl == 0) && ((mf & 0x2000) != 0)) { + // right ctrl went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x1d); + kdrctrl = 1; + } + if ((kdrctrl != 0) && ((mf & 0x2000) == 0)) { + // right ctrl went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x1d); + kdrctrl = 0; + } + + // left alt + if ((kdlalt == 0) && ((mf & 0x20) != 0)) { + // left alt went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x38); + kdlalt = 1; + } + if ((kdlalt != 0) && ((mf & 0x20) == 0)) { + // left alt went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x38); + kdlalt = 0; + } + + // right alt + if ((kdralt == 0) && ((mf & 0x40) != 0)) { + // right alt went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x38); + kdralt = 1; + } + if ((kdralt != 0) && ((mf & 0x40) == 0)) { + // right alt went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x38); + kdralt = 0; + } + + // left meta + if ((kdlmeta == 0) && ((mf & 0x08) != 0)) { + // left meta went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5b); + kdlmeta = 1; + } + if ((kdlmeta != 0) && ((mf & 0x08) == 0)) { + // left meta went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5b); + kdlmeta = 0; + } + + // right meta + if ((kdrmeta == 0) && ((mf & 0x10) != 0)) { + // right meta went down + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5c); + kdrmeta = 1; + } + if ((kdrmeta != 0) && ((mf & 0x10) == 0)) { + // right meta went up + rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5c); + kdrmeta = 0; + } +} + +- (void) releaseResources +{ + int i; + + for (i = 0; i < argc; i++) + { + if (argv[i]) + free(argv[i]); + } + + for (MRDPWindow * w in windows) + { + [w setWindow:nil]; + [w setView:nil]; + } + + if (!is_connected) + return; + + freerdp_channels_global_uninit(); + + if (pixel_data) + free(pixel_data); + + if (run_loop_src != 0) + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode); + + if (run_loop_src != 0) + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src, kCFRunLoopDefaultMode); +} + +/** ********************************************************************* + * called when our view needs refreshing + ***********************************************************************/ + +- (void) drawRect:(NSRect)dirtyRect +{ + if (!rdp_context) + return; + + if (g_mrdpview->isRemoteApp && g_mrdpview->currentWindow) { + return; + } + + if (!bmiRep) { + pixel_data = (char *) malloc(width * height * sizeof(struct rgba_data)); + bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixel_data + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:sizeof(struct rgba_data) + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 //NSAlphaFirstBitmapFormat + bytesPerRow:width * sizeof(struct rgba_data) + bitsPerPixel:0]; + } + + [bmiRep drawInRect:dirtyRect fromRect:dirtyRect operation:NSCompositeCopy fraction:1.0 respectFlipped:NO hints:nil]; +} + +/************************************************************************ + instance methods +************************************************************************/ + +/** ********************************************************************* + * called when RDP server wants us to update a rect with new data + ***********************************************************************/ + +- (void) my_draw_rect:(void *)context +{ + int w; + int h; + + rdpContext * ctx = (rdpContext *) context; + + struct rgba_data + { + char red; + char green; + char blue; + char alpha; + }; + + if (isRemoteApp && currentWindow) { + NSRect vrect = [ [currentWindow view] frame]; + [[currentWindow view] setNeedsDisplayInRect:vrect]; + // actual drawing will be done in MRDPRailView:drawRect() + return; + } + + w = width; + h = height; + rect.origin.x = 0; + rect.origin.y = 0; + rect.size.width = w; + rect.size.height = h; + + if (!bmiRep) { + pixel_data = (char *) malloc(w * h * sizeof(struct rgba_data)); + bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixel_data + pixelsWide:w + pixelsHigh:h + bitsPerSample:8 + samplesPerPixel:sizeof(struct rgba_data) + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 //NSAlphaFirstBitmapFormat + bytesPerRow:w * sizeof(struct rgba_data) + bitsPerPixel:0]; + } + +#ifdef MRDP_DRAW_INDIVIDUAL_RECTS + [self setNeedsDisplayInRect:rect]; + return; +#endif + + convert_color_space(pixel_data, (char *) ctx->gdi->primary_buffer, &rect, w, h); + [self setNeedsDisplayInRect:rect]; +} + +/** ********************************************************************* + * save state info for use by other methods later on + ***********************************************************************/ + +- (void) saveStateInfo:(freerdp *) instance:(rdpContext *) context +{ + rdp_instance = instance; + rdp_context = context; +} + +/** ********************************************************************* + * double check that a mouse event occurred in our client view + ***********************************************************************/ + +- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr +{ + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + if ((x < 0) || (y < 0)) { + if (mouseInClientArea) { + // set default cursor before leaving client area + mouseInClientArea = NO; + NSCursor *cur = [NSCursor arrowCursor]; + [cur set]; + } + return NO; + } + if ((x > width) || (y > height)) { + if (mouseInClientArea) { + // set default cursor before leaving client area + mouseInClientArea = NO; + NSCursor *cur = [NSCursor arrowCursor]; + [cur set]; + } + return NO; + } + + // on Mac origin is at lower left, but we want it on upper left + y = height - y; + + *xptr = x; + *yptr = y; + mouseInClientArea = YES; + return YES; +} + +/** ********************************************************************* + * called when we fail to connect to a RDP server + ***********************************************************************/ + +- (void) rdpConnectError +{ + + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Error connecting to server"]; + [alert beginSheetModalForWindow:[g_mrdpview window] + modalDelegate:g_mrdpview + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + +/** ********************************************************************* + * called when we fail to launch remote app on RDP server + ***********************************************************************/ + +- (void) rdpRemoteAppError +{ + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Error starting remote app on specified server"]; + [alert beginSheetModalForWindow:[g_mrdpview window] + modalDelegate:g_mrdpview + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + +/** ********************************************************************* + * just a terminate selector for above call + ***********************************************************************/ + +- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci +{ + [NSApp terminate:nil]; +} + +- (void) onPasteboardTimerFired :(NSTimer *) timer +{ + NSArray *types; + int i; + + i = (int) [pasteboard_rd changeCount]; + if (i != pasteboard_changecount) + { + pasteboard_changecount = i; + types = [NSArray arrayWithObject:NSStringPboardType]; + NSString *str = [pasteboard_rd availableTypeFromArray:types]; + if (str != nil) + { + cliprdr_send_supported_format_list(rdp_instance); + } + } +} + +- (void) setViewSize : (int) w : (int) h +{ + // store current dimensions + width = w; + height = h; + + // compute difference between window and client area + NSRect outerRect = [[g_mrdpview window] frame]; + NSRect innerRect = [g_mrdpview frame]; + + int widthDiff = outerRect.size.width - innerRect.size.width; + int heightDiff = outerRect.size.height - innerRect.size.height; + + if (!g_mrdpview->isRemoteApp) { + // we are not in RemoteApp mode, disable resizing + outerRect.size.width = w + widthDiff; + outerRect.size.height = h + heightDiff; + [[g_mrdpview window] setMaxSize:outerRect.size]; + [[g_mrdpview window] setMinSize:outerRect.size]; + [[g_mrdpview window] setFrame:outerRect display:YES]; + + // set client area to specified dimensions + innerRect.size.width = w; + innerRect.size.height = h; + [g_mrdpview setFrame:innerRect]; + + return; + } + + // we are in RemoteApp mode + + outerRect.origin.x = 0; + outerRect.origin.y = 0; + outerRect.size.width = width + widthDiff; + outerRect.size.height = height + heightDiff; + [[g_mrdpview window] setFrame:outerRect display:YES]; + + // set client area to specified dimensions + innerRect.size.width = width; + innerRect.size.height = height; + [g_mrdpview setFrame:innerRect]; + + // main window displays desktop background - hide it + [[g_mrdpview window] orderOut:g_mrdpview]; +} + +// RAIL_TODO is this func required +- (void) windowDidResize:(NSNotification *) notification +{ + RAIL_WINDOW_MOVE_ORDER windowMove; + + printf("RAIL_TODO: MRDPView: windowDidResize() - not yet implemented\n"); + + return; + + // window resize valid only in RemoteApp mode + if (!g_mrdpview->isRemoteApp) + return; + + // window has resized, let server know + + NSRect r = [[g_mrdpview window] frame]; + printf("----- LK_TODO: MRDPView:windowDidResize (%d,%d %dx%d)\n", + (int) r.origin.x, (int) r.origin.y, + (int) r.size.width, (int) r.size.height); + + + windowMove.windowId = [currentWindow windowID]; + + windowMove.left = (uint16) r.origin.x; // x-cordinate of top left corner + windowMove.right = (uint16) (windowMove.left + r.size.width); // x-cordinate of bottom right corner + windowMove.top = (uint16) r.origin.y; // y-cordinate of top left corner + windowMove.bottom = (uint16) (windowMove.top + r.size.height); // y-cordinate of bottom right corner + + printf("----- LK_TODO: MRDPView:windowDidResize windowID=%d left=%d top=%d right=%d bottom=x%d width=%f height=%f\n", + [currentWindow windowID], windowMove.left, windowMove.top, windowMove.right, windowMove.bottom, r.size.width, r.size.height); + + //mac_send_rail_client_event(g_mrdpview->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); +} + +/************************************************************************ + * * + * C functions * + * * + ***********************************************************************/ + +/** ********************************************************************* + * connect to RDP server + * + * @return 0 on success, -1 on failure + ***********************************************************************/ + +int rdp_connect() +{ + freerdp *inst; + int status; + + freerdp_channels_global_init(); + + inst = freerdp_new(); + inst->PreConnect = mac_pre_connect; + inst->PostConnect = mac_post_connect; + inst->context_size = sizeof(struct mac_context); + inst->ContextNew = mac_context_new; + inst->ContextFree = mac_context_free; + inst->ReceiveChannelData = receive_channel_data; + freerdp_context_new(inst); + + status = freerdp_connect(inst); + if(status) { + freerdp_check_fds(inst); + [g_mrdpview setIs_connected:1]; + return 0; + } + [g_mrdpview setIs_connected:0]; + [g_mrdpview rdpConnectError]; + return -1; +} + +/** ********************************************************************* + * a callback given to freerdp_connect() to process the pre-connect operations. + * + * @param inst - pointer to a rdp_freerdp struct that contains the connection's parameters, and + * will be filled with the appropriate informations. + * + * @return true if successful. false otherwise. + ************************************************************************/ + +boolean mac_pre_connect(freerdp *inst) +{ + char *cptr; + int len; + int i; + + inst->settings->offscreen_bitmap_cache = false; + inst->settings->glyph_cache = true; + inst->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; + inst->settings->order_support[NEG_GLYPH_INDEX_INDEX] = true; + inst->settings->order_support[NEG_FAST_GLYPH_INDEX] = false; + inst->settings->order_support[NEG_FAST_INDEX_INDEX] = false; + inst->settings->order_support[NEG_SCRBLT_INDEX] = true; + inst->settings->order_support[NEG_SAVEBITMAP_INDEX] = false; + + inst->settings->bitmap_cache = true; + inst->settings->order_support[NEG_MEMBLT_INDEX] = true; + inst->settings->order_support[NEG_MEMBLT_V2_INDEX] = true; + inst->settings->order_support[NEG_MEM3BLT_INDEX] = false; + inst->settings->order_support[NEG_MEM3BLT_V2_INDEX] = false; + inst->settings->bitmapCacheV2NumCells = 3; // 5; + inst->settings->bitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; + inst->settings->bitmapCacheV2CellInfo[0].persistent = false; + inst->settings->bitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; + inst->settings->bitmapCacheV2CellInfo[1].persistent = false; + inst->settings->bitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; + inst->settings->bitmapCacheV2CellInfo[2].persistent = false; + inst->settings->bitmapCacheV2CellInfo[3].numEntries = 0; // 4096; + inst->settings->bitmapCacheV2CellInfo[3].persistent = false; + inst->settings->bitmapCacheV2CellInfo[4].numEntries = 0; // 2048; + inst->settings->bitmapCacheV2CellInfo[4].persistent = false; + + inst->settings->order_support[NEG_MULTIDSTBLT_INDEX] = false; + inst->settings->order_support[NEG_MULTIPATBLT_INDEX] = false; + inst->settings->order_support[NEG_MULTISCRBLT_INDEX] = false; + inst->settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false; + inst->settings->order_support[NEG_POLYLINE_INDEX] = false; + inst->settings->color_depth = 24; + inst->settings->sw_gdi = 1; + + // setup callbacks + inst->update->BeginPaint = mac_begin_paint; + inst->update->EndPaint = mac_end_paint; + inst->update->SetBounds = mac_set_bounds; + inst->update->BitmapUpdate = mac_bitmap_update; + + NSArray *args = [[NSProcessInfo processInfo] arguments]; + +#ifdef RUN_IN_XCODE + g_mrdpview->argc = 30; +#else + g_mrdpview->argc = (int) [args count]; +#endif + + g_mrdpview->argv = malloc(sizeof(char *) * g_mrdpview->argc); + if (g_mrdpview->argv == NULL) { + return false; + } + +#ifdef RUN_IN_XCODE + + // create our own cmd line args + i = 0; + + NSString *sptr = [args objectAtIndex:0]; + len = [sptr length] + 1; + cptr = (char *) malloc(len); + strcpy(cptr, [sptr UTF8String]); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "-g"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "1280x800"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "--sec"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "rdp"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "--plugin"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "cliprdr"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "--plugin"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "rdpsnd"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "-u"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "lk"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "-p"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "abc@@@123"); + g_mrdpview->argv[i++] = cptr; + +#if 1 + // for RemoteApp (RAIL) testing + cptr = (char *)malloc(80); + strcpy(cptr, "--app"); + g_mrdpview->argv[i++] = cptr; + g_mrdpview->isRemoteApp = TRUE; + + cptr = (char *)malloc(80); + strcpy(cptr, "--plugin"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "rail"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "--data"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "||WordPad"); + g_mrdpview->argv[i++] = cptr; + + cptr = (char *)malloc(80); + strcpy(cptr, "--"); + g_mrdpview->argv[i++] = cptr; +#endif + + cptr = (char *)malloc(80); + strcpy(cptr, "192.168.1.69:45990"); + g_mrdpview->argv[i++] = cptr; + + g_mrdpview->argc = i; + +#else + // MacFreeRDP was not run in Xcode + i = 0; + + // in RemoteApp (RAIL) mode, we connect to RDP server at max screen resolution; + // in order to achieve this, we need to modify the cmd line args entered by the user; + + if (g_mrdpview->isRemoteApp) { + boolean gotGeometry = NO; + + // get dimensions of screen that has keyboard focus; + // we use these dimensions when connecting to RDP server + inst->settings->width = [[NSScreen mainScreen] frame].size.width; + inst->settings->height = [[NSScreen mainScreen] frame].size.height - g_mrdpview->titleBarHeight; + g_mrdpview->width = inst->settings->width; + g_mrdpview->height = inst->settings->height; + + for (NSString * str in args) + { + if (gotGeometry) { + gotGeometry = NO; + cptr = (char *) malloc(20); + sprintf(cptr, "%dx%d", g_mrdpview->width, g_mrdpview->height); + g_mrdpview->argv[i++] = cptr; + continue; + } + + len = (int) ([str length] + 1); + cptr = (char *) malloc(len); + strcpy(cptr, [str UTF8String]); + g_mrdpview->argv[i++] = cptr; + + // -g is the cmd line arg to specify screen resolution/geometry + if ([str compare:@"-g"] == NSOrderedSame) { + gotGeometry = YES; + } + } + } + else { + for (NSString * str in args) + { + len = (int) ([str length] + 1); + cptr = (char *) malloc(len); + strcpy(cptr, [str UTF8String]); + g_mrdpview->argv[i++] = cptr; + } + } +#endif + + freerdp_parse_args(inst->settings, g_mrdpview->argc, g_mrdpview->argv, process_plugin_args, inst->context->channels, NULL, NULL); + if ((strcmp(g_mrdpview->argv[1], "-h") == 0) || (strcmp(g_mrdpview->argv[1], "--help") == 0)) { + [NSApp terminate:nil]; + return true; + } + + [g_mrdpview setViewSize:inst->settings->width :inst->settings->height]; + + freerdp_channels_pre_connect(inst->context->channels, inst); + return true; +} + +/** ********************************************************************* + * a callback registered with freerdp_connect() to perform post-connection operations. + * we get called only if the connection was initialized properly, and will continue + * the initialization based on the newly created connection. + * + * @param inst - pointer to a rdp_freerdp struct + * + * @return true on success, false on failure + * + ************************************************************************/ + +boolean mac_post_connect(freerdp *inst) +{ + uint32 flags; + rdpPointer rdp_pointer; + void *rd_fds[32]; + void *wr_fds[32]; + int rd_count = 0; + int wr_count = 0; + int index; + int fds[32]; + + memset(&rdp_pointer, 0, sizeof(rdpPointer)); + rdp_pointer.size = sizeof(rdpPointer); + rdp_pointer.New = pointer_new; + rdp_pointer.Free = pointer_free; + rdp_pointer.Set = pointer_set; + rdp_pointer.SetNull = pointer_setNull; + rdp_pointer.SetDefault = pointer_setDefault; + + flags = CLRCONV_ALPHA; + flags |= CLRBUF_32BPP; + + gdi_init(inst, flags, NULL); + pointer_cache_register_callbacks(inst->update); + graphics_register_pointer(inst->context->graphics, &rdp_pointer); + + // register file descriptors with the RunLoop + if (!freerdp_get_fds(inst, rd_fds, &rd_count, 0, 0)) + { + printf("mac_post_connect: freerdp_get_fds() failed!\n"); + } + + for (index = 0; index < rd_count; index++) + { + fds[index] = (int)(long)rd_fds[index]; + } + register_fds(fds, rd_count, inst); + + // register channel manager file descriptors with the RunLoop + if (!freerdp_channels_get_fds(inst->context->channels, inst, rd_fds, &rd_count, wr_fds, &wr_count)) + { + printf("ERROR: freerdp_channels_get_fds() failed\n"); + } + for (index = 0; index < rd_count; index++) + { + fds[index] = (int)(long)rd_fds[index]; + } + register_channel_fds(fds, rd_count, inst); + freerdp_channels_post_connect(inst->context->channels, inst); + + // setup RAIL (remote app) + inst->context->rail = rail_new(inst->settings); + rail_register_update_callbacks(inst->context->rail, inst->update); + mac_rail_register_callbacks(inst, inst->context->rail); + + // setup pasteboard (aka clipboard) for copy operations (write only) + g_mrdpview->pasteboard_wr = [NSPasteboard generalPasteboard]; + + // setup pasteboard for read operations + g_mrdpview->pasteboard_rd = [NSPasteboard generalPasteboard]; + g_mrdpview->pasteboard_changecount = (int) [g_mrdpview->pasteboard_rd changeCount]; + g_mrdpview->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:g_mrdpview selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + + // we want to be notified when window resizes + [[NSNotificationCenter defaultCenter] addObserver:g_mrdpview selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:nil]; + + return true; +} + +/** ********************************************************************* + * create a new mouse cursor + * + * @param context our context state + * @param pointer information about the cursor to create + * + ************************************************************************/ + +void pointer_new(rdpContext* context, rdpPointer* pointer) +{ + MRDPCursor *mrdpCursor = [[MRDPCursor alloc] init]; + uint8 *cursor_data; + + NSRect rect; + rect.size.width = pointer->width; + rect.size.height = pointer->height; + rect.origin.x = pointer->xPos; + rect.origin.y = pointer->yPos; + + cursor_data = (uint8 *) malloc(rect.size.width * rect.size.height * 4); + mrdpCursor->cursor_data = cursor_data; + + 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 + + // store cursor bitmap image in representation - required by NSImage + NSBitmapImageRep *bmiRep; + bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data + pixelsWide:rect.size.width + pixelsHigh:rect.size.height + bitsPerSample:8 + samplesPerPixel:sizeof(struct rgba_data) + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 + bytesPerRow:rect.size.width * 4 + bitsPerPixel:0]; + mrdpCursor->bmiRep = bmiRep; + + // create an image using above representation + NSImage *image = [[NSImage alloc] initWithSize:[bmiRep size]]; + [image addRepresentation: bmiRep]; + [image setFlipped:NO]; + mrdpCursor->nsImage = image; + + // need hotspot to create cursor + NSPoint hotSpot; + hotSpot.x = pointer->xPos; + hotSpot.y = pointer->yPos; + + NSCursor *cursor = [[NSCursor alloc] initWithImage: image hotSpot:hotSpot]; + mrdpCursor->nsCursor = cursor; + mrdpCursor->pointer = pointer; + + // save cursor for later use in pointer_set() + NSMutableArray *ma = g_mrdpview->cursors; + [ma addObject:mrdpCursor]; +} + +/** ********************************************************************* + * release resources on specified cursor + ************************************************************************/ + +void pointer_free(rdpContext* context, rdpPointer* pointer) +{ + NSMutableArray *ma = g_mrdpview->cursors; + + for (MRDPCursor *cursor in ma) + { + if (cursor->pointer == pointer) { + cursor->nsImage = nil; + cursor->nsCursor = nil; + cursor->bmiRep = nil; + free(cursor->cursor_data); + [ma removeObject:cursor]; + return; + } + } +} + +/** ********************************************************************* + * set specified cursor as the current cursor + ************************************************************************/ + +void pointer_set(rdpContext* context, rdpPointer* pointer) +{ + NSMutableArray *ma = g_mrdpview->cursors; + + if (!g_mrdpview->mouseInClientArea) + { + return; // not in client area + } + + for (MRDPCursor *cursor in ma) + { + if (cursor->pointer == pointer) { + [cursor->nsCursor set]; + return; + } + } +} + +/** ********************************************************************* + * do not display any mouse cursor + ***********************************************************************/ + +void pointer_setNull(rdpContext* context) +{ +} + +/** ********************************************************************* + * display default mouse cursor + ***********************************************************************/ + +void pointer_setDefault(rdpContext* context) +{ +} + +/** ********************************************************************* + * create a new context - but all we really need to do is save state info + ***********************************************************************/ + +void mac_context_new(freerdp *inst, rdpContext *context) +{ + [g_mrdpview saveStateInfo:inst :context]; + context->channels = freerdp_channels_new(); +} + +/** ********************************************************************* + * we don't do much over here + ***********************************************************************/ + +void mac_context_free(freerdp *inst, rdpContext *context) +{ +} + +/** ********************************************************************* + * clip drawing surface so nothing is drawn outside specified bounds + ***********************************************************************/ + +void mac_set_bounds(rdpContext *context, rdpBounds *bounds) +{ +} + +/** ********************************************************************* + * we don't do much over here + ***********************************************************************/ + +void mac_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) +{ +} + +/** ********************************************************************* + * we don't do much over here + ***********************************************************************/ + +void mac_begin_paint(rdpContext *context) +{ + rdpGdi* gdi = context->gdi; + gdi->primary->hdc->hwnd->invalid->null = 1; +} + +/** ********************************************************************* + * RDP server wants us to draw new data in the view + ***********************************************************************/ + +void mac_end_paint(rdpContext* context) +{ + int i; + NSRect drawRect; + rdpGdi * gdi; + + if ((context == 0) || (context->gdi == 0)) + return; + + if (context->gdi->primary->hdc->hwnd->invalid->null) + return; + + if (context->gdi->drawing != context->gdi->primary) + return; + + gdi = g_mrdpview->rdp_context->gdi; + + if (g_mrdpview->isRemoteApp && g_mrdpview->currentWindow) { + [[g_mrdpview->currentWindow view] updateDisplay]; + return; + } + + for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++) + { + drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x; + drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y; + drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w; + drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h; + + convert_color_space(g_mrdpview->pixel_data, (char *) gdi->primary_buffer, &drawRect, g_mrdpview->width, g_mrdpview->height); + + [g_mrdpview setNeedsDisplayInRect:drawRect]; + } + gdi->primary->hdc->hwnd->ninvalid = 0; +} + +/** ********************************************************************* + * called when data is available on a socket + ***********************************************************************/ + +void skt_activity_cb( + CFSocketRef s, + CFSocketCallBackType callbackType, + CFDataRef address, + const void *data, + void *info + ) +{ + if (!freerdp_check_fds(info)) { + // lost connection or did not connect + [NSApp terminate:nil]; + } +} + +/** ********************************************************************* + * called when data is available on a virtual channel + ***********************************************************************/ + +void channel_activity_cb( + CFSocketRef s, + CFSocketCallBackType callbackType, + CFDataRef address, + const void *data, + void *info + ) +{ + freerdp *inst = (freerdp *) info; + RDP_EVENT* event; + + GOT_HERE; + + freerdp_channels_check_fds(inst->context->channels, inst); + event = freerdp_channels_pop_event(inst->context->channels); + if (event) { + switch (event->event_class) + { + case RDP_EVENT_CLASS_RAIL: + mac_process_rail_event(inst, event); + break; + + case RDP_EVENT_CLASS_CLIPRDR: + process_cliprdr_event(inst, event); + break; + } + } +} + +/** ********************************************************************* + * setup callbacks for data availability on sockets + ***********************************************************************/ + +int register_fds(int *fds, int count, void *inst) +{ + int i; + CFSocketRef skt_ref; + CFSocketContext skt_context = { 0, inst, NULL, NULL, NULL }; + + for (i = 0; i < count; i++) + { + skt_ref = CFSocketCreateWithNative(NULL, fds[i], kCFSocketReadCallBack, skt_activity_cb, &skt_context); + g_mrdpview->run_loop_src = CFSocketCreateRunLoopSource(NULL, skt_ref, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), g_mrdpview->run_loop_src, kCFRunLoopDefaultMode); + CFRelease(skt_ref); + } + return 0; +} + +/** ********************************************************************* + * setup callbacks for data availability on channels + ***********************************************************************/ + +int register_channel_fds(int *fds, int count, void *inst) +{ + int i; + CFSocketRef skt_ref; + CFSocketContext skt_context = { 0, inst, NULL, NULL, NULL }; + + for (i = 0; i < count; i++) + { + skt_ref = CFSocketCreateWithNative(NULL, fds[i], kCFSocketReadCallBack, channel_activity_cb, &skt_context); + g_mrdpview->run_loop_src_channels = CFSocketCreateRunLoopSource(NULL, skt_ref, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), g_mrdpview->run_loop_src_channels, kCFRunLoopDefaultMode); + CFRelease(skt_ref); + } + return 0; +} + +/** ********************************************************************* + * called when channel data is available + ***********************************************************************/ + +int receive_channel_data(freerdp *inst, int chan_id, uint8 *data, int size, int flags, int total_size) +{ + return freerdp_channels_data(inst, chan_id, data, size, flags, total_size); +} + +/** ********************************************************************* + * convert an array containing ARGB data to RGBA + ***********************************************************************/ + +void convert_color_space(char *dest, char *src, NSRect* drawRect, int width, int height) +{ + int i; + int j; + int x; + int y; + int cx; + int cy; + int pixel; + int pixel1; + int pixel2; + int* src32; + int* dst32; + + if ((!dest) || (!src)) { + return; + } + + x = drawRect->origin.x; + y = drawRect->origin.y; + cx = drawRect->size.width; + cy = drawRect->size.height; + + for (j = 0; j < cy; j++) + { + src32 = (int*)(src + ((y + j) * width + x) * 4); + dst32 = (int*)(dest + ((y + j) * width + x) * 4); + for (i = 0; i < cx; i++) + { + pixel = *src32; + pixel1 = (pixel & 0x00ff0000) >> 16; + pixel2 = (pixel & 0x000000ff) << 16; + pixel = (pixel & 0xff00ff00) | pixel1 | pixel2; + *dst32 = pixel; + src32++; + dst32++; + } + } + + drawRect->origin.y = height - drawRect->origin.y - drawRect->size.height; +} + +/** + * 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. + * + * @param settings + * @param name + * @param plugin_data + * @param user_data + * + * @return 1 + */ + +int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data) +{ + rdpChannels* channels = (rdpChannels*) user_data; + + freerdp_channels_load_plugin(channels, settings, name, plugin_data); + return 1; +} + +/* + * stuff related to clipboard redirection + */ + +/** + * remote system has requested clipboard data from local system + */ + +void cliprdr_process_cb_data_request_event(freerdp *inst) +{ + RDP_CB_DATA_RESPONSE_EVENT *event; + NSArray *types; + int len; + + event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, + RDP_EVENT_TYPE_CB_DATA_RESPONSE, NULL, NULL); + types = [NSArray arrayWithObject:NSStringPboardType]; + NSString *str = [g_mrdpview->pasteboard_rd availableTypeFromArray:types]; + if (str == nil) + { + event->data = NULL; + event->size = 0; + } + else + { + NSString *data = [g_mrdpview->pasteboard_rd stringForType:NSStringPboardType]; + len = (int) ([data length] * 2 + 2); + event->data = malloc(len); + [data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding]; + event->size = len; + } + freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); +} + +void cliprdr_send_data_request(freerdp *inst, uint32 format) +{ + RDP_CB_DATA_REQUEST_EVENT* event; + + event = (RDP_CB_DATA_REQUEST_EVENT *) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, + RDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL); + event->format = format; + freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); +} + +/** + * at the moment, only the following formats are supported + * CB_FORMAT_TEXT + * CB_FORMAT_UNICODETEXT + */ + +void cliprdr_process_cb_data_response_event(freerdp *inst, RDP_CB_DATA_RESPONSE_EVENT *event) +{ + NSString *str; + NSArray *types; + + if (event->size == 0) { + return; + } + + if (g_mrdpview->pasteboard_format == CB_FORMAT_TEXT || g_mrdpview->pasteboard_format == CB_FORMAT_UNICODETEXT) { + str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2]; + types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; + [g_mrdpview->pasteboard_wr declareTypes:types owner:g_mrdpview]; + [g_mrdpview->pasteboard_wr setString:str forType:NSStringPboardType]; + } +} + +void cliprdr_process_cb_monitor_ready_event(freerdp* inst) +{ + RDP_EVENT* event; + RDP_CB_FORMAT_LIST_EVENT* format_list_event; + + event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); + + format_list_event = (RDP_CB_FORMAT_LIST_EVENT*)event; + format_list_event->num_formats = 0; + + freerdp_channels_send_event(inst->context->channels, event); +} + +/** + * list of supported clipboard formats; currently only the following are supported + * CB_FORMAT_TEXT + * CB_FORMAT_UNICODETEXT + */ + +void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVENT* event) +{ + int i; + + if (event->num_formats == 0) { + return; + } + + for (i = 0; i < event->num_formats; i++) + { + switch (event->formats[i]) + { + case CB_FORMAT_RAW: + printf("CB_FORMAT_RAW: not yet supported\n"); + break; + + case CB_FORMAT_TEXT: + case CB_FORMAT_UNICODETEXT: + g_mrdpview->pasteboard_format = CB_FORMAT_UNICODETEXT; + cliprdr_send_data_request(inst, 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; + } + } +} + +void process_cliprdr_event(freerdp *inst, RDP_EVENT *event) +{ + if (event) { + switch (event->event_type) + { + // Monitor Ready PDU is sent by server to indicate that it has been + // inited and is ready. This PDU is transmitted by the server after it has sent + // Clipboard Capabilities PDU + case RDP_EVENT_TYPE_CB_MONITOR_READY: + cliprdr_process_cb_monitor_ready_event(inst); + break; + + // 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 + case RDP_EVENT_TYPE_CB_FORMAT_LIST: + cliprdr_process_cb_format_list_event(inst, (RDP_CB_FORMAT_LIST_EVENT*) event); + break; + + // 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 + case RDP_EVENT_TYPE_CB_DATA_REQUEST: + cliprdr_process_cb_data_request_event(inst); + break; + + // 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 + case RDP_EVENT_TYPE_CB_DATA_RESPONSE: + cliprdr_process_cb_data_response_event(inst, (RDP_CB_DATA_RESPONSE_EVENT*) event); + break; + + default: + printf("process_cliprdr_event: unknown event type %d\n", event->event_type); + break; + } + freerdp_event_free(event); + } +} + +void cliprdr_send_supported_format_list(freerdp *inst) +{ + RDP_CB_FORMAT_LIST_EVENT* event; + + event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, + RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); + + event->formats = (uint32 *) malloc(sizeof(uint32) * 1); + event->num_formats = 1; + event->formats[0] = CB_FORMAT_UNICODETEXT; + freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); +} + +/**************************************************************************************** + * * + * * + * RemoteApp (RAIL) related stuff goes here * + * * + * * + ****************************************************************************************/ + +void mac_process_rail_event(freerdp *inst, RDP_EVENT *event) +{ + switch (event->event_type) + { + case RDP_EVENT_TYPE_RAIL_CHANNEL_GET_SYSPARAMS: + mac_process_rail_get_sysparams_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_EXEC_RESULTS: + mac_process_rail_exec_result_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_SYSPARAM: + mac_process_rail_server_sysparam_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_MINMAXINFO: + mac_process_rail_server_minmaxinfo_event(inst->context->channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_LOCALMOVESIZE: + mac_process_rail_server_localmovesize_event(inst, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_APPID_RESP: + GOT_HERE; + //xf_process_rail_appid_resp_event(xfi, channels, event); + break; + + case RDP_EVENT_TYPE_RAIL_CHANNEL_LANGBARINFO: + GOT_HERE; + //xf_process_rail_langbarinfo_event(xfi, channels, event); + break; + } +} + +void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window) +{ + boolean centerWindow = NO; + boolean moveWindow = NO; + boolean displayAsModal = NO; + NSMutableArray * ma = g_mrdpview->windows; + + // make sure window fits resolution + if (window->windowWidth > g_mrdpview->width) + window->windowWidth = g_mrdpview->width; + + if (window->windowHeight > g_mrdpview->height) + window->windowHeight = g_mrdpview->height; + + // center main window, which is the first to be created + if ([ma count] == 0) { + centerWindow = YES; + moveWindow = YES; + } + + if ((window->extendedStyle & WS_EX_TOPMOST) || (window->extendedStyle & WS_EX_TOOLWINDOW)) { + [g_mrdpview->currentWindow view]->skipMoveWindowOnce = TRUE; + moveWindow = YES; + } + else if (window->style & WS_POPUP) { + centerWindow = YES; + moveWindow = YES; + } + else { + } + + // create NSWindow + NSRect winFrame = NSMakeRect(window->windowOffsetX, window->windowOffsetY, + window->windowWidth, window->windowHeight); + if (centerWindow) + apple_center_window(&winFrame); + + MRDPRailWindow * newWindow = [[MRDPRailWindow alloc] initWithContentRect:winFrame + styleMask:NSTitledWindowMask | NSResizableWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + + // this does not work if specified during window creation in above code + [newWindow setStyleMask:NSBorderlessWindowMask]; + + if (moveWindow) { + // let RDP server know that window has moved + RAIL_WINDOW_MOVE_ORDER windowMove; + apple_to_windowMove(&winFrame, &windowMove); + windowMove.windowId = window->windowId; + mac_send_rail_client_event(g_mrdpview->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); + } + + // create MRDPRailView and add to above window + NSRect viewFrame = NSMakeRect(window->clientOffsetX, window->clientOffsetY, + window->clientAreaWidth, window->clientAreaHeight); + + MRDPRailView * newView = [[MRDPRailView alloc] initWithFrame:viewFrame]; + [newView setRdpInstance:g_mrdpview->rdp_instance width:g_mrdpview->width andHeight:g_mrdpview->height windowID: window->windowId]; + [newWindow setContentView:newView]; + + // save new window + MRDPWindow * mrdpWindow = [[MRDPWindow alloc] init]; + [mrdpWindow setWindowID:window->windowId]; + [mrdpWindow setWindow:newWindow]; + [mrdpWindow setView:newView]; + + // add to list of windows + [ma addObject:mrdpWindow]; + + // make new window current + g_mrdpview->currentWindow = mrdpWindow; + + if (displayAsModal) { + // display as modal window + NSModalSession session = [NSApp beginModalSessionForWindow:newWindow]; + while (1) + { + if ([NSApp runModalSession:session] != NSRunContinuesResponse) + break; + } + [NSApp endModalSession:session]; + } + else { + [newWindow makeKeyAndOrderFront:NSApp]; + [[g_mrdpview window] resignFirstResponder]; + [g_mrdpview resignFirstResponder]; + [[g_mrdpview window] setNextResponder:newWindow]; + } + + return; +} + +void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window) +{ + if (g_mrdpview->currentWindow) { + rail_MoveWindow(rail, window); + return; + } +} + +void mac_rail_ShowWindow(rdpRail *rail, rdpWindow *window, uint8 state) +{ +} + +void mac_rail_SetWindowText(rdpRail *rail, rdpWindow *window) +{ +} + +void mac_rail_SetWindowIcon(rdpRail *rail, rdpWindow *window, rdpIcon *icon) +{ +} + +void mac_rail_SetWindowRects(rdpRail *rail, rdpWindow *window) +{ +} + +void mac_rail_SetWindowVisibilityRects(rdpRail *rail, rdpWindow *window) +{ +} + +/** ********************************************************************* + * destroy window created in mac_rail_CreateWindow() + ***********************************************************************/ + +void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window) +{ + int count = 0; + + for (MRDPWindow * win in g_mrdpview->windows) + { + if ([win windowID] == window->windowId) { + //[[win window] close]; + [win setView:nil]; + [win setWindow:nil]; + [g_mrdpview->windows removeObject:win]; + count = [g_mrdpview->windows count]; + if (count) { + g_mrdpview->currentWindow = [g_mrdpview->windows objectAtIndex:count - 1]; + //[[g_mrdpview window] makeKeyAndOrderFront:[g_mrdpview->currentWindow window]]; + [[g_mrdpview->currentWindow window] makeKeyAndOrderFront:NSApp]; + } + else { + g_mrdpview->currentWindow = nil; + // RAIL_TODO [[g_mrdpview window] makeKeyAndOrderFront:[g_mrdpview window]]; + [NSApp terminate:nil]; + } + return; + } + } +} + +void mac_rail_register_callbacks(freerdp *inst, rdpRail *rail) +{ + GOT_HERE; + + rail->extra = (void *) inst; + rail->rail_CreateWindow = mac_rail_CreateWindow; + rail->rail_MoveWindow = mac_rail_MoveWindow; + rail->rail_ShowWindow = mac_rail_ShowWindow; + rail->rail_SetWindowText = mac_rail_SetWindowText; + rail->rail_SetWindowIcon = mac_rail_SetWindowIcon; + rail->rail_SetWindowRects = mac_rail_SetWindowRects; + rail->rail_SetWindowVisibilityRects = mac_rail_SetWindowVisibilityRects; + rail->rail_DestroyWindow = mac_rail_DestroyWindow; +} + +/** ********************************************************************* + * set work area size, which is the portion of the screen not obscured + * by the system taskbar or by application desktop toolbars + ************************************************************************/ + +void mac_process_rail_get_sysparams_event(rdpChannels *channels, RDP_EVENT *event) +{ + RAIL_SYSPARAM_ORDER * sysparam; + sysparam = (RAIL_SYSPARAM_ORDER *) event->user_data; + + sysparam->workArea.left = 0; + sysparam->workArea.top = 22; + sysparam->workArea.right = g_mrdpview->width; + sysparam->workArea.bottom = g_mrdpview->height - 22; + + sysparam->taskbarPos.left = 0; + sysparam->taskbarPos.top = 0; + sysparam->taskbarPos.right = 0; + sysparam->taskbarPos.bottom = 0; + + sysparam->dragFullWindows = false; + + mac_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SET_SYSPARAMS, sysparam); +} + +void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* event) +{ + RAIL_SYSPARAM_ORDER* sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data; + + GOT_HERE; + + switch (sysparam->param) + { + case SPI_SET_SCREEN_SAVE_ACTIVE: + break; + + case SPI_SET_SCREEN_SAVE_SECURE: + break; + } +} + +/** ********************************************************************* + * server returned result of exec'ing remote app on server + ************************************************************************/ + +void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event) +{ + RAIL_EXEC_RESULT_ORDER* exec_result; + + GOT_HERE; + + exec_result = (RAIL_EXEC_RESULT_ORDER*) event->user_data; + + if (exec_result->execResult != RAIL_EXEC_S_OK) { + printf("RAIL exec error: execResult=%s NtError=0x%X\n", + error_code_names[exec_result->execResult], exec_result->rawResult); + g_mrdpview->is_connected = FALSE; + [g_mrdpview rdpRemoteAppError]; + } + else { + mac_rail_enable_remoteapp_mode(); + } +} + +/** ********************************************************************* + * sent by server when a window move or resize on the server is being + * initiated. this PDU contains info about the min and max extents + * to which the window can be moved or sized + ************************************************************************/ + +void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event) +{ + RAIL_MINMAXINFO_ORDER * minmax = (RAIL_MINMAXINFO_ORDER*) event->user_data; + +#if 0 + printf("minmax_info: maxPosX=%d maxPosY=%d maxWidth=%d maxHeight=%d minTrackWidth=%d minTrackHeight=%d maxTrackWidth=%d maxTrackHeight=%d\n", + minmax->maxPosX, minmax->maxPosY, minmax->maxWidth, minmax->maxHeight, + minmax->minTrackWidth, minmax->minTrackHeight, minmax->maxTrackWidth, minmax->maxTrackHeight); +#endif +} + +/** ********************************************************************* + * sent by the server when a window on the server is beginning a move or + * resize; use this info to initiate a local move or resize of the + * corresponding local window + ************************************************************************/ + +void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event) +{ + RAIL_LOCALMOVESIZE_ORDER * moveSize = (RAIL_LOCALMOVESIZE_ORDER *) event->user_data; + RAIL_WINDOW_MOVE_ORDER windowMove; + + switch (moveSize->moveSizeType) { + case RAIL_WMSZ_LEFT: + printf("!!!! RAIL_WMSZ_LEFT\n"); + break; + + case RAIL_WMSZ_RIGHT: + printf("!!!! RAIL_WMSZ_RIGHT\n"); + break; + + case RAIL_WMSZ_TOP: + printf("!!!! RAIL_WMSZ_TOP\n"); + break; + + case RAIL_WMSZ_TOPLEFT: + printf("!!!! RAIL_WMSZ_TOPLEFT\n"); + break; + + case RAIL_WMSZ_TOPRIGHT: + printf("!!!! RAIL_WMSZ_TOPRIGHT\n"); + break; + + case RAIL_WMSZ_BOTTOM: + printf("!!!! RAIL_WMSZ_BOTTOM\n"); + break; + + case RAIL_WMSZ_BOTTOMLEFT: + printf("!!!! RAIL_WMSZ_BOTTOMLEFT\n"); + break; + + case RAIL_WMSZ_BOTTOMRIGHT: + printf("!!!! RAIL_WMSZ_BOTTOMRIGHT\n"); + break; + + case RAIL_WMSZ_MOVE: + if (moveSize->isMoveSizeStart) { + // local window move in progress + [g_mrdpview->currentWindow view]->isMoveSizeInProgress = YES; + [g_mrdpview->currentWindow view]->saveInitialDragLoc = YES; + + return; + } + + // local move has completed + [g_mrdpview->currentWindow view]->isMoveSizeInProgress = NO; + [g_mrdpview->currentWindow view]->saveInitialDragLoc = NO; + + //NSRect rect = [[g_mrdpview->currentWindow view] frame]; + NSRect rect = [[[g_mrdpview->currentWindow view] window] frame]; + + // let RDP server know where this window is located + mac_send_rail_client_event(inst->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); + + // the event we just sent will cause an extra MoveWindow() to be invoked which we need to ignore + [g_mrdpview->currentWindow view]->skipMoveWindowOnce = YES; + + break; + + case RAIL_WMSZ_KEYMOVE: + printf("!!!! RAIL_WMSZ_KEYMOVE\n"); + break; + + case RAIL_WMSZ_KEYSIZE: + printf("!!!! RAIL_WMSZ_KEYSIZE\n"); + break; + + default: + break; + } + return; +} + +void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param) +{ + RDP_EVENT *out_event = NULL; + void *payload = NULL; + + GOT_HERE; + + payload = rail_clone_order(event_type, param); + if (payload != NULL) { + out_event = freerdp_event_new(RDP_EVENT_CLASS_RAIL, event_type, + mac_on_free_rail_client_event, payload); + freerdp_channels_send_event(channels, out_event); + } +} + +void mac_on_free_rail_client_event(RDP_EVENT* event) +{ + GOT_HERE; + + if (event->event_class == RDP_EVENT_CLASS_RAIL) + { + rail_free_cloned_order(event->event_type, event->user_data); + } +} + +void mac_rail_enable_remoteapp_mode() +{ + GOT_HERE; + + if (!g_mrdpview->isRemoteApp) + g_mrdpview->isRemoteApp = TRUE; +} + +/** + * given a rect with 0,0 at the bottom left (apple cords) + * convert it to a rect with 0,0 at the top left (windows cords) + */ + +void apple_to_windows_cords(NSRect * r) +{ + r->origin.y = g_mrdpview->height - (r->origin.y + r->size.height); +} + +/** + * 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) + */ + +void windows_to_apple_cords(NSRect * r) +{ + r->origin.y = g_mrdpview->height - (r->origin.y + r->size.height); +} + +void apple_center_window(NSRect * r) +{ + r->origin.x = (g_mrdpview->width - r->size.width) / 2; + r->origin.y = (g_mrdpview->height - r->size.height) / 2; +} + +void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove) +{ + windowMove->left = (uint16) r->origin.x; // x-cord of top left corner + windowMove->top = (uint16) g_mrdpview->height - (r->origin.y + r->size.height); // y-cord of top left corner + windowMove->right = (uint16) (windowMove->left + r->size.width); // x-cord of bottom right corner + windowMove->bottom = (uint16) (windowMove->top + r->size.height); // y-cord of bottom right corner +} + +@end From 28c4203649e18073e380bb2a089514cd9f9b5ace Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Fri, 22 Jun 2012 11:02:13 -0700 Subject: [PATCH 08/27] Fixed following issues in RAIL mode + tool tips are now correctly positioned + window dragging bug has been fixed + resize after window drag was not working - fixed + implemented local resizing --- client/Mac/MRDPRailView.h | 2 + client/Mac/MRDPRailView.m | 221 +++++++++++++++++++++++++++++++++++++- client/Mac/Mac/MRDPView.m | 102 +++++++++--------- 3 files changed, 272 insertions(+), 53 deletions(-) diff --git a/client/Mac/MRDPRailView.h b/client/Mac/MRDPRailView.h index 7240e6234..179f82c7e 100644 --- a/client/Mac/MRDPRailView.h +++ b/client/Mac/MRDPRailView.h @@ -13,6 +13,7 @@ NSPoint savedDragLocation; char * pixelData; boolean mouseInClientArea; + boolean titleBarClicked; int width; int height; int savedWindowId; @@ -32,6 +33,7 @@ boolean isMoveSizeInProgress; boolean saveInitialDragLoc; boolean skipMoveWindowOnce; + int localMoveType; } - (void) updateDisplay; diff --git a/client/Mac/MRDPRailView.m b/client/Mac/MRDPRailView.m index 2cb0b191e..29dfdb6b0 100644 --- a/client/Mac/MRDPRailView.m +++ b/client/Mac/MRDPRailView.m @@ -117,6 +117,7 @@ extern struct kkey g_keys[]; - (void) drawRect:(NSRect)dirtyRect { [bmiRep drawInRect:dirtyRect fromRect:dirtyRect operation:NSCompositeCopy fraction:1.0 respectFlipped:NO hints:nil]; + if (pixelData) { free(pixelData); pixelData = NULL; @@ -152,6 +153,7 @@ extern struct kkey g_keys[]; NSRect winFrame = [[self window] frame]; NSPoint loc = [event locationInWindow]; + int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); @@ -173,7 +175,18 @@ extern struct kkey g_keys[]; NSPoint loc = [event locationInWindow]; int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); + int yPos = (int) (winFrame.size.height - loc.y); + y = height - y; + + + if ((yPos >= 4) && (yPos <= 20)) + titleBarClicked = YES; + else + titleBarClicked = NO; + + savedDragLocation.x = loc.x; + savedDragLocation.y = loc.y; rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); } @@ -191,8 +204,9 @@ extern struct kkey g_keys[]; int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); y = height - y; - + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); + titleBarClicked = NO; } /** ********************************************************************* @@ -291,11 +305,214 @@ extern struct kkey g_keys[]; * called when mouse is moved with left button pressed * note: invocation order is: mouseDown, mouseDragged, mouseUp ***********************************************************************/ - - (void) mouseDragged:(NSEvent *)event { [super mouseDragged:event]; + NSRect winFrame = [[self window] frame]; + NSPoint loc = [event locationInWindow]; + int x = (int) loc.x; + int y = (int) loc.y; + + if (titleBarClicked) { + // window is being dragged to a new location + int newX = x - savedDragLocation.x; + int newY = y - savedDragLocation.y; + + if ((newX == 0) && (newY == 0)) + return; + + winFrame.origin.x += newX; + winFrame.origin.y += newY; + + [[self window] setFrame:winFrame display:YES]; + + return; + } + + if (localMoveType == RAIL_WMSZ_LEFT) { + // left border resize taking place + int diff = (int) (loc.x - savedDragLocation.x); + if (diff == 0) + return; + + if (diff < 0) { + diff = abs(diff); + winFrame.origin.x -= diff; + winFrame.size.width += diff; + } + else { + winFrame.origin.x += diff; + winFrame.size.width -= diff; + } + + [[self window] setFrame:winFrame display:YES]; + return; + } + + if (localMoveType == RAIL_WMSZ_RIGHT) { + // right border resize taking place + int diff = (int) (loc.x - savedDragLocation.x); + if (diff == 0) + return; + + savedDragLocation.x = loc.x; + savedDragLocation.y = loc.y; + + winFrame.size.width += diff; + [[self window] setFrame:winFrame display:YES]; + return; + } + + if (localMoveType == RAIL_WMSZ_TOP) { + // top border resize taking place + int diff = (int) (loc.y - savedDragLocation.y); + if (diff == 0) + return; + + savedDragLocation.x = loc.x; + savedDragLocation.y = loc.y; + + winFrame.size.height += diff; + [[self window] setFrame:winFrame display:YES]; + return; + } + + if (localMoveType == RAIL_WMSZ_BOTTOM) { + // bottom border resize taking place + int diff = (int) (loc.y - savedDragLocation.y); + if (diff == 0) + return; + + if (diff < 0) { + diff = abs(diff); + winFrame.origin.y -= diff; + winFrame.size.height += diff; + } + else { + winFrame.origin.y += diff; + winFrame.size.height -= diff; + } + + [[self window] setFrame:winFrame display:YES]; + return; + } + + if (localMoveType == RAIL_WMSZ_TOPLEFT) { + // top left border resize taking place + int diff = (int) (loc.x - savedDragLocation.x); + if (diff != 0) { + if (diff < 0) { + diff = abs(diff); + winFrame.origin.x -= diff; + winFrame.size.width += diff; + } + else { + winFrame.origin.x += diff; + winFrame.size.width -= diff; + } + } + + diff = (int) (loc.y - savedDragLocation.y); + if (diff != 0) { + savedDragLocation.y = loc.y; + winFrame.size.height += diff; + } + + [[self window] setFrame:winFrame display:YES]; + return; + } + + if (localMoveType == RAIL_WMSZ_TOPRIGHT) { + // top right border resize taking place + int diff = (int) (loc.x - savedDragLocation.x); + if (diff != 0) { + winFrame.size.width += diff; + } + + diff = (int) (loc.y - savedDragLocation.y); + if (diff != 0) { + winFrame.size.height += diff; + } + + savedDragLocation.x = loc.x; + savedDragLocation.y = loc.y; + + [[self window] setFrame:winFrame display:YES]; + return; + } + + if (localMoveType == RAIL_WMSZ_BOTTOMLEFT) { + // bottom left border resize taking place + int diff = (int) (loc.x - savedDragLocation.x); + if (diff != 0) { + if (diff < 0) { + diff = abs(diff); + winFrame.origin.x -= diff; + winFrame.size.width += diff; + } + else { + winFrame.origin.x += diff; + winFrame.size.width -= diff; + } + } + + diff = (int) (loc.y - savedDragLocation.y); + if (diff != 0) { + if (diff < 0) { + diff = abs(diff); + winFrame.origin.y -= diff; + winFrame.size.height += diff; + } + else { + winFrame.origin.y += diff; + winFrame.size.height -= diff; + } + } + + [[self window] setFrame:winFrame display:YES]; + return; + } + + if (localMoveType == RAIL_WMSZ_BOTTOMRIGHT) { + // bottom right border resize taking place + int diff = (int) (loc.x - savedDragLocation.x); + if (diff != 0) { + savedDragLocation.x = loc.x; + //savedDragLocation.y = loc.y; + winFrame.size.width += diff; + } + + diff = (int) (loc.y - savedDragLocation.y); + if (diff != 0) { + if (diff < 0) { + diff = abs(diff); + winFrame.origin.y -= diff; + winFrame.size.height += diff; + } + else { + winFrame.origin.y += diff; + winFrame.size.height -= diff; + } + } + + [[self window] setFrame:winFrame display:YES]; + return; + } + + x = (int) (winFrame.origin.x + loc.x); + y = (int) (winFrame.origin.y + loc.y); + y = height - y; + + // send mouse motion event to RDP server + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); +} + +// RAIL_TODO delete this +- (void) __mouseDragged:(NSEvent *)event +{ + [super mouseDragged:event]; + NSPoint loc = [event locationInWindow]; int x = (int) loc.x; int y = (int) loc.y; diff --git a/client/Mac/Mac/MRDPView.m b/client/Mac/Mac/MRDPView.m index 9e2f43fc7..f1801e701 100644 --- a/client/Mac/Mac/MRDPView.m +++ b/client/Mac/Mac/MRDPView.m @@ -18,14 +18,17 @@ * - all funcs same as above * - PolygonSc seems to create a transparent rect * - ensure mouse cursor changes are working ok after moving to NSTracking area + * - when we move the window to a 2nd monitor, display stops working * - RAIL: * - * - - * - tool tips to be correctly positioned - * - dragging is slightly of - * - resize after dragging not working + * - done - tool tips to be correctly positioned + * - done - dragging is slightly of + * - done - resize after dragging not working * - dragging app from macbook to monitor gives exec/access err * - unable to drag rect out of monitor boundaries + * - two finger scroll + * - moving scroll bar does a window resize instead of a scroll * - * - * - @@ -266,7 +269,7 @@ struct kkey g_keys[256] = // 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]; + [self addTrackingArea:trackingArea]; // windows in RemoteApp (RAIL) mode cannot have title bars NSArray * args = [[NSProcessInfo processInfo] arguments]; @@ -282,6 +285,8 @@ struct kkey g_keys[256] = [self addTrackingArea:trackingArea]; mouseInClientArea = YES; + + printScreenInfo(); } /** ********************************************************************* @@ -486,7 +491,9 @@ struct kkey g_keys[256] = int x = (int) loc.x; int y = (int) loc.y; - // RAIL_TODO delete this if not reqd +// RAIL_TODO delete this if not reqd +#if 0 + if ((isRemoteApp) && (isMoveSizeInProgress)) { if (saveInitialDragLoc) { saveInitialDragLoc = NO; @@ -503,7 +510,8 @@ struct kkey g_keys[256] = r.origin.y += newY; [[g_mrdpview window] setFrame:r display:YES]; } - +#endif + y = height - y; // send mouse motion event to RDP server @@ -936,35 +944,6 @@ struct kkey g_keys[256] = // RAIL_TODO is this func required - (void) windowDidResize:(NSNotification *) notification { - RAIL_WINDOW_MOVE_ORDER windowMove; - - printf("RAIL_TODO: MRDPView: windowDidResize() - not yet implemented\n"); - - return; - - // window resize valid only in RemoteApp mode - if (!g_mrdpview->isRemoteApp) - return; - - // window has resized, let server know - - NSRect r = [[g_mrdpview window] frame]; - printf("----- LK_TODO: MRDPView:windowDidResize (%d,%d %dx%d)\n", - (int) r.origin.x, (int) r.origin.y, - (int) r.size.width, (int) r.size.height); - - - windowMove.windowId = [currentWindow windowID]; - - windowMove.left = (uint16) r.origin.x; // x-cordinate of top left corner - windowMove.right = (uint16) (windowMove.left + r.size.width); // x-cordinate of bottom right corner - windowMove.top = (uint16) r.origin.y; // y-cordinate of top left corner - windowMove.bottom = (uint16) (windowMove.top + r.size.height); // y-cordinate of bottom right corner - - printf("----- LK_TODO: MRDPView:windowDidResize windowID=%d left=%d top=%d right=%d bottom=x%d width=%f height=%f\n", - [currentWindow windowID], windowMove.left, windowMove.top, windowMove.right, windowMove.bottom, r.size.width, r.size.height); - - //mac_send_rail_client_event(g_mrdpview->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); } /************************************************************************ @@ -1122,7 +1101,7 @@ boolean mac_pre_connect(freerdp *inst) g_mrdpview->argv[i++] = cptr; cptr = (char *)malloc(80); - strcpy(cptr, "lk"); + strcpy(cptr, "jay"); g_mrdpview->argv[i++] = cptr; cptr = (char *)malloc(80); @@ -1130,7 +1109,7 @@ boolean mac_pre_connect(freerdp *inst) g_mrdpview->argv[i++] = cptr; cptr = (char *)malloc(80); - strcpy(cptr, "abc@@@123"); + strcpy(cptr, "tucker"); g_mrdpview->argv[i++] = cptr; #if 1 @@ -1162,7 +1141,11 @@ boolean mac_pre_connect(freerdp *inst) #endif cptr = (char *)malloc(80); - strcpy(cptr, "192.168.1.69:45990"); +#if 0 + strcpy(cptr, "mousey.homeip.net:45990"); +#else + strcpy(cptr, "192.168.168.227"); +#endif g_mrdpview->argv[i++] = cptr; g_mrdpview->argc = i; @@ -1937,6 +1920,9 @@ void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window) if ((window->extendedStyle & WS_EX_TOPMOST) || (window->extendedStyle & WS_EX_TOOLWINDOW)) { [g_mrdpview->currentWindow view]->skipMoveWindowOnce = TRUE; moveWindow = YES; + + // convert from windows to Mac cords + window->windowOffsetY = g_mrdpview->height - window->windowOffsetY - window->windowHeight; } else if (window->style & WS_POPUP) { centerWindow = YES; @@ -2171,39 +2157,38 @@ void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event) { RAIL_LOCALMOVESIZE_ORDER * moveSize = (RAIL_LOCALMOVESIZE_ORDER *) event->user_data; - RAIL_WINDOW_MOVE_ORDER windowMove; switch (moveSize->moveSizeType) { case RAIL_WMSZ_LEFT: - printf("!!!! RAIL_WMSZ_LEFT\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_LEFT; break; case RAIL_WMSZ_RIGHT: - printf("!!!! RAIL_WMSZ_RIGHT\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_RIGHT; break; case RAIL_WMSZ_TOP: - printf("!!!! RAIL_WMSZ_TOP\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_TOP; break; case RAIL_WMSZ_TOPLEFT: - printf("!!!! RAIL_WMSZ_TOPLEFT\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_TOPLEFT; break; case RAIL_WMSZ_TOPRIGHT: - printf("!!!! RAIL_WMSZ_TOPRIGHT\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_TOPRIGHT; break; case RAIL_WMSZ_BOTTOM: - printf("!!!! RAIL_WMSZ_BOTTOM\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_BOTTOM; break; case RAIL_WMSZ_BOTTOMLEFT: - printf("!!!! RAIL_WMSZ_BOTTOMLEFT\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_BOTTOMLEFT; break; case RAIL_WMSZ_BOTTOMRIGHT: - printf("!!!! RAIL_WMSZ_BOTTOMRIGHT\n"); + [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_BOTTOMRIGHT; break; case RAIL_WMSZ_MOVE: @@ -2220,13 +2205,12 @@ void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event [g_mrdpview->currentWindow view]->saveInitialDragLoc = NO; //NSRect rect = [[g_mrdpview->currentWindow view] frame]; - NSRect rect = [[[g_mrdpview->currentWindow view] window] frame]; + NSRect r = [[[g_mrdpview->currentWindow view] window] frame]; // let RDP server know where this window is located + RAIL_WINDOW_MOVE_ORDER windowMove; + apple_to_windowMove(&r, &windowMove); mac_send_rail_client_event(inst->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); - - // the event we just sent will cause an extra MoveWindow() to be invoked which we need to ignore - [g_mrdpview->currentWindow view]->skipMoveWindowOnce = YES; break; @@ -2311,4 +2295,20 @@ void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove) windowMove->bottom = (uint16) (windowMove->top + r->size.height); // y-cord of bottom right corner } +void printScreenInfo() +{ + + int count = [[NSScreen screens] count]; + + for (int i = 0; i< count; i++) + { + NSRect r = [[[NSScreen screens] objectAtIndex:i] frame]; + + printf("screen %d: rect(%d,%d %dx%d)\n", + i, (int) r.origin.x, (int) r.origin.y, + (int) r.size.width, (int) r.size.height); + } + printf("\n"); +} + @end From 41f615e849b45416bedde18d6d418e6ad841135e Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Sat, 23 Jun 2012 18:26:44 -0700 Subject: [PATCH 09/27] Fixed following issues in RAIL mode + two finger scrolling + after a resize operation, scrolling causes window resize instead of scrolling + unable to drag rectangle out of monitor boundaries + dragging rail app to secondary monitor was causing Exec access error --- client/Mac/MRDPRailView.h | 2 + client/Mac/MRDPRailView.m | 182 +++++--------------------------------- client/Mac/Mac/MRDPView.m | 141 ++++------------------------- 3 files changed, 41 insertions(+), 284 deletions(-) diff --git a/client/Mac/MRDPRailView.h b/client/Mac/MRDPRailView.h index 179f82c7e..17a7cf4a4 100644 --- a/client/Mac/MRDPRailView.h +++ b/client/Mac/MRDPRailView.h @@ -44,6 +44,8 @@ void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window); void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove); void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param); +void windows_to_apple_cords(NSRect * r); +void rail_MoveWindow(rdpRail * rail, rdpWindow * window); @end diff --git a/client/Mac/MRDPRailView.m b/client/Mac/MRDPRailView.m index 29dfdb6b0..f4409006e 100644 --- a/client/Mac/MRDPRailView.m +++ b/client/Mac/MRDPRailView.m @@ -17,8 +17,6 @@ extern struct kkey g_keys[]; - (void) updateDisplay { boolean moveWindow = NO; - int i; - NSRect drawRect; NSRect srcRectOuter; NSRect destRectOuter; @@ -37,7 +35,7 @@ extern struct kkey g_keys[]; srcRectOuter = NSMakeRect(0, 0, self->width, self->height); destRectOuter = [[self window] frame]; - + // cannot be bigger than our current screen size NSRect screenSize = [[NSScreen mainScreen] frame]; if (destRectOuter.size.width > screenSize.size.width) { @@ -45,22 +43,13 @@ extern struct kkey g_keys[]; moveWindow = YES; } - // RAIL_TODO do not hardcode to 22 if (destRectOuter.size.height > screenSize.size.height) { destRectOuter.size.height = screenSize.size.height; moveWindow = YES; } - // cannot have negative cords - if (destRectOuter.origin.x < 0) { - destRectOuter.origin.x = 0; - moveWindow = YES; - } - - if (destRectOuter.origin.y < 0) { - destRectOuter.origin.y = 0; - moveWindow = YES; - } + if (destRectOuter.origin.x + destRectOuter.size.width > width) + destRectOuter.size.width = width - destRectOuter.origin.x; [self setupBmiRep:destRectOuter.size.width :destRectOuter.size.height]; @@ -72,41 +61,16 @@ extern struct kkey g_keys[]; //skipMoveWindowOnce = TRUE; //mac_send_rail_client_event(g_mrdpRailView->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &newWndLoc); } - - //printf("MRDPRailView : updateDisplay : drawing %d rectangles\n", gdi->primary->hdc->hwnd->ninvalid); - // if src and dest rect are not the same size, copy the entire - // rectangle in one go instead of in many small rectangles + destRectOuter.origin.y = height - destRectOuter.origin.y - destRectOuter.size.height; + rail_convert_color_space(pixelData, (char *) gdi->primary_buffer, + &destRectOuter, self->width, self->height); - //if (destRectOuter.size.width != self->width) { - if (1) { - destRectOuter.origin.y = height - destRectOuter.origin.y - destRectOuter.size.height; - rail_convert_color_space1(pixelData, (char *) gdi->primary_buffer, - &destRectOuter, self->width, self->height); - - if (moveWindow) - [self setNeedsDisplayInRect:destRectOuter]; - else - [self setNeedsDisplayInRect:[self frame]]; + if (moveWindow) + [self setNeedsDisplayInRect:destRectOuter]; + else + [self setNeedsDisplayInRect:[self frame]]; - gdi->primary->hdc->hwnd->ninvalid = 0; - - return; - } - - for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++) - { - drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x; - drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y; - drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w; - drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h; - - rail_convert_color_space(pixelData, (char *) gdi->primary_buffer, - &drawRect, &destRectOuter, - &drawRect, &srcRectOuter); - - [self setNeedsDisplayInRect:drawRect]; - } gdi->primary->hdc->hwnd->ninvalid = 0; } @@ -282,22 +246,23 @@ extern struct kkey g_keys[]; uint16 flags; [super scrollWheel:event]; - + NSRect winFrame = [[self window] frame]; NSPoint loc = [event locationInWindow]; int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); y = height - y; - + flags = PTR_FLAGS_WHEEL; - if ([event deltaY] < 0) { + if ([event scrollingDeltaY] < 0) { flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; } else { flags |= 0x0078; } - x += (int) [event deltaX]; - y += (int) [event deltaY]; + x += (int) [event scrollingDeltaX]; + y += (int) [event scrollingDeltaY]; + rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); } @@ -308,7 +273,7 @@ extern struct kkey g_keys[]; - (void) mouseDragged:(NSEvent *)event { [super mouseDragged:event]; - + NSRect winFrame = [[self window] frame]; NSPoint loc = [event locationInWindow]; int x = (int) loc.x; @@ -324,9 +289,8 @@ extern struct kkey g_keys[]; winFrame.origin.x += newX; winFrame.origin.y += newY; - - [[self window] setFrame:winFrame display:YES]; + [[self window] setFrame:winFrame display:YES]; return; } @@ -508,43 +472,6 @@ extern struct kkey g_keys[]; rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); } -// RAIL_TODO delete this -- (void) __mouseDragged:(NSEvent *)event -{ - [super mouseDragged:event]; - - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - if (isMoveSizeInProgress) { - if (saveInitialDragLoc) { - saveInitialDragLoc = NO; - savedDragLocation.x = x; - savedDragLocation.y = y; - return; - } - - int newX = x - savedDragLocation.x; - int newY = y - savedDragLocation.y; - - NSRect r = [[self window] frame]; - r.origin.x += newX; - r.origin.y += newY; - [[self window] setFrame:r display:YES]; - - return; - } - - NSRect winFrame = [[self window] frame]; - x = (int) (winFrame.origin.x + loc.x); - y = (int) (winFrame.origin.y + loc.y); - y = height - y; - - // send mouse motion event to RDP server - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); -} - /** ********************************************************************* * called when a key is pressed ***********************************************************************/ @@ -738,71 +665,7 @@ void rail_cvt_from_rect(char *dest, char *src, NSRect destRect, int destWidth, i /** ********************************************************************* * color space conversion used specifically in RAIL ***********************************************************************/ - -int rail_convert_color_space(char * destBuf, char * srcBuf, - NSRect * destRect, NSRect * destRectOuter, - NSRect * srcRect, NSRect * srcRectOuter) -{ - int i; - int j; - int numRows; - int srcX; - int srcY; - int destX; - int destY; - int pixelsPerRow; - int pixel; - int pixel1; - int pixel2; - int * src32; - int * dest32; - - int destWidth = destRectOuter->size.width; - int destHeight = destRectOuter->size.height; - int srcWidth = srcRectOuter->size.width; - int srcHeight = srcRectOuter->size.height; - - if ((!destBuf) || (!srcBuf)) { - return 1; - } - - if ((destRect->size.width != srcRect->size.width) || (destRect->size.height != srcRect->size.height)) { - printf("##### RAIL_TODO: rail_convert_color_space : destRect & srcRect dimensions don't match\n"); - return 1; - } - - numRows = srcRect->size.height; - srcX = srcRect->origin.x; - srcY = srcRect->origin.y; - destX = destRect->origin.x; - destY = destRect->origin.y; - pixelsPerRow = destRect->size.width; - - for (i = 0; i < numRows; i++) - { - src32 = (int *) (srcBuf + ((srcY + i) * srcWidth + srcX) * 4); - dest32 = (int *) (destBuf + ((destY + i) * destWidth + destX) * 4); - - for (j = 0; j < pixelsPerRow; j++) - { - pixel = *src32; - pixel1 = (pixel & 0x00ff0000) >> 16; - pixel2 = (pixel & 0x000000ff) << 16; - pixel = (pixel & 0xff00ff00) | pixel1 | pixel2; - - *dest32 = pixel; - src32++; - dest32++; - } - } - - destRect->origin.y = destHeight - destRect->origin.y - destRect->size.height; - - return 0; -} - -// RAIL_TODO rename this func -void rail_convert_color_space1(char *destBuf, char * srcBuf, +void rail_convert_color_space(char *destBuf, char * srcBuf, NSRect * destRect, int width, int height) { int i; @@ -825,13 +688,14 @@ void rail_convert_color_space1(char *destBuf, char * srcBuf, if ((!destBuf) || (!srcBuf)) { return; } - - numRows = destHeight; + + numRows = (destRect->origin.y + destHeight > height) ? height - destRect->origin.y : destHeight; + pixelsPerRow = destWidth; + srcX = destRect->origin.x; srcY = destRect->origin.y; destX = 0; destY = 0; - pixelsPerRow = destWidth; for (i = 0; i < numRows; i++) { diff --git a/client/Mac/Mac/MRDPView.m b/client/Mac/Mac/MRDPView.m index f1801e701..c86a7d92a 100644 --- a/client/Mac/Mac/MRDPView.m +++ b/client/Mac/Mac/MRDPView.m @@ -21,14 +21,10 @@ * - when we move the window to a 2nd monitor, display stops working * - RAIL: * - - * - - * - done - tool tips to be correctly positioned - * - done - dragging is slightly of - * - done - resize after dragging not working * - dragging app from macbook to monitor gives exec/access err * - unable to drag rect out of monitor boundaries * - two finger scroll - * - moving scroll bar does a window resize instead of a scroll + * - done - moving scroll bar does a window resize instead of a scroll * - * - * - @@ -39,12 +35,6 @@ #define RUN_IN_XCODE -// LK_TODO -#define GOT_HERE //printf("### got here: %s : %s() : %d\n", __FILE__, __func__, __LINE__) - -// RAIL_TODO DELETE WHEN DONE TESTING -#define MRDP_DRAW_INDIVIDUAL_RECTS - @implementation MRDPView MRDPView *g_mrdpview; @@ -285,7 +275,7 @@ struct kkey g_keys[256] = [self addTrackingArea:trackingArea]; mouseInClientArea = YES; - + [self setAcceptsTouchEvents:YES]; printScreenInfo(); } @@ -490,28 +480,7 @@ struct kkey g_keys[256] = NSPoint loc = [event locationInWindow]; int x = (int) loc.x; int y = (int) loc.y; - -// RAIL_TODO delete this if not reqd -#if 0 - - if ((isRemoteApp) && (isMoveSizeInProgress)) { - if (saveInitialDragLoc) { - saveInitialDragLoc = NO; - savedDragLocation.x = x; - savedDragLocation.y = y; - return; - } - - int newX = x - savedDragLocation.x; - int newY = y - savedDragLocation.y; - - NSRect r = [[self window] frame]; - r.origin.x += newX; - r.origin.y += newY; - [[g_mrdpview window] setFrame:r display:YES]; - } -#endif - + y = height - y; // send mouse motion event to RDP server @@ -734,63 +703,6 @@ struct kkey g_keys[256] = instance methods ************************************************************************/ -/** ********************************************************************* - * called when RDP server wants us to update a rect with new data - ***********************************************************************/ - -- (void) my_draw_rect:(void *)context -{ - int w; - int h; - - rdpContext * ctx = (rdpContext *) context; - - struct rgba_data - { - char red; - char green; - char blue; - char alpha; - }; - - if (isRemoteApp && currentWindow) { - NSRect vrect = [ [currentWindow view] frame]; - [[currentWindow view] setNeedsDisplayInRect:vrect]; - // actual drawing will be done in MRDPRailView:drawRect() - return; - } - - w = width; - h = height; - rect.origin.x = 0; - rect.origin.y = 0; - rect.size.width = w; - rect.size.height = h; - - if (!bmiRep) { - pixel_data = (char *) malloc(w * h * sizeof(struct rgba_data)); - bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixel_data - pixelsWide:w - pixelsHigh:h - bitsPerSample:8 - samplesPerPixel:sizeof(struct rgba_data) - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 //NSAlphaFirstBitmapFormat - bytesPerRow:w * sizeof(struct rgba_data) - bitsPerPixel:0]; - } - -#ifdef MRDP_DRAW_INDIVIDUAL_RECTS - [self setNeedsDisplayInRect:rect]; - return; -#endif - - convert_color_space(pixel_data, (char *) ctx->gdi->primary_buffer, &rect, w, h); - [self setNeedsDisplayInRect:rect]; -} - /** ********************************************************************* * save state info for use by other methods later on ***********************************************************************/ @@ -941,7 +853,6 @@ struct kkey g_keys[256] = [[g_mrdpview window] orderOut:g_mrdpview]; } -// RAIL_TODO is this func required - (void) windowDidResize:(NSNotification *) notification { } @@ -1101,7 +1012,7 @@ boolean mac_pre_connect(freerdp *inst) g_mrdpview->argv[i++] = cptr; cptr = (char *)malloc(80); - strcpy(cptr, "jay"); + strcpy(cptr, "lk"); g_mrdpview->argv[i++] = cptr; cptr = (char *)malloc(80); @@ -1109,7 +1020,7 @@ boolean mac_pre_connect(freerdp *inst) g_mrdpview->argv[i++] = cptr; cptr = (char *)malloc(80); - strcpy(cptr, "tucker"); + strcpy(cptr, "abc@@@123"); g_mrdpview->argv[i++] = cptr; #if 1 @@ -1141,7 +1052,7 @@ boolean mac_pre_connect(freerdp *inst) #endif cptr = (char *)malloc(80); -#if 0 +#if 1 strcpy(cptr, "mousey.homeip.net:45990"); #else strcpy(cptr, "192.168.168.227"); @@ -1530,8 +1441,6 @@ void channel_activity_cb( freerdp *inst = (freerdp *) info; RDP_EVENT* event; - GOT_HERE; - freerdp_channels_check_fds(inst->context->channels, inst); event = freerdp_channels_pop_event(inst->context->channels); if (event) { @@ -1886,12 +1795,10 @@ void mac_process_rail_event(freerdp *inst, RDP_EVENT *event) break; case RDP_EVENT_TYPE_RAIL_CHANNEL_APPID_RESP: - GOT_HERE; //xf_process_rail_appid_resp_event(xfi, channels, event); break; case RDP_EVENT_TYPE_RAIL_CHANNEL_LANGBARINFO: - GOT_HERE; //xf_process_rail_langbarinfo_event(xfi, channels, event); break; } @@ -1985,9 +1892,9 @@ void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window) } else { [newWindow makeKeyAndOrderFront:NSApp]; - [[g_mrdpview window] resignFirstResponder]; - [g_mrdpview resignFirstResponder]; - [[g_mrdpview window] setNextResponder:newWindow]; + //[[g_mrdpview window] resignFirstResponder]; + //[g_mrdpview resignFirstResponder]; + //[[g_mrdpview window] setNextResponder:newWindow]; } return; @@ -2044,7 +1951,6 @@ void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window) } else { g_mrdpview->currentWindow = nil; - // RAIL_TODO [[g_mrdpview window] makeKeyAndOrderFront:[g_mrdpview window]]; [NSApp terminate:nil]; } return; @@ -2054,8 +1960,6 @@ void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window) void mac_rail_register_callbacks(freerdp *inst, rdpRail *rail) { - GOT_HERE; - rail->extra = (void *) inst; rail->rail_CreateWindow = mac_rail_CreateWindow; rail->rail_MoveWindow = mac_rail_MoveWindow; @@ -2096,8 +2000,6 @@ void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* ev { RAIL_SYSPARAM_ORDER* sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data; - GOT_HERE; - switch (sysparam->param) { case SPI_SET_SCREEN_SAVE_ACTIVE: @@ -2116,8 +2018,6 @@ void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event) { RAIL_EXEC_RESULT_ORDER* exec_result; - GOT_HERE; - exec_result = (RAIL_EXEC_RESULT_ORDER*) event->user_data; if (exec_result->execResult != RAIL_EXEC_S_OK) { @@ -2139,13 +2039,7 @@ void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event) void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event) { - RAIL_MINMAXINFO_ORDER * minmax = (RAIL_MINMAXINFO_ORDER*) event->user_data; - -#if 0 - printf("minmax_info: maxPosX=%d maxPosY=%d maxWidth=%d maxHeight=%d minTrackWidth=%d minTrackHeight=%d maxTrackWidth=%d maxTrackHeight=%d\n", - minmax->maxPosX, minmax->maxPosY, minmax->maxWidth, minmax->maxHeight, - minmax->minTrackWidth, minmax->minTrackHeight, minmax->maxTrackWidth, minmax->maxTrackHeight); -#endif + //RAIL_MINMAXINFO_ORDER * minmax = (RAIL_MINMAXINFO_ORDER*) event->user_data; } /** ********************************************************************* @@ -2157,7 +2051,7 @@ void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event) { RAIL_LOCALMOVESIZE_ORDER * moveSize = (RAIL_LOCALMOVESIZE_ORDER *) event->user_data; - + switch (moveSize->moveSizeType) { case RAIL_WMSZ_LEFT: [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_LEFT; @@ -2204,9 +2098,8 @@ void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event [g_mrdpview->currentWindow view]->isMoveSizeInProgress = NO; [g_mrdpview->currentWindow view]->saveInitialDragLoc = NO; - //NSRect rect = [[g_mrdpview->currentWindow view] frame]; NSRect r = [[[g_mrdpview->currentWindow view] window] frame]; - + // let RDP server know where this window is located RAIL_WINDOW_MOVE_ORDER windowMove; apple_to_windowMove(&r, &windowMove); @@ -2225,6 +2118,10 @@ void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event default: break; } + + if (moveSize->isMoveSizeStart == 0) + [g_mrdpview->currentWindow view]->localMoveType = 0; + return; } @@ -2233,8 +2130,6 @@ void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void * RDP_EVENT *out_event = NULL; void *payload = NULL; - GOT_HERE; - payload = rail_clone_order(event_type, param); if (payload != NULL) { out_event = freerdp_event_new(RDP_EVENT_CLASS_RAIL, event_type, @@ -2245,8 +2140,6 @@ void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void * void mac_on_free_rail_client_event(RDP_EVENT* event) { - GOT_HERE; - if (event->event_class == RDP_EVENT_CLASS_RAIL) { rail_free_cloned_order(event->event_type, event->user_data); @@ -2255,8 +2148,6 @@ void mac_on_free_rail_client_event(RDP_EVENT* event) void mac_rail_enable_remoteapp_mode() { - GOT_HERE; - if (!g_mrdpview->isRemoteApp) g_mrdpview->isRemoteApp = TRUE; } From a76b6087c11bfa4e2b3152b4fcd37255973c87ce Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Sat, 23 Jun 2012 18:42:15 -0700 Subject: [PATCH 10/27] updated TODO list --- client/Mac/Mac/MRDPView.m | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/client/Mac/Mac/MRDPView.m b/client/Mac/Mac/MRDPView.m index c86a7d92a..0dad2c488 100644 --- a/client/Mac/Mac/MRDPView.m +++ b/client/Mac/Mac/MRDPView.m @@ -12,22 +12,6 @@ * + 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 - * - when we move the window to a 2nd monitor, display stops working - * - RAIL: - * - - * - dragging app from macbook to monitor gives exec/access err - * - unable to drag rect out of monitor boundaries - * - two finger scroll - * - done - moving scroll bar does a window resize instead of a scroll - * - - * - - * - */ #import "MRDPView.h" @@ -1020,7 +1004,7 @@ boolean mac_pre_connect(freerdp *inst) g_mrdpview->argv[i++] = cptr; cptr = (char *)malloc(80); - strcpy(cptr, "abc@@@123"); + strcpy(cptr, "lk"); g_mrdpview->argv[i++] = cptr; #if 1 @@ -1052,11 +1036,8 @@ boolean mac_pre_connect(freerdp *inst) #endif cptr = (char *)malloc(80); -#if 1 - strcpy(cptr, "mousey.homeip.net:45990"); -#else - strcpy(cptr, "192.168.168.227"); -#endif + strcpy(cptr, "192.168.1.69:45990"); + g_mrdpview->argv[i++] = cptr; g_mrdpview->argc = i; From 418ac24764f238d6ff6f8c4170f07dfaeca23d7a Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Tue, 26 Jun 2012 15:17:01 -0700 Subject: [PATCH 11/27] Mac: test commit, EOL white space removal --- client/Mac/MRDPRailView.m | 165 +++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 83 deletions(-) diff --git a/client/Mac/MRDPRailView.m b/client/Mac/MRDPRailView.m index f4409006e..7b69cf1e5 100644 --- a/client/Mac/MRDPRailView.m +++ b/client/Mac/MRDPRailView.m @@ -19,20 +19,20 @@ extern struct kkey g_keys[]; boolean moveWindow = NO; NSRect srcRectOuter; NSRect destRectOuter; - + rdpGdi * gdi; - + if ((context == 0) || (context->gdi == 0)) return; - + if (context->gdi->primary->hdc->hwnd->invalid->null) return; - + if (context->gdi->drawing != context->gdi->primary) return; - + gdi = context->gdi; - + srcRectOuter = NSMakeRect(0, 0, self->width, self->height); destRectOuter = [[self window] frame]; @@ -42,15 +42,15 @@ extern struct kkey g_keys[]; destRectOuter.size.width = screenSize.size.width; moveWindow = YES; } - + if (destRectOuter.size.height > screenSize.size.height) { destRectOuter.size.height = screenSize.size.height; - moveWindow = YES; + moveWindow = YES; } - + if (destRectOuter.origin.x + destRectOuter.size.width > width) destRectOuter.size.width = width - destRectOuter.origin.x; - + [self setupBmiRep:destRectOuter.size.width :destRectOuter.size.height]; if (moveWindow) { @@ -61,12 +61,12 @@ extern struct kkey g_keys[]; //skipMoveWindowOnce = TRUE; //mac_send_rail_client_event(g_mrdpRailView->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &newWndLoc); } - + destRectOuter.origin.y = height - destRectOuter.origin.y - destRectOuter.size.height; - rail_convert_color_space(pixelData, (char *) gdi->primary_buffer, + rail_convert_color_space(pixelData, (char *) gdi->primary_buffer, &destRectOuter, self->width, self->height); - - if (moveWindow) + + if (moveWindow) [self setNeedsDisplayInRect:destRectOuter]; else [self setNeedsDisplayInRect:[self frame]]; @@ -81,7 +81,7 @@ extern struct kkey g_keys[]; - (void) drawRect:(NSRect)dirtyRect { [bmiRep drawInRect:dirtyRect fromRect:dirtyRect operation:NSCompositeCopy fraction:1.0 respectFlipped:NO hints:nil]; - + if (pixelData) { free(pixelData); pixelData = NULL; @@ -93,19 +93,19 @@ extern struct kkey g_keys[]; * become first responder so we can get keyboard and mouse events ***********************************************************************/ -- (BOOL)acceptsFirstResponder -{ - return YES; +- (BOOL)acceptsFirstResponder +{ + return YES; } /** ********************************************************************* * called when a mouse move event occurrs - * + * * 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 - * versions, we do this manually. + * versions, we do this manually. * * 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 @@ -114,15 +114,15 @@ extern struct kkey g_keys[]; - (void) mouseMoved:(NSEvent *)event { [super mouseMoved:event]; - + NSRect winFrame = [[self window] frame]; NSPoint loc = [event locationInWindow]; - + int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); - + y = height - y; - + // send mouse motion event to RDP server rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); } @@ -146,12 +146,12 @@ extern struct kkey g_keys[]; if ((yPos >= 4) && (yPos <= 20)) titleBarClicked = YES; - else + else titleBarClicked = NO; - + savedDragLocation.x = loc.x; savedDragLocation.y = loc.y; - + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); } @@ -168,7 +168,7 @@ extern struct kkey g_keys[]; int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); y = height - y; - + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); titleBarClicked = NO; } @@ -203,7 +203,7 @@ extern struct kkey g_keys[]; int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); y = height - y; - + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON2, x, y); } @@ -237,22 +237,22 @@ extern struct kkey g_keys[]; int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); y = height - y; - + rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON3, x, y); } - (void) scrollWheel:(NSEvent *)event { uint16 flags; - + [super scrollWheel:event]; - + NSRect winFrame = [[self window] frame]; NSPoint loc = [event locationInWindow]; int x = (int) (winFrame.origin.x + loc.x); int y = (int) (winFrame.origin.y + loc.y); y = height - y; - + flags = PTR_FLAGS_WHEEL; if ([event scrollingDeltaY] < 0) { flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; @@ -262,7 +262,7 @@ extern struct kkey g_keys[]; } x += (int) [event scrollingDeltaX]; y += (int) [event scrollingDeltaY]; - + rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); } @@ -273,7 +273,7 @@ extern struct kkey g_keys[]; - (void) mouseDragged:(NSEvent *)event { [super mouseDragged:event]; - + NSRect winFrame = [[self window] frame]; NSPoint loc = [event locationInWindow]; int x = (int) loc.x; @@ -283,13 +283,13 @@ extern struct kkey g_keys[]; // window is being dragged to a new location int newX = x - savedDragLocation.x; int newY = y - savedDragLocation.y; - + if ((newX == 0) && (newY == 0)) return; - + winFrame.origin.x += newX; winFrame.origin.y += newY; - + [[self window] setFrame:winFrame display:YES]; return; } @@ -299,7 +299,7 @@ extern struct kkey g_keys[]; int diff = (int) (loc.x - savedDragLocation.x); if (diff == 0) return; - + if (diff < 0) { diff = abs(diff); winFrame.origin.x -= diff; @@ -309,7 +309,7 @@ extern struct kkey g_keys[]; winFrame.origin.x += diff; winFrame.size.width -= diff; } - + [[self window] setFrame:winFrame display:YES]; return; } @@ -319,10 +319,10 @@ extern struct kkey g_keys[]; int diff = (int) (loc.x - savedDragLocation.x); if (diff == 0) return; - + savedDragLocation.x = loc.x; savedDragLocation.y = loc.y; - + winFrame.size.width += diff; [[self window] setFrame:winFrame display:YES]; return; @@ -333,21 +333,21 @@ extern struct kkey g_keys[]; int diff = (int) (loc.y - savedDragLocation.y); if (diff == 0) return; - + savedDragLocation.x = loc.x; savedDragLocation.y = loc.y; - + winFrame.size.height += diff; [[self window] setFrame:winFrame display:YES]; return; } - + if (localMoveType == RAIL_WMSZ_BOTTOM) { // bottom border resize taking place int diff = (int) (loc.y - savedDragLocation.y); if (diff == 0) return; - + if (diff < 0) { diff = abs(diff); winFrame.origin.y -= diff; @@ -357,11 +357,11 @@ extern struct kkey g_keys[]; winFrame.origin.y += diff; winFrame.size.height -= diff; } - + [[self window] setFrame:winFrame display:YES]; return; } - + if (localMoveType == RAIL_WMSZ_TOPLEFT) { // top left border resize taking place int diff = (int) (loc.x - savedDragLocation.x); @@ -382,7 +382,7 @@ extern struct kkey g_keys[]; savedDragLocation.y = loc.y; winFrame.size.height += diff; } - + [[self window] setFrame:winFrame display:YES]; return; } @@ -393,7 +393,7 @@ extern struct kkey g_keys[]; if (diff != 0) { winFrame.size.width += diff; } - + diff = (int) (loc.y - savedDragLocation.y); if (diff != 0) { winFrame.size.height += diff; @@ -405,7 +405,7 @@ extern struct kkey g_keys[]; [[self window] setFrame:winFrame display:YES]; return; } - + if (localMoveType == RAIL_WMSZ_BOTTOMLEFT) { // bottom left border resize taking place int diff = (int) (loc.x - savedDragLocation.x); @@ -420,7 +420,7 @@ extern struct kkey g_keys[]; winFrame.size.width -= diff; } } - + diff = (int) (loc.y - savedDragLocation.y); if (diff != 0) { if (diff < 0) { @@ -433,11 +433,11 @@ extern struct kkey g_keys[]; winFrame.size.height -= diff; } } - + [[self window] setFrame:winFrame display:YES]; return; } - + if (localMoveType == RAIL_WMSZ_BOTTOMRIGHT) { // bottom right border resize taking place int diff = (int) (loc.x - savedDragLocation.x); @@ -446,7 +446,7 @@ extern struct kkey g_keys[]; //savedDragLocation.y = loc.y; winFrame.size.width += diff; } - + diff = (int) (loc.y - savedDragLocation.y); if (diff != 0) { if (diff < 0) { @@ -459,15 +459,15 @@ extern struct kkey g_keys[]; winFrame.size.height -= diff; } } - + [[self window] setFrame:winFrame display:YES]; return; } - + x = (int) (winFrame.origin.x + loc.x); y = (int) (winFrame.origin.y + loc.y); y = height - y; - + // send mouse motion event to RDP server rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); } @@ -479,7 +479,7 @@ extern struct kkey g_keys[]; - (void) keyDown:(NSEvent *) event { int key; - + key = [event keyCode]; rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_DOWN, g_keys[key].key_code); } @@ -503,7 +503,7 @@ extern struct kkey g_keys[]; - (void) flagsChanged:(NSEvent *) event { NSUInteger mf = [event modifierFlags]; - + // caps lock if (mf == 0x10100) { printf("TODO: caps lock is on\n"); @@ -524,7 +524,7 @@ extern struct kkey g_keys[]; rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x2a); kdlshift = 0; } - + // right shift if ((kdrshift == 0) && ((mf & 4) != 0)) { // right shift went down @@ -536,7 +536,7 @@ extern struct kkey g_keys[]; rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x36); kdrshift = 0; } - + // left ctrl if ((kdlctrl == 0) && ((mf & 1) != 0)) { // left ctrl went down @@ -548,7 +548,7 @@ extern struct kkey g_keys[]; rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x1d); kdlctrl = 0; } - + // right ctrl if ((kdrctrl == 0) && ((mf & 0x2000) != 0)) { // right ctrl went down @@ -560,7 +560,7 @@ extern struct kkey g_keys[]; rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x1d); kdrctrl = 0; } - + // left alt if ((kdlalt == 0) && ((mf & 0x20) != 0)) { // left alt went down @@ -572,7 +572,7 @@ extern struct kkey g_keys[]; rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x38); kdlalt = 0; } - + // right alt if ((kdralt == 0) && ((mf & 0x40) != 0)) { // right alt went down @@ -584,7 +584,7 @@ extern struct kkey g_keys[]; rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x38); kdralt = 0; } - + // left meta if ((kdlmeta == 0) && ((mf & 0x08) != 0)) { // left meta went down @@ -596,7 +596,7 @@ extern struct kkey g_keys[]; rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5b); kdlmeta = 0; } - + // right meta if ((kdrmeta == 0) && ((mf & 0x10) != 0)) { // right meta went down @@ -617,15 +617,15 @@ extern struct kkey g_keys[]; width = w; height = h; savedWindowId = windowID; - + NSRect tr = NSMakeRect(0, 0, - [[NSScreen mainScreen] frame].size.width, + [[NSScreen mainScreen] frame].size.width, [[NSScreen mainScreen] frame].size.height); - + NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:tr options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveAlways owner:self userInfo:nil]; - + [self addTrackingArea:trackingArea]; - + g_mrdpRailView = self; [self becomeFirstResponder]; @@ -640,10 +640,10 @@ extern struct kkey g_keys[]; char blue; char alpha; }; - + if (pixelData) free(pixelData); - + pixelData = (char *) malloc(frameWidth * frameHeight * sizeof(struct rgba_data)); bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixelData pixelsWide:frameWidth @@ -665,7 +665,7 @@ void rail_cvt_from_rect(char *dest, char *src, NSRect destRect, int destWidth, i /** ********************************************************************* * color space conversion used specifically in RAIL ***********************************************************************/ -void rail_convert_color_space(char *destBuf, char * srcBuf, +void rail_convert_color_space(char *destBuf, char * srcBuf, NSRect * destRect, int width, int height) { int i; @@ -681,10 +681,10 @@ void rail_convert_color_space(char *destBuf, char * srcBuf, int pixel2; int * src32; int * dest32; - + int destWidth = destRect->size.width; int destHeight = destRect->size.height; - + if ((!destBuf) || (!srcBuf)) { return; } @@ -696,12 +696,12 @@ void rail_convert_color_space(char *destBuf, char * srcBuf, srcY = destRect->origin.y; destX = 0; destY = 0; - + for (i = 0; i < numRows; i++) { src32 = (int *) (srcBuf + ((srcY + i) * width + srcX) * 4); dest32 = (int *) (destBuf + ((destY + i) * destWidth + destX) * 4); - + for (j = 0; j < pixelsPerRow; j++) { pixel = *src32; @@ -715,7 +715,7 @@ void rail_convert_color_space(char *destBuf, char * srcBuf, dest32++; } } - + destRect->origin.y = destHeight - destRect->origin.y - destRect->size.height; return; } @@ -729,12 +729,12 @@ void rail_MoveWindow(rdpRail * rail, rdpWindow * window) if (g_mrdpRailView->isMoveSizeInProgress) { return; } - + if (g_mrdpRailView->skipMoveWindowOnce) { g_mrdpRailView->skipMoveWindowOnce = NO; return; } - + // this rect is based on Windows co-ordinates... NSRect r; r.origin.x = window->windowOffsetX; @@ -747,4 +747,3 @@ void rail_MoveWindow(rdpRail * rail, rdpWindow * window) } @end - From 2d59cb4f269093b3c0bec7199037fa9b21ae30ae Mon Sep 17 00:00:00 2001 From: Jim Grandy Date: Tue, 26 Jun 2012 16:52:38 -0700 Subject: [PATCH 12/27] Pushing larger cache size for Jay's xrdp offscreen surface remoting technique --- libfreerdp-cache/offscreen.c | 2 +- libfreerdp-core/settings.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libfreerdp-cache/offscreen.c b/libfreerdp-cache/offscreen.c index c4eb018d6..190d72814 100644 --- a/libfreerdp-cache/offscreen.c +++ b/libfreerdp-cache/offscreen.c @@ -137,7 +137,7 @@ rdpOffscreenCache* offscreen_cache_new(rdpSettings* settings) offscreen_cache->currentSurface = SCREEN_BITMAP_SURFACE; offscreen_cache->maxSize = 7680; - offscreen_cache->maxEntries = 100; + offscreen_cache->maxEntries = 2000; settings->offscreen_bitmap_cache_size = offscreen_cache->maxSize; settings->offscreen_bitmap_cache_entries = offscreen_cache->maxEntries; diff --git a/libfreerdp-core/settings.c b/libfreerdp-core/settings.c index 306f86d1f..c822551ff 100644 --- a/libfreerdp-core/settings.c +++ b/libfreerdp-core/settings.c @@ -154,7 +154,7 @@ rdpSettings* settings_new(void* instance) settings->offscreen_bitmap_cache = true; settings->offscreen_bitmap_cache_size = 7680; - settings->offscreen_bitmap_cache_entries = 100; + settings->offscreen_bitmap_cache_entries = 2000; settings->draw_nine_grid_cache_size = 2560; settings->draw_nine_grid_cache_entries = 256; From cc2fdd6da2e621d88a5431bee02fc9be07d7d76a Mon Sep 17 00:00:00 2001 From: Jim Grandy Date: Tue, 26 Jun 2012 16:57:18 -0700 Subject: [PATCH 13/27] Pushing jpeg codec support, used in xrdp's offscreen surface remoting technique. Will likely be superceded by use of jpeg2000. --- client/X11/xf_graphics.c | 10 ++- include/freerdp/codec/jpeg.h | 28 +++++++ libfreerdp-cache/bitmap.c | 15 +++- libfreerdp-codec/CMakeLists.txt | 3 +- libfreerdp-codec/jpeg.c | 141 ++++++++++++++++++++++++++++++++ libfreerdp-core/capabilities.c | 1 + libfreerdp-gdi/graphics.c | 10 ++- 7 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 include/freerdp/codec/jpeg.h create mode 100644 libfreerdp-codec/jpeg.c diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index f88a29d18..ce9e028e6 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -25,6 +25,7 @@ #endif #include +#include #include "xf_graphics.h" @@ -116,7 +117,14 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed) + if (compressed == 2) + { + if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) + { + printf("jpeg Decompression Failed\n"); + } + } + else if (compressed) { boolean status; diff --git a/include/freerdp/codec/jpeg.h b/include/freerdp/codec/jpeg.h new file mode 100644 index 000000000..36540d922 --- /dev/null +++ b/include/freerdp/codec/jpeg.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Compressed Bitmap + * + * Copyright 2012 Jay Sorg + * + * 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. + */ + +#ifndef __JPEG_H +#define __JPEG_H + +#include + +boolean +jpeg_decompress(uint8* input, uint8* output, int width, int height, int size, int bpp); + +#endif /* __BITMAP_H */ diff --git a/libfreerdp-cache/bitmap.c b/libfreerdp-cache/bitmap.c index a382bfe0c..6d42d263d 100644 --- a/libfreerdp-cache/bitmap.c +++ b/libfreerdp-cache/bitmap.c @@ -102,9 +102,18 @@ void update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cach cache_bitmap_v2->bitmapBpp = context->instance->settings->color_depth; } - bitmap->Decompress(context, bitmap, - cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight, - cache_bitmap_v2->bitmapBpp, cache_bitmap_v2->bitmapLength, cache_bitmap_v2->compressed); + if (cache_bitmap_v2->compressed && (cache_bitmap_v2->flags & 0x80)) + { + bitmap->Decompress(context, bitmap, + cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight, + cache_bitmap_v2->bitmapBpp, cache_bitmap_v2->bitmapLength, 2); + } + else + { + bitmap->Decompress(context, bitmap, + cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight, + cache_bitmap_v2->bitmapBpp, cache_bitmap_v2->bitmapLength, cache_bitmap_v2->compressed); + } bitmap->New(context, bitmap); diff --git a/libfreerdp-codec/CMakeLists.txt b/libfreerdp-codec/CMakeLists.txt index 78d7610ea..442b5fbba 100644 --- a/libfreerdp-codec/CMakeLists.txt +++ b/libfreerdp-codec/CMakeLists.txt @@ -44,6 +44,7 @@ set(FREERDP_CODEC_SRCS nsc_types.h mppc_dec.c mppc_enc.c + jpeg.c ) if(WITH_SSE2) @@ -67,7 +68,7 @@ endif() add_library(freerdp-codec ${FREERDP_CODEC_SRCS}) set_target_properties(freerdp-codec PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") -target_link_libraries(freerdp-codec freerdp-utils) +target_link_libraries(freerdp-codec freerdp-utils jpeg) install(TARGETS freerdp-codec DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/libfreerdp-codec/jpeg.c b/libfreerdp-codec/jpeg.c new file mode 100644 index 000000000..ac96def9b --- /dev/null +++ b/libfreerdp-codec/jpeg.c @@ -0,0 +1,141 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Compressed jpeg + * + * Copyright 2012 Jay Sorg + * + * 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. + */ + +#include +#include +#include + +#define HAVE_BOOLEAN +#include + +struct mydata_decomp +{ + char* data; + int data_bytes; +}; + +/*****************************************************************************/ +static void my_init_source(j_decompress_ptr cinfo) +{ +} + +/*****************************************************************************/ +static boolean my_fill_input_buffer(j_decompress_ptr cinfo) +{ + struct mydata_decomp* md; + + md = (struct mydata_decomp*)(cinfo->client_data); + cinfo->src->next_input_byte = (unsigned char*)(md->data); + cinfo->src->bytes_in_buffer = md->data_bytes; + return 1; +} + +/*****************************************************************************/ +static void my_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ +} + +/*****************************************************************************/ +static boolean my_resync_to_restart(j_decompress_ptr cinfo, int desired) +{ + return 1; +} + +/*****************************************************************************/ +static void my_term_source(j_decompress_ptr cinfo) +{ +} + +/*****************************************************************************/ +int +do_decompress(char* comp_data, int comp_data_bytes, + int* width, int* height, int* bpp, + char* decomp_data, int* decomp_data_bytes) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + struct jpeg_source_mgr src_mgr; + struct mydata_decomp md; + JSAMPROW row_pointer[1]; + + memset(&cinfo, 0, sizeof(cinfo)); + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + memset(&src_mgr, 0, sizeof(src_mgr)); + cinfo.src = &src_mgr; + src_mgr.init_source = my_init_source; + src_mgr.fill_input_buffer = my_fill_input_buffer; + src_mgr.skip_input_data = my_skip_input_data; + src_mgr.resync_to_restart = my_resync_to_restart; + src_mgr.term_source = my_term_source; + + memset(&md, 0, sizeof(md)); + md.data = comp_data; + md.data_bytes = comp_data_bytes; + cinfo.client_data = &md; + + jpeg_read_header(&cinfo, 1); + + cinfo.out_color_space = JCS_RGB; + + *width = cinfo.image_width; + *height = cinfo.image_height; + *bpp = cinfo.num_components * 8; + + jpeg_start_decompress(&cinfo); + + while(cinfo.output_scanline < cinfo.image_height) + { + row_pointer[0] = (JSAMPROW) decomp_data; + jpeg_read_scanlines(&cinfo, row_pointer, 1); + decomp_data += cinfo.image_width * cinfo.num_components; + } + *decomp_data_bytes = cinfo.output_width * + cinfo.output_height * cinfo.num_components; + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + return 0; +} + +/* jpeg decompress */ +boolean +jpeg_decompress(uint8 * input, uint8 * output, int width, int height, int size, int bpp) +{ + int lwidth; + int lheight; + int lbpp; + int ldecomp_data_bytes; + + if (bpp != 24) + { + return 0; + } + if (do_decompress((char*)input, size, + &lwidth, &lheight, &lbpp, + (char*)output, &ldecomp_data_bytes) != 0) + { + return 0; + } + if (lwidth != width || lheight != height || lbpp != bpp) + { + return 0; + } + return 1; +} diff --git a/libfreerdp-core/capabilities.c b/libfreerdp-core/capabilities.c index 001b38f06..43615cdad 100644 --- a/libfreerdp-core/capabilities.c +++ b/libfreerdp-core/capabilities.c @@ -1014,6 +1014,7 @@ void rdp_write_bitmap_cache_v2_capability_set(STREAM* s, rdpSettings* settings) header = rdp_capability_set_start(s); cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG; + cacheFlags |= 0x80; /* jpeg hack */ if (settings->persistent_bitmap_cache) cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG; diff --git a/libfreerdp-gdi/graphics.c b/libfreerdp-gdi/graphics.c index 04816334c..d83ed2031 100644 --- a/libfreerdp-gdi/graphics.c +++ b/libfreerdp-gdi/graphics.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -98,7 +99,14 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed) + if (compressed == 2) + { + if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) + { + printf("jpeg Decompression Failed\n"); + } + } + else if (compressed) { boolean status; From b8c0d4e77219ccfee3165dc857a6cb88d860b76b Mon Sep 17 00:00:00 2001 From: Jim Grandy Date: Wed, 27 Jun 2012 10:14:06 -0700 Subject: [PATCH 14/27] Resolve merge error, remove debugging code --- client/Mac/MRDPView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index 757e55be0..1e0c2b724 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -34,7 +34,8 @@ #import "MRDPView.h" #import "MRDPCursor.h" -#define RUN_IN_XCODE +// Should be defined in Makefile +// #define RUN_IN_XCODE // LK_TODO #define GOT_HERE //printf("### got here: %s : %s() : %d\n", __FILE__, __func__, __LINE__) @@ -1869,7 +1870,6 @@ void cliprdr_send_supported_format_list(freerdp *inst) freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); } -<<<<<<< HEAD /**************************************************************************************** * * * * From 21c8fc6110542017a5a38fd2ce3dbfcce9536be5 Mon Sep 17 00:00:00 2001 From: Jim Grandy Date: Wed, 27 Jun 2012 10:17:49 -0700 Subject: [PATCH 15/27] Remove redundant copies of files --- client/Mac/Mac/MRDPCursor.h | 25 - client/Mac/Mac/MRDPCursor.m | 12 - client/Mac/Mac/MRDPRailWindow.h | 13 - client/Mac/Mac/MRDPRailWindow.m | 18 - client/Mac/Mac/MRDPView.h | 177 --- client/Mac/Mac/MRDPView.m | 2186 ------------------------------- 6 files changed, 2431 deletions(-) delete mode 100644 client/Mac/Mac/MRDPCursor.h delete mode 100644 client/Mac/Mac/MRDPCursor.m delete mode 100644 client/Mac/Mac/MRDPRailWindow.h delete mode 100644 client/Mac/Mac/MRDPRailWindow.m delete mode 100644 client/Mac/Mac/MRDPView.h delete mode 100644 client/Mac/Mac/MRDPView.m diff --git a/client/Mac/Mac/MRDPCursor.h b/client/Mac/Mac/MRDPCursor.h deleted file mode 100644 index 9df734ba4..000000000 --- a/client/Mac/Mac/MRDPCursor.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// MRDPCursor.h -// MacFreeRDP -// -// Created by Laxmikant Rashinkar -// Copyright (c) 2012 FreeRDP.org All rights reserved. -// - -#import - -#define boolean int - -#include "freerdp/graphics.h" - -@interface MRDPCursor : NSObject -{ -@public - rdpPointer *pointer; - uint8 *cursor_data; // bitmapped pixel data - NSBitmapImageRep *bmiRep; - NSCursor *nsCursor; - NSImage *nsImage; -} - -@end diff --git a/client/Mac/Mac/MRDPCursor.m b/client/Mac/Mac/MRDPCursor.m deleted file mode 100644 index 29a93c808..000000000 --- a/client/Mac/Mac/MRDPCursor.m +++ /dev/null @@ -1,12 +0,0 @@ -// -// MRDPCursor.m -// MacFreeRDP -// -// Created by Laxmikant Rashinkar -// Copyright (c) 2012 FreeRDP.org All rights reserved. -// - -#import "MRDPCursor.h" - -@implementation MRDPCursor -@end diff --git a/client/Mac/Mac/MRDPRailWindow.h b/client/Mac/Mac/MRDPRailWindow.h deleted file mode 100644 index 629dc819c..000000000 --- a/client/Mac/Mac/MRDPRailWindow.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// MRDPRailWindow.h -// Mac -// -// Created by Laxmikant Rashinkar -// Copyright (c) 2012 __MyCompanyName__. All rights reserved. -// - -#import - -@interface MRDPRailWindow : NSWindow - -@end diff --git a/client/Mac/Mac/MRDPRailWindow.m b/client/Mac/Mac/MRDPRailWindow.m deleted file mode 100644 index 9cab180f4..000000000 --- a/client/Mac/Mac/MRDPRailWindow.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// MRDPRailWindow.m -// Mac -// -// Created by Laxmikant Rashinkar -// Copyright (c) 2012 __MyCompanyName__. All rights reserved. -// - -#import "MRDPRailWindow.h" - -@implementation MRDPRailWindow - -- (BOOL) canBecomeKeyWindow -{ - return YES; -} - -@end diff --git a/client/Mac/Mac/MRDPView.h b/client/Mac/Mac/MRDPView.h deleted file mode 100644 index b0ecf432f..000000000 --- a/client/Mac/Mac/MRDPView.h +++ /dev/null @@ -1,177 +0,0 @@ -// -// MRDPView.h -// MacFreeRDP -// -// Created by Laxmikant Rashinkar -// Copyright (c) 2012 FreeRDP.org All rights reserved. -// - -#import - -typedef int boolean; - -#import "MRDPWindow.h" -#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/plugins/cliprdr.h" -#import "freerdp/utils/args.h" -#import "freerdp/rail/rail.h" -#import "freerdp/rail.h" -#import "freerdp/utils/rail.h" - -@interface MRDPView : NSView -{ - CFRunLoopSourceRef run_loop_src; - CFRunLoopSourceRef run_loop_src_channels; - NSBitmapImageRep *bmiRep; - NSMutableArray *cursors; - NSMutableArray *windows; - NSTimer *pasteboard_timer; - NSRect rect; - NSRect prevWinPosition; - freerdp *rdp_instance; - rdpContext *rdp_context; - char *pixel_data; - int width; - int height; - int argc; - int titleBarHeight; - char **argv; - - // RAIL stuff - MRDPWindow *currentWindow; - NSPoint savedDragLocation; - boolean mouseInClientArea; - boolean isRemoteApp; - boolean firstCreateWindow; - boolean isMoveSizeInProgress; - boolean skipResizeOnce; - boolean saveInitialDragLoc; - boolean skipMoveWindowOnce; - - // store state info for some keys - int kdlshift; - int kdrshift; - int kdlctrl; - int kdrctrl; - int kdlalt; - int kdralt; - int kdlmeta; - int kdrmeta; - int kdcapslock; - -@public - NSWindow *ourMainWindow; - NSPasteboard *pasteboard_rd; // for reading from clipboard - NSPasteboard *pasteboard_wr; // for writing to clipboard - int pasteboard_changecount; - int pasteboard_format; - int is_connected; // true when connected to RDP server -} - -- (void) rdpConnectEror; -- (void) rdpRemoteAppError; -- (void) saveStateInfo :(freerdp *) instance :(rdpContext *) context; -- (void) onPasteboardTimerFired :(NSTimer *) timer; -- (void) my_draw_rect :(void *) context; -- (void) releaseResources; -- (void) setViewSize : (int) width : (int) height; - -@property (assign) int is_connected; - -@end - -/* Pointer Flags */ -#define PTR_FLAGS_WHEEL 0x0200 -#define PTR_FLAGS_WHEEL_NEGATIVE 0x0100 -#define PTR_FLAGS_MOVE 0x0800 -#define PTR_FLAGS_DOWN 0x8000 -#define PTR_FLAGS_BUTTON1 0x1000 -#define PTR_FLAGS_BUTTON2 0x2000 -#define PTR_FLAGS_BUTTON3 0x4000 -#define WheelRotationMask 0x01FF - -void pointer_new(rdpContext* context, rdpPointer* pointer); -void pointer_free(rdpContext* context, rdpPointer* pointer); -void pointer_set(rdpContext* context, rdpPointer* pointer); -void pointer_setNull(rdpContext* context); -void pointer_setDefault(rdpContext* context); -int rdp_connect(); -boolean mac_pre_connect(freerdp *inst); -boolean mac_post_connect(freerdp *inst); -void mac_context_new(freerdp *inst, rdpContext *context); -void mac_context_free(freerdp *inst, rdpContext *context); -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 *inst, rdpContext *context); -void skt_activity_cb(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info); -void channel_activity_cb(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info); -int register_fds(int *fds, int count, void *inst); -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 *inst, int chan_id, uint8 *data, int size, int flags, int total_size); -void process_cliprdr_event(freerdp *inst, RDP_EVENT *event); -void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVENT* event); -void cliprdr_send_data_request(freerdp *inst, uint32 format); -void cliprdr_process_cb_monitor_ready_event(freerdp* inst); -void cliprdr_process_cb_data_response_event(freerdp *inst, RDP_CB_DATA_RESPONSE_EVENT *event); -void cliprdr_process_text(freerdp *inst, uint8 *data, int len); -void cliprdr_send_supported_format_list(freerdp *inst); -int register_channel_fds(int *fds, int count, void *inst); - -void mac_process_rail_event(freerdp *inst, RDP_EVENT *event); -void mac_rail_register_callbacks(freerdp *inst, rdpRail *rail); -void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window); -void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window); -void mac_rail_ShowWindow(rdpRail *rail, rdpWindow *window, uint8 state); -void mac_rail_SetWindowText(rdpRail *rail, rdpWindow *window); -void mac_rail_SetWindowIcon(rdpRail *rail, rdpWindow *window, rdpIcon *icon); -void mac_rail_SetWindowRects(rdpRail *rail, rdpWindow *window); -void mac_rail_SetWindowVisibilityRects(rdpRail *rail, rdpWindow *window); -void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window); -void mac_process_rail_get_sysparams_event(rdpChannels *channels, RDP_EVENT *event); -void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param); -void mac_on_free_rail_client_event(RDP_EVENT* event); -void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* event); -void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event); -void mac_rail_enable_remoteapp_mode(); -void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event); -void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event); -void apple_center_window(NSRect * r); -void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove); - -struct mac_context -{ - // *must* have this - do not delete - rdpContext _p; -}; - -struct cursor -{ - rdpPointer *pointer; - uint8 *cursor_data; // bitmapped pixel data - void *bmiRep; // NSBitmapImageRep - void *nsCursor; // NSCursor - void *nsImage; // NSImage -}; - -struct rgba_data -{ - char red; - char green; - char blue; - char alpha; -}; - -struct kkey -{ - int key_code; - int flags; -}; - diff --git a/client/Mac/Mac/MRDPView.m b/client/Mac/Mac/MRDPView.m deleted file mode 100644 index 0dad2c488..000000000 --- a/client/Mac/Mac/MRDPView.m +++ /dev/null @@ -1,2186 +0,0 @@ -// -// MRDPView.m -// MacFreeRDP -// -// Created by Laxmikant Rashinkar -// Copyright (c) 2012 FreeRDP.org All rights reserved. -// - -/* - * TODO - * + 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 - */ - -#import "MRDPView.h" -#import "MRDPCursor.h" - -#define RUN_IN_XCODE - -@implementation MRDPView - -MRDPView *g_mrdpview; - -@synthesize is_connected; - -struct kkey g_keys[]; -void convert_color_space(char *dest, char *src, NSRect* drawRect, int width, int height); - -const char* error_code_names[] = -{ - "RAIL_EXEC_S_OK", - "RAIL_EXEC_E_HOOK_NOT_LOADED", - "RAIL_EXEC_E_DECODE_FAILED", - "RAIL_EXEC_E_NOT_IN_ALLOWLIST", - "RAIL_EXEC_E_FILE_NOT_FOUND", - "RAIL_EXEC_E_FAIL", - "RAIL_EXEC_E_SESSION_LOCKED" -}; - - -struct kkey g_keys[256] = -{ - { 0x1e, 0 }, // a 0 - { 0x1f, 0 }, // s - { 0x20, 0 }, // d - { 0x21, 0 }, // f - { 0x23, 0 }, // h - { 0x22, 0 }, // g - { 0x2c, 0 }, // z - { 0x2d, 0 }, // x - { 0x2e, 0 }, // c - { 0x2f, 0 }, // v - { 0x00, 0 }, // 10 - { 0x30, 0 }, // b - { 0x10, 0 }, // q - { 0x11, 0 }, // w - { 0x12, 0 }, // e - { 0x13, 0 }, // r - { 0x15, 0 }, // y - { 0x14, 0 }, // t - { 0x02, 0 }, // 1 - { 0x03, 0 }, // 2 - { 0x04, 0 }, // 3 20 - { 0x05, 0 }, // 4 - { 0x07, 0 }, // 6 - { 0x06, 0 }, // 5 - { 0x0d, 0 }, // = or + - { 0x0a, 0 }, // 9 - { 0x08, 0 }, // 7 - { 0x0c, 0 }, // - or _ - { 0x09, 0 }, // 8 - { 0x0b, 0 }, // 0 - { 0x1b, 0 }, // ] or } 30 - { 0x18, 0 }, // o - { 0x16, 0 }, // u - { 0x1a, 0 }, // [ or { - { 0x17, 0 }, // i - { 0x19, 0 }, // p - { 0x1c, 0 }, // enter - { 0x26, 0 }, // l - { 0x24, 0 }, // j - { 0x28, 0 }, // ' or " - { 0x25, 0 }, // k 40 - { 0x27, 0 }, // ; or : - { 0x2b, 0 }, // \ or | - { 0x33, 0 }, // , or < - { 0x35, 0 }, // / or ? - { 0x31, 0 }, // n - { 0x32, 0 }, // m - { 0x34, 0 }, // . or > - { 0x0f, 0 }, // tab - { 0x39, 0 }, // space - { 0x29, 0 }, // ` or ~ 50 - { 0x0e, 0 }, // backspace - { 0x00, 0 }, // - { 0x01, 0 }, // esc - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, // 60 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x53, 0 }, // KP. - { 0x00, 0 }, - { 0x37, 0 }, // KP* - { 0x00, 0 }, - { 0x4e, 0 }, // KP+ - { 0x00, 0 }, // 70 - { 0x45, 0 }, // num lock - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x35, 1 }, // KP/ - { 0x1c, 1 }, // KPEnter - { 0x00, 0 }, - { 0x4a, 0 }, // KP- - { 0x00, 0 }, - { 0x00, 0 }, // 80 - { 0x00, 0 }, - { 0x52, 0 }, // KP0 - { 0x4f, 0 }, // KP1 - { 0x50, 0 }, // KP2 - { 0x51, 0 }, // KP3 - { 0x4b, 0 }, // KP4 - { 0x4c, 0 }, // KP5 - { 0x4d, 0 }, // KP6 - { 0x47, 0 }, // KP7 - { 0x00, 0 }, // 90 - { 0x48, 0 }, // KP8 - { 0x49, 0 }, // KP9 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, // 100 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x5d, 1 }, // menu 110 - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x52, 1 }, // Insert - { 0x47, 1 }, // Home - { 0x49, 1 }, // PgUp - { 0x53, 1 }, // Delete - { 0x00, 0 }, - { 0x4f, 1 }, // End - { 0x00, 0 }, // 120 - { 0x51, 1 }, // PgDown - { 0x3b, 0 }, // f1 - { 0x4b, 1 }, // left - { 0x4d, 1 }, // right - { 0x50, 1 }, // down - { 0x48, 1 }, // up - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, - { 0x00, 0 }, -}; - -/************************************************************************ - methods we override -************************************************************************/ - -/** ********************************************************************* - * create MRDPView with specified rectangle - ***********************************************************************/ - -- (id)initWithFrame:(NSRect)frame -{ - self = [super initWithFrame:frame]; - if (self) { - // Initialization code here. - } - - return self; -} - -/** ********************************************************************* - * called when MRDPView has been successfully created from the NIB - ***********************************************************************/ - -- (void) awakeFromNib -{ - g_mrdpview = self; - - // 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]; - - firstCreateWindow = TRUE; - skipResizeOnce = YES; - windows = [[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]; - - // windows in RemoteApp (RAIL) mode cannot have title bars - NSArray * args = [[NSProcessInfo processInfo] arguments]; - for (NSString * str in args) - { - if ([str compare:@"--app"] == NSOrderedSame) { - isRemoteApp = TRUE; - break; - } - } - - if (!isRemoteApp) - [self addTrackingArea:trackingArea]; - - mouseInClientArea = YES; - [self setAcceptsTouchEvents:YES]; - printScreenInfo(); -} - -/** ********************************************************************* - * become first responder so we can get keyboard and mouse events - ***********************************************************************/ - -- (BOOL)acceptsFirstResponder -{ - return YES; -} - -/** ********************************************************************* - * called when a mouse move event occurrs - * - * 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 - * versions, we do this manually. - * - * 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 - ***********************************************************************/ - - - (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 - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); -} - -/** ********************************************************************* - * called when left mouse button is pressed down - ***********************************************************************/ - -- (void)mouseDown:(NSEvent *) event -{ - [super mouseDown:event]; - - if (!is_connected) - return; - - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - y = height - y; - - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); -} - -/** ********************************************************************* - * called when left mouse button is released - ***********************************************************************/ - -- (void) mouseUp:(NSEvent *) event -{ - [super mouseUp:event]; - - if (!is_connected) - return; - - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - y = height - y; - - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON1, x, y); -} - -/** ********************************************************************* - * called when right mouse button is pressed down - ***********************************************************************/ - -- (void) rightMouseDown:(NSEvent *)event -{ - [super rightMouseDown:event]; - - if (!is_connected) - return; - - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - y = height - y; - - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y); -} - -/** ********************************************************************* - * called when right mouse button is released - ***********************************************************************/ - -- (void) rightMouseUp:(NSEvent *)event -{ - [super rightMouseUp:event]; - - if (!is_connected) - return; - - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - y = height - y; - - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON2, x, y); -} - -/** ********************************************************************* - * called when middle mouse button is pressed - ***********************************************************************/ - -- (void) otherMouseDown:(NSEvent *)event -{ - [super otherMouseDown:event]; - - if (!is_connected) - return; - - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - y = height - y; - - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y); -} - -/** ********************************************************************* - * called when middle mouse button is released - ***********************************************************************/ - -- (void) otherMouseUp:(NSEvent *)event -{ - [super otherMouseUp:event]; - - if (!is_connected) - return; - - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - y = height - y; - - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_BUTTON3, x, y); -} - -- (void) scrollWheel:(NSEvent *)event -{ - uint16 flags; - - [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; - if ([event deltaY] < 0) { - flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; - } - else { - flags |= 0x0078; - } - x += (int) [event deltaX]; - y += (int) [event deltaY]; - rdp_instance->input->MouseEvent(rdp_instance->input, flags, x, y); -} - -/** ********************************************************************* - * called when mouse is moved with left button pressed - * note: invocation order is: mouseDown, mouseDragged, mouseUp - ***********************************************************************/ - -- (void) mouseDragged:(NSEvent *)event -{ - [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 - rdp_instance->input->MouseEvent(rdp_instance->input, PTR_FLAGS_MOVE, x, y); -} - -/** ********************************************************************* - * called when a key is pressed - ***********************************************************************/ - -- (void) keyDown:(NSEvent *) event -{ - int key; - - if (!is_connected) { - return; - } - - key = [event keyCode]; - rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_DOWN, g_keys[key].key_code); -} - -/** ********************************************************************* - * called when a key is released - ***********************************************************************/ - -- (void) keyUp:(NSEvent *) event -{ - int key; - - if (!is_connected) { - return; - } - - key = [event keyCode]; - rdp_instance->input->KeyboardEvent(rdp_instance->input, g_keys[key].flags | KBD_FLAGS_RELEASE, g_keys[key].key_code); -} - -/** ********************************************************************* - * called when shift, control, alt and meta keys are pressed/released - ***********************************************************************/ - -- (void) flagsChanged:(NSEvent *) event -{ - NSUInteger mf = [event modifierFlags]; - - if (!is_connected) { - 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 - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x2a); - kdlshift = 1; - } - if ((kdlshift != 0) && ((mf & 2) == 0)) { - // left shift went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x2a); - kdlshift = 0; - } - - // right shift - if ((kdrshift == 0) && ((mf & 4) != 0)) { - // right shift went down - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x36); - kdrshift = 1; - } - if ((kdrshift != 0) && ((mf & 4) == 0)) { - // right shift went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x36); - kdrshift = 0; - } - - // left ctrl - if ((kdlctrl == 0) && ((mf & 1) != 0)) { - // left ctrl went down - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x1d); - kdlctrl = 1; - } - if ((kdlctrl != 0) && ((mf & 1) == 0)) { - // left ctrl went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x1d); - kdlctrl = 0; - } - - // right ctrl - if ((kdrctrl == 0) && ((mf & 0x2000) != 0)) { - // right ctrl went down - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x1d); - kdrctrl = 1; - } - if ((kdrctrl != 0) && ((mf & 0x2000) == 0)) { - // right ctrl went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x1d); - kdrctrl = 0; - } - - // left alt - if ((kdlalt == 0) && ((mf & 0x20) != 0)) { - // left alt went down - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_DOWN, 0x38); - kdlalt = 1; - } - if ((kdlalt != 0) && ((mf & 0x20) == 0)) { - // left alt went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, KBD_FLAGS_RELEASE, 0x38); - kdlalt = 0; - } - - // right alt - if ((kdralt == 0) && ((mf & 0x40) != 0)) { - // right alt went down - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x38); - kdralt = 1; - } - if ((kdralt != 0) && ((mf & 0x40) == 0)) { - // right alt went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x38); - kdralt = 0; - } - - // left meta - if ((kdlmeta == 0) && ((mf & 0x08) != 0)) { - // left meta went down - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5b); - kdlmeta = 1; - } - if ((kdlmeta != 0) && ((mf & 0x08) == 0)) { - // left meta went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5b); - kdlmeta = 0; - } - - // right meta - if ((kdrmeta == 0) && ((mf & 0x10) != 0)) { - // right meta went down - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_DOWN, 0x5c); - kdrmeta = 1; - } - if ((kdrmeta != 0) && ((mf & 0x10) == 0)) { - // right meta went up - rdp_instance->input->KeyboardEvent(rdp_instance->input, 1 | KBD_FLAGS_RELEASE, 0x5c); - kdrmeta = 0; - } -} - -- (void) releaseResources -{ - int i; - - for (i = 0; i < argc; i++) - { - if (argv[i]) - free(argv[i]); - } - - for (MRDPWindow * w in windows) - { - [w setWindow:nil]; - [w setView:nil]; - } - - if (!is_connected) - return; - - freerdp_channels_global_uninit(); - - if (pixel_data) - free(pixel_data); - - if (run_loop_src != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode); - - if (run_loop_src != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src, kCFRunLoopDefaultMode); -} - -/** ********************************************************************* - * called when our view needs refreshing - ***********************************************************************/ - -- (void) drawRect:(NSRect)dirtyRect -{ - if (!rdp_context) - return; - - if (g_mrdpview->isRemoteApp && g_mrdpview->currentWindow) { - return; - } - - if (!bmiRep) { - pixel_data = (char *) malloc(width * height * sizeof(struct rgba_data)); - bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &pixel_data - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 - samplesPerPixel:sizeof(struct rgba_data) - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 //NSAlphaFirstBitmapFormat - bytesPerRow:width * sizeof(struct rgba_data) - bitsPerPixel:0]; - } - - [bmiRep drawInRect:dirtyRect fromRect:dirtyRect operation:NSCompositeCopy fraction:1.0 respectFlipped:NO hints:nil]; -} - -/************************************************************************ - instance methods -************************************************************************/ - -/** ********************************************************************* - * save state info for use by other methods later on - ***********************************************************************/ - -- (void) saveStateInfo:(freerdp *) instance:(rdpContext *) context -{ - rdp_instance = instance; - rdp_context = context; -} - -/** ********************************************************************* - * double check that a mouse event occurred in our client view - ***********************************************************************/ - -- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr -{ - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - if ((x < 0) || (y < 0)) { - if (mouseInClientArea) { - // set default cursor before leaving client area - mouseInClientArea = NO; - NSCursor *cur = [NSCursor arrowCursor]; - [cur set]; - } - return NO; - } - if ((x > width) || (y > height)) { - if (mouseInClientArea) { - // set default cursor before leaving client area - mouseInClientArea = NO; - NSCursor *cur = [NSCursor arrowCursor]; - [cur set]; - } - return NO; - } - - // on Mac origin is at lower left, but we want it on upper left - y = height - y; - - *xptr = x; - *yptr = y; - mouseInClientArea = YES; - return YES; -} - -/** ********************************************************************* - * called when we fail to connect to a RDP server - ***********************************************************************/ - -- (void) rdpConnectError -{ - - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:@"Error connecting to server"]; - [alert beginSheetModalForWindow:[g_mrdpview window] - modalDelegate:g_mrdpview - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; -} - -/** ********************************************************************* - * called when we fail to launch remote app on RDP server - ***********************************************************************/ - -- (void) rdpRemoteAppError -{ - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:@"Error starting remote app on specified server"]; - [alert beginSheetModalForWindow:[g_mrdpview window] - modalDelegate:g_mrdpview - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; -} - -/** ********************************************************************* - * just a terminate selector for above call - ***********************************************************************/ - -- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci -{ - [NSApp terminate:nil]; -} - -- (void) onPasteboardTimerFired :(NSTimer *) timer -{ - NSArray *types; - int i; - - i = (int) [pasteboard_rd changeCount]; - if (i != pasteboard_changecount) - { - pasteboard_changecount = i; - types = [NSArray arrayWithObject:NSStringPboardType]; - NSString *str = [pasteboard_rd availableTypeFromArray:types]; - if (str != nil) - { - cliprdr_send_supported_format_list(rdp_instance); - } - } -} - -- (void) setViewSize : (int) w : (int) h -{ - // store current dimensions - width = w; - height = h; - - // compute difference between window and client area - NSRect outerRect = [[g_mrdpview window] frame]; - NSRect innerRect = [g_mrdpview frame]; - - int widthDiff = outerRect.size.width - innerRect.size.width; - int heightDiff = outerRect.size.height - innerRect.size.height; - - if (!g_mrdpview->isRemoteApp) { - // we are not in RemoteApp mode, disable resizing - outerRect.size.width = w + widthDiff; - outerRect.size.height = h + heightDiff; - [[g_mrdpview window] setMaxSize:outerRect.size]; - [[g_mrdpview window] setMinSize:outerRect.size]; - [[g_mrdpview window] setFrame:outerRect display:YES]; - - // set client area to specified dimensions - innerRect.size.width = w; - innerRect.size.height = h; - [g_mrdpview setFrame:innerRect]; - - return; - } - - // we are in RemoteApp mode - - outerRect.origin.x = 0; - outerRect.origin.y = 0; - outerRect.size.width = width + widthDiff; - outerRect.size.height = height + heightDiff; - [[g_mrdpview window] setFrame:outerRect display:YES]; - - // set client area to specified dimensions - innerRect.size.width = width; - innerRect.size.height = height; - [g_mrdpview setFrame:innerRect]; - - // main window displays desktop background - hide it - [[g_mrdpview window] orderOut:g_mrdpview]; -} - -- (void) windowDidResize:(NSNotification *) notification -{ -} - -/************************************************************************ - * * - * C functions * - * * - ***********************************************************************/ - -/** ********************************************************************* - * connect to RDP server - * - * @return 0 on success, -1 on failure - ***********************************************************************/ - -int rdp_connect() -{ - freerdp *inst; - int status; - - freerdp_channels_global_init(); - - inst = freerdp_new(); - inst->PreConnect = mac_pre_connect; - inst->PostConnect = mac_post_connect; - inst->context_size = sizeof(struct mac_context); - inst->ContextNew = mac_context_new; - inst->ContextFree = mac_context_free; - inst->ReceiveChannelData = receive_channel_data; - freerdp_context_new(inst); - - status = freerdp_connect(inst); - if(status) { - freerdp_check_fds(inst); - [g_mrdpview setIs_connected:1]; - return 0; - } - [g_mrdpview setIs_connected:0]; - [g_mrdpview rdpConnectError]; - return -1; -} - -/** ********************************************************************* - * a callback given to freerdp_connect() to process the pre-connect operations. - * - * @param inst - pointer to a rdp_freerdp struct that contains the connection's parameters, and - * will be filled with the appropriate informations. - * - * @return true if successful. false otherwise. - ************************************************************************/ - -boolean mac_pre_connect(freerdp *inst) -{ - char *cptr; - int len; - int i; - - inst->settings->offscreen_bitmap_cache = false; - inst->settings->glyph_cache = true; - inst->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; - inst->settings->order_support[NEG_GLYPH_INDEX_INDEX] = true; - inst->settings->order_support[NEG_FAST_GLYPH_INDEX] = false; - inst->settings->order_support[NEG_FAST_INDEX_INDEX] = false; - inst->settings->order_support[NEG_SCRBLT_INDEX] = true; - inst->settings->order_support[NEG_SAVEBITMAP_INDEX] = false; - - inst->settings->bitmap_cache = true; - inst->settings->order_support[NEG_MEMBLT_INDEX] = true; - inst->settings->order_support[NEG_MEMBLT_V2_INDEX] = true; - inst->settings->order_support[NEG_MEM3BLT_INDEX] = false; - inst->settings->order_support[NEG_MEM3BLT_V2_INDEX] = false; - inst->settings->bitmapCacheV2NumCells = 3; // 5; - inst->settings->bitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; - inst->settings->bitmapCacheV2CellInfo[0].persistent = false; - inst->settings->bitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; - inst->settings->bitmapCacheV2CellInfo[1].persistent = false; - inst->settings->bitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; - inst->settings->bitmapCacheV2CellInfo[2].persistent = false; - inst->settings->bitmapCacheV2CellInfo[3].numEntries = 0; // 4096; - inst->settings->bitmapCacheV2CellInfo[3].persistent = false; - inst->settings->bitmapCacheV2CellInfo[4].numEntries = 0; // 2048; - inst->settings->bitmapCacheV2CellInfo[4].persistent = false; - - inst->settings->order_support[NEG_MULTIDSTBLT_INDEX] = false; - inst->settings->order_support[NEG_MULTIPATBLT_INDEX] = false; - inst->settings->order_support[NEG_MULTISCRBLT_INDEX] = false; - inst->settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false; - inst->settings->order_support[NEG_POLYLINE_INDEX] = false; - inst->settings->color_depth = 24; - inst->settings->sw_gdi = 1; - - // setup callbacks - inst->update->BeginPaint = mac_begin_paint; - inst->update->EndPaint = mac_end_paint; - inst->update->SetBounds = mac_set_bounds; - inst->update->BitmapUpdate = mac_bitmap_update; - - NSArray *args = [[NSProcessInfo processInfo] arguments]; - -#ifdef RUN_IN_XCODE - g_mrdpview->argc = 30; -#else - g_mrdpview->argc = (int) [args count]; -#endif - - g_mrdpview->argv = malloc(sizeof(char *) * g_mrdpview->argc); - if (g_mrdpview->argv == NULL) { - return false; - } - -#ifdef RUN_IN_XCODE - - // create our own cmd line args - i = 0; - - NSString *sptr = [args objectAtIndex:0]; - len = [sptr length] + 1; - cptr = (char *) malloc(len); - strcpy(cptr, [sptr UTF8String]); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "-g"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "1280x800"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "--sec"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "rdp"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "--plugin"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "cliprdr"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "--plugin"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "rdpsnd"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "-u"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "lk"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "-p"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "lk"); - g_mrdpview->argv[i++] = cptr; - -#if 1 - // for RemoteApp (RAIL) testing - cptr = (char *)malloc(80); - strcpy(cptr, "--app"); - g_mrdpview->argv[i++] = cptr; - g_mrdpview->isRemoteApp = TRUE; - - cptr = (char *)malloc(80); - strcpy(cptr, "--plugin"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "rail"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "--data"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "||WordPad"); - g_mrdpview->argv[i++] = cptr; - - cptr = (char *)malloc(80); - strcpy(cptr, "--"); - g_mrdpview->argv[i++] = cptr; -#endif - - cptr = (char *)malloc(80); - strcpy(cptr, "192.168.1.69:45990"); - - g_mrdpview->argv[i++] = cptr; - - g_mrdpview->argc = i; - -#else - // MacFreeRDP was not run in Xcode - i = 0; - - // in RemoteApp (RAIL) mode, we connect to RDP server at max screen resolution; - // in order to achieve this, we need to modify the cmd line args entered by the user; - - if (g_mrdpview->isRemoteApp) { - boolean gotGeometry = NO; - - // get dimensions of screen that has keyboard focus; - // we use these dimensions when connecting to RDP server - inst->settings->width = [[NSScreen mainScreen] frame].size.width; - inst->settings->height = [[NSScreen mainScreen] frame].size.height - g_mrdpview->titleBarHeight; - g_mrdpview->width = inst->settings->width; - g_mrdpview->height = inst->settings->height; - - for (NSString * str in args) - { - if (gotGeometry) { - gotGeometry = NO; - cptr = (char *) malloc(20); - sprintf(cptr, "%dx%d", g_mrdpview->width, g_mrdpview->height); - g_mrdpview->argv[i++] = cptr; - continue; - } - - len = (int) ([str length] + 1); - cptr = (char *) malloc(len); - strcpy(cptr, [str UTF8String]); - g_mrdpview->argv[i++] = cptr; - - // -g is the cmd line arg to specify screen resolution/geometry - if ([str compare:@"-g"] == NSOrderedSame) { - gotGeometry = YES; - } - } - } - else { - for (NSString * str in args) - { - len = (int) ([str length] + 1); - cptr = (char *) malloc(len); - strcpy(cptr, [str UTF8String]); - g_mrdpview->argv[i++] = cptr; - } - } -#endif - - freerdp_parse_args(inst->settings, g_mrdpview->argc, g_mrdpview->argv, process_plugin_args, inst->context->channels, NULL, NULL); - if ((strcmp(g_mrdpview->argv[1], "-h") == 0) || (strcmp(g_mrdpview->argv[1], "--help") == 0)) { - [NSApp terminate:nil]; - return true; - } - - [g_mrdpview setViewSize:inst->settings->width :inst->settings->height]; - - freerdp_channels_pre_connect(inst->context->channels, inst); - return true; -} - -/** ********************************************************************* - * a callback registered with freerdp_connect() to perform post-connection operations. - * we get called only if the connection was initialized properly, and will continue - * the initialization based on the newly created connection. - * - * @param inst - pointer to a rdp_freerdp struct - * - * @return true on success, false on failure - * - ************************************************************************/ - -boolean mac_post_connect(freerdp *inst) -{ - uint32 flags; - rdpPointer rdp_pointer; - void *rd_fds[32]; - void *wr_fds[32]; - int rd_count = 0; - int wr_count = 0; - int index; - int fds[32]; - - memset(&rdp_pointer, 0, sizeof(rdpPointer)); - rdp_pointer.size = sizeof(rdpPointer); - rdp_pointer.New = pointer_new; - rdp_pointer.Free = pointer_free; - rdp_pointer.Set = pointer_set; - rdp_pointer.SetNull = pointer_setNull; - rdp_pointer.SetDefault = pointer_setDefault; - - flags = CLRCONV_ALPHA; - flags |= CLRBUF_32BPP; - - gdi_init(inst, flags, NULL); - pointer_cache_register_callbacks(inst->update); - graphics_register_pointer(inst->context->graphics, &rdp_pointer); - - // register file descriptors with the RunLoop - if (!freerdp_get_fds(inst, rd_fds, &rd_count, 0, 0)) - { - printf("mac_post_connect: freerdp_get_fds() failed!\n"); - } - - for (index = 0; index < rd_count; index++) - { - fds[index] = (int)(long)rd_fds[index]; - } - register_fds(fds, rd_count, inst); - - // register channel manager file descriptors with the RunLoop - if (!freerdp_channels_get_fds(inst->context->channels, inst, rd_fds, &rd_count, wr_fds, &wr_count)) - { - printf("ERROR: freerdp_channels_get_fds() failed\n"); - } - for (index = 0; index < rd_count; index++) - { - fds[index] = (int)(long)rd_fds[index]; - } - register_channel_fds(fds, rd_count, inst); - freerdp_channels_post_connect(inst->context->channels, inst); - - // setup RAIL (remote app) - inst->context->rail = rail_new(inst->settings); - rail_register_update_callbacks(inst->context->rail, inst->update); - mac_rail_register_callbacks(inst, inst->context->rail); - - // setup pasteboard (aka clipboard) for copy operations (write only) - g_mrdpview->pasteboard_wr = [NSPasteboard generalPasteboard]; - - // setup pasteboard for read operations - g_mrdpview->pasteboard_rd = [NSPasteboard generalPasteboard]; - g_mrdpview->pasteboard_changecount = (int) [g_mrdpview->pasteboard_rd changeCount]; - g_mrdpview->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:g_mrdpview selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; - - // we want to be notified when window resizes - [[NSNotificationCenter defaultCenter] addObserver:g_mrdpview selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:nil]; - - return true; -} - -/** ********************************************************************* - * create a new mouse cursor - * - * @param context our context state - * @param pointer information about the cursor to create - * - ************************************************************************/ - -void pointer_new(rdpContext* context, rdpPointer* pointer) -{ - MRDPCursor *mrdpCursor = [[MRDPCursor alloc] init]; - uint8 *cursor_data; - - NSRect rect; - rect.size.width = pointer->width; - rect.size.height = pointer->height; - rect.origin.x = pointer->xPos; - rect.origin.y = pointer->yPos; - - cursor_data = (uint8 *) malloc(rect.size.width * rect.size.height * 4); - mrdpCursor->cursor_data = cursor_data; - - 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 - - // store cursor bitmap image in representation - required by NSImage - NSBitmapImageRep *bmiRep; - bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **) &cursor_data - pixelsWide:rect.size.width - pixelsHigh:rect.size.height - bitsPerSample:8 - samplesPerPixel:sizeof(struct rgba_data) - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 - bytesPerRow:rect.size.width * 4 - bitsPerPixel:0]; - mrdpCursor->bmiRep = bmiRep; - - // create an image using above representation - NSImage *image = [[NSImage alloc] initWithSize:[bmiRep size]]; - [image addRepresentation: bmiRep]; - [image setFlipped:NO]; - mrdpCursor->nsImage = image; - - // need hotspot to create cursor - NSPoint hotSpot; - hotSpot.x = pointer->xPos; - hotSpot.y = pointer->yPos; - - NSCursor *cursor = [[NSCursor alloc] initWithImage: image hotSpot:hotSpot]; - mrdpCursor->nsCursor = cursor; - mrdpCursor->pointer = pointer; - - // save cursor for later use in pointer_set() - NSMutableArray *ma = g_mrdpview->cursors; - [ma addObject:mrdpCursor]; -} - -/** ********************************************************************* - * release resources on specified cursor - ************************************************************************/ - -void pointer_free(rdpContext* context, rdpPointer* pointer) -{ - NSMutableArray *ma = g_mrdpview->cursors; - - for (MRDPCursor *cursor in ma) - { - if (cursor->pointer == pointer) { - cursor->nsImage = nil; - cursor->nsCursor = nil; - cursor->bmiRep = nil; - free(cursor->cursor_data); - [ma removeObject:cursor]; - return; - } - } -} - -/** ********************************************************************* - * set specified cursor as the current cursor - ************************************************************************/ - -void pointer_set(rdpContext* context, rdpPointer* pointer) -{ - NSMutableArray *ma = g_mrdpview->cursors; - - if (!g_mrdpview->mouseInClientArea) - { - return; // not in client area - } - - for (MRDPCursor *cursor in ma) - { - if (cursor->pointer == pointer) { - [cursor->nsCursor set]; - return; - } - } -} - -/** ********************************************************************* - * do not display any mouse cursor - ***********************************************************************/ - -void pointer_setNull(rdpContext* context) -{ -} - -/** ********************************************************************* - * display default mouse cursor - ***********************************************************************/ - -void pointer_setDefault(rdpContext* context) -{ -} - -/** ********************************************************************* - * create a new context - but all we really need to do is save state info - ***********************************************************************/ - -void mac_context_new(freerdp *inst, rdpContext *context) -{ - [g_mrdpview saveStateInfo:inst :context]; - context->channels = freerdp_channels_new(); -} - -/** ********************************************************************* - * we don't do much over here - ***********************************************************************/ - -void mac_context_free(freerdp *inst, rdpContext *context) -{ -} - -/** ********************************************************************* - * clip drawing surface so nothing is drawn outside specified bounds - ***********************************************************************/ - -void mac_set_bounds(rdpContext *context, rdpBounds *bounds) -{ -} - -/** ********************************************************************* - * we don't do much over here - ***********************************************************************/ - -void mac_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) -{ -} - -/** ********************************************************************* - * we don't do much over here - ***********************************************************************/ - -void mac_begin_paint(rdpContext *context) -{ - rdpGdi* gdi = context->gdi; - gdi->primary->hdc->hwnd->invalid->null = 1; -} - -/** ********************************************************************* - * RDP server wants us to draw new data in the view - ***********************************************************************/ - -void mac_end_paint(rdpContext* context) -{ - int i; - NSRect drawRect; - rdpGdi * gdi; - - if ((context == 0) || (context->gdi == 0)) - return; - - if (context->gdi->primary->hdc->hwnd->invalid->null) - return; - - if (context->gdi->drawing != context->gdi->primary) - return; - - gdi = g_mrdpview->rdp_context->gdi; - - if (g_mrdpview->isRemoteApp && g_mrdpview->currentWindow) { - [[g_mrdpview->currentWindow view] updateDisplay]; - return; - } - - for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++) - { - drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x; - drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y; - drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w; - drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h; - - convert_color_space(g_mrdpview->pixel_data, (char *) gdi->primary_buffer, &drawRect, g_mrdpview->width, g_mrdpview->height); - - [g_mrdpview setNeedsDisplayInRect:drawRect]; - } - gdi->primary->hdc->hwnd->ninvalid = 0; -} - -/** ********************************************************************* - * called when data is available on a socket - ***********************************************************************/ - -void skt_activity_cb( - CFSocketRef s, - CFSocketCallBackType callbackType, - CFDataRef address, - const void *data, - void *info - ) -{ - if (!freerdp_check_fds(info)) { - // lost connection or did not connect - [NSApp terminate:nil]; - } -} - -/** ********************************************************************* - * called when data is available on a virtual channel - ***********************************************************************/ - -void channel_activity_cb( - CFSocketRef s, - CFSocketCallBackType callbackType, - CFDataRef address, - const void *data, - void *info - ) -{ - freerdp *inst = (freerdp *) info; - RDP_EVENT* event; - - freerdp_channels_check_fds(inst->context->channels, inst); - event = freerdp_channels_pop_event(inst->context->channels); - if (event) { - switch (event->event_class) - { - case RDP_EVENT_CLASS_RAIL: - mac_process_rail_event(inst, event); - break; - - case RDP_EVENT_CLASS_CLIPRDR: - process_cliprdr_event(inst, event); - break; - } - } -} - -/** ********************************************************************* - * setup callbacks for data availability on sockets - ***********************************************************************/ - -int register_fds(int *fds, int count, void *inst) -{ - int i; - CFSocketRef skt_ref; - CFSocketContext skt_context = { 0, inst, NULL, NULL, NULL }; - - for (i = 0; i < count; i++) - { - skt_ref = CFSocketCreateWithNative(NULL, fds[i], kCFSocketReadCallBack, skt_activity_cb, &skt_context); - g_mrdpview->run_loop_src = CFSocketCreateRunLoopSource(NULL, skt_ref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), g_mrdpview->run_loop_src, kCFRunLoopDefaultMode); - CFRelease(skt_ref); - } - return 0; -} - -/** ********************************************************************* - * setup callbacks for data availability on channels - ***********************************************************************/ - -int register_channel_fds(int *fds, int count, void *inst) -{ - int i; - CFSocketRef skt_ref; - CFSocketContext skt_context = { 0, inst, NULL, NULL, NULL }; - - for (i = 0; i < count; i++) - { - skt_ref = CFSocketCreateWithNative(NULL, fds[i], kCFSocketReadCallBack, channel_activity_cb, &skt_context); - g_mrdpview->run_loop_src_channels = CFSocketCreateRunLoopSource(NULL, skt_ref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), g_mrdpview->run_loop_src_channels, kCFRunLoopDefaultMode); - CFRelease(skt_ref); - } - return 0; -} - -/** ********************************************************************* - * called when channel data is available - ***********************************************************************/ - -int receive_channel_data(freerdp *inst, int chan_id, uint8 *data, int size, int flags, int total_size) -{ - return freerdp_channels_data(inst, chan_id, data, size, flags, total_size); -} - -/** ********************************************************************* - * convert an array containing ARGB data to RGBA - ***********************************************************************/ - -void convert_color_space(char *dest, char *src, NSRect* drawRect, int width, int height) -{ - int i; - int j; - int x; - int y; - int cx; - int cy; - int pixel; - int pixel1; - int pixel2; - int* src32; - int* dst32; - - if ((!dest) || (!src)) { - return; - } - - x = drawRect->origin.x; - y = drawRect->origin.y; - cx = drawRect->size.width; - cy = drawRect->size.height; - - for (j = 0; j < cy; j++) - { - src32 = (int*)(src + ((y + j) * width + x) * 4); - dst32 = (int*)(dest + ((y + j) * width + x) * 4); - for (i = 0; i < cx; i++) - { - pixel = *src32; - pixel1 = (pixel & 0x00ff0000) >> 16; - pixel2 = (pixel & 0x000000ff) << 16; - pixel = (pixel & 0xff00ff00) | pixel1 | pixel2; - *dst32 = pixel; - src32++; - dst32++; - } - } - - drawRect->origin.y = height - drawRect->origin.y - drawRect->size.height; -} - -/** - * 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. - * - * @param settings - * @param name - * @param plugin_data - * @param user_data - * - * @return 1 - */ - -int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data) -{ - rdpChannels* channels = (rdpChannels*) user_data; - - freerdp_channels_load_plugin(channels, settings, name, plugin_data); - return 1; -} - -/* - * stuff related to clipboard redirection - */ - -/** - * remote system has requested clipboard data from local system - */ - -void cliprdr_process_cb_data_request_event(freerdp *inst) -{ - RDP_CB_DATA_RESPONSE_EVENT *event; - NSArray *types; - int len; - - event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, - RDP_EVENT_TYPE_CB_DATA_RESPONSE, NULL, NULL); - types = [NSArray arrayWithObject:NSStringPboardType]; - NSString *str = [g_mrdpview->pasteboard_rd availableTypeFromArray:types]; - if (str == nil) - { - event->data = NULL; - event->size = 0; - } - else - { - NSString *data = [g_mrdpview->pasteboard_rd stringForType:NSStringPboardType]; - len = (int) ([data length] * 2 + 2); - event->data = malloc(len); - [data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding]; - event->size = len; - } - freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); -} - -void cliprdr_send_data_request(freerdp *inst, uint32 format) -{ - RDP_CB_DATA_REQUEST_EVENT* event; - - event = (RDP_CB_DATA_REQUEST_EVENT *) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, - RDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL); - event->format = format; - freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); -} - -/** - * at the moment, only the following formats are supported - * CB_FORMAT_TEXT - * CB_FORMAT_UNICODETEXT - */ - -void cliprdr_process_cb_data_response_event(freerdp *inst, RDP_CB_DATA_RESPONSE_EVENT *event) -{ - NSString *str; - NSArray *types; - - if (event->size == 0) { - return; - } - - if (g_mrdpview->pasteboard_format == CB_FORMAT_TEXT || g_mrdpview->pasteboard_format == CB_FORMAT_UNICODETEXT) { - str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2]; - types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; - [g_mrdpview->pasteboard_wr declareTypes:types owner:g_mrdpview]; - [g_mrdpview->pasteboard_wr setString:str forType:NSStringPboardType]; - } -} - -void cliprdr_process_cb_monitor_ready_event(freerdp* inst) -{ - RDP_EVENT* event; - RDP_CB_FORMAT_LIST_EVENT* format_list_event; - - event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); - - format_list_event = (RDP_CB_FORMAT_LIST_EVENT*)event; - format_list_event->num_formats = 0; - - freerdp_channels_send_event(inst->context->channels, event); -} - -/** - * list of supported clipboard formats; currently only the following are supported - * CB_FORMAT_TEXT - * CB_FORMAT_UNICODETEXT - */ - -void cliprdr_process_cb_format_list_event(freerdp *inst, RDP_CB_FORMAT_LIST_EVENT* event) -{ - int i; - - if (event->num_formats == 0) { - return; - } - - for (i = 0; i < event->num_formats; i++) - { - switch (event->formats[i]) - { - case CB_FORMAT_RAW: - printf("CB_FORMAT_RAW: not yet supported\n"); - break; - - case CB_FORMAT_TEXT: - case CB_FORMAT_UNICODETEXT: - g_mrdpview->pasteboard_format = CB_FORMAT_UNICODETEXT; - cliprdr_send_data_request(inst, 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; - } - } -} - -void process_cliprdr_event(freerdp *inst, RDP_EVENT *event) -{ - if (event) { - switch (event->event_type) - { - // Monitor Ready PDU is sent by server to indicate that it has been - // inited and is ready. This PDU is transmitted by the server after it has sent - // Clipboard Capabilities PDU - case RDP_EVENT_TYPE_CB_MONITOR_READY: - cliprdr_process_cb_monitor_ready_event(inst); - break; - - // 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 - case RDP_EVENT_TYPE_CB_FORMAT_LIST: - cliprdr_process_cb_format_list_event(inst, (RDP_CB_FORMAT_LIST_EVENT*) event); - break; - - // 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 - case RDP_EVENT_TYPE_CB_DATA_REQUEST: - cliprdr_process_cb_data_request_event(inst); - break; - - // 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 - case RDP_EVENT_TYPE_CB_DATA_RESPONSE: - cliprdr_process_cb_data_response_event(inst, (RDP_CB_DATA_RESPONSE_EVENT*) event); - break; - - default: - printf("process_cliprdr_event: unknown event type %d\n", event->event_type); - break; - } - freerdp_event_free(event); - } -} - -void cliprdr_send_supported_format_list(freerdp *inst) -{ - RDP_CB_FORMAT_LIST_EVENT* event; - - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, - RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); - - event->formats = (uint32 *) malloc(sizeof(uint32) * 1); - event->num_formats = 1; - event->formats[0] = CB_FORMAT_UNICODETEXT; - freerdp_channels_send_event(inst->context->channels, (RDP_EVENT*) event); -} - -/**************************************************************************************** - * * - * * - * RemoteApp (RAIL) related stuff goes here * - * * - * * - ****************************************************************************************/ - -void mac_process_rail_event(freerdp *inst, RDP_EVENT *event) -{ - switch (event->event_type) - { - case RDP_EVENT_TYPE_RAIL_CHANNEL_GET_SYSPARAMS: - mac_process_rail_get_sysparams_event(inst->context->channels, event); - break; - - case RDP_EVENT_TYPE_RAIL_CHANNEL_EXEC_RESULTS: - mac_process_rail_exec_result_event(inst->context->channels, event); - break; - - case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_SYSPARAM: - mac_process_rail_server_sysparam_event(inst->context->channels, event); - break; - - case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_MINMAXINFO: - mac_process_rail_server_minmaxinfo_event(inst->context->channels, event); - break; - - case RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_LOCALMOVESIZE: - mac_process_rail_server_localmovesize_event(inst, event); - break; - - case RDP_EVENT_TYPE_RAIL_CHANNEL_APPID_RESP: - //xf_process_rail_appid_resp_event(xfi, channels, event); - break; - - case RDP_EVENT_TYPE_RAIL_CHANNEL_LANGBARINFO: - //xf_process_rail_langbarinfo_event(xfi, channels, event); - break; - } -} - -void mac_rail_CreateWindow(rdpRail *rail, rdpWindow *window) -{ - boolean centerWindow = NO; - boolean moveWindow = NO; - boolean displayAsModal = NO; - NSMutableArray * ma = g_mrdpview->windows; - - // make sure window fits resolution - if (window->windowWidth > g_mrdpview->width) - window->windowWidth = g_mrdpview->width; - - if (window->windowHeight > g_mrdpview->height) - window->windowHeight = g_mrdpview->height; - - // center main window, which is the first to be created - if ([ma count] == 0) { - centerWindow = YES; - moveWindow = YES; - } - - if ((window->extendedStyle & WS_EX_TOPMOST) || (window->extendedStyle & WS_EX_TOOLWINDOW)) { - [g_mrdpview->currentWindow view]->skipMoveWindowOnce = TRUE; - moveWindow = YES; - - // convert from windows to Mac cords - window->windowOffsetY = g_mrdpview->height - window->windowOffsetY - window->windowHeight; - } - else if (window->style & WS_POPUP) { - centerWindow = YES; - moveWindow = YES; - } - else { - } - - // create NSWindow - NSRect winFrame = NSMakeRect(window->windowOffsetX, window->windowOffsetY, - window->windowWidth, window->windowHeight); - if (centerWindow) - apple_center_window(&winFrame); - - MRDPRailWindow * newWindow = [[MRDPRailWindow alloc] initWithContentRect:winFrame - styleMask:NSTitledWindowMask | NSResizableWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - - // this does not work if specified during window creation in above code - [newWindow setStyleMask:NSBorderlessWindowMask]; - - if (moveWindow) { - // let RDP server know that window has moved - RAIL_WINDOW_MOVE_ORDER windowMove; - apple_to_windowMove(&winFrame, &windowMove); - windowMove.windowId = window->windowId; - mac_send_rail_client_event(g_mrdpview->rdp_instance->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); - } - - // create MRDPRailView and add to above window - NSRect viewFrame = NSMakeRect(window->clientOffsetX, window->clientOffsetY, - window->clientAreaWidth, window->clientAreaHeight); - - MRDPRailView * newView = [[MRDPRailView alloc] initWithFrame:viewFrame]; - [newView setRdpInstance:g_mrdpview->rdp_instance width:g_mrdpview->width andHeight:g_mrdpview->height windowID: window->windowId]; - [newWindow setContentView:newView]; - - // save new window - MRDPWindow * mrdpWindow = [[MRDPWindow alloc] init]; - [mrdpWindow setWindowID:window->windowId]; - [mrdpWindow setWindow:newWindow]; - [mrdpWindow setView:newView]; - - // add to list of windows - [ma addObject:mrdpWindow]; - - // make new window current - g_mrdpview->currentWindow = mrdpWindow; - - if (displayAsModal) { - // display as modal window - NSModalSession session = [NSApp beginModalSessionForWindow:newWindow]; - while (1) - { - if ([NSApp runModalSession:session] != NSRunContinuesResponse) - break; - } - [NSApp endModalSession:session]; - } - else { - [newWindow makeKeyAndOrderFront:NSApp]; - //[[g_mrdpview window] resignFirstResponder]; - //[g_mrdpview resignFirstResponder]; - //[[g_mrdpview window] setNextResponder:newWindow]; - } - - return; -} - -void mac_rail_MoveWindow(rdpRail *rail, rdpWindow *window) -{ - if (g_mrdpview->currentWindow) { - rail_MoveWindow(rail, window); - return; - } -} - -void mac_rail_ShowWindow(rdpRail *rail, rdpWindow *window, uint8 state) -{ -} - -void mac_rail_SetWindowText(rdpRail *rail, rdpWindow *window) -{ -} - -void mac_rail_SetWindowIcon(rdpRail *rail, rdpWindow *window, rdpIcon *icon) -{ -} - -void mac_rail_SetWindowRects(rdpRail *rail, rdpWindow *window) -{ -} - -void mac_rail_SetWindowVisibilityRects(rdpRail *rail, rdpWindow *window) -{ -} - -/** ********************************************************************* - * destroy window created in mac_rail_CreateWindow() - ***********************************************************************/ - -void mac_rail_DestroyWindow(rdpRail *rail, rdpWindow *window) -{ - int count = 0; - - for (MRDPWindow * win in g_mrdpview->windows) - { - if ([win windowID] == window->windowId) { - //[[win window] close]; - [win setView:nil]; - [win setWindow:nil]; - [g_mrdpview->windows removeObject:win]; - count = [g_mrdpview->windows count]; - if (count) { - g_mrdpview->currentWindow = [g_mrdpview->windows objectAtIndex:count - 1]; - //[[g_mrdpview window] makeKeyAndOrderFront:[g_mrdpview->currentWindow window]]; - [[g_mrdpview->currentWindow window] makeKeyAndOrderFront:NSApp]; - } - else { - g_mrdpview->currentWindow = nil; - [NSApp terminate:nil]; - } - return; - } - } -} - -void mac_rail_register_callbacks(freerdp *inst, rdpRail *rail) -{ - rail->extra = (void *) inst; - rail->rail_CreateWindow = mac_rail_CreateWindow; - rail->rail_MoveWindow = mac_rail_MoveWindow; - rail->rail_ShowWindow = mac_rail_ShowWindow; - rail->rail_SetWindowText = mac_rail_SetWindowText; - rail->rail_SetWindowIcon = mac_rail_SetWindowIcon; - rail->rail_SetWindowRects = mac_rail_SetWindowRects; - rail->rail_SetWindowVisibilityRects = mac_rail_SetWindowVisibilityRects; - rail->rail_DestroyWindow = mac_rail_DestroyWindow; -} - -/** ********************************************************************* - * set work area size, which is the portion of the screen not obscured - * by the system taskbar or by application desktop toolbars - ************************************************************************/ - -void mac_process_rail_get_sysparams_event(rdpChannels *channels, RDP_EVENT *event) -{ - RAIL_SYSPARAM_ORDER * sysparam; - sysparam = (RAIL_SYSPARAM_ORDER *) event->user_data; - - sysparam->workArea.left = 0; - sysparam->workArea.top = 22; - sysparam->workArea.right = g_mrdpview->width; - sysparam->workArea.bottom = g_mrdpview->height - 22; - - sysparam->taskbarPos.left = 0; - sysparam->taskbarPos.top = 0; - sysparam->taskbarPos.right = 0; - sysparam->taskbarPos.bottom = 0; - - sysparam->dragFullWindows = false; - - mac_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SET_SYSPARAMS, sysparam); -} - -void mac_process_rail_server_sysparam_event(rdpChannels* channels, RDP_EVENT* event) -{ - RAIL_SYSPARAM_ORDER* sysparam = (RAIL_SYSPARAM_ORDER*) event->user_data; - - switch (sysparam->param) - { - case SPI_SET_SCREEN_SAVE_ACTIVE: - break; - - case SPI_SET_SCREEN_SAVE_SECURE: - break; - } -} - -/** ********************************************************************* - * server returned result of exec'ing remote app on server - ************************************************************************/ - -void mac_process_rail_exec_result_event(rdpChannels* channels, RDP_EVENT* event) -{ - RAIL_EXEC_RESULT_ORDER* exec_result; - - exec_result = (RAIL_EXEC_RESULT_ORDER*) event->user_data; - - if (exec_result->execResult != RAIL_EXEC_S_OK) { - printf("RAIL exec error: execResult=%s NtError=0x%X\n", - error_code_names[exec_result->execResult], exec_result->rawResult); - g_mrdpview->is_connected = FALSE; - [g_mrdpview rdpRemoteAppError]; - } - else { - mac_rail_enable_remoteapp_mode(); - } -} - -/** ********************************************************************* - * sent by server when a window move or resize on the server is being - * initiated. this PDU contains info about the min and max extents - * to which the window can be moved or sized - ************************************************************************/ - -void mac_process_rail_server_minmaxinfo_event(rdpChannels* channels, RDP_EVENT* event) -{ - //RAIL_MINMAXINFO_ORDER * minmax = (RAIL_MINMAXINFO_ORDER*) event->user_data; -} - -/** ********************************************************************* - * sent by the server when a window on the server is beginning a move or - * resize; use this info to initiate a local move or resize of the - * corresponding local window - ************************************************************************/ - -void mac_process_rail_server_localmovesize_event(freerdp *inst, RDP_EVENT *event) -{ - RAIL_LOCALMOVESIZE_ORDER * moveSize = (RAIL_LOCALMOVESIZE_ORDER *) event->user_data; - - switch (moveSize->moveSizeType) { - case RAIL_WMSZ_LEFT: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_LEFT; - break; - - case RAIL_WMSZ_RIGHT: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_RIGHT; - break; - - case RAIL_WMSZ_TOP: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_TOP; - break; - - case RAIL_WMSZ_TOPLEFT: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_TOPLEFT; - break; - - case RAIL_WMSZ_TOPRIGHT: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_TOPRIGHT; - break; - - case RAIL_WMSZ_BOTTOM: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_BOTTOM; - break; - - case RAIL_WMSZ_BOTTOMLEFT: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_BOTTOMLEFT; - break; - - case RAIL_WMSZ_BOTTOMRIGHT: - [g_mrdpview->currentWindow view]->localMoveType = RAIL_WMSZ_BOTTOMRIGHT; - break; - - case RAIL_WMSZ_MOVE: - if (moveSize->isMoveSizeStart) { - // local window move in progress - [g_mrdpview->currentWindow view]->isMoveSizeInProgress = YES; - [g_mrdpview->currentWindow view]->saveInitialDragLoc = YES; - - return; - } - - // local move has completed - [g_mrdpview->currentWindow view]->isMoveSizeInProgress = NO; - [g_mrdpview->currentWindow view]->saveInitialDragLoc = NO; - - NSRect r = [[[g_mrdpview->currentWindow view] window] frame]; - - // let RDP server know where this window is located - RAIL_WINDOW_MOVE_ORDER windowMove; - apple_to_windowMove(&r, &windowMove); - mac_send_rail_client_event(inst->context->channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &windowMove); - - break; - - case RAIL_WMSZ_KEYMOVE: - printf("!!!! RAIL_WMSZ_KEYMOVE\n"); - break; - - case RAIL_WMSZ_KEYSIZE: - printf("!!!! RAIL_WMSZ_KEYSIZE\n"); - break; - - default: - break; - } - - if (moveSize->isMoveSizeStart == 0) - [g_mrdpview->currentWindow view]->localMoveType = 0; - - return; -} - -void mac_send_rail_client_event(rdpChannels *channels, uint16 event_type, void *param) -{ - RDP_EVENT *out_event = NULL; - void *payload = NULL; - - payload = rail_clone_order(event_type, param); - if (payload != NULL) { - out_event = freerdp_event_new(RDP_EVENT_CLASS_RAIL, event_type, - mac_on_free_rail_client_event, payload); - freerdp_channels_send_event(channels, out_event); - } -} - -void mac_on_free_rail_client_event(RDP_EVENT* event) -{ - if (event->event_class == RDP_EVENT_CLASS_RAIL) - { - rail_free_cloned_order(event->event_type, event->user_data); - } -} - -void mac_rail_enable_remoteapp_mode() -{ - if (!g_mrdpview->isRemoteApp) - g_mrdpview->isRemoteApp = TRUE; -} - -/** - * given a rect with 0,0 at the bottom left (apple cords) - * convert it to a rect with 0,0 at the top left (windows cords) - */ - -void apple_to_windows_cords(NSRect * r) -{ - r->origin.y = g_mrdpview->height - (r->origin.y + r->size.height); -} - -/** - * 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) - */ - -void windows_to_apple_cords(NSRect * r) -{ - r->origin.y = g_mrdpview->height - (r->origin.y + r->size.height); -} - -void apple_center_window(NSRect * r) -{ - r->origin.x = (g_mrdpview->width - r->size.width) / 2; - r->origin.y = (g_mrdpview->height - r->size.height) / 2; -} - -void apple_to_windowMove(NSRect * r, RAIL_WINDOW_MOVE_ORDER * windowMove) -{ - windowMove->left = (uint16) r->origin.x; // x-cord of top left corner - windowMove->top = (uint16) g_mrdpview->height - (r->origin.y + r->size.height); // y-cord of top left corner - windowMove->right = (uint16) (windowMove->left + r->size.width); // x-cord of bottom right corner - windowMove->bottom = (uint16) (windowMove->top + r->size.height); // y-cord of bottom right corner -} - -void printScreenInfo() -{ - - int count = [[NSScreen screens] count]; - - for (int i = 0; i< count; i++) - { - NSRect r = [[[NSScreen screens] objectAtIndex:i] frame]; - - printf("screen %d: rect(%d,%d %dx%d)\n", - i, (int) r.origin.x, (int) r.origin.y, - (int) r.size.width, (int) r.size.height); - } - printf("\n"); -} - -@end From c74cae42094cce3b75a0cf2dfb5848def0ee0df6 Mon Sep 17 00:00:00 2001 From: xangis Date: Fri, 20 Jul 2012 14:05:06 -0700 Subject: [PATCH 16/27] Add building channels for Windows and stubs for clipboard reader. --- CMakeLists.txt | 4 +- client/Windows/CMakeLists.txt | 74 ++++++++++++------------ client/Windows/wf_cliprdr.c | 106 ++++++++++++++++++++++++++++++++++ client/Windows/wf_cliprdr.h | 33 +++++++++++ client/Windows/wfreerdp.c | 3 + 5 files changed, 181 insertions(+), 39 deletions(-) create mode 100644 client/Windows/wf_cliprdr.c create mode 100644 client/Windows/wf_cliprdr.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 71d133634..e76a60cac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,9 +161,7 @@ add_subdirectory(libfreerdp-channels) add_subdirectory(libfreerdp-locale) add_subdirectory(libfreerdp-core) -if(NOT WIN32) - add_subdirectory(channels) -endif() +add_subdirectory(channels) option(WITH_CLIENT "Build client binaries" ON) if(WITH_CLIENT) diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index 68b46713f..1aefab7ef 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -1,36 +1,38 @@ -# FreeRDP: A Remote Desktop Protocol Client -# FreeRDP Windows cmake build script -# -# Copyright 2011 O.S. Systems Software Ltda. -# Copyright 2011 Otavio Salvador -# Copyright 2011 Marc-Andre Moreau -# -# 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. - -add_executable(wfreerdp WIN32 - wf_gdi.c - wf_gdi.h - wf_event.c - wf_event.h - wf_graphics.c - wf_graphics.h - wfreerdp.c - wfreerdp.h) - -target_link_libraries(wfreerdp freerdp-core) -target_link_libraries(wfreerdp freerdp-gdi) -target_link_libraries(wfreerdp freerdp-utils) -target_link_libraries(wfreerdp freerdp-codec) -target_link_libraries(wfreerdp freerdp-channels) - -install(TARGETS wfreerdp DESTINATION ${CMAKE_INSTALL_BINDIR}) +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP Windows cmake build script +# +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# 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. + +add_executable(wfreerdp WIN32 + wf_gdi.c + wf_gdi.h + wf_event.c + wf_event.h + wf_graphics.c + wf_graphics.h + wf_cliprdr.c + wf_cliprdr.h + wfreerdp.c + wfreerdp.h) + +target_link_libraries(wfreerdp freerdp-core) +target_link_libraries(wfreerdp freerdp-gdi) +target_link_libraries(wfreerdp freerdp-utils) +target_link_libraries(wfreerdp freerdp-codec) +target_link_libraries(wfreerdp freerdp-channels) + +install(TARGETS wfreerdp DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/client/Windows/wf_cliprdr.c b/client/Windows/wf_cliprdr.c new file mode 100644 index 000000000..5ce19004e --- /dev/null +++ b/client/Windows/wf_cliprdr.c @@ -0,0 +1,106 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Windows Clipboard Redirection + * + * Copyright 2012 Jason Champion + * + * 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. + */ + +#include +#include +#include +#include + +#include "wf_cliprdr.h" + +void wf_cliprdr_init(wfInfo* wfi, rdpChannels* chanman) +{ + +} + +void wf_cliprdr_uninit(wfInfo* wfi) +{ + +} + +static void wf_cliprdr_process_cb_monitor_ready_event(wfInfo* wfi) +{ + +} + +static void wf_cliprdr_process_cb_data_request_event(wfInfo* wfi, RDP_CB_DATA_REQUEST_EVENT* event) +{ + +} + +static void wf_cliprdr_process_cb_format_list_event(wfInfo* wfi, RDP_CB_FORMAT_LIST_EVENT* event) +{ + +} + +static void wf_cliprdr_process_cb_data_response_event(wfInfo* wfi, RDP_CB_DATA_RESPONSE_EVENT* event) +{ + +} + +void wf_process_cliprdr_event(wfInfo* wfi, RDP_EVENT* event) +{ + switch (event->event_type) + { + case RDP_EVENT_TYPE_CB_MONITOR_READY: + wf_cliprdr_process_cb_monitor_ready_event(wfi); + break; + + case RDP_EVENT_TYPE_CB_FORMAT_LIST: + wf_cliprdr_process_cb_format_list_event(wfi, (RDP_CB_FORMAT_LIST_EVENT*) event); + break; + + case RDP_EVENT_TYPE_CB_DATA_REQUEST: + wf_cliprdr_process_cb_data_request_event(wfi, (RDP_CB_DATA_REQUEST_EVENT*) event); + break; + + case RDP_EVENT_TYPE_CB_DATA_RESPONSE: + wf_cliprdr_process_cb_data_response_event(wfi, (RDP_CB_DATA_RESPONSE_EVENT*) event); + break; + + default: + break; + } +} + +boolean wf_cliprdr_process_selection_notify(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return true; +} + +boolean wf_cliprdr_process_selection_request(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return true; +} + +boolean wf_cliprdr_process_selection_clear(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return true; +} + +boolean wf_cliprdr_process_property_notify(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return true; +} + +void wf_cliprdr_check_owner(wfInfo* wfi) +{ + +} + diff --git a/client/Windows/wf_cliprdr.h b/client/Windows/wf_cliprdr.h new file mode 100644 index 000000000..99e38b63f --- /dev/null +++ b/client/Windows/wf_cliprdr.h @@ -0,0 +1,33 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Windows Clipboard Redirection + * + * Copyright 2012 Jason Champion + * + * 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. + */ +#ifndef __WF_CLIPRDR_H +#define __WF_CLIPRDR_H + +#include "wfreerdp.h" + +void wf_cliprdr_init(wfInfo* wfi, rdpChannels* chanman); +void wf_cliprdr_uninit(wfInfo* wfi); +void wf_process_cliprdr_event(wfInfo* wfi, RDP_EVENT* event); +boolean wf_cliprdr_process_selection_notify(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +boolean wf_cliprdr_process_selection_request(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +boolean wf_cliprdr_process_selection_clear(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +boolean wf_cliprdr_process_property_notify(wfInfo* wfi, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +void wf_cliprdr_check_owner(wfInfo* wfi); + +#endif /* __WF_CLIPRDR_H */ diff --git a/client/Windows/wfreerdp.c b/client/Windows/wfreerdp.c index 7c1d79144..916ddeb21 100644 --- a/client/Windows/wfreerdp.c +++ b/client/Windows/wfreerdp.c @@ -41,6 +41,7 @@ #include "wf_gdi.h" #include "wf_graphics.h" +#include "wf_cliprdr.h" #include "wfreerdp.h" @@ -383,6 +384,8 @@ boolean wf_post_connect(freerdp* instance) freerdp_channels_post_connect(instance->context->channels, instance); + wf_cliprdr_init(wfi, instance->context->channels); + return true; } From 238cf848c2ee460cec1560e2c5cf5522b15fdf28 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Tue, 24 Jul 2012 12:05:22 -0700 Subject: [PATCH 17/27] codecs: added --jpeg command line, moved jpeg hack to bitmap cache v3, added bcv3 xxx setting --- client/X11/xf_graphics.c | 50 +++++++++++++++++++++++++++++----- include/freerdp/constants.h | 1 + include/freerdp/graphics.h | 2 +- include/freerdp/settings.h | 6 +++- libfreerdp-cache/bitmap.c | 50 ++++++++++++++++++++++++++++++++++ libfreerdp-core/capabilities.c | 33 ++++++++++++++++++++-- libfreerdp-gdi/graphics.c | 47 ++++++++++++++++++++++++++++---- libfreerdp-gdi/graphics.h | 2 +- libfreerdp-utils/args.c | 44 ++++++++++++++++++++++++++++++ 9 files changed, 217 insertions(+), 18 deletions(-) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index ce9e028e6..cc14ffd29 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -25,6 +25,7 @@ #endif #include +#include #include #include "xf_graphics.h" @@ -61,7 +62,7 @@ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) { if (data != bitmap->data) xfree(bitmap->data); - + bitmap->data = data; } } @@ -106,9 +107,14 @@ void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) } void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed) + uint8* data, int width, int height, int bpp, int length, int compressed) { uint16 size; + RFX_MESSAGE* msg; + uint8* src; + uint8* dst; + int yindex; + int xindex; size = width * height * (bpp + 7) / 8; @@ -117,22 +123,52 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed == 2) + if (compressed == 4) + { + printf("xf_Bitmap_Decompress: nsc not done\n"); + } + else if (compressed == 3) + { + xfInfo* xfi = ((xfContext*)context)->xfi; + rfx_context_set_pixel_format(xfi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(xfi->rfx_context, data, length); + if (msg == NULL) + { + printf("xf_Bitmap_Decompress: rfx Decompression Failed\n"); + } + else + { + for (yindex = 0; yindex < height; yindex++) + { + src = msg->tiles[0]->data + yindex * 64 * 4; + dst = bitmap->data + yindex * width * 3; + for (xindex = 0; xindex < width; xindex++) + { + *(dst++) = *(src++); + *(dst++) = *(src++); + *(dst++) = *(src++); + src++; + } + } + rfx_message_free(xfi->rfx_context, msg); + } + } + else if (compressed == 2) { if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) { - printf("jpeg Decompression Failed\n"); + printf("xf_Bitmap_Decompress: jpeg Decompression Failed\n"); } } - else if (compressed) + else if (compressed == 1) { boolean status; status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - if (status != true) + if (status == false) { - printf("Bitmap Decompression Failed\n"); + printf("xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); } } else diff --git a/include/freerdp/constants.h b/include/freerdp/constants.h index 88b3c321f..c9bcf67c7 100644 --- a/include/freerdp/constants.h +++ b/include/freerdp/constants.h @@ -27,6 +27,7 @@ enum RDP_CODEC_ID { CODEC_ID_NONE = 0x00, CODEC_ID_NSCODEC = 0x01, + CODEC_ID_JPEG = 0x02, CODEC_ID_REMOTEFX = 0x03 }; diff --git a/include/freerdp/graphics.h b/include/freerdp/graphics.h index 033ff3a23..bf0a00a84 100644 --- a/include/freerdp/graphics.h +++ b/include/freerdp/graphics.h @@ -35,7 +35,7 @@ typedef void (*pBitmap_New)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Free)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Paint)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Decompress)(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed); + uint8* data, int width, int height, int bpp, int length, int compressed); typedef void (*pBitmap_SetSurface)(rdpContext* context, rdpBitmap* bitmap, boolean primary); struct rdp_bitmap diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 5ff5a0d4e..572be4cba 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -388,7 +388,11 @@ struct rdp_settings ALIGN64 uint32 ns_codec_id; /* 283 */ ALIGN64 uint32 rfx_codec_mode; /* 284 */ ALIGN64 boolean frame_acknowledge; /* 285 */ - ALIGN64 uint64 paddingM[296 - 286]; /* 286 */ + ALIGN64 boolean jpeg_codec; /* 286 */ + ALIGN64 uint32 jpeg_codec_id; /* 287 */ + ALIGN64 uint32 jpeg_quality; /* 288 */ + ALIGN64 uint32 preferred_codec_id; /* 289 */ + ALIGN64 uint64 paddingM[296 - 290]; /* 290 */ /* Recording */ ALIGN64 boolean dump_rfx; /* 296 */ diff --git a/libfreerdp-cache/bitmap.c b/libfreerdp-cache/bitmap.c index 6d42d263d..dede3a715 100644 --- a/libfreerdp-cache/bitmap.c +++ b/libfreerdp-cache/bitmap.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -125,6 +126,54 @@ void update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cach bitmap_cache_put(cache->bitmap, cache_bitmap_v2->cacheId, cache_bitmap_v2->cacheIndex, bitmap); } +void update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3) +{ + rdpBitmap* bitmap; + rdpBitmap* prevBitmap; + rdpCache* cache = context->cache; + BITMAP_DATA_EX* bitmapData = &cache_bitmap_v3->bitmapData; + boolean compression; + + bitmap = Bitmap_Alloc(context); + + Bitmap_SetDimensions(context, bitmap, bitmapData->width, bitmapData->height); + + if (cache_bitmap_v3->bitmapData.bpp == 0) + { + /* Workaround for Windows 8 bug where bitmapBpp is not set */ + cache_bitmap_v3->bitmapData.bpp = context->instance->settings->color_depth; + } + + switch (bitmapData->codecID) + { + case CODEC_ID_JPEG: + compression = 2; + break; + case CODEC_ID_REMOTEFX: + compression = 3; + break; + case CODEC_ID_NSCODEC: + compression = 4; + break; + default: + compression = 1; + break; + } + + bitmap->Decompress(context, bitmap, + bitmapData->data, bitmap->width, bitmap->height, + bitmapData->bpp, bitmapData->length, compression); + + bitmap->New(context, bitmap); + + prevBitmap = bitmap_cache_get(cache->bitmap, cache_bitmap_v3->cacheId, cache_bitmap_v3->cacheIndex); + + if (prevBitmap != NULL) + Bitmap_Free(context, prevBitmap); + + bitmap_cache_put(cache->bitmap, cache_bitmap_v3->cacheId, cache_bitmap_v3->cacheIndex, bitmap); +} + void update_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap_update) { int i; @@ -229,6 +278,7 @@ void bitmap_cache_register_callbacks(rdpUpdate* update) update->secondary->CacheBitmap = update_gdi_cache_bitmap; update->secondary->CacheBitmapV2 = update_gdi_cache_bitmap_v2; + update->secondary->CacheBitmapV3 = update_gdi_cache_bitmap_v3; update->BitmapUpdate = update_gdi_bitmap_update; } diff --git a/libfreerdp-core/capabilities.c b/libfreerdp-core/capabilities.c index 43615cdad..080ad9525 100644 --- a/libfreerdp-core/capabilities.c +++ b/libfreerdp-core/capabilities.c @@ -62,6 +62,9 @@ static const char* const CAPSET_TYPE_STRINGS[] = /* CODEC_GUID_NSCODEC 0xCA8D1BB9000F154F589FAE2D1A87E2D6 */ #define CODEC_GUID_NSCODEC "\xb9\x1b\x8d\xca\x0f\x00\x4f\x15\x58\x9f\xae\x2d\x1a\x87\xe2\xd6" +/* CODEC_GUID_JPEG 0x430C9EED1BAF4CE6869ACB8B37B66237*/ +#define CODEC_GUID_JPEG "\xE6\x4C\xAF\x1B\xED\x9E\x0C\x43\x86\x9A\xCB\x8B\x37\xB6\x62\x37" + void rdp_read_capability_set_header(STREAM* s, uint16* length, uint16* type) { stream_read_uint16(s, *type); /* capabilitySetType */ @@ -1014,7 +1017,6 @@ void rdp_write_bitmap_cache_v2_capability_set(STREAM* s, rdpSettings* settings) header = rdp_capability_set_start(s); cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG; - cacheFlags |= 0x80; /* jpeg hack */ if (settings->persistent_bitmap_cache) cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG; @@ -1529,6 +1531,12 @@ void rdp_write_nsc_client_capability_container(STREAM* s, rdpSettings* settings) stream_write_uint8(s, 3); /* colorLossLevel */ } +void rdp_write_jpeg_client_capability_container(STREAM* s, rdpSettings* settings) +{ + stream_write_uint16(s, 1); /* codecPropertiesLength */ + stream_write_uint8(s, settings->jpeg_quality); +} + /** * Write RemoteFX Server Capability Container.\n * @param s stream @@ -1540,6 +1548,12 @@ void rdp_write_rfx_server_capability_container(STREAM* s, rdpSettings* settings) stream_write_uint32(s, 0); /* reserved */ } +void rdp_write_jpeg_server_capability_container(STREAM* s, rdpSettings* settings) +{ + stream_write_uint16(s, 1); /* codecPropertiesLength */ + stream_write_uint8(s, 75); +} + /** * Write NSCODEC Server Capability Container.\n * @param s stream @@ -1571,6 +1585,8 @@ void rdp_write_bitmap_codecs_capability_set(STREAM* s, rdpSettings* settings) bitmapCodecCount++; if (settings->ns_codec) bitmapCodecCount++; + if (settings->jpeg_codec) + bitmapCodecCount++; stream_write_uint8(s, bitmapCodecCount); @@ -1603,6 +1619,20 @@ void rdp_write_bitmap_codecs_capability_set(STREAM* s, rdpSettings* settings) rdp_write_nsc_client_capability_container(s, settings); } } + if (settings->jpeg_codec) + { + stream_write(s, CODEC_GUID_JPEG, 16); + if (settings->server_mode) + { + stream_write_uint8(s, 0); /* codecID is defined by the client */ + rdp_write_jpeg_server_capability_container(s, settings); + } + else + { + stream_write_uint8(s, CODEC_ID_JPEG); /* codecID */ + rdp_write_jpeg_client_capability_container(s, settings); + } + } rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS); } @@ -2098,4 +2128,3 @@ boolean rdp_send_confirm_active(rdpRdp* rdp) return rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->user_id); } - diff --git a/libfreerdp-gdi/graphics.c b/libfreerdp-gdi/graphics.c index d83ed2031..1ea61d793 100644 --- a/libfreerdp-gdi/graphics.c +++ b/libfreerdp-gdi/graphics.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -88,9 +89,14 @@ void gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) } void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed) + uint8* data, int width, int height, int bpp, int length, int compressed) { uint16 size; + RFX_MESSAGE* msg; + uint8* src; + uint8* dst; + int yindex; + int xindex; size = width * height * (bpp + 7) / 8; @@ -99,11 +105,41 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed == 2) + if (compressed == 4) + { + printf("gdi_Bitmap_Decompress: nsc not done\n"); + } + else if (compressed == 3) + { + rdpGdi* gdi = context->gdi; + rfx_context_set_pixel_format(gdi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(gdi->rfx_context, data, length); + if (msg == NULL) + { + printf("gdi_Bitmap_Decompress: rfx Decompression Failed\n"); + } + else + { + for (yindex = 0; yindex < height; yindex++) + { + src = msg->tiles[0]->data + yindex * 64 * 4; + dst = bitmap->data + yindex * width * 3; + for (xindex = 0; xindex < width; xindex++) + { + *(dst++) = *(src++); + *(dst++) = *(src++); + *(dst++) = *(src++); + src++; + } + } + rfx_message_free(gdi->rfx_context, msg); + } + } + else if (compressed == 2) { if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) { - printf("jpeg Decompression Failed\n"); + printf("gdi_Bitmap_Decompress: jpeg Decompression Failed\n"); } } else if (compressed) @@ -112,9 +148,9 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - if (status != true) + if (status == false) { - printf("Bitmap Decompression Failed\n"); + printf("gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); } } else @@ -244,4 +280,3 @@ void gdi_register_graphics(rdpGraphics* graphics) graphics_register_glyph(graphics, glyph); xfree(glyph); } - diff --git a/libfreerdp-gdi/graphics.h b/libfreerdp-gdi/graphics.h index 3940a44be..35d26855c 100644 --- a/libfreerdp-gdi/graphics.h +++ b/libfreerdp-gdi/graphics.h @@ -28,7 +28,7 @@ HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, int width, int height, int bpp, uint8 void gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap); void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap); void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed); + uint8* data, int width, int height, int bpp, int length, int compressed); void gdi_register_graphics(rdpGraphics* graphics); #endif /* __GDI_GRAPHICS_H */ diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 8e510f9b5..ce7eb4ade 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -86,10 +86,13 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, " --gdi: graphics rendering (hw, sw)\n" " --no-osb: disable offscreen bitmaps\n" " --no-bmp-cache: disable bitmap cache\n" + " --bcv3: codec for bitmap cache v3 (rfx, nsc, jpeg)\n" " --plugin: load a virtual channel plugin\n" " --rfx: enable RemoteFX\n" " --rfx-mode: RemoteFX operational flags (v[ideo], i[mage]), default is video\n" " --nsc: enable NSCodec (experimental)\n" + " --jpeg: enable jpeg codec, uses 75 quality\n" + " --jpegex: enable jpeg and set quality(1..99)\n" " --disable-wallpaper: disables wallpaper\n" " --composition: enable desktop composition\n" " --disable-full-window-drag: disables full window drag\n" @@ -346,6 +349,47 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, return FREERDP_ARGS_PARSE_FAILURE; } } + else if (strcmp("--bcv3", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing codec name\n"); + return FREERDP_ARGS_PARSE_FAILURE; + } + settings->bitmap_cache_v3 = true; + if (strcmp("rfx", argv[index]) == 0) + { + printf("setting rfx\n"); + settings->preferred_codec_id = 3; /* CODEC_ID_REMOTEFX */ + } + else if (strcmp("nsc", argv[index]) == 0) + { + printf("setting codec nsc\n"); + settings->preferred_codec_id = 1; /* CODEC_ID_NSCODEC */ + } + else if (strcmp("jpeg", argv[index]) == 0) + { + printf("setting codec jpeg\n"); + settings->preferred_codec_id = 2; + } + } + else if (strcmp("--jpeg", argv[index]) == 0) + { + settings->jpeg_codec = true; + settings->jpeg_quality = 75; + } + else if (strcmp("--jpegex", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing codec name\n"); + return FREERDP_ARGS_PARSE_FAILURE; + } + settings->jpeg_codec = true; + settings->jpeg_quality = atoi(argv[index]); + } else if (strcmp("--rfx", argv[index]) == 0) { settings->rfx_codec = true; From ea9e5fcbee239ce725b26f7a7008f5261ae09aec Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Tue, 24 Jul 2012 16:54:29 -0700 Subject: [PATCH 18/27] codec: use the CODEC_ID_* names instead of magic numbers --- client/X11/xf_graphics.c | 97 +++++++++++++++++++------------------ include/freerdp/graphics.h | 3 +- libfreerdp-cache/bitmap.c | 42 ++++------------ libfreerdp-gdi/graphics.c | 98 +++++++++++++++++++------------------- libfreerdp-gdi/graphics.h | 3 +- libfreerdp-utils/args.c | 7 +-- 6 files changed, 118 insertions(+), 132 deletions(-) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index cc14ffd29..de3a53a7c 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -107,7 +107,8 @@ void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) } void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, int compressed) + uint8* data, int width, int height, int bpp, int length, + boolean compressed, int codec_id) { uint16 size; RFX_MESSAGE* msg; @@ -115,6 +116,8 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, uint8* dst; int yindex; int xindex; + xfInfo* xfi; + boolean status; size = width * height * (bpp + 7) / 8; @@ -123,57 +126,57 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed == 4) + switch (codec_id) { - printf("xf_Bitmap_Decompress: nsc not done\n"); - } - else if (compressed == 3) - { - xfInfo* xfi = ((xfContext*)context)->xfi; - rfx_context_set_pixel_format(xfi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); - msg = rfx_process_message(xfi->rfx_context, data, length); - if (msg == NULL) - { - printf("xf_Bitmap_Decompress: rfx Decompression Failed\n"); - } - else - { - for (yindex = 0; yindex < height; yindex++) + case CODEC_ID_NSCODEC: + printf("xf_Bitmap_Decompress: nsc not done\n"); + break; + case CODEC_ID_REMOTEFX: + xfi = ((xfContext*)context)->xfi; + rfx_context_set_pixel_format(xfi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(xfi->rfx_context, data, length); + if (msg == NULL) { - src = msg->tiles[0]->data + yindex * 64 * 4; - dst = bitmap->data + yindex * width * 3; - for (xindex = 0; xindex < width; xindex++) + printf("xf_Bitmap_Decompress: rfx Decompression Failed\n"); + } + else + { + for (yindex = 0; yindex < height; yindex++) { - *(dst++) = *(src++); - *(dst++) = *(src++); - *(dst++) = *(src++); - src++; + src = msg->tiles[0]->data + yindex * 64 * 4; + dst = bitmap->data + yindex * width * 3; + for (xindex = 0; xindex < width; xindex++) + { + *(dst++) = *(src++); + *(dst++) = *(src++); + *(dst++) = *(src++); + src++; + } + } + rfx_message_free(xfi->rfx_context, msg); + } + break; + case CODEC_ID_JPEG: + if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) + { + printf("xf_Bitmap_Decompress: jpeg Decompression Failed\n"); + } + break; + default: + if (compressed) + { + status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); + + if (status == false) + { + printf("xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); } } - rfx_message_free(xfi->rfx_context, msg); - } - } - else if (compressed == 2) - { - if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) - { - printf("xf_Bitmap_Decompress: jpeg Decompression Failed\n"); - } - } - else if (compressed == 1) - { - boolean status; - - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - - if (status == false) - { - printf("xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); - } - } - else - { - freerdp_image_flip(data, bitmap->data, width, height, bpp); + else + { + freerdp_image_flip(data, bitmap->data, width, height, bpp); + } + break; } bitmap->compressed = false; diff --git a/include/freerdp/graphics.h b/include/freerdp/graphics.h index bf0a00a84..578feae3b 100644 --- a/include/freerdp/graphics.h +++ b/include/freerdp/graphics.h @@ -35,7 +35,8 @@ typedef void (*pBitmap_New)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Free)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Paint)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Decompress)(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, int compressed); + uint8* data, int width, int height, int bpp, int length, + boolean compressed, int codec_id); typedef void (*pBitmap_SetSurface)(rdpContext* context, rdpBitmap* bitmap, boolean primary); struct rdp_bitmap diff --git a/libfreerdp-cache/bitmap.c b/libfreerdp-cache/bitmap.c index dede3a715..a87e9b550 100644 --- a/libfreerdp-cache/bitmap.c +++ b/libfreerdp-cache/bitmap.c @@ -75,7 +75,8 @@ void update_gdi_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitm bitmap->Decompress(context, bitmap, cache_bitmap->bitmapDataStream, cache_bitmap->bitmapWidth, cache_bitmap->bitmapHeight, - cache_bitmap->bitmapBpp, cache_bitmap->bitmapLength, cache_bitmap->compressed); + cache_bitmap->bitmapBpp, cache_bitmap->bitmapLength, + cache_bitmap->compressed, CODEC_ID_NONE); bitmap->New(context, bitmap); @@ -103,18 +104,10 @@ void update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cach cache_bitmap_v2->bitmapBpp = context->instance->settings->color_depth; } - if (cache_bitmap_v2->compressed && (cache_bitmap_v2->flags & 0x80)) - { - bitmap->Decompress(context, bitmap, - cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight, - cache_bitmap_v2->bitmapBpp, cache_bitmap_v2->bitmapLength, 2); - } - else - { - bitmap->Decompress(context, bitmap, - cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight, - cache_bitmap_v2->bitmapBpp, cache_bitmap_v2->bitmapLength, cache_bitmap_v2->compressed); - } + bitmap->Decompress(context, bitmap, + cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapWidth, cache_bitmap_v2->bitmapHeight, + cache_bitmap_v2->bitmapBpp, cache_bitmap_v2->bitmapLength, + cache_bitmap_v2->compressed, CODEC_ID_NONE); bitmap->New(context, bitmap); @@ -132,7 +125,6 @@ void update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cach rdpBitmap* prevBitmap; rdpCache* cache = context->cache; BITMAP_DATA_EX* bitmapData = &cache_bitmap_v3->bitmapData; - boolean compression; bitmap = Bitmap_Alloc(context); @@ -144,25 +136,10 @@ void update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cach cache_bitmap_v3->bitmapData.bpp = context->instance->settings->color_depth; } - switch (bitmapData->codecID) - { - case CODEC_ID_JPEG: - compression = 2; - break; - case CODEC_ID_REMOTEFX: - compression = 3; - break; - case CODEC_ID_NSCODEC: - compression = 4; - break; - default: - compression = 1; - break; - } - bitmap->Decompress(context, bitmap, bitmapData->data, bitmap->width, bitmap->height, - bitmapData->bpp, bitmapData->length, compression); + bitmapData->bpp, bitmapData->length, true, + bitmapData->codecID); bitmap->New(context, bitmap); @@ -207,7 +184,8 @@ void update_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap_update) bitmap->Decompress(context, bitmap, bitmap_data->bitmapDataStream, bitmap_data->width, bitmap_data->height, - bitmap_data->bitsPerPixel, bitmap_data->bitmapLength, bitmap_data->compressed); + bitmap_data->bitsPerPixel, bitmap_data->bitmapLength, + bitmap_data->compressed, CODEC_ID_NONE); if (reused) bitmap->Free(context, bitmap); diff --git a/libfreerdp-gdi/graphics.c b/libfreerdp-gdi/graphics.c index 1ea61d793..c68cbb1e5 100644 --- a/libfreerdp-gdi/graphics.c +++ b/libfreerdp-gdi/graphics.c @@ -89,7 +89,8 @@ void gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) } void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, int compressed) + uint8* data, int width, int height, int bpp, int length, + boolean compressed, int codec_id) { uint16 size; RFX_MESSAGE* msg; @@ -97,6 +98,8 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, uint8* dst; int yindex; int xindex; + rdpGdi* gdi; + boolean status; size = width * height * (bpp + 7) / 8; @@ -105,58 +108,57 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed == 4) + switch (codec_id) { - printf("gdi_Bitmap_Decompress: nsc not done\n"); - } - else if (compressed == 3) - { - rdpGdi* gdi = context->gdi; - rfx_context_set_pixel_format(gdi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); - msg = rfx_process_message(gdi->rfx_context, data, length); - if (msg == NULL) - { - printf("gdi_Bitmap_Decompress: rfx Decompression Failed\n"); - } - else - { - for (yindex = 0; yindex < height; yindex++) + case CODEC_ID_NSCODEC: + printf("gdi_Bitmap_Decompress: nsc not done\n"); + break; + case CODEC_ID_REMOTEFX: + gdi = context->gdi; + rfx_context_set_pixel_format(gdi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(gdi->rfx_context, data, length); + if (msg == NULL) { - src = msg->tiles[0]->data + yindex * 64 * 4; - dst = bitmap->data + yindex * width * 3; - for (xindex = 0; xindex < width; xindex++) + printf("gdi_Bitmap_Decompress: rfx Decompression Failed\n"); + } + else + { + for (yindex = 0; yindex < height; yindex++) { - *(dst++) = *(src++); - *(dst++) = *(src++); - *(dst++) = *(src++); - src++; + src = msg->tiles[0]->data + yindex * 64 * 4; + dst = bitmap->data + yindex * width * 3; + for (xindex = 0; xindex < width; xindex++) + { + *(dst++) = *(src++); + *(dst++) = *(src++); + *(dst++) = *(src++); + src++; + } + } + rfx_message_free(gdi->rfx_context, msg); + } + break; + case CODEC_ID_JPEG: + if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) + { + printf("gdi_Bitmap_Decompress: jpeg Decompression Failed\n"); + } + break; + default: + if (compressed) + { + status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); + + if (status == false) + { + printf("gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); } } - rfx_message_free(gdi->rfx_context, msg); - } - } - else if (compressed == 2) - { - if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) - { - printf("gdi_Bitmap_Decompress: jpeg Decompression Failed\n"); - } - } - else if (compressed) - { - boolean status; - - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - - if (status == false) - { - printf("gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); - } - } - else - { - freerdp_image_flip(data, bitmap->data, width, height, bpp); - + else + { + freerdp_image_flip(data, bitmap->data, width, height, bpp); + } + break; } bitmap->width = width; diff --git a/libfreerdp-gdi/graphics.h b/libfreerdp-gdi/graphics.h index 35d26855c..930c5e860 100644 --- a/libfreerdp-gdi/graphics.h +++ b/libfreerdp-gdi/graphics.h @@ -28,7 +28,8 @@ HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, int width, int height, int bpp, uint8 void gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap); void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap); void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, int compressed); + uint8* data, int width, int height, int bpp, int length, + boolean compressed, int codec_id); void gdi_register_graphics(rdpGraphics* graphics); #endif /* __GDI_GRAPHICS_H */ diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index ce7eb4ade..b19582f9a 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -361,17 +362,17 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, if (strcmp("rfx", argv[index]) == 0) { printf("setting rfx\n"); - settings->preferred_codec_id = 3; /* CODEC_ID_REMOTEFX */ + settings->preferred_codec_id = CODEC_ID_REMOTEFX; } else if (strcmp("nsc", argv[index]) == 0) { printf("setting codec nsc\n"); - settings->preferred_codec_id = 1; /* CODEC_ID_NSCODEC */ + settings->preferred_codec_id = CODEC_ID_NSCODEC; } else if (strcmp("jpeg", argv[index]) == 0) { printf("setting codec jpeg\n"); - settings->preferred_codec_id = 2; + settings->preferred_codec_id = CODEC_ID_JPEG; } } else if (strcmp("--jpeg", argv[index]) == 0) From 317fb28c7e088140f69d089b42fa676200e715b1 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Tue, 24 Jul 2012 17:50:10 -0700 Subject: [PATCH 19/27] adedd --bcv3 cap, working now to xrdp --- include/freerdp/settings.h | 2 +- libfreerdp-core/capabilities.c | 28 ++++++++++++++++++++++++++++ libfreerdp-utils/args.c | 6 +++--- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 572be4cba..b0af75c17 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -391,7 +391,7 @@ struct rdp_settings ALIGN64 boolean jpeg_codec; /* 286 */ ALIGN64 uint32 jpeg_codec_id; /* 287 */ ALIGN64 uint32 jpeg_quality; /* 288 */ - ALIGN64 uint32 preferred_codec_id; /* 289 */ + ALIGN64 uint32 v3_codec_id; /* 289 */ ALIGN64 uint64 paddingM[296 - 290]; /* 290 */ /* Recording */ diff --git a/libfreerdp-core/capabilities.c b/libfreerdp-core/capabilities.c index 080ad9525..98324edc6 100644 --- a/libfreerdp-core/capabilities.c +++ b/libfreerdp-core/capabilities.c @@ -1647,6 +1647,21 @@ void rdp_read_frame_acknowledge_capability_set(STREAM* s, uint16 length, rdpSett stream_seek_uint32(s); /* (4 bytes) */ } +void rdp_read_bitmap_cache_v3_codec_id_capability_set(STREAM* s, uint16 length, rdpSettings* settings) +{ + stream_seek_uint8(s); /* (1 byte) */ +} + +void rdp_write_bitmap_cache_v3_codec_id_capability_set(STREAM* s, rdpSettings* settings) +{ + uint8* header; + + header = rdp_capability_set_start(s); + stream_write_uint8(s, settings->v3_codec_id); + rdp_capability_set_finish(s, header, 6); +} + + /** * Write frame acknowledge capability set.\n * @param s stream @@ -1799,6 +1814,10 @@ boolean rdp_read_capability_sets(STREAM* s, rdpSettings* settings, uint16 number rdp_read_frame_acknowledge_capability_set(s, length, settings); break; + case 6: + rdp_read_bitmap_cache_v3_codec_id_capability_set(s, length, settings); + break; + default: printf("unknown capability type %d\n", type); break; @@ -2106,6 +2125,15 @@ void rdp_write_confirm_active(STREAM* s, rdpSettings* settings) } } + if (settings->received_caps[6]) + { + if (settings->v3_codec_id != 0) + { + numberCapabilities++; + rdp_write_bitmap_cache_v3_codec_id_capability_set(s, settings); + } + } + stream_get_mark(s, em); stream_set_mark(s, lm); /* go back to lengthCombinedCapabilities */ diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index b19582f9a..a5a5c15d5 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -362,17 +362,17 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, if (strcmp("rfx", argv[index]) == 0) { printf("setting rfx\n"); - settings->preferred_codec_id = CODEC_ID_REMOTEFX; + settings->v3_codec_id = CODEC_ID_REMOTEFX; } else if (strcmp("nsc", argv[index]) == 0) { printf("setting codec nsc\n"); - settings->preferred_codec_id = CODEC_ID_NSCODEC; + settings->v3_codec_id = CODEC_ID_NSCODEC; } else if (strcmp("jpeg", argv[index]) == 0) { printf("setting codec jpeg\n"); - settings->preferred_codec_id = CODEC_ID_JPEG; + settings->v3_codec_id = CODEC_ID_JPEG; } } else if (strcmp("--jpeg", argv[index]) == 0) From 502396c99adc24873493e8737c74aed8cdf5dfcb Mon Sep 17 00:00:00 2001 From: xangis Date: Tue, 24 Jul 2012 17:58:04 -0700 Subject: [PATCH 20/27] Add stubs for wf_rail and wf_window for Windows client. --- client/Windows/CMakeLists.txt | 4 +++ client/Windows/wf_rail.c | 54 +++++++++++++++++++++++++++++++++++ client/Windows/wf_rail.h | 32 +++++++++++++++++++++ client/Windows/wf_window.c | 20 +++++++++++++ client/Windows/wf_window.h | 27 ++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 client/Windows/wf_rail.c create mode 100644 client/Windows/wf_rail.h create mode 100644 client/Windows/wf_window.c create mode 100644 client/Windows/wf_window.h diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index 1aefab7ef..e239f206a 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -26,6 +26,10 @@ add_executable(wfreerdp WIN32 wf_graphics.h wf_cliprdr.c wf_cliprdr.h + wf_window.c + wf_window.h + wf_rail.c + wf_rail.h wfreerdp.c wfreerdp.h) diff --git a/client/Windows/wf_rail.c b/client/Windows/wf_rail.c new file mode 100644 index 000000000..6a831c9ba --- /dev/null +++ b/client/Windows/wf_rail.c @@ -0,0 +1,54 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Windows RAIL + * + * Copyright 2012 Jason Champion + * + * 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. + */ + +#include +#include +#include +#include + +#include "wf_window.h" +#include "wf_rail.h" + +void wf_rail_paint(wfInfo* wfi, rdpRail* rail, sint32 uleft, sint32 utop, uint32 uright, uint32 ubottom) +{ +} + +void wf_rail_register_callbacks(wfInfo* wfi, rdpRail* rail) +{ +} + +void wf_rail_send_client_system_command(wfInfo* wfi, uint32 windowId, uint16 command) +{ +} + +void wf_rail_send_activate(wfInfo* wfi, HWND window, boolean enabled) +{ +} + +void wf_process_rail_event(wfInfo* wfi, rdpChannels* chanman, RDP_EVENT* event) +{ +} + +void wf_rail_adjust_position(wfInfo* wfi, rdpWindow *window) +{ +} + +void wf_rail_end_local_move(wfInfo* wfi, rdpWindow *window) +{ +} diff --git a/client/Windows/wf_rail.h b/client/Windows/wf_rail.h new file mode 100644 index 000000000..82683ef42 --- /dev/null +++ b/client/Windows/wf_rail.h @@ -0,0 +1,32 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Windows RAIL + * + * Copyright 2012 Jason Champion + * + * 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. + */ +#ifndef __WF_RAIL_H +#define __WF_RAIL_H + +#include "wfreerdp.h" + +void wf_rail_paint(wfInfo* wfi, rdpRail* rail, sint32 uleft, sint32 utop, uint32 uright, uint32 ubottom); +void wf_rail_register_callbacks(wfInfo* wfi, rdpRail* rail); +void wf_rail_send_client_system_command(wfInfo* wfi, uint32 windowId, uint16 command); +void wf_rail_send_activate(wfInfo* wfi, HWND window, boolean enabled); +void wf_process_rail_event(wfInfo* wfi, rdpChannels* chanman, RDP_EVENT* event); +void wf_rail_adjust_position(wfInfo* wfi, rdpWindow *window); +void wf_rail_end_local_move(wfInfo* wfi, rdpWindow *window); + +#endif \ No newline at end of file diff --git a/client/Windows/wf_window.c b/client/Windows/wf_window.c new file mode 100644 index 000000000..670ddc1e0 --- /dev/null +++ b/client/Windows/wf_window.c @@ -0,0 +1,20 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Windows RAIL + * + * Copyright 2012 Jason Champion + * + * 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. + */ + +#include "wf_window.h" \ No newline at end of file diff --git a/client/Windows/wf_window.h b/client/Windows/wf_window.h new file mode 100644 index 000000000..aeb54f4c6 --- /dev/null +++ b/client/Windows/wf_window.h @@ -0,0 +1,27 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Windows RAIL + * + * Copyright 2012 Jason Champion + * + * 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. + */ +#ifndef __WF_WINDOW_H +#define __WF_WINDOW_H + +#include +#include + +#include "wfreerdp.h" + +#endif \ No newline at end of file From c3e9966429ce5a1826a902d2c0f5885f6e544bb4 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Tue, 24 Jul 2012 18:26:24 -0700 Subject: [PATCH 21/27] added cmake option to compile jpeg, off by default --- cmake/ConfigOptions.cmake | 1 + config.h.in | 1 + libfreerdp-codec/CMakeLists.txt | 7 +++++-- libfreerdp-codec/jpeg.c | 15 ++++++++++++++- libfreerdp-utils/args.c | 11 +++++++++++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 11c65b3f7..693076c3a 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -3,6 +3,7 @@ option(WITH_NEON "Enable NEON optimization for rfx decoder" OFF) option(WITH_PROFILER "Compile profiler." OFF) option(WITH_SSE2_TARGET "Allow compiler to generate SSE2 instructions." OFF) option(WITH_SSE2 "Use SSE2 optimization." OFF) +option(WITH_JPEG "Use JPEG decoding." OFF) option(WITH_DEBUG_CERTIFICATE "Print certificate related debug messages." OFF) option(WITH_DEBUG_CHANNELS "Print channel manager debug messages." OFF) diff --git a/config.h.in b/config.h.in index d250bedda..836554d27 100644 --- a/config.h.in +++ b/config.h.in @@ -25,6 +25,7 @@ #cmakedefine WITH_PROFILER #cmakedefine WITH_SSE2 #cmakedefine WITH_NEON +#cmakedefine WITH_JPEG /* Debug */ #cmakedefine WITH_DEBUG_CERTIFICATE diff --git a/libfreerdp-codec/CMakeLists.txt b/libfreerdp-codec/CMakeLists.txt index 442b5fbba..c06afc3ce 100644 --- a/libfreerdp-codec/CMakeLists.txt +++ b/libfreerdp-codec/CMakeLists.txt @@ -65,10 +65,13 @@ if(WITH_NEON) set_property(SOURCE rfx_neon.c PROPERTY COMPILE_FLAGS "-mfpu=neon -mfloat-abi=softfp") endif() +if(WITH_JPEG) + set(FREERDP_JPEG_LIBS jpeg) +endif() + add_library(freerdp-codec ${FREERDP_CODEC_SRCS}) set_target_properties(freerdp-codec PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") -target_link_libraries(freerdp-codec freerdp-utils jpeg) +target_link_libraries(freerdp-codec freerdp-utils ${FREERDP_JPEG_LIBS}) install(TARGETS freerdp-codec DESTINATION ${CMAKE_INSTALL_LIBDIR}) - diff --git a/libfreerdp-codec/jpeg.c b/libfreerdp-codec/jpeg.c index ac96def9b..eec5eb614 100644 --- a/libfreerdp-codec/jpeg.c +++ b/libfreerdp-codec/jpeg.c @@ -17,10 +17,13 @@ * limitations under the License. */ +#include "config.h" #include #include #include +#ifdef WITH_JPEG + #define HAVE_BOOLEAN #include @@ -63,7 +66,7 @@ static void my_term_source(j_decompress_ptr cinfo) } /*****************************************************************************/ -int +static int do_decompress(char* comp_data, int comp_data_bytes, int* width, int* height, int* bpp, char* decomp_data, int* decomp_data_bytes) @@ -139,3 +142,13 @@ jpeg_decompress(uint8 * input, uint8 * output, int width, int height, int size, } return 1; } + +#else + +boolean +jpeg_decompress(uint8 * input, uint8 * output, int width, int height, int size, int bpp) +{ + return 0; +} + +#endif diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index a5a5c15d5..0adc990a2 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -92,8 +92,10 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, " --rfx: enable RemoteFX\n" " --rfx-mode: RemoteFX operational flags (v[ideo], i[mage]), default is video\n" " --nsc: enable NSCodec (experimental)\n" +#ifdef WITH_JPEG " --jpeg: enable jpeg codec, uses 75 quality\n" " --jpegex: enable jpeg and set quality(1..99)\n" +#endif " --disable-wallpaper: disables wallpaper\n" " --composition: enable desktop composition\n" " --disable-full-window-drag: disables full window drag\n" @@ -369,12 +371,20 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, printf("setting codec nsc\n"); settings->v3_codec_id = CODEC_ID_NSCODEC; } +#ifdef WITH_JPEG else if (strcmp("jpeg", argv[index]) == 0) { printf("setting codec jpeg\n"); settings->v3_codec_id = CODEC_ID_JPEG; } +#endif + else + { + printf("bad codec name\n"); + return FREERDP_ARGS_PARSE_FAILURE; + } } +#ifdef WITH_JPEG else if (strcmp("--jpeg", argv[index]) == 0) { settings->jpeg_codec = true; @@ -391,6 +401,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, settings->jpeg_codec = true; settings->jpeg_quality = atoi(argv[index]); } +#endif else if (strcmp("--rfx", argv[index]) == 0) { settings->rfx_codec = true; From 0dbdd0004c3c638869378d32378ef23eb474da93 Mon Sep 17 00:00:00 2001 From: xangis Date: Wed, 25 Jul 2012 14:41:00 -0700 Subject: [PATCH 22/27] Exclude channels that don't build on Windows from project. --- channels/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/channels/CMakeLists.txt b/channels/CMakeLists.txt index 648e2a819..9345ff544 100644 --- a/channels/CMakeLists.txt +++ b/channels/CMakeLists.txt @@ -18,9 +18,11 @@ # limitations under the License. add_subdirectory(cliprdr) -add_subdirectory(drdynvc) -add_subdirectory(rdpdbg) -add_subdirectory(rdpdr) add_subdirectory(rail) -add_subdirectory(rdpsnd) +if(NOT WIN32) + add_subdirectory(drdynvc) + add_subdirectory(rdpdbg) + add_subdirectory(rdpdr) + add_subdirectory(rdpsnd) +endif() From 76166628f4bb8a7fe41d4de78d7c263ae381ccf1 Mon Sep 17 00:00:00 2001 From: xangis Date: Wed, 25 Jul 2012 14:50:04 -0700 Subject: [PATCH 23/27] Windows build complains about missing jpeg_decompress. Used WITH_JPEG ifdef to make it happier. --- libfreerdp-codec/jpeg.c | 8 -------- libfreerdp-gdi/graphics.c | 2 ++ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/libfreerdp-codec/jpeg.c b/libfreerdp-codec/jpeg.c index eec5eb614..8d8e57708 100644 --- a/libfreerdp-codec/jpeg.c +++ b/libfreerdp-codec/jpeg.c @@ -143,12 +143,4 @@ jpeg_decompress(uint8 * input, uint8 * output, int width, int height, int size, return 1; } -#else - -boolean -jpeg_decompress(uint8 * input, uint8 * output, int width, int height, int size, int bpp) -{ - return 0; -} - #endif diff --git a/libfreerdp-gdi/graphics.c b/libfreerdp-gdi/graphics.c index c68cbb1e5..565ff46ea 100644 --- a/libfreerdp-gdi/graphics.c +++ b/libfreerdp-gdi/graphics.c @@ -139,10 +139,12 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, } break; case CODEC_ID_JPEG: +#ifdef WITH_JPEG if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) { printf("gdi_Bitmap_Decompress: jpeg Decompression Failed\n"); } +#endif break; default: if (compressed) From a0d651d8a27c895132076981ec3e46c5ffbd1f09 Mon Sep 17 00:00:00 2001 From: xangis Date: Wed, 25 Jul 2012 15:08:35 -0700 Subject: [PATCH 24/27] Fix for C2036 void pointer unknown size build error on Windows. --- channels/rail/rail_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/rail/rail_main.c b/channels/rail/rail_main.c index 58d1de40e..3b2c63a1d 100644 --- a/channels/rail/rail_main.c +++ b/channels/rail/rail_main.c @@ -128,7 +128,7 @@ static void rail_recv_set_sysparams_event(rdpRailOrder* rail_order, RDP_EVENT* e while (data && data->size > 0) { rail_process_plugin_data(rail_order, data); - data = (RDP_PLUGIN_DATA*)(((void*) data) + data->size); + data = (RDP_PLUGIN_DATA*)((char *)(data) + data->size); } } From e8b1584051002e1fcde8f96d27854261511b64fe Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Wed, 25 Jul 2012 15:27:16 -0700 Subject: [PATCH 25/27] --bcv3 rfx implies --rfx, same with jpeg --- libfreerdp-utils/args.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 0adc990a2..7975ad022 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -365,6 +365,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, { printf("setting rfx\n"); settings->v3_codec_id = CODEC_ID_REMOTEFX; + settings->rfx_codec = true; } else if (strcmp("nsc", argv[index]) == 0) { @@ -376,6 +377,8 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, { printf("setting codec jpeg\n"); settings->v3_codec_id = CODEC_ID_JPEG; + settings->jpeg_codec = true; + settings->jpeg_quality = 75; } #endif else From 8e2dac6813021c8441627f54a8c5bd1589984665 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Wed, 25 Jul 2012 19:18:47 -0700 Subject: [PATCH 26/27] jpeg: don't overwrite jpeg quality unless zero --- libfreerdp-utils/args.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 7975ad022..e27f986d9 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -378,7 +378,8 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, printf("setting codec jpeg\n"); settings->v3_codec_id = CODEC_ID_JPEG; settings->jpeg_codec = true; - settings->jpeg_quality = 75; + if (settings->jpeg_quality == 0) + settings->jpeg_quality = 75; } #endif else From 06e7db4e6b3c12cd22bb7912efb11784e7cca6a6 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Thu, 26 Jul 2012 11:15:41 -0700 Subject: [PATCH 27/27] codec: minor change --- libfreerdp-codec/jpeg.c | 8 ++++++++ libfreerdp-utils/args.c | 1 + 2 files changed, 9 insertions(+) diff --git a/libfreerdp-codec/jpeg.c b/libfreerdp-codec/jpeg.c index 8d8e57708..eec5eb614 100644 --- a/libfreerdp-codec/jpeg.c +++ b/libfreerdp-codec/jpeg.c @@ -143,4 +143,12 @@ jpeg_decompress(uint8 * input, uint8 * output, int width, int height, int size, return 1; } +#else + +boolean +jpeg_decompress(uint8 * input, uint8 * output, int width, int height, int size, int bpp) +{ + return 0; +} + #endif diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index e27f986d9..1871c2330 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -371,6 +371,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, { printf("setting codec nsc\n"); settings->v3_codec_id = CODEC_ID_NSCODEC; + settings->ns_codec = true; } #ifdef WITH_JPEG else if (strcmp("jpeg", argv[index]) == 0)