/* Haiku window system support. Hey, Emacs, this is -*- C++ -*- Copyright (C) 2021 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "haiku_support.h" extern "C" { extern void emacs_abort (void); pthread_t app_thread_id; } class Emacs : public BApplication { public: Emacs () : BApplication ("application/emacs") { } }; class EmacsWindow : public BWindow { public: EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 0) { } void WindowActivated (bool activated) { struct haiku_activation_event rq; rq.window = this; rq.activated_p = activated; haiku_write (ACTIVATION, &rq); } void MessageReceived (BMessage *msg) { if (msg->GetPointer ("menuptr")) { struct haiku_menu_bar_select_event rq; rq.window = this; rq.ptr = (void *) msg->GetPointer ("menuptr"); haiku_write (MENU_BAR_SELECT_EVENT, &rq); } BWindow::MessageReceived (msg); } void DispatchMessage (BMessage *msg, BHandler *handler) { if (msg->what == B_KEY_DOWN || msg->what == B_KEY_UP) { struct haiku_key_event rq; rq.window = this; int32_t code = msg->GetInt32 ("raw_char", 0); rq.modifiers = 0; if (modifiers () & B_SHIFT_KEY) rq.modifiers |= HAIKU_MODIFIER_SHIFT; if (modifiers () & B_CONTROL_KEY) rq.modifiers |= HAIKU_MODIFIER_CTRL; if (modifiers () & B_COMMAND_KEY) rq.modifiers |= HAIKU_MODIFIER_ALT; rq.mb_char = code; rq.kc = msg->GetInt32 ("key", -1); rq.unraw_mb_char = BUnicodeChar::FromUTF8 (msg->GetString ("bytes")); haiku_write (msg->what == B_KEY_DOWN ? KEY_DOWN : KEY_UP, &rq); } else if (msg->what == B_MOUSE_WHEEL_CHANGED) { struct haiku_wheel_move_event rq; rq.window = this; rq.modifiers = 0; if (modifiers () & B_SHIFT_KEY) rq.modifiers |= HAIKU_MODIFIER_SHIFT; if (modifiers () & B_CONTROL_KEY) rq.modifiers |= HAIKU_MODIFIER_CTRL; if (modifiers () & B_COMMAND_KEY) rq.modifiers |= HAIKU_MODIFIER_ALT; float dx, dy; if (msg->FindFloat ("be:wheel_delta_x", &dx) == B_OK && msg->FindFloat ("be:wheel_delta_y", &dy) == B_OK) { rq.delta_x = dx; rq.delta_y = dy; haiku_write (WHEEL_MOVE_EVENT, &rq); }; } else BWindow::DispatchMessage (msg, handler); } void MenusBeginning () { struct haiku_menu_bar_state_event rq; rq.window = this; haiku_write (MENU_BAR_OPEN, &rq); } void MenusEnded () { struct haiku_menu_bar_state_event rq; rq.window = this; haiku_write (MENU_BAR_CLOSE, &rq); } void FrameResized (float newWidth, float newHeight) { struct haiku_resize_event rq; rq.window = this; rq.px_heightf = newHeight; rq.px_widthf = newWidth; haiku_write (FRAME_RESIZED, &rq); } void FrameMoved (BPoint newPosition) { struct haiku_move_event rq; rq.window = this; rq.x = std::lrint (newPosition.x); rq.y = std::lrint (newPosition.y); haiku_write (MOVE_EVENT, &rq); } bool QuitRequested () { struct haiku_quit_requested_event rq; rq.window = this; haiku_write (QUIT_REQUESTED, &rq); return false; } void Minimize (bool minimized_p) { BWindow::Minimize (minimized_p); struct haiku_iconification_event rq; rq.window = this; rq.iconified_p = minimized_p; haiku_write (ICONIFICATION, &rq); } }; class EmacsMenuBar : BMenuBar { public: EmacsMenuBar () : BMenuBar (BRect (0, 0, 0, 0), NULL) { } void FrameResized (float newWidth, float newHeight) { struct haiku_menu_bar_resize_event rq; rq.window = this->Window (); rq.height = std::lrint (newHeight); rq.width = std::lrint (newWidth); haiku_write (MENU_BAR_RESIZE, &rq); BMenuBar::FrameResized (newWidth, newHeight); } }; class EmacsView : public BView { private: uint32_t previous_buttons = 0; public: int looper_locked_count = 0; BRegion sb_region; EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs Content", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_SUBPIXEL_PRECISE) { } void Draw (BRect expose_bounds) { struct haiku_expose_event rq; if (sb_region.Contains (std::lrint (expose_bounds.left), std::lrint (expose_bounds.top)) && sb_region.Contains (std::lrint (expose_bounds.right), std::lrint (expose_bounds.top)) && sb_region.Contains (std::lrint (expose_bounds.left), std::lrint (expose_bounds.bottom)) && sb_region.Contains (std::lrint (expose_bounds.right), std::lrint (expose_bounds.bottom))) return; rq.x = std::floor (expose_bounds.left); rq.y = std::floor (expose_bounds.top); rq.width = std::ceil (expose_bounds.right - expose_bounds.left + 1); rq.height = std::ceil (expose_bounds.bottom - expose_bounds.top + 1); if (!rq.width) rq.width = 1; if (!rq.height) rq.height = 1; rq.window = this->Window (); haiku_write (FRAME_EXPOSED, &rq); } void MouseMoved (BPoint point, uint32 transit, const BMessage *msg) { struct haiku_mouse_motion_event rq; rq.just_exited_p = transit == B_EXITED_VIEW; rq.x = point.x; rq.y = point.y; rq.be_code = transit; rq.window = this->Window (); haiku_write (MOUSE_MOTION, &rq); } void MouseDown (BPoint point) { struct haiku_button_event rq; uint32_t buttons; this->GetMouse (&point, &buttons, false); rq.window = this->Window (); rq.btn_no = 0; if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON) && (buttons & B_PRIMARY_MOUSE_BUTTON)) rq.btn_no = 0; else if (!(previous_buttons & B_SECONDARY_MOUSE_BUTTON) && (buttons & B_SECONDARY_MOUSE_BUTTON)) rq.btn_no = 2; else if (!(previous_buttons & B_TERTIARY_MOUSE_BUTTON) && (buttons & B_TERTIARY_MOUSE_BUTTON)) rq.btn_no = 1; previous_buttons = buttons; rq.x = point.x; rq.y = point.y; uint32_t mods = modifiers (); rq.modifiers = 0; if (mods & B_SHIFT_KEY) rq.modifiers |= HAIKU_MODIFIER_SHIFT; if (mods & B_CONTROL_KEY) rq.modifiers |= HAIKU_MODIFIER_CTRL; if (mods & B_COMMAND_KEY) rq.modifiers |= HAIKU_MODIFIER_ALT; haiku_write (BUTTON_DOWN, &rq); } void MouseUp (BPoint point) { struct haiku_button_event rq; uint32_t buttons; this->GetMouse (&point, &buttons, false); rq.window = this->Window (); rq.btn_no = 0; if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON) && !(buttons & B_PRIMARY_MOUSE_BUTTON)) rq.btn_no = 0; else if ((previous_buttons & B_SECONDARY_MOUSE_BUTTON) && !(buttons & B_SECONDARY_MOUSE_BUTTON)) rq.btn_no = 2; else if ((previous_buttons & B_TERTIARY_MOUSE_BUTTON) && !(buttons & B_TERTIARY_MOUSE_BUTTON)) rq.btn_no = 1; previous_buttons = buttons; rq.x = point.x; rq.y = point.y; uint32_t mods = modifiers (); rq.modifiers = 0; if (mods & B_SHIFT_KEY) rq.modifiers |= HAIKU_MODIFIER_SHIFT; if (mods & B_CONTROL_KEY) rq.modifiers |= HAIKU_MODIFIER_CTRL; if (mods & B_COMMAND_KEY) rq.modifiers |= HAIKU_MODIFIER_ALT; haiku_write (BUTTON_UP, &rq); } }; class EmacsScrollBar : BScrollBar { public: void *scroll_bar; EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p) : BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ? B_HORIZONTAL : B_VERTICAL) { BView *vw = (BView *) this; vw->SetFlags (vw->Flags () & ~B_FRAME_EVENTS); vw->SetResizingMode (B_FOLLOW_NONE); } void ValueChanged (float new_value) { struct haiku_scroll_bar_value_event rq; rq.scroll_bar = scroll_bar; rq.position = new_value; haiku_write (SCROLL_BAR_VALUE_EVENT, &rq); } void MouseDown (BPoint pt) { struct haiku_scroll_bar_drag_event rq; rq.dragging_p = 1; rq.scroll_bar = scroll_bar; haiku_write (SCROLL_BAR_DRAG_EVENT, &rq); BScrollBar::MouseDown (pt); } void MouseUp (BPoint pt) { struct haiku_scroll_bar_drag_event rq; rq.dragging_p = 0; rq.scroll_bar = scroll_bar; haiku_write (SCROLL_BAR_DRAG_EVENT, &rq); BScrollBar::MouseUp (pt); } }; static void * start_running_application (void *data) { haiku_io_init_in_app_thread (); ((Emacs *) data)->Lock (); ((Emacs *) data)->Run (); ((Emacs *) data)->Unlock (); return NULL; } void * BBitmap_data (void *bitmap) { return ((BBitmap *) bitmap)->Bits (); } int BBitmap_convert (void *_bitmap, void **new_bitmap) { BBitmap *bitmap = (BBitmap *) _bitmap; if (bitmap->ColorSpace () != B_RGBA32) return 0; BRect bounds = bitmap->Bounds (); BBitmap *bmp = new (std::nothrow) BBitmap (bounds, B_RGBA32); if (!bmp) return 0; if (bmp->ImportBits (bitmap) != B_OK) { delete bmp; return 0; } **(BBitmap **) new_bitmap = bmp; return 1; } void BBitmap_free (void *bitmap) { delete (BBitmap *) bitmap; } void * BBitmap_new (int width, int height, int mono_p) { return new (std::nothrow) BBitmap (BRect (0, 0, width, height), mono_p ? B_GRAY1 : B_RGB32); } void BBitmap_dimensions (void *bitmap, int *left, int *top, int *right, int *bottom, int32_t *bytes_per_row, int *mono_p) { BRect rect = ((BBitmap *) bitmap)->Bounds (); *left = rect.left; *top = rect.top; *right = rect.right; *bottom = rect.bottom; *bytes_per_row = ((BBitmap *) bitmap)->BytesPerRow (); *mono_p = (((BBitmap *) bitmap)->ColorSpace () == B_GRAY1); } void * BApplication_setup (void) { if (be_app) return be_app; Emacs *app; app = new Emacs; if (pthread_create (&app_thread_id, NULL, start_running_application, app)) { perror ("pthread_create"); emacs_abort (); } return app; } void * BWindow_new (void *_view) { BWindow *window = new (std::nothrow) EmacsWindow; BView **v = (BView **) _view; if (!window) { *v = NULL; return window; } BView *vw = new (std::nothrow) EmacsView; if (!vw) { *v = NULL; window->Lock (); window->Quit (); return NULL; } window->BeginViewTransaction (); window->AddChild (vw); *v = vw; return window; } void BWindow_quit (void *window) { ((BWindow *) window)->Lock (); ((BWindow *) window)->Quit (); } void BWindow_set_offset (void *window, int x, int y) { ((BWindow *) window)->MoveTo (x, y); } void BWindow_iconify (void *window) { if (((BWindow *) window)->IsHidden ()) BWindow_set_visible (window, true); ((BWindow *) window)->Minimize (true); } void BWindow_set_visible (void *window, int visible_p) { BWindow *win = (BWindow *) window; if (visible_p) { if (win->IsMinimized ()) win->Minimize (false); win->Show (); } else if (!win->IsHidden ()) { if (win->IsMinimized ()) win->Minimize (false); win->Hide (); } } void BWindow_retitle (void *window, const char *title) { ((BWindow *) window)->SetTitle (title); } void BWindow_resize (void *window, int width, int height) { ((BWindow *) window)->ResizeTo (width, height); } void BWindow_activate (void *window) { ((BWindow *) window)->Activate (); } void BScreen_px_dim (int *width, int *height) { BScreen screen; BRect frame = screen.Frame (); *width = frame.right - frame.left; *height = frame.bottom - frame.top; } void BView_resize_to (void *view, int width, int height) { BView *vw = (BView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->ResizeTo (width, height); vw->UnlockLooper (); } void * BCursor_create_default (void) { return new BCursor (B_CURSOR_ID_SYSTEM_DEFAULT); } void * BCursor_from_id (enum haiku_cursor cursor) { return new BCursor ((enum BCursorID) cursor); } void * BCursor_create_i_beam (void) { return new BCursor (B_CURSOR_ID_I_BEAM); } void * BCursor_create_progress_cursor (void) { return new BCursor (B_CURSOR_ID_PROGRESS); } void * BCursor_create_grab (void) { return new BCursor (B_CURSOR_ID_GRAB); } void BCursor_delete (void *cursor) { delete (BCursor *) cursor; } void BView_set_view_cursor (void *view, void *cursor) { if (!((BView *) view)->LockLooper ()) emacs_abort (); ((BView *) view)->SetViewCursor ((BCursor *) cursor); ((BView *) view)->UnlockLooper (); } void BWindow_Flush (void *window) { ((BWindow *) window)->Flush (); } void BMapKey (uint32_t kc, int *non_ascii_p, unsigned *code) { *code = 0; switch (kc) { default: *non_ascii_p = 0; if (kc < 0xe && kc > 0x1) { *code = XK_F1 + kc - 2; *non_ascii_p = 1; } return; case 0x1e: *code = XK_BackSpace; break; case 0x32: case 0x5b: case 0x47: *code = XK_Return; break; case 0x61: *code = XK_Left; break; case 0x63: *code = XK_Right; break; case 0x57: *code = XK_Up; break; case 0x62: *code = XK_Down; break; case 0x64: *code = XK_Insert; break; case 0x65: *code = XK_Delete; break; case 0x37: *code = XK_Home; break; case 0x58: *code = XK_End; break; case 0x39: *code = XK_Page_Up; break; case 0x5a: *code = XK_Page_Down; break; case 0x1: *code = XK_Escape; break; case 0x68: *code = XK_Menu; break; } *non_ascii_p = 1; } void * BScrollBar_make_for_view (void *view, int horizontal_p, int x, int y, int x1, int y1, void *scroll_bar_ptr) { EmacsScrollBar *sb = new EmacsScrollBar (x, y, x1, y1, horizontal_p); sb->scroll_bar = scroll_bar_ptr; BView *vw = (BView *) view; BView *sv = (BView *) sb; if (!vw->LockLooper ()) emacs_abort (); vw->AddChild ((BView *) sb); sv->WindowActivated (vw->Window ()->IsActive ()); vw->UnlockLooper (); return sb; } void BScrollBar_delete (void *sb) { BView *view = (BView *) sb; BView *pr = view->Parent (); if (!pr->LockLooper ()) emacs_abort (); pr->RemoveChild (view); pr->UnlockLooper (); delete (EmacsScrollBar *) sb; } void BView_move_frame (void *view, int x, int y, int x1, int y1) { BView *vw = (BView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->MoveTo (x, y); vw->ResizeTo (x1 - x, y1 - y); vw->UnlockLooper (); } void BView_scroll_bar_update (void *sb, int portion, int whole, int position) { BScrollBar *bar = (BScrollBar *) sb; if (!bar->LockLooper ()) emacs_abort (); bar->SetRange (0, whole); bar->SetValue (position); bar->UnlockLooper (); } int BScrollBar_default_size (int horizontal_p) { return horizontal_p ? B_H_SCROLL_BAR_HEIGHT : B_V_SCROLL_BAR_WIDTH; } void BView_hide (void *view) { BView *vw = (BView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->Hide (); vw->UnlockLooper (); } void BView_show (void *view) { BView *vw = (BView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->Show (); vw->UnlockLooper (); } void BView_invalidate (void *view) { BView *vw = (BView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->Invalidate (); vw->UnlockLooper (); } void BView_draw_lock (void *view) { EmacsView *vw = (EmacsView *) view; if (vw->looper_locked_count) { vw->looper_locked_count++; return; } if (!vw->LockLooper ()) emacs_abort (); vw->looper_locked_count++; } void BView_draw_unlock (void *view) { EmacsView *vw = (EmacsView *) view; if (--vw->looper_locked_count) return; vw->UnlockLooper (); } void BWindow_center_on_screen (void *window) { BWindow *w = (BWindow *) window; w->CenterOnScreen (); } void BView_mouse_down (void *view, int x, int y) { BView *vw = (BView *) view; if (vw->LockLooper ()) { vw->MouseDown (BPoint (x, y)); vw->UnlockLooper (); } } void BView_mouse_up (void *view, int x, int y) { BView *vw = (BView *) view; if (vw->LockLooper ()) { vw->MouseUp (BPoint (x, y)); vw->UnlockLooper (); } } void BView_mouse_moved (void *view, int x, int y, uint32_t transit) { BView *vw = (BView *) view; if (vw->LockLooper ()) { vw->MouseMoved (BPoint (x, y), transit, NULL); vw->UnlockLooper (); } } void BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h) { BBitmap *bmp = (BBitmap *) bitmap; unsigned char *data = (unsigned char *) bmp->Bits (); unsigned short *bts = (unsigned short *) bits; for (int i = 0; i < h; i++) { *((unsigned short *) data) = bts[i]; data += bmp->BytesPerRow (); } } void BView_publish_scroll_bar (void *view, int x, int y, int width, int height) { EmacsView *vw = (EmacsView *) view; if (vw->LockLooper ()) { vw->sb_region.Include (BRect (x, y, x - 1 + width, y - 1 + height)); vw->UnlockLooper (); } } void BView_forget_scroll_bar (void *view, int x, int y, int width, int height) { EmacsView *vw = (EmacsView *) view; if (vw->LockLooper ()) { vw->sb_region.Exclude (BRect (x, y, x - 1 + width, y - 1 + height)); vw->UnlockLooper (); } } int BFont_family_count (void) { return count_font_families (); } void BView_get_mouse (void *view, int *x, int *y) { BPoint l; BView *vw = (BView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->GetMouse (&l, NULL, 1); vw->UnlockLooper (); *x = std::lrint (l.x); *y = std::lrint (l.y); } void BView_convert_to_screen (void *view, int *x, int *y) { BPoint l = BPoint (*x, *y); BView *vw = (BView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->ConvertToScreen (&l); vw->UnlockLooper (); *x = std::lrint (l.x); *y = std::lrint (l.y); } void BWindow_change_decoration (void *window, int decorate_p) { BWindow *w = (BWindow *) window; if (!w->LockLooper ()) emacs_abort (); if (decorate_p) w->SetLook (B_DOCUMENT_WINDOW_LOOK); else w->SetLook (B_NO_BORDER_WINDOW_LOOK); w->UnlockLooper (); } void BWindow_set_tooltip_decoration (void *window) { BWindow *w = (BWindow *) window; if (!w->LockLooper ()) emacs_abort (); w->SetLook (B_BORDERED_WINDOW_LOOK); w->UnlockLooper (); } void BWindow_set_avoid_focus (void *window, int avoid_focus_p) { BWindow *w = (BWindow *) window; if (!w->LockLooper ()) emacs_abort (); if (!avoid_focus_p) w->SetFlags (w->Flags () & ~B_AVOID_FOCUS); else w->SetFlags (B_AVOID_FOCUS); w->UnlockLooper (); } void BView_emacs_delete (void *view) { EmacsView *vw = (EmacsView *) view; if (!vw->LockLooper ()) emacs_abort (); vw->RemoveSelf (); delete vw; } uint32_t haiku_current_workspace (void) { return current_workspace (); } uint32_t BWindow_workspaces (void *window) { return ((BWindow *) window)->Workspaces (); } void * BPopUpMenu_new (const char *name) { BPopUpMenu *menu = new BPopUpMenu (name, false); return menu; } void BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p, bool marked_p) { BMenu *m = (BMenu *) menu; BMessage *msg; if (ptr) msg = new BMessage (); BMenuItem *it = new BMenuItem (label, ptr ? msg : NULL); it->SetTarget (m->Window ()); it->SetEnabled (enabled_p); it->SetMarked (marked_p); if (ptr) msg->AddPointer ("menuptr", ptr); m->AddItem (it); } void BMenu_add_separator (void *menu) { BMenu *m = (BMenu *) menu; m->AddSeparatorItem (); } void * BMenu_new_submenu (void *menu, const char *label, bool enabled_p) { BMenu *m = (BMenu *) menu; BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN); mn->SetRadioMode (0); BMenuItem *i = new BMenuItem (mn); i->SetEnabled (enabled_p); m->AddItem (i); return mn; } void * BMenu_new_menu_bar_submenu (void *menu, const char *label) { BMenu *m = (BMenu *) menu; BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN); mn->SetRadioMode (0); BMenuItem *i = new BMenuItem (mn); i->SetEnabled (1); m->AddItem (i); return mn; } void * BMenu_run (void *menu, int x, int y) { BPopUpMenu *mn = (BPopUpMenu *) menu; BMenuItem *it = mn->Go (BPoint (x, y)); if (it) { BMessage *mg = it->Message (); if (mg) return (void *) mg->GetPointer ("menuptr"); else return NULL; } return NULL; } void BPopUpMenu_delete (void *menu) { delete (BPopUpMenu *) menu; } void * BMenuBar_new (void *view) { BView *vw = (BView *) view; EmacsMenuBar *bar = new EmacsMenuBar (); if (!vw->LockLooper ()) emacs_abort (); vw->AddChild ((BView *) bar); vw->UnlockLooper (); return bar; } void BMenuBar_delete (void *menubar) { BView *vw = (BView *) menubar; BView *p = vw->Parent (); if (!p->LockLooper ()) emacs_abort (); vw->RemoveSelf (); p->UnlockLooper (); delete vw; } void BMenu_delete_all (void *menu) { BMenu *mn = (BMenu *) menu; mn->RemoveItems (0, mn->CountItems (), true); } void BMenu_delete_from (void *menu, int start, int count) { BMenu *mn = (BMenu *) menu; mn->RemoveItems (start, count, true); } int BMenu_count_items (void *menu) { return ((BMenu *) menu)->CountItems (); } void * BMenu_item_at (void *menu, int idx) { return ((BMenu *) menu)->ItemAt (idx); } void BMenu_item_set_label (void *item, const char *label) { ((BMenuItem *) item)->SetLabel (label); } void * BMenu_item_get_menu (void *item) { return ((BMenuItem *) item)->Submenu (); } void haiku_ring_bell (void) { beep (); } void * BAlert_new (const char *text, enum haiku_alert_type type) { return new BAlert (NULL, text, NULL, NULL, NULL, B_WIDTH_AS_USUAL, (enum alert_type) type); } void * BAlert_add_button (void *alert, const char *text) { BAlert *al = (BAlert *) alert; al->AddButton (text); return al->ButtonAt (al->CountButtons () - 1); } int32_t BAlert_go (void *alert) { return ((BAlert *) alert)->Go (); } void BButton_set_enabled (void *button, int enabled_p) { ((BButton *) button)->SetEnabled (enabled_p); } void BView_set_tooltip (void *view, const char *tooltip) { ((BView *) view)->SetToolTip (tooltip); } void BAlert_delete (void *alert) { delete (BAlert *) alert; }