ref: 5ce54979cf257881bdbfe1e3754cb1d5df4d84cc
parent: 31e15655e642339a90344e6d97d5a788154000e6
author: iyzsong <iyzsong@envs.net>
date: Sat Mar 2 11:00:42 EST 2024
add Haiku port
--- /dev/null
+++ b/Make.haiku
@@ -1,0 +1,21 @@
+# Haiku
+AR=ar
+AS=as
+RANLIB=ranlib
+CC=gcc
+CXX=g++
+CFLAGS=-Wall -Wno-missing-braces -Wno-parentheses -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -D_THREAD_SAFE -D_POSIX_C_SOURCE -O2
+O=o
+OS=posix
+GUI=haiku
+AUDIO=haiku
+LDADD=-ggdb -lbe -lnetwork -lmedia -lstdc++
+LDFLAGS=
+TARG=drawterm
+
+
+all: default
+
+libmachdep.a:
+ arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/; s/armv[567].*/arm/; s/aarch64/arm64/'`; \
+ (cd posix-$$arch && make)
--- /dev/null
+++ b/gui-haiku/Makefile
@@ -1,0 +1,13 @@
+ROOT=..
+include ../Make.config
+LIB=libgui.a
+
+OFILES=screen.$O
+
+default: $(LIB)
+$(LIB): $(OFILES)
+ $(AR) r $(LIB) $(OFILES)
+ $(RANLIB) $(LIB)
+
+screen.$O: screen.cpp
+ $(CXX) -o $@ $(CFLAGS) $<
--- /dev/null
+++ b/gui-haiku/screen.cpp
@@ -1,0 +1,376 @@
+#include <memory>
+#include <Autolock.h>
+#include <Application.h>
+#include <Bitmap.h>
+#include <Clipboard.h>
+#include <Screen.h>
+#include <Window.h>
+#include <Input.h>
+#include <private/input/InputServerTypes.h>
+#include <private/interface/input_globals.h>
+
+extern "C" {
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include "devaudio.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "cursor.h"
+#include "keyboard.h"
+#include "screen.h"
+}
+
+Memimage *gscreen = (Memimage *)nil;
+
+class View : public BView {
+private:
+ std::unique_ptr<BBitmap> bitmap;
+ Mousestate ms;
+
+public:
+ View(BRect frame)
+ : BView(frame, NULL, B_FOLLOW_ALL_SIDES,
+ B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE) {
+ SetViewColor(B_TRANSPARENT_COLOR);
+ bitmap = std::make_unique<BBitmap>(frame, B_RGBA32);
+ }
+
+ void *GetFrameBuffer() { return bitmap->Bits(); }
+
+ void Draw(BRect updateRect) override {
+ qlock(&drawlock);
+ DrawBitmap(bitmap.get(), updateRect, updateRect);
+ qunlock(&drawlock);
+ }
+
+ void MessageReceived(BMessage *message) override {
+ switch (message->what) {
+ case B_VIEW_RESIZED: {
+ int32 width, height;
+ width = message->GetInt32("width", 0);
+ height = message->GetInt32("height", 0);
+ qlock(&drawlock);
+ bitmap = std::make_unique<BBitmap>(BRect(0, 0, width, height), B_RGBA32);
+ memset(bitmap->Bits(), 0xff, bitmap->BitsLength());
+ qunlock(&drawlock);
+ screenresize(Rect(0, 0, width + 1, height + 1));
+ break;
+ }
+
+ case B_KEY_DOWN:
+ case B_UNMAPPED_KEY_DOWN:
+ case B_KEY_UP:
+ case B_UNMAPPED_KEY_UP: {
+ static struct {
+ int8 byte;
+ int32 key;
+ Rune k;
+ } transtab[] = {
+ 0x00, 0x3b, Kcaps,
+ 0x00, 0x5C, Kctl,
+ 0x00, 0x60, Kctl,
+ 0x00, 0x4b, Kshift,
+ 0x00, 0x56, Kshift,
+ 0x00, 0x5d, Kalt,
+ 0x00, 0x5f, Kalt,
+ 0x00, 0x66, Kmod4,
+
+ 0x10, B_F1_KEY, KF | 1,
+ 0x10, B_F2_KEY, KF | 2,
+ 0x10, B_F3_KEY, KF | 3,
+ 0x10, B_F4_KEY, KF | 4,
+ 0x10, B_F5_KEY, KF | 5,
+ 0x10, B_F6_KEY, KF | 6,
+ 0x10, B_F7_KEY, KF | 7,
+ 0x10, B_F8_KEY, KF | 8,
+ 0x10, B_F9_KEY, KF | 9,
+ 0x10, B_F10_KEY, KF | 10,
+ 0x10, B_F11_KEY, KF | 11,
+ 0x10, B_F12_KEY, KF | 12,
+ 0x10, B_PRINT_KEY, Kprint,
+ 0x10, B_SCROLL_KEY, Kscroll,
+ 0x10, B_PAUSE_KEY, Kbreak,
+
+ B_DELETE, 0x34, Kdel,
+ B_INSERT, 0x1f, Kins,
+ B_HOME, 0x20, Khome,
+ B_END, 0x35, Kend,
+ B_PAGE_UP, 0x21, Kpgup,
+ B_PAGE_DOWN, 0x36, Kpgdown,
+ B_UP_ARROW, 0x57, Kup,
+ B_RIGHT_ARROW, 0x63, Kright,
+ B_LEFT_ARROW, 0x61, Kleft,
+ B_DOWN_ARROW, 0x62, Kdown,
+ };
+ int32 key = message->GetInt32("key", 0);
+ int8 byte = message->GetInt8("byte", 0);
+ bool down =
+ message->what == B_KEY_DOWN || message->what == B_UNMAPPED_KEY_DOWN;
+ Rune k = 0;
+ for (int i = 0; i < nelem(transtab); i++){
+ if (key != transtab[i].key || byte != transtab[i].byte)
+ continue;
+ k = transtab[i].k;
+ break;
+ }
+ kbdkey(k == 0 ? byte : k, down);
+ break;
+ }
+
+ case B_MOUSE_MOVED: {
+ BPoint where = message->GetPoint("where", BPoint(0, 0));
+ ms.xy.x = where.x;
+ ms.xy.y = where.y;
+ ms.msec = message->GetInt64("when", 0) / 1000;
+ absmousetrack(ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
+ break;
+ }
+
+ case B_MOUSE_WHEEL_CHANGED: {
+ float delta_y = message->GetFloat("be:wheel_delta_y", 0);
+ int32 buttons = delta_y < 0 ? 8 : 16;
+ ms.msec = message->GetInt64("when", 0) / 1000;
+ absmousetrack(ms.xy.x, ms.xy.y, buttons, ms.msec);
+ break;
+ }
+
+ case B_MOUSE_DOWN:
+ case B_MOUSE_UP: {
+ int32 buttons = message->GetInt32("buttons", 0);
+ ms.msec = message->GetInt64("when", 0) / 1000;
+ ms.buttons = 0;
+ if (buttons & B_MOUSE_BUTTON(1))
+ ms.buttons |= 1;
+ if (buttons & B_MOUSE_BUTTON(2))
+ ms.buttons |= 4;
+ if (buttons & B_MOUSE_BUTTON(3))
+ ms.buttons |= 2;
+ absmousetrack(ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
+ break;
+ }
+
+ default:
+ BView::MessageReceived(message);
+ }
+ }
+};
+
+static void winproc(void *arg) {
+ BWindow *window = (BWindow *)arg;
+ thread_id tid = find_thread(NULL);
+ rename_thread(tid, "window");
+ BAutolock locker(window);
+ window->Loop();
+}
+
+static const uint32 kToggleFullScreen = 'TFSn';
+
+class Window : public BWindow {
+private:
+ BRect fSavedFrame;
+ bool fFullScreen;
+
+ void _ToggleFullScreen() {
+ if (fFullScreen) {
+ ResizeTo(fSavedFrame.Width(), fSavedFrame.Height());
+ MoveTo(fSavedFrame.left, fSavedFrame.top);
+ SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_MOVABLE));
+ fFullScreen = false;
+ } else {
+ BScreen screen(this);
+ BRect frame = screen.Frame();
+ fSavedFrame = Frame();
+ ResizeTo(frame.Width() + 1, frame.Height() + 1);
+ MoveTo(frame.left, frame.top);
+ SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_MOVABLE));
+ fFullScreen = true;
+ }
+ }
+
+public:
+ Window(BRect frame)
+ : BWindow(frame, "drawterm", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE) {
+ fFullScreen = false;
+
+ BMessage *message = new BMessage(kToggleFullScreen);
+ AddShortcut(B_ENTER, B_COMMAND_KEY, message);
+ }
+
+ ~Window() {
+ status_t exit_value;
+ wait_for_thread(Thread(), &exit_value);
+ }
+
+ thread_id Run() override {
+ thread_id tid = 0;
+ if (IsLocked()) {
+ kproc("window", winproc, this);
+ while (tid == 0) {
+ tid = find_thread("window");
+ osmsleep(10);
+ }
+ Unlock();
+ }
+ return tid;
+ }
+
+ bool QuitRequested() override {
+ status_t exit_value;
+ thread_id tid = find_thread("cpu");
+ audiodevclose();
+ kill_thread(tid);
+ wait_for_thread(tid, &exit_value);
+ return BLooper::QuitRequested();
+ }
+
+ void MessageReceived(BMessage *message) override {
+ switch (message->what) {
+ case kToggleFullScreen:
+ _ToggleFullScreen();
+ break;
+ default:
+ BWindow::MessageReceived(message);
+ }
+ }
+};
+
+class Application : public BApplication {
+public:
+ Window *window;
+ View *view;
+
+ Application() : BApplication("application/x-vnd.9front-drawterm") {
+ BRect frame(0, 0, 640 - 1, 480 - 1);
+ window = new Window(frame);
+ view = new View(frame);
+ window->AddChild(view);
+ window->CenterOnScreen();
+ view->MakeFocus();
+ window->Show();
+ }
+};
+#define sApp ((Application *)be_app)
+
+char *clipread(void) {
+ const void *data = NULL;
+ char *ret = NULL;
+ ssize_t textLen;
+ if (be_clipboard->Lock()) {
+ BMessage *clip = be_clipboard->Data();
+ if (clip){
+ clip->FindData("text/plain", B_MIME_TYPE, &data, &textLen);
+ ret = (char*)malloc(textLen + 1);
+ if (ret != NULL){
+ memcpy(ret, data, textLen);
+ ret[textLen] = '\0';
+ }
+ }
+ be_clipboard->Unlock();
+ }
+ return ret;
+}
+
+int clipwrite(char *text) {
+ ssize_t textLen = strlen(text);
+ if (be_clipboard->Lock()) {
+ BMessage *clip = be_clipboard->Data();
+ if (clip) {
+ be_clipboard->Clear();
+ clip->AddData("text/plain", B_MIME_TYPE, text, textLen);
+ be_clipboard->Commit();
+ }
+ be_clipboard->Unlock();
+ }
+ return textLen;
+}
+
+void flushmemscreen(Rectangle r) {
+ BRect rect(r.min.x, r.min.y, r.max.x - 1, r.max.y - 1);
+ BMessage message(B_INVALIDATE);
+ message.AddRect("be:area", rect);
+ sApp->window->PostMessage(&message, sApp->view);
+}
+
+Memdata *attachscreen(Rectangle *r, ulong *chan, int *depth, int *width,
+ int *softscreen) {
+ *r = gscreen->clipr;
+ *chan = gscreen->chan;
+ *depth = gscreen->depth;
+ *width = gscreen->width;
+ *softscreen = 1;
+ gscreen->data->ref++;
+ return gscreen->data;
+}
+
+void getcolor(ulong i, ulong *r, ulong *g, ulong *b) {
+ ulong v;
+ v = cmap2rgb(i);
+ *r = (v >> 16) & 0xFF;
+ *g = (v >> 8) & 0xFF;
+ *b = v & 0xFF;
+}
+
+void setcolor(ulong i, ulong r, ulong g, ulong b) {}
+
+void setcursor(void) {
+ static uint8 data[68];
+ uint8 *p = data;
+ lock(&cursor.lk);
+ *p++ = 16;
+ *p++ = 1;
+ *p++ = -cursor.offset.x;
+ *p++ = -cursor.offset.y;
+ for (int i = 0; i < 32; i++) {
+ p[i] = cursor.set[i];
+ p[i + 32] = cursor.set[i] | cursor.clr[i];
+ }
+ sApp->SetCursor(data);
+ unlock(&cursor.lk);
+}
+
+void mouseset(Point xy) {
+ BAutolock locker(sApp->window);
+ BMessage message(IS_SET_MOUSE_POSITION);
+ BMessage reply;
+ BPoint where(xy.x, xy.y);
+ sApp->view->ConvertToScreen(&where);
+ message.AddPoint("where", where);
+ _control_input_server_(&message, &reply);
+}
+
+void screeninit(void) {
+ BAutolock locker(sApp->window);
+ BRect bounds = sApp->view->Bounds();
+ Rectangle r = Rect(0, 0, bounds.right + 1, bounds.bottom + 1);
+ memimageinit();
+ screensize(r, XRGB32);
+ gscreen->clipr = r;
+ terminit();
+}
+
+static void cpuproc(void *arg) {
+ rename_thread(find_thread(NULL), "cpu");
+ cpubody();
+}
+
+void guimain(void) {
+ Application app;
+ kproc("cpu", cpuproc, nil);
+ app.Run();
+}
+
+void screensize(Rectangle r, ulong chan) {
+ static Memdata md = {
+ .base = 0,
+ .allocd = 0,
+ };
+ if (gscreen != nil)
+ freememimage(gscreen);
+ md.ref = 1;
+ md.bdata = (uchar *)sApp->view->GetFrameBuffer();
+ gscreen = allocmemimaged(r, chan, &md);
+ gscreen->clipr = ZR;
+}
--- a/include/dtos.h
+++ b/include/dtos.h
@@ -1,4 +1,4 @@
-#if defined(linux) || defined(IRIX) || defined(SOLARIS) || defined(OSF1) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined(__sun) || defined(sun) || defined(__OpenBSD__) || defined(__DragonFly__)
+#if defined(linux) || defined(IRIX) || defined(SOLARIS) || defined(OSF1) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined(__sun) || defined(sun) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__HAIKU__)
# include "unix.h"
# ifdef __APPLE__
# define panic dt_panic
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -48,3 +48,5 @@
%.$O: %.c
$(CC) $(CFLAGS) $*.c
+devaudio-haiku.$O: devaudio-haiku.cpp
+ $(CXX) $(CFLAGS) $<
--- /dev/null
+++ b/kern/devaudio-haiku.cpp
@@ -1,0 +1,85 @@
+#include <Autolock.h>
+#include <SoundPlayer.h>
+#include <memory>
+
+extern "C" {
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include "devaudio.h"
+}
+
+static struct {
+ BLocker locker;
+ std::unique_ptr<BSoundPlayer> player;
+ uint8 buffer[44100 * 4 / 10];
+ size_t written;
+} snd;
+
+static void play(void *cookie, void *buffer, size_t size,
+ const media_raw_audio_format &format) {
+ BAutolock locker(&snd.locker);
+ if (snd.written >= size) {
+ memcpy(buffer, snd.buffer, size);
+ snd.written -= size;
+ if (snd.written > 0)
+ memmove(snd.buffer, snd.buffer + size, snd.written);
+ } else {
+ memset(buffer, 0, size);
+ }
+}
+
+void audiodevopen(void) {
+ const media_raw_audio_format format = {
+ .frame_rate = 44100,
+ .channel_count = 2,
+ .format = media_raw_audio_format::B_AUDIO_SHORT,
+ .byte_order = B_MEDIA_LITTLE_ENDIAN,
+ .buffer_size = 4096,
+ };
+ snd.player = std::make_unique<BSoundPlayer>(&format, "devaudio", play);
+ snd.written = 0;
+ if (snd.player->InitCheck() != B_OK) {
+ snd.player.reset(nullptr);
+ return;
+ }
+ snd.player->Start();
+}
+
+void audiodevclose(void) { snd.player.reset(nullptr); }
+
+int audiodevread(void *a, int n) {
+ error("no reading");
+ return -1;
+}
+
+int audiodevwrite(void *a, int n) {
+ int w = n;
+ uint8 *p = (uint8 *)a;
+
+ if (snd.player.get() == nullptr)
+ return -1;
+
+ while (n > 0) {
+ snd.locker.Lock();
+ int max = sizeof(snd.buffer) - snd.written;
+ int x = n > max ? max : n;
+ if (x < 1) {
+ snd.locker.Unlock();
+ osmsleep(10);
+ } else {
+ memcpy(snd.buffer + snd.written, p, x);
+ snd.written += x;
+ p += x;
+ n -= x;
+ snd.locker.Unlock();
+ }
+ }
+ return w;
+}
+
+void audiodevsetvol(int what, int left, int right) { error("not supported"); }
+
+void audiodevgetvol(int what, int *left, int *right) { error("not supported"); }