summaryrefslogtreecommitdiffstats
path: root/server/Mac
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /server/Mac
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--server/Mac/CMakeLists.txt78
-rw-r--r--server/Mac/ModuleOptions.cmake4
-rw-r--r--server/Mac/mf_audin.c64
-rw-r--r--server/Mac/mf_audin.h33
-rw-r--r--server/Mac/mf_event.c219
-rw-r--r--server/Mac/mf_event.h75
-rw-r--r--server/Mac/mf_info.c231
-rw-r--r--server/Mac/mf_info.h49
-rw-r--r--server/Mac/mf_input.c511
-rw-r--r--server/Mac/mf_input.h36
-rw-r--r--server/Mac/mf_interface.c0
-rw-r--r--server/Mac/mf_interface.h106
-rw-r--r--server/Mac/mf_mountain_lion.c269
-rw-r--r--server/Mac/mf_mountain_lion.h38
-rw-r--r--server/Mac/mf_peer.c485
-rw-r--r--server/Mac/mf_peer.h33
-rw-r--r--server/Mac/mf_rdpsnd.c200
-rw-r--r--server/Mac/mf_rdpsnd.h58
-rw-r--r--server/Mac/mf_types.h33
-rw-r--r--server/Mac/mfreerdp.c108
-rw-r--r--server/Mac/mfreerdp.h28
21 files changed, 2658 insertions, 0 deletions
diff --git a/server/Mac/CMakeLists.txt b/server/Mac/CMakeLists.txt
new file mode 100644
index 0000000..9dddb38
--- /dev/null
+++ b/server/Mac/CMakeLists.txt
@@ -0,0 +1,78 @@
+# FreeRDP: A Remote Desktop Protocol Implementation
+# FreeRDP Mac OS X Server cmake build script
+#
+# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# 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(MODULE_NAME "mfreerdp-server")
+set(MODULE_PREFIX "FREERDP_SERVER_MAC")
+
+FIND_LIBRARY(AUDIO_TOOL AudioToolbox)
+FIND_LIBRARY(CORE_AUDIO CoreAudio)
+FIND_LIBRARY(CORE_VIDEO CoreVideo)
+FIND_LIBRARY(APP_SERVICES ApplicationServices)
+FIND_LIBRARY(IOKIT IOKit)
+FIND_LIBRARY(IOSURFACE IOSurface)
+FIND_LIBRARY(CARBON Carbon)
+
+set(${MODULE_PREFIX}_SRCS
+ mfreerdp.c
+ mfreerdp.h
+ mf_interface.c
+ mf_interface.h
+ mf_event.c
+ mf_event.h
+ mf_peer.c
+ mf_peer.h
+ mf_info.c
+ mf_info.h
+ mf_input.c
+ mf_input.h
+ mf_mountain_lion.c
+ mf_mountain_lion.h)
+
+if(CHANNEL_AUDIN_SERVER)
+ set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}
+ mf_audin.c
+ mf_audin.h)
+endif()
+
+if(CHANNEL_RDPSND_SERVER)
+ set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}
+ mf_rdpsnd.c
+ mf_rdpsnd.h)
+
+endif()
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+if (WITH_BINARY_VERSIONING)
+ set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_NAME}${FREERDP_API_VERSION}")
+endif()
+
+set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
+ freerdp-server
+ ${AUDIO_TOOL}
+ ${CORE_AUDIO}
+ ${CORE_VIDEO}
+ ${APP_SERVICES}
+ ${IOKIT}
+ ${IOSURFACE}
+ ${CARBON})
+
+set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
+
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/Mac")
diff --git a/server/Mac/ModuleOptions.cmake b/server/Mac/ModuleOptions.cmake
new file mode 100644
index 0000000..bfd36cb
--- /dev/null
+++ b/server/Mac/ModuleOptions.cmake
@@ -0,0 +1,4 @@
+
+set(FREERDP_SERVER_NAME "mfreerdp-server")
+set(FREERDP_SERVER_PLATFORM "X11")
+set(FREERDP_SERVER_VENDOR "FreeRDP")
diff --git a/server/Mac/mf_audin.c b/server/Mac/mf_audin.c
new file mode 100644
index 0000000..aaabafa
--- /dev/null
+++ b/server/Mac/mf_audin.c
@@ -0,0 +1,64 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server (Audio Input)
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2015 Thincast Technologies GmbH
+ * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
+ * Copyright 2023 Pascal Nowack <Pascal.Nowack@gmx.de>
+ *
+ * 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 <freerdp/config.h>
+
+#include "mfreerdp.h"
+
+#include "mf_audin.h"
+#include "mf_interface.h"
+
+#include <freerdp/server/server-common.h>
+#include <freerdp/log.h>
+#define TAG SERVER_TAG("mac")
+
+static UINT mf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* data)
+{
+ /* TODO: Implement */
+ WINPR_ASSERT(audin);
+ WINPR_ASSERT(data);
+
+ WLog_WARN(TAG, "not implemented");
+ WLog_DBG(TAG, "receive %" PRIdz " bytes.", Stream_Length(data->Data));
+ return CHANNEL_RC_OK;
+}
+
+BOOL mf_peer_audin_init(mfPeerContext* context)
+{
+ WINPR_ASSERT(context);
+
+ context->audin = audin_server_context_new(context->vcm);
+ context->audin->rdpcontext = &context->_p;
+ context->audin->userdata = context;
+
+ context->audin->Data = mf_peer_audin_data;
+
+ return audin_server_set_formats(context->audin, -1, NULL);
+}
+
+void mf_peer_audin_uninit(mfPeerContext* context)
+{
+ WINPR_ASSERT(context);
+
+ audin_server_context_free(context->audin);
+ context->audin = NULL;
+}
diff --git a/server/Mac/mf_audin.h b/server/Mac/mf_audin.h
new file mode 100644
index 0000000..31edffa
--- /dev/null
+++ b/server/Mac/mf_audin.h
@@ -0,0 +1,33 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server (Audio Input)
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_AUDIN_H
+#define FREERDP_SERVER_MAC_AUDIN_H
+
+#include <freerdp/freerdp.h>
+#include <freerdp/listener.h>
+
+#include "mf_types.h"
+#include "mfreerdp.h"
+
+BOOL mf_peer_audin_init(mfPeerContext* context);
+void mf_peer_audin_uninit(mfPeerContext* context);
+
+#endif /* FREERDP_SERVER_MAC_AUDIN_H */
diff --git a/server/Mac/mf_event.c b/server/Mac/mf_event.c
new file mode 100644
index 0000000..e30b9ac
--- /dev/null
+++ b/server/Mac/mf_event.c
@@ -0,0 +1,219 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * OS X Server Event Handling
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 <freerdp/config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mf_event.h"
+
+#include <freerdp/log.h>
+#define TAG SERVER_TAG("mac")
+
+int mf_is_event_set(mfEventQueue* event_queue)
+{
+ fd_set rfds;
+ int num_set;
+ struct timeval time = { 0 };
+
+ FD_ZERO(&rfds);
+ FD_SET(event_queue->pipe_fd[0], &rfds);
+ num_set = select(event_queue->pipe_fd[0] + 1, &rfds, 0, 0, &time);
+
+ return (num_set == 1);
+}
+
+void mf_signal_event(mfEventQueue* event_queue)
+{
+ int length;
+
+ length = write(event_queue->pipe_fd[1], "sig", 4);
+
+ if (length != 4)
+ WLog_ERR(TAG, "mf_signal_event: error");
+}
+
+void mf_set_event(mfEventQueue* event_queue)
+{
+ int length;
+
+ length = write(event_queue->pipe_fd[1], "sig", 4);
+
+ if (length != 4)
+ WLog_ERR(TAG, "mf_set_event: error");
+}
+
+void mf_clear_events(mfEventQueue* event_queue)
+{
+ int length;
+
+ while (mf_is_event_set(event_queue))
+ {
+ length = read(event_queue->pipe_fd[0], &length, 4);
+
+ if (length != 4)
+ WLog_ERR(TAG, "mf_clear_event: error");
+ }
+}
+
+void mf_clear_event(mfEventQueue* event_queue)
+{
+ int length;
+
+ length = read(event_queue->pipe_fd[0], &length, 4);
+
+ if (length != 4)
+ WLog_ERR(TAG, "mf_clear_event: error");
+}
+
+void mf_event_push(mfEventQueue* event_queue, mfEvent* event)
+{
+ pthread_mutex_lock(&(event_queue->mutex));
+
+ if (event_queue->count >= event_queue->size)
+ {
+ event_queue->size *= 2;
+ event_queue->events =
+ (mfEvent**)realloc((void*)event_queue->events, sizeof(mfEvent*) * event_queue->size);
+ }
+
+ event_queue->events[(event_queue->count)++] = event;
+
+ pthread_mutex_unlock(&(event_queue->mutex));
+
+ mf_set_event(event_queue);
+}
+
+mfEvent* mf_event_peek(mfEventQueue* event_queue)
+{
+ mfEvent* event;
+
+ pthread_mutex_lock(&(event_queue->mutex));
+
+ if (event_queue->count < 1)
+ event = NULL;
+ else
+ event = event_queue->events[0];
+
+ pthread_mutex_unlock(&(event_queue->mutex));
+
+ return event;
+}
+
+mfEvent* mf_event_pop(mfEventQueue* event_queue)
+{
+ mfEvent* event;
+
+ pthread_mutex_lock(&(event_queue->mutex));
+
+ if (event_queue->count < 1)
+ return NULL;
+
+ /* remove event signal */
+ mf_clear_event(event_queue);
+
+ event = event_queue->events[0];
+ (event_queue->count)--;
+
+ memmove(&event_queue->events[0], &event_queue->events[1], event_queue->count * sizeof(void*));
+
+ pthread_mutex_unlock(&(event_queue->mutex));
+
+ return event;
+}
+
+mfEventRegion* mf_event_region_new(int x, int y, int width, int height)
+{
+ mfEventRegion* event_region = malloc(sizeof(mfEventRegion));
+
+ if (event_region != NULL)
+ {
+ event_region->x = x;
+ event_region->y = y;
+ event_region->width = width;
+ event_region->height = height;
+ }
+
+ return event_region;
+}
+
+void mf_event_region_free(mfEventRegion* event_region)
+{
+ free(event_region);
+}
+
+mfEvent* mf_event_new(int type)
+{
+ mfEvent* event = malloc(sizeof(mfEvent));
+ if (!event)
+ return NULL;
+ event->type = type;
+ return event;
+}
+
+void mf_event_free(mfEvent* event)
+{
+ free(event);
+}
+
+mfEventQueue* mf_event_queue_new()
+{
+ mfEventQueue* event_queue = malloc(sizeof(mfEventQueue));
+
+ if (event_queue != NULL)
+ {
+ event_queue->pipe_fd[0] = -1;
+ event_queue->pipe_fd[1] = -1;
+
+ event_queue->size = 16;
+ event_queue->count = 0;
+ event_queue->events = (mfEvent**)malloc(sizeof(mfEvent*) * event_queue->size);
+
+ if (pipe(event_queue->pipe_fd) < 0)
+ {
+ free(event_queue);
+ return NULL;
+ }
+
+ pthread_mutex_init(&(event_queue->mutex), NULL);
+ }
+
+ return event_queue;
+}
+
+void mf_event_queue_free(mfEventQueue* event_queue)
+{
+ if (event_queue->pipe_fd[0] != -1)
+ {
+ close(event_queue->pipe_fd[0]);
+ event_queue->pipe_fd[0] = -1;
+ }
+
+ if (event_queue->pipe_fd[1] != -1)
+ {
+ close(event_queue->pipe_fd[1]);
+ event_queue->pipe_fd[1] = -1;
+ }
+
+ pthread_mutex_destroy(&(event_queue->mutex));
+}
diff --git a/server/Mac/mf_event.h b/server/Mac/mf_event.h
new file mode 100644
index 0000000..197cfd7
--- /dev/null
+++ b/server/Mac/mf_event.h
@@ -0,0 +1,75 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * OS X Server Event Handling
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_EVENT_H
+#define FREERDP_SERVER_MAC_EVENT_H
+
+typedef struct mf_event mfEvent;
+typedef struct mf_event_queue mfEventQueue;
+typedef struct mf_event_region mfEventRegion;
+
+#include <pthread.h>
+#include "mfreerdp.h"
+
+//#include "mf_peer.h"
+
+enum mf_event_type
+{
+ FREERDP_SERVER_MAC_EVENT_TYPE_REGION,
+ FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK
+};
+
+struct mf_event
+{
+ int type;
+};
+
+struct mf_event_queue
+{
+ int size;
+ int count;
+ int pipe_fd[2];
+ mfEvent** events;
+ pthread_mutex_t mutex;
+};
+
+struct mf_event_region
+{
+ int type;
+
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+void mf_event_push(mfEventQueue* event_queue, mfEvent* event);
+mfEvent* mf_event_peek(mfEventQueue* event_queue);
+mfEvent* mf_event_pop(mfEventQueue* event_queue);
+
+mfEventRegion* mf_event_region_new(int x, int y, int width, int height);
+void mf_event_region_free(mfEventRegion* event_region);
+
+mfEvent* mf_event_new(int type);
+void mf_event_free(mfEvent* event);
+
+mfEventQueue* mf_event_queue_new(void);
+void mf_event_queue_free(mfEventQueue* event_queue);
+
+#endif /* FREERDP_SERVER_MAC_EVENT_H */
diff --git a/server/Mac/mf_info.c b/server/Mac/mf_info.c
new file mode 100644
index 0000000..ab523e1
--- /dev/null
+++ b/server/Mac/mf_info.c
@@ -0,0 +1,231 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 <freerdp/config.h>
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "mf_info.h"
+#include "mf_mountain_lion.h"
+
+#define MF_INFO_DEFAULT_FPS 30
+#define MF_INFO_MAXPEERS 32
+
+static mfInfo* mfInfoInstance = NULL;
+
+int mf_info_lock(mfInfo* mfi)
+{
+ int status = pthread_mutex_lock(&mfi->mutex);
+
+ switch (status)
+ {
+ case 0:
+ return TRUE;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ return 1;
+}
+
+int mf_info_try_lock(mfInfo* mfi, UINT32 ms)
+{
+ int status = pthread_mutex_trylock(&mfi->mutex);
+
+ switch (status)
+ {
+ case 0:
+ return TRUE;
+ break;
+
+ case EBUSY:
+ return FALSE;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ return 1;
+}
+
+int mf_info_unlock(mfInfo* mfi)
+{
+ int status = pthread_mutex_unlock(&mfi->mutex);
+
+ switch (status)
+ {
+ case 0:
+ return TRUE;
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+
+ return 1;
+}
+
+mfInfo* mf_info_init()
+{
+ mfInfo* mfi;
+
+ mfi = (mfInfo*)calloc(1, sizeof(mfInfo));
+
+ if (mfi != NULL)
+ {
+ pthread_mutex_init(&mfi->mutex, NULL);
+
+ mfi->peers = (freerdp_peer**)calloc(MF_INFO_MAXPEERS, sizeof(freerdp_peer*));
+ if (!mfi->peers)
+ {
+ free(mfi);
+ return NULL;
+ }
+
+ mfi->framesPerSecond = MF_INFO_DEFAULT_FPS;
+ mfi->input_disabled = FALSE;
+ }
+
+ return mfi;
+}
+
+mfInfo* mf_info_get_instance()
+{
+ if (mfInfoInstance == NULL)
+ mfInfoInstance = mf_info_init();
+
+ return mfInfoInstance;
+}
+
+void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context)
+{
+ if (mf_info_lock(mfi) > 0)
+ {
+ int peerId;
+
+ if (mfi->peerCount == MF_INFO_MAXPEERS)
+ {
+ mf_info_unlock(mfi);
+ return;
+ }
+
+ context->info = mfi;
+
+ if (mfi->peerCount == 0)
+ {
+ mf_mlion_display_info(&mfi->servscreen_width, &mfi->servscreen_height, &mfi->scale);
+ mf_mlion_screen_updates_init();
+ mf_mlion_start_getting_screen_updates();
+ }
+
+ peerId = 0;
+
+ for (int i = 0; i < MF_INFO_MAXPEERS; ++i)
+ {
+ // empty index will be our peer id
+ if (mfi->peers[i] == NULL)
+ {
+ peerId = i;
+ break;
+ }
+ }
+
+ mfi->peers[peerId] = ((rdpContext*)context)->peer;
+ mfi->peers[peerId]->pId = peerId;
+ mfi->peerCount++;
+
+ mf_info_unlock(mfi);
+ }
+}
+
+void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context)
+{
+ if (mf_info_lock(mfi) > 0)
+ {
+ int peerId;
+
+ peerId = ((rdpContext*)context)->peer->pId;
+ mfi->peers[peerId] = NULL;
+ mfi->peerCount--;
+
+ if (mfi->peerCount == 0)
+ mf_mlion_stop_getting_screen_updates();
+
+ mf_info_unlock(mfi);
+ }
+}
+
+BOOL mf_info_have_updates(mfInfo* mfi)
+{
+ if (mfi->framesWaiting == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+void mf_info_update_changes(mfInfo* mfi)
+{
+}
+
+void mf_info_find_invalid_region(mfInfo* mfi)
+{
+ mf_mlion_get_dirty_region(&mfi->invalid);
+}
+
+void mf_info_clear_invalid_region(mfInfo* mfi)
+{
+ mf_mlion_clear_dirty_region();
+ mfi->invalid.height = 0;
+ mfi->invalid.width = 0;
+}
+
+void mf_info_invalidate_full_screen(mfInfo* mfi)
+{
+ mfi->invalid.x = 0;
+ mfi->invalid.y = 0;
+ mfi->invalid.height = mfi->servscreen_height;
+ mfi->invalid.width = mfi->servscreen_width;
+}
+
+BOOL mf_info_have_invalid_region(mfInfo* mfi)
+{
+ if (mfi->invalid.width * mfi->invalid.height == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch)
+{
+ *width = mfi->invalid.width / mfi->scale;
+ *height = mfi->invalid.height / mfi->scale;
+ *pitch = mfi->servscreen_width * mfi->scale * 4;
+
+ mf_mlion_get_pixelData(mfi->invalid.x / mfi->scale, mfi->invalid.y / mfi->scale, *width,
+ *height, pBits);
+
+ *pBits = *pBits + (mfi->invalid.x * 4) + (*pitch * mfi->invalid.y);
+}
diff --git a/server/Mac/mf_info.h b/server/Mac/mf_info.h
new file mode 100644
index 0000000..8f08982
--- /dev/null
+++ b/server/Mac/mf_info.h
@@ -0,0 +1,49 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_INFO_H
+#define FREERDP_SERVER_MAC_INFO_H
+
+#define FREERDP_SERVER_MAC_INFO_DEFAULT_FPS 1
+#define FREERDP_SERVER_MAC_INFO_MAXPEERS 1
+
+#include <winpr/wtypes.h>
+#include <freerdp/codec/rfx.h>
+
+#include "mf_interface.h"
+
+int mf_info_lock(mfInfo* mfi);
+int mf_info_try_lock(mfInfo* mfi, UINT32 ms);
+int mf_info_unlock(mfInfo* mfi);
+
+mfInfo* mf_info_get_instance(void);
+void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context);
+void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context);
+
+BOOL mf_info_have_updates(mfInfo* mfi);
+void mf_info_update_changes(mfInfo* mfi);
+void mf_info_find_invalid_region(mfInfo* mfi);
+void mf_info_clear_invalid_region(mfInfo* mfi);
+void mf_info_invalidate_full_screen(mfInfo* mfi);
+BOOL mf_info_have_invalid_region(mfInfo* mfi);
+void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch);
+// BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM
+// dwData);
+
+#endif /* FREERDP_SERVER_MAC_INFO_H */
diff --git a/server/Mac/mf_input.c b/server/Mac/mf_input.c
new file mode 100644
index 0000000..fd4af85
--- /dev/null
+++ b/server/Mac/mf_input.c
@@ -0,0 +1,511 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server (Input)
+ *
+ * Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 <freerdp/config.h>
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <Carbon/Carbon.h>
+
+#include <winpr/windows.h>
+
+#include "mf_input.h"
+#include "mf_info.h"
+
+#include <freerdp/log.h>
+#define TAG SERVER_TAG("mac")
+
+static const CGKeyCode keymap[256] = {
+ 0xFF, // 0x0
+ kVK_Escape, // 0x1
+ kVK_ANSI_1, // 0x2
+ kVK_ANSI_2, // 0x3
+ kVK_ANSI_3, // 0x4
+ kVK_ANSI_4, // 0x5
+ kVK_ANSI_5, // 0x6
+ kVK_ANSI_6, // 0x7
+ kVK_ANSI_7, // 0x8
+ kVK_ANSI_8, // 0x9
+ kVK_ANSI_9, // 0xa
+ kVK_ANSI_0, // 0xb
+ kVK_ANSI_Minus, // 0xc
+ kVK_ANSI_Equal, // 0xd
+ kVK_Delete, // 0xe
+ kVK_Tab, // 0xf
+ kVK_ANSI_Q, // 0x10
+ kVK_ANSI_W, // 0x11
+ kVK_ANSI_E, // 0x12
+ kVK_ANSI_R, // 0x13
+ kVK_ANSI_T, // 0x14
+ kVK_ANSI_Y, // 0x15
+ kVK_ANSI_U, // 0x16
+ kVK_ANSI_I, // 0x17
+ kVK_ANSI_O, // 0x18
+ kVK_ANSI_P, // 0x19
+ kVK_ANSI_LeftBracket, // 0x1a
+ kVK_ANSI_RightBracket, // 0x1b
+ kVK_Return, // 0x1c
+ kVK_Control, // 0x1d
+ kVK_ANSI_A, // 0x1e
+ kVK_ANSI_S, // 0x1f
+ kVK_ANSI_D, // 0x20
+ kVK_ANSI_F, // 0x21
+ kVK_ANSI_G, // 0x22
+ kVK_ANSI_H, // 0x23
+ kVK_ANSI_J, // 0x24
+ kVK_ANSI_K, // 0x25
+ kVK_ANSI_L, // 0x26
+ kVK_ANSI_Semicolon, // 0x27
+ kVK_ANSI_Quote, // 0x28
+ kVK_ANSI_Grave, // 0x29
+ kVK_Shift, // 0x2a
+ kVK_ANSI_Backslash, // 0x2b
+ kVK_ANSI_Z, // 0x2c
+ kVK_ANSI_X, // 0x2d
+ kVK_ANSI_C, // 0x2e
+ kVK_ANSI_V, // 0x2f
+ kVK_ANSI_B, // 0x30
+ kVK_ANSI_N, // 0x31
+ kVK_ANSI_M, // 0x32
+ kVK_ANSI_Comma, // 0x33
+ kVK_ANSI_Period, // 0x34
+ kVK_ANSI_Slash, // 0x35
+ kVK_Shift, // 0x36
+ kVK_ANSI_KeypadMultiply, // 0x37
+ kVK_Option, // 0x38
+ kVK_Space, // 0x39
+ kVK_CapsLock, // 0x3a
+ kVK_F1, // 0x3b
+ kVK_F2, // 0x3c
+ kVK_F3, // 0x3d
+ kVK_F4, // 0x3e
+ kVK_F5, // 0x3f
+ kVK_F6, // 0x40
+ kVK_F7, // 0x41
+ kVK_F8, // 0x42
+ kVK_F9, // 0x43
+ kVK_F10, // 0x44
+ 0xFF, // 0x45 -- numlock
+ 0xFF, // 0x46 -- scroll lock
+ kVK_ANSI_Keypad7, // 0x47
+ kVK_ANSI_Keypad8, // 0x48
+ kVK_ANSI_Keypad9, // 0x49
+ kVK_ANSI_KeypadMinus, // 0x4a
+ kVK_ANSI_Keypad4, // 0x4b
+ kVK_ANSI_Keypad5, // 0x4c
+ kVK_ANSI_Keypad6, // 0x4d
+ kVK_ANSI_KeypadPlus, // 0x4e
+ kVK_ANSI_Keypad1, // 0x4f
+ kVK_ANSI_Keypad2, // 0x50
+ kVK_ANSI_Keypad3, // 0x51
+ kVK_ANSI_Keypad0, // 0x52
+ kVK_ANSI_KeypadDecimal, // 0x53
+ 0xFF, // 0x54
+ 0xFF, // 0x55
+ 0xFF, // 0x56
+ kVK_F11, // 0x57
+ kVK_F12, // 0x58
+ 0xFF, // 0x59 -- pause
+ 0xFF, // 0x5a
+ kVK_Control, // 0x5b
+ kVK_Control, // 0x5c
+ 0xFF, // 0x5d -- application
+ 0xFF, // 0x5e -- power
+ 0xFF, // 0x5f -- sleep
+ 0xFF, // 0x60
+ 0xFF, // 0x61
+ 0xFF, // 0x62
+ 0xFF, // 0x63 -- wake
+ 0xFF, // 0x64
+ 0xFF, // 0x65
+ 0xFF, // 0x66
+ 0xFF, // 0x67
+ 0xFF, // 0x68
+ 0xFF, // 0x69
+ 0xFF, // 0x6a
+ 0xFF, // 0x6b
+ 0xFF, // 0x6c
+ 0xFF, // 0x6d
+ 0xFF, // 0x6e
+ 0xFF, // 0x6f
+ 0xFF, // 0x70
+ 0xFF, // 0x71
+ 0xFF, // 0x72
+ 0xFF, // 0x73
+ 0xFF, // 0x74
+ 0xFF, // 0x75
+ 0xFF, // 0x76
+ 0xFF, // 0x77
+ 0xFF, // 0x78
+ 0xFF, // 0x79
+ 0xFF, // 0x7a
+ 0xFF, // 0x7b
+ 0xFF, // 0x7c
+ 0xFF, // 0x7d
+ 0xFF, // 0x7e
+ 0xFF, // 0x7f
+ 0xFF, // 0x80
+ 0xFF, // 0x81
+ 0xFF, // 0x82
+ 0xFF, // 0x83
+ 0xFF, // 0x84
+ 0xFF, // 0x85
+ 0xFF, // 0x86
+ 0xFF, // 0x87
+ 0xFF, // 0x88
+ 0xFF, // 0x89
+ 0xFF, // 0x8a
+ 0xFF, // 0x8b
+ 0xFF, // 0x8c
+ 0xFF, // 0x8d
+ 0xFF, // 0x8e
+ 0xFF, // 0x8f
+ 0xFF, // 0x90
+ 0xFF, // 0x91
+ 0xFF, // 0x92
+ 0xFF, // 0x93
+ 0xFF, // 0x94
+ 0xFF, // 0x95
+ 0xFF, // 0x96
+ 0xFF, // 0x97
+ 0xFF, // 0x98
+ 0xFF, // 0x99
+ 0xFF, // 0x9a
+ 0xFF, // 0x9b
+ 0xFF, // 0x9c
+ 0xFF, // 0x9d
+ 0xFF, // 0x9e
+ 0xFF, // 0x9f
+ 0xFF, // 0xa0
+ 0xFF, // 0xa1
+ 0xFF, // 0xa2
+ 0xFF, // 0xa3
+ 0xFF, // 0xa4
+ 0xFF, // 0xa5
+ 0xFF, // 0xa6
+ 0xFF, // 0xa7
+ 0xFF, // 0xa8
+ 0xFF, // 0xa9
+ 0xFF, // 0xaa
+ 0xFF, // 0xab
+ 0xFF, // 0xac
+ 0xFF, // 0xad
+ 0xFF, // 0xae
+ 0xFF, // 0xaf
+ 0xFF, // 0xb0
+ 0xFF, // 0xb1
+ 0xFF, // 0xb2
+ 0xFF, // 0xb3
+ 0xFF, // 0xb4
+ 0xFF, // 0xb5
+ 0xFF, // 0xb6
+ 0xFF, // 0xb7
+ 0xFF, // 0xb8
+ 0xFF, // 0xb9
+ 0xFF, // 0xba
+ 0xFF, // 0xbb
+ 0xFF, // 0xbc
+ 0xFF, // 0xbd
+ 0xFF, // 0xbe
+ 0xFF, // 0xbf
+ 0xFF, // 0xc0
+ 0xFF, // 0xc1
+ 0xFF, // 0xc2
+ 0xFF, // 0xc3
+ 0xFF, // 0xc4
+ 0xFF, // 0xc5
+ 0xFF, // 0xc6
+ 0xFF, // 0xc7
+ 0xFF, // 0xc8
+ 0xFF, // 0xc9
+ 0xFF, // 0xca
+ 0xFF, // 0xcb
+ 0xFF, // 0xcc
+ 0xFF, // 0xcd
+ 0xFF, // 0xce
+ 0xFF, // 0xcf
+ 0xFF, // 0xd0
+ 0xFF, // 0xd1
+ 0xFF, // 0xd2
+ 0xFF, // 0xd3
+ 0xFF, // 0xd4
+ 0xFF, // 0xd5
+ 0xFF, // 0xd6
+ 0xFF, // 0xd7
+ 0xFF, // 0xd8
+ 0xFF, // 0xd9
+ 0xFF, // 0xda
+ 0xFF, // 0xdb
+ 0xFF, // 0xdc
+ 0xFF, // 0xdd
+ 0xFF, // 0xde
+ 0xFF, // 0xdf
+ 0xFF, // 0xe0
+ 0xFF, // 0xe1
+ 0xFF, // 0xe2
+ 0xFF, // 0xe3
+ 0xFF, // 0xe4
+ 0xFF, // 0xe5
+ 0xFF, // 0xe6
+ 0xFF, // 0xe7
+ 0xFF, // 0xe8
+ 0xFF, // 0xe9
+ 0xFF, // 0xea
+ 0xFF, // 0xeb
+ 0xFF, // 0xec
+ 0xFF, // 0xed
+ 0xFF, // 0xee
+ 0xFF, // 0xef
+ 0xFF, // 0xf0
+ 0xFF, // 0xf1
+ 0xFF, // 0xf2
+ 0xFF, // 0xf3
+ 0xFF, // 0xf4
+ 0xFF, // 0xf5
+ 0xFF, // 0xf6
+ 0xFF, // 0xf7
+ 0xFF, // 0xf8
+ 0xFF, // 0xf9
+ 0xFF, // 0xfa
+ 0xFF, // 0xfb
+ 0xFF, // 0xfc
+ 0xFF, // 0xfd
+ 0xFF, // 0xfe
+};
+
+BOOL mf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
+{
+ CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
+ BOOL keyDown = TRUE;
+ CGEventRef kbEvent;
+ CGKeyCode kCode = 0xFF;
+
+ if (flags & KBD_FLAGS_RELEASE)
+ {
+ keyDown = FALSE;
+ }
+
+ if (flags & KBD_FLAGS_EXTENDED)
+ {
+ switch (code)
+ {
+ // case 0x52: //insert
+ case 0x53:
+ kCode = kVK_ForwardDelete;
+ break;
+
+ case 0x4B:
+ kCode = kVK_LeftArrow;
+ break;
+
+ case 0x47:
+ kCode = kVK_Home;
+ break;
+
+ case 0x4F:
+ kCode = kVK_End;
+ break;
+
+ case 0x48:
+ kCode = kVK_UpArrow;
+ break;
+
+ case 0x50:
+ kCode = kVK_DownArrow;
+ break;
+
+ case 0x49:
+ kCode = kVK_PageUp;
+ break;
+
+ case 0x51:
+ kCode = kVK_PageDown;
+ break;
+
+ case 0x4D:
+ kCode = kVK_RightArrow;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ kCode = keymap[code];
+ }
+
+ kbEvent = CGEventCreateKeyboardEvent(source, kCode, keyDown);
+ CGEventPost(kCGHIDEventTap, kbEvent);
+ CFRelease(kbEvent);
+ CFRelease(source);
+ return TRUE;
+}
+
+BOOL mf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
+{
+ return FALSE;
+}
+
+BOOL mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
+{
+ float width, height;
+ CGWheelCount wheelCount = 2;
+ INT32 scroll_x = 0;
+ INT32 scroll_y = 0;
+
+ if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL))
+ {
+ INT32 scroll = flags & WheelRotationMask;
+
+ if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
+ scroll = -(flags & WheelRotationMask) / 392;
+ else
+ scroll = (flags & WheelRotationMask) / 120;
+
+ if (flags & PTR_FLAGS_WHEEL)
+ scroll_y = scroll;
+ else
+ scroll_x = scroll;
+
+ CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
+ CGEventRef scrollEvent = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitLine,
+ wheelCount, scroll_y, scroll_x);
+ CGEventPost(kCGHIDEventTap, scrollEvent);
+ CFRelease(scrollEvent);
+ CFRelease(source);
+ }
+ else
+ {
+ mfInfo* mfi;
+ CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
+ CGEventType mouseType = kCGEventNull;
+ CGMouseButton mouseButton = kCGMouseButtonLeft;
+ mfi = mf_info_get_instance();
+ // width and height of primary screen (even in multimon setups
+ width = (float)mfi->servscreen_width;
+ height = (float)mfi->servscreen_height;
+ x += mfi->servscreen_xoffset;
+ y += mfi->servscreen_yoffset;
+
+ if (flags & PTR_FLAGS_MOVE)
+ {
+ if (mfi->mouse_down_left == TRUE)
+ {
+ mouseType = kCGEventLeftMouseDragged;
+ }
+ else if (mfi->mouse_down_right == TRUE)
+ {
+ mouseType = kCGEventRightMouseDragged;
+ }
+ else if (mfi->mouse_down_other == TRUE)
+ {
+ mouseType = kCGEventOtherMouseDragged;
+ }
+ else
+ {
+ mouseType = kCGEventMouseMoved;
+ }
+
+ CGEventRef move = CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y),
+ mouseButton // ignored for just movement
+ );
+ CGEventPost(kCGHIDEventTap, move);
+ CFRelease(move);
+ }
+
+ if (flags & PTR_FLAGS_BUTTON1)
+ {
+ mouseButton = kCGMouseButtonLeft;
+
+ if (flags & PTR_FLAGS_DOWN)
+ {
+ mouseType = kCGEventLeftMouseDown;
+ mfi->mouse_down_left = TRUE;
+ }
+ else
+ {
+ mouseType = kCGEventLeftMouseUp;
+ mfi->mouse_down_right = FALSE;
+ }
+ }
+ else if (flags & PTR_FLAGS_BUTTON2)
+ {
+ mouseButton = kCGMouseButtonRight;
+
+ if (flags & PTR_FLAGS_DOWN)
+ {
+ mouseType = kCGEventRightMouseDown;
+ mfi->mouse_down_right = TRUE;
+ }
+ else
+ {
+ mouseType = kCGEventRightMouseUp;
+ mfi->mouse_down_right = FALSE;
+ }
+ }
+ else if (flags & PTR_FLAGS_BUTTON3)
+ {
+ mouseButton = kCGMouseButtonCenter;
+
+ if (flags & PTR_FLAGS_DOWN)
+ {
+ mouseType = kCGEventOtherMouseDown;
+ mfi->mouse_down_other = TRUE;
+ }
+ else
+ {
+ mouseType = kCGEventOtherMouseUp;
+ mfi->mouse_down_other = FALSE;
+ }
+ }
+
+ CGEventRef mouseEvent =
+ CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton);
+ CGEventPost(kCGHIDEventTap, mouseEvent);
+ CFRelease(mouseEvent);
+ CFRelease(source);
+ }
+
+ return TRUE;
+}
+
+BOOL mf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
+{
+ return FALSE;
+}
+
+BOOL mf_input_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code)
+{
+ return FALSE;
+}
+
+BOOL mf_input_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code)
+{
+ return FALSE;
+}
+
+BOOL mf_input_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
+{
+ return FALSE;
+}
+
+BOOL mf_input_extended_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
+{
+ return FALSE;
+}
diff --git a/server/Mac/mf_input.h b/server/Mac/mf_input.h
new file mode 100644
index 0000000..4c039f8
--- /dev/null
+++ b/server/Mac/mf_input.h
@@ -0,0 +1,36 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server (Input)
+ *
+ * Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_INPUT_H
+#define FREERDP_SERVER_MAC_INPUT_H
+
+#include "mf_interface.h"
+
+BOOL mf_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code);
+BOOL mf_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code);
+BOOL mf_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
+BOOL mf_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
+
+// dummy versions
+BOOL mf_input_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code);
+BOOL mf_input_unicode_keyboard_event_dummy(rdpInput* input, UINT16 flags, UINT16 code);
+BOOL mf_input_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
+BOOL mf_input_extended_mouse_event_dummy(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
+
+#endif /* FREERDP_SERVER_MAC_INPUT_H */
diff --git a/server/Mac/mf_interface.c b/server/Mac/mf_interface.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/server/Mac/mf_interface.c
diff --git a/server/Mac/mf_interface.h b/server/Mac/mf_interface.h
new file mode 100644
index 0000000..6ba86f3
--- /dev/null
+++ b/server/Mac/mf_interface.h
@@ -0,0 +1,106 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_INTERFACE_H
+#define FREERDP_SERVER_MAC_INTERFACE_H
+
+#include <pthread.h>
+
+#include <freerdp/config.h>
+#include <freerdp/codec/rfx.h>
+#include <freerdp/codec/nsc.h>
+#include <freerdp/listener.h>
+#include <freerdp/freerdp.h>
+
+#include <winpr/crt.h>
+
+#ifdef WITH_SERVER_CHANNELS
+#include <freerdp/channels/wtsvc.h>
+#endif
+
+#ifdef CHANNEL_RDPSND_SERVER
+#include <freerdp/server/rdpsnd.h>
+#include "mf_rdpsnd.h"
+#endif
+
+#ifdef CHANNEL_AUDIN_SERVER
+#include <freerdp/server/audin.h>
+#include "mf_audin.h"
+#endif
+
+#include "mf_types.h"
+
+struct mf_peer_context
+{
+ rdpContext _p;
+
+ mfInfo* info;
+ wStream* s;
+ BOOL activated;
+ UINT32 frame_id;
+ BOOL audin_open;
+ RFX_CONTEXT* rfx_context;
+ NSC_CONTEXT* nsc_context;
+
+#ifdef WITH_SERVER_CHANNELS
+ HANDLE vcm;
+#endif
+
+#ifdef CHANNEL_AUDIN_SERVER
+ audin_server_context* audin;
+#endif
+
+#ifdef CHANNEL_RDPSND_SERVER
+ RdpsndServerContext* rdpsnd;
+#endif
+};
+
+struct mf_info
+{
+ // STREAM* s;
+
+ // screen and monitor info
+ UINT32 screenID;
+ UINT32 virtscreen_width;
+ UINT32 virtscreen_height;
+ UINT32 servscreen_width;
+ UINT32 servscreen_height;
+ UINT32 servscreen_xoffset;
+ UINT32 servscreen_yoffset;
+
+ int bitsPerPixel;
+ int peerCount;
+ int activePeerCount;
+ int framesPerSecond;
+ freerdp_peer** peers;
+ unsigned int framesWaiting;
+ UINT32 scale;
+
+ RFX_RECT invalid;
+ pthread_mutex_t mutex;
+
+ BOOL mouse_down_left;
+ BOOL mouse_down_right;
+ BOOL mouse_down_other;
+ BOOL input_disabled;
+ BOOL force_all_disconnect;
+};
+
+#endif /* FREERDP_SERVER_MAC_INTERFACE_H */
diff --git a/server/Mac/mf_mountain_lion.c b/server/Mac/mf_mountain_lion.c
new file mode 100644
index 0000000..9db86b8
--- /dev/null
+++ b/server/Mac/mf_mountain_lion.c
@@ -0,0 +1,269 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * OS X Server Event Handling
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 <dispatch/dispatch.h>
+#include <CoreGraphics/CoreGraphics.h>
+#include <CoreVideo/CoreVideo.h>
+#include <IOKit/IOKitLib.h>
+#include <IOSurface/IOSurface.h>
+
+#include "mf_mountain_lion.h"
+
+dispatch_semaphore_t region_sem;
+dispatch_semaphore_t data_sem;
+dispatch_queue_t screen_update_q;
+CGDisplayStreamRef stream;
+
+CGDisplayStreamUpdateRef lastUpdate = NULL;
+
+BYTE* localBuf = NULL;
+
+BOOL ready = FALSE;
+
+void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef,
+ CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status,
+ uint64_t displayTime, IOSurfaceRef frameSurface,
+ CGDisplayStreamUpdateRef updateRef) {
+ dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
+
+ // may need to move this down
+ if (ready == TRUE)
+ {
+
+ RFX_RECT rect;
+ unsigned long offset_beg;
+ unsigned long stride;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = 0;
+ rect.height = 0;
+ mf_mlion_peek_dirty_region(&rect);
+
+ // lock surface
+ IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
+ // get pointer
+ void* baseAddress = IOSurfaceGetBaseAddress(frameSurface);
+ // copy region
+
+ stride = IOSurfaceGetBytesPerRow(frameSurface);
+ // memcpy(localBuf, baseAddress + offset_beg, surflen);
+ for (int i = 0; i < rect.height; i++)
+ {
+ offset_beg = (stride * (rect.y + i) + (rect.x * 4));
+ memcpy(localBuf + offset_beg, baseAddress + offset_beg, rect.width * 4);
+ }
+
+ // unlock surface
+ IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
+
+ ready = FALSE;
+ dispatch_semaphore_signal(data_sem);
+ }
+
+ if (status != kCGDisplayStreamFrameStatusFrameComplete)
+ {
+ switch (status)
+ {
+ case kCGDisplayStreamFrameStatusFrameIdle:
+ break;
+
+ case kCGDisplayStreamFrameStatusStopped:
+ break;
+
+ case kCGDisplayStreamFrameStatusFrameBlank:
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (lastUpdate == NULL)
+ {
+ CFRetain(updateRef);
+ lastUpdate = updateRef;
+ }
+ else
+ {
+ CGDisplayStreamUpdateRef tmpRef;
+ tmpRef = lastUpdate;
+ lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
+ CFRelease(tmpRef);
+ }
+
+ dispatch_semaphore_signal(region_sem);
+};
+
+int mf_mlion_display_info(UINT32* disp_width, UINT32* disp_height, UINT32* scale)
+{
+ CGDirectDisplayID display_id;
+
+ display_id = CGMainDisplayID();
+
+ CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
+
+ size_t pixelWidth = CGDisplayModeGetPixelWidth(mode);
+ // size_t pixelHeight = CGDisplayModeGetPixelHeight(mode);
+
+ size_t wide = CGDisplayPixelsWide(display_id);
+ size_t high = CGDisplayPixelsHigh(display_id);
+
+ CGDisplayModeRelease(mode);
+
+ *disp_width = wide; // pixelWidth;
+ *disp_height = high; // pixelHeight;
+ *scale = pixelWidth / wide;
+
+ return 0;
+}
+
+int mf_mlion_screen_updates_init()
+{
+ CGDirectDisplayID display_id;
+
+ display_id = CGMainDisplayID();
+
+ screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL);
+
+ region_sem = dispatch_semaphore_create(1);
+ data_sem = dispatch_semaphore_create(1);
+
+ UINT32 pixelWidth;
+ UINT32 pixelHeight;
+ UINT32 scale;
+
+ mf_mlion_display_info(&pixelWidth, &pixelHeight, &scale);
+
+ localBuf = malloc(pixelWidth * pixelHeight * 4);
+ if (!localBuf)
+ return -1;
+
+ CFDictionaryRef opts;
+
+ void* keys[2];
+ void* values[2];
+
+ keys[0] = (void*)kCGDisplayStreamShowCursor;
+ values[0] = (void*)kCFBooleanFalse;
+
+ opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1,
+ NULL, NULL);
+
+ stream = CGDisplayStreamCreateWithDispatchQueue(display_id, pixelWidth, pixelHeight, 'BGRA',
+ opts, screen_update_q, streamHandler);
+
+ CFRelease(opts);
+
+ return 0;
+}
+
+int mf_mlion_start_getting_screen_updates()
+{
+ CGError err;
+
+ err = CGDisplayStreamStart(stream);
+
+ if (err != kCGErrorSuccess)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+int mf_mlion_stop_getting_screen_updates()
+{
+ CGError err;
+
+ err = CGDisplayStreamStop(stream);
+
+ if (err != kCGErrorSuccess)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+int mf_mlion_get_dirty_region(RFX_RECT* invalid)
+{
+ dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
+
+ if (lastUpdate != NULL)
+ {
+ mf_mlion_peek_dirty_region(invalid);
+ }
+
+ dispatch_semaphore_signal(region_sem);
+
+ return 0;
+}
+
+int mf_mlion_peek_dirty_region(RFX_RECT* invalid)
+{
+ size_t num_rects;
+ CGRect dirtyRegion;
+
+ const CGRect* rects =
+ CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects);
+
+ if (num_rects == 0)
+ {
+ return 0;
+ }
+
+ dirtyRegion = *rects;
+ for (size_t i = 0; i < num_rects; i++)
+ {
+ dirtyRegion = CGRectUnion(dirtyRegion, *(rects + i));
+ }
+
+ invalid->x = dirtyRegion.origin.x;
+ invalid->y = dirtyRegion.origin.y;
+ invalid->height = dirtyRegion.size.height;
+ invalid->width = dirtyRegion.size.width;
+
+ return 0;
+}
+
+int mf_mlion_clear_dirty_region()
+{
+ dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
+
+ CFRelease(lastUpdate);
+ lastUpdate = NULL;
+
+ dispatch_semaphore_signal(region_sem);
+
+ return 0;
+}
+
+int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData)
+{
+ dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
+ ready = TRUE;
+ dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
+ dispatch_semaphore_signal(region_sem);
+
+ // this second wait allows us to block until data is copied... more on this later
+ dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
+ *pxData = localBuf;
+ dispatch_semaphore_signal(data_sem);
+
+ return 0;
+}
diff --git a/server/Mac/mf_mountain_lion.h b/server/Mac/mf_mountain_lion.h
new file mode 100644
index 0000000..c1fbe9b
--- /dev/null
+++ b/server/Mac/mf_mountain_lion.h
@@ -0,0 +1,38 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * OS X Server Event Handling
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_MLION_H
+#define FREERDP_SERVER_MAC_MLION_H
+
+#include <freerdp/codec/rfx.h>
+
+int mf_mlion_display_info(UINT32* disp_width, UINT32* dispHeight, UINT32* scale);
+
+int mf_mlion_screen_updates_init(void);
+
+int mf_mlion_start_getting_screen_updates(void);
+int mf_mlion_stop_getting_screen_updates(void);
+
+int mf_mlion_get_dirty_region(RFX_RECT* invalid);
+int mf_mlion_peek_dirty_region(RFX_RECT* invalid);
+int mf_mlion_clear_dirty_region(void);
+
+int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData);
+
+#endif /* FREERDP_SERVER_MAC_MLION_H */
diff --git a/server/Mac/mf_peer.c b/server/Mac/mf_peer.c
new file mode 100644
index 0000000..0669127
--- /dev/null
+++ b/server/Mac/mf_peer.c
@@ -0,0 +1,485 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 <freerdp/config.h>
+
+#include <freerdp/listener.h>
+#include <freerdp/codec/rfx.h>
+#include <winpr/stream.h>
+#include <freerdp/peer.h>
+#include <freerdp/codec/color.h>
+
+#include <winpr/crt.h>
+#include <winpr/assert.h>
+
+#include "mf_peer.h"
+#include "mf_info.h"
+#include "mf_input.h"
+#include "mf_event.h"
+#include "mf_rdpsnd.h"
+#include "mf_audin.h"
+
+#include <mach/clock.h>
+#include <mach/mach.h>
+#include <dispatch/dispatch.h>
+
+#include "OpenGL/OpenGL.h"
+#include "OpenGL/gl.h"
+
+#include "CoreVideo/CoreVideo.h"
+
+#include <freerdp/log.h>
+#define TAG SERVER_TAG("mac")
+
+// refactor these
+static int info_last_sec = 0;
+static int info_last_nsec = 0;
+
+static dispatch_source_t info_timer;
+static dispatch_queue_t info_queue;
+
+static mfEventQueue* info_event_queue;
+
+static CGLContextObj glContext;
+static CGContextRef bmp;
+static CGImageRef img;
+
+static void mf_peer_context_free(freerdp_peer* client, rdpContext* context);
+
+static BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount)
+{
+ if (info_event_queue->pipe_fd[0] == -1)
+ return TRUE;
+
+ rfds[*rcount] = (void*)(long)info_event_queue->pipe_fd[0];
+ (*rcount)++;
+ return TRUE;
+}
+
+static void mf_peer_rfx_update(freerdp_peer* client)
+{
+ // check
+ mfInfo* mfi = mf_info_get_instance();
+ mf_info_find_invalid_region(mfi);
+
+ if (mf_info_have_invalid_region(mfi) == false)
+ {
+ return;
+ }
+
+ long width;
+ long height;
+ int pitch;
+ BYTE* dataBits = NULL;
+ mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch);
+ mf_info_clear_invalid_region(mfi);
+ // encode
+ wStream* s;
+ RFX_RECT rect;
+ rdpUpdate* update;
+ mfPeerContext* mfp;
+ SURFACE_BITS_COMMAND cmd = { 0 };
+
+ WINPR_ASSERT(client);
+
+ mfp = (mfPeerContext*)client->context;
+ WINPR_ASSERT(mfp);
+
+ update = client->context->update;
+ WINPR_ASSERT(update);
+
+ s = mfp->s;
+ WINPR_ASSERT(s);
+
+ Stream_Clear(s);
+ Stream_SetPosition(s, 0);
+ UINT32 x = mfi->invalid.x / mfi->scale;
+ UINT32 y = mfi->invalid.y / mfi->scale;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+
+ rfx_context_reset(mfp->rfx_context, mfi->servscreen_width, mfi->servscreen_height);
+
+ if (!(rfx_compose_message(mfp->rfx_context, s, &rect, 1, (BYTE*)dataBits, rect.width,
+ rect.height, pitch)))
+ {
+ return;
+ }
+
+ cmd.destLeft = x;
+ cmd.destTop = y;
+ cmd.destRight = x + rect.width;
+ cmd.destBottom = y + rect.height;
+ cmd.bmp.bpp = 32;
+ cmd.bmp.codecID = 3;
+ cmd.bmp.width = rect.width;
+ cmd.bmp.height = rect.height;
+ cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
+ cmd.bmp.bitmapData = Stream_Buffer(s);
+ // send
+ update->SurfaceBits(update->context, &cmd);
+ // clean up... maybe?
+}
+
+static BOOL mf_peer_check_fds(freerdp_peer* client)
+{
+ mfPeerContext* context = (mfPeerContext*)client->context;
+ mfEvent* event;
+
+ if (context->activated == FALSE)
+ return TRUE;
+
+ event = mf_event_peek(info_event_queue);
+
+ if (event != NULL)
+ {
+ if (event->type == FREERDP_SERVER_MAC_EVENT_TYPE_REGION)
+ {
+ }
+ else if (event->type == FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK)
+ {
+ event = mf_event_pop(info_event_queue);
+ mf_peer_rfx_update(client);
+ mf_event_free(event);
+ }
+ }
+
+ return TRUE;
+}
+
+/* Called when we have a new peer connecting */
+static BOOL mf_peer_context_new(freerdp_peer* client, rdpContext* context)
+{
+ rdpSettings* settings;
+ mfPeerContext* peer = (mfPeerContext*)context;
+
+ WINPR_ASSERT(client);
+ WINPR_ASSERT(context);
+
+ settings = context->settings;
+ WINPR_ASSERT(settings);
+
+ if (!(peer->info = mf_info_get_instance()))
+ return FALSE;
+
+ if (!(peer->rfx_context = rfx_context_new_ex(
+ TRUE, freerdp_settings_get_uint32(settings, FreeRDP_ThreadingFlags))))
+ goto fail;
+
+ rfx_context_reset(peer->rfx_context,
+ freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
+ freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
+ rfx_context_set_mode(peer->rfx_context, RLGR3);
+ rfx_context_set_pixel_format(peer->rfx_context, PIXEL_FORMAT_BGRA32);
+
+ if (!(peer->s = Stream_New(NULL, 0xFFFF)))
+ goto fail;
+
+ peer->vcm = WTSOpenServerA((LPSTR)client->context);
+
+ if (!peer->vcm || (peer->vcm == INVALID_HANDLE_VALUE))
+ goto fail;
+
+ mf_info_peer_register(peer->info, peer);
+ return TRUE;
+fail:
+ mf_peer_context_free(client, context);
+ return FALSE;
+}
+
+/* Called after a peer disconnects */
+static void mf_peer_context_free(freerdp_peer* client, rdpContext* context)
+{
+ mfPeerContext* peer = (mfPeerContext*)context;
+ if (context)
+ {
+ mf_info_peer_unregister(peer->info, peer);
+ dispatch_suspend(info_timer);
+ Stream_Free(peer->s, TRUE);
+ rfx_context_free(peer->rfx_context);
+ // nsc_context_free(peer->nsc_context);
+#ifdef CHANNEL_AUDIN_SERVER
+
+ mf_peer_audin_uninit(peer);
+
+#endif
+#ifdef CHANNEL_RDPSND_SERVER
+ mf_peer_rdpsnd_stop();
+
+ if (peer->rdpsnd)
+ rdpsnd_server_context_free(peer->rdpsnd);
+
+#endif
+ WTSCloseServer(peer->vcm);
+ }
+}
+
+/* Called when a new client connects */
+static BOOL mf_peer_init(freerdp_peer* client)
+{
+ client->ContextSize = sizeof(mfPeerContext);
+ client->ContextNew = mf_peer_context_new;
+ client->ContextFree = mf_peer_context_free;
+
+ if (!freerdp_peer_context_new(client))
+ return FALSE;
+
+ info_event_queue = mf_event_queue_new();
+ info_queue = dispatch_queue_create("FreeRDP.update.timer", DISPATCH_QUEUE_SERIAL);
+ info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue);
+
+ if (info_timer)
+ {
+ // DEBUG_WARN( "created timer\n");
+ dispatch_source_set_timer(info_timer, DISPATCH_TIME_NOW, 42ull * NSEC_PER_MSEC,
+ 100ull * NSEC_PER_MSEC);
+ dispatch_source_set_event_handler(info_timer, ^{
+ // DEBUG_WARN( "dispatch\n");
+ mfEvent* event = mf_event_new(FREERDP_SERVER_MAC_EVENT_TYPE_FRAME_TICK);
+ mf_event_push(info_event_queue, (mfEvent*)event);
+ });
+ dispatch_resume(info_timer);
+ }
+
+ return TRUE;
+}
+
+static BOOL mf_peer_post_connect(freerdp_peer* client)
+{
+ mfInfo* mfi = mf_info_get_instance();
+
+ WINPR_ASSERT(client);
+
+ mfPeerContext* context = (mfPeerContext*)client->context;
+ WINPR_ASSERT(context);
+
+ rdpSettings* settings = client->context->settings;
+ WINPR_ASSERT(settings);
+
+ mfi->scale = 1;
+ // mfi->servscreen_width = 2880 / mfi->scale;
+ // mfi->servscreen_height = 1800 / mfi->scale;
+ UINT32 bitsPerPixel = 32;
+
+ if ((freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != mfi->servscreen_width) ||
+ (freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) != mfi->servscreen_height))
+ {
+ }
+
+ if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, mfi->servscreen_width))
+ return FALSE;
+ if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, mfi->servscreen_height))
+ return FALSE;
+ if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, bitsPerPixel))
+ return FALSE;
+
+ WINPR_ASSERT(client->context->update);
+ WINPR_ASSERT(client->context->update->DesktopResize);
+ client->context->update->DesktopResize(client->context);
+
+ mfi->mouse_down_left = FALSE;
+ mfi->mouse_down_right = FALSE;
+ mfi->mouse_down_other = FALSE;
+#ifdef CHANNEL_RDPSND_SERVER
+
+ if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd"))
+ {
+ mf_peer_rdpsnd_init(context); /* Audio Output */
+ }
+
+#endif
+ /* Dynamic Virtual Channels */
+#ifdef CHANNEL_AUDIN_SERVER
+ mf_peer_audin_init(context); /* Audio Input */
+#endif
+ return TRUE;
+}
+
+static BOOL mf_peer_activate(freerdp_peer* client)
+{
+ WINPR_ASSERT(client);
+
+ mfPeerContext* context = (mfPeerContext*)client->context;
+ WINPR_ASSERT(context);
+
+ rdpSettings* settings = client->context->settings;
+ WINPR_ASSERT(settings);
+
+ rfx_context_reset(context->rfx_context,
+ freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
+ freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
+ context->activated = TRUE;
+ return TRUE;
+}
+
+static BOOL mf_peer_synchronize_event(rdpInput* input, UINT32 flags)
+{
+ return TRUE;
+}
+
+static BOOL mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
+{
+ bool state_down = FALSE;
+
+ if (flags == KBD_FLAGS_DOWN)
+ {
+ state_down = TRUE;
+ }
+ return TRUE;
+}
+
+static BOOL mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
+{
+ return FALSE;
+}
+
+static BOOL mf_peer_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
+{
+ return FALSE;
+}
+
+static void* mf_peer_main_loop(void* arg)
+{
+ mfPeerContext* context;
+ rdpSettings* settings;
+ rdpInput* input;
+ rdpUpdate* update;
+ freerdp_peer* client = (freerdp_peer*)arg;
+
+ if (!mf_peer_init(client))
+ goto fail;
+
+ const mf_server_info* info = client->ContextExtra;
+ WINPR_ASSERT(info);
+
+ WINPR_ASSERT(client->context);
+
+ settings = client->context->settings;
+ WINPR_ASSERT(settings);
+
+ /* Initialize the real server settings here */
+ rdpPrivateKey* key = freerdp_key_new_from_file(info->key);
+ if (!key)
+ goto fail;
+ if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
+ goto fail;
+ rdpCertificate* cert = freerdp_certificate_new_from_file(info->cert);
+ if (!cert)
+ goto fail;
+ if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
+ goto fail;
+
+ if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
+ goto fail;
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
+ goto fail;
+ if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
+ goto fail;
+
+ if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE))
+ goto fail;
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, FALSE))
+ goto fail;
+
+ client->PostConnect = mf_peer_post_connect;
+ client->Activate = mf_peer_activate;
+
+ input = client->context->input;
+ WINPR_ASSERT(input);
+
+ input->SynchronizeEvent = mf_peer_synchronize_event;
+ input->KeyboardEvent = mf_input_keyboard_event; // mf_peer_keyboard_event;
+ input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event;
+ input->MouseEvent = mf_input_mouse_event;
+ input->ExtendedMouseEvent = mf_input_extended_mouse_event;
+
+ update = client->context->update;
+ WINPR_ASSERT(update);
+
+ // update->RefreshRect = mf_peer_refresh_rect;
+ update->SuppressOutput = mf_peer_suppress_output;
+
+ WINPR_ASSERT(client->Initialize);
+ const BOOL rc = client->Initialize(client);
+ if (!rc)
+ goto fail;
+ context = (mfPeerContext*)client->context;
+
+ while (1)
+ {
+ DWORD status;
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
+ DWORD count = client->GetEventHandles(client, handles, ARRAYSIZE(handles));
+
+ if ((count == 0) || (count == MAXIMUM_WAIT_OBJECTS))
+ {
+ WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
+ break;
+ }
+
+ handles[count++] = WTSVirtualChannelManagerGetEventHandle(context->vcm);
+
+ status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
+ if (status == WAIT_FAILED)
+ {
+ WLog_ERR(TAG, "WaitForMultipleObjects failed");
+ break;
+ }
+
+ if (client->CheckFileDescriptor(client) != TRUE)
+ {
+ break;
+ }
+
+ if ((mf_peer_check_fds(client)) != TRUE)
+ {
+ break;
+ }
+
+ if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
+ {
+ break;
+ }
+ }
+
+ client->Disconnect(client);
+ freerdp_peer_context_free(client);
+fail:
+ freerdp_peer_free(client);
+ return NULL;
+}
+
+BOOL mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
+{
+ pthread_t th;
+
+ WINPR_ASSERT(instance);
+ WINPR_ASSERT(client);
+
+ client->ContextExtra = instance->info;
+ if (pthread_create(&th, 0, mf_peer_main_loop, client) == 0)
+ {
+ pthread_detach(th);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/server/Mac/mf_peer.h b/server/Mac/mf_peer.h
new file mode 100644
index 0000000..e4a966c
--- /dev/null
+++ b/server/Mac/mf_peer.h
@@ -0,0 +1,33 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_PEER_H
+#define FREERDP_SERVER_MAC_PEER_H
+
+#include "mf_interface.h"
+
+typedef struct
+{
+ const char* cert;
+ const char* key;
+} mf_server_info;
+
+BOOL mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client);
+
+#endif /* FREERDP_SERVER_MAC_PEER_H */
diff --git a/server/Mac/mf_rdpsnd.c b/server/Mac/mf_rdpsnd.c
new file mode 100644
index 0000000..e1946f2
--- /dev/null
+++ b/server/Mac/mf_rdpsnd.c
@@ -0,0 +1,200 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server (Audio Output)
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2015 Thincast Technologies GmbH
+ * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
+ *
+ * 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 <freerdp/config.h>
+
+#include <freerdp/server/rdpsnd.h>
+
+#include "mf_info.h"
+#include "mf_rdpsnd.h"
+#include "mf_interface.h"
+
+#include <winpr/sysinfo.h>
+#include <freerdp/server/server-common.h>
+#include <freerdp/log.h>
+#define TAG SERVER_TAG("mac")
+
+AQRecorderState recorderState;
+
+static void mf_peer_rdpsnd_activated(RdpsndServerContext* context)
+{
+ OSStatus status;
+ BOOL formatAgreed = FALSE;
+ AUDIO_FORMAT* agreedFormat = NULL;
+ // we should actually loop through the list of client formats here
+ // and see if we can send the client something that it supports...
+ WLog_DBG(TAG, "Client supports the following %d formats: ", context->num_client_formats);
+
+ int i = 0;
+ for (; i < context->num_client_formats; i++)
+ {
+ /* TODO: improve the way we agree on a format */
+ for (int j = 0; j < context->num_server_formats; j++)
+ {
+ if ((context->client_formats[i].wFormatTag == context->server_formats[j].wFormatTag) &&
+ (context->client_formats[i].nChannels == context->server_formats[j].nChannels) &&
+ (context->client_formats[i].nSamplesPerSec ==
+ context->server_formats[j].nSamplesPerSec))
+ {
+ WLog_DBG(TAG, "agreed on format!");
+ formatAgreed = TRUE;
+ agreedFormat = (AUDIO_FORMAT*)&context->server_formats[j];
+ break;
+ }
+ }
+
+ if (formatAgreed == TRUE)
+ break;
+ }
+
+ if (formatAgreed == FALSE)
+ {
+ WLog_DBG(TAG, "Could not agree on a audio format with the server");
+ return;
+ }
+
+ context->SelectFormat(context, i);
+ context->SetVolume(context, 0x7FFF, 0x7FFF);
+
+ switch (agreedFormat->wFormatTag)
+ {
+ case WAVE_FORMAT_ALAW:
+ recorderState.dataFormat.mFormatID = kAudioFormatDVIIntelIMA;
+ break;
+
+ case WAVE_FORMAT_PCM:
+ recorderState.dataFormat.mFormatID = kAudioFormatLinearPCM;
+ break;
+
+ default:
+ recorderState.dataFormat.mFormatID = kAudioFormatLinearPCM;
+ break;
+ }
+
+ recorderState.dataFormat.mSampleRate = agreedFormat->nSamplesPerSec;
+ recorderState.dataFormat.mFormatFlags =
+ kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
+ recorderState.dataFormat.mBytesPerPacket = 4;
+ recorderState.dataFormat.mFramesPerPacket = 1;
+ recorderState.dataFormat.mBytesPerFrame = 4;
+ recorderState.dataFormat.mChannelsPerFrame = agreedFormat->nChannels;
+ recorderState.dataFormat.mBitsPerChannel = agreedFormat->wBitsPerSample;
+ recorderState.snd_context = context;
+ status =
+ AudioQueueNewInput(&recorderState.dataFormat, mf_peer_rdpsnd_input_callback, &recorderState,
+ NULL, kCFRunLoopCommonModes, 0, &recorderState.queue);
+
+ if (status != noErr)
+ {
+ WLog_DBG(TAG, "Failed to create a new Audio Queue. Status code: %" PRId32 "", status);
+ }
+
+ UInt32 dataFormatSize = sizeof(recorderState.dataFormat);
+ AudioQueueGetProperty(recorderState.queue, kAudioConverterCurrentInputStreamDescription,
+ &recorderState.dataFormat, &dataFormatSize);
+ mf_rdpsnd_derive_buffer_size(recorderState.queue, &recorderState.dataFormat, 0.05,
+ &recorderState.bufferByteSize);
+
+ for (int i = 0; i < SND_NUMBUFFERS; ++i)
+ {
+ AudioQueueAllocateBuffer(recorderState.queue, recorderState.bufferByteSize,
+ &recorderState.buffers[i]);
+ AudioQueueEnqueueBuffer(recorderState.queue, recorderState.buffers[i], 0, NULL);
+ }
+
+ recorderState.currentPacket = 0;
+ recorderState.isRunning = true;
+ AudioQueueStart(recorderState.queue, NULL);
+}
+
+BOOL mf_peer_rdpsnd_init(mfPeerContext* context)
+{
+ context->rdpsnd = rdpsnd_server_context_new(context->vcm);
+ context->rdpsnd->rdpcontext = &context->_p;
+ context->rdpsnd->data = context;
+ context->rdpsnd->num_server_formats =
+ server_rdpsnd_get_formats(&context->rdpsnd->server_formats);
+
+ if (context->rdpsnd->num_server_formats > 0)
+ context->rdpsnd->src_format = &context->rdpsnd->server_formats[0];
+
+ context->rdpsnd->Activated = mf_peer_rdpsnd_activated;
+ context->rdpsnd->Initialize(context->rdpsnd, TRUE);
+ return TRUE;
+}
+
+BOOL mf_peer_rdpsnd_stop()
+{
+ recorderState.isRunning = false;
+ AudioQueueStop(recorderState.queue, true);
+ return TRUE;
+}
+
+void mf_peer_rdpsnd_input_callback(void* inUserData, AudioQueueRef inAQ,
+ AudioQueueBufferRef inBuffer, const AudioTimeStamp* inStartTime,
+ UInt32 inNumberPacketDescriptions,
+ const AudioStreamPacketDescription* inPacketDescs)
+{
+ OSStatus status;
+ AQRecorderState* rState;
+ rState = inUserData;
+
+ if (inNumberPacketDescriptions == 0 && rState->dataFormat.mBytesPerPacket != 0)
+ {
+ inNumberPacketDescriptions =
+ inBuffer->mAudioDataByteSize / rState->dataFormat.mBytesPerPacket;
+ }
+
+ if (rState->isRunning == 0)
+ {
+ return;
+ }
+
+ rState->snd_context->SendSamples(rState->snd_context, inBuffer->mAudioData,
+ inBuffer->mAudioDataByteSize / 4,
+ (UINT16)(GetTickCount() & 0xffff));
+ status = AudioQueueEnqueueBuffer(rState->queue, inBuffer, 0, NULL);
+
+ if (status != noErr)
+ {
+ WLog_DBG(TAG, "AudioQueueEnqueueBuffer() returned status = %" PRId32 "", status);
+ }
+}
+
+void mf_rdpsnd_derive_buffer_size(AudioQueueRef audioQueue,
+ AudioStreamBasicDescription* ASBDescription, Float64 seconds,
+ UInt32* outBufferSize)
+{
+ static const int maxBufferSize = 0x50000;
+ int maxPacketSize = ASBDescription->mBytesPerPacket;
+
+ if (maxPacketSize == 0)
+ {
+ UInt32 maxVBRPacketSize = sizeof(maxPacketSize);
+ AudioQueueGetProperty(audioQueue, kAudioQueueProperty_MaximumOutputPacketSize,
+ // in Mac OS X v10.5, instead use
+ // kAudioConverterPropertyMaximumOutputPacketSize
+ &maxPacketSize, &maxVBRPacketSize);
+ }
+
+ Float64 numBytesForTime = ASBDescription->mSampleRate * maxPacketSize * seconds;
+ *outBufferSize = (UInt32)(numBytesForTime < maxBufferSize ? numBytesForTime : maxBufferSize);
+}
diff --git a/server/Mac/mf_rdpsnd.h b/server/Mac/mf_rdpsnd.h
new file mode 100644
index 0000000..28bcb0d
--- /dev/null
+++ b/server/Mac/mf_rdpsnd.h
@@ -0,0 +1,58 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server (Audio Output)
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_RDPSND_H
+#define FREERDP_SERVER_MAC_RDPSND_H
+
+#include <CoreAudio/CoreAudio.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <freerdp/freerdp.h>
+#include <freerdp/listener.h>
+#include <freerdp/server/rdpsnd.h>
+
+#include "mf_types.h"
+#include "mfreerdp.h"
+
+void mf_rdpsnd_derive_buffer_size(AudioQueueRef audioQueue,
+ AudioStreamBasicDescription* ASBDescription, Float64 seconds,
+ UInt32* outBufferSize);
+
+void mf_peer_rdpsnd_input_callback(void* inUserData, AudioQueueRef inAQ,
+ AudioQueueBufferRef inBuffer, const AudioTimeStamp* inStartTime,
+ UInt32 inNumberPacketDescriptions,
+ const AudioStreamPacketDescription* inPacketDescs);
+
+#define SND_NUMBUFFERS 3
+typedef struct
+{
+ AudioStreamBasicDescription dataFormat;
+ AudioQueueRef queue;
+ AudioQueueBufferRef buffers[SND_NUMBUFFERS];
+ AudioFileID audioFile;
+ UInt32 bufferByteSize;
+ SInt64 currentPacket;
+ bool isRunning;
+ RdpsndServerContext* snd_context;
+} AQRecorderState;
+
+BOOL mf_peer_rdpsnd_init(mfPeerContext* context);
+BOOL mf_peer_rdpsnd_stop(void);
+
+#endif /* FREERDP_SERVER_MAC_RDPSND_H */
diff --git a/server/Mac/mf_types.h b/server/Mac/mf_types.h
new file mode 100644
index 0000000..e33be83
--- /dev/null
+++ b/server/Mac/mf_types.h
@@ -0,0 +1,33 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Client
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2023 Armin Novak <anovak@thincst.com>
+ * Copyright 2023 Thincast Technologies GmbH
+ *
+ * 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 FREERDP_SERVER_MAC_TYPES_H
+#define FREERDP_SERVER_MAC_TYPES_H
+
+#include <pthread.h>
+
+#include <freerdp/config.h>
+
+#include <winpr/crt.h>
+
+typedef struct mf_info mfInfo;
+typedef struct mf_peer_context mfPeerContext;
+
+#endif /* FREERDP_SERVER_MAC_TYPES_H */
diff --git a/server/Mac/mfreerdp.c b/server/Mac/mfreerdp.c
new file mode 100644
index 0000000..8a3fffd
--- /dev/null
+++ b/server/Mac/mfreerdp.c
@@ -0,0 +1,108 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 <freerdp/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include <CoreGraphics/CGEvent.h>
+
+#include <winpr/crt.h>
+#include <winpr/wtsapi.h>
+#include <winpr/assert.h>
+
+#include <freerdp/freerdp.h>
+#include <freerdp/constants.h>
+#include <freerdp/channels/wtsvc.h>
+#include <freerdp/channels/channels.h>
+#include <freerdp/server/server-common.h>
+
+#include "mfreerdp.h"
+#include "mf_peer.h"
+
+#include <freerdp/log.h>
+#define TAG SERVER_TAG("mac")
+
+static void mf_server_main_loop(freerdp_listener* instance)
+{
+ WINPR_ASSERT(instance);
+ WINPR_ASSERT(instance->GetEventHandles);
+ WINPR_ASSERT(instance->CheckFileDescriptor);
+
+ while (1)
+ {
+ DWORD status;
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
+ DWORD count = instance->GetEventHandles(instance, handles, ARRAYSIZE(handles));
+
+ if (count == 0)
+ {
+ WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
+ break;
+ }
+
+ status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
+ if (status == WAIT_FAILED)
+ {
+ WLog_ERR(TAG, "WaitForMultipleObjects failed");
+ break;
+ }
+
+ if (instance->CheckFileDescriptor(instance) != TRUE)
+ {
+ break;
+ }
+ }
+
+ instance->Close(instance);
+}
+
+int main(int argc, char* argv[])
+{
+ freerdp_server_warn_unmaintained(argc, argv);
+ mf_server_info info = { .key = "server.key", .cert = "server.crt" };
+
+ freerdp_listener* instance;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
+
+ if (!(instance = freerdp_listener_new()))
+ return 1;
+
+ instance->info = &info;
+ instance->PeerAccepted = mf_peer_accepted;
+
+ if (instance->Open(instance, NULL, 3389))
+ {
+ mf_server_main_loop(instance);
+ }
+
+ freerdp_listener_free(instance);
+
+ return 0;
+}
diff --git a/server/Mac/mfreerdp.h b/server/Mac/mfreerdp.h
new file mode 100644
index 0000000..38fa25b
--- /dev/null
+++ b/server/Mac/mfreerdp.h
@@ -0,0 +1,28 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Mac OS X Server
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
+ *
+ * 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 FREERDP_SERVER_MAC_FREERDP_H
+#define FREERDP_SERVER_MAC_FREERDP_H
+
+#include <freerdp/freerdp.h>
+#include <freerdp/listener.h>
+#include <freerdp/codec/rfx.h>
+
+#endif /* FREERDP_SERVER_MAC_FREERDP_H */