summaryrefslogtreecommitdiffstats
path: root/src/VBox/Additions/haiku
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Additions/haiku
parentInitial commit. (diff)
downloadvirtualbox-c31cb7e733ae8e33d73383e04db264d4293f0b1a.tar.xz
virtualbox-c31cb7e733ae8e33d73383e04db264d4293f0b1a.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Additions/haiku')
-rw-r--r--src/VBox/Additions/haiku/.scm-settings30
-rw-r--r--src/VBox/Additions/haiku/Makefile.kmk73
-rw-r--r--src/VBox/Additions/haiku/SharedFolders/Makefile.kmk89
-rw-r--r--src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h515
-rw-r--r--src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h122
-rw-r--r--src/VBox/Additions/haiku/SharedFolders/lock.h315
-rw-r--r--src/VBox/Additions/haiku/SharedFolders/vboxsf.c1055
-rw-r--r--src/VBox/Additions/haiku/SharedFolders/vboxsf.h120
-rw-r--r--src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp144
-rw-r--r--src/VBox/Additions/haiku/VBoxMouse/Makefile.kmk90
-rw-r--r--src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.cpp318
-rw-r--r--src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.h91
-rw-r--r--src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.cpp117
-rw-r--r--src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.h87
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/Makefile.kmk128
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp468
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.h88
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.cpp177
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.h86
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.cpp101
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.h89
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.cpp297
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.h109
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h78
-rw-r--r--src/VBox/Additions/haiku/VBoxTray/VBoxTray.rdef93
-rw-r--r--src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk64
-rw-r--r--src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk75
-rw-r--r--src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp473
-rw-r--r--src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h115
-rw-r--r--src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h114
-rw-r--r--src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk95
-rw-r--r--src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp382
-rw-r--r--src/VBox/Additions/haiku/include/VBoxGuestInternal.h74
-rw-r--r--src/VBox/Additions/haiku/include/lock.h318
-rwxr-xr-xsrc/VBox/Additions/haiku/load.sh52
-rwxr-xr-xsrc/VBox/Additions/haiku/unload.sh36
36 files changed, 6678 insertions, 0 deletions
diff --git a/src/VBox/Additions/haiku/.scm-settings b/src/VBox/Additions/haiku/.scm-settings
new file mode 100644
index 00000000..12be50ac
--- /dev/null
+++ b/src/VBox/Additions/haiku/.scm-settings
@@ -0,0 +1,30 @@
+# $Id: .scm-settings $
+## @file
+# Source code massager settings for haiku guest additions.
+#
+
+#
+# Copyright (C) 2010-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+
+/VBoxTray/VBoxTray.rdef: --treat-as .rc
+
diff --git a/src/VBox/Additions/haiku/Makefile.kmk b/src/VBox/Additions/haiku/Makefile.kmk
new file mode 100644
index 00000000..77c9dc0f
--- /dev/null
+++ b/src/VBox/Additions/haiku/Makefile.kmk
@@ -0,0 +1,73 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for Haiku Guest Additions.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+#
+# This code is based on:
+#
+# VirtualBox Guest Additions for Haiku.
+# Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+# François Revol <revol@free.fr>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+ifneq ($(KBUILD_HOST),haiku)
+ $(error "The Haiku guest additions installer can only be built on Haiku!")
+endif
+
+#
+# Include sub-makefiles.
+#
+include $(PATH_SUB_CURRENT)/SharedFolders/Makefile.kmk
+include $(PATH_SUB_CURRENT)/VBoxMouse/Makefile.kmk
+include $(PATH_SUB_CURRENT)/VBoxTray/Makefile.kmk
+include $(PATH_SUB_CURRENT)/VBoxVideo/Makefile.kmk
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk b/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk
new file mode 100644
index 00000000..daa5d002
--- /dev/null
+++ b/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk
@@ -0,0 +1,89 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for shared folders, Haiku Guest Additions.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+#
+# This code is based on:
+#
+# VirtualBox Guest Additions for Haiku.
+# Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+# François Revol <revol@free.fr>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+ifdef VBOX_WITH_ADDITION_DRIVERS
+ SYSMODS += vboxsf
+endif
+
+#
+# Populate FILES_VBOXSF_NOBIN
+#
+#include $(PATH_SUB_CURRENT)/files_vboxsf
+
+#
+# The module (for syntax checking).
+# The DEBUG_HASH* stuff is for CONFIG_DYNAMIC_DEBUG-enabled kernels
+#
+vboxsf_TEMPLATE = VBoxGuestR0Drv
+vboxsf_DEFS = \
+ MODULE IN_RT_R0 VBOXGUEST VBOX_WITH_HGCM \
+ KBUILD_MODNAME=KBUILD_STR\(vboxsf\) \
+ KBUILD_BASENAME=KBUILD_STR\(vboxsf\)
+vboxsf_INCS = \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest \
+ $(PATH_ROOT)/src/VBox/Runtime/r0drv/haiku
+vboxsf_SOURCES = \
+ vboxsf.c \
+ vnode_cache.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c
+vboxsf_LIBS = \
+ $(VBOX_LIB_VBGL_R0)
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h b/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h
new file mode 100644
index 00000000..ac01704d
--- /dev/null
+++ b/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h
@@ -0,0 +1,515 @@
+/* $Id: OpenHashTable.h $ */
+/** @file
+ * OpenHashTable, Haiku Guest Additions.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ *
+ * Copyright 2007, Hugo Santos. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h
+#define GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+
+#include <OS.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _KERNEL_MODE
+# include <KernelExport.h>
+# include "kernel_cpp.h"
+#endif
+
+/*!
+ The Definition template must have four methods: `HashKey', `Hash',
+ `Compare' and `GetLink;. It must also define several types as shown in the
+ following example:
+
+ struct Foo {
+ int bar;
+
+ Foo* fNext;
+ };
+
+ struct HashTableDefinition {
+ typedef int KeyType;
+ typedef Foo ValueType;
+
+ size_t HashKey(int key) const
+ {
+ return key >> 1;
+ }
+
+ size_t Hash(Foo* value) const
+ {
+ return HashKey(value->bar);
+ }
+
+ bool Compare(int key, Foo* value) const
+ {
+ return value->bar == key;
+ }
+
+ Foo*& GetLink(Foo* value) const
+ {
+ return value->fNext;
+ }
+ };
+*/
+
+
+struct MallocAllocator
+{
+ void* Allocate(size_t size) const
+ {
+ return malloc(size);
+ }
+
+ void Free(void* memory) const
+ {
+ free(memory);
+ }
+};
+
+
+template<typename Definition, bool AutoExpand = true,
+ bool CheckDuplicates = false, typename Allocator = MallocAllocator>
+class BOpenHashTable
+{
+public:
+ typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
+ typedef typename Definition::KeyType KeyType;
+ typedef typename Definition::ValueType ValueType;
+
+ static const size_t kMinimumSize = 8;
+
+ // All allocations are of power of 2 lengths.
+
+ // regrowth factor: 200 / 256 = 78.125%
+ // 50 / 256 = 19.53125%
+
+ BOpenHashTable()
+ :
+ fTableSize(0),
+ fItemCount(0),
+ fTable(NULL)
+ {
+ }
+
+ BOpenHashTable(const Definition& definition)
+ :
+ fDefinition(definition),
+ fTableSize(0),
+ fItemCount(0),
+ fTable(NULL)
+ {
+ }
+
+ BOpenHashTable(const Definition& definition, const Allocator& allocator)
+ :
+ fDefinition(definition),
+ fAllocator(allocator),
+ fTableSize(0),
+ fItemCount(0),
+ fTable(NULL)
+ {
+ }
+
+ ~BOpenHashTable()
+ {
+ fAllocator.Free(fTable);
+ }
+
+ status_t Init(size_t initialSize = kMinimumSize)
+ {
+ if (initialSize > 0 && !_Resize(initialSize))
+ return B_NO_MEMORY;
+ return B_OK;
+ }
+
+ size_t TableSize() const
+ {
+ return fTableSize;
+ }
+
+ size_t CountElements() const
+ {
+ return fItemCount;
+ }
+
+ ValueType* Lookup(const KeyType& key) const
+ {
+ if (fTableSize == 0)
+ return NULL;
+
+ size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
+ ValueType* slot = fTable[index];
+
+ while (slot)
+ {
+ if (fDefinition.Compare(key, slot))
+ break;
+ slot = _Link(slot);
+ }
+
+ return slot;
+ }
+
+ status_t Insert(ValueType* value)
+ {
+ if (fTableSize == 0)
+ {
+ if (!_Resize(kMinimumSize))
+ return B_NO_MEMORY;
+ }
+ else if (AutoExpand && fItemCount >= (fTableSize * 200 / 256))
+ _Resize(fTableSize * 2);
+
+ InsertUnchecked(value);
+ return B_OK;
+ }
+
+ void InsertUnchecked(ValueType* value)
+ {
+ if (CheckDuplicates && _ExhaustiveSearch(value))
+ {
+#ifdef _KERNEL_MODE
+ panic("Hash Table: value already in table.");
+#else
+ debugger("Hash Table: value already in table.");
+#endif
+ }
+
+ _Insert(fTable, fTableSize, value);
+ fItemCount++;
+ }
+
+ // TODO: a ValueType* Remove(const KeyType& key) method is missing
+
+ bool Remove(ValueType* value)
+ {
+ if (!RemoveUnchecked(value))
+ return false;
+
+ if (AutoExpand && fTableSize > kMinimumSize
+ && fItemCount < (fTableSize * 50 / 256))
+ _Resize(fTableSize / 2);
+
+ return true;
+ }
+
+ bool RemoveUnchecked(ValueType* value)
+ {
+ size_t index = fDefinition.Hash(value) & (fTableSize - 1);
+ ValueType* previous = NULL;
+ ValueType* slot = fTable[index];
+
+ while (slot)
+ {
+ ValueType* next = _Link(slot);
+
+ if (value == slot)
+ {
+ if (previous)
+ _Link(previous) = next;
+ else
+ fTable[index] = next;
+ break;
+ }
+
+ previous = slot;
+ slot = next;
+ }
+
+ if (slot == NULL)
+ return false;
+
+ if (CheckDuplicates && _ExhaustiveSearch(value))
+ {
+#ifdef _KERNEL_MODE
+ panic("Hash Table: duplicate detected.");
+#else
+ debugger("Hash Table: duplicate detected.");
+#endif
+ }
+
+ fItemCount--;
+ return true;
+ }
+
+ /*! Removes all elements from the hash table. No resizing happens. The
+ elements are not deleted. If \a returnElements is \c true, the method
+ returns all elements chained via their hash table link.
+ */
+ ValueType* Clear(bool returnElements = false)
+ {
+ if (this->fItemCount == 0)
+ return NULL;
+
+ ValueType* result = NULL;
+
+ if (returnElements)
+ {
+ ValueType** nextPointer = &result;
+
+ // iterate through all buckets
+ for (size_t i = 0; i < fTableSize; i++)
+ {
+ ValueType* element = fTable[i];
+ if (element != NULL)
+ {
+ // add the bucket to the list
+ *nextPointer = element;
+
+ // update nextPointer to point to the fNext of the last
+ // element in the bucket
+ while (element != NULL)
+ {
+ nextPointer = &_Link(element);
+ element = *nextPointer;
+ }
+ }
+ }
+ }
+
+ memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize);
+
+ return result;
+ }
+
+ /*! If the table needs resizing, the number of bytes for the required
+ allocation is returned. If no resizing is needed, 0 is returned.
+ */
+ size_t ResizeNeeded() const
+ {
+ size_t size = fTableSize;
+ if (size == 0 || fItemCount >= (size * 200 / 256))
+ {
+ // grow table
+ if (size == 0)
+ size = kMinimumSize;
+ while (fItemCount >= size * 200 / 256)
+ size <<= 1;
+ }
+ else if (size > kMinimumSize && fItemCount < size * 50 / 256)
+ {
+ // shrink table
+ while (fItemCount < size * 50 / 256)
+ size >>= 1;
+ if (size < kMinimumSize)
+ size = kMinimumSize;
+ }
+
+ if (size == fTableSize)
+ return 0;
+
+ return size * sizeof(ValueType*);
+ }
+
+ /*! Resizes the table using the given allocation. The allocation must not
+ be \c NULL. It must be of size \a size, which must a value returned
+ earlier by ResizeNeeded(). If the size requirements have changed in the
+ meantime, the method free()s the given allocation and returns \c false,
+ unless \a force is \c true, in which case the supplied allocation is
+ used in any event.
+ Otherwise \c true is returned.
+ If \a oldTable is non-null and resizing is successful, the old table
+ will not be freed, but will be returned via this parameter instead.
+ */
+ bool Resize(void* allocation, size_t size, bool force = false,
+ void** oldTable = NULL)
+ {
+ if (!force && size != ResizeNeeded())
+ {
+ fAllocator.Free(allocation);
+ return false;
+ }
+
+ _Resize((ValueType**)allocation, size / sizeof(ValueType*), oldTable);
+ return true;
+ }
+
+ class Iterator
+ {
+ public:
+ Iterator(const HashTable* table)
+ : fTable(table)
+ {
+ Rewind();
+ }
+
+ Iterator(const HashTable* table, size_t index, ValueType* value)
+ : fTable(table), fIndex(index), fNext(value) {}
+
+ bool HasNext() const { return fNext != NULL; }
+
+ ValueType* Next()
+ {
+ ValueType* current = fNext;
+ _GetNext();
+ return current;
+ }
+
+ void Rewind()
+ {
+ // get the first one
+ fIndex = 0;
+ fNext = NULL;
+ _GetNext();
+ }
+
+ protected:
+ Iterator() {}
+
+ void _GetNext()
+ {
+ if (fNext)
+ fNext = fTable->_Link(fNext);
+
+ while (fNext == NULL && fIndex < fTable->fTableSize)
+ fNext = fTable->fTable[fIndex++];
+ }
+
+ const HashTable* fTable;
+ size_t fIndex;
+ ValueType* fNext;
+ };
+
+ Iterator GetIterator() const
+ {
+ return Iterator(this);
+ }
+
+ Iterator GetIterator(const KeyType& key) const
+ {
+ if (fTableSize == 0)
+ return Iterator(this, fTableSize, NULL);
+
+ size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
+ ValueType* slot = fTable[index];
+
+ while (slot)
+ {
+ if (fDefinition.Compare(key, slot))
+ break;
+ slot = _Link(slot);
+ }
+
+ if (slot == NULL)
+ return Iterator(this, fTableSize, NULL);
+
+ return Iterator(this, index + 1, slot);
+ }
+
+protected:
+ // for g++ 2.95
+ friend class Iterator;
+
+ void _Insert(ValueType** table, size_t tableSize, ValueType* value)
+ {
+ size_t index = fDefinition.Hash(value) & (tableSize - 1);
+
+ _Link(value) = table[index];
+ table[index] = value;
+ }
+
+ bool _Resize(size_t newSize)
+ {
+ ValueType** newTable
+ = (ValueType**)fAllocator.Allocate(sizeof(ValueType*) * newSize);
+ if (newTable == NULL)
+ return false;
+
+ _Resize(newTable, newSize);
+ return true;
+ }
+
+ void _Resize(ValueType** newTable, size_t newSize, void** _oldTable = NULL)
+ {
+ for (size_t i = 0; i < newSize; i++)
+ newTable[i] = NULL;
+
+ if (fTable)
+ {
+ for (size_t i = 0; i < fTableSize; i++)
+ {
+ ValueType* bucket = fTable[i];
+ while (bucket)
+ {
+ ValueType* next = _Link(bucket);
+ _Insert(newTable, newSize, bucket);
+ bucket = next;
+ }
+ }
+
+ if (_oldTable != NULL)
+ *_oldTable = fTable;
+ else
+ fAllocator.Free(fTable);
+ }
+ else if (_oldTable != NULL)
+ *_oldTable = NULL;
+
+ fTableSize = newSize;
+ fTable = newTable;
+ }
+
+ ValueType*& _Link(ValueType* bucket) const
+ {
+ return fDefinition.GetLink(bucket);
+ }
+
+ bool _ExhaustiveSearch(ValueType* value) const
+ {
+ for (size_t i = 0; i < fTableSize; i++)
+ {
+ ValueType* bucket = fTable[i];
+ while (bucket) {
+ if (bucket == value)
+ return true;
+ bucket = _Link(bucket);
+ }
+ }
+
+ return false;
+ }
+
+ Definition fDefinition;
+ Allocator fAllocator;
+ size_t fTableSize;
+ size_t fItemCount;
+ ValueType** fTable;
+};
+
+#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h */
+
diff --git a/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h b/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h
new file mode 100644
index 00000000..7cc3093f
--- /dev/null
+++ b/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h
@@ -0,0 +1,122 @@
+/* $Id: kernel_cpp.h $ */
+/** @file
+ * Kernel C++, Haiku private.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku. C++ in the kernel.
+ *
+ * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h
+#define GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#ifdef __cplusplus
+
+#include <new>
+#include <stdlib.h>
+
+#if _KERNEL_MODE || _LOADER_MODE
+
+using namespace std;
+extern const nothrow_t std::nothrow;
+
+// We need new() versions we can use when also linking against libgcc.
+// std::nothrow can't be used since it's defined in both libgcc and
+// kernel_cpp.cpp.
+typedef struct {} mynothrow_t;
+extern const mynothrow_t mynothrow;
+
+
+inline void *
+operator new(size_t size) throw (std::bad_alloc)
+{
+ // we don't actually throw any exceptions, but we have to
+ // keep the prototype as specified in <new>, or else GCC 3
+ // won't like us
+ return malloc(size);
+}
+
+
+inline void *
+operator new[](size_t size) throw (std::bad_alloc)
+{
+ return malloc(size);
+}
+
+
+inline void *
+operator new(size_t size, const std::nothrow_t &) throw ()
+{
+ return malloc(size);
+}
+
+
+inline void *
+operator new[](size_t size, const std::nothrow_t &) throw ()
+{
+ return malloc(size);
+}
+
+
+inline void *
+operator new(size_t size, const mynothrow_t &) throw ()
+{
+ return malloc(size);
+}
+
+
+inline void *
+operator new[](size_t size, const mynothrow_t &) throw ()
+{
+ return malloc(size);
+}
+
+
+inline void
+operator delete(void *ptr) throw ()
+{
+ free(ptr);
+}
+
+
+inline void
+operator delete[](void *ptr) throw ()
+{
+ free(ptr);
+}
+
+#endif // #if _KERNEL_MODE
+
+#endif // __cplusplus
+
+#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h */
diff --git a/src/VBox/Additions/haiku/SharedFolders/lock.h b/src/VBox/Additions/haiku/SharedFolders/lock.h
new file mode 100644
index 00000000..4bca6a3f
--- /dev/null
+++ b/src/VBox/Additions/haiku/SharedFolders/lock.h
@@ -0,0 +1,315 @@
+/* $Id: lock.h $ */
+/** @file
+ * Lock.h - Haiku, private locking internals.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ *
+ * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_lock_h
+#define GA_INCLUDED_SRC_haiku_SharedFolders_lock_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <OS.h>
+
+
+struct mutex_waiter;
+
+typedef struct mutex {
+ const char* name;
+ struct mutex_waiter* waiters;
+#if KDEBUG
+ thread_id holder;
+#else
+ int32 count;
+ uint16 ignore_unlock_count;
+#endif
+ uint8 flags;
+} mutex;
+
+#define MUTEX_FLAG_CLONE_NAME 0x1
+
+
+typedef struct recursive_lock {
+ mutex lock;
+#if !KDEBUG
+ thread_id holder;
+#endif
+ int recursion;
+} recursive_lock;
+
+
+struct rw_lock_waiter;
+
+typedef struct rw_lock {
+ const char* name;
+ struct rw_lock_waiter* waiters;
+ thread_id holder;
+ vint32 count;
+ int32 owner_count;
+ int16 active_readers;
+ // Only > 0 while a writer is waiting: number
+ // of active readers when the first waiting
+ // writer started waiting.
+ int16 pending_readers;
+ // Number of readers that have already
+ // incremented "count", but have not yet started
+ // to wait at the time the last writer unlocked.
+ uint32 flags;
+} rw_lock;
+
+#define RW_LOCK_WRITER_COUNT_BASE 0x10000
+
+#define RW_LOCK_FLAG_CLONE_NAME 0x1
+
+
+#if KDEBUG
+# define KDEBUG_RW_LOCK_DEBUG 0
+ // Define to 1 if you want to use ASSERT_READ_LOCKED_RW_LOCK().
+ // The rw_lock will just behave like a recursive locker then.
+# define ASSERT_LOCKED_RECURSIVE(r) \
+ { ASSERT(find_thread(NULL) == (r)->lock.holder); }
+# define ASSERT_LOCKED_MUTEX(m) { ASSERT(find_thread(NULL) == (m)->holder); }
+# define ASSERT_WRITE_LOCKED_RW_LOCK(l) \
+ { ASSERT(find_thread(NULL) == (l)->holder); }
+# if KDEBUG_RW_LOCK_DEBUG
+# define ASSERT_READ_LOCKED_RW_LOCK(l) \
+ { ASSERT(find_thread(NULL) == (l)->holder); }
+# else
+# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false)
+# endif
+#else
+# define ASSERT_LOCKED_RECURSIVE(r) do {} while (false)
+# define ASSERT_LOCKED_MUTEX(m) do {} while (false)
+# define ASSERT_WRITE_LOCKED_RW_LOCK(m) do {} while (false)
+# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false)
+#endif
+
+
+// static initializers
+#if KDEBUG
+# define MUTEX_INITIALIZER(name) { name, NULL, -1, 0 }
+# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), 0 }
+#else
+# define MUTEX_INITIALIZER(name) { name, NULL, 0, 0, 0 }
+# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), -1, 0 }
+#endif
+
+#define RW_LOCK_INITIALIZER(name) { name, NULL, -1, 0, 0, 0 }
+
+
+#if KDEBUG
+# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->lock.holder)
+#else
+# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->holder)
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void recursive_lock_init(recursive_lock *lock, const char *name);
+ // name is *not* cloned nor freed in recursive_lock_destroy()
+extern void recursive_lock_init_etc(recursive_lock *lock, const char *name,
+ uint32 flags);
+extern void recursive_lock_destroy(recursive_lock *lock);
+extern status_t recursive_lock_lock(recursive_lock *lock);
+extern status_t recursive_lock_trylock(recursive_lock *lock);
+extern void recursive_lock_unlock(recursive_lock *lock);
+extern int32 recursive_lock_get_recursion(recursive_lock *lock);
+
+extern void rw_lock_init(rw_lock* lock, const char* name);
+ // name is *not* cloned nor freed in rw_lock_destroy()
+extern void rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags);
+extern void rw_lock_destroy(rw_lock* lock);
+extern status_t rw_lock_write_lock(rw_lock* lock);
+
+extern void mutex_init(mutex* lock, const char* name);
+ // name is *not* cloned nor freed in mutex_destroy()
+extern void mutex_init_etc(mutex* lock, const char* name, uint32 flags);
+extern void mutex_destroy(mutex* lock);
+extern status_t mutex_switch_lock(mutex* from, mutex* to);
+ // Unlocks "from" and locks "to" such that unlocking and starting to wait
+ // for the lock is atomically. I.e. if "from" guards the object "to" belongs
+ // to, the operation is safe as long as "from" is held while destroying
+ // "to".
+extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to);
+ // Like mutex_switch_lock(), just for a switching from a read-locked
+ // rw_lock.
+
+
+// implementation private:
+
+extern status_t _rw_lock_read_lock(rw_lock* lock);
+extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock,
+ uint32 timeoutFlags, bigtime_t timeout);
+extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked);
+extern void _rw_lock_write_unlock(rw_lock* lock, bool threadsLocked);
+
+extern status_t _mutex_lock(mutex* lock, bool threadsLocked);
+extern void _mutex_unlock(mutex* lock, bool threadsLocked);
+extern status_t _mutex_trylock(mutex* lock);
+extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags,
+ bigtime_t timeout);
+
+
+static inline status_t
+rw_lock_read_lock(rw_lock* lock)
+{
+#if KDEBUG_RW_LOCK_DEBUG
+ return rw_lock_write_lock(lock);
+#else
+ int32 oldCount = atomic_add(&lock->count, 1);
+ if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
+ return _rw_lock_read_lock(lock);
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags,
+ bigtime_t timeout)
+{
+#if KDEBUG_RW_LOCK_DEBUG
+ return mutex_lock_with_timeout(lock, timeoutFlags, timeout);
+#else
+ int32 oldCount = atomic_add(&lock->count, 1);
+ if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
+ return _rw_lock_read_lock_with_timeout(lock, timeoutFlags, timeout);
+ return B_OK;
+#endif
+}
+
+
+static inline void
+rw_lock_read_unlock(rw_lock* lock)
+{
+#if KDEBUG_RW_LOCK_DEBUG
+ rw_lock_write_unlock(lock);
+#else
+ int32 oldCount = atomic_add(&lock->count, -1);
+ if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
+ _rw_lock_read_unlock(lock, false);
+#endif
+}
+
+
+static inline void
+rw_lock_write_unlock(rw_lock* lock)
+{
+ _rw_lock_write_unlock(lock, false);
+}
+
+
+static inline status_t
+mutex_lock(mutex* lock)
+{
+#if KDEBUG
+ return _mutex_lock(lock, false);
+#else
+ if (atomic_add(&lock->count, -1) < 0)
+ return _mutex_lock(lock, false);
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+mutex_lock_threads_locked(mutex* lock)
+{
+#if KDEBUG
+ return _mutex_lock(lock, true);
+#else
+ if (atomic_add(&lock->count, -1) < 0)
+ return _mutex_lock(lock, true);
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+mutex_trylock(mutex* lock)
+{
+#if KDEBUG
+ return _mutex_trylock(lock);
+#else
+ if (atomic_test_and_set(&lock->count, -1, 0) != 0)
+ return B_WOULD_BLOCK;
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout)
+{
+#if KDEBUG
+ return _mutex_lock_with_timeout(lock, timeoutFlags, timeout);
+#else
+ if (atomic_add(&lock->count, -1) < 0)
+ return _mutex_lock_with_timeout(lock, timeoutFlags, timeout);
+ return B_OK;
+#endif
+}
+
+
+static inline void
+mutex_unlock(mutex* lock)
+{
+#if !KDEBUG
+ if (atomic_add(&lock->count, 1) < -1)
+#endif
+ _mutex_unlock(lock, false);
+}
+
+
+static inline void
+mutex_transfer_lock(mutex* lock, thread_id thread)
+{
+#if KDEBUG
+ lock->holder = thread;
+#endif
+}
+
+
+extern void lock_debug_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_lock_h */
diff --git a/src/VBox/Additions/haiku/SharedFolders/vboxsf.c b/src/VBox/Additions/haiku/SharedFolders/vboxsf.c
new file mode 100644
index 00000000..26182d42
--- /dev/null
+++ b/src/VBox/Additions/haiku/SharedFolders/vboxsf.c
@@ -0,0 +1,1055 @@
+/* $Id: vboxsf.c $ */
+/** @file
+ * Shared folders - Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "vboxsf.h"
+
+#define MODULE_NAME "file_systems/vboxsf"
+#define FS_NAME "vboxsf"
+#define FS_PRETTY_NAME "VirtualBox Shared Folders"
+
+VBGLSFCLIENT g_clientHandle;
+static fs_volume_ops vboxsf_volume_ops;
+static fs_vnode_ops vboxsf_vnode_ops;
+
+status_t init_module(void)
+{
+#if 0
+ /** @todo enable this soon */
+ int rc = get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest);
+ if (RT_LIKELY(rc == B_OK)
+ {
+ rc = VbglR0SfInit();
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR0SfConnect(&g_clientHandle);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR0SfSetUtf8(&g_clientHandle);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR0SfSetSymlinks(&g_clientHandle);
+ if (RT_FAILURE(rc))
+ LogRel((FS_NAME ": Warning! VbglR0SfSetSymlinks failed (rc=%d) - symlink will appear as copies.\n", rc));
+
+ mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock");
+ Log((FS_NAME ": init_module succeeded.\n");
+ return B_OK;
+ }
+ else
+ LogRel((FS_NAME ": VbglR0SfSetUtf8 failed. rc=%d\n", rc));
+ }
+ else
+ LogRel((FS_NAME ": VbglR0SfConnect failed. rc=%d\n", rc));
+ }
+ else
+ LogRel((FS_NAME ": VbglR0SfInit failed. rc=%d\n", rc));
+ }
+ else
+ LogRel((FS_NAME ": get_module failed for '%s'. rc=%d\n", VBOXGUEST_MODULE_NAME, rc));
+
+ return B_ERROR;
+#endif
+
+ if (get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest) != B_OK)
+ {
+ dprintf("get_module(%s) failed\n", VBOXGUEST_MODULE_NAME);
+ return B_ERROR;
+ }
+
+ if (RT_FAILURE(VbglR0SfInit()))
+ {
+ dprintf("VbglR0SfInit failed\n");
+ return B_ERROR;
+ }
+
+ if (RT_FAILURE(VbglR0SfConnect(&g_clientHandle)))
+ {
+ dprintf("VbglR0SfConnect failed\n");
+ return B_ERROR;
+ }
+
+ if (RT_FAILURE(VbglR0SfSetUtf8(&g_clientHandle)))
+ {
+ dprintf("VbglR0SfSetUtf8 failed\n");
+ return B_ERROR;
+ }
+
+ if (RT_FAILURE(VbglR0SfSetSymlinks(&g_clientHandle)))
+ {
+ dprintf("warning: VbglR0SfSetSymlinks failed (old vbox?) - symlinks will appear as copies\n");
+ }
+
+ mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock");
+
+ dprintf(FS_NAME ": inited successfully\n");
+ return B_OK;
+}
+
+void uninit_module(void)
+{
+ mutex_destroy(&g_vnodeCacheLock);
+ put_module(VBOXGUEST_MODULE_NAME);
+}
+
+
+PSHFLSTRING make_shflstring(const char* const s)
+{
+ int len = strlen(s);
+ if (len > 0xFFFE)
+ {
+ dprintf(FS_NAME ": make_shflstring: string too long\n");
+ return NULL;
+ }
+
+ PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len);
+ if (!rv)
+ return NULL;
+
+ rv->u16Length = len;
+ rv->u16Size = len + 1;
+ strcpy(rv->String.utf8, s);
+ return rv;
+}
+
+
+PSHFLSTRING clone_shflstring(PSHFLSTRING s)
+{
+ PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s->u16Length);
+ if (rv)
+ memcpy(rv, s, sizeof(SHFLSTRING) + s->u16Length);
+ return rv;
+}
+
+PSHFLSTRING concat_shflstring_cstr(PSHFLSTRING s1, const char* const s2)
+{
+ size_t s2len = strlen(s2);
+ PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1->u16Length + s2len);
+ if (rv)
+ {
+ memcpy(rv, s1, sizeof(SHFLSTRING) + s1->u16Length);
+ strcat(rv->String.utf8, s2);
+ rv->u16Length += s2len;
+ rv->u16Size += s2len;
+ }
+ return rv;
+}
+
+
+PSHFLSTRING concat_cstr_shflstring(const char* const s1, PSHFLSTRING s2)
+{
+ size_t s1len = strlen(s1);
+ PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1len + s2->u16Length);
+ if (rv)
+ {
+ strcpy(rv->String.utf8, s1);
+ strcat(rv->String.utf8, s2->String.utf8);
+ rv->u16Length = s1len + s2->u16Length;
+ rv->u16Size = rv->u16Length + 1;
+ }
+ return rv;
+}
+
+
+PSHFLSTRING build_path(vboxsf_vnode* dir, const char* const name)
+{
+ dprintf("*** build_path(%p, %p)\n", dir, name);
+ if (!dir || !name)
+ return NULL;
+
+ size_t len = dir->path->u16Length + strlen(name) + 1;
+ PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len);
+ if (rv)
+ {
+ strcpy(rv->String.utf8, dir->path->String.utf8);
+ strcat(rv->String.utf8, "/");
+ strcat(rv->String.utf8, name);
+ rv->u16Length = len;
+ rv->u16Size = rv->u16Length + 1;
+ }
+ return rv;
+}
+
+
+status_t mount(fs_volume *volume, const char *device, uint32 flags, const char *args, ino_t *_rootVnodeID)
+{
+ if (device)
+ {
+ dprintf(FS_NAME ": trying to mount a real device as a vbox share is silly\n");
+ return B_BAD_TYPE;
+ }
+
+ dprintf(FS_NAME ": mount(%s)\n", args);
+
+ PSHFLSTRING sharename = make_shflstring(args);
+
+ vboxsf_volume* vbsfvolume = malloc(sizeof(vboxsf_volume));
+ volume->private_volume = vbsfvolume;
+ int rv = VbglR0SfMapFolder(&g_clientHandle, sharename, &(vbsfvolume->map));
+ free(sharename);
+
+ if (rv == 0)
+ {
+ vboxsf_vnode* root_vnode;
+
+ PSHFLSTRING name = make_shflstring("");
+ if (!name)
+ {
+ dprintf(FS_NAME ": make_shflstring() failed\n");
+ return B_NO_MEMORY;
+ }
+
+ status_t rs = vboxsf_new_vnode(&vbsfvolume->map, name, name, &root_vnode);
+ dprintf(FS_NAME ": allocated %p (path=%p name=%p)\n", root_vnode, root_vnode->path, root_vnode->name);
+
+ if (rs != B_OK)
+ {
+ dprintf(FS_NAME ": vboxsf_new_vnode() failed (%d)\n", (int)rs);
+ return rs;
+ }
+
+ rs = publish_vnode(volume, root_vnode->vnode, root_vnode, &vboxsf_vnode_ops, S_IFDIR, 0);
+ dprintf(FS_NAME ": publish_vnode(): %d\n", (int)rs);
+ *_rootVnodeID = root_vnode->vnode;
+ volume->ops = &vboxsf_volume_ops;
+ return B_OK;
+ }
+ else
+ {
+ dprintf(FS_NAME ": VbglR0SfMapFolder failed (%d)\n", rv);
+ free(volume->private_volume);
+ return vbox_err_to_haiku_err(rv);
+ }
+}
+
+
+status_t unmount(fs_volume *volume)
+{
+ dprintf(FS_NAME ": unmount\n");
+ VbglR0SfUnmapFolder(&g_clientHandle, volume->private_volume);
+ return B_OK;
+}
+
+
+status_t vboxsf_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* st)
+{
+ vboxsf_vnode* vnode = _vnode->private_node;
+ vboxsf_volume* volume = _volume->private_volume;
+ SHFLCREATEPARMS params;
+ int rc;
+
+ dprintf("vboxsf_read_stat (_vnode=%p, vnode=%p, path=%p (%s))\n", _vnode, vnode, vnode->path->String.utf8, vnode->path->String.utf8);
+
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
+ dprintf("sf_stat: calling VbglR0SfCreate, file %s, flags %x\n", vnode->path->String.utf8, params.CreateFlags);
+ rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, &params);
+ if (rc == VERR_INVALID_NAME)
+ {
+ /* this can happen for names like 'foo*' on a Windows host */
+ return B_ENTRY_NOT_FOUND;
+ }
+ if (RT_FAILURE(rc))
+ {
+ dprintf("VbglR0SfCreate: %d\n", params.Result);
+ return vbox_err_to_haiku_err(params.Result);
+ }
+ if (params.Result != SHFL_FILE_EXISTS)
+ {
+ dprintf("VbglR0SfCreate: %d\n", params.Result);
+ return B_ENTRY_NOT_FOUND;
+ }
+
+ st->st_dev = 0;
+ st->st_ino = vnode->vnode;
+ st->st_mode = mode_from_fmode(params.Info.Attr.fMode);
+ st->st_nlink = 1;
+ st->st_uid = 0;
+ st->st_gid = 0;
+ st->st_rdev = 0;
+ st->st_size = params.Info.cbObject;
+ st->st_blksize = 1;
+ st->st_blocks = params.Info.cbAllocated;
+ st->st_atime = RTTimeSpecGetSeconds(&params.Info.AccessTime);
+ st->st_mtime = RTTimeSpecGetSeconds(&params.Info.ModificationTime);
+ st->st_ctime = RTTimeSpecGetSeconds(&params.Info.BirthTime);
+ return B_OK;
+}
+
+
+status_t vboxsf_open_dir(fs_volume* _volume, fs_vnode* _vnode, void** _cookie)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_vnode* vnode = _vnode->private_node;
+ SHFLCREATEPARMS params;
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
+
+ int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, &params);
+ if (RT_SUCCESS(rc))
+ {
+ if (params.Result == SHFL_FILE_EXISTS && params.Handle != SHFL_HANDLE_NIL)
+ {
+ vboxsf_dir_cookie* cookie = malloc(sizeof(vboxsf_dir_cookie));
+ *_cookie = cookie;
+ cookie->index = 0;
+ cookie->path = build_path(vnode, "*");
+ cookie->handle = params.Handle;
+ cookie->has_more_files = true;
+ cookie->buffer_start = cookie->buffer = NULL;
+ cookie->buffer_length = cookie->num_files = 0;
+ return B_OK;
+ }
+ else
+ return B_ENTRY_NOT_FOUND;
+ }
+ else
+ {
+ dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc);
+ return vbox_err_to_haiku_err(rc);
+ }
+}
+
+
+/** read a single entry from a dir */
+status_t vboxsf_read_dir_1(vboxsf_volume* volume, vboxsf_vnode* vnode, vboxsf_dir_cookie* cookie,
+ struct dirent* buffer, size_t bufferSize)
+{
+ dprintf("%p, %d, %p\n", cookie, cookie->has_more_files, cookie->buffer);
+ if (!cookie->has_more_files)
+ return B_ENTRY_NOT_FOUND;
+
+ if (!cookie->buffer)
+ {
+ cookie->buffer_length = 16384;
+ cookie->buffer_start = cookie->buffer = malloc(cookie->buffer_length);
+
+ int rc = VbglR0SfDirInfo(&g_clientHandle, &volume->map, cookie->handle, cookie->path, 0, cookie->index,
+ &cookie->buffer_length, cookie->buffer, &cookie->num_files);
+
+ if (rc != 0 && rc != VERR_NO_MORE_FILES)
+ {
+ dprintf(FS_NAME ": VbglR0SfDirInfo failed: %d\n", rc);
+ free(cookie->buffer_start);
+ cookie->buffer_start = NULL;
+ return vbox_err_to_haiku_err(rc);
+ }
+
+ if (rc == VERR_NO_MORE_FILES)
+ {
+ free(cookie->buffer_start);
+ cookie->buffer_start = NULL;
+ cookie->has_more_files = false;
+ return B_ENTRY_NOT_FOUND;
+ }
+ }
+
+ if (bufferSize <= sizeof(struct dirent) + cookie->buffer->name.u16Length)
+ {
+ dprintf("hit end of buffer\n");
+ return B_BUFFER_OVERFLOW;
+ }
+
+ PSHFLSTRING name1 = clone_shflstring(&cookie->buffer->name);
+ if (!name1)
+ {
+ dprintf(FS_NAME ": make_shflstring() failed\n");
+ return B_NO_MEMORY;
+ }
+
+ vboxsf_vnode* new_vnode;
+ int rv = vboxsf_new_vnode(&volume->map, build_path(vnode, name1->String.utf8), name1, &new_vnode);
+ if (rv != B_OK)
+ {
+ dprintf(FS_NAME ": vboxsf_new_vnode() failed\n");
+ return rv;
+ }
+
+ buffer->d_dev = 0;
+ buffer->d_pdev = 0;
+ buffer->d_ino = new_vnode->vnode;
+ buffer->d_pino = vnode->vnode;
+ buffer->d_reclen = sizeof(struct dirent) + cookie->buffer->name.u16Length;
+ strncpy(buffer->d_name, cookie->buffer->name.String.utf8, NAME_MAX);
+
+ size_t size = offsetof(SHFLDIRINFO, name.String) + cookie->buffer->name.u16Size;
+ cookie->buffer = ((void*)cookie->buffer + size);
+ cookie->index++;
+
+ if (cookie->index >= cookie->num_files)
+ {
+ // hit end of this buffer, next call will reallocate a new one
+ free(cookie->buffer_start);
+ cookie->buffer_start = cookie->buffer = NULL;
+ }
+ return B_OK;
+}
+
+
+status_t vboxsf_read_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
+ struct dirent* buffer, size_t bufferSize, uint32* _num)
+{
+ vboxsf_dir_cookie* cookie = _cookie;
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_vnode* vnode = _vnode->private_node;
+ uint32 num_read = 0;
+ status_t rv = B_OK;
+
+ for (num_read = 0; num_read < *_num && cookie->has_more_files; num_read++)
+ {
+ rv = vboxsf_read_dir_1(volume, vnode, cookie, buffer, bufferSize);
+ if (rv == B_BUFFER_OVERFLOW || rv == B_ENTRY_NOT_FOUND)
+ {
+ // hit end of at least one of the buffers - not really an error
+ rv = B_OK;
+ break;
+ }
+ bufferSize -= buffer->d_reclen;
+ buffer = ((void*)(buffer)) + buffer->d_reclen;
+ }
+
+ *_num = num_read;
+ return rv;
+}
+
+
+status_t vboxsf_free_dir_cookie(fs_volume* _volume, fs_vnode* vnode, void* _cookie)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_dir_cookie* cookie = _cookie;
+
+ VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle);
+ free(cookie->path);
+ free(cookie);
+
+ return B_OK;
+}
+
+
+status_t vboxsf_read_fs_info(fs_volume* _volume, struct fs_info* info)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+
+ SHFLVOLINFO volume_info;
+ uint32_t bytes = sizeof(SHFLVOLINFO);
+
+ int rc = VbglR0SfFsInfo(&g_clientHandle, &volume->map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,
+ &bytes, (PSHFLDIRINFO)&volume_info);
+ if (RT_FAILURE(rc))
+ {
+ dprintf(FS_NAME ": VbglR0SfFsInfo failed (%d)\n", rc);
+ return vbox_err_to_haiku_err(rc);
+ }
+
+ info->flags = B_FS_IS_PERSISTENT;
+ if (volume_info.fsProperties.fReadOnly)
+ info->flags |= B_FS_IS_READONLY;
+
+ info->dev = 0;
+ info->root = 1;
+ info->block_size = volume_info.ulBytesPerAllocationUnit;
+ info->io_size = volume_info.ulBytesPerAllocationUnit;
+ info->total_blocks = volume_info.ullTotalAllocationBytes / info->block_size;
+ info->free_blocks = volume_info.ullAvailableAllocationBytes / info->block_size;
+ info->total_nodes = LONGLONG_MAX;
+ info->free_nodes = LONGLONG_MAX;
+ strcpy(info->volume_name, "VBox share");
+ return B_OK;
+}
+
+
+status_t vboxsf_lookup(fs_volume* _volume, fs_vnode* dir, const char* name, ino_t* _id)
+{
+ dprintf(FS_NAME ": lookup %s\n", name);
+ vboxsf_volume* volume = _volume->private_volume;
+ SHFLCREATEPARMS params;
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+ params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
+
+ PSHFLSTRING path = build_path(dir->private_node, name);
+ if (!path)
+ {
+ dprintf(FS_NAME ": make_shflstring() failed\n");
+ return B_NO_MEMORY;
+ }
+
+ int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, &params);
+ if (RT_SUCCESS(rc))
+ {
+ if (params.Result == SHFL_FILE_EXISTS)
+ {
+ vboxsf_vnode* vn;
+ status_t rv = vboxsf_new_vnode(&volume->map, path, path, &vn);
+ if (rv == B_OK)
+ {
+ *_id = vn->vnode;
+ rv = publish_vnode(_volume, vn->vnode, vn, &vboxsf_vnode_ops, mode_from_fmode(params.Info.Attr.fMode), 0);
+ }
+ return rv;
+ }
+ else
+ {
+ free(path);
+ return B_ENTRY_NOT_FOUND;
+ }
+ }
+ else
+ {
+ free(path);
+ dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc);
+ return vbox_err_to_haiku_err(rc);
+ }
+}
+
+
+mode_t mode_from_fmode(RTFMODE fMode)
+{
+ mode_t m = 0;
+
+ if (RTFS_IS_DIRECTORY(fMode))
+ m |= S_IFDIR;
+ else if (RTFS_IS_FILE(fMode))
+ m |= S_IFREG;
+ else if (RTFS_IS_FIFO(fMode))
+ m |= S_IFIFO;
+ else if (RTFS_IS_DEV_CHAR(fMode))
+ m |= S_IFCHR;
+ else if (RTFS_IS_DEV_BLOCK(fMode))
+ m |= S_IFBLK;
+ else if (RTFS_IS_SYMLINK(fMode))
+ m |= S_IFLNK;
+ else if (RTFS_IS_SOCKET(fMode))
+ m |= S_IFSOCK;
+
+ if (fMode & RTFS_UNIX_IRUSR)
+ m |= S_IRUSR;
+ if (fMode & RTFS_UNIX_IWUSR)
+ m |= S_IWUSR;
+ if (fMode & RTFS_UNIX_IXUSR)
+ m |= S_IXUSR;
+ if (fMode & RTFS_UNIX_IRGRP)
+ m |= S_IRGRP;
+ if (fMode & RTFS_UNIX_IWGRP)
+ m |= S_IWGRP;
+ if (fMode & RTFS_UNIX_IXGRP)
+ m |= S_IXGRP;
+ if (fMode & RTFS_UNIX_IROTH)
+ m |= S_IROTH;
+ if (fMode & RTFS_UNIX_IWOTH)
+ m |= S_IWOTH;
+ if (fMode & RTFS_UNIX_IXOTH)
+ m |= S_IXOTH;
+ if (fMode & RTFS_UNIX_ISUID)
+ m |= S_ISUID;
+ if (fMode & RTFS_UNIX_ISGID)
+ m |= S_ISGID;
+ if (fMode & RTFS_UNIX_ISTXT)
+ m |= S_ISVTX;
+
+ return m;
+}
+
+
+status_t vboxsf_open(fs_volume* _volume, fs_vnode* _vnode, int openMode, void** _cookie)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_vnode* vnode = _vnode->private_node;
+
+ dprintf(FS_NAME ": open %s (mode=%x)\n", vnode->path->String.utf8, openMode);
+
+ SHFLCREATEPARMS params;
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+
+ if (openMode & O_RDWR)
+ params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
+ else if (openMode & O_RDONLY)
+ params.CreateFlags |= SHFL_CF_ACCESS_READ;
+ else if (openMode & O_WRONLY)
+ params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
+
+ if (openMode & O_APPEND)
+ params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
+
+ if (openMode & O_CREAT)
+ {
+ params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
+ if (openMode & O_EXCL)
+ params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
+ else if (openMode & O_TRUNC)
+ params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+ else
+ params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
+ }
+ else
+ {
+ params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
+ if (openMode & O_TRUNC)
+ params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+ else
+ params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
+ }
+
+ int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, &params);
+ if (!RT_SUCCESS(rc))
+ {
+ dprintf("VbglR0SfCreate returned %d\n", rc);
+ return vbox_err_to_haiku_err(rc);
+ }
+
+ vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie));
+ if (!cookie)
+ {
+ dprintf("couldn't allocate file cookie\n");
+ return B_NO_MEMORY;
+ }
+
+ cookie->handle = params.Handle;
+ cookie->path = vnode->path;
+
+ *_cookie = cookie;
+
+ return B_OK;
+}
+
+
+status_t vboxsf_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode, int perms, void **_cookie, ino_t *_newVnodeID)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+
+ SHFLCREATEPARMS params;
+
+ RT_ZERO(params);
+ params.Handle = SHFL_HANDLE_NIL;
+
+ if (openMode & O_RDWR)
+ params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
+ else if (openMode & O_RDONLY)
+ params.CreateFlags |= SHFL_CF_ACCESS_READ;
+ else if (openMode & O_WRONLY)
+ params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
+
+ if (openMode & O_APPEND)
+ params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
+
+ if (openMode & O_CREAT)
+ {
+ params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
+ if (openMode & O_EXCL)
+ params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
+ else if (openMode & O_TRUNC)
+ params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+ else
+ params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
+ }
+ else
+ {
+ params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
+ if (openMode & O_TRUNC)
+ params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+ else
+ params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
+ }
+
+ PSHFLSTRING path = build_path(_dir->private_node, name);
+ int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, &params);
+
+ if (!RT_SUCCESS(rc))
+ {
+ dprintf("VbglR0SfCreate returned %d\n", rc);
+ free(path);
+ return vbox_err_to_haiku_err(rc);
+ }
+
+ vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie));
+ if (!cookie)
+ {
+ dprintf("couldn't allocate file cookie\n");
+ free(path);
+ return B_NO_MEMORY;
+ }
+
+ cookie->handle = params.Handle;
+ cookie->path = path;
+
+ *_cookie = cookie;
+ return vboxsf_lookup(_volume, _dir, name, _newVnodeID);
+}
+
+
+status_t vboxsf_close(fs_volume* _volume, fs_vnode* _vnode, void* _cookie)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_file_cookie* cookie = _cookie;
+
+ int rc = VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle);
+ dprintf("VbglR0SfClose returned %d\n", rc);
+ return vbox_err_to_haiku_err(rc);
+}
+
+
+status_t vboxsf_rewind_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie)
+{
+ vboxsf_dir_cookie* cookie = _cookie;
+ cookie->index = 0;
+ return B_OK;
+}
+
+
+status_t vboxsf_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
+{
+ return B_OK;
+}
+
+
+status_t vboxsf_free_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie)
+{
+ vboxsf_dir_cookie* cookie = _cookie;
+ free(cookie);
+ return B_OK;
+}
+
+status_t vboxsf_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, void *buffer, size_t *length)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_vnode* vnode = _vnode->private_node;
+ vboxsf_file_cookie* cookie = _cookie;
+
+ if (*length > 0xFFFFFFFF)
+ *length = 0xFFFFFFFF;
+
+ uint32_t l = *length;
+ void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */
+ int rc = VbglR0SfRead(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/);
+ memcpy(buffer, other_buffer, l);
+ free(other_buffer);
+
+ dprintf("VbglR0SfRead returned %d\n", rc);
+ *length = l;
+ return vbox_err_to_haiku_err(rc);
+}
+
+
+status_t vboxsf_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, const void *buffer, size_t *length)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_vnode* vnode = _vnode->private_node;
+ vboxsf_file_cookie* cookie = _cookie;
+
+ if (*length > 0xFFFFFFFF)
+ *length = 0xFFFFFFFF;
+
+ uint32_t l = *length;
+ void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */
+ memcpy(other_buffer, buffer, l);
+ int rc = VbglR0SfWrite(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/);
+ free(other_buffer);
+
+ *length = l;
+ return vbox_err_to_haiku_err(rc);
+}
+
+
+status_t vboxsf_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, uint32 statMask)
+{
+ /* The host handles updating the stat info - in the guest, this is a no-op */
+ return B_OK;
+}
+
+
+status_t vboxsf_create_dir(fs_volume *_volume, fs_vnode *parent, const char *name, int perms)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+
+ SHFLCREATEPARMS params;
+ params.Handle = 0;
+ params.Info.cbObject = 0;
+ params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
+ SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
+
+ PSHFLSTRING path = build_path(parent->private_node, name);
+ int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, &params);
+ free(path);
+ /** @todo r=ramshankar: we should perhaps also check rc here and change
+ * Handle initialization from 0 to SHFL_HANDLE_NIL. */
+ if (params.Handle == SHFL_HANDLE_NIL)
+ return vbox_err_to_haiku_err(rc);
+ VbglR0SfClose(&g_clientHandle, &volume->map, params.Handle);
+ return B_OK;
+}
+
+
+status_t vboxsf_remove_dir(fs_volume *_volume, fs_vnode *parent, const char *name)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+
+ PSHFLSTRING path = build_path(parent->private_node, name);
+ int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_DIR);
+ free(path);
+
+ return vbox_err_to_haiku_err(rc);
+}
+
+
+status_t vboxsf_unlink(fs_volume *_volume, fs_vnode *parent, const char *name)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+
+ PSHFLSTRING path = build_path(parent->private_node, name);
+ int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_FILE);
+ free(path);
+
+ return vbox_err_to_haiku_err(rc);
+}
+
+status_t vboxsf_link(fs_volume *volume, fs_vnode *dir, const char *name, fs_vnode *vnode)
+{
+ return B_UNSUPPORTED;
+}
+
+
+status_t vboxsf_rename(fs_volume* _volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+
+ PSHFLSTRING oldpath = build_path(fromDir->private_node, fromName);
+ PSHFLSTRING newpath = build_path(toDir->private_node, toName);
+ int rc = VbglR0SfRename(&g_clientHandle, &volume->map, oldpath, newpath, SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
+ free(oldpath);
+ free(newpath);
+
+ return vbox_err_to_haiku_err(rc);
+}
+
+
+status_t vboxsf_create_symlink(fs_volume* _volume, fs_vnode* dir, const char* name, const char* path, int mode)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+
+ PSHFLSTRING target = make_shflstring(path);
+ PSHFLSTRING linkpath = build_path(dir->private_node, name);
+ SHFLFSOBJINFO stuff;
+ RT_ZERO(stuff);
+
+ int rc = VbglR0SfSymlink(&g_clientHandle, &volume->map, linkpath, target, &stuff);
+
+ free(target);
+ free(linkpath);
+
+ return vbox_err_to_haiku_err(rc);
+}
+
+
+status_t vboxsf_read_symlink(fs_volume* _volume, fs_vnode* link, char* buffer, size_t* _bufferSize)
+{
+ vboxsf_volume* volume = _volume->private_volume;
+ vboxsf_vnode* vnode = link->private_node;
+
+ int rc = VbglR0SfReadLink(&g_clientHandle, &volume->map, vnode->path, *_bufferSize, buffer);
+ *_bufferSize = strlen(buffer);
+
+ return vbox_err_to_haiku_err(rc);
+}
+
+
+/** @todo move this into the runtime */
+status_t vbox_err_to_haiku_err(int rc)
+{
+ switch (rc)
+ {
+ case VINF_SUCCESS: return B_OK;
+ case VERR_INVALID_POINTER: return B_BAD_ADDRESS;
+ case VERR_INVALID_PARAMETER: return B_BAD_VALUE;
+ case VERR_PERMISSION_DENIED: return B_PERMISSION_DENIED;
+ case VERR_NOT_IMPLEMENTED: return B_UNSUPPORTED;
+ case VERR_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND;
+
+ case SHFL_PATH_NOT_FOUND:
+ case SHFL_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND;
+ case SHFL_FILE_EXISTS: return B_FILE_EXISTS;
+
+ default:
+ return B_ERROR;
+ }
+}
+
+
+static status_t std_ops(int32 op, ...)
+{
+ switch(op)
+ {
+ case B_MODULE_INIT:
+ dprintf(MODULE_NAME ": B_MODULE_INIT\n");
+ return init_module();
+ case B_MODULE_UNINIT:
+ dprintf(MODULE_NAME ": B_MODULE_UNINIT\n");
+ uninit_module();
+ return B_OK;
+ default:
+ return B_ERROR;
+ }
+}
+
+
+static fs_volume_ops vboxsf_volume_ops =
+{
+ unmount,
+ vboxsf_read_fs_info,
+ NULL, /* write_fs_info */
+ NULL, /* sync */
+ vboxsf_get_vnode,
+ NULL, /* open_index_dir */
+ NULL, /* close_index_dir */
+ NULL, /* free_index_dir_cookie */
+ NULL, /* read_index_dir */
+ NULL, /* rewind_index_dir */
+ NULL, /* create_index */
+ NULL, /* remove_index */
+ NULL, /* read_index_stat */
+ NULL, /* open_query */
+ NULL, /* close_query */
+ NULL, /* free_query_cookie */
+ NULL, /* read_query */
+ NULL, /* rewind_query */
+ NULL, /* all_layers_mounted */
+ NULL, /* create_sub_vnode */
+ NULL, /* delete_sub_vnode */
+};
+
+static fs_vnode_ops vboxsf_vnode_ops =
+{
+ vboxsf_lookup,
+ NULL, /* get_vnode_name */
+ vboxsf_put_vnode,
+ NULL, /* remove_vnode */
+ NULL, /* can_page */
+ NULL, /* read_pages */
+ NULL, /* write_pages */
+ NULL, /* io */
+ NULL, /* cancel_io */
+ NULL, /* get_file_map */
+ NULL, /* ioctl */
+ NULL, /* set_flags */
+ NULL, /* select */
+ NULL, /* deselect */
+ NULL, /* fsync */
+ vboxsf_read_symlink,
+ vboxsf_create_symlink,
+ vboxsf_link,
+ vboxsf_unlink,
+ vboxsf_rename,
+ NULL, /* access */
+ vboxsf_read_stat,
+ vboxsf_write_stat,
+ NULL, /* preallocate */
+ vboxsf_create,
+ vboxsf_open,
+ vboxsf_close,
+ vboxsf_free_cookie,
+ vboxsf_read,
+ vboxsf_write,
+ vboxsf_create_dir,
+ vboxsf_remove_dir,
+ vboxsf_open_dir,
+ vboxsf_close_dir,
+ vboxsf_free_dir_cookie,
+ vboxsf_read_dir,
+ vboxsf_rewind_dir,
+ NULL, /* open_attr_dir */
+ NULL, /* close_attr_dir */
+ NULL, /* free_attr_dir_cookie */
+ NULL, /* read_attr_dir */
+ NULL, /* rewind_attr_dir */
+ NULL, /* create_attr */
+ NULL, /* open_attr */
+ NULL, /* close_attr */
+ NULL, /* free_attr_cookie */
+ NULL, /* read_attr */
+ NULL, /* write_attr */
+ NULL, /* read_attr_stat */
+ NULL, /* write_attr_stat */
+ NULL, /* rename_attr */
+ NULL, /* remove_attr */
+ NULL, /* create_special_node */
+ NULL, /* get_super_vnode */
+};
+
+static file_system_module_info sVBoxSharedFileSystem =
+{
+ {
+ MODULE_NAME B_CURRENT_FS_API_VERSION,
+ 0,
+ std_ops,
+ },
+ FS_NAME,
+ FS_PRETTY_NAME,
+ 0, /* DDM flags */
+ NULL, /* identify_partition */
+ NULL, /* scan_partition */
+ NULL, /* free_identify_partition_cookie */
+ NULL, /* free_partition_content_cookie */
+ mount,
+};
+
+module_info *modules[] =
+{
+ (module_info *)&sVBoxSharedFileSystem,
+ NULL,
+};
+
diff --git a/src/VBox/Additions/haiku/SharedFolders/vboxsf.h b/src/VBox/Additions/haiku/SharedFolders/vboxsf.h
new file mode 100644
index 00000000..d8449987
--- /dev/null
+++ b/src/VBox/Additions/haiku/SharedFolders/vboxsf.h
@@ -0,0 +1,120 @@
+/* $Id: vboxsf.h $ */
+/** @file
+ * Shared folders - Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h
+#define GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <malloc.h>
+#include <dirent.h>
+#include <fs_info.h>
+#include <sys/stat.h>
+#include <fs_interface.h>
+#include <KernelExport.h>
+#include <VBoxGuest-haiku.h>
+#include <VBox/VBoxGuestLibSharedFolders.h>
+#include "lock.h"
+
+typedef struct vboxsf_volume
+{
+ VBGLSFMAP map;
+ ino_t rootid;
+} vboxsf_volume;
+
+typedef struct vboxsf_vnode
+{
+ PVBGLSFMAP map;
+ PSHFLSTRING name;
+ PSHFLSTRING path;
+ ino_t vnode;
+ struct vboxsf_vnode* next;
+} vboxsf_vnode;
+
+typedef struct vboxsf_dir_cookie
+{
+ SHFLHANDLE handle;
+ PSHFLSTRING path;
+ uint32_t index;
+ bool has_more_files;
+ PSHFLDIRINFO buffer_start, buffer;
+ uint32_t buffer_length, num_files;
+} vboxsf_dir_cookie;
+
+typedef struct vboxsf_file_cookie
+{
+ SHFLHANDLE handle;
+ PSHFLSTRING path;
+} vboxsf_file_cookie;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+status_t vboxsf_new_vnode(PVBGLSFMAP map, PSHFLSTRING path, PSHFLSTRING name, vboxsf_vnode** p);
+status_t vboxsf_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter);
+status_t vboxsf_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter);
+PSHFLSTRING make_shflstring(const char* const s);
+mode_t mode_from_fmode(RTFMODE fMode);
+status_t vbox_err_to_haiku_err(int rc);
+extern mutex g_vnodeCacheLock;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h */
+
diff --git a/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp b/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp
new file mode 100644
index 00000000..05221606
--- /dev/null
+++ b/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp
@@ -0,0 +1,144 @@
+/* $Id: vnode_cache.cpp $ */
+/** @file
+ * Shared folders - Haiku Guest Additions, vnode cache header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "vboxsf.h"
+#include "OpenHashTable.h"
+
+struct HashTableDefinition
+{
+ typedef uint32 KeyType;
+ typedef vboxsf_vnode ValueType;
+
+ size_t HashKey(uint32 key) const
+ {
+ return key;
+ }
+
+ size_t Hash(vboxsf_vnode* value) const
+ {
+ return HashKey(value->vnode);
+ }
+
+ bool Compare(uint32 key, vboxsf_vnode* value) const
+ {
+ return value->vnode == key;
+ }
+
+ vboxsf_vnode*& GetLink(vboxsf_vnode* value) const
+ {
+ return value->next;
+ }
+};
+
+static BOpenHashTable<HashTableDefinition> g_cache;
+static ino_t g_nextVnid = 1;
+mutex g_vnodeCacheLock;
+
+
+extern "C" status_t vboxsf_new_vnode(PVBSFMAP map, PSHFLSTRING path, PSHFLSTRING name, vboxsf_vnode** p)
+{
+ vboxsf_vnode* vn = (vboxsf_vnode*)malloc(sizeof(vboxsf_vnode));
+ if (vn == NULL)
+ return B_NO_MEMORY;
+
+ dprintf("creating new vnode at %p with path=%p (%s)\n", vn, path->String.utf8, path->String.utf8);
+ vn->map = map;
+ vn->path = path;
+ if (name)
+ vn->name = name;
+ else
+ {
+ const char* cname = strrchr((char*)path->String.utf8, '/');
+ if (!cname)
+ vn->name = path; // no slash, assume this *is* the filename
+ else
+ vn->name = make_shflstring(cname);
+ }
+
+ if (mutex_lock(&g_vnodeCacheLock) < B_OK)
+ {
+ free(vn);
+ return B_ERROR;
+ }
+
+ vn->vnode = g_nextVnid++;
+ *p = vn;
+ dprintf("vboxsf: allocated %p (path=%p name=%p)\n", vn, vn->path, vn->name);
+ status_t rv = g_cache.Insert(vn);
+
+ mutex_unlock(&g_vnodeCacheLock);
+
+ return rv;
+}
+
+
+extern "C" status_t vboxsf_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode,
+ int* _type, uint32* _flags, bool reenter)
+{
+ vboxsf_vnode* vn = g_cache.Lookup(id);
+ if (vn)
+ {
+ vnode->private_node = vn;
+ return B_OK;
+ }
+ return B_ERROR;
+}
+
+
+extern "C" status_t vboxsf_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
+{
+ g_cache.Remove((vboxsf_vnode*)vnode->private_node);
+}
+
diff --git a/src/VBox/Additions/haiku/VBoxMouse/Makefile.kmk b/src/VBox/Additions/haiku/VBoxMouse/Makefile.kmk
new file mode 100644
index 00000000..f8089e11
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxMouse/Makefile.kmk
@@ -0,0 +1,90 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for VBoxMouse, Haiku Additions.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+#
+# This code is based on:
+#
+# VirtualBox Guest Additions for Haiku.
+# Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+# François Revol <revol@free.fr>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# @todo split the mouse code to communicate with VBoxMouse/VBoxService
+# to allow building with gcc2.
+# R1 will need gcc2-built input_server add-ons.
+
+PROGRAMS += VBoxMouse
+VBoxMouse_TEMPLATE = VBoxGuestR3Exe
+VBoxMouse_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR
+VBoxMouse_DEFS += LOG_ENABLED
+VBoxMouse_INCS = ../include
+VBoxMouse_SOURCES = \
+ VBoxMouse.cpp
+
+VBoxMouse_LIBS = \
+ be \
+ device \
+ $(VBOX_LIB_IPRT_GUEST_R3) \
+ $(VBOX_LIB_VBGL_R3) \
+ /system/servers/input_server
+
+PROGRAMS += VBoxMouseFilter
+VBoxMouseFilter_TEMPLATE = VBoxGuestR3Exe
+VBoxMouseFilter_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR
+VBoxMouseFilter_DEFS += LOG_ENABLED
+VBoxMouseFilter_INCS = ../include
+VBoxMouseFilter_SOURCES = \
+ VBoxMouseFilter.cpp
+
+VBoxMouseFilter_LIBS = $(VBoxMouse_LIBS)
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.cpp b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.cpp
new file mode 100644
index 00000000..50261a45
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.cpp
@@ -0,0 +1,318 @@
+/* $Id: VBoxMouse.cpp $ */
+/** @file
+ * VBoxMouse; input_server add-on - Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <Clipboard.h>
+#include <Debug.h>
+#include <Message.h>
+#include <String.h>
+
+#include "VBoxMouse.h"
+#include <VBox/VBoxGuest.h> /** @todo use the VbglR3 interface! */
+#include <VBox/VBoxGuestLib.h>
+#include <VBoxGuestInternal.h>
+#include <VBox/VMMDev.h>
+#include <VBox/log.h>
+#include <iprt/errcore.h>
+
+/* Export as global symbol with C linkage, RTDECL is necessary. */
+RTDECL(BInputServerDevice *)
+instantiate_input_device()
+{
+ return new VBoxMouse();
+}
+
+
+static inline int vboxMouseAcquire()
+{
+ uint32_t fFeatures = 0;
+ int rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3SetMouseStatus(fFeatures | VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL);
+ if (RT_FAILURE(rc))
+ LogRel(("VbglR3SetMouseStatus failed. rc=%d\n", rc));
+ }
+ else
+ LogRel(("VbglR3GetMouseStatus failed. rc=%d\n", rc));
+ return rc;
+}
+
+
+static inline int vboxMouseRelease()
+{
+ uint32_t fFeatures = 0;
+ int rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3SetMouseStatus(fFeatures & ~VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE & ~VMMDEV_MOUSE_NEW_PROTOCOL);
+ if (RT_FAILURE(rc))
+ LogRel(("VbglR3SetMouseStatus failed. rc=%d\n", rc));
+ }
+ else
+ LogRel(("VbglR3GetMouseStatus failed. rc=%d\n", rc));
+ return rc;
+}
+
+
+VBoxMouse::VBoxMouse()
+ : BInputServerDevice(),
+ fDriverFD(-1),
+ fServiceThreadID(-1),
+ fExiting(false)
+{
+}
+
+
+VBoxMouse::~VBoxMouse()
+{
+}
+
+
+status_t VBoxMouse::InitCheck()
+{
+ int rc = VbglR3Init();
+ if (!RT_SUCCESS(rc))
+ return ENXIO;
+
+ input_device_ref device = { (char *)"VBoxMouse", B_POINTING_DEVICE, (void *)this };
+ input_device_ref *deviceList[2] = { &device, NULL };
+ RegisterDevices(deviceList);
+
+ return B_OK;
+}
+
+
+status_t VBoxMouse::SystemShuttingDown()
+{
+ VbglR3Term();
+
+ return B_OK;
+}
+
+
+status_t VBoxMouse::Start(const char *device, void *cookie)
+{
+#if 0
+ status_t err;
+ int rc;
+ uint32_t fFeatures = 0;
+ Log(("VBoxMouse::%s()\n", __FUNCTION__));
+
+ rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ rc = VbglR3SetMouseStatus(fFeatures
+ | VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
+ | VMMDEV_MOUSE_NEW_PROTOCOL);
+ if (!RT_SUCCESS(rc))
+ {
+ LogRel(("VBoxMouse: Error switching guest mouse into absolute mode: %d\n", rc));
+ return B_DEVICE_NOT_FOUND;
+ }
+
+ err = fServiceThreadID = spawn_thread(_ServiceThreadNub,
+ "VBoxMouse", B_NORMAL_PRIORITY, this);
+ if (err >= B_OK)
+ {
+ resume_thread(fServiceThreadID);
+ return B_OK;
+ }
+ else
+ LogRel(("VBoxMouse: Error starting service thread: 0x%08lx\n",
+ err));
+
+ // release the mouse
+ rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ rc = VbglR3SetMouseStatus(fFeatures
+ & ~VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
+ & ~VMMDEV_MOUSE_NEW_PROTOCOL);
+
+ return B_ERROR;
+#endif
+
+ status_t err = B_OK;
+ int rc;
+ uint32_t fFeatures = 0;
+ LogFlowFunc(("device=%s cookie=%p\n", device, cookie));
+
+ rc = vboxMouseAcquire();
+ if (RT_SUCCESS(rc))
+ {
+ err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxMouse", B_NORMAL_PRIORITY, this);
+ if (err >= B_OK)
+ {
+ resume_thread(fServiceThreadID);
+ return B_OK;
+ }
+ else
+ LogRel(("VBoxMouse::Start Error starting service thread: 0x%08lx\n", err));
+
+ vboxMouseRelease();
+ err = B_ERROR;
+ }
+ else
+ {
+ LogRel(("VBoxMouse::Start vboxMouseAcquire failed. rc=%d\n", rc));
+ err = B_DEVICE_NOT_FOUND;
+ }
+
+ return err;
+}
+
+
+status_t VBoxMouse::Stop(const char *device, void *cookie)
+{
+ status_t status;
+ int rc;
+ uint32_t fFeatures = 0;
+ Log(("VBoxMouse::%s()\n", __FUNCTION__));
+
+ fExiting = true;
+
+ vboxMouseRelease();
+
+ close(fDriverFD);
+ fDriverFD = -1;
+ //XXX WTF ?
+ suspend_thread(fServiceThreadID);
+ resume_thread(fServiceThreadID);
+ wait_for_thread(fServiceThreadID, &status);
+ fServiceThreadID = -1;
+ fExiting = false;
+ return B_OK;
+}
+
+
+status_t VBoxMouse::Control(const char *device, void *cookie, uint32 code, BMessage *message)
+{
+ switch (code)
+ {
+ case B_MOUSE_SPEED_CHANGED:
+ case B_CLICK_SPEED_CHANGED:
+ case B_MOUSE_ACCELERATION_CHANGED:
+ default:
+ return BInputServerDevice::Control(device, cookie, code, message);
+ }
+ return B_OK;
+}
+
+
+status_t VBoxMouse::_ServiceThreadNub(void *_this)
+{
+ VBoxMouse *service = (VBoxMouse *)_this;
+ return service->_ServiceThread();
+}
+
+
+status_t VBoxMouse::_ServiceThread()
+{
+ Log(("VBoxMouse::%s()\n", __FUNCTION__));
+
+ fDriverFD = open(VBOXGUEST_DEVICE_NAME, O_RDWR);
+ if (fDriverFD < 0)
+ return ENXIO;
+
+ /* The thread waits for incoming messages from the host. */
+ while (!fExiting)
+ {
+ uint32_t cx, cy, fFeatures;
+ int rc;
+
+ fd_set readSet, writeSet, errorSet;
+ FD_ZERO(&readSet);
+ FD_ZERO(&writeSet);
+ FD_ZERO(&errorSet);
+ FD_SET(fDriverFD, &readSet);
+ if (fDriverFD < 0)
+ break;
+ rc = select(fDriverFD + 1, &readSet, &writeSet, &errorSet, NULL);
+ if (rc < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ break;
+ }
+
+ rc = VbglR3GetMouseStatus(&fFeatures, &cx, &cy);
+ if ( RT_SUCCESS(rc)
+ && (fFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE))
+ {
+ float x = cx * 1.0 / 65535;
+ float y = cy * 1.0 / 65535;
+
+ _debugPrintf("VBoxMouse: at %d,%d %f,%f\n", cx, cy, x, y);
+
+ /* Send absolute movement */
+ bigtime_t now = system_time();
+ BMessage *event = new BMessage(B_MOUSE_MOVED);
+ event->AddInt64("when", now);
+ event->AddFloat("x", x);
+ event->AddFloat("y", y);
+ event->AddFloat("be:tablet_x", x);
+ event->AddFloat("be:tablet_y", y);
+ //event->PrintToStream();
+ EnqueueMessage(event);
+
+ //LogRelFlow(("processed host event rc = %d\n", rc));
+ }
+ }
+ return 0;
+}
+
diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.h b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.h
new file mode 100644
index 00000000..69a62b8a
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.h
@@ -0,0 +1,91 @@
+/* $Id: VBoxMouse.h $ */
+/** @file
+ * VBoxMouse; input_server add-on - Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouse_h
+#define GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouse_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <InputServerDevice.h>
+
+extern "C" _EXPORT BInputServerDevice* instantiate_input_device();
+
+class VBoxMouse : public BInputServerDevice
+{
+ public:
+ VBoxMouse();
+ virtual ~VBoxMouse();
+
+ virtual status_t InitCheck();
+ virtual status_t SystemShuttingDown();
+
+ virtual status_t Start(const char *device, void *cookie);
+ virtual status_t Stop(const char *device, void *cookie);
+ virtual status_t Control(const char *device, void *cookie, uint32 code, BMessage *message);
+
+ private:
+
+ static status_t _ServiceThreadNub(void *_this);
+ status_t _ServiceThread();
+
+ int fDriverFD;
+ thread_id fServiceThreadID;
+ bool fExiting;
+};
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouse_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.cpp b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.cpp
new file mode 100644
index 00000000..5f0158ba
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.cpp
@@ -0,0 +1,117 @@
+/* $Id: VBoxMouseFilter.cpp $ */
+/** @file
+ * VBoxMouse; input_server filter - Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <Clipboard.h>
+#include <Debug.h>
+#include <Message.h>
+#include <String.h>
+
+#include "VBoxMouseFilter.h"
+#include <VBox/VBoxGuestLib.h>
+#include <VBoxGuestInternal.h>
+#include <VBox/log.h>
+#include <iprt/errcore.h>
+
+/** @todo can this be merged with VBoxMouse? */
+
+RTDECL(BInputServerFilter *)
+instantiate_input_filter()
+{
+ return new VBoxMouseFilter();
+}
+
+VBoxMouseFilter::VBoxMouseFilter()
+ : BInputServerFilter(),
+ fDriverFD(-1),
+ fServiceThreadID(-1),
+ fExiting(false),
+ fCurrentButtons(0)
+{
+}
+
+
+VBoxMouseFilter::~VBoxMouseFilter()
+{
+}
+
+
+filter_result VBoxMouseFilter::Filter(BMessage *message, BList *outList)
+{
+ switch (message->what)
+ {
+ case B_MOUSE_UP:
+ case B_MOUSE_DOWN:
+ {
+ printf("click|release\n");
+ message->FindInt32("buttons", &fCurrentButtons);
+ /** @todo r=ramshankar this looks wrong, no 'break' here? */
+ }
+
+ case B_MOUSE_MOVED:
+ {
+ printf("mouse moved\n");
+ message->ReplaceInt32("buttons", fCurrentButtons);
+ /** @todo r=ramshankar: 'break' or explicit comment please. */
+ }
+ }
+
+ return B_DISPATCH_MESSAGE;
+}
+
diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.h b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.h
new file mode 100644
index 00000000..64996a2f
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.h
@@ -0,0 +1,87 @@
+/* $Id: VBoxMouseFilter.h $ */
+/** @file
+ * VBoxMouse; input_server filter - Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouseFilter_h
+#define GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouseFilter_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <InputServerFilter.h>
+
+extern "C" _EXPORT BInputServerFilter* instantiate_input_filter();
+
+class VBoxMouseFilter : public BInputServerFilter
+{
+ public:
+ VBoxMouseFilter();
+ virtual ~VBoxMouseFilter();
+
+ virtual filter_result Filter(BMessage* message, BList* outList);
+
+ private:
+ static status_t _ServiceThreadNub(void *_this);
+ status_t _ServiceThread();
+
+ int fDriverFD;
+ thread_id fServiceThreadID;
+ bool fExiting;
+ bool fEnabled;
+ int32 fCurrentButtons;
+};
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouseFilter_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/Makefile.kmk b/src/VBox/Additions/haiku/VBoxTray/Makefile.kmk
new file mode 100644
index 00000000..96d6c52e
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/Makefile.kmk
@@ -0,0 +1,128 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for VBoxTray, Haiku Guest Additions.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+#
+# This code is based on:
+#
+# VirtualBox Guest Additions for Haiku.
+# Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+# François Revol <revol@free.fr>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# @todo split the tray code,
+# single bin will cause problems loading gcc4 binary from a gcc2-built Deskbar!
+
+PROGRAMS += VBoxTray
+VBoxTray_TEMPLATE = VBoxGuestR3Exe
+VBoxTray_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR
+VBoxTray_DEFS += LOG_ENABLED
+VBoxTray_INCS = ../include
+VBoxTray_SOURCES = \
+ VBoxClipboard.cpp \
+ VBoxDisplay.cpp \
+ VBoxGuestApplication.cpp \
+ VBoxGuestDeskbarView.cpp
+
+VBoxTray_SOURCES += \
+ $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
+
+VBoxTray_LIBS = \
+ be translation \
+ $(VBOX_LIB_VBGL_R3) \
+ $(VBOX_LIB_IPRT_GUEST_R3) \
+ $(VBOX_LIB_VBGL_R3)
+
+VBoxTray_RSRCS += $(VBoxTray_0_OUTDIR)/VBoxTray.rsrc
+VBoxTray_DEPS += $(VBoxTray_0_OUTDIR)/VBoxTray.rsrc
+VBoxTray_CLEAN += $(VBoxTray_0_OUTDIR)/VBoxTray.rsrc
+
+# VBoxGuestApplication.cpp uses VBOX_SVN_REV.
+VBoxGuestApplication.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
+VBoxGuestApplication.cpp_DEPS = $(VBOX_SVN_REV_KMK)
+VBoxGuestDeskbarView.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
+VBoxGuestDeskbarView.cpp_DEPS = $(VBOX_SVN_REV_KMK)
+
+## The icon location is configurable.
+VBoxTray.rdef_INCS = $(VBoxTray_0_OUTDIR)
+VBoxTray.rdef_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) \
+ VBOX_HAIKU_DESKBAR_ICON_PNG=\"$(VBOX_BRAND_GUI_VBOX_16PX_PNG)\"
+VBoxTray.rdef_DEPS = $(VBOX_SVN_REV_KMK)
+
+VBoxTray.rsrc_DEPS = VBoxTray.rdef
+VBoxTray.rsrc_CLEAN = VBoxTray.rdef
+
+
+
+#XXX: cleanup!
+#XXX: handle deps correctly
+#XXX: -I / is due to a bug in rc with absolute paths
+## Resource file.
+$$(VBoxTray_0_OUTDIR)/VBoxTray.rsrc: $$(VBoxTray_DEFPATH)/VBoxTray.rdef $$(VBoxTray_DEFPATH)/Makefile.kmk | $$(dir $$@)
+ $(call MSG_TOOL,$(VBOX_HAIKU_RCTOOL),HaikuResources,$<,$@)
+ $(QUIET)cat $< | gcc -E -I $(dir $<) -I $(dir $<)/../include $(foreach name, $(INCS), -I $(name)) $(foreach dname, $(VBoxTray.rdef_DEFS), -D$(dname)) - | grep -v '^#' | $(VBOX_HAIKU_RCTOOL) -I / -I $(dir $<) -I $(dir $<)/../include -o "$@" -
+
+
+# rc -I $(VBoxTray_DEFPATH)/../include -o $@ $<
+# $(RM) -f $@
+# $(APPEND) $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))"'
+
+## The icon location is configurable.
+#VBoxTray.rc_INCS = $(VBoxTray_0_OUTDIR)
+#VBoxTray.rc_DEPS = $(VBoxTray_0_OUTDIR)/VBoxTray-icon.rc
+#VBoxTray.rc_CLEAN = $(VBoxTray_0_OUTDIR)/VBoxTray-icon.rc
+
+## Icon include file.
+#$$(VBoxTray_0_OUTDIR)/VBoxTray-icon.rc: $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) $$(VBoxTray_DEFPATH)/Makefile.kmk | $$(dir $$@)
+# $(RM) -f $@
+# $(APPEND) $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))"'
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp
new file mode 100644
index 00000000..b500b95d
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp
@@ -0,0 +1,468 @@
+/* $Id: VBoxClipboard.cpp $ */
+/** @file
+ * VBoxClipboard; Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * Fran�ois Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <new>
+#include <Bitmap.h>
+#include <BitmapStream.h>
+#include <Clipboard.h>
+#include <DataIO.h>
+#include <Message.h>
+#include <TranslationUtils.h>
+#include <TranslatorFormats.h>
+#include <TranslatorRoster.h>
+#include <String.h>
+
+#include "VBoxGuestApplication.h"
+#include "VBoxClipboard.h"
+#include <VBoxGuestInternal.h>
+
+#include <iprt/mem.h>
+#include <VBox/GuestHost/clipboard-helper.h>
+#include <VBox/HostServices/VBoxClipboardSvc.h>
+#include <VBox/log.h>
+
+/** @todo r=ramshankar: this hack should go eventually. */
+#ifdef DEBUG_ramshankar
+# undef Log
+# define Log(x) printf x
+# undef LogRel
+# define LogRel(x) printf x
+# undef LogRelFlowFunc
+# define LogRelFlowFunc(x) printf x
+#endif
+
+
+VBoxShClService::VBoxShClService()
+ : BHandler("VBoxShClService"),
+ fClientId(-1),
+ fServiceThreadID(-1),
+ fExiting(false)
+{
+}
+
+
+VBoxShClService::~VBoxShClService()
+{
+}
+
+
+status_t VBoxShClService::Connect()
+{
+ status_t err;
+ LogFlowFunc(("Connect\n"));
+
+ int rc = VbglR3ClipboardConnect(&fClientId);
+ if (RT_SUCCESS(rc))
+ {
+ err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxShClService", B_NORMAL_PRIORITY, this);
+ if (err >= B_OK)
+ {
+ resume_thread(fServiceThreadID);
+ err = be_clipboard->StartWatching(BMessenger(this));
+ LogFlow(("be_clipboard->StartWatching: %ld\n", err));
+ if (err == B_OK)
+ return B_OK;
+ else
+ LogRel(("VBoxShClService: Error watching the system clipboard: %ld\n", err));
+ }
+ else
+ LogRel(("VBoxShClService: Error starting service thread: %ld\n", err));
+
+ //rc = RTErrConvertFromErrno(err);
+ VbglR3ClipboardDisconnect(fClientId);
+ }
+ else
+ LogRel(("VBoxShClService: Error starting service thread: %d\n", rc));
+ return B_ERROR;
+}
+
+
+status_t VBoxShClService::Disconnect()
+{
+ status_t status;
+
+ be_clipboard->StopWatching(BMessenger(this));
+
+ fExiting = true;
+
+ VbglR3ClipboardDisconnect(fClientId);
+
+ wait_for_thread(fServiceThreadID, &status);
+ return B_OK;
+}
+
+
+void VBoxShClService::MessageReceived(BMessage *message)
+{
+ uint32_t formats = 0;
+ message->PrintToStream();
+ switch (message->what)
+ {
+ case VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS:
+ {
+ int rc;
+ uint32_t cb;
+ void *pv;
+ bool commit = false;
+
+ if (message->FindInt32("Formats", (int32 *)&formats) != B_OK)
+ break;
+
+ if (!formats)
+ break;
+
+ if (!be_clipboard->Lock())
+ break;
+
+ be_clipboard->Clear();
+ BMessage *clip = be_clipboard->Data();
+ if (!clip)
+ {
+ be_clipboard->Unlock();
+ break;
+ }
+
+ if (formats & VBOX_SHCL_FMT_UNICODETEXT)
+ {
+ pv = _VBoxReadHostClipboard(VBOX_SHCL_FMT_UNICODETEXT, &cb);
+ if (pv)
+ {
+ char *text;
+ rc = RTUtf16ToUtf8((PCRTUTF16)pv, &text);
+ if (RT_SUCCESS(rc))
+ {
+ BString str(text);
+ /** @todo user vboxClipboardUtf16WinToLin() */
+ // convert Windows CRLF to LF
+ str.ReplaceAll("\r\n", "\n");
+ // don't include the \0
+ clip->AddData("text/plain", B_MIME_TYPE, str.String(), str.Length());
+ RTStrFree(text);
+ commit = true;
+ }
+ free(pv);
+ }
+ }
+
+ if (formats & VBOX_SHCL_FMT_BITMAP)
+ {
+ pv = _VBoxReadHostClipboard(VBOX_SHCL_FMT_BITMAP, &cb);
+ if (pv)
+ {
+ void *pBmp = NULL;
+ size_t cbBmp = 0;
+ rc = ShClDibToBmp(pv, cb, &pBmp, &cbBmp);
+ if (RT_SUCCESS(rc))
+ {
+ BMemoryIO mio(pBmp, cbBmp);
+ BBitmap *bitmap = BTranslationUtils::GetBitmap(&mio);
+ if (bitmap)
+ {
+ BMessage bitmapArchive;
+
+ /** @todo r=ramshankar: split this into functions with error checking as
+ * neccessary. */
+ if ( bitmap->IsValid()
+ && bitmap->Archive(&bitmapArchive) == B_OK
+ && clip->AddMessage("image/bitmap", &bitmapArchive) == B_OK)
+ {
+ commit = true;
+ }
+ delete bitmap;
+ }
+ RTMemFree(pBmp);
+ }
+ free(pv);
+ }
+ }
+
+ /*
+ * Make sure we don't bounce this data back to the host, it's impolite. It can also
+ * be used as a hint to applications probably.
+ */
+ clip->AddBool("FromVirtualBoxHost", true);
+ if (commit)
+ be_clipboard->Commit();
+ be_clipboard->Unlock();
+ break;
+ }
+
+ case VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA:
+ {
+ int rc;
+
+ if (message->FindInt32("Formats", (int32 *)&formats) != B_OK)
+ break;
+
+ if (!formats)
+ break;
+ if (!be_clipboard->Lock())
+ break;
+
+ BMessage *clip = be_clipboard->Data();
+ if (!clip)
+ {
+ be_clipboard->Unlock();
+ break;
+ }
+ clip->PrintToStream();
+
+ if (formats & VBOX_SHCL_FMT_UNICODETEXT)
+ {
+ const char *text;
+ int32 textLen;
+ if (clip->FindData("text/plain", B_MIME_TYPE, (const void **)&text, &textLen) == B_OK)
+ {
+ // usually doesn't include the \0 so be safe
+ BString str(text, textLen);
+ // convert from LF to Windows CRLF
+ str.ReplaceAll("\n", "\r\n");
+ PRTUTF16 pwsz;
+ rc = RTStrToUtf16(str.String(), &pwsz);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t cb = (RTUtf16Len(pwsz) + 1) * sizeof(RTUTF16);
+
+ rc = VbglR3ClipboardWriteData(fClientId, VBOX_SHCL_FMT_UNICODETEXT, pwsz, cb);
+ //printf("VbglR3ClipboardWriteData: %d\n", rc);
+ RTUtf16Free(pwsz);
+ }
+ }
+ }
+ else if (formats & VBOX_SHCL_FMT_BITMAP)
+ {
+ BMessage archivedBitmap;
+ if (clip->FindMessage("image/bitmap", &archivedBitmap) == B_OK ||
+ clip->FindMessage("image/x-be-bitmap", &archivedBitmap) == B_OK)
+ {
+ BBitmap *bitmap = new(std::nothrow) BBitmap(&archivedBitmap);
+ if (bitmap)
+ {
+ // Don't delete bitmap, BBitmapStream will.
+ BBitmapStream stream(bitmap);
+ BTranslatorRoster *roster = BTranslatorRoster::Default();
+ if (roster && bitmap->IsValid())
+ {
+ BMallocIO bmpStream;
+ if (roster->Translate(&stream, NULL, NULL, &bmpStream, B_BMP_FORMAT) == B_OK)
+ {
+ const void *pDib;
+ size_t cbDibSize;
+ /* Strip out the BM header */
+ rc = ShClBmpGetDib(bmpStream.Buffer(), bmpStream.BufferLength(), &pDib, &cbDibSize);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3ClipboardWriteData(fClientId, VBOX_SHCL_FMT_BITMAP, (void *)pDib,
+ cbDibSize);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ be_clipboard->Unlock();
+ break;
+ }
+
+ case B_CLIPBOARD_CHANGED:
+ {
+ printf("B_CLIPBOARD_CHANGED\n");
+ const void *data;
+ int32 dataLen;
+ if (!be_clipboard->Lock())
+ break;
+
+ BMessage *clip = be_clipboard->Data();
+ if (!clip)
+ {
+ be_clipboard->Unlock();
+ break;
+ }
+
+ bool fromVBox;
+ if (clip->FindBool("FromVirtualBoxHost", &fromVBox) == B_OK && fromVBox)
+ {
+ // It already comes from the host, discard.
+ be_clipboard->Unlock();
+ break;
+ }
+
+ if (clip->FindData("text/plain", B_MIME_TYPE, &data, &dataLen) == B_OK)
+ formats |= VBOX_SHCL_FMT_UNICODETEXT;
+
+ if ( clip->HasMessage("image/bitmap")
+ || clip->HasMessage("image/x-be-bitmap"))
+ {
+ formats |= VBOX_SHCL_FMT_BITMAP;
+ }
+
+ be_clipboard->Unlock();
+
+ VbglR3ClipboardReportFormats(fClientId, formats);
+ break;
+ }
+
+ case B_QUIT_REQUESTED:
+ fExiting = true;
+ break;
+
+ default:
+ BHandler::MessageReceived(message);
+ }
+}
+
+
+status_t VBoxShClService::_ServiceThreadNub(void *_this)
+{
+ VBoxShClService *service = (VBoxShClService *)_this;
+ return service->_ServiceThread();
+}
+
+
+status_t VBoxShClService::_ServiceThread()
+{
+ printf("VBoxShClService::%s()\n", __FUNCTION__);
+
+ /* The thread waits for incoming messages from the host. */
+ for (;;)
+ {
+ uint32_t u32Msg;
+ uint32_t u32Formats;
+ int rc = VbglR3ClipboardGetHostMsgOld(fClientId, &u32Msg, &u32Formats);
+ if (RT_SUCCESS(rc))
+ {
+ switch (u32Msg)
+ {
+ case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
+ {
+ /*
+ * The host has announced available clipboard formats. Forward
+ * the information to the handler.
+ */
+ LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_REPORT_FORMATS u32Formats=%x\n", u32Formats));
+ BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS);
+ msg.AddInt32("Formats", (uint32)u32Formats);
+ Looper()->PostMessage(&msg, this);
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_READ_DATA:
+ {
+ /* The host needs data in the specified format. */
+ LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_READ_DATA u32Formats=%x\n", u32Formats));
+ BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA);
+ msg.AddInt32("Formats", (uint32)u32Formats);
+ Looper()->PostMessage(&msg, this);
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_QUIT:
+ {
+ /* The host is terminating. */
+ LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_QUIT\n"));
+ fExiting = true;
+ return VERR_INTERRUPTED;
+ }
+
+ default:
+ Log(("VBoxShClService::%s: Unsupported message from host! Message = %u\n", __FUNCTION__, u32Msg));
+ }
+ }
+ else
+ fExiting = true;
+
+ LogRelFlow(("processed host event rc = %d\n", rc));
+
+ if (fExiting)
+ break;
+ }
+ return 0;
+}
+
+
+void* VBoxShClService::_VBoxReadHostClipboard(uint32_t format, uint32_t *pcb)
+{
+ uint32_t cb = 1024;
+ void *pv;
+ int rc;
+
+ pv = malloc(cb);
+ if (pv == NULL)
+ return NULL;
+
+ rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb);
+ if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
+ return pv;
+ if (rc == VINF_BUFFER_OVERFLOW)
+ {
+ free(pv);
+ cb = *pcb;
+ pv = malloc(cb);
+ if (pv == NULL)
+ return NULL;
+
+ rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb);
+ if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
+ return pv;
+
+ free(pv);
+ }
+ return NULL;
+}
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.h b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.h
new file mode 100644
index 00000000..ad4cabbd
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.h
@@ -0,0 +1,88 @@
+/* $Id: VBoxClipboard.h $ */
+/** @file
+ * VBoxClipboard, Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxClipboard_h
+#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxClipboard_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <Handler.h>
+
+class VBoxShClService : public BHandler
+{
+ public:
+ VBoxShClService();
+ virtual ~VBoxShClService();
+
+ virtual status_t Connect();
+ virtual status_t Disconnect();
+
+ virtual void MessageReceived(BMessage *message);
+
+ private:
+ static status_t _ServiceThreadNub(void *_this);
+ status_t _ServiceThread();
+
+ void* _VBoxReadHostClipboard(uint32_t format, uint32_t *pcb);
+
+ uint32_t fClientId;
+ thread_id fServiceThreadID;
+ bool fExiting;
+};
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxClipboard_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.cpp
new file mode 100644
index 00000000..5eb0a7d5
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.cpp
@@ -0,0 +1,177 @@
+/* $Id: VBoxDisplay.cpp $ */
+/** @file
+ * VBoxDisplayService, Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <new>
+#include <DataIO.h>
+#include <Message.h>
+#include <TranslationUtils.h>
+#include <TranslatorFormats.h>
+#include <TranslatorRoster.h>
+#include <String.h>
+
+#include "VBoxGuestApplication.h"
+#include "VBoxDisplay.h"
+#include <VBoxGuestInternal.h>
+#include "../VBoxVideo/common/VBoxVideo_common.h"
+
+#include <iprt/mem.h>
+#include <VBox/log.h>
+
+#ifdef DEBUG_ramshankar
+# undef Log
+# define Log(x) printf x
+# undef LogRel
+# define LogRel(x) printf x
+# undef LogRelFlowFunc
+# define LogRelFlowFunc(x) printf x
+#endif
+
+VBoxDisplayService::VBoxDisplayService()
+ : BHandler("VBoxDisplayService"),
+ fClientId(-1),
+ fServiceThreadID(-1),
+ fExiting(false),
+ fScreen(B_MAIN_SCREEN_ID)
+{
+}
+
+
+VBoxDisplayService::~VBoxDisplayService()
+{
+}
+
+
+void VBoxDisplayService::Start()
+{
+ status_t err;
+ err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxDisplayService", B_NORMAL_PRIORITY, this);
+ if (err >= B_OK)
+ resume_thread(fServiceThreadID);
+ else
+ LogRel(("VBoxDisplayService: Error starting service thread: %s\n", strerror(err)));
+}
+
+
+void VBoxDisplayService::MessageReceived(BMessage *message)
+{
+ if (message->what == B_QUIT_REQUESTED)
+ fExiting = true;
+ else
+ BHandler::MessageReceived(message);
+}
+
+
+status_t VBoxDisplayService::_ServiceThreadNub(void *_this)
+{
+ VBoxDisplayService *service = (VBoxDisplayService *)_this;
+ return service->_ServiceThread();
+}
+
+
+status_t VBoxDisplayService::_ServiceThread()
+{
+ LogFlow(("VBoxDisplayService::_ServiceThread"));
+
+ VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
+ VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0);
+ for (;;)
+ {
+ uint32_t events;
+ int rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 5000, &events);
+ if ( rc == VERR_TIMEOUT
+ || rc == VERR_INTERRUPTED)
+ continue;
+
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t cx, cy, cBits, iDisplay;
+ int rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay, NULL, NULL, NULL, NULL, true);
+ LogFlow(("rc2=%d screen %d size changed (%d, %d, %d)\n", rc2, iDisplay, cx, cy, cBits));
+
+ if (RT_SUCCESS(rc2))
+ {
+ display_mode mode;
+ fScreen.GetMode(&mode);
+ if (cBits == 0)
+ cBits = get_depth_for_color_space(mode.space);
+
+ mode.timing.h_display = cx;
+ mode.timing.v_display = cy;
+ mode.space = get_color_space_for_depth(cBits);
+ mode.virtual_width = cx;
+ mode.virtual_height = cy;
+
+ /*= {
+ {0, cx, 0, 0, cBits * cx / 8, cy, 0, 0, cBits * cy / 8, 0},
+ get_color_space_for_depth(cBits),
+ cx, cy, 0, 0, 0
+ };*/
+
+ fScreen.SetMode(&mode, false);
+ }
+ }
+ else
+ fExiting = true;
+
+ LogFlow(("processed host event rc = %d\n", rc));
+ if (fExiting)
+ break;
+ }
+ return 0;
+}
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.h b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.h
new file mode 100644
index 00000000..434cca51
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.h
@@ -0,0 +1,86 @@
+/* $Id: VBoxDisplay.h $ */
+/** @file
+ * VBoxDisplayService, Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxDisplay_h
+#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxDisplay_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <Handler.h>
+#include <Screen.h>
+
+class VBoxDisplayService : public BHandler
+{
+ public:
+ VBoxDisplayService();
+ virtual ~VBoxDisplayService();
+
+ void Start();
+ virtual void MessageReceived(BMessage *message);
+
+ private:
+ static status_t _ServiceThreadNub(void *_this);
+ status_t _ServiceThread();
+
+ uint32_t fClientId;
+ thread_id fServiceThreadID;
+ volatile bool fExiting;
+ BScreen fScreen;
+};
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxDisplay_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.cpp
new file mode 100644
index 00000000..c2c26762
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.cpp
@@ -0,0 +1,101 @@
+/* $Id: VBoxGuestApplication.cpp $ */
+/** @file
+ * VBoxGuestApplication, Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/log.h>
+
+#include <errno.h>
+#include <Alert.h>
+#include <Debug.h>
+#include <Invoker.h>
+#include <String.h>
+
+#include "VBoxClipboard.h"
+#include "VBoxGuestApplication.h"
+#include "VBoxGuestDeskbarView.h"
+
+VBoxGuestApplication::VBoxGuestApplication()
+ : BApplication(VBOX_GUEST_APP_SIG)
+{
+}
+
+
+VBoxGuestApplication::~VBoxGuestApplication()
+{
+}
+
+
+void VBoxGuestApplication::ReadyToRun()
+{
+ status_t err;
+
+ err = VBoxGuestDeskbarView::AddToDeskbar();
+ LogFlow(("VBoxGuestDeskbarView::ReadyToRun: AddToDeskbar returned 0x%08lx\n", err));
+ exit(0);
+}
+
+
+int main(int argc, const char **argv)
+{
+ new VBoxGuestApplication();
+ be_app->Run();
+ delete be_app;
+ return 0;
+}
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.h b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.h
new file mode 100644
index 00000000..d7996740
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.h
@@ -0,0 +1,89 @@
+/* $Id: VBoxGuestApplication.h $ */
+/** @file
+ * VBoxGuestApplication, Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestApplication_h
+#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestApplication_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+/** @todo r=ramshankar; why are we including all the headers here!?? Do it in
+ * the .cpp please. */
+#include <Application.h>
+
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+
+#include <VBox/version.h>
+#include <VBox/log.h>
+#include <VBox/VBoxGuest.h> /** @todo use the VbglR3 interface! */
+#include <VBox/VBoxGuestLib.h>
+
+#include <VBoxGuestInternal.h>
+
+class VBoxShClService;
+
+class VBoxGuestApplication : public BApplication
+{
+ public:
+ VBoxGuestApplication();
+ virtual ~VBoxGuestApplication();
+
+ virtual void ReadyToRun();
+};
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestApplication_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.cpp
new file mode 100644
index 00000000..aaba2392
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.cpp
@@ -0,0 +1,297 @@
+/* $Id: VBoxGuestDeskbarView.cpp $ */
+/** @file
+ * VBoxGuestDeskbarView, Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <errno.h>
+#include <Alert.h>
+#include <Roster.h>
+#include <Debug.h>
+#include <Deskbar.h>
+#include <File.h>
+#include <MenuItem.h>
+#include <Path.h>
+#include <PopUpMenu.h>
+#include <Resources.h>
+#include <String.h>
+#include <TranslationUtils.h>
+
+#include "VBoxGuestDeskbarView.h"
+#include "VBoxGuestApplication.h"
+
+#define VIEWNAME "VBoxGuestDeskbarView"
+
+static status_t
+our_image(image_info& image)
+{
+ /** @todo r=ramshankar: find a way to do this without annoying the compiler, probably uintptr_t? */
+ int32 cookie = 0;
+ while (get_next_image_info(B_CURRENT_TEAM, &cookie, &image) == B_OK)
+ {
+ if ((char *)our_image >= (char *)image.text
+ && (char *)our_image <= (char *)image.text + image.text_size)
+ return B_OK;
+ }
+
+ return B_ERROR;
+}
+
+
+VBoxGuestDeskbarView::VBoxGuestDeskbarView()
+ : BView(BRect(0, 0, 15, 15), VIEWNAME, B_FOLLOW_NONE,
+ B_WILL_DRAW | B_NAVIGABLE),
+ fIcon(NULL), fClipboardService(NULL), fDisplayService(NULL)
+{
+ _Init();
+}
+
+
+VBoxGuestDeskbarView::VBoxGuestDeskbarView(BMessage *archive)
+ : BView(archive),
+ fIcon(NULL)
+{
+ archive->PrintToStream();
+ _Init(archive);
+}
+
+
+VBoxGuestDeskbarView::~VBoxGuestDeskbarView()
+{
+ delete fIcon;
+ if (fClipboardService)
+ {
+ fClipboardService->Disconnect();
+ delete fClipboardService;
+ }
+ VbglR3Term();
+}
+
+
+BArchivable* VBoxGuestDeskbarView::Instantiate(BMessage *data)
+{
+ if (!validate_instantiation(data, VIEWNAME))
+ return NULL;
+
+ return new VBoxGuestDeskbarView(data);
+}
+
+
+status_t VBoxGuestDeskbarView::Archive(BMessage *data, bool deep) const
+{
+ status_t err;
+
+ err = BView::Archive(data, false);
+ if (err < B_OK)
+ {
+ LogRel(("VBoxGuestDeskbarView::Archive failed.rc=%08lx\n", err));
+ return err;
+ }
+ data->AddString("add_on", VBOX_GUEST_APP_SIG);
+ data->AddString("class", "VBoxGuestDeskbarView");
+ return B_OK;
+}
+
+
+void VBoxGuestDeskbarView::Draw(BRect rect)
+{
+ SetDrawingMode(B_OP_ALPHA);
+ DrawBitmap(fIcon);
+}
+
+
+void VBoxGuestDeskbarView::AttachedToWindow()
+{
+ BView::AttachedToWindow();
+ if (Parent())
+ {
+ SetViewColor(Parent()->ViewColor());
+ SetLowColor(Parent()->LowColor());
+ }
+
+ if (fClipboardService) /* Don't repeatedly crash deskbar if vboxdev not loaded */
+ {
+ Looper()->AddHandler(fClipboardService);
+ fClipboardService->Connect();
+ }
+
+ if (fDisplayService)
+ fDisplayService->Start();
+}
+
+
+void VBoxGuestDeskbarView::DetachedFromWindow()
+{
+ BMessage message(B_QUIT_REQUESTED);
+ fClipboardService->MessageReceived(&message);
+ fDisplayService->MessageReceived(&message);
+}
+
+
+void VBoxGuestDeskbarView::MouseDown(BPoint point)
+{
+ int32 buttons = B_PRIMARY_MOUSE_BUTTON;
+ if (Looper() != NULL && Looper()->CurrentMessage() != NULL)
+ Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
+
+ BPoint where = ConvertToScreen(point);
+
+ if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0)
+ {
+ BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
+ menu->SetAsyncAutoDestruct(true);
+ menu->SetFont(be_plain_font);
+
+ menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED)));
+ menu->SetTargetForItems(this);
+
+ menu->Go(where, true, true, true);
+ }
+}
+
+
+void VBoxGuestDeskbarView::MessageReceived(BMessage *message)
+{
+ if (message->what == B_QUIT_REQUESTED)
+ RemoveFromDeskbar();
+ else
+ BHandler::MessageReceived(message);
+}
+
+
+status_t VBoxGuestDeskbarView::AddToDeskbar(bool force)
+{
+ BDeskbar deskbar;
+ status_t err;
+
+ if (force)
+ RemoveFromDeskbar();
+ else if (deskbar.HasItem(VIEWNAME))
+ return B_OK;
+
+ app_info info;
+ err = be_app->GetAppInfo(&info);
+ if (err < B_OK)
+ return err;
+
+ BPath p(&info.ref);
+ return deskbar.AddItem(&info.ref);
+}
+
+
+status_t VBoxGuestDeskbarView::RemoveFromDeskbar()
+{
+ BDeskbar deskbar;
+ return deskbar.RemoveItem(VIEWNAME);
+}
+
+
+status_t VBoxGuestDeskbarView::_Init(BMessage *archive)
+{
+ BString toolTipText;
+ toolTipText << VBOX_PRODUCT << " Guest Additions ";
+ toolTipText << VBOX_VERSION_MAJOR << "." << VBOX_VERSION_MINOR << "." << VBOX_VERSION_BUILD;
+ toolTipText << "r" << VBOX_SVN_REV;
+
+ SetToolTip(toolTipText.String());
+
+ image_info info;
+ if (our_image(info) != B_OK)
+ return B_ERROR;
+
+ BFile file(info.name, B_READ_ONLY);
+ if (file.InitCheck() < B_OK)
+ return B_ERROR;
+
+ BResources resources(&file);
+ if (resources.InitCheck() < B_OK)
+ return B_ERROR;
+
+ const void *data = NULL;
+ size_t size;
+ //data = resources.LoadResource(B_VECTOR_ICON_TYPE,
+ // kNetworkStatusNoDevice + i, &size);
+ data = resources.LoadResource('data', 400, &size);
+ if (data != NULL)
+ {
+ BMemoryIO mem(data, size);
+ fIcon = BTranslationUtils::GetBitmap(&mem);
+ }
+
+ int rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3Init();
+ if (RT_SUCCESS(rc))
+ {
+ fClipboardService = new VBoxShClService();
+ fDisplayService = new VBoxDisplayService();
+ }
+ else
+ LogRel(("VBoxGuestDeskbarView::_init VbglR3Init failed. rc=%d\n", rc));
+ }
+ else
+ LogRel(("VBoxGuestDeskbarView::_init RTR3InitDll failed. rc=%d\n", rc));
+ return RTErrConvertToErrno(rc);
+}
+
+
+RTDECL(BView*) instantiate_deskbar_item()
+{
+ return new VBoxGuestDeskbarView();
+}
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.h b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.h
new file mode 100644
index 00000000..be8cfa54
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.h
@@ -0,0 +1,109 @@
+/* $Id: VBoxGuestDeskbarView.h $ */
+/** @file
+ * VBoxGuestDeskbarView, Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestDeskbarView_h
+#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestDeskbarView_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <Bitmap.h>
+#include <View.h>
+
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+
+#include <VBox/version.h>
+#include <VBox/log.h>
+#include <VBox/VBoxGuest.h> /** @todo use the VbglR3 interface! */
+#include <VBox/VBoxGuestLib.h>
+
+#include <VBoxGuestInternal.h>
+#include "VBoxClipboard.h"
+#include "VBoxDisplay.h"
+
+#define REMOVE_FROM_DESKBAR_MSG 'vbqr'
+
+class VBoxGuestDeskbarView : public BView
+{
+ public:
+ VBoxGuestDeskbarView();
+ VBoxGuestDeskbarView(BMessage *archive);
+ virtual ~VBoxGuestDeskbarView();
+
+ static BArchivable* Instantiate(BMessage *data);
+ virtual status_t Archive(BMessage *data, bool deep = true) const;
+
+ void Draw(BRect rect);
+ void AttachedToWindow();
+ void DetachedFromWindow();
+
+ virtual void MouseDown(BPoint point);
+ virtual void MessageReceived(BMessage *message);
+
+ static status_t AddToDeskbar(bool force = true);
+ static status_t RemoveFromDeskbar();
+
+ private:
+ status_t _Init(BMessage *archive = NULL);
+ BBitmap *fIcon;
+
+ VBoxShClService *fClipboardService;
+ VBoxDisplayService *fDisplayService;
+};
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestDeskbarView_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h b/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h
new file mode 100644
index 00000000..0a1a0e6e
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h
@@ -0,0 +1,78 @@
+/* $Id: VBoxServiceDescriptor.h $ */
+/** @file
+ * VBoxGuestServiceDescriptor, Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h
+#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <Handler.h>
+
+class VBoxShClService : public BHandler
+{
+ public:
+ VBoxShClService();
+ virtual ~VBoxShClService();
+};
+
+/* The shared clipboard service prototypes. */
+int VBoxShClInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
+unsigned __stdcall VBoxShClThread(void *pInstance);
+void VBoxShClDestroy(const VBOXSERVICEENV *pEnv, void *pInstance);
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxTray.rdef b/src/VBox/Additions/haiku/VBoxTray/VBoxTray.rdef
new file mode 100644
index 00000000..f2bd244c
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxTray/VBoxTray.rdef
@@ -0,0 +1,93 @@
+/* $Id: VBoxTray.rdef $ */
+/** @file
+ * VBoxApp - Resource definition file containing version info and icon, Haiku Guest Additions.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ *-----------------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "VBoxGuestInternal.h"
+
+resource(1, "BEOS:APP_SIG") #'MIMS' VBOX_GUEST_APP_SIG;
+
+resource app_flags B_SINGLE_LAUNCH;
+
+/* This is done for all binaries with VBOX_HAIKU_XRES_SETVER_CMDS
+resource app_version {
+ major = VBOX_VERSION_MAJOR,
+ middle = VBOX_VERSION_MINOR,
+ minor = VBOX_VERSION_BUILD,
+
+ variety = B_APPV_DEVELOPMENT,
+ internal = VBOX_SVN_REV,
+
+ short_info = VBOX_PRODUCT,
+ long_info = VBOX_PRODUCT " " VBOX_VERSION_STRING " ©2009-" VBOX_C_YEAR " " VBOX_VENDOR
+};
+*/
+
+/* Maybe one day ? */
+//resource(1, "BEOS:FILE_TYPES") message {
+// "types" = "application/x-vnd.Be.URL.vboxsf"
+//};
+
+resource vector_icon {
+ $"6E636966060500020006023B55F13C5CD2BE755C3D78974A454E48FFCB000EB3"
+ $"B5FF003BFF020006023CD471BA2F923B0FF33DF6F048DA184417BB0000FBFFFF"
+ $"0000FF020006023C318B3A487CBD09B43EEB2D4B485C48176F0000AAFFFF0537"
+ $"C704016D05FF070A062231224E3E5C5248522D37260A042231224E3E5C3E3A0A"
+ $"0422313E3A522D37260A043E5C5248522D3E3A0A043E5E4E5E60485444080835"
+ $"3A393B3C4442384441493A4B444F460A04352E503750533547060A040104000A"
+ $"0001001001178400040A010101000A020102000A030103000A05020506123F45"
+ $"D10000000000003F45D1C70BA246F45D0117820004"
+};
+
+resource(400, "DeskbarShelfIcon.png") #'data' import VBOX_HAIKU_DESKBAR_ICON_PNG;
+
diff --git a/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk b/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk
new file mode 100644
index 00000000..43090fec
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk
@@ -0,0 +1,64 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for Haiku VBoxVideo.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+#
+# This code is based on:
+#
+# VirtualBox Guest Additions for Haiku.
+# Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+# François Revol <revol@free.fr>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+include $(PATH_SUB_CURRENT)/accelerant/Makefile.kmk
+include $(PATH_SUB_CURRENT)/driver/Makefile.kmk
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk b/src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk
new file mode 100644
index 00000000..7084e0ed
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk
@@ -0,0 +1,75 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for VBoxVideo accelerant, Haiku Guest Additions.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+#
+# This code is based on:
+#
+# VirtualBox Guest Additions for Haiku.
+# Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+# François Revol <revol@free.fr>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+SUB_DEPTH = ../../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+PROGRAMS += vboxvideo.accelerant
+vboxvideo.accelerant_TEMPLATE = VBoxGuestR3Exe
+vboxvideo.accelerant_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR
+vboxvideo.accelerant_DEFS += LOG_ENABLED
+vboxvideo.accelerant_INCS = ../include
+vboxvideo.accelerant_SOURCES = \
+ accelerant.cpp
+
+vboxvideo.accelerant_LIBS = \
+ be device \
+ $(VBOX_LIB_IPRT_GUEST_R3_SHARED) \
+ $(VBOX_LIB_VBGL_R3) \
+ /system/servers/app_server
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp
new file mode 100644
index 00000000..5352bd82
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp
@@ -0,0 +1,473 @@
+/* $Id: accelerant.cpp $ */
+/** @file
+ * VBoxVideo Accelerant; Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Accelerant.h>
+#include "accelerant.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+AccelerantInfo gInfo;
+static engine_token sEngineToken = { 1, 0 /*B_2D_ACCELERATION*/, NULL };
+
+/** @todo r=ramshankar: get rid of this and replace with IPRT logging. */
+#define TRACE(x...) do { \
+ FILE* logfile = fopen("/var/log/vboxvideo.accelerant.log", "a"); \
+ fprintf(logfile, x); \
+ fflush(logfile); \
+ fsync(fileno(logfile)); \
+ fclose(logfile); \
+ sync(); \
+ } while(0)
+
+class AreaCloner
+{
+ public:
+ AreaCloner()
+ : fArea(-1)
+ {
+ }
+
+ ~AreaCloner()
+ {
+ if (fArea >= B_OK)
+ delete_area(fArea);
+ }
+
+ area_id Clone(const char *name, void **_address, uint32 spec, uint32 protection, area_id sourceArea)
+ {
+ fArea = clone_area(name, _address, spec, protection, sourceArea);
+ return fArea;
+ }
+
+ status_t InitCheck()
+ {
+ return fArea < B_OK ? (status_t)fArea : B_OK;
+ }
+
+ void Keep()
+ {
+ fArea = -1;
+ }
+
+ private:
+ area_id fArea;
+};
+
+extern "C"
+void* get_accelerant_hook(uint32 feature, void *data)
+{
+ TRACE("%s\n", __FUNCTION__);
+ switch (feature)
+ {
+ /* General */
+ case B_INIT_ACCELERANT:
+ return (void *)vboxvideo_init_accelerant;
+ case B_UNINIT_ACCELERANT:
+ return (void *)vboxvideo_uninit_accelerant;
+ case B_CLONE_ACCELERANT:
+ return (void *)vboxvideo_clone_accelerant;
+ case B_ACCELERANT_CLONE_INFO_SIZE:
+ return (void *)vboxvideo_accelerant_clone_info_size;
+ case B_GET_ACCELERANT_CLONE_INFO:
+ return (void *)vboxvideo_get_accelerant_clone_info;
+ case B_GET_ACCELERANT_DEVICE_INFO:
+ return (void *)vboxvideo_get_accelerant_device_info;
+ case B_ACCELERANT_RETRACE_SEMAPHORE:
+ return (void *)vboxvideo_accelerant_retrace_semaphore;
+
+ /* Mode configuration */
+ case B_ACCELERANT_MODE_COUNT:
+ return (void *)vboxvideo_accelerant_mode_count;
+ case B_GET_MODE_LIST:
+ return (void *)vboxvideo_get_mode_list;
+ case B_SET_DISPLAY_MODE:
+ return (void *)vboxvideo_set_display_mode;
+ case B_GET_DISPLAY_MODE:
+ return (void *)vboxvideo_get_display_mode;
+ case B_GET_EDID_INFO:
+ return (void *)vboxvideo_get_edid_info;
+ case B_GET_FRAME_BUFFER_CONFIG:
+ return (void *)vboxvideo_get_frame_buffer_config;
+ case B_GET_PIXEL_CLOCK_LIMITS:
+ return (void *)vboxvideo_get_pixel_clock_limits;
+
+#if 0
+ /* cursor managment */
+ case B_SET_CURSOR_SHAPE:
+ return (void*)vboxvideo_set_cursor_shape;
+ case B_MOVE_CURSOR:
+ return (void*)vboxvideo_move_cursor;
+ case B_SHOW_CURSOR:
+ return (void*)vboxvideo_show_cursor;
+#endif
+
+ /* Engine/synchronization */
+ case B_ACCELERANT_ENGINE_COUNT:
+ return (void *)vboxvideo_accelerant_engine_count;
+ case B_ACQUIRE_ENGINE:
+ return (void *)vboxvideo_acquire_engine;
+ case B_RELEASE_ENGINE:
+ return (void *)vboxvideo_release_engine;
+ case B_WAIT_ENGINE_IDLE:
+ return (void *)vboxvideo_wait_engine_idle;
+ case B_GET_SYNC_TOKEN:
+ return (void *)vboxvideo_get_sync_token;
+ case B_SYNC_TO_TOKEN:
+ return (void *)vboxvideo_sync_to_token;
+ }
+
+ return NULL;
+}
+
+status_t vboxvideo_init_common(int fd, bool cloned)
+{
+ unlink("/var/log/vboxvideo.accelerant.log"); // clear old log - next TRACE() will recreate it
+ TRACE("%s\n", __FUNCTION__);
+
+ gInfo.deviceFD = fd;
+ gInfo.isClone = cloned;
+ gInfo.sharedInfo = NULL;
+ gInfo.sharedInfoArea = -1;
+
+ area_id sharedArea;
+ if (ioctl(gInfo.deviceFD, VBOXVIDEO_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id)) != 0)
+ {
+ TRACE("ioctl failed\n");
+ return B_ERROR;
+ }
+
+ AreaCloner sharedCloner;
+ gInfo.sharedInfoArea = sharedCloner.Clone("vboxvideo shared info", (void **)&gInfo.sharedInfo, B_ANY_ADDRESS,
+ B_READ_AREA | B_WRITE_AREA, sharedArea);
+ status_t status = sharedCloner.InitCheck();
+ if (status < B_OK)
+ {
+ TRACE("InitCheck failed (%s)\n", strerror(status));
+ return status;
+ }
+ sharedCloner.Keep();
+
+ return B_OK;
+}
+
+
+status_t vboxvideo_init_accelerant(int fd)
+{
+ return vboxvideo_init_common(fd, false);
+}
+
+
+ssize_t vboxvideo_accelerant_clone_info_size(void)
+{
+ TRACE("%s\n", __FUNCTION__);
+ return B_PATH_NAME_LENGTH;
+}
+
+
+void vboxvideo_get_accelerant_clone_info(void *data)
+{
+ TRACE("%s\n", __FUNCTION__);
+ ioctl(gInfo.deviceFD, VBOXVIDEO_GET_DEVICE_NAME, data, B_PATH_NAME_LENGTH);
+}
+
+
+status_t vboxvideo_clone_accelerant(void *data)
+{
+ TRACE("%s\n", __FUNCTION__);
+
+ /* Create full device name */
+ char path[MAXPATHLEN];
+ strcpy(path, "/dev/");
+ strcat(path, (const char *)data);
+
+ int fd = open(path, B_READ_WRITE);
+ if (fd < 0)
+ return errno;
+
+ return vboxvideo_init_common(fd, true);
+}
+
+
+void vboxvideo_uninit_accelerant(void)
+{
+ delete_area(gInfo.sharedInfoArea);
+ gInfo.sharedInfo = NULL;
+ gInfo.sharedInfoArea = -1;
+
+ if (gInfo.isClone)
+ close(gInfo.deviceFD);
+
+ TRACE("%s\n", __FUNCTION__);
+}
+
+
+status_t vboxvideo_get_accelerant_device_info(accelerant_device_info *adi)
+{
+ TRACE("%s\n", __FUNCTION__);
+ adi->version = B_ACCELERANT_VERSION;
+ strcpy(adi->name, "Virtual display");
+ strcpy(adi->chipset, "VirtualBox Graphics Adapter");
+ strcpy(adi->serial_no, "9001");
+ return B_OK;
+}
+
+
+sem_id vboxvideo_accelerant_retrace_semaphore(void)
+{
+ TRACE("%s\n", __FUNCTION__);
+ return -1;
+}
+
+
+// modes & constraints
+uint32 vboxvideo_accelerant_mode_count(void)
+{
+ TRACE("%s\n", __FUNCTION__);
+ return 1;
+}
+
+
+status_t vboxvideo_get_mode_list(display_mode *dm)
+{
+ /// @todo return some standard modes here
+ TRACE("%s\n", __FUNCTION__);
+ return vboxvideo_get_display_mode(dm);
+}
+
+
+status_t vboxvideo_set_display_mode(display_mode *modeToSet)
+{
+ TRACE("%s\n", __FUNCTION__);
+ TRACE("trying to set mode %dx%d\n", modeToSet->timing.h_display, modeToSet->timing.v_display);
+ return ioctl(gInfo.deviceFD, VBOXVIDEO_SET_DISPLAY_MODE, modeToSet, sizeof(display_mode));
+}
+
+
+status_t vboxvideo_get_display_mode(display_mode *currentMode)
+{
+ TRACE("%s\n", __FUNCTION__);
+ *currentMode = gInfo.sharedInfo->currentMode;
+ TRACE("current mode is %dx%d\n", currentMode->timing.h_display, currentMode->timing.v_display);
+ return B_OK;
+}
+
+
+status_t vboxvideo_get_edid_info(void *info, size_t size, uint32 *_version)
+{
+ TRACE("%s\n", __FUNCTION__);
+
+ /* Copied from the X11 implementation: */
+ static const uint8 edid_data[128] = {
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, /* header */
+ 0x58, 0x58, /* manufacturer (VBX) */
+ 0x00, 0x00, /* product code */
+ 0x00, 0x00, 0x00, 0x00, /* serial number goes here */
+ 0x01, /* week of manufacture */
+ 0x00, /* year of manufacture */
+ 0x01, 0x03, /* EDID version */
+ 0x80, /* capabilities - digital */
+ 0x00, /* horiz. res in cm, zero for projectors */
+ 0x00, /* vert. res in cm */
+ 0x78, /* display gamma (120 == 2.2). Should we ask the host for this? */
+ 0xEE, /* features (standby, suspend, off, RGB, standard colour space,
+ * preferred timing mode) */
+ 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
+ /* chromaticity for standard colour space - should we ask the host? */
+ 0x00, 0x00, 0x00, /* no default timings */
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, /* no standard timings */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* descriptor block 1 goes here */
+ 0x00, 0x00, 0x00, 0xFD, 0x00, /* descriptor block 2, monitor ranges */
+ 0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, /* 0-200Hz vertical, 0-200KHz horizontal, 1000MHz pixel clock */
+ 0x00, 0x00, 0x00, 0xFC, 0x00, /* descriptor block 3, monitor name */
+ 'V', 'B', 'O', 'X', ' ', 'm', 'o', 'n', 'i', 't', 'o', 'r', '\n',
+ 0x00, 0x00, 0x00, 0x10, 0x00, /* descriptor block 4: dummy data */
+ 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20,
+ 0x00, /* number of extensions */
+ 0x00 /* checksum goes here */
+ };
+
+ if (size < 128)
+ return B_BUFFER_OVERFLOW;
+
+ *_version = 1; /* EDID_VERSION_1 */
+ memcpy(info, edid_data, 128);
+ return B_OK;
+}
+
+
+status_t vboxvideo_get_frame_buffer_config(frame_buffer_config *config)
+{
+ TRACE("%s\n", __FUNCTION__);
+ config->frame_buffer = gInfo.sharedInfo->framebuffer;
+ config->frame_buffer_dma = NULL;
+ config->bytes_per_row = get_depth_for_color_space(gInfo.sharedInfo->currentMode.space)
+ * gInfo.sharedInfo->currentMode.timing.h_display / 8;
+ return B_OK;
+}
+
+
+status_t vboxvideo_get_pixel_clock_limits(display_mode *dm, uint32 *low, uint32 *high)
+{
+ TRACE("%s\n", __FUNCTION__);
+ // irrelevant for virtual monitors
+ *low = 0;
+ *high = 9001;
+ return B_OK;
+}
+
+
+/* Cursor */
+status_t vboxvideo_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotY, uint8 *andMask, uint8 *xorMask)
+{
+ TRACE("%s\n", __FUNCTION__);
+ // VBoxHGSMIUpdatePointerShape
+ return B_UNSUPPORTED;
+}
+
+
+void vboxvideo_move_cursor(uint16 x, uint16 y)
+{
+ TRACE("%s\n", __FUNCTION__);
+}
+
+
+void vboxvideo_show_cursor(bool is_visible)
+{
+ TRACE("%s\n", __FUNCTION__);
+}
+
+
+/* Accelerant engine */
+uint32 vboxvideo_accelerant_engine_count(void)
+{
+ TRACE("%s\n", __FUNCTION__);
+ return 1;
+}
+
+status_t vboxvideo_acquire_engine(uint32 capabilities, uint32 maxWait, sync_token *st, engine_token **et)
+{
+ TRACE("%s\n", __FUNCTION__);
+ *et = &sEngineToken;
+ return B_OK;
+}
+
+
+status_t vboxvideo_release_engine(engine_token *et, sync_token *st)
+{
+ TRACE("%s\n", __FUNCTION__);
+ if (st != NULL)
+ st->engine_id = et->engine_id;
+
+ return B_OK;
+}
+
+
+void vboxvideo_wait_engine_idle(void)
+{
+ TRACE("%s\n", __FUNCTION__);
+}
+
+
+status_t vboxvideo_get_sync_token(engine_token *et, sync_token *st)
+{
+ TRACE("%s\n", __FUNCTION__);
+ return B_OK;
+}
+
+
+status_t vboxvideo_sync_to_token(sync_token *st)
+{
+ TRACE("%s\n", __FUNCTION__);
+ return B_OK;
+}
+
+
+/* 2D acceleration */
+void vboxvideo_screen_to_screen_blit(engine_token *et, blit_params *list, uint32 count)
+{
+ TRACE("%s\n", __FUNCTION__);
+}
+
+
+void vboxvideo_fill_rectangle(engine_token *et, uint32 color, fill_rect_params *list, uint32 count)
+{
+ TRACE("%s\n", __FUNCTION__);
+}
+
+
+void vboxvideo_invert_rectangle(engine_token *et, fill_rect_params *list, uint32 count)
+{
+ TRACE("%s\n", __FUNCTION__);
+}
+
+
+void vboxvideo_fill_span(engine_token *et, uint32 color, uint16 *list, uint32 count)
+{
+ TRACE("%s\n", __FUNCTION__);
+}
diff --git a/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h
new file mode 100644
index 00000000..735f4d2b
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h
@@ -0,0 +1,115 @@
+/* $Id: accelerant.h $ */
+/** @file
+ * VBoxVideo Accelerant; Haiku Guest Additions, header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxVideo_accelerant_accelerant_h
+#define GA_INCLUDED_SRC_haiku_VBoxVideo_accelerant_accelerant_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <Accelerant.h>
+#include "../common/VBoxVideo_common.h"
+
+struct AccelerantInfo
+{
+ /** @todo doxygen document these fields */
+ int deviceFD;
+ bool isClone;
+
+ SharedInfo *sharedInfo;
+ area_id sharedInfoArea;
+};
+extern AccelerantInfo gInfo;
+
+/* General */
+status_t vboxvideo_init_accelerant(int fd);
+ssize_t vboxvideo_accelerant_clone_info_size(void);
+void vboxvideo_get_accelerant_clone_info(void *data);
+status_t vboxvideo_clone_accelerant(void *data);
+void vboxvideo_uninit_accelerant(void);
+status_t vboxvideo_get_accelerant_device_info(accelerant_device_info *adi);
+sem_id vboxvideo_accelerant_retrace_semaphore(void);
+
+/* Modes & constraints */
+uint32 vboxvideo_accelerant_mode_count(void);
+status_t vboxvideo_get_mode_list(display_mode *dm);
+status_t vboxvideo_set_display_mode(display_mode *modeToSet);
+status_t vboxvideo_get_display_mode(display_mode *currentMode);
+status_t vboxvideo_get_edid_info(void *info, size_t size, uint32 *_version);
+status_t vboxvideo_get_frame_buffer_config(frame_buffer_config *config);
+status_t vboxvideo_get_pixel_clock_limits(display_mode *dm, uint32 *low, uint32 *high);
+
+/* Cursor */
+status_t vboxvideo_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotY, uint8 *andMask, uint8 *xorMask);
+void vboxvideo_move_cursor(uint16 x, uint16 y);
+void vboxvideo_show_cursor(bool is_visible);
+
+/* Accelerant engine */
+uint32 vboxvideo_accelerant_engine_count(void);
+status_t vboxvideo_acquire_engine(uint32 capabilities, uint32 maxWait, sync_token *st, engine_token **et);
+status_t vboxvideo_release_engine(engine_token *et, sync_token *st);
+void vboxvideo_wait_engine_idle(void);
+status_t vboxvideo_get_sync_token(engine_token *et, sync_token *st);
+status_t vboxvideo_sync_to_token(sync_token *st);
+
+/* 2D acceleration */
+void vboxvideo_screen_to_screen_blit(engine_token *et, blit_params *list, uint32 count);
+void vboxvideo_fill_rectangle(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
+void vboxvideo_invert_rectangle(engine_token *et, fill_rect_params *list, uint32 count);
+void vboxvideo_fill_span(engine_token *et, uint32 color, uint16 *list, uint32 count);
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxVideo_accelerant_accelerant_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h b/src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h
new file mode 100644
index 00000000..b00bce3f
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h
@@ -0,0 +1,114 @@
+/* $Id: VBoxVideo_common.h $ */
+/** @file
+ * VBoxVideo, Haiku Guest Additions, common header.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_SRC_haiku_VBoxVideo_common_VBoxVideo_common_h
+#define GA_INCLUDED_SRC_haiku_VBoxVideo_common_VBoxVideo_common_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <Drivers.h>
+#include <Accelerant.h>
+#include <PCI.h>
+
+struct SharedInfo
+{
+ display_mode currentMode;
+ area_id framebufferArea;
+ void *framebuffer;
+};
+
+enum
+{
+ VBOXVIDEO_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1,
+ VBOXVIDEO_GET_DEVICE_NAME,
+ VBOXVIDEO_SET_DISPLAY_MODE
+};
+
+static inline uint32 get_color_space_for_depth(uint32 depth)
+{
+ switch (depth)
+ {
+ case 1: return B_GRAY1;
+ case 4: return B_GRAY8;
+ /* The app_server is smart enough to translate this to VGA mode */
+ case 8: return B_CMAP8;
+ case 15: return B_RGB15;
+ case 16: return B_RGB16;
+ case 24: return B_RGB24;
+ case 32: return B_RGB32;
+ }
+
+ return 0;
+}
+
+static inline uint32 get_depth_for_color_space(uint32 depth)
+{
+ switch (depth)
+ {
+ case B_GRAY1: return 1;
+ case B_GRAY8: return 4;
+ case B_CMAP8: return 8;
+ case B_RGB15: return 15;
+ case B_RGB16: return 16;
+ case B_RGB24: return 24;
+ case B_RGB32: return 32;
+ }
+ return 0;
+}
+
+#endif /* !GA_INCLUDED_SRC_haiku_VBoxVideo_common_VBoxVideo_common_h */
+
diff --git a/src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk b/src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk
new file mode 100644
index 00000000..b32a91b3
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk
@@ -0,0 +1,95 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for VBoxVideo driver, Haiku Guest Additions.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+#
+# This code is based on:
+#
+# VirtualBox Guest Additions for Haiku.
+# Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+# François Revol <revol@free.fr>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+SUB_DEPTH = ../../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+ifdef VBOX_WITH_ADDITION_DRIVERS
+ SYSMODS += vboxvideo
+endif
+
+#
+# Populate FILES_VBOXSF_NOBIN
+#
+#include $(PATH_SUB_CURRENT)/files_VBoxVideo
+
+#
+# The module (for syntax checking).
+# The DEBUG_HASH* stuff is for CONFIG_DYNAMIC_DEBUG-enabled kernels
+#
+vboxvideo_TEMPLATE = VBoxGuestR0Drv
+vboxvideo_DEFS = \
+ MODULE IN_RT_R0 VBOXGUEST VBOX_WITH_HGCM \
+ KBUILD_MODNAME=KBUILD_STR\(VBoxVideo\) \
+ KBUILD_BASENAME=KBUILD_STR\(VBoxVideo\)
+vboxvideo_INCS = \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuestLib \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest \
+ $(PATH_ROOT)/src/VBox/Runtime/r0drv/haiku \
+ $(VBOX_GRAPHICS_INCS)
+vboxvideo_SOURCES = \
+ driver.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/HGSMIBuffers.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/Modesetting.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c
+vboxvideo_LIBS = \
+ $(VBOX_LIB_VBGL_R0) \
+ $(VBOX_PATH_ADDITIONS_LIB)/HGSMIGuestR0Lib$(VBOX_SUFF_LIB)
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp b/src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp
new file mode 100644
index 00000000..ce04560a
--- /dev/null
+++ b/src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp
@@ -0,0 +1,382 @@
+/* $Id: driver.cpp $ */
+/** @file
+ * VBoxVideo driver, Haiku Guest Additions, implementation.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <KernelExport.h>
+#include <PCI.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <graphic_driver.h>
+#include <VBoxGuest-haiku.h>
+#include <VBoxVideoGuest.h>
+#include "../common/VBoxVideo_common.h"
+
+#define VENDOR_ID 0x80ee
+#define DEVICE_ID 0xbeef
+#define DRIVER_NAME "VBoxVideoDriver"
+#define DEVICE_FORMAT "vd_%04X_%04X_%02X%02X%02X"
+
+/** @todo r=ramshankar: pretty sure IPRT has something for page rounding,
+ * replace with IPRT version later. */
+#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
+
+#define ENABLE_DEBUG_TRACE
+
+#undef TRACE
+#ifdef ENABLE_DEBUG_TRACE
+#define TRACE(x...) dprintf("VBoxVideo: " x)
+#else
+#define TRACE(x...) ;
+#endif
+
+int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support
+
+extern "C" status_t vm_set_area_memory_type(area_id id, phys_addr_t physicalBase, uint32 type);
+
+struct Benaphore
+{
+ sem_id sem;
+ int32 count;
+
+ status_t Init(const char *name)
+ {
+ count = 0;
+ sem = create_sem(0, name);
+ return sem < 0 ? sem : B_OK;
+ }
+
+ status_t Acquire()
+ {
+ if (atomic_add(&count, 1) > 0)
+ return acquire_sem(sem);
+ return B_OK;
+ }
+
+ status_t Release()
+ {
+ if (atomic_add(&count, -1) > 1)
+ return release_sem(sem);
+ return B_OK;
+ }
+
+ void Delete()
+ {
+ delete_sem(sem);
+ }
+};
+
+struct DeviceInfo
+{
+ uint32 openCount; /* Count of how many times device has been opened */
+ uint32 flags; /* Device flags */
+ area_id sharedArea; /* Area shared between driver and all accelerants */
+ SharedInfo *sharedInfo; /* Pointer to shared info area memory */
+ pci_info pciInfo; /* Copy of pci info for this device */
+ char name[B_OS_NAME_LENGTH]; /* Name of device */
+};
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+status_t device_open(const char *name, uint32 flags, void **cookie);
+status_t device_close(void *dev);
+status_t device_free(void *dev);
+status_t device_read(void *dev, off_t pos, void *buf, size_t *len);
+status_t device_write(void *dev, off_t pos, const void *buf, size_t *len);
+status_t device_ioctl(void *dev, uint32 msg, void *buf, size_t len);
+static uint32 get_color_space_for_depth(uint32 depth);
+
+
+/*********************************************************************************************************************************
+* Globals *
+*********************************************************************************************************************************/
+/* At most one virtual video card ever appears, no reason for this to be an array */
+static DeviceInfo gDeviceInfo;
+static char *gDeviceNames[2] = { gDeviceInfo.name, NULL };
+static bool gCanHasDevice = false; /* is the device present? */
+static Benaphore gLock;
+static pci_module_info *gPCI;
+
+static device_hooks gDeviceHooks =
+{
+ device_open,
+ device_close,
+ device_free,
+ device_ioctl,
+ device_read,
+ device_write,
+ NULL, /* select */
+ NULL, /* deselect */
+ NULL, /* read_pages */
+ NULL /* write_pages */
+};
+
+
+status_t init_hardware()
+{
+ LogFlowFunc(("init_hardware\n"));
+
+ status_t err = get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest);
+ if (err == B_OK)
+ {
+ err = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
+ if (err == B_OK)
+ return B_OK;
+
+ LogRel((DRIVER_NAME ":_init_hardware() get_module(%s) failed. err=%08lx\n", B_PCI_MODULE_NAME));
+ }
+ else
+ LogRel((DRIVER_NAME ":_init_hardware() get_module(%s) failed. err=%08lx\n", VBOXGUEST_MODULE_NAME, err));
+ return B_ERROR;
+}
+
+
+status_t init_driver()
+{
+ LogFlowFunc(("init_driver\n"));
+
+ gLock.Init("VBoxVideo driver lock");
+
+ uint32 pciIndex = 0;
+
+ while (gPCI->get_nth_pci_info(pciIndex, &gDeviceInfo.pciInfo) == B_OK)
+ {
+ if (gDeviceInfo.pciInfo.vendor_id == VENDOR_ID && gDeviceInfo.pciInfo.device_id == DEVICE_ID)
+ {
+ sprintf(gDeviceInfo.name, "graphics/" DEVICE_FORMAT,
+ gDeviceInfo.pciInfo.vendor_id, gDeviceInfo.pciInfo.device_id,
+ gDeviceInfo.pciInfo.bus, gDeviceInfo.pciInfo.device, gDeviceInfo.pciInfo.function);
+ TRACE("found device %s\n", gDeviceInfo.name);
+
+ gCanHasDevice = true;
+ gDeviceInfo.openCount = 0;
+
+ size_t sharedSize = (sizeof(SharedInfo) + 7) & ~7;
+ gDeviceInfo.sharedArea = create_area("vboxvideo shared info",
+ (void **)&gDeviceInfo.sharedInfo, B_ANY_KERNEL_ADDRESS,
+ ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK,
+ B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA);
+
+ uint16_t width, height, vwidth, bpp, flags;
+ VBoxVideoGetModeRegisters(&width, &height, &vwidth, &bpp, &flags);
+
+ gDeviceInfo.sharedInfo->currentMode.space = get_color_space_for_depth(bpp);
+ gDeviceInfo.sharedInfo->currentMode.virtual_width = width;
+ gDeviceInfo.sharedInfo->currentMode.virtual_height = height;
+ gDeviceInfo.sharedInfo->currentMode.h_display_start = 0;
+ gDeviceInfo.sharedInfo->currentMode.v_display_start = 0;
+ gDeviceInfo.sharedInfo->currentMode.flags = 0;
+ gDeviceInfo.sharedInfo->currentMode.timing.h_display = width;
+ gDeviceInfo.sharedInfo->currentMode.timing.v_display = height;
+ /* Not used, but this makes a reasonable-sounding refresh rate show in screen prefs: */
+ gDeviceInfo.sharedInfo->currentMode.timing.h_total = 1000;
+ gDeviceInfo.sharedInfo->currentMode.timing.v_total = 1;
+ gDeviceInfo.sharedInfo->currentMode.timing.pixel_clock = 850;
+
+ /* Map the PCI memory space */
+ uint32 command_reg = gPCI->read_pci_config(gDeviceInfo.pciInfo.bus,
+ gDeviceInfo.pciInfo.device, gDeviceInfo.pciInfo.function, PCI_command, 2);
+ command_reg |= PCI_command_io | PCI_command_memory | PCI_command_master;
+ gPCI->write_pci_config(gDeviceInfo.pciInfo.bus, gDeviceInfo.pciInfo.device,
+ gDeviceInfo.pciInfo.function, PCI_command, 2, command_reg);
+
+ gDeviceInfo.sharedInfo->framebufferArea = map_physical_memory("vboxvideo framebuffer",
+ (phys_addr_t)gDeviceInfo.pciInfo.u.h0.base_registers[0],
+ gDeviceInfo.pciInfo.u.h0.base_register_sizes[0], B_ANY_KERNEL_BLOCK_ADDRESS,
+ B_READ_AREA | B_WRITE_AREA, &(gDeviceInfo.sharedInfo->framebuffer));
+ vm_set_area_memory_type(gDeviceInfo.sharedInfo->framebufferArea,
+ (phys_addr_t)gDeviceInfo.pciInfo.u.h0.base_registers[0], B_MTR_WC);
+ break;
+ }
+
+ pciIndex++;
+ }
+
+ return B_OK;
+}
+
+
+const char** publish_devices()
+{
+ LogFlowFunc(("publish_devices\n"));
+ if (gCanHasDevice)
+ return (const char **)gDeviceNames;
+ return NULL;
+}
+
+
+device_hooks* find_device(const char *name)
+{
+ LogFlowFunc(("find_device\n"));
+ if (gCanHasDevice && strcmp(name, gDeviceInfo.name) == 0)
+ return &gDeviceHooks;
+
+ return NULL;
+}
+
+
+void uninit_driver()
+{
+ LogFlowFunc(("uninit_driver\n"));
+ gLock.Delete();
+ put_module(VBOXGUEST_MODULE_NAME);
+}
+
+status_t device_open(const char *name, uint32 flags, void **cookie)
+{
+ LogFlowFunc(("device_open\n"));
+
+ if (!gCanHasDevice || strcmp(name, gDeviceInfo.name) != 0)
+ return B_BAD_VALUE;
+
+ /** @todo init device! */
+
+ *cookie = (void *)&gDeviceInfo;
+ return B_OK;
+}
+
+
+status_t device_close(void *dev)
+{
+ LogFlowFunc(("device_close\n"));
+ return B_ERROR;
+}
+
+
+status_t device_free(void *dev)
+{
+ LogFlowFunc(("device_free\n"));
+
+ DeviceInfo& di = *(DeviceInfo *)dev;
+ gLock.Acquire();
+
+ if (di.openCount <= 1)
+ {
+ /// @todo deinit device!
+ delete_area(di.sharedArea);
+ di.sharedArea = -1;
+ di.sharedInfo = NULL;
+ }
+
+ if (di.openCount > 0)
+ di.openCount--;
+
+ gLock.Release();
+
+ return B_OK;
+}
+
+
+status_t device_read(void *dev, off_t pos, void *buf, size_t *len)
+{
+ LogFlowFunc(("device_read\n"));
+ return B_NOT_ALLOWED;
+}
+
+
+status_t device_write(void *dev, off_t pos, const void *buf, size_t *len)
+{
+ LogFlowFunc(("device_write\n"));
+ return B_NOT_ALLOWED;
+}
+
+
+status_t device_ioctl(void *cookie, uint32 msg, void *buf, size_t len)
+{
+ LogFlowFunc(("device_ioctl\n"));
+
+ DeviceInfo *dev = (DeviceInfo *)cookie;
+
+ switch (msg)
+ {
+ case B_GET_ACCELERANT_SIGNATURE:
+ {
+ strcpy((char *)buf, "vboxvideo.accelerant");
+ return B_OK;
+ }
+
+ case VBOXVIDEO_GET_PRIVATE_DATA:
+ {
+ /** @todo r=ramshankar: implement RTR0MemUserCopyFrom for haiku. */
+ return user_memcpy(buf, &dev->sharedArea, sizeof(area_id));
+ }
+
+ case VBOXVIDEO_GET_DEVICE_NAME:
+ {
+ /** @todo r=ramshankar: implement RTR0MemUserCopyFrom for haiku. */
+ if (user_strlcpy((char *)buf, gDeviceInfo.name, len) < B_OK)
+ return B_BAD_ADDRESS;
+ return B_OK;
+ }
+
+ case VBOXVIDEO_SET_DISPLAY_MODE:
+ {
+ display_mode *mode = (display_mode *)buf;
+ VBoxVideoSetModeRegisters(mode->timing.h_display, mode->timing.v_display,
+ mode->timing.h_display, get_depth_for_color_space(mode->space), 0, 0, 0);
+ gDeviceInfo.sharedInfo->currentMode = *mode;
+ return B_OK;
+ }
+ default:
+ return B_BAD_VALUE;
+ }
+}
+
diff --git a/src/VBox/Additions/haiku/include/VBoxGuestInternal.h b/src/VBox/Additions/haiku/include/VBoxGuestInternal.h
new file mode 100644
index 00000000..87adbb92
--- /dev/null
+++ b/src/VBox/Additions/haiku/include/VBoxGuestInternal.h
@@ -0,0 +1,74 @@
+/* $$ */
+/** @file
+ * VBoxGuestInternal - Private Haiku additions declarations.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ * Copyright (c) 2011 Mike Smith <mike@scgtrp.net>
+ * François Revol <revol@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GA_INCLUDED_HAIKU_VBoxGuestInternal_h
+#define GA_INCLUDED_HAIKU_VBoxGuestInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+/** The MIME signature of the VBoxGuest application. */
+#define VBOX_GUEST_APP_SIG "application/x-vnd.Oracle-VBoxGuest"
+
+/** The code used for messages sent by and to the system tray. */
+#define VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA 'vbC2'
+#define VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS 'vbC3'
+
+/** The code used for messages sent by and to the system tray. */
+#define VBOX_GUEST_APP_ACTION 'vbox'
+
+#endif /* !GA_INCLUDED_HAIKU_VBoxGuestInternal_h */
+
diff --git a/src/VBox/Additions/haiku/include/lock.h b/src/VBox/Additions/haiku/include/lock.h
new file mode 100644
index 00000000..13d2f94c
--- /dev/null
+++ b/src/VBox/Additions/haiku/include/lock.h
@@ -0,0 +1,318 @@
+/* $Id: lock.h $ */
+/** @file
+ * Lock.h - Haiku, private locking internals.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/*
+ * This code is based on:
+ *
+ * VirtualBox Guest Additions for Haiku.
+ *
+ * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+/** @todo r=ramshankar: Eventually this file should be shipped by Haiku and
+ * should be removed from the VBox tree. */
+
+#ifndef GA_INCLUDED_HAIKU_lock_h
+#define GA_INCLUDED_HAIKU_lock_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <OS.h>
+
+
+struct mutex_waiter;
+
+typedef struct mutex {
+ const char* name;
+ struct mutex_waiter* waiters;
+#if KDEBUG
+ thread_id holder;
+#else
+ int32 count;
+ uint16 ignore_unlock_count;
+#endif
+ uint8 flags;
+} mutex;
+
+#define MUTEX_FLAG_CLONE_NAME 0x1
+
+
+typedef struct recursive_lock {
+ mutex lock;
+#if !KDEBUG
+ thread_id holder;
+#endif
+ int recursion;
+} recursive_lock;
+
+
+struct rw_lock_waiter;
+
+typedef struct rw_lock {
+ const char* name;
+ struct rw_lock_waiter* waiters;
+ thread_id holder;
+ vint32 count;
+ int32 owner_count;
+ int16 active_readers;
+ // Only > 0 while a writer is waiting: number
+ // of active readers when the first waiting
+ // writer started waiting.
+ int16 pending_readers;
+ // Number of readers that have already
+ // incremented "count", but have not yet started
+ // to wait at the time the last writer unlocked.
+ uint32 flags;
+} rw_lock;
+
+#define RW_LOCK_WRITER_COUNT_BASE 0x10000
+
+#define RW_LOCK_FLAG_CLONE_NAME 0x1
+
+
+#if KDEBUG
+# define KDEBUG_RW_LOCK_DEBUG 0
+ // Define to 1 if you want to use ASSERT_READ_LOCKED_RW_LOCK().
+ // The rw_lock will just behave like a recursive locker then.
+# define ASSERT_LOCKED_RECURSIVE(r) \
+ { ASSERT(find_thread(NULL) == (r)->lock.holder); }
+# define ASSERT_LOCKED_MUTEX(m) { ASSERT(find_thread(NULL) == (m)->holder); }
+# define ASSERT_WRITE_LOCKED_RW_LOCK(l) \
+ { ASSERT(find_thread(NULL) == (l)->holder); }
+# if KDEBUG_RW_LOCK_DEBUG
+# define ASSERT_READ_LOCKED_RW_LOCK(l) \
+ { ASSERT(find_thread(NULL) == (l)->holder); }
+# else
+# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false)
+# endif
+#else
+# define ASSERT_LOCKED_RECURSIVE(r) do {} while (false)
+# define ASSERT_LOCKED_MUTEX(m) do {} while (false)
+# define ASSERT_WRITE_LOCKED_RW_LOCK(m) do {} while (false)
+# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false)
+#endif
+
+
+// static initializers
+#if KDEBUG
+# define MUTEX_INITIALIZER(name) { name, NULL, -1, 0 }
+# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), 0 }
+#else
+# define MUTEX_INITIALIZER(name) { name, NULL, 0, 0, 0 }
+# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), -1, 0 }
+#endif
+
+#define RW_LOCK_INITIALIZER(name) { name, NULL, -1, 0, 0, 0 }
+
+
+#if KDEBUG
+# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->lock.holder)
+#else
+# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->holder)
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void recursive_lock_init(recursive_lock *lock, const char *name);
+ // name is *not* cloned nor freed in recursive_lock_destroy()
+extern void recursive_lock_init_etc(recursive_lock *lock, const char *name,
+ uint32 flags);
+extern void recursive_lock_destroy(recursive_lock *lock);
+extern status_t recursive_lock_lock(recursive_lock *lock);
+extern status_t recursive_lock_trylock(recursive_lock *lock);
+extern void recursive_lock_unlock(recursive_lock *lock);
+extern int32 recursive_lock_get_recursion(recursive_lock *lock);
+
+extern void rw_lock_init(rw_lock* lock, const char* name);
+ // name is *not* cloned nor freed in rw_lock_destroy()
+extern void rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags);
+extern void rw_lock_destroy(rw_lock* lock);
+extern status_t rw_lock_write_lock(rw_lock* lock);
+
+extern void mutex_init(mutex* lock, const char* name);
+ // name is *not* cloned nor freed in mutex_destroy()
+extern void mutex_init_etc(mutex* lock, const char* name, uint32 flags);
+extern void mutex_destroy(mutex* lock);
+extern status_t mutex_switch_lock(mutex* from, mutex* to);
+ // Unlocks "from" and locks "to" such that unlocking and starting to wait
+ // for the lock is atomically. I.e. if "from" guards the object "to" belongs
+ // to, the operation is safe as long as "from" is held while destroying
+ // "to".
+extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to);
+ // Like mutex_switch_lock(), just for a switching from a read-locked
+ // rw_lock.
+
+
+// implementation private:
+
+extern status_t _rw_lock_read_lock(rw_lock* lock);
+extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock,
+ uint32 timeoutFlags, bigtime_t timeout);
+extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked);
+extern void _rw_lock_write_unlock(rw_lock* lock, bool threadsLocked);
+
+extern status_t _mutex_lock(mutex* lock, bool threadsLocked);
+extern void _mutex_unlock(mutex* lock, bool threadsLocked);
+extern status_t _mutex_trylock(mutex* lock);
+extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags,
+ bigtime_t timeout);
+
+
+static inline status_t
+rw_lock_read_lock(rw_lock* lock)
+{
+#if KDEBUG_RW_LOCK_DEBUG
+ return rw_lock_write_lock(lock);
+#else
+ int32 oldCount = atomic_add(&lock->count, 1);
+ if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
+ return _rw_lock_read_lock(lock);
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags,
+ bigtime_t timeout)
+{
+#if KDEBUG_RW_LOCK_DEBUG
+ return mutex_lock_with_timeout(lock, timeoutFlags, timeout);
+#else
+ int32 oldCount = atomic_add(&lock->count, 1);
+ if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
+ return _rw_lock_read_lock_with_timeout(lock, timeoutFlags, timeout);
+ return B_OK;
+#endif
+}
+
+
+static inline void
+rw_lock_read_unlock(rw_lock* lock)
+{
+#if KDEBUG_RW_LOCK_DEBUG
+ rw_lock_write_unlock(lock);
+#else
+ int32 oldCount = atomic_add(&lock->count, -1);
+ if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
+ _rw_lock_read_unlock(lock, false);
+#endif
+}
+
+
+static inline void
+rw_lock_write_unlock(rw_lock* lock)
+{
+ _rw_lock_write_unlock(lock, false);
+}
+
+
+static inline status_t
+mutex_lock(mutex* lock)
+{
+#if KDEBUG
+ return _mutex_lock(lock, false);
+#else
+ if (atomic_add(&lock->count, -1) < 0)
+ return _mutex_lock(lock, false);
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+mutex_lock_threads_locked(mutex* lock)
+{
+#if KDEBUG
+ return _mutex_lock(lock, true);
+#else
+ if (atomic_add(&lock->count, -1) < 0)
+ return _mutex_lock(lock, true);
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+mutex_trylock(mutex* lock)
+{
+#if KDEBUG
+ return _mutex_trylock(lock);
+#else
+ if (atomic_test_and_set(&lock->count, -1, 0) != 0)
+ return B_WOULD_BLOCK;
+ return B_OK;
+#endif
+}
+
+
+static inline status_t
+mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout)
+{
+#if KDEBUG
+ return _mutex_lock_with_timeout(lock, timeoutFlags, timeout);
+#else
+ if (atomic_add(&lock->count, -1) < 0)
+ return _mutex_lock_with_timeout(lock, timeoutFlags, timeout);
+ return B_OK;
+#endif
+}
+
+
+static inline void
+mutex_unlock(mutex* lock)
+{
+#if !KDEBUG
+ if (atomic_add(&lock->count, 1) < -1)
+#endif
+ _mutex_unlock(lock, false);
+}
+
+
+static inline void
+mutex_transfer_lock(mutex* lock, thread_id thread)
+{
+#if KDEBUG
+ lock->holder = thread;
+#endif
+}
+
+
+extern void lock_debug_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !GA_INCLUDED_HAIKU_lock_h */
diff --git a/src/VBox/Additions/haiku/load.sh b/src/VBox/Additions/haiku/load.sh
new file mode 100755
index 00000000..209a55ac
--- /dev/null
+++ b/src/VBox/Additions/haiku/load.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# $Id: load.sh $
+## @file
+# Driver load script.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+outdir=out/haiku.x86/debug/bin/additions
+instdir=/boot/apps/VBoxAdditions
+
+
+# vboxguest
+mkdir -p ~/config/add-ons/kernel/generic/
+cp $outdir/vboxguest ~/config/add-ons/kernel/generic/
+
+# vboxdev
+mkdir -p ~/config/add-ons/kernel/drivers/dev/misc/
+cp $outdir/vboxdev ~/config/add-ons/kernel/drivers/bin/
+ln -sf ../../bin/vboxdev ~/config/add-ons/kernel/drivers/dev/misc
+
+# VBoxMouse
+cp $outdir/VBoxMouse ~/config/add-ons/input_server/devices/
+cp $outdir/VBoxMouseFilter ~/config/add-ons/input_server/filters/
+
+# Services
+mkdir -p $instdir
+cp $outdir/VBoxService $instdir/
+cp $outdir/VBoxTray $instdir/
+cp $outdir/VBoxControl $instdir/
+ln -sf $instdir/VBoxService ~/config/boot/launch
+
diff --git a/src/VBox/Additions/haiku/unload.sh b/src/VBox/Additions/haiku/unload.sh
new file mode 100755
index 00000000..7ed68eb8
--- /dev/null
+++ b/src/VBox/Additions/haiku/unload.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# $Id: unload.sh $
+## @file
+# Driver unload script.
+#
+
+#
+# Copyright (C) 2012-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+basedir=/boot/home/config/add-ons/
+rm -f $basedir/input_server/devices/VBoxMouse
+rm -f $basedir/kernel/drivers/bin/vboxdev
+rm -f $basedir/kernel/drivers/dev/misc/vboxdev
+rm -f $basedir/kernel/file_systems/vboxsf
+rm -f $basedir/kernel/generic/vboxguest
+rm -rf /boot/apps/VBoxAdditions
+