Files
haikuports/app-emulation/qemu/patches/qemu-8.2.2-haiku.patchset
DalmeGNU bdd874cc3a qemu: set haiku native display as default (#11479)
(instead of broken SDL display)
2024-12-19 08:11:43 +01:00

1584 lines
43 KiB
Plaintext

From 19b2d4851c80fce6cfe6982917089d4a2e130a3b Mon Sep 17 00:00:00 2001
From: David Karoly <david.karoly@outlook.com>
Date: Sat, 4 Feb 2023 13:39:11 +0100
Subject: introduce Haiku ui
diff --git a/meson.build b/meson.build
index aea6184..f69a9b1 100644
--- a/meson.build
+++ b/meson.build
@@ -29,6 +29,10 @@ if targetos == 'darwin' and \
all_languages += ['objc']
objc = meson.get_compiler('objc')
endif
+if targetos == 'haiku' and add_languages('cpp', required: false, native: false)
+ all_languages += ['cpp']
+ cxx = meson.get_compiler('cpp')
+endif
# Temporary directory used for files created while
# configure runs. Since it is in the build directory
@@ -601,6 +605,7 @@ hvf = not_found
midl = not_found
widl = not_found
pathcch = not_found
+haiku = not_found
host_dsosuf = '.so'
if targetos == 'windows'
midl = find_program('midl', required: false)
@@ -626,6 +631,11 @@ elif targetos == 'haiku'
socket = [cc.find_library('posix_error_mapper'),
cc.find_library('network'),
cc.find_library('bsd')]
+ if not get_option('haiku').disabled()
+ haikulibs = [cc.find_library('be'),
+ cc.find_library('game')]
+ haiku = declare_dependency(dependencies: haikulibs)
+ endif
elif targetos == 'openbsd'
if get_option('tcg').allowed() and target_dirs.length() > 0
# Disable OpenBSD W^X if available
@@ -2108,6 +2118,7 @@ config_host_data.set('CONFIG_COCOA', cocoa.found())
config_host_data.set('CONFIG_DARWIN', targetos == 'darwin')
config_host_data.set('CONFIG_FUZZ', get_option('fuzzing'))
config_host_data.set('CONFIG_GCOV', get_option('b_coverage'))
+config_host_data.set('CONFIG_HAIKU', haiku.found())
config_host_data.set('CONFIG_LIBUDEV', libudev.found())
config_host_data.set('CONFIG_LINUX', targetos == 'linux')
config_host_data.set('CONFIG_POSIX', targetos != 'windows')
@@ -4288,6 +4299,9 @@ summary_info = {}
if targetos == 'darwin'
summary_info += {'Cocoa support': cocoa}
endif
+if targetos == 'haiku'
+ summary_info += {'Haiku support': haiku}
+endif
summary_info += {'SDL support': sdl}
summary_info += {'SDL image support': sdl_image}
summary_info += {'GTK support': gtk}
diff --git a/meson_options.txt b/meson_options.txt
index c9baeda..9f6d560 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -144,6 +144,8 @@ option('bpf', type : 'feature', value : 'auto',
description: 'eBPF support')
option('cocoa', type : 'feature', value : 'auto',
description: 'Cocoa user interface (macOS only)')
+option('haiku', type : 'feature', value : 'auto',
+ description: 'Haiku user interface (Haiku only)')
option('curl', type : 'feature', value : 'auto',
description: 'CURL block device driver')
option('gio', type : 'feature', value : 'auto',
diff --git a/qapi/ui.json b/qapi/ui.json
index a0158ba..0744f10 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1493,6 +1493,7 @@
{ 'name': 'egl-headless', 'if': 'CONFIG_OPENGL' },
{ 'name': 'curses', 'if': 'CONFIG_CURSES' },
{ 'name': 'cocoa', 'if': 'CONFIG_COCOA' },
+ { 'name': 'haiku', 'if': 'CONFIG_HAIKU' },
{ 'name': 'spice-app', 'if': 'CONFIG_SPICE' },
{ 'name': 'dbus', 'if': 'CONFIG_DBUS_DISPLAY' }
]
diff --git a/ui/console.c b/ui/console.c
index 8320556..bf60b55 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1623,6 +1623,9 @@ bool qemu_display_find_default(DisplayOptions *opts)
#endif
#if defined(CONFIG_COCOA)
DISPLAY_TYPE_COCOA
+#endif
+#if defined(CONFIG_HAIKU)
+ DISPLAY_TYPE_HAIKU
#endif
};
int i;
diff --git a/ui/haiku.cpp b/ui/haiku.cpp
new file mode 100644
index 0000000..46f99de
--- /dev/null
+++ b/ui/haiku.cpp
@@ -0,0 +1,908 @@
+/*
+ * QEMU Haiku display driver
+ *
+ * Copyright (c) 2005-2013 Michael Lotz
+ *
+ * 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 "haiku.h"
+
+#include <Cursor.h>
+#include <Path.h>
+#include <Screen.h>
+#include <WindowScreen.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <signal.h>
+
+struct QemuConsole;
+
+static QEMUApplication *sApplication = NULL;
+static QEMUWindow *sWindow = NULL;
+static QEMUView *sView = NULL;
+static bool sFullScreen = false;
+static QemuConsole *sCurrentConsole = NULL;
+static bool sGraphicConsole = false;
+static bool sAbsoluteMouse = false;
+static bool sGrabInput = false;
+static int sWidth = 100;
+static int sHeight = 100;
+static BPoint sCenter;
+static BPoint sPreviousLocation;
+static thread_id sMainThread = -1;
+
+static const uint32 kMessageBlockSignals = 'bksg';
+
+static const uint32 kKeycodeEvent = 'keyc';
+static const uint32 kKeysymEvent = 'keys';
+static const uint32 kMouseEvent = 'mous';
+static const uint32 kConsoleSelectEvent = 'cons';
+static const uint32 kShutdownRequest = 'shut';
+static const uint32 kInvalidationRequest = 'ival';
+
+
+// QEMU C interface
+extern "C" {
+#define new _new
+#define class _class
+#define typename _typename
+ // Guard against reserved keywords in C includes
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu-main.h"
+#include "ui/console.h"
+#include "ui/input.h"
+
+#undef new
+#undef class
+#undef typename
+
+static void haiku_refresh(DisplayChangeListener *dcl);
+static void haiku_update(DisplayChangeListener *dcl, int x, int y, int w,
+ int h);
+static void haiku_switch(DisplayChangeListener *dcl,
+ DisplaySurface *newSurface);
+
+ void qemu_system_shutdown_request(void);
+};
+
+
+// Haiku keycode to scancode table
+static const uint8
+haiku_to_pc_key[] = {
+ 0x00, /* 0x00 */ 0x01, /* 0x01 Esc */
+ 0x3b, /* 0x02 F1 */ 0x3c, /* 0x03 F2 */
+ 0x3d, /* 0x04 F3 */ 0x3e, /* 0x05 F4 */
+ 0x3f, /* 0x06 F5 */ 0x40, /* 0x07 F6 */
+ 0x41, /* 0x08 F7 */ 0x42, /* 0x09 F8 */
+ 0x43, /* 0x0a F9 */ 0x44, /* 0x0b F10 */
+ 0x57, /* 0x0c F11 */ 0x58, /* 0x0d F12 */
+ 0xb7, /* 0x0e Print Screen */ 0x46, /* 0x0f Scroll Lock */
+ 0xc5, /* 0x10 Pause */ 0x29, /* 0x11 Grave */
+ 0x02, /* 0x12 1 */ 0x03, /* 0x13 2 */
+ 0x04, /* 0x14 3 */ 0x05, /* 0x15 4 */
+ 0x06, /* 0x16 5 */ 0x07, /* 0x17 6 */
+ 0x08, /* 0x18 7 */ 0x09, /* 0x19 8 */
+ 0x0a, /* 0x1a 9 */ 0x0b, /* 0x1b 0 */
+ 0x0c, /* 0x1c Minus */ 0x0d, /* 0x1d Equals */
+ 0x0e, /* 0x1e Backspace */ 0xd2, /* 0x1f Insert */
+ 0xc7, /* 0x20 Home */ 0xc9, /* 0x21 Page Up */
+ 0x45, /* 0x22 Num Lock */ 0xb5, /* 0x23 KP Divide */
+ 0x37, /* 0x24 KP Multiply */ 0x4a, /* 0x25 KP Subtract */
+ 0x0f, /* 0x26 Tab */ 0x10, /* 0x27 Q */
+ 0x11, /* 0x28 W */ 0x12, /* 0x29 E */
+ 0x13, /* 0x2a R */ 0x14, /* 0x2b T */
+ 0x15, /* 0x2c Y */ 0x16, /* 0x2d U */
+ 0x17, /* 0x2e I */ 0x18, /* 0x2f O */
+ 0x19, /* 0x30 P */ 0x1a, /* 0x31 Left Bracket */
+ 0x1b, /* 0x32 Right Bracket */ 0x2b, /* 0x33 Backslash */
+ 0xd3, /* 0x34 Delete */ 0xcf, /* 0x35 End */
+ 0xd1, /* 0x36 Page Down */ 0x47, /* 0x37 KP 7 */
+ 0x48, /* 0x38 KP 8 */ 0x49, /* 0x39 KP 9 */
+ 0x4e, /* 0x3a KP Add */ 0x3a, /* 0x3b Caps Lock */
+ 0x1e, /* 0x3c A */ 0x1f, /* 0x3d S */
+ 0x20, /* 0x3e D */ 0x21, /* 0x3f F */
+ 0x22, /* 0x40 G */ 0x23, /* 0x41 H */
+ 0x24, /* 0x42 J */ 0x25, /* 0x43 K */
+ 0x26, /* 0x44 L */ 0x27, /* 0x45 Semicolon */
+ 0x28, /* 0x46 Single Quote */ 0x1c, /* 0x47 Enter */
+ 0x4b, /* 0x48 KP 4 */ 0x4c, /* 0x49 KP 5 */
+ 0x4d, /* 0x4a KP 6 */ 0x2a, /* 0x4b Left Shift */
+ 0x2c, /* 0x4c Z */ 0x2d, /* 0x4d X */
+ 0x2e, /* 0x4e C */ 0x2f, /* 0x4f V */
+ 0x30, /* 0x50 B */ 0x31, /* 0x51 N */
+ 0x32, /* 0x52 M */ 0x33, /* 0x53 Comma */
+ 0x34, /* 0x54 Period */ 0x35, /* 0x55 Slash */
+ 0x36, /* 0x56 Right Shift */ 0xc8, /* 0x57 Up */
+ 0x4f, /* 0x58 KP 1 */ 0x50, /* 0x59 KP 2 */
+ 0x51, /* 0x5a KP 3 */ 0x9c, /* 0x5b KP Enter */
+ 0x1d, /* 0x5c Left Control */ 0x38, /* 0x5d Left Alt */
+ 0x39, /* 0x5e Space */ 0xb8, /* 0x5f Right Alt */
+ 0x9d, /* 0x60 Right Control */ 0xcb, /* 0x61 Left */
+ 0xd0, /* 0x62 Down */ 0xcd, /* 0x63 Right */
+ 0x52, /* 0x64 KP 0 */ 0x53, /* 0x65 KP . */
+ 0xdb, /* 0x66 Left Windows */ 0xdc, /* 0x67 Right Windows */
+ 0xdd, /* 0x68 Menu */ 0x56, /* 0x69 */
+ 0x7d, /* 0x6a Macron */ 0x73, /* 0x6b Backslash */
+ 0x7b, /* 0x6c Muhenkan */ 0x79, /* 0x6d Henkan */
+ 0x70, /* 0x6e Hiragana Katakana */ 0x00, /* 0x6f */
+ 0x00, /* 0x70 */ 0x00, /* 0x71 */
+ 0x00, /* 0x72 */ 0x00, /* 0x73 */
+ 0x00, /* 0x74 */ 0x00, /* 0x75 */
+ 0x00, /* 0x76 */ 0x00, /* 0x77 */
+ 0x00, /* 0x78 */ 0x00, /* 0x79 */
+ 0x00, /* 0x7a */ 0x00, /* 0x7b */
+ 0x00, /* 0x7c */ 0x00, /* 0x7d */
+ 0x54, /* 0x7e Alt SysRq */ 0xc6, /* 0x7f Control Break */
+};
+
+
+// Key constants from vl.h
+#define QEMU_KEY_ESC1(c) ((c) | 0xe100)
+#define QEMU_KEY_BACKSPACE 0x007f
+#define QEMU_KEY_UP QEMU_KEY_ESC1('A')
+#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B')
+#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C')
+#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D')
+#define QEMU_KEY_HOME QEMU_KEY_ESC1(1)
+#define QEMU_KEY_END QEMU_KEY_ESC1(4)
+#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5)
+#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6)
+#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3)
+
+#define QEMU_KEY_CTRL_UP 0xe400
+#define QEMU_KEY_CTRL_DOWN 0xe401
+#define QEMU_KEY_CTRL_LEFT 0xe402
+#define QEMU_KEY_CTRL_RIGHT 0xe403
+#define QEMU_KEY_CTRL_HOME 0xe404
+#define QEMU_KEY_CTRL_END 0xe405
+#define QEMU_KEY_CTRL_PAGEUP 0xe406
+#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
+
+
+static void
+haiku_register_display_change_listener(void)
+{
+ static const DisplayChangeListenerOps sDisplayChangeListenerOps = {
+ .dpy_name = "haiku",
+ .dpy_refresh = haiku_refresh,
+ .dpy_gfx_update = haiku_update,
+ .dpy_gfx_switch = haiku_switch,
+ };
+
+ static DisplayChangeListener sDisplayChangeListener = {
+ .ops = &sDisplayChangeListenerOps,
+ };
+
+ register_displaychangelistener(&sDisplayChangeListener);
+}
+
+
+static void
+block_signals(bool block)
+{
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR1);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask(block ? SIG_BLOCK : SIG_UNBLOCK, &set, NULL);
+}
+
+
+static int
+haiku_main(void)
+{
+ block_signals(true);
+ sMainThread = find_thread(NULL);
+ QEMUApplication *app = new QEMUApplication();
+
+ sApplication->InitDisplay();
+ haiku_register_display_change_listener();
+
+ app->Run();
+ delete app;
+ return 0;
+}
+
+
+QEMUApplication::QEMUApplication()
+ : BApplication("application/x-vnd.mmlr.QEMU"),
+ fThread(0),
+ fWindow(NULL)
+{
+ sApplication = this;
+
+ qemu_mutex_unlock_iothread();
+ fThread = spawn_thread(&RunQEMUMain, "qemu_main", B_LOW_PRIORITY, this);
+ resume_thread(fThread);
+}
+
+
+bool
+QEMUApplication::QuitRequested()
+{
+ if (sView != NULL)
+ sView->QueueShutdownRequest();
+ return true;
+}
+
+
+void
+QEMUApplication::InitDisplay()
+{
+ fWindow = new QEMUWindow();
+ fWindow->Show();
+
+ BMessage reply;
+ BMessenger(fWindow->Looper()).SendMessage(kMessageBlockSignals , &reply);
+}
+
+
+int32
+QEMUApplication::RunQEMUMain(void *arg)
+{
+ QEMUApplication *app = (QEMUApplication *)arg;
+
+ block_signals(false);
+
+ qemu_mutex_lock_iothread();
+ qemu_default_main();
+ qemu_mutex_unlock_iothread();
+
+ app->PostMessage(B_QUIT_REQUESTED);
+ return B_OK;
+}
+
+
+QEMUWindow::QEMUWindow()
+ : BWindow(BRect(100, 100, 150, 150), "QEMU", B_TITLED_WINDOW,
+ B_QUIT_ON_WINDOW_CLOSE | B_NOT_RESIZABLE)
+{
+ sWindow = this;
+ fView = new QEMUView(Bounds());
+ AddChild(fView);
+}
+
+
+void
+QEMUWindow::MessageReceived(BMessage *message)
+{
+ if (message->what == kMessageBlockSignals) {
+ block_signals(true);
+ return;
+ }
+
+ BWindow::MessageReceived(message);
+}
+
+
+QEMUView::QEMUView(BRect frame)
+ : BView(frame, "fView", B_FOLLOW_ALL, B_WILL_DRAW),
+ fBitmap(NULL)
+{
+ sView = this;
+ fBitmap = new BBitmap(frame, 0, B_RGBA32);
+ AddFilter(new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, &MessageFilter));
+}
+
+
+QEMUView::~QEMUView()
+{
+ if (sFullScreen)
+ BScreen().SetMode(&fDisplayMode);
+}
+
+
+void
+QEMUView::AttachedToWindow()
+{
+ MakeFocus();
+}
+
+
+void
+QEMUView::UpdateFullScreen()
+{
+ if (!sFullScreen)
+ return;
+
+ BScreen screen;
+ display_mode current;
+ display_mode *modes;
+ display_mode *mode;
+ uint32 count;
+
+ screen.GetMode(&current);
+ screen.GetModeList(&modes, &count);
+
+ for (uint32 i = 0; i < count; i++) {
+ mode = &modes[i];
+ if (mode->virtual_width == sWidth
+ && mode->virtual_height == sHeight
+ && mode->space == current.space) {
+ screen.SetMode(mode);
+ break;
+ }
+ }
+
+ sWindow->MoveTo(0, 0);
+}
+
+
+void
+QEMUView::CenterMouse(bool &warp)
+{
+ BRect window = sWindow->Frame();
+ BPoint center = window.LeftTop() + sCenter;
+ set_mouse_position((int32)center.x, (int32)center.y);
+ warp = true;
+}
+
+
+void
+QEMUView::StartGrab(bool &grab)
+{
+ sApplication->HideCursor();
+ sWindow->SetTitle("QEMU - Press Ctrl-Alt to exit grab");
+ grab = true;
+}
+
+
+void
+QEMUView::EndGrab(bool &grab, int32 modifiers)
+{
+ sApplication->ShowCursor();
+ sWindow->SetTitle("QEMU");
+ grab = false;
+
+ // reset any set modifiers
+ if (modifiers & B_LEFT_SHIFT_KEY)
+ QueueKeycode(0x2a, false);
+ if (modifiers & B_RIGHT_SHIFT_KEY)
+ QueueKeycode(0x36, false);
+
+ if (modifiers & B_LEFT_COMMAND_KEY)
+ QueueKeycode(0x38, false);
+ if (modifiers & B_RIGHT_COMMAND_KEY)
+ QueueKeycode(0xb8, false);
+
+ if (modifiers & B_LEFT_CONTROL_KEY)
+ QueueKeycode(0x1d, false);
+ if (modifiers & B_RIGHT_CONTROL_KEY)
+ QueueKeycode(0x9d, false);
+
+ if (modifiers & B_LEFT_OPTION_KEY)
+ QueueKeycode(0xdb, false);
+ if (modifiers & B_RIGHT_OPTION_KEY)
+ QueueKeycode(0xdc, false);
+}
+
+
+void
+QEMUView::QueueEvent(BMessage *event)
+{
+ if (!fEventQueue.Lock())
+ return;
+
+ fEventQueue.AddMessage(event);
+ fEventQueue.Unlock();
+}
+
+
+void
+QEMUView::QueueKeycode(uint8 keycode, bool keyDown)
+{
+ BMessage *event = new BMessage(kKeycodeEvent);
+ event->AddUInt8("keycode", keycode);
+ event->AddBool("keyDown", keyDown);
+ sView->QueueEvent(event);
+}
+
+
+void
+QEMUView::QueueKeysym(int32 keysym)
+{
+ BMessage *event = new BMessage(kKeysymEvent);
+ event->AddInt32("keysym", keysym);
+ sView->QueueEvent(event);
+}
+
+
+void
+QEMUView::QueueMouseEvent(BPoint where, int32 deltaZ, int32 buttonState)
+{
+ int32 deltaX = where.x;
+ int32 deltaY = where.y;
+
+ if (!sAbsoluteMouse) {
+ deltaX -= sCenter.x;
+ deltaY -= sCenter.y;
+ }
+
+ BMessage *event = new BMessage(kMouseEvent);
+ event->AddInt32("deltaX", deltaX);
+ event->AddInt32("deltaY", deltaY);
+ event->AddInt32("deltaZ", deltaZ);
+ event->AddInt32("buttonState", buttonState);
+ sView->QueueEvent(event);
+}
+
+
+void
+QEMUView::QueueShutdownRequest()
+{
+ sView->QueueEvent(new BMessage(kShutdownRequest));
+}
+
+
+void
+QEMUView::QueueConsoleSelect(uint8 console)
+{
+ BMessage *event = new BMessage(kConsoleSelectEvent);
+ event->AddUInt8("console", console);
+ sView->QueueEvent(event);
+}
+
+
+void
+QEMUView::QueueInvalidation()
+{
+ sView->QueueEvent(new BMessage(kInvalidationRequest));
+}
+
+
+void
+QEMUView::ProcessEvents()
+{
+ while (true) {
+ if (!fEventQueue.Lock())
+ return;
+
+ BMessage *event = fEventQueue.NextMessage();
+ fEventQueue.Unlock();
+
+ if (event == NULL)
+ return;
+
+ switch (event->what) {
+ case kKeycodeEvent:
+ {
+ uint8 keycode = 0;
+ bool keyDown = false;
+ if (event->FindUInt8("keycode", &keycode) != B_OK
+ || event->FindBool("keyDown", &keyDown) != B_OK) {
+ break;
+ }
+
+ qemu_input_event_send_key_number(sCurrentConsole, keycode,
+ keyDown);
+ break;
+ }
+
+ case kKeysymEvent:
+ {
+ int32 keysym = 0;
+ if (event->FindInt32("keysym", &keysym) != B_OK)
+ break;
+
+ qemu_text_console_put_keysym(NULL, keysym);
+ break;
+ }
+
+ case kMouseEvent:
+ {
+ int32 deltaX = 0;
+ int32 deltaY = 0;
+ int32 deltaZ = 0;
+ int32 buttonState = 0;
+ if (event->FindInt32("deltaX", &deltaX) != B_OK
+ || event->FindInt32("deltaY", &deltaY) != B_OK
+ || event->FindInt32("deltaZ", &deltaZ) != B_OK
+ || event->FindInt32("buttonState", &buttonState) != B_OK) {
+ break;
+ }
+
+ if (sAbsoluteMouse) {
+ qemu_input_queue_abs(sCurrentConsole, INPUT_AXIS_X, deltaX,
+ 0, sWidth);
+ qemu_input_queue_abs(sCurrentConsole, INPUT_AXIS_Y, deltaY,
+ 0, sHeight);
+ } else {
+ qemu_input_queue_rel(sCurrentConsole, INPUT_AXIS_X, deltaX);
+ qemu_input_queue_rel(sCurrentConsole, INPUT_AXIS_Y, deltaY);
+ }
+
+ static int32 lastButtonState = 0;
+ if (lastButtonState != buttonState) {
+ // Haiku buttons are the same as QEMU
+ static uint32_t buttonMap[INPUT_BUTTON__MAX] = {
+ [INPUT_BUTTON_LEFT] = B_PRIMARY_MOUSE_BUTTON,
+ [INPUT_BUTTON_MIDDLE] = B_TERTIARY_MOUSE_BUTTON,
+ [INPUT_BUTTON_RIGHT] = B_SECONDARY_MOUSE_BUTTON
+ };
+
+ qemu_input_update_buttons(sCurrentConsole, buttonMap,
+ lastButtonState, buttonState);
+ lastButtonState = buttonState;
+ }
+
+ qemu_input_event_sync();
+
+ if (deltaZ != 0) {
+ qemu_input_queue_btn(sCurrentConsole, deltaZ < 0
+ ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN,
+ true);
+ qemu_input_event_sync();
+ qemu_input_queue_btn(sCurrentConsole, deltaZ < 0
+ ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN,
+ false);
+ qemu_input_event_sync();
+ }
+
+ break;
+ }
+
+ case kShutdownRequest:
+ qemu_system_shutdown_request();
+ break;
+
+ case kConsoleSelectEvent:
+ {
+ uint8 console = 0;
+ if (event->FindUInt8("console", &console) != B_OK)
+ break;
+
+ console_select(console);
+ sCurrentConsole = qemu_console_lookup_by_index(console);
+ sGraphicConsole = qemu_console_is_graphic(NULL);
+ break;
+ }
+
+ case kInvalidationRequest:
+ graphic_hw_invalidate(NULL);
+ graphic_hw_update(NULL);
+ break;
+ }
+
+ delete event;
+ }
+}
+
+
+filter_result
+QEMUView::MessageFilter(BMessage *message, BHandler **target,
+ BMessageFilter *filter)
+{
+ static bool sMouseWarp = false;
+ static int32 sMouseButtons = 0;
+ static BPoint sMousePosition;
+ bool keyDown = false;
+
+ switch (message->what) {
+ case B_KEY_DOWN:
+ case B_UNMAPPED_KEY_DOWN:
+ keyDown = true;
+ // fall
+
+ case B_KEY_UP:
+ case B_UNMAPPED_KEY_UP: {
+ int32 modifiers;
+ message->FindInt32("modifiers", &modifiers);
+
+ int32 key;
+ message->FindInt32("key", &key);
+ uint8 keycode = haiku_to_pc_key[(uint8)key];
+
+ int32 mask = (B_COMMAND_KEY | B_CONTROL_KEY);
+ if (!keyDown && sGrabInput && (modifiers & mask)
+ && (key == 0x5d || key == 0x5c)) {
+ EndGrab(sGrabInput, modifiers);
+ return B_SKIP_MESSAGE;
+ }
+
+ if (keyDown && (modifiers & mask) == mask) {
+ switch (key) {
+ case 0x3f: { /* f - fullscreen */
+ BScreen screen;
+ if (!sFullScreen) {
+ screen.GetMode(&sView->fDisplayMode);
+ sWindow->MoveTo(0, 0);
+ sFullScreen = true;
+ } else {
+ screen.SetMode(&sView->fDisplayMode);
+ sWindow->MoveTo(sView->fWindowLocation);
+ sFullScreen = false;
+ }
+
+ UpdateFullScreen();
+ QueueInvalidation();
+ return B_SKIP_MESSAGE;
+ } break;
+
+ case 0x52: { /* m - pseudo fullscreen */
+ BPoint location = sWindow->Frame().LeftTop();
+ if (location.x == 0 && location.y == 0)
+ sWindow->MoveTo(sPreviousLocation);
+ else {
+ sPreviousLocation = location;
+ sWindow->MoveTo(0, 0);
+ }
+
+ QueueInvalidation();
+ return B_SKIP_MESSAGE;
+ } break;
+
+ case 0x12 ... 0x1a: { /* 1 to 9 - switch console */
+ QueueConsoleSelect(key - 0x12);
+ QueueInvalidation();
+ return B_SKIP_MESSAGE;
+ } break;
+ }
+ } else if (!sGraphicConsole) {
+ if (!keyDown)
+ return B_SKIP_MESSAGE;
+
+ int32 rawChar;
+ message->FindInt32("raw_char", &rawChar);
+
+ int keysym = 0;
+ if (modifiers & (B_LEFT_CONTROL_KEY | B_RIGHT_CONTROL_KEY)) {
+ switch(rawChar) {
+ case B_UP_ARROW: keysym = QEMU_KEY_CTRL_UP; break;
+ case B_DOWN_ARROW: keysym = QEMU_KEY_CTRL_DOWN; break;
+ case B_LEFT_ARROW: keysym = QEMU_KEY_CTRL_LEFT; break;
+ case B_RIGHT_ARROW: keysym = QEMU_KEY_CTRL_RIGHT; break;
+ case B_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
+ case B_END: keysym = QEMU_KEY_CTRL_END; break;
+ case B_PAGE_UP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
+ case B_PAGE_DOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
+ }
+ } else {
+ switch(rawChar) {
+ case B_UP_ARROW: keysym = QEMU_KEY_UP; break;
+ case B_DOWN_ARROW: keysym = QEMU_KEY_DOWN; break;
+ case B_LEFT_ARROW: keysym = QEMU_KEY_LEFT; break;
+ case B_RIGHT_ARROW: keysym = QEMU_KEY_RIGHT; break;
+ case B_HOME: keysym = QEMU_KEY_HOME; break;
+ case B_END: keysym = QEMU_KEY_END; break;
+ case B_PAGE_UP: keysym = QEMU_KEY_PAGEUP; break;
+ case B_PAGE_DOWN: keysym = QEMU_KEY_PAGEDOWN; break;
+ case B_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
+ case B_DELETE: keysym = QEMU_KEY_DELETE; break;
+ }
+ }
+
+ if (keysym)
+ QueueKeysym(keysym);
+ else {
+ const char *bytes;
+ if (message->FindString("bytes", &bytes) == B_OK && bytes[0] != 0)
+ QueueKeysym(bytes[0]);
+ }
+ return B_SKIP_MESSAGE;
+ }
+
+ QueueKeycode(keycode, keyDown);
+ return B_SKIP_MESSAGE;
+ } break;
+
+ case B_MOUSE_MOVED: {
+ if (!sGrabInput && !sAbsoluteMouse)
+ break;
+
+ if (sMouseWarp) {
+ sMouseWarp = false;
+ return B_SKIP_MESSAGE;
+ }
+
+ int32 transit;
+ if (message->FindInt32("be:transit", &transit) == B_OK
+ && transit != B_ENTERED_VIEW && transit != B_INSIDE_VIEW) {
+ break;
+ }
+
+ message->FindPoint("where", &sMousePosition);
+
+ QueueMouseEvent(sMousePosition, 0, sMouseButtons);
+
+ if (!sAbsoluteMouse)
+ CenterMouse(sMouseWarp);
+
+ return B_SKIP_MESSAGE;
+ } break;
+
+ case B_MOUSE_DOWN:
+ case B_MOUSE_UP: {
+ int32 buttons;
+ message->FindInt32("buttons", &buttons);
+
+ if (!sGrabInput && !sAbsoluteMouse) {
+ if (message->what == B_MOUSE_DOWN
+ && (buttons & B_PRIMARY_MOUSE_BUTTON)) {
+ CenterMouse(sMouseWarp);
+ StartGrab(sGrabInput);
+ }
+ break;
+ }
+
+ sMouseButtons = buttons;
+ message->FindPoint("where", &sMousePosition);
+
+ QueueMouseEvent(sMousePosition, 0, sMouseButtons);
+ return B_SKIP_MESSAGE;
+ } break;
+
+ case B_MOUSE_WHEEL_CHANGED: {
+ if (!sGrabInput && !sAbsoluteMouse)
+ break;
+
+ float delta;
+ message->FindFloat("be:wheel_delta_y", &delta);
+
+ QueueMouseEvent(sMousePosition, (int32)delta, sMouseButtons);
+ return B_SKIP_MESSAGE;
+ } break;
+ }
+
+ return B_DISPATCH_MESSAGE;
+}
+
+
+void
+QEMUView::Update(BPoint point, int width, int height)
+{
+ LockLooper();
+ fBitmap->ImportBits(fFrameBuffer, fFrameBufferSize, fBytesPerRow,
+ fColorSpace, point, point, BSize(width, height));
+
+ Invalidate(BRect(point.x, point.y, point.x + width, point.y + height));
+ UnlockLooper();
+}
+
+
+void
+QEMUView::Draw(BRect updateRect)
+{
+ if (fBitmap == NULL)
+ return;
+
+ DrawBitmap(fBitmap, updateRect, updateRect);
+}
+
+
+void
+QEMUView::UpdateFrameBuffer(int width, int height, uchar *bits,
+ int bytesPerRow, int bitsPerPixel)
+{
+ if (LockLooper()) {
+ delete fBitmap;
+ fBitmap = new BBitmap(BRect(0, 0, width - 1, height - 1), 0, B_RGBA32);
+ fFrameBuffer = bits;
+ fFrameBufferSize = bytesPerRow * height;
+ fBytesPerRow = bytesPerRow;
+
+ switch (bitsPerPixel) {
+ case 32:
+ fColorSpace = B_RGB32;
+ break;
+ case 24:
+ fColorSpace = B_RGB24;
+ break;
+ case 16:
+ fColorSpace = B_RGB16;
+ break;
+ case 15:
+ fColorSpace = B_RGB15;
+ break;
+ case 8:
+ fColorSpace = B_CMAP8;
+ break;
+ default:
+ printf("unsupported display depth %d\n", bitsPerPixel);
+ break;
+ }
+
+ UnlockLooper();
+ }
+}
+
+
+static void
+haiku_refresh(DisplayChangeListener *dcl)
+{
+ //printf(">haiku_refresh\n");
+ sView->ProcessEvents();
+ if (sGraphicConsole)
+ graphic_hw_update(NULL);
+ //printf("<haiku_refresh\n");
+}
+
+
+static void
+haiku_update(DisplayChangeListener *dcl, int x, int y, int w, int h)
+{
+ //printf(">haiku_update x=%d y=%d w=%d h=%d\n", x, y, w, h);
+ sView->Update(BPoint(x, y), w, h);
+ //printf("<haiku_update\n");
+}
+
+
+static void
+haiku_switch(DisplayChangeListener *dcl, DisplaySurface *newSurface)
+{
+ //printf(">haiku_switch\n");
+ sWidth = surface_width(newSurface);
+ sHeight = surface_height(newSurface);
+ sCenter.x = (int32)(sWidth / 2);
+ sCenter.y = (int32)(sHeight / 2);
+ sWindow->ResizeTo(sWidth - 1, sHeight - 1);
+ sWindow->SetZoomLimits(sWidth, sHeight);
+ sView->UpdateFrameBuffer(surface_width(newSurface),
+ surface_height(newSurface), (uint8 *)surface_data(newSurface),
+ surface_stride(newSurface), surface_bits_per_pixel(newSurface));
+ sView->UpdateFullScreen();
+ //printf("<haiku_switch\n");
+}
+
+
+static void
+haiku_mouse_mode_change(Notifier *notifier, void *data)
+{
+ sAbsoluteMouse = qemu_input_is_absolute(NULL);
+ BCursor cursor(sAbsoluteMouse ? B_CURSOR_ID_NO_CURSOR
+ : B_CURSOR_ID_SYSTEM_DEFAULT);
+
+ if (sAbsoluteMouse) {
+ if (sGrabInput)
+ sView->EndGrab(sGrabInput, 0);
+ sApplication->SetCursor(&cursor, true);
+ } else
+ sApplication->SetCursor(&cursor, true);
+}
+
+
+void
+haiku_display_init(DisplayState *ds, DisplayOptions *o)
+{
+ qemu_main = haiku_main;
+
+ sFullScreen = (o->has_full_screen && o->full_screen);
+ sGraphicConsole = qemu_console_is_graphic(NULL);
+ sAbsoluteMouse = qemu_input_is_absolute(NULL);
+
+ static Notifier sMouseModeChangeNotifier = { haiku_mouse_mode_change };
+ qemu_add_mouse_mode_change_notifier(&sMouseModeChangeNotifier);
+}
+
+static QemuDisplay qemu_display_haiku = {
+ .type = DISPLAY_TYPE_HAIKU,
+ .init = haiku_display_init,
+};
+
+static void register_haiku(void)
+{
+ qemu_display_register(&qemu_display_haiku);
+}
+
+type_init(register_haiku);
diff --git a/ui/haiku.h b/ui/haiku.h
new file mode 100644
index 0000000..74ff982
--- /dev/null
+++ b/ui/haiku.h
@@ -0,0 +1,113 @@
+/*
+ * QEMU Haiku display driver
+ *
+ * Copyright (c) 2005-2013 Michael Lotz
+ *
+ * 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 _HAIKU_H_
+#define _HAIKU_H_
+
+//#include "haiku-include-before.h"
+#include <Accelerant.h>
+#include <Application.h>
+#include <Bitmap.h>
+#include <MessageFilter.h>
+#include <MessageQueue.h>
+#include <View.h>
+#include <Window.h>
+
+class QEMUWindow;
+class QEMUView;
+
+class QEMUApplication : public BApplication {
+public:
+ QEMUApplication();
+
+virtual bool QuitRequested();
+ void InitDisplay();
+
+private:
+static int32 RunQEMUMain(void *arg);
+
+ thread_id fThread;
+ QEMUWindow * fWindow;
+};
+
+
+class QEMUWindow : public BWindow {
+public:
+ QEMUWindow();
+
+virtual void MessageReceived(BMessage *message);
+
+private:
+ QEMUView * fView;
+};
+
+
+class QEMUView : public BView {
+public:
+ QEMUView(BRect frame);
+virtual ~QEMUView();
+
+virtual void AttachedToWindow();
+
+ void Update(BPoint point, int width, int height);
+virtual void Draw(BRect updateRect);
+
+ void UpdateFrameBuffer(int width, int height,
+ uchar *bits, int bytesPerRow,
+ int bitsPerPixel);
+
+static void UpdateFullScreen();
+static void CenterMouse(bool &warp);
+static void StartGrab(bool &grab);
+static void EndGrab(bool &grab, int32 modifiers);
+
+static void QueueKeycode(uint8 keycode, bool keyDown);
+static void QueueKeysym(int32 keysym);
+static void QueueMouseEvent(BPoint where, int32 deltaZ,
+ int32 buttonState);
+static void QueueShutdownRequest();
+static void QueueConsoleSelect(uint8 console);
+static void QueueInvalidation();
+
+ void ProcessEvents();
+
+private:
+ void QueueEvent(BMessage *event);
+
+static filter_result MessageFilter(BMessage *message, BHandler **target,
+ BMessageFilter *filter);
+
+ BBitmap * fBitmap;
+ BPoint fWindowLocation;
+ display_mode fDisplayMode;
+
+ uint8 * fFrameBuffer;
+ uint32 fFrameBufferSize;
+ uint32 fBytesPerRow;
+ color_space fColorSpace;
+
+ BMessageQueue fEventQueue;
+};
+
+#endif
diff --git a/ui/meson.build b/ui/meson.build
index 0f09d31..f22d04d 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -31,6 +31,11 @@ system_ss.add(when: 'CONFIG_LINUX', if_true: files(
))
system_ss.add(when: cocoa, if_true: files('cocoa.m'))
+if haiku.found()
+ system_ss.add(haiku)
+ system_ss.add(files('haiku.cpp'))
+endif
+
vnc_ss = ss.source_set()
vnc_ss.add(files(
'vnc.c',
--
2.43.2
From 32b6e3cfc8e07559643e7b26dac5461cf5199159 Mon Sep 17 00:00:00 2001
From: David Karoly <david.karoly@outlook.com>
Date: Sat, 4 Feb 2023 13:43:10 +0100
Subject: regenerate meson build options
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 680fa3f..4d2303a 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -123,6 +123,7 @@ meson_options_help() {
printf "%s\n" ' gtk-clipboard clipboard support for the gtk UI (EXPERIMENTAL, MAY HANG)'
printf "%s\n" ' guest-agent Build QEMU Guest Agent'
printf "%s\n" ' guest-agent-msi Build MSI package for the QEMU Guest Agent'
+ printf "%s\n" ' haiku Haiku user interface (Haiku only)'
printf "%s\n" ' hv-balloon hv-balloon driver (requires Glib 2.68+ GTree API)'
printf "%s\n" ' hvf HVF acceleration support'
printf "%s\n" ' iconv Font glyph conversion support'
@@ -333,6 +334,8 @@ _meson_option_parse() {
--disable-guest-agent) printf "%s" -Dguest_agent=disabled ;;
--enable-guest-agent-msi) printf "%s" -Dguest_agent_msi=enabled ;;
--disable-guest-agent-msi) printf "%s" -Dguest_agent_msi=disabled ;;
+ --enable-haiku) printf "%s" -Dhaiku=enabled ;;
+ --disable-haiku) printf "%s" -Dhaiku=disabled ;;
--enable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=true ;;
--disable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=false ;;
--enable-hv-balloon) printf "%s" -Dhv_balloon=enabled ;;
--
2.43.2
From bbbe00f667c6860d8a42dbc9d13cada416ce89c6 Mon Sep 17 00:00:00 2001
From: David Karoly <david.karoly@outlook.com>
Date: Sat, 4 Feb 2023 13:43:27 +0100
Subject: introduce Haiku audio backend
diff --git a/audio/audio.c b/audio/audio.c
index 7ac74f9..1d543c1 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2015,6 +2015,9 @@ void audio_create_pdos(Audiodev *dev)
#ifdef CONFIG_AUDIO_DSOUND
CASE(DSOUND, dsound, );
#endif
+#ifdef CONFIG_AUDIO_HAIKU
+ CASE(HAIKU, haiku, );
+#endif
#ifdef CONFIG_AUDIO_JACK
CASE(JACK, jack, Jack);
#endif
diff --git a/audio/audio.h b/audio/audio.h
index fcc2230..f5ffbb4 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -27,8 +27,10 @@
#include "qemu/queue.h"
#include "qapi/qapi-types-audio.h"
+#ifndef __cplusplus
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
+#endif
typedef void (*audio_callback_fn) (void *opaque, int avail);
@@ -154,7 +156,7 @@ uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
static inline void *advance (void *p, int incr)
{
- uint8_t *d = p;
+ uint8_t *d = (uint8_t *)p;
return (d + incr);
}
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 7ccfec0..e7cfd96 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -357,6 +357,10 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
case AUDIODEV_DRIVER_DSOUND:
return dev->u.dsound.TYPE;
#endif
+#ifdef CONFIG_AUDIO_HAIKU
+ case AUDIODEV_DRIVER_HAIKU:
+ return dev->u.haiku.TYPE;
+#endif
#ifdef CONFIG_AUDIO_JACK
case AUDIODEV_DRIVER_JACK:
return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE);
diff --git a/audio/haikuaudio.cpp b/audio/haikuaudio.cpp
new file mode 100644
index 0000000..6a7d472
--- /dev/null
+++ b/audio/haikuaudio.cpp
@@ -0,0 +1,193 @@
+/*
+ * QEMU Haiku audio output driver
+ *
+ * Copyright (c) 2005-2013 Michael Lotz
+ *
+ * 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.
+ */
+
+extern "C" {
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+
+#include "audio/audio.h"
+
+#define AUDIO_CAP "haiku"
+#include "audio_int.h"
+
+static int haiku_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
+static void haiku_fini_out(HWVoiceOut *hw);
+static void haiku_enable_out(HWVoiceOut *hw, bool enable);
+
+static void * haiku_audio_init(Audiodev *dev, Error **errp);
+static void haiku_audio_fini(void *opaque);
+
+static void register_audio_haiku(void);
+}
+
+#include <SoundPlayer.h>
+
+typedef struct HaikuVoiceOut {
+ HWVoiceOut hw;
+ BSoundPlayer *player;
+ Audiodev *dev;
+} HaikuVoiceOut;
+
+
+void
+PlayBuffer(void *cookie, void *buffer, size_t size, const media_raw_audio_format &format)
+{
+ HaikuVoiceOut *voice = (HaikuVoiceOut *)cookie;
+ HWVoiceOut *hw = &voice->hw;
+
+ while (hw->pending_emul && size) {
+ size_t start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
+ assert(start < hw->size_emul);
+
+ size_t write_len = MIN(MIN(hw->pending_emul, size), hw->size_emul - start);
+ memcpy(buffer, hw->buf_emul + start, write_len);
+
+ hw->pending_emul -= write_len;
+ size -= write_len;
+ buffer = (uint8_t *)buffer + write_len;
+ }
+
+ if (size)
+ audio_pcm_info_clear_buf(&hw->info, buffer, size / hw->info.bytes_per_frame);
+}
+
+
+static uint32
+aud_to_haikufmt(AudioFormat fmt, int endianness)
+{
+ switch (fmt) {
+ case AUDIO_FORMAT_U8:
+ return media_raw_audio_format::B_AUDIO_UCHAR;
+ case AUDIO_FORMAT_S8:
+ return media_raw_audio_format::B_AUDIO_CHAR;
+ case AUDIO_FORMAT_S16:
+ return media_raw_audio_format::B_AUDIO_SHORT;
+ case AUDIO_FORMAT_S32:
+ return media_raw_audio_format::B_AUDIO_INT;
+ case AUDIO_FORMAT_U16:
+ case AUDIO_FORMAT_U32:
+ printf("Unsigned 16/32 bit audio format not supported!\n");
+ return 1;
+ default:
+ dolog("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_AUDIO
+ abort();
+#endif
+ return media_raw_audio_format::B_AUDIO_UCHAR;
+ }
+}
+
+
+static int
+haiku_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
+{
+ HaikuVoiceOut *voice = (HaikuVoiceOut *)hw;
+ Audiodev *dev = (Audiodev *)drv_opaque;
+
+ media_raw_audio_format format;
+ format.frame_rate = as->freq;
+ format.channel_count = as->nchannels;
+ format.byte_order = B_MEDIA_LITTLE_ENDIAN;
+ format.buffer_size = audio_buffer_bytes(dev->u.haiku.out, as, 11610);
+ format.format = aud_to_haikufmt(as->fmt, as->endianness);
+
+ audio_pcm_init_info(&hw->info, as);
+ hw->samples = 4 * audio_buffer_samples(dev->u.haiku.out, as, 11610);
+
+ voice->dev = dev;
+ voice->player = new BSoundPlayer(&format, "QEMU", PlayBuffer, NULL, voice);
+ voice->player->Start();
+ voice->player->SetHasData(true);
+
+ return 0;
+}
+
+
+static void
+haiku_fini_out(HWVoiceOut *hw)
+{
+ HaikuVoiceOut *voice = (HaikuVoiceOut *)hw;
+
+ voice->player->Stop();
+ delete voice->player;
+ voice->player = NULL;
+}
+
+
+static void
+haiku_enable_out(HWVoiceOut *hw, bool enable)
+{
+ HaikuVoiceOut *voice = (HaikuVoiceOut *)hw;
+ if (!voice->player)
+ return;
+
+ if (enable) {
+ ldebug("enabling voice\n");
+ voice->player->SetHasData(true);
+ } else {
+ ldebug("disabling voice\n");
+ //voice->player->SetHasData(false);
+ }
+}
+
+
+static void *
+haiku_audio_init(Audiodev *dev, Error **errp)
+{
+ // just an opaque handle, doesn't matter, we don't use it
+ return (void *)dev;
+}
+
+
+static void
+haiku_audio_fini(void *opaque)
+{
+}
+
+
+static struct audio_pcm_ops haiku_pcm_ops = {
+ .init_out = haiku_init_out,
+ .fini_out = haiku_fini_out,
+ .write = audio_generic_write,
+ .enable_out = haiku_enable_out,
+};
+
+
+static struct audio_driver haiku_audio_driver = {
+ .name = "haiku",
+ .descr = "Haiku Native Audio",
+ .init = haiku_audio_init,
+ .fini = haiku_audio_fini,
+ .pcm_ops = &haiku_pcm_ops,
+ .max_voices_out = 1,
+ .max_voices_in = 0,
+ .voice_size_out = sizeof(HaikuVoiceOut),
+ .voice_size_in = 0
+};
+
+static void register_audio_haiku(void)
+{
+ audio_driver_register(&haiku_audio_driver);
+}
+type_init(register_audio_haiku);
diff --git a/audio/meson.build b/audio/meson.build
index 608f35e..c033292 100644
--- a/audio/meson.build
+++ b/audio/meson.build
@@ -17,6 +17,7 @@ foreach m : [
['pa', pulse, files('paaudio.c')],
['sdl', sdl, files('sdlaudio.c')],
['jack', jack, files('jackaudio.c')],
+ ['haiku', haiku, files('haikuaudio.cpp')],
['sndio', sndio, files('sndioaudio.c')],
['pipewire', pipewire, files('pwaudio.c')],
['spice', spice, files('spiceaudio.c')]
diff --git a/meson.build b/meson.build
index f69a9b1..e450a39 100644
--- a/meson.build
+++ b/meson.build
@@ -633,7 +633,8 @@ elif targetos == 'haiku'
cc.find_library('bsd')]
if not get_option('haiku').disabled()
haikulibs = [cc.find_library('be'),
- cc.find_library('game')]
+ cc.find_library('game'),
+ cc.find_library('media')]
haiku = declare_dependency(dependencies: haikulibs)
endif
elif targetos == 'openbsd'
@@ -1942,6 +1943,7 @@ if have_system
'alsa': alsa.found(),
'coreaudio': coreaudio.found(),
'dsound': dsound.found(),
+ 'haiku': haiku.found(),
'jack': jack.found(),
'oss': oss.found(),
'pa': pulse.found(),
@@ -1955,7 +1957,7 @@ if have_system
# Default to native drivers first, OSS second, SDL third
audio_drivers_priority = \
- [ 'pa', 'coreaudio', 'dsound', 'sndio', 'oss' ] + \
+ [ 'pa', 'coreaudio', 'dsound', 'haiku', 'sndio', 'oss' ] + \
(targetos == 'linux' ? [] : [ 'sdl' ])
audio_drivers_default = []
foreach k: audio_drivers_priority
diff --git a/qapi/audio.json b/qapi/audio.json
index 519697c..c71bb91 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -455,6 +455,7 @@
{ 'name': 'coreaudio', 'if': 'CONFIG_AUDIO_COREAUDIO' },
{ 'name': 'dbus', 'if': 'CONFIG_DBUS_DISPLAY' },
{ 'name': 'dsound', 'if': 'CONFIG_AUDIO_DSOUND' },
+ { 'name': 'haiku', 'if': 'CONFIG_AUDIO_HAIKU' },
{ 'name': 'jack', 'if': 'CONFIG_AUDIO_JACK' },
{ 'name': 'oss', 'if': 'CONFIG_AUDIO_OSS' },
{ 'name': 'pa', 'if': 'CONFIG_AUDIO_PA' },
@@ -494,6 +495,8 @@
'if': 'CONFIG_DBUS_DISPLAY' },
'dsound': { 'type': 'AudiodevDsoundOptions',
'if': 'CONFIG_AUDIO_DSOUND' },
+ 'haiku': { 'type': 'AudiodevGenericOptions',
+ 'if': 'CONFIG_AUDIO_HAIKU' },
'jack': { 'type': 'AudiodevJackOptions',
'if': 'CONFIG_AUDIO_JACK' },
'oss': { 'type': 'AudiodevOssOptions',
--
2.43.2
From e6c627655981859152b53451bbe8931bbcd5706e Mon Sep 17 00:00:00 2001
From: David Karoly <david.karoly@outlook.com>
Date: Fri, 8 Dec 2023 17:08:37 +0100
Subject: kludge haiku.cpp
diff --git a/ui/haiku.cpp b/ui/haiku.cpp
index 46f99de..c9478ee 100644
--- a/ui/haiku.cpp
+++ b/ui/haiku.cpp
@@ -68,7 +68,9 @@ extern "C" {
// Guard against reserved keywords in C includes
#include "qemu/osdep.h"
-#include "qemu/main-loop.h"
+// main-loop.h does not work very well when including it from a C++ souce file
+// therefore the required function prototypes are re-declared below
+//#include "qemu/main-loop.h"
#include "qemu-main.h"
#include "ui/console.h"
#include "ui/input.h"
@@ -77,6 +79,12 @@ extern "C" {
#undef class
#undef typename
+#define qemu_mutex_lock_iothread() \
+ qemu_mutex_lock_iothread_impl(__FILE__, __LINE__)
+
+void qemu_mutex_lock_iothread_impl(const char *file, int line);
+void qemu_mutex_unlock_iothread(void);
+
static void haiku_refresh(DisplayChangeListener *dcl);
static void haiku_update(DisplayChangeListener *dcl, int x, int y, int w,
int h);
--
2.43.2
From eafef1273d843bdf3bcc9b9df1efab2132771c16 Mon Sep 17 00:00:00 2001
From: Daniel Martin <dalmemail@gmail.com>
Date: Wed, 18 Dec 2024 23:03:19 +0000
Subject: [PATCH 1/1] Set Haiku native video backend as default (instead of
broken SDL)
---
ui/console.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ui/console.c b/ui/console.c
index bf60b55..684d436 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1615,6 +1615,9 @@ void qemu_display_register(QemuDisplay *ui)
bool qemu_display_find_default(DisplayOptions *opts)
{
static DisplayType prio[] = {
+#if defined(CONFIG_HAIKU)
+ DISPLAY_TYPE_HAIKU,
+#endif
#if defined(CONFIG_GTK)
DISPLAY_TYPE_GTK,
#endif
@@ -1623,9 +1626,6 @@ bool qemu_display_find_default(DisplayOptions *opts)
#endif
#if defined(CONFIG_COCOA)
DISPLAY_TYPE_COCOA
-#endif
-#if defined(CONFIG_HAIKU)
- DISPLAY_TYPE_HAIKU
#endif
};
int i;
--
2.45.2