From ee6ba77e17eff85d6a5b23c93266bf8505cda8c9 Mon Sep 17 00:00:00 2001 From: Gerasim Troeglazov <3dEyes@gmail.com> Date: Tue, 25 Sep 2018 22:11:54 +1000 Subject: [PATCH] FreeRDP: add recipe for 2.0.0~git version * revisions newer than afb0d750 not working. don't bump! * cliboard not implemented (you need disable clibpord with key -clipboard) --- net-misc/freerdp/freerdp-2.0.0~git.recipe | 118 ++ .../patches/freerdp-2.0.0~git.patchset | 1263 +++++++++++++++++ 2 files changed, 1381 insertions(+) create mode 100644 net-misc/freerdp/freerdp-2.0.0~git.recipe create mode 100644 net-misc/freerdp/patches/freerdp-2.0.0~git.patchset diff --git a/net-misc/freerdp/freerdp-2.0.0~git.recipe b/net-misc/freerdp/freerdp-2.0.0~git.recipe new file mode 100644 index 000000000..92021a0b3 --- /dev/null +++ b/net-misc/freerdp/freerdp-2.0.0~git.recipe @@ -0,0 +1,118 @@ +SUMMARY="Free implementation of the Remote Desktop Protocol" +DESCRIPTION="FreeRDP is a free implementation of the Remote Desktop Protocol (RDP), \ +released under the Apache license. +Enjoy the freedom of using your software wherever you want, the way you want it, in \ +a world where interoperability can finally liberate your computing experience." +HOMEPAGE="http://rdesktop.org" +COPYRIGHT="FreeRDP team" +LICENSE="Apache v2" +REVISION="1" +srcGitRev="a51e5a9084917f88941a9bfe7d4c18b7afb0d750" +SOURCE_URI="https://github.com/FreeRDP/FreeRDP/archive/$srcGitRev.tar.gz" +CHECKSUM_SHA256="b5a7f3e90d05ff246dc966bbb9de1d6ec92934ef5c66c2e60da54b1e38b2cad6" +SOURCE_DIR="FreeRDP-$srcGitRev" +PATCHES="freerdp-2.0.0~git.patchset" + +ARCHITECTURES="!x86_gcc2 x86_64" +SECONDARY_ARCHITECTURES="x86" + +PROVIDES=" + freerdp$secondaryArchSuffix = $portVersion + cmd:FreeRDP$secondaryArchSuffix = $portVersion + cmd:winpr_hash$secondaryArchSuffix = $portVersion + cmd:winpr_makecert$secondaryArchSuffix = $portVersion + lib:libfreerdp_client2$secondaryArchSuffix = $portVersion + lib:libfreerdp2$secondaryArchSuffix = $portVersion + lib:libwinpr_tools2$secondaryArchSuffix = $portVersion + lib:libwinpr2$secondaryArchSuffix = $portVersion + " +REQUIRES=" + haiku$secondaryArchSuffix + lib:libavcodec$secondaryArchSuffix + lib:libavformat$secondaryArchSuffix + lib:libavutil$secondaryArchSuffix + lib:libcrypto$secondaryArchSuffix + lib:libexecinfo$secondaryArchSuffix + lib:libglib_2.0$secondaryArchSuffix + lib:libjpeg$secondaryArchSuffix + lib:libssl$secondaryArchSuffix + lib:libz$secondaryArchSuffix + " + +PROVIDES_devel=" + freerdp${secondaryArchSuffix}_devel = $portVersion + devel:libfreerdp_client2$secondaryArchSuffix = $portVersion + devel:libfreerdp2$secondaryArchSuffix = $portVersion + devel:libwinpr_tools2$secondaryArchSuffix = $portVersion + devel:libwinpr2$secondaryArchSuffix = $portVersion + " +REQUIRES_devel=" + haiku$secondaryArchSuffix + freerdp$secondaryArchSuffix == $portVersion base + " + +BUILD_REQUIRES=" + haiku${secondaryArchSuffix}_devel + devel:libavcodec$secondaryArchSuffix + devel:libavformat$secondaryArchSuffix + devel:libavutil$secondaryArchSuffix + devel:libcrypto$secondaryArchSuffix + devel:libexecinfo$secondaryArchSuffix + devel:libglib_2.0$secondaryArchSuffix + devel:libjpeg$secondaryArchSuffix + devel:libssl$secondaryArchSuffix + devel:libz$secondaryArchSuffix + " +BUILD_PREREQUIRES=" + cmd:cmake + cmd:gcc$secondaryArchSuffix + cmd:ld$secondaryArchSuffix + cmd:make + cmd:pkg_config$secondaryArchSuffix + " + +BUILD() +{ + mkdir -p build + cd build + cmake .. $cmakeDirArgs \ + -DCMAKE_INSTALL_PREFIX:PATH=$prefix \ + -DCMAKE_INSTALL_INCLUDEDIR=$includeDir \ + -DCMAKE_INSTALL_LIBDIR=$libDir \ + -DCMAKE_INSTALL_BINDIR:PATH=$binDir \ + -DCMAKE_INSTALL_SBINDIR:PATH=$binDir \ + -DCMAKE_INSTALL_LIBEXECDIR:PATH=$binDir \ + -DCMAKE_CXX_FLAGS:STRING=-D_BSD_SOURCE \ + -DCMAKE_C_FLAGS:STRING=-D_BSD_SOURCE \ + -DWITH_GSTREAMER_1_0=OFF \ + -DWITH_FFMPEG=ON \ + -DWITH_JPEG=ON \ + -DWITH_CUPS=OFF \ + -DWITH_OSS=OFF \ + -DWITH_PULSE=OFF \ + -DBUILD_SHARED_LIBS=ON + make $jobArgs +} + +INSTALL() +{ + cd build + make install + mkdir -p $includeDir + cp -f client/Haiku/FreeRDP $binDir + ln -s $binDir/FreeRDP $binDir/freerdp + mv $prefix/include/* $includeDir + rm -rf $prefix/include + + fixPkgconfig + + prepareInstalledDevelLibs \ + libfreerdp-client2 \ + libfreerdp2 \ + libwinpr-tools2 \ + libwinpr2 + + packageEntries devel \ + $developDir \ + $libDir/cmake +} diff --git a/net-misc/freerdp/patches/freerdp-2.0.0~git.patchset b/net-misc/freerdp/patches/freerdp-2.0.0~git.patchset new file mode 100644 index 000000000..09b65ea35 --- /dev/null +++ b/net-misc/freerdp/patches/freerdp-2.0.0~git.patchset @@ -0,0 +1,1263 @@ +From 0b30ec8c722d6e13d7981f57ce4c2ca96f37bb24 Mon Sep 17 00:00:00 2001 +From: Gerasim Troeglazov <3dEyes@gmail.com> +Date: Wed, 29 Aug 2018 21:51:04 +1000 +Subject: Fix build + + +diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c +index 4c327f7..ccd72ce 100644 +--- a/channels/rdpsnd/client/rdpsnd_main.c ++++ b/channels/rdpsnd/client/rdpsnd_main.c +@@ -1513,7 +1513,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p + } + + rdpsnd->attached = TRUE; +-#if !defined(_WIN32) && !defined(ANDROID) ++#if !defined(_WIN32) && !defined(ANDROID) && !defined(__HAIKU__) + { + sigset_t mask; + sigemptyset(&mask); +diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt +index 166847e..02481d0 100644 +--- a/client/CMakeLists.txt ++++ b/client/CMakeLists.txt +@@ -55,6 +55,11 @@ if(FREERDP_VENDOR AND WITH_CLIENT) + message(STATUS "Adding Android client") + add_subdirectory(Android) + endif() ++ ++ if(HAIKU) ++ message(STATUS "Adding Haiku client") ++ add_subdirectory(Haiku) ++ endif() + endif() + + # Pick up other clients +diff --git a/winpr/include/winpr/winsock.h b/winpr/include/winpr/winsock.h +index 5e04418..f4e1717 100644 +--- a/winpr/include/winpr/winsock.h ++++ b/winpr/include/winpr/winsock.h +@@ -84,6 +84,10 @@ WINPR_API INT winpr_inet_pton(INT Family, PCSTR pszAddrString, PVOID pAddrBuf); + #include + #include + #include ++#ifdef __HAIKU__ ++#include ++#include ++#endif + + #include + #include +diff --git a/winpr/libwinpr/synch/CMakeLists.txt b/winpr/libwinpr/synch/CMakeLists.txt +index 7c86c34..a7fda31 100644 +--- a/winpr/libwinpr/synch/CMakeLists.txt ++++ b/winpr/libwinpr/synch/CMakeLists.txt +@@ -30,7 +30,7 @@ winpr_module_add( + timer.c + wait.c) + +-if((NOT WIN32) AND (NOT APPLE) AND (NOT ANDROID) AND (NOT OPENBSD)) ++if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU) AND (NOT ANDROID) AND (NOT OPENBSD)) + winpr_library_add(rt) + endif() + +diff --git a/winpr/libwinpr/synch/timer.c b/winpr/libwinpr/synch/timer.c +index dbd628f..f8a125a 100644 +--- a/winpr/libwinpr/synch/timer.c ++++ b/winpr/libwinpr/synch/timer.c +@@ -768,7 +768,9 @@ static int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue) + pthread_attr_init(&(timerQueue->attr)); + timerQueue->param.sched_priority = sched_get_priority_max(SCHED_FIFO); + pthread_attr_setschedparam(&(timerQueue->attr), &(timerQueue->param)); ++#ifndef __HAIKU__ + pthread_attr_setschedpolicy(&(timerQueue->attr), SCHED_FIFO); ++#endif + pthread_create(&(timerQueue->thread), &(timerQueue->attr), TimerQueueThread, timerQueue); + return 0; + } +diff --git a/winpr/libwinpr/sysinfo/CMakeLists.txt b/winpr/libwinpr/sysinfo/CMakeLists.txt +index f9b7f69..126eb48 100644 +--- a/winpr/libwinpr/sysinfo/CMakeLists.txt ++++ b/winpr/libwinpr/sysinfo/CMakeLists.txt +@@ -21,10 +21,14 @@ endif() + + winpr_module_add(sysinfo.c) + +-if((NOT WIN32) AND (NOT APPLE) AND (NOT ANDROID) AND (NOT OPENBSD)) ++if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU) AND (NOT ANDROID) AND (NOT OPENBSD)) + winpr_library_add(rt) + endif() + ++if(HAIKU) ++ winpr_library_add(network) ++endif() ++ + if(BUILD_TESTING) + add_subdirectory(test) + endif() +diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt +index abf4dc1..bf6d495 100644 +--- a/winpr/libwinpr/utils/CMakeLists.txt ++++ b/winpr/libwinpr/utils/CMakeLists.txt +@@ -141,7 +141,7 @@ if(UNIX) + winpr_library_add(m) + endif() + +-if((FREEBSD) AND (NOT KFREEBSD)) ++if(((FREEBSD) AND (NOT KFREEBSD)) OR (HAIKU)) + winpr_library_add(execinfo) + endif() + +diff --git a/winpr/libwinpr/winsock/winsock.c b/winpr/libwinpr/winsock/winsock.c +index 50bf1eb..1ed7577 100644 +--- a/winpr/libwinpr/winsock/winsock.c ++++ b/winpr/libwinpr/winsock/winsock.c +@@ -371,9 +371,11 @@ void WSASetLastError(int iError) + case WSAEPROTONOSUPPORT: + errno = EPROTONOSUPPORT; + break; ++#ifndef __HAIKU__ + case WSAESOCKTNOSUPPORT: + errno = ESOCKTNOSUPPORT; + break; ++#endif + case WSAEOPNOTSUPP: + errno = EOPNOTSUPP; + break; +@@ -416,9 +418,11 @@ void WSASetLastError(int iError) + case WSAESHUTDOWN: + errno = ESHUTDOWN; + break; ++#ifndef __HAIKU__ + case WSAETOOMANYREFS: + errno = ETOOMANYREFS; + break; ++#endif + case WSAETIMEDOUT: + errno = ETIMEDOUT; + break; +@@ -445,18 +449,22 @@ void WSASetLastError(int iError) + errno = EPROCLIM; + break; + #endif ++#ifndef __HAIKU__ + case WSAEUSERS: + errno = EUSERS; + break; ++#endif + case WSAEDQUOT: + errno = EDQUOT; + break; + case WSAESTALE: + errno = ESTALE; + break; ++#ifndef __HAIKU__ + case WSAEREMOTE: + errno = EREMOTE; + break; ++#endif + } + } + +@@ -516,9 +524,11 @@ int WSAGetLastError(void) + case EPROTONOSUPPORT: + iError = WSAEPROTONOSUPPORT; + break; ++#ifndef __HAIKU__ + case ESOCKTNOSUPPORT: + iError = WSAESOCKTNOSUPPORT; + break; ++#endif + case EOPNOTSUPP: + iError = WSAEOPNOTSUPP; + break; +@@ -561,9 +571,11 @@ int WSAGetLastError(void) + case ESHUTDOWN: + iError = WSAESHUTDOWN; + break; ++#ifndef __HAIKU__ + case ETOOMANYREFS: + iError = WSAETOOMANYREFS; + break; ++#endif + case ETIMEDOUT: + iError = WSAETIMEDOUT; + break; +@@ -590,19 +602,22 @@ int WSAGetLastError(void) + iError = WSAEPROCLIM; + break; + #endif ++#ifndef __HAIKU__ + case EUSERS: + iError = WSAEUSERS; + break; ++#endif + case EDQUOT: + iError = WSAEDQUOT; + break; + case ESTALE: + iError = WSAESTALE; + break; ++#ifndef __HAIKU__ + case EREMOTE: + iError = WSAEREMOTE; + break; +- ++#endif + /* Special cases */ + + #if (EAGAIN != EWOULDBLOCK) +diff --git a/winpr/winpr.pc.in b/winpr/winpr.pc.in +index 6b0c950..73aea67 100644 +--- a/winpr/winpr.pc.in ++++ b/winpr/winpr.pc.in +@@ -11,5 +11,5 @@ Version: @WINPR_VERSION@ + Requires: + Requires.private: libssl + Libs: -L${libdir} ${libs} +-Libs.private: -ldl -lrt -lm -lpthread ++Libs.private: -ldl -lnetwork -lbe + Cflags: -I${includedir} +-- +2.16.4 + + +From bb4cf466631ce75df92b53c7478c7fe41f281b77 Mon Sep 17 00:00:00 2001 +From: Gerasim Troeglazov <3dEyes@gmail.com> +Date: Wed, 29 Aug 2018 21:53:34 +1000 +Subject: Add Haiku support + + +diff --git a/client/Haiku/App.cpp b/client/Haiku/App.cpp +new file mode 100644 +index 0000000..92874d0 +--- /dev/null ++++ b/client/Haiku/App.cpp +@@ -0,0 +1,20 @@ ++/* ++ * Copyright 2010 Your Name ++ * All rights reserved. Distributed under the terms of the MIT license. ++ */ ++ ++#include "App.h" ++ ++const char *APPSIGNATURE = "application/x-vnd.freerdp"; ++ ++TestApplication::TestApplication() ++ :BApplication(APPSIGNATURE) ++{ ++ ++} ++ ++ ++TestApplication::~TestApplication() ++{ ++} ++ +diff --git a/client/Haiku/App.h b/client/Haiku/App.h +new file mode 100644 +index 0000000..828c3bc +--- /dev/null ++++ b/client/Haiku/App.h +@@ -0,0 +1,16 @@ ++#ifndef _TEST_APPLICATION_H ++#define _TEST_APPLICATION_H ++ ++#include ++#include ++#include ++#include ++ ++class TestApplication : public BApplication { ++ public: ++ TestApplication(); ++ virtual ~TestApplication(); ++}; ++ ++#endif ++ +diff --git a/client/Haiku/CMakeLists.txt b/client/Haiku/CMakeLists.txt +new file mode 100644 +index 0000000..1441dc8 +--- /dev/null ++++ b/client/Haiku/CMakeLists.txt +@@ -0,0 +1,36 @@ ++# FreeRDP: A Remote Desktop Protocol Implementation ++# FreeRDP Haiku UI cmake build script ++# ++# Copyright 2018 Gerasim Troeglazov <3dEyes@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 "FreeRDP") ++set(MODULE_PREFIX "FREERDP_CLIENT_HAIKU") ++set(CMAKE_POSITION_INDEPENDENT_CODE OFF) ++ ++set(${MODULE_PREFIX}_SRCS ++ FreeRDP.cpp App.cpp MainWindow.cpp MainView.cpp) ++ ++add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) ++ ++set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CMAKE_DL_LIBS}) ++set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client freerdp) ++set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} be network media translation) ++target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) ++ ++ADD_CUSTOM_COMMAND(TARGET ${MODULE_NAME} COMMAND rc -o Resources.rsrc ${CMAKE_CURRENT_SOURCE_DIR}/Resources.rdef COMMENT "Compiling resources") ++ADD_CUSTOM_COMMAND(TARGET ${MODULE_NAME} COMMAND xres -o ${MODULE_NAME} Resources.rsrc COMMENT "Adding resources to executable") ++ADD_CUSTOM_COMMAND(TARGET ${MODULE_NAME} COMMAND mimeset --all ${MODULE_NAME} COMMENT "Adjusting MIME types") ++ ++set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Haiku") +diff --git a/client/Haiku/FreeRDP.cpp b/client/Haiku/FreeRDP.cpp +new file mode 100644 +index 0000000..a3fbb7b +--- /dev/null ++++ b/client/Haiku/FreeRDP.cpp +@@ -0,0 +1,322 @@ ++/** ++ * FreeRDP: A Remote Desktop Protocol Implementation ++ * FreeRDP Test UI ++ * ++ * Copyright 2011 Marc-Andre Moreau ++ * Copyright 2016 Armin Novak ++ * Copyright 2016 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. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "App.h" ++#include "MainWindow.h" ++#include "MainView.h" ++ ++#include ++#include ++#include ++ ++extern "C" { ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++} ++ ++#define TAG CLIENT_TAG("haiku") ++ ++MainWindow *wnd = NULL; ++ ++struct tf_context ++{ ++ rdpContext _p; ++}; ++typedef struct tf_context tfContext; ++ ++static BOOL tf_context_new(freerdp* instance, rdpContext* context) ++{ ++ return TRUE; ++} ++ ++static void tf_context_free(freerdp* instance, rdpContext* context) ++{ ++} ++ ++static BOOL tf_begin_paint(rdpContext* context) ++{ ++ rdpGdi* gdi = context->gdi; ++ gdi->primary->hdc->hwnd->invalid->null = TRUE; ++ return TRUE; ++} ++ ++static BOOL tf_end_paint(rdpContext* context) ++{ ++ rdpGdi* gdi = context->gdi; ++ ++ if(wnd==NULL) ++ return TRUE; ++ ++ if (gdi->primary->hdc->hwnd->invalid->null) ++ return TRUE; ++ ++ char* data = (char*)wnd->fb->GetBuffer(); ++ ++ int x = gdi->primary->hdc->hwnd->invalid->x; ++ int y = gdi->primary->hdc->hwnd->invalid->y; ++ int w = gdi->primary->hdc->hwnd->invalid->w; ++ int h = gdi->primary->hdc->hwnd->invalid->h; ++ ++ for (int i = 0; i < h; i++) ++ { ++ memcpy(data + ((i + y) * (gdi->width * GetBytesPerPixel( ++ gdi->dstFormat))) + x * GetBytesPerPixel(gdi->dstFormat), ++ gdi->primary_buffer + ((i + y) * (gdi->width * GetBytesPerPixel( ++ gdi->dstFormat))) + x * GetBytesPerPixel(gdi->dstFormat), ++ w * GetBytesPerPixel(gdi->dstFormat)); ++ } ++ ++ wnd->fb->Paint(); ++ ++ return TRUE; ++} ++ ++static BOOL tf_pre_connect(freerdp* instance) ++{ ++ rdpSettings* settings; ++ settings = instance->settings; ++ settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; ++ settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; ++ settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; ++ settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; ++ settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE; ++ settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; ++ settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; ++ settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; ++ settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; ++ settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE; ++ settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; ++ settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; ++ settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE; ++ settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE; ++ settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; ++ settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = FALSE; ++ settings->OrderSupport[NEG_FAST_INDEX_INDEX] = FALSE; ++ settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = FALSE; ++ settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE; ++ settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; ++ settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; ++ settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; ++ ++ if (settings->Fullscreen) { ++ BScreen screen; ++ settings->DesktopWidth = (UINT32) screen.Frame().right + 1; ++ settings->DesktopHeight = (UINT32) screen.Frame().bottom + 1; ++ } ++ ++ return TRUE; ++} ++ ++static BOOL tf_post_connect(freerdp* instance) ++{ ++ rdpGdi* gdi; ++ rdpContext* context; ++ rdpSettings* settings; ++ ++ context = ((rdpContext*) instance->context); ++ ++ if (!gdi_init(instance, PIXEL_FORMAT_BGRA32)) ++ return FALSE; ++ ++ gdi = instance->context->gdi; ++ settings = instance->settings; ++ ++ instance->update->BeginPaint = tf_begin_paint; ++ instance->update->EndPaint = tf_end_paint; ++ ++ if(wnd==NULL) { ++ char wndTitle[256]={"FreeRDP"}; ++ ++ BRect rect = BRect(50, 50, 50 + gdi->width, 50 + gdi->height); ++ if (settings->Fullscreen) { ++ rect = BRect(0, 0, gdi->width, gdi->height); ++ } ++ if (settings->WindowTitle != NULL) ++ snprintf(wndTitle, 255, "%s", settings->WindowTitle); ++ else if (settings->ServerPort == 3389) ++ snprintf(wndTitle, 255, "FreeRDP: %s", settings->ServerHostname); ++ else ++ snprintf(wndTitle, 255, "FreeRDP: %S:%u", settings->ServerHostname, settings->ServerPort); ++ ++ wnd = new MainWindow(rect, wndTitle, instance); ++ wnd->Show(); ++ } ++ ++ return TRUE; ++} ++ ++static void tf_post_disconnect(freerdp* instance) ++{ ++ rdpContext* context; ++ ++ if (!instance) ++ return; ++ ++ if (!instance->context) ++ return; ++ ++ context = (rdpContext*) instance->context; ++ gdi_free(instance); ++ ++ if (wnd!=NULL) { ++ wnd->Lock(); ++ wnd->Quit(); ++ } ++} ++ ++static DWORD WINAPI tf_haiku_app_thread_proc(LPVOID arg) ++{ ++ TestApplication app; ++ app.Run(); ++ ++ ExitThread(0); ++ return 0; ++} ++ ++ ++static DWORD WINAPI tf_client_thread_proc(LPVOID arg) ++{ ++ freerdp* instance = (freerdp*)arg; ++ DWORD nCount; ++ DWORD status; ++ HANDLE handles[64]; ++ ++ if (!freerdp_connect(instance)) ++ { ++ WLog_ERR(TAG, "connection failure"); ++ return 0; ++ } ++ ++ while (!freerdp_shall_disconnect(instance)) ++ { ++ nCount = freerdp_get_event_handles(instance->context, &handles[0], 64); ++ ++ if (nCount == 0) ++ { ++ WLog_ERR(TAG, "%s: freerdp_get_event_handles failed", __FUNCTION__); ++ break; ++ } ++ ++ status = WaitForMultipleObjects(nCount, handles, FALSE, 100); ++ ++ if (status == WAIT_FAILED) ++ { ++ WLog_ERR(TAG, "%s: WaitForMultipleObjects failed with %"PRIu32"", __FUNCTION__, ++ status); ++ break; ++ } ++ ++ if (!freerdp_check_event_handles(instance->context)) ++ { ++ if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS) ++ WLog_ERR(TAG, "Failed to check FreeRDP event handles"); ++ ++ break; ++ } ++ } ++ ++ freerdp_disconnect(instance); ++ ExitThread(0); ++ return 0; ++} ++ ++int main(int argc, char* argv[]) ++{ ++ int status; ++ HANDLE thread; ++ freerdp* instance; ++ instance = freerdp_new(); ++ ++ if (!instance) ++ { ++ WLog_ERR(TAG, "Couldn't create instance"); ++ winpr_exit(1); ++ } ++ ++ instance->PreConnect = tf_pre_connect; ++ instance->PostConnect = tf_post_connect; ++ instance->PostDisconnect = tf_post_disconnect; ++ instance->ContextSize = sizeof(tfContext); ++ instance->ContextNew = tf_context_new; ++ instance->ContextFree = tf_context_free; ++ freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); ++ ++ if (!freerdp_context_new(instance)) ++ { ++ WLog_ERR(TAG, "Couldn't create context"); ++ return winpr_exit(1); ++ } ++ ++ status = freerdp_client_settings_parse_command_line(instance->settings, argc, ++ argv, FALSE); ++ ++ if (status < 0) ++ { ++ return winpr_exit(0); ++ } ++ ++ if (!freerdp_client_load_addins(instance->context->channels, ++ instance->settings)) ++ return winpr_exit(-1); ++ ++ //if (!(thread = CreateThread(NULL, 0, tf_haiku_app_thread_proc, instance, 0, NULL))) ++ //{ ++// WLog_ERR(TAG, "Failed to create app thread"); ++// } ++ ++ if (!(thread = CreateThread(NULL, 0, tf_client_thread_proc, instance, 0, NULL))) ++ { ++ WLog_ERR(TAG, "Failed to create client thread"); ++ } ++ else ++ { ++ WaitForSingleObject(thread, INFINITE); ++ } ++ ++ freerdp_context_free(instance); ++ freerdp_free(instance); ++ return winpr_exit(0); ++} +diff --git a/client/Haiku/MainView.cpp b/client/Haiku/MainView.cpp +new file mode 100644 +index 0000000..00e70a0 +--- /dev/null ++++ b/client/Haiku/MainView.cpp +@@ -0,0 +1,235 @@ ++/* ++ * Copyright 2010 Your Name ++ * All rights reserved. Distributed under the terms of the MIT license. ++ */ ++ ++#include "MainWindow.h" ++#include "MainView.h" ++ ++ ++FBView::FBView(BRect rect) : ++ BView(rect, "FBView", B_FOLLOW_ALL, B_WILL_DRAW|B_PULSE_NEEDED|B_FRAME_EVENTS), ++ showBar(false) ++{ ++ FBView(rect, rect.IntegerWidth(), rect.IntegerHeight()); ++} ++ ++FBView::FBView(BRect rect, int width, int height) : ++ BView(rect, "FBView", B_FOLLOW_ALL, B_WILL_DRAW|B_PULSE_NEEDED|B_FRAME_EVENTS), ++ showBar(false) ++{ ++ buffer_width = width; ++ buffer_height = height; ++ lastButtons = 0; ++ ++ BRect fbRect = BRect(0,0,buffer_width-1,buffer_height-1); ++ bufferView = new BView(fbRect, "bufferView", B_FOLLOW_ALL_SIDES, 0); ++ bufferBitmap = new BBitmap(fbRect, B_RGB32, true); ++ bufferBitmap->AddChild(bufferView); ++ ++ font = be_bold_font; ++ font.SetSize(14); ++ SetFont(&font, B_FONT_ALL); ++ ++ title = BString("FreeRDP"); ++ ++ //printf("BTranslationUtils::GetBitmap\n"); ++ //closeBitmap = BTranslationUtils::GetBitmapFile("/NoIndex64/Public/FreeRDP/client/Haiku/images/close.png"); ++ //printf("W:%f H:%f\n", closeBitmap->Bounds().Width(), closeBitmap->Bounds().Height()); ++ //zoomBitmap = new BBitmap(BRect(0,0,16,16),B_RGB32);//BTranslationUtils::GetBitmap(B_PNG_FORMAT, "zoom.png"); ++} ++ ++FBView::~FBView() ++{ ++ //delete closeBitmap; ++ //delete zoomBitmap; ++} ++ ++void ++FBView::AttachedToWindow(void) ++{ ++ tickCount = 0; ++} ++ ++void ++FBView::Pulse(void) ++{ ++ uint32 dx = Bounds().Width() / 3; ++ uint32 h = showBar?20:2; ++ if (lastPos.y >= 0 && lastPos.y < h && lastPos.x > dx && lastPos.x < dx * 2 ) { ++ tickCount++; ++ if(tickCount > 5) { ++ showBar = true; ++ Invalidate(); ++ } ++ return; ++ } ++ if(showBar) { ++ showBar = false; ++ Invalidate(); ++ } ++ tickCount = 0; ++} ++ ++void ++FBView::SetInstance(freerdp *inst) ++{ ++ instance = inst; ++ title.SetTo(Window()->Title()); ++} ++ ++BPoint ++FBView::GetLastMousePos() ++{ ++ return lastPos; ++} ++ ++void FBView::MouseMoved(BPoint p, uint32 transit,const BMessage *message) ++{ ++ rdpInput* input = instance->input; ++ switch(transit) ++ { ++ case B_INSIDE_VIEW: ++ case B_ENTERED_VIEW: ++ { ++ input->MouseEvent(input, PTR_FLAGS_MOVE, p.x, p.y); ++ tickCount = 0; ++ break; ++ } ++ case B_EXITED_VIEW: ++ break; ++ case B_OUTSIDE_VIEW: ++ break; ++ } ++ lastPos = p; ++} ++ ++void FBView::MouseDown(BPoint p) ++{ ++ rdpInput* input = instance->input; ++ ++ uint32 dx = Bounds().Width() / 3; ++ uint32 h = showBar?20:2; ++ ++ uint32 buttons = Window()->CurrentMessage()->FindInt32("buttons"); ++ int32 clicks = Window()->CurrentMessage()->FindInt32("clicks"); ++ int flags = PTR_FLAGS_DOWN; ++ ++ if (buttons & B_PRIMARY_MOUSE_BUTTON) ++ flags |= PTR_FLAGS_BUTTON1; ++ if (buttons & B_SECONDARY_MOUSE_BUTTON) ++ flags |= PTR_FLAGS_BUTTON2; ++ if (buttons & B_TERTIARY_MOUSE_BUTTON) ++ flags |= PTR_FLAGS_BUTTON2; ++ ++ if (showBar && buttons & B_PRIMARY_MOUSE_BUTTON) { ++ BRect closeButtonRect(dx + 3, 3, dx + h - 3, h - 3); ++ if (closeButtonRect.Contains(p)) { ++ freerdp_abort_connect(instance); ++ } else if(clicks == 2) { ++ Window()->Minimize(true); ++ flags = 0; ++ } ++ } ++ ++ if (flags != 0) ++ input->MouseEvent(input, flags, p.x, p.y); ++ ++ lastPos = p; ++ lastButtons = buttons; ++} ++ ++void FBView::MouseUp(BPoint p) ++{ ++ rdpInput* input = instance->input; ++ ++ uint32 buttons = Window()->CurrentMessage()->FindInt32("buttons"); ++ int flags = 0; ++ ++ if ((buttons ^ lastButtons) & B_PRIMARY_MOUSE_BUTTON) ++ flags |= PTR_FLAGS_BUTTON1; ++ if ((buttons ^ lastButtons) & B_SECONDARY_MOUSE_BUTTON) ++ flags |= PTR_FLAGS_BUTTON2; ++ if ((buttons ^lastButtons) & B_TERTIARY_MOUSE_BUTTON) ++ flags |= PTR_FLAGS_BUTTON2; ++ ++ if (flags != 0) ++ input->MouseEvent(input, flags, p.x, p.y); ++ ++ lastPos = p; ++ lastButtons = buttons; ++} ++ ++void ++FBView::Draw(BRect r) ++{ ++ uint32 dx = Bounds().Width() / 3; ++ uint32 h = showBar?20:2; ++ ++ DrawBitmap(bufferBitmap, r, r); ++ if (showBar) { ++ BRect r(dx, -1, dx * 2, h); ++ SetDrawingMode(B_OP_COPY); ++ ++ SetHighColor(255, 203, 0); ++ SetLowColor(255, 203, 0); ++ FillRect(r); ++ SetHighColor(179, 143, 0); ++ SetLowColor(179, 143, 0); ++ StrokeRect(r); ++ ++ SetDrawingMode(B_OP_ALPHA); ++ BRect closeButtonRect(dx + 3, 3, dx + h - 3, h - 3); ++ StrokeRect(closeButtonRect); ++ //DrawBitmap(closeBitmap, BPoint(dx + 3, 3)); ++ ++ SetHighColor(0, 0, 0); ++ SetLowColor(0, 0, 0); ++ float width = font.StringWidth(title); ++ DrawString(title, BPoint(Bounds().Width()/2 - width/2, 16)); ++ } ++} ++ ++void ++FBView::Paint() ++{ ++ if(LockLooper()) { ++ bufferView->LockLooper(); ++ SetDrawingMode(B_OP_COPY); ++ DrawBitmap(bufferBitmap);//, bufferView->Bounds(), Bounds()); ++ bufferView->UnlockLooper(); ++ UnlockLooper(); ++ } ++} ++ ++uint32 * ++FBView::GetBuffer() ++{ ++ if(bufferBitmap) { ++ return (uint32*)bufferBitmap->Bits(); ++ } ++ return NULL; ++} ++ ++uint32 ++FBView::GetBufferSize() ++{ ++ if(bufferBitmap) { ++ return bufferBitmap->BitsLength()/4; ++ } ++ return 0; ++} ++ ++int ++FBView::Width() ++{ ++ return buffer_width; ++} ++ ++int ++FBView::Height() ++{ ++ return buffer_height; ++} ++ ++ +diff --git a/client/Haiku/MainView.h b/client/Haiku/MainView.h +new file mode 100644 +index 0000000..8597c85 +--- /dev/null ++++ b/client/Haiku/MainView.h +@@ -0,0 +1,74 @@ ++#ifndef _H_FBVIEW_ ++#define _H_FBVIEW_ ++ ++#include ++#include ++#include ++ ++extern "C" { ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++} ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++class FBView : public BView ++{ ++ public: ++ FBView(BRect rect); ++ FBView(BRect rect, int width, int height); ++ ~FBView(); ++ ++ void Paint(); ++ void SetInstance(freerdp *instance); ++ uint32 *GetBuffer(); ++ uint32 GetBufferSize(); ++ BPoint GetLastMousePos(); ++ ++ int Width(); ++ int Height(); ++protected: ++ virtual void Draw(BRect r); ++ virtual void MouseDown(BPoint p); ++ virtual void MouseUp(BPoint p); ++ virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); ++ virtual void Pulse(void); ++ virtual void AttachedToWindow(void); ++ ++private: ++ int buffer_width; ++ int buffer_height; ++ BView *bufferView; ++ BBitmap *bufferBitmap; ++ BBitmap *closeBitmap; ++ BBitmap *zoomBitmap; ++ uint32 lastButtons; ++ BPoint lastPos; ++ freerdp *instance; ++ uint32 tickCount; ++ bool showBar; ++ BFont font; ++ BString title; ++}; ++ ++#endif +diff --git a/client/Haiku/MainWindow.cpp b/client/Haiku/MainWindow.cpp +new file mode 100644 +index 0000000..8228e34 +--- /dev/null ++++ b/client/Haiku/MainWindow.cpp +@@ -0,0 +1,131 @@ ++#include ++#include ++#include "MainWindow.h" ++ ++BApplication app("application/x-vnd.freerdp"); ++ ++static const uint32 be_to_scan_codes[] = { ++VK_ESCAPE, VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, ++VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, VK_PRINT, VK_SCROLL, 0, ++////////// ++VK_OEM_3,VK_KEY_1,VK_KEY_2,VK_KEY_3,VK_KEY_4,VK_KEY_5,VK_KEY_6,VK_KEY_7,VK_KEY_8, ++VK_KEY_9,VK_KEY_0,VK_OEM_MINUS,VK_OEM_PLUS,VK_BACK,VK_INSERT|KBDEXT, ++VK_HOME|KBDEXT,VK_PRIOR|KBDEXT,VK_NUMLOCK,VK_DIVIDE|KBDEXT,VK_MULTIPLY,VK_SUBTRACT, ++////////// ++VK_TAB,VK_KEY_Q,VK_KEY_W,VK_KEY_E,VK_KEY_R,VK_KEY_T,VK_KEY_Y,VK_KEY_U,VK_KEY_I, ++VK_KEY_O,VK_KEY_P,VK_OEM_4,VK_OEM_6,VK_OEM_5,VK_DELETE|KBDEXT,VK_END|KBDEXT,VK_NEXT|KBDEXT, ++VK_NUMPAD7,VK_NUMPAD8,VK_NUMPAD9,VK_ADD, ++////////// ++VK_CAPITAL,VK_KEY_A,VK_KEY_S,VK_KEY_D,VK_KEY_F,VK_KEY_G,VK_KEY_H,VK_KEY_J,VK_KEY_K,VK_KEY_L,VK_OEM_1,VK_OEM_7,VK_RETURN, ++VK_NUMPAD4,VK_NUMPAD5,VK_NUMPAD6, ++////////// ++VK_LSHIFT,VK_KEY_Z,VK_KEY_X,VK_KEY_C,VK_KEY_V,VK_KEY_B,VK_KEY_N,VK_KEY_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2, ++VK_RSHIFT,VK_UP|KBDEXT,VK_NUMPAD1,VK_NUMPAD2,VK_NUMPAD3,VK_RETURN|KBDEXT, ++////////// ++VK_LCONTROL,VK_LMENU,VK_SPACE,VK_RMENU,VK_RCONTROL,VK_LEFT|KBDEXT,VK_DOWN|KBDEXT,VK_RIGHT|KBDEXT,VK_NUMPAD0,VK_DECIMAL, ++VK_LWIN|KBDEXT,VK_RWIN|KBDEXT,127,0 ++}; ++ ++ ++MainWindow::MainWindow(BRect frame, const char* title, freerdp *inst) ++ : BWindow(frame, title, B_TITLED_WINDOW_LOOK,B_NORMAL_WINDOW_FEEL,B_NOT_RESIZABLE|B_NOT_ZOOMABLE) ++{ ++ fb = new FBView(Bounds(), frame.Width(),frame.Height()); ++ AddChild(fb); ++ SetInstance(inst); ++ SetPulseRate(100000); ++} ++ ++ ++MainWindow::~MainWindow() ++{ ++} ++ ++void ++MainWindow::MessageReceived(BMessage *message) ++{ ++ switch(message->what) { ++ case B_UNMAPPED_KEY_DOWN: ++ case B_KEY_DOWN: ++ { ++ rdpInput* input = instance->input; ++ ++ const char *bytes; ++ int32 key; ++ uint32 keycode; ++ message->FindInt32("key",&key); ++ keycode = be_to_scan_codes[(uint8)key-1]; ++ DWORD scancode = GetVirtualScanCodeFromVirtualKeyCode(keycode, input->context->settings->KeyboardType); ++ ++ if (scancode) ++ freerdp_input_send_keyboard_event_ex(input, TRUE, scancode); ++ ++ break; ++ } ++ case B_UNMAPPED_KEY_UP: ++ case B_KEY_UP: ++ { ++ rdpInput* input = instance->input; ++ ++ const char *bytes; ++ int32 key; ++ uint32 keycode; ++ message->FindInt32("key",&key); ++ keycode = be_to_scan_codes[(uint8)key-1]; ++ DWORD scancode = GetVirtualScanCodeFromVirtualKeyCode(keycode, input->context->settings->KeyboardType); ++ ++ if (scancode) ++ freerdp_input_send_keyboard_event_ex(input, FALSE, scancode); ++ ++ break; ++ } ++ case B_MOUSE_WHEEL_CHANGED: ++ { ++ rdpInput* input = instance->input; ++ BPoint pos = fb->GetLastMousePos(); ++ ++ float shift=0; ++ UINT16 flags; ++ ++ flags = PTR_FLAGS_WHEEL; ++ ++ if(message->FindFloat("be:wheel_delta_y",&shift)==B_OK) { ++ if(shift<0) { ++ flags |= 0x0078; ++ } ++ if(shift>0) { ++ flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; ++ } ++ } ++ input->MouseEvent(input, flags, pos.x, pos.y); ++ break; ++ } ++// case B_CLIPBOARD_CHANGED: ++// { ++// break; ++// } ++ case B_WINDOW_ACTIVATED: ++ case B_WORKSPACE_ACTIVATED: ++ { ++ break; ++ } ++ default: ++ BWindow::MessageReceived(message); ++ break; ++ } ++} ++ ++ ++void ++MainWindow::SetInstance(freerdp *inst) ++{ ++ instance = inst; ++ fb->SetInstance(inst); ++} ++ ++bool ++MainWindow::QuitRequested() ++{ ++ freerdp_abort_connect(instance); ++ return false; ++} +diff --git a/client/Haiku/MainWindow.h b/client/Haiku/MainWindow.h +new file mode 100644 +index 0000000..709a2c0 +--- /dev/null ++++ b/client/Haiku/MainWindow.h +@@ -0,0 +1,50 @@ ++#ifndef _TEST_WINDOW_H ++#define _TEST_WINDOW_H ++ ++#include ++#include ++#include ++ ++extern "C" { ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++} ++ ++#include ++#include ++#include ++#include ++ ++#include "MainView.h" ++ ++class MainWindow : public BWindow { ++ public: ++ MainWindow(BRect rect, const char* name, freerdp *instance); ++ virtual ~MainWindow(); ++ ++ virtual void MessageReceived(BMessage *message); ++ bool QuitRequested(); ++ ++ void SetInstance(freerdp *instance); ++ ++ FBView *fb; ++ private: ++ freerdp *instance; ++}; ++ ++#endif ++ ++ +diff --git a/client/Haiku/ModuleOptions.cmake b/client/Haiku/ModuleOptions.cmake +new file mode 100644 +index 0000000..130bfa1 +--- /dev/null ++++ b/client/Haiku/ModuleOptions.cmake +@@ -0,0 +1,4 @@ ++ ++set(FREERDP_CLIENT_NAME "hfreerdp") ++set(FREERDP_CLIENT_PLATFORM "Haiku") ++set(FREERDP_CLIENT_VENDOR "FreeRDP") +diff --git a/client/Haiku/Resources.rdef b/client/Haiku/Resources.rdef +new file mode 100644 +index 0000000..86dd149 +--- /dev/null ++++ b/client/Haiku/Resources.rdef +@@ -0,0 +1,55 @@ ++/* ++ * Resources.rdef ++ */ ++ ++resource app_signature "application/x-vnd.freerdp"; ++ ++resource app_flags B_MULTIPLE_LAUNCH; ++ ++resource app_version { ++ major = 2, ++ middle = 0, ++ minor = 0, ++ variety = 0, ++ internal = 0, ++ short_info = "FreeRDP", ++ long_info = "FreeRDP" ++}; ++ ++resource(1, "close.png") #'PNG ' import "images/close.png"; ++resource(2, "zoom.png") #'PNG ' import "images/zoom.png"; ++ ++resource vector_icon { ++ $"6E6369662803010000020016023CC7ED389BBFBA16553E39AF4977C842ADC700" ++ $"FFFFD3020016023C529D3753A2B8966F3D9D074B6044496AAF0047FFA0020016" ++ $"02BC4E75BC411A3C90D9BCA00C47587D4ABA850090FFD40200160238313C3B5C" ++ $"F0BFCD953C7AAB4C13943FCAF901ECFFC3054B04016B020006033E2F99387F17" ++ $"BA42DC3FF5B84A0E32482C90001D1E2C3D454658FF010101020006023879063B" ++ $"8224BE2CC73B10D94A1F6F49B89400242222FF9A9A9A020006033C69A6000000" ++ $"0000003E186148800049800000D4CECE58F3F3F3FFD9D9D90389FF0005000500" ++ $"0500030100000500033A3A4303F46E0C03010000020016023CC7ED389BBFBA16" ++ $"553E39AF4977C842ADC700FFFFD3020006023C529D3753A2B8966F3D9D074B60" ++ $"44496AAF00474747FFA5A0A002001602BC4E75BC411A3C90D9BCA00C47587D4A" ++ $"BA850090FFD40200160238313C3B5CF0BFCD953C7AAB4C13943FCAF901ECFFC3" ++ $"054B04017E020006033E2F99387F17BA42DC3FF5B84A0E32482C90001D1E2C3D" ++ $"454658FF010101020006023879063B8224BE2CC73B10D94A1F6F49B894002422" ++ $"22FF9A9A9A020006033C69A60000000000003E186148800049800000D4CECE58" ++ $"F3F3F3FFD9D9D9038AFF01050005000500030100000500033A3A43033A3A4303" ++ $"0100000300AAFF0300FF0003FFAA002200000A062228224A485E525252302C22" ++ $"0A042228483852302C220A044838485E525252300A042228224A485E48380A04" ++ $"453A45572446242C0A04B560442446242CB569B8200A0445544557244626440A" ++ $"0438263D234E28492C080438263D234E284E2E0A03492C4E284E2E0802425843" ++ $"C9830A06486054606052CA1BC5B95C4D524800000A0430303050505050300000" ++ $"000000000A04B570B86DB57DC12FC17CC729C17CBD8F0A062228224A485E5252" ++ $"52302C220A062228224A485E525252302C220A042228483852302C220A044838" ++ $"485E525252300A042228224A485E48380A042228224A485E48380A04453A4557" ++ $"2446242C0A04B560442446242CB569B8200A04B560442446242CB569B8200A04" ++ $"45544557244626440A0438263D234E28492C080438263D234E284E2E0A03492C" ++ $"4E284E2E0802425843C9830A04B570B86DB57DC12FC17CC729C17CBD8F0F0A06" ++ $"010C000A0001091001178400040A040108000A05010A000A0001011001178400" ++ $"040A010102000A03020405000A080106000A090107000A0A010B1815FF011782" ++ $"20040A020103000A110112023E00150000000000003E260D42CEDE44B6B40A26" ++ $"0112023E21EE0000000000003E260D483363471B5A0A250112023E0015000000" ++ $"0000003E260D42CEDE482DAD0A270112023E21EE0000000000003E41BA483363" ++ $"4901E6" ++}; +diff --git a/client/Haiku/images/close.png b/client/Haiku/images/close.png +new file mode 100644 +index 0000000000000000000000000000000000000000..584d790923a6dc766842e4baa2227f64aadf8d69 +GIT binary patch +literal 163 +zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|S)MMAAsQ2>UNYosP~dTU*#5C1 +z?&xHT3L*8qvmS)Rs^%_~Q2YFsS$|1!`it3(se32J%wO~`Wl79&Ge*bW6bJsAT;5qx +zyj8p8Sia;7Tn;+p{rlF+C$9^_wg>sMZ`w6A=~t~(WG?TLi_iZua`!Yw+VW_I0BvRP +MboFyt=akR{0P0ga`Tzg` + +literal 0 +HcmV?d00001 + +diff --git a/client/Haiku/images/zoom.png b/client/Haiku/images/zoom.png +new file mode 100644 +index 0000000000000000000000000000000000000000..4b796324247432ac5b5a9c595daf97cf4c2e33ab +GIT binary patch +literal 248 +zcmVT~(m?k3lv=wGL_)S2bcK<~Zn+v+O$JD4w +z=7(6M7ckPgvJNZ)kve)5dRo^uk}R^|9$dN;gjfxLl)0OGO6v+p-R=0fr%y=TVb9RL +y(0D?Gwt^cePMdcmQk({o_O=|SbiIe?JE