From patchwork Sun Sep 19 22:50:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 65175 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E604CB70CD for ; Mon, 20 Sep 2010 08:54:41 +1000 (EST) Received: from localhost ([127.0.0.1]:52419 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OxSmM-0000Hf-BO for incoming@patchwork.ozlabs.org; Sun, 19 Sep 2010 18:54:38 -0400 Received: from [140.186.70.92] (port=44828 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OxSix-0007QD-Tv for qemu-devel@nongnu.org; Sun, 19 Sep 2010 18:51:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OxSiu-0004ql-I8 for qemu-devel@nongnu.org; Sun, 19 Sep 2010 18:51:07 -0400 Received: from fmmailgate01.web.de ([217.72.192.221]:55332) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OxSit-0004qK-Oa for qemu-devel@nongnu.org; Sun, 19 Sep 2010 18:51:04 -0400 Received: from smtp02.web.de ( [172.20.0.184]) by fmmailgate01.web.de (Postfix) with ESMTP id 1E1F91692EAD9; Mon, 20 Sep 2010 00:51:03 +0200 (CEST) Received: from [87.173.118.124] (helo=localhost.localdomain) by smtp02.web.de with asmtp (WEB.DE 4.110 #24) id 1OxSis-00017x-00; Mon, 20 Sep 2010 00:51:02 +0200 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= To: qemu-devel@nongnu.org Date: Mon, 20 Sep 2010 00:50:50 +0200 Message-Id: <1284936650-1203-9-git-send-email-andreas.faerber@web.de> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1284936650-1203-8-git-send-email-andreas.faerber@web.de> References: <7861078417-BeMail@haiku> <1284936650-1203-1-git-send-email-andreas.faerber@web.de> <1284936650-1203-2-git-send-email-andreas.faerber@web.de> <1284936650-1203-3-git-send-email-andreas.faerber@web.de> <1284936650-1203-4-git-send-email-andreas.faerber@web.de> <1284936650-1203-5-git-send-email-andreas.faerber@web.de> <1284936650-1203-6-git-send-email-andreas.faerber@web.de> <1284936650-1203-7-git-send-email-andreas.faerber@web.de> <1284936650-1203-8-git-send-email-andreas.faerber@web.de> X-Sender: Andreas.Faerber@web.de X-Provags-ID: V01U2FsdGVkX1+BpHOQjasp6995nvAyJCEF3dev+utfkEzjSCx9 1RKSINGZknZA24YjJPSJu7ysuvEq3dZy8MG4S09vV9cGu/3qV+ +eAwz1UuyjbGLb7OVtLg== X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: haikuports-devs@ports.haiku-files.org, Blue Swirl , =?UTF-8?q?Andreas=20F=C3=A4rber?= , Michael Lotz Subject: [Qemu-devel] [FYI 8/8] ui: Haiku frontend X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Since Haiku is still in development and raw builds don't contain the SDL or a VNC client, a native frontend is convenient. mmlr had maintained a basic one for BeOS/Haiku until the kqemu drop. The code has been ported to HEAD but is not yet fully updated to match CODING_STYLE. Cc: Michael Lotz Haiku's native APIs are C++ based, so we need a new make rule. Some enabled GCC warnings are not applicable to C++ code and cause warnings. Cc: Blue Swirl Note that this frontend is another candidate user of a central qemu_main() prototype, like Cocoa. It would also be candidate for a generic argv check for non-graphic mode, to be shared with Cocoa. --- Makefile | 2 + Makefile.objs | 1 + configure | 1 + console.h | 3 + rules.mak | 6 +- ui/haiku.cpp | 607 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui/haiku.h | 96 +++++++++ vl.c | 10 +- 8 files changed, 724 insertions(+), 2 deletions(-) create mode 100644 ui/haiku.cpp create mode 100644 ui/haiku.h diff --git a/Makefile b/Makefile index ab91d42..64eea3e 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,8 @@ QEMU_CFLAGS+=$(CURL_CFLAGS) ui/cocoa.o: ui/cocoa.m +ui/haiku.o: ui/haiku.cpp + ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) diff --git a/Makefile.objs b/Makefile.objs index f702ad4..6ae0e14 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -112,6 +112,7 @@ ui-obj-y += vnc-enc-tight.o vnc-palette.o ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o ui-obj-$(CONFIG_COCOA) += cocoa.o +ui-obj-$(CONFIG_HAIKU) += haiku.o ifdef CONFIG_VNC_THREAD ui-obj-y += vnc-jobs-async.o else diff --git a/configure b/configure index 3a0d50e..b533990 100755 --- a/configure +++ b/configure @@ -454,6 +454,7 @@ Haiku) haiku="yes" QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS $QEMU_CFLAGS" LIBS="-lposix_error_mapper -lnetwork $LIBS" + LIBS="-lstdc++ -lbe -lgame $LIBS" ;; *) audio_drv_list="oss" diff --git a/console.h b/console.h index aafb031..9a8268a 100644 --- a/console.h +++ b/console.h @@ -364,6 +364,9 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); /* cocoa.m */ void cocoa_display_init(DisplayState *ds, int full_screen); +/* haiku.cpp */ +void haiku_display_init(DisplayState *ds, int full_screen); + /* vnc.c */ void vnc_display_init(DisplayState *ds); void vnc_display_close(DisplayState *ds); diff --git a/rules.mak b/rules.mak index c843a13..29481b9 100644 --- a/rules.mak +++ b/rules.mak @@ -8,6 +8,7 @@ MAKEFLAGS += -rR %.d: %.h: %.c: +%.cpp: %.m: %.mak: @@ -23,6 +24,9 @@ QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d %.o: %.m $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@") +%.o: %.cpp + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CXX $(TARGET_DIR)$@") + LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(1) $(LIBS)," LINK $(TARGET_DIR)$@") %$(EXESUF): %.o @@ -39,7 +43,7 @@ quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1)) cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ >/dev/null 2>&1 && echo OK), $2, $3) -VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi +VPATH_SUFFIXES = %.c %.h %.S %.m %.cpp %.mak %.texi set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1))) # Generate timestamp files for .h include files diff --git a/ui/haiku.cpp b/ui/haiku.cpp new file mode 100644 index 0000000..37b9414 --- /dev/null +++ b/ui/haiku.cpp @@ -0,0 +1,607 @@ +/* + * QEMU Haiku display driver + * + * Copyright (c) 2010 Andreas Färber + * Copyright (c) 2005-2009 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 + +#include +#include +#include + + +extern "C" { + +#include "qemu-common.h" +#include "console.h" +#include "sysemu.h" + +int qemu_main(int argc, char **argv, char** envp); + +} + + +QEMUApplication *gApplication; +QEMUWindow *gWindow; +QEMUView *gView; +bool gFullScreen; +int gWidth = 100; +int gHeight = 100; +BPoint gCenter; +BPoint gPreviousLocation; + + +// 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 */ +}; + + +int +main(int argc, char **argv) +{ + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-nographic") == 0 || + strcmp(argv[i], "-curses") == 0 || + strcmp(argv[i], "-vnc") == 0) { + return qemu_main(argc, argv, NULL); + } + } + QEMUApplication *app = new QEMUApplication(argc, argv); + app->Run(); + delete app; + return 0; +} + + +QEMUApplication::QEMUApplication(int argc, char **argv) + : BApplication("application/x-vnd.qemu.QEMU"), + fThread(0), + fWindow(NULL) +{ + gApplication = this; + + fArgC = argc; + fArgV = argv; + + fThread = spawn_thread(&RunQEMUMain, "qemu_main", B_LOW_PRIORITY, this); + resume_thread(fThread); +} + + +bool +QEMUApplication::QuitRequested() +{ + qemu_system_shutdown_request(); + return true; +} + + +void +QEMUApplication::InitDisplay() +{ + fWindow = new QEMUWindow(); + fWindow->Show(); +} + + +int32 +QEMUApplication::RunQEMUMain(void *arg) +{ + QEMUApplication *app = (QEMUApplication *)arg; + qemu_main(app->fArgC, app->fArgV, NULL); + 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) +{ + gWindow = this; + fView = new QEMUView(Bounds()); + AddChild(fView); + fView->MakeFocus(); +} + + +QEMUView::QEMUView(BRect frame) + : BView(frame, "fView", B_FOLLOW_ALL, B_WILL_DRAW), + fBitmap(NULL) +{ + gView = this; + fBitmap = new BBitmap(frame, 0, B_RGBA32); + AddFilter(new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, &MessageFilter)); +} + + +QEMUView::~QEMUView() +{ + if (gFullScreen) { + BScreen().SetMode(&fDisplayMode); + } +} + + +void +QEMUView::UpdateFullScreen() +{ + if (!gFullScreen) { + return; + } + + BScreen screen; + display_mode current; + display_mode *modes; + display_mode *mode; + uint32 count; + + screen.GetMode(¤t); + screen.GetModeList(&modes, &count); + + for (uint32 i = 0; i < count; i++) { + mode = &modes[i]; + if (mode->virtual_width == gWidth + && mode->virtual_height == gHeight + && mode->space == current.space) { + screen.SetMode(mode); + break; + } + } + + gWindow->MoveTo(0, 0); +} + + +void +QEMUView::CenterMouse(bool &warp) +{ + BRect window = gWindow->Frame(); + BPoint center = window.LeftTop() + gCenter; + set_mouse_position((int32)center.x, (int32)center.y); + warp = true; +} + + +void +QEMUView::StartGrab(bool &grab) +{ + gApplication->HideCursor(); + gWindow->SetTitle("QEMU - Press Ctrl-Alt to exit grab"); + grab = true; +} + + +void +QEMUView::EndGrab(bool &grab, int32 modifiers) +{ + gApplication->ShowCursor(); + gWindow->SetTitle("QEMU"); + grab = false; + + // reset any set modifiers + if (modifiers & B_LEFT_SHIFT_KEY) + kbd_put_keycode(0xaa); + if (modifiers & B_RIGHT_SHIFT_KEY) + kbd_put_keycode(0xb6); + + if (modifiers & B_LEFT_COMMAND_KEY) + kbd_put_keycode(0xb8); + if (modifiers & B_RIGHT_COMMAND_KEY) { + kbd_put_keycode(0xe0); + kbd_put_keycode(0xb8); + } + + if (modifiers & B_LEFT_CONTROL_KEY) + kbd_put_keycode(0x9d); + if (modifiers & B_RIGHT_CONTROL_KEY) { + kbd_put_keycode(0xe0); + kbd_put_keycode(0x9d); + } + + if (modifiers & B_LEFT_OPTION_KEY) { + kbd_put_keycode(0xe0); + kbd_put_keycode(0xdb); + } + if (modifiers & B_RIGHT_OPTION_KEY) { + kbd_put_keycode(0xe0); + kbd_put_keycode(0xdc); + } +} + + +filter_result +QEMUView::MessageFilter(BMessage *message, BHandler **target, + BMessageFilter *filter) +{ + static bool sGrabInput = false; + static bool sMouseWarp = false; + static int32 sMouseButtons = 0; + 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 (!gFullScreen) { + screen.GetMode(&gView->fDisplayMode); + gWindow->MoveTo(0, 0); + gFullScreen = true; + } else { + screen.SetMode(&gView->fDisplayMode); + gWindow->MoveTo(gView->fWindowLocation); + gFullScreen = false; + } + + UpdateFullScreen(); + if (is_graphic_console()) { + vga_hw_invalidate(); + vga_hw_update(); + } + + return B_SKIP_MESSAGE; + } break; + + case 0x52: { /* m - pseudo fullscreen */ + BPoint location = gWindow->Frame().LeftTop(); + if (location.x == 0 && location.y == 0) + gWindow->MoveTo(gPreviousLocation); + else { + gPreviousLocation = location; + gWindow->MoveTo(0, 0); + } + + if (is_graphic_console()) { + vga_hw_invalidate(); + vga_hw_update(); + } + + return B_SKIP_MESSAGE; + } break; + + case 0x12 ... 0x1a: { /* 1 to 9 - switch console */ + console_select(key - 0x12); + if (is_graphic_console()) { + vga_hw_invalidate(); + vga_hw_update(); + } + + return B_SKIP_MESSAGE; + } break; + } + } else if (!is_graphic_console()) { + 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) + kbd_put_keysym(keysym); + else { + const char *bytes; + if (message->FindString("bytes", &bytes) == B_OK && bytes[0] != 0) + kbd_put_keysym(bytes[0]); + } + return B_SKIP_MESSAGE; + } + + if (keycode & 0x80) + kbd_put_keycode(0xe0); + + if (keyDown) + kbd_put_keycode(keycode & 0x7f); + else + kbd_put_keycode(keycode | 0x80); + + return B_SKIP_MESSAGE; + } break; + + case B_MOUSE_MOVED: { + if (!sGrabInput) + break; + + if (sMouseWarp) { + sMouseWarp = false; + return B_SKIP_MESSAGE; + } + + BPoint where; + message->FindPoint("where", &where); + BPoint delta = where - gCenter; + + // Haiku buttons are the same as QEMU + kbd_mouse_event((int)delta.x, (int)delta.y, 0, sMouseButtons); + + CenterMouse(sMouseWarp); + return B_SKIP_MESSAGE; + } break; + + case B_MOUSE_DOWN: + case B_MOUSE_UP: { + int32 buttons; + message->FindInt32("buttons", &buttons); + + if (!sGrabInput) { + if (message->what == B_MOUSE_DOWN + && (buttons & B_PRIMARY_MOUSE_BUTTON)) { + CenterMouse(sMouseWarp); + StartGrab(sGrabInput); + } + break; + } + + sMouseButtons = buttons; + // Haiku buttons are the same as QEMU + kbd_mouse_event(0, 0, 0, sMouseButtons); + return B_SKIP_MESSAGE; + } break; + + case B_MOUSE_WHEEL_CHANGED: { + if (!sGrabInput) + break; + + float delta; + message->FindFloat("be:wheel_delta_y", &delta); + kbd_mouse_event(0, 0, (int)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, width, height); + + Draw(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(); + } +} + + +// QEMU C interface +extern "C" { + +static void haiku_update(DisplayState *ds, int x, int y, int w, int h); +static void haiku_resize(DisplayState *ds); +static void haiku_refresh(DisplayState *ds); + +}; + + +static void +haiku_update(DisplayState *ds, int x, int y, int w, int h) +{ + //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); + gView->Update(BPoint(x, y), w, h); +} + + +static void +haiku_resize(DisplayState *ds) +{ + //printf("resizing\n"); + gWidth = ds_get_width(ds); + gHeight = ds_get_height(ds); + gCenter.x = (int32)(gWidth / 2); + gCenter.y = (int32)(gHeight / 2); + gWindow->ResizeTo(gWidth - 1, gHeight - 1); + gWindow->SetZoomLimits(gWidth, gHeight); + gView->UpdateFrameBuffer(ds_get_width(ds), ds_get_height(ds), + ds_get_data(ds), ds_get_linesize(ds), ds_get_bits_per_pixel(ds)); + gView->UpdateFullScreen(); +} + + +static void +haiku_refresh(DisplayState *ds) +{ + //printf("refreshing\n"); + if (is_graphic_console()) { + vga_hw_update(); + } +} + + +void +haiku_display_init(DisplayState *ds, int fullScreen) +{ + gApplication->InitDisplay(); + gFullScreen = fullScreen != 0; + + DisplayChangeListener *displayChangeListener + = (DisplayChangeListener *)qemu_mallocz(sizeof(DisplayChangeListener)); + displayChangeListener->dpy_update = haiku_update; + displayChangeListener->dpy_resize = haiku_resize; + displayChangeListener->dpy_refresh = haiku_refresh; + register_displaychangelistener(ds, displayChangeListener); +} diff --git a/ui/haiku.h b/ui/haiku.h new file mode 100644 index 0000000..2c342d2 --- /dev/null +++ b/ui/haiku.h @@ -0,0 +1,96 @@ +/* + * QEMU Haiku display driver + * + * Copyright (c) 2005-2009 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 +#include +#include +#include +#include +#include + +class QEMUWindow; +class QEMUView; + +class QEMUApplication : public BApplication { +public: + QEMUApplication(int argc, char **argv); + +virtual bool QuitRequested(); + void InitDisplay(); + +private: +static int32 RunQEMUMain(void *arg); + + int fArgC; + char ** fArgV; + + thread_id fThread; + QEMUWindow * fWindow; +}; + + +class QEMUWindow : public BWindow { +public: + QEMUWindow(); + +private: + QEMUView * fView; +}; + + +class QEMUView : public BView { +public: + QEMUView(BRect frame); +virtual ~QEMUView(); + + 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); + +private: +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; +}; + +#endif diff --git a/vl.c b/vl.c index d352d18..7641763 100644 --- a/vl.c +++ b/vl.c @@ -1799,6 +1799,10 @@ static const QEMUOption *lookup_opt(int argc, char **argv, return popt; } +#ifdef CONFIG_HAIKU +#define main qemu_main +#endif + int main(int argc, char **argv, char **envp) { const char *gdbstub_dev = NULL; @@ -2919,7 +2923,7 @@ int main(int argc, char **argv, char **envp) ds = get_displaystate(); if (display_type == DT_DEFAULT) { -#if defined(CONFIG_SDL) || defined(CONFIG_COCOA) +#if defined(CONFIG_SDL) || defined(CONFIG_COCOA) || defined(CONFIG_HAIKU) display_type = DT_SDL; #else display_type = DT_VNC; @@ -2945,6 +2949,10 @@ int main(int argc, char **argv, char **envp) case DT_SDL: cocoa_display_init(ds, full_screen); break; +#elif defined(CONFIG_HAIKU) + case DT_SDL: + haiku_display_init(ds, full_screen); + break; #endif case DT_VNC: vnc_display_init(ds);