From d2b97d1868c9a97d454ed559a82481d9f29825a5 Mon Sep 17 00:00:00 2001
From: Gerasim Troeglazov <3dEyes@gmail.com>
Date: Sat, 1 Jan 2022 23:26:50 +1000
Subject: Add Haiku support


diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index bc35728..a0b0531 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -95,6 +95,15 @@ PRIVATE
     desktop-app::external_xxhash
 )
 
+if (HAIKU)
+	target_link_libraries(Telegram
+	PRIVATE
+		be
+		jpeg
+		translation
+	)
+endif()
+
 target_precompile_headers(Telegram PRIVATE ${src_loc}/stdafx.h)
 nice_target_sources(Telegram ${src_loc}
 PRIVATE
@@ -1240,6 +1249,16 @@ else()
     )
 endif()
 
+if (HAIKU)
+	remove_target_sources(Telegram ${src_loc}
+		platform/linux/notifications_manager_linux_dummy.cpp
+	)
+    nice_target_sources(Telegram ${src_loc}
+    PRIVATE
+		platform/linux/notifications_manager_haiku.cpp
+    )
+endif()
+
 if (DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
     remove_target_sources(Telegram ${src_loc}
         platform/linux/linux_wayland_integration.cpp
@@ -1379,7 +1398,7 @@ else()
 endif()
 
 set(bundle_identifier "io.github.kotatogram")
-if (LINUX AND DESKTOP_APP_USE_PACKAGED)
+if (LINUX AND NOT HAIKU AND DESKTOP_APP_USE_PACKAGED)
     set(output_name "kotatogram-desktop")
 else()
     set(output_name "Kotatogram")
diff --git a/Telegram/SourceFiles/calls/group/calls_group_menu.cpp b/Telegram/SourceFiles/calls/group/calls_group_menu.cpp
index 0fdaf4c..ea0f606 100644
--- a/Telegram/SourceFiles/calls/group/calls_group_menu.cpp
+++ b/Telegram/SourceFiles/calls/group/calls_group_menu.cpp
@@ -583,6 +583,7 @@ void FillMenu(
 			real->recordStartDateValue(),
 			handler));
 	}
+#ifndef Q_OS_HAIKU
 	if (addScreenCast) {
 		const auto sharing = call->isSharingScreen();
 		const auto toggle = [=] {
@@ -600,6 +601,7 @@ void FillMenu(
 				: tr::lng_group_call_screen_share_start(tr::now)),
 			toggle);
 	}
+#endif
 	menu->addAction(tr::lng_group_call_settings(tr::now), [=] {
 		if (const auto strong = weak.get()) {
 			showBox(Box(SettingsBox, strong));
diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp
index f0248ed..d325571 100644
--- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp
+++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp
@@ -1936,7 +1936,9 @@ void Panel::updateButtonsGeometry() {
 		const auto muteSize = _mute->innerSize().width() + 2 * addSkip;
 		const auto skip = st::groupCallButtonSkipSmall;
 		const auto fullWidth = (_video->width() + skip)
+#ifndef Q_OS_HAIKU
 			+ (_screenShare->width() + skip)
+#endif
 			+ (muteSize + skip)
 			+ (_settings ->width() + skip)
 			+ _hangup->width();
@@ -1947,9 +1949,13 @@ void Panel::updateButtonsGeometry() {
 			- membersWidth
 			- membersSkip
 			- fullWidth) / 2;
+#ifndef Q_OS_HAIKU
 		toggle(_screenShare, !hidden);
 		_screenShare->moveToLeft(left, buttonsTop);
 		left += _screenShare->width() + skip;
+#else
+		toggle(_screenShare, false);
+#endif
 		toggle(_video, !hidden);
 		_video->moveToLeft(left, buttonsTop);
 		left += _video->width() + skip;
diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h
index 4e0b6d6..c7121c5 100644
--- a/Telegram/SourceFiles/core/core_settings.h
+++ b/Telegram/SourceFiles/core/core_settings.h
@@ -784,7 +784,7 @@ private:
 	rpl::variable<float64> _dialogsWidthRatio; // per-window
 	rpl::variable<int> _thirdColumnWidth = kDefaultThirdColumnWidth; // p-w
 	bool _notifyFromAll = true;
-	rpl::variable<bool> _nativeWindowFrame = Platform::IsLinux();
+	rpl::variable<bool> _nativeWindowFrame = true;
 	rpl::variable<std::optional<bool>> _systemDarkMode = std::nullopt;
 	rpl::variable<bool> _systemDarkModeEnabled = false;
 	WindowPosition _windowPosition; // per-window
diff --git a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp
index 453ccfd..c8374f9 100644
--- a/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp
+++ b/Telegram/SourceFiles/platform/linux/file_utilities_linux.cpp
@@ -14,6 +14,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "platform/linux/linux_xdp_open_with_dialog.h"
 #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
 
+#ifdef Q_OS_HAIKU
+#include <base/haiku_types.h>
+#include <InterfaceKit.h>
+#include <StorageKit.h>
+#include <SupportKit.h>
+#include <MimeType.h>
+#include <Roster.h>
+#endif
+
 #include <QtCore/QProcess>
 #include <QtGui/QDesktopServices>
 
@@ -48,6 +57,23 @@ void UnsafeOpenEmailLink(const QString &email) {
 }
 
 bool UnsafeShowOpenWith(const QString &filepath) {
+#ifdef Q_OS_HAIKU	
+	BMessenger trackerMessenger("application/x-vnd.Be-TRAK");
+	if (trackerMessenger.IsValid()) {
+		update_mime_info(filepath.toUtf8().data(), false, true, false);
+
+		BEntry fileEntry(filepath.toUtf8().data());
+		entry_ref fileRef;
+		if (fileEntry.GetRef(&fileRef) == B_OK) {
+			BMessage openCommand(B_REFS_RECEIVED);
+			openCommand.AddRef("refs", &fileRef);
+			openCommand.AddInt32("launchUsingSelector", 0);
+			if (trackerMessenger.SendMessage(&openCommand) == B_OK)
+				return true;
+		}
+	}
+#endif
+
 #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
 	if (internal::ShowXDPOpenWithDialog(filepath)) {
 		return true;
diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp
index 500b5b6..d784700 100644
--- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp
+++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp
@@ -934,11 +934,17 @@ bool MainWindow::hasTrayIcon() const {
 
 bool MainWindow::isActiveForTrayMenu() {
 	updateIsActive();
+#ifdef Q_OS_HAIKU
+	return isVisible();
+#else
 	return Platform::IsWayland() ? isVisible() : isActive();
+#endif
 }
 
 void MainWindow::psShowTrayMenu() {
+#ifndef Q_OS_HAIKU
 	_trayIconMenuXEmbed->popup(QCursor::pos());
+#endif
 }
 
 void MainWindow::psTrayMenuUpdated() {
@@ -977,6 +983,10 @@ void MainWindow::psSetupTrayIcon() {
 		}
 		trayIcon->setIcon(TrayIconGen(counter, muted));
 
+#ifdef Q_OS_HAIKU
+		trayIcon->setContextMenu(trayIconMenu);
+#endif
+
 		attachToTrayIcon(trayIcon);
 	}
 	updateIconCounters();
@@ -1067,8 +1077,10 @@ void MainWindow::updateIconCounters() {
 }
 
 void MainWindow::initTrayMenuHook() {
+#ifndef Q_OS_HAIKU
 	_trayIconMenuXEmbed.emplace(nullptr, trayIconMenu);
 	_trayIconMenuXEmbed->deleteOnHide(false);
+#endif
 }
 
 void MainWindow::createGlobalMenu() {
diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_haiku.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_haiku.cpp
new file mode 100644
index 0000000..8605b28
--- /dev/null
+++ b/Telegram/SourceFiles/platform/linux/notifications_manager_haiku.cpp
@@ -0,0 +1,268 @@
+/* 
+This file is part of Telegram Desktop for Haiku,
+
+For license and copyright information please follow this link:
+https://github.com/desktop-app/legal/blob/master/LEGAL
+
+Copyright (c) 2018-2021 Gerasim Troeglazov, 3dEyes@gmail.com
+*/
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "platform/linux/notifications_manager_linux.h"
+
+#include "window/notifications_utilities.h"
+#include "history/history.h"
+#include "lang/lang_keys.h"
+#include "core/application.h"
+#include "core/core_settings.h"
+#include "main/main_session.h"
+
+#define USE_HAIKU_UINT64
+#include "base/haiku_types.h"
+
+#include <AppKit.h>
+#include <SupportKit.h>
+#include <Notification.h>
+#include <InterfaceKit.h>
+#include <TranslationUtils.h>
+#include <OS.h>
+
+#define NOTIFY_MESSAGE_DEEP	16
+#define NOTIFY_PORT_NAME "tg_notify"
+#define NOTIFY_GATE_NAME "/bin/qnotify"
+#define NOTIFY_MESSAGE 'QNTF'
+
+#include <QObject>
+#include <QString>
+#include <QStringList>
+#include <QTimer>
+
+namespace Platform {
+namespace Notifications {
+
+bool Supported() {
+	return true;
+}
+
+void Finish() {
+}
+
+bool SkipAudio() {
+	return false;
+}
+
+bool SkipToast() {
+	return false;
+}
+
+bool SkipFlashBounce() {
+	return false;
+}
+
+bool SkipAudioForCustom() {
+	return false;
+}
+
+bool SkipToastForCustom() {
+	return false;
+}
+
+bool SkipFlashBounceForCustom() {
+	return false;
+}
+
+bool Enforced() {
+	return false;
+}
+
+bool ByDefault() {
+	return true;
+}
+
+void Create(Window::Notifications::System *system) {
+	if (Core::App().settings().nativeNotifications() && Supported()) {
+		auto result = std::make_unique<Manager>(system);
+		system->setManager(std::move(result));
+		return;
+	}
+	system->setManager(nullptr);
+}
+
+class Manager::Private : public QObject {
+
+public:
+	using Type = Window::Notifications::CachedUserpics::Type;
+	explicit Private(not_null<Manager*> manager, Type type);
+
+	void showNotification(
+		not_null<PeerData*> peer,
+		std::shared_ptr<Data::CloudImageView> &userpicView,
+		MsgId msgId,
+		const QString &title,
+		const QString &subtitle,
+		const QString &msg,
+		DisplayOptions options);
+
+	~Private();
+
+private:
+	void CheckNotificationAction();
+
+	QTimer *_checkNotificationTimer;
+	Window::Notifications::CachedUserpics _cachedUserpics;
+	const not_null<Manager*> _manager;
+	int32 _portId;
+};
+
+Manager::Private::Private(not_null<Manager*> manager, Type type)
+: _cachedUserpics(type)
+, _manager(manager) {
+	_portId = create_port(NOTIFY_MESSAGE_DEEP, NOTIFY_PORT_NAME);
+	_checkNotificationTimer = new QTimer(this);
+	connect(_checkNotificationTimer, &QTimer::timeout, this, &Manager::Private::CheckNotificationAction);
+	_checkNotificationTimer->start(250);
+}
+
+Manager::Private::~Private() {
+	delete _checkNotificationTimer;
+	if (_portId > 0)
+		delete_port(_portId);
+}
+
+void Manager::Private::CheckNotificationAction()
+{
+	ssize_t msgSize;
+
+	do {
+		msgSize = port_buffer_size_etc(_portId, B_RELATIVE_TIMEOUT, 0);
+	} while (msgSize == B_INTERRUPTED);
+
+	if (msgSize < 0)
+		return;
+
+	char* buffer = new(std::nothrow) char[msgSize];
+	if (!buffer)
+		return;
+
+	int32 code;
+	status_t result;
+	do {
+		result = read_port(_portId, &code, buffer, msgSize);
+	} while (result == B_INTERRUPTED);
+
+	BMessage message;
+
+	if (result < 0 || code != NOTIFY_MESSAGE) {
+		delete[] buffer;
+		return;
+	}
+	
+	if (message.Unflatten(buffer) == B_OK) {
+		uint64 sessionId = message.GetUInt64("session", 0);
+		uint64 peerId = message.GetUInt64("peer", 0);
+		int64 messageId = message.GetInt64("message", 0);
+
+		const auto key = FullPeer{
+			.sessionId = sessionId,
+			.peerId = PeerId(peerId)
+		};
+		const auto notificationId = NotificationId{ .full = key, .msgId = messageId };
+
+		crl::on_main(this, [=] {
+			_manager->notificationActivated(notificationId);
+		});
+	}
+	delete[] buffer;
+}
+
+void Manager::Private::showNotification(
+	not_null<PeerData*> peer,
+	std::shared_ptr<Data::CloudImageView> &userpicView,
+	MsgId msgId,
+	const QString &title,
+	const QString &subtitle,
+	const QString &msg,
+	DisplayOptions options) {
+	auto titleText = title;
+	auto subtitleText = subtitle;
+	auto msgText = msg;
+
+	const auto key = options.hideNameAndPhoto
+		? InMemoryKey()
+		: peer->userpicUniqueKey(userpicView);
+
+	auto userpicPath = _cachedUserpics.get(key, peer, userpicView);
+	BBitmap *icon = BTranslationUtils::GetBitmapFile(userpicPath.toUtf8().data());
+	QString args = QString(
+		"mode:port "
+		"target:tg_notify "
+		"session:uint64:%1 "
+		"peer:uint64:%2 "
+		"message:int64:%3")
+		.arg(peer->session().uniqueId()).arg(peer->id.value).arg(msgId.bare);
+	BNotification notify(B_INFORMATION_NOTIFICATION);
+	if (icon)
+		notify.SetIcon(icon);
+	notify.SetGroup("Telegram");
+	notify.SetTitle(titleText.toUtf8().data());
+	notify.SetContent(msgText.toUtf8().data());
+	entry_ref ref;
+	BEntry entry(NOTIFY_GATE_NAME);
+	entry.GetRef(&ref);
+	notify.SetOnClickFile(&ref);
+	notify.AddOnClickArg(BString(args.toUtf8().data()));
+	notify.Send();
+}
+
+Manager::Manager(not_null<Window::Notifications::System*> system)
+: NativeManager(system)
+, _private(std::make_unique<Private>(this, Private::Type::Rounded)) {
+}
+
+Manager::~Manager() = default;
+
+void Manager::doShowNativeNotification(
+		not_null<PeerData*> peer,
+		std::shared_ptr<Data::CloudImageView> &userpicView,
+		MsgId msgId,
+		const QString &title,
+		const QString &subtitle,
+		const QString &msg,
+		DisplayOptions options) {
+	_private->showNotification(
+		peer,
+		userpicView,
+		msgId,
+		title,
+		subtitle,
+		msg,
+		options);
+}
+
+void Manager::doClearAllFast() { }
+
+void Manager::doClearFromItem(not_null<HistoryItem*> item) { }
+
+void Manager::doClearFromHistory(not_null<History*> history) { }
+
+void Manager::doClearFromSession(not_null<Main::Session*> session) { }
+
+bool Manager::doSkipAudio() const {
+	return false;
+}
+
+bool Manager::doSkipToast() const {
+	return false;
+}
+
+bool Manager::doSkipFlashBounce() const {
+	return false;
+}
+
+} // namespace Notifications
+} // namespace Platform
diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp
index 26168ba..1706cbb 100644
--- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp
+++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp
@@ -34,6 +34,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "base/platform/linux/base_linux_xsettings.h"
 #endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
 
+#ifdef Q_OS_HAIKU
+#include <base/haiku_types.h>
+#endif
+
 #include <QtWidgets/QApplication>
 #include <QtWidgets/QStyle>
 #include <QtCore/QStandardPaths>
@@ -44,7 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #ifdef Q_OS_FREEBSD
 #include <malloc_np.h>
-#else // Q_OS_FREEBSD
+#elif !defined (Q_OS_HAIKU) // Q_OS_FREEBSD
 #include <jemalloc/jemalloc.h>
 #endif // Q_OS_FREEBSD
 
@@ -78,6 +82,33 @@ constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_c
 constexpr auto kIBusPortalService = "org.freedesktop.portal.IBus"_cs;
 constexpr auto kWebviewService = "io.github.kotatogram.GtkIntegration.WebviewHelper-%1-%2"_cs;
 
+#ifdef Q_OS_HAIKU
+void HaikuAutostart(bool start) {
+	const auto home = QDir::homePath();
+	if (home.isEmpty()) {
+		return;
+	}
+
+	QFile file(home + "/config/settings/boot/launch/kotatogram-desktop");
+	if (start) {
+		if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+			QTextStream out(&file);
+			out
+				<< "#!/bin/bash" << Qt::endl
+				<< "cd /system/apps" << Qt::endl
+				<< "./Kotatogram -autostart" << " &" << Qt::endl;
+			file.close();
+			file.setPermissions(file.permissions()
+				| QFileDevice::ExeOwner
+				| QFileDevice::ExeGroup
+				| QFileDevice::ExeOther);
+		}
+	} else {
+		file.remove();
+	}
+}
+#endif // Q_OS_HAIKU
+
 #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
 void PortalAutostart(bool start, bool silent) {
 	if (cExeName().isEmpty()) {
@@ -618,37 +649,6 @@ void psActivateProcess(uint64 pid) {
 //	objc_activateProgram();
 }
 
-namespace {
-
-#ifdef __HAIKU__
-void HaikuAutostart(bool start) {
-	const auto home = QDir::homePath();
-	if (home.isEmpty()) {
-		return;
-	}
-
-	QFile file(home + "/config/settings/boot/launch/kotatogram-desktop");
-	if (start) {
-		if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
-			QTextStream out(&file);
-			out
-				<< "#!/bin/bash" << Qt::endl
-				<< "cd /system/apps" << Qt::endl
-				<< "./Kotatogram -autostart" << " &" << Qt::endl;
-			file.close();
-			file.setPermissions(file.permissions()
-				| QFileDevice::ExeOwner
-				| QFileDevice::ExeGroup
-				| QFileDevice::ExeOther);
-		}
-	} else {
-		file.remove();
-	}
-}
-#endif // __HAIKU__
-
-} // namespace
-
 QString psAppDataPath() {
 	// We should not use ~/.TelegramDesktop, since it's a fork.
 	/*
@@ -664,7 +664,11 @@ QString psAppDataPath() {
 	}
 	*/
 
-	return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/';
+#ifdef Q_OS_HAIKU
+	return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + '/';
+#else
+ 	return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/';
+#endif
 }
 
 void psDoCleanup() {
@@ -692,8 +696,9 @@ namespace Platform {
 
 void start() {
 	auto backgroundThread = true;
+#ifndef Q_OS_HAIKU
 	mallctl("background_thread", nullptr, nullptr, &backgroundThread, sizeof(bool));
-
+#endif
 	// Prevent any later calls into setlocale() by Qt
 	QCoreApplicationPrivate::initLocale();
 
@@ -829,7 +834,7 @@ bool OpenSystemSettings(SystemSettingsType type) {
 		} else if (DesktopEnvironment::IsMATE()) {
 			add("mate-volume-control");
 		}
-#ifdef __HAIKU__
+#ifdef Q_OS_HAIKU
 		add("Media");
 #endif // __ HAIKU__
 		add("pavucontrol-qt");
diff --git a/Telegram/cmake/lib_tgvoip.cmake b/Telegram/cmake/lib_tgvoip.cmake
index 68a64ba..319e5b4 100644
--- a/Telegram/cmake/lib_tgvoip.cmake
+++ b/Telegram/cmake/lib_tgvoip.cmake
@@ -116,6 +116,14 @@ if (NOT TGVOIP_FOUND)
         os/linux/AudioPulse.cpp
         os/linux/AudioPulse.h
 
+        # Haiku
+        os/haiku/AudioInputHaiku.cpp
+        os/haiku/AudioInputHaiku.h
+        os/haiku/AudioOutputHaiku.cpp
+        os/haiku/AudioOutputHaiku.h
+        os/haiku/RingBuffer.cpp
+        os/haiku/RingBuffer.h
+
         # POSIX
         os/posix/NetworkSocketPosix.cpp
         os/posix/NetworkSocketPosix.h
@@ -153,6 +161,25 @@ if (NOT TGVOIP_FOUND)
                 TGVOIP_NO_OSX_PRIVATE_API
             )
         endif()
+    elseif (HAIKU)
+        target_compile_definitions(lib_tgvoip_bundled
+        PUBLIC
+           WEBRTC_POSIX
+           WEBRTC_HAIKU
+        )
+        target_compile_options(lib_tgvoip_bundled
+        PRIVATE
+            -Wno-unknown-pragmas
+            -Wno-error=sequence-point
+            -Wno-error=unused-result
+            -mmmx
+            -msse2
+        )
+        target_link_libraries(lib_tgvoip_bundled
+        PRIVATE
+           network
+           media
+        )
     else()
         add_library(lib_tgvoip_bundled_options INTERFACE)
         target_compile_options(lib_tgvoip_bundled_options
-- 
2.30.2

