emacs/src/haiku_support.cc

2931 lines
63 KiB
C++
Raw Normal View History

Add support for the Haiku operating system and its window system * .gitignore: Add binaries specific to Haiku. * Makefie.in (HAVE_BE_APP): New variable. (install-arch-dep): Install Emacs and Emacs.pdmp when using Haiku. * configure.ac: Detect and configure for Haiku and various related configurations. (be-app, be-freetype, be-cairo): New options. (HAVE_BE_APP, HAIKU_OBJ, HAIKU_CXX_OBJ) (HAIKU_LIBS, HAIKU_CFLAGS): New variables. (HAIKU, HAVE_TINY_SPEED_T): New define. (emacs_config_features): Add BE_APP. * doc/emacs/Makefile.in (EMACSSOURCES): Add Haiku appendix. * doc/emacs/emacs.texi: Add Haiku appendix to menus and include it. * doc/emacs/haiku.texi: New Haiku appendix. * doc/lispref/display.texi (Defining Faces, Window Systems): Explain meaning of `haiku' as a window system identifier. (haiku-use-system-tooltips): Explain meaning of system tooltips on Haiku. * doc/lispref/frames.texi (Multiple Terminals): Explain meaning of haiku as a display type. (Frame Layout): Clarify section for Haiku frames. (Size Parameters): Explain limitations of fullwidth and fullheight on Haiku. (Management Parameters): Explain limitations of inhibiting double buffering on builds with Cairo, and the inability of frames with no-accept-focus to receive keyboard input on Haiku. (Font and Color Parameters): Explain the different font backends available on Haiku. (Raising and Lowering): Explain that lowering and restacking frames doesn't work on Haiku. (Child Frames): Explain oddities of child frame visibility on Haiku. * doc/lispref/os.texi (System Environment): Explain meaning of haiku. * etc/MACHINES: Add appropriate notices for Haiku. * etc/NEWS: Document changes. * etc/PROBLEMS: Document font spacing bug on Haiku. * lib-src/Makefile.in: Build be-resources binary on Haiku. (CXX, CXXFLAGS, NON_CXX_FLAGS, ALL_CXXFLAGS) (HAVE_BE_APP, HAIKU_LIBS, HAIKU_CFLAGS): New variables. (DONT_INSTALL): Add be-resources binary if on Haiku. (be-resources): New target. * lib-src/be_resources: Add helper binary for setting resources on the Emacs application. * lib-src/emacsclient.c (decode_options): Set alt_display to "be" on Haiku. * lisp/cus-edit.el (custom-button, custom-button-mouse) (custom-button-unraised, custom-button-pressed): Update face definitions for Haiku. * lisp/cus-start.el: Add haiku-debug-on-fatal-error and haiku-use-system-tooltips. * lisp/faces.el (face-valid-attribute-values): Clarify attribute comment for Haiku. (tool-bar): Add appropriate toolbar color for Haiku. * lisp/frame.el (haiku-frame-geometry) (haiku-mouse-absolute-pixel-position) (haiku-set-mouse-absolute-pixel-position) (haiku-frame-edges) (haiku-frame-list-z-order): New function declarations. (frame-geometry, frame-edges) (mouse-absolute-pixel-position) (set-mouse-absolute-pixel-position) (frame-list-z-order): Call appropriate window system functions on Haiku. (display-mouse-p, display-graphic-p) (display-images-p, display-pixel-height) (display-pixel-width, display-mm-height) (display-mm-width, display-backing-store) (display-save-under, display-planes) (display-color-cells, display-visual-class): Update type tests for Haiku. * lisp/international/mule-cmds.el (set-coding-system-map): Also prevent set-terminal-coding-system from appearing in the menu bar on Haiku. * lisp/loadup.el: Load Haiku-specific files when built with Haiku, and don't rename newly built Emacs on Haiku as BFS doesn't support hard links. * lisp/menu-bar.el (menu-bar-open): Add for Haiku. * lisp/mwheel.el (mouse-wheel-down-event): Expect wheel-up on Haiku. (mouse-wheel-up-event): Expect wheel-down on Haiku. (mouse-wheel-left-event): Expect wheel-left on Haiku. (mouse-wheel-right-event): Expect wheel-right on Haiku. * lisp/net/browse-url.el (browse-url--browser-defcustom-type): Add option for WebPositive. (browse-url-webpositive-program): New variable. (browse-url-default-program): Search for WebPositive. (browse-url-webpositive): New function. * lisp/net/eww.el (eww-form-submit, eww-form-file) (eww-form-checkbox, eww-form-select): Define faces appropriately for Haiku. * lisp/term/haiku-win.el: New file. * lisp/tooltip.el (menu-or-popup-active-p): New function declaration. (tooltip-show-help): Don't use tooltips on Haiku when a menu is active. * lisp/version.el (haiku-get-version-string): New function declaration. (emacs-version): Add Haiku version string if appropriate. * src/Makefile.in: Also produce binary named "Emacs" with Haiku resources set. (CXX, HAIKU_OBJ, HAIKU_CXX_OBJ, HAIKU_LIBS) (HAIKU_CFLAGS, HAVE_BE_APP, NON_CXX_FLAGS) (ALL_CXX_FLAGS): New variables. (.SUFFIXES): Add .cc. (.cc.o): New target. (base_obj): Add Haiku C objects. (doc_obj, obj): Split objects that should scanned for documentation into doc_obj. (SOME_MACHINE_OBJECTS): Add appropriate Haiku C objects. (all): Depend on Emacs and Emacs.pdmp on Haiku. (LIBES): Add Haiku libraries. (gl-stamp) ($(etc)/DOC): Scan doc_obj instead of obj (temacs$(EXEEXT): Use C++ linker on Haiku. (ctagsfiles3): New variable. (TAGS): Scan C++ files. * src/alloc.c (garbage_collect): Mark Haiku display. * src/dispextern.h (HAVE_NATIVE_TRANSFORMS): Also enable on Haiku. (struct image): Add fields for Haiku transforms. (RGB_PIXEL_COLOR): Define to unsigned long on Haiku as well. (sit_for): Also check USABLE_SIGPOLL. (init_display_interactive): Set initial window system to Haiku on Haiku builds. * src/emacs.c (main): Define Haiku syms and init haiku clipboard. (shut_down_emacs): Quit BApplication on Haiku and trigger debug on aborts if haiku_debug_on_fatal_error. (Vsystem_type): Update docstring. * src/fileio.c (next-read-file-uses-dialog-p): Enable on Haiku. * src/filelock.c (WTMP_FILE): Only define if BOOT_TIME is also defined. * src/floatfns.c (double_integer_scale): Work around Haiku libroot brain damage. * src/font.c (syms_of_font): Define appropriate font driver symbols for Haiku builds with various options. * src/font.h: Also enable ftcrfont on Haiku builds with Cairo. (font_data_structures_may_be_ill_formed): Also enable on Haiku builds that have Cairo. * src/frame.c (Fframep): Update doc-string for Haiku builds and return haiku if appropriate. (syms_of_frame): New symbol `haiku'. * src/frame.h (struct frame): Add output data for Haiku. (FRAME_HAIKU_P): New macro. (FRAME_WINDOW_P): Test for Haiku frames as well. * src/ftcrfont.c (RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG): New macros. (ftcrfont_draw): Add haiku specific code for Haiku builds with Cairo. * src/ftfont.c (ftfont_open): Set face. (ftfont_has_char, ftfont_text_extents): Work around crash. (syms_of_ftfont): New symbol `mono'. * src/ftfont.h (struct font_info): Enable Cairo-specific fields for Cairo builds on Haiku. * src/haiku_draw_support.cc: * src/haiku_font_support.cc: * src/haiku_io.c: * src/haiku_select.cc: * src/haiku_support.cc: * src/haiku_support.h: * src/haikufns.c: * src/haikufont.c: * src/haikugui.h: * src/haikuimage.c: * src/haikumenu.c: * src/haikuselect.c: * src/haikuselect.h: * src/haikuterm.c: * src/haikuterm.h: Add new files for Haiku windowing support. * src/haiku.c: Add new files for Haiku operating system support. * src/image.c: Implement image transforms and native XPM support on Haiku. (GET_PIXEL, PUT_PIXEL, NO_PIXMAP) (PIX_MASK_RETAIN, PIX_MASK_DRAW) (RGB_TO_ULONG, RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG, RED16_FROM_ULONG, GREEN16_FROM_ULONG) (BLUE16_FROM_ULONG): Define to appropriate values on Haiku. (image_create_bitmap_from_data): Add Haiku support. (image_create_bitmap_from_file): Add TODO on Haiku. (free_bitmap_record): Free bitmap on Haiku. (image_size_in_bytes): Implement for Haiku bitmaps. (image_set_transform): Implement on Haiku. (image_create_x_image_and_pixmap_1): Implement on Haiku, 24-bit or 1-bit only. (image_destroy_x_image, image_get_x_image): Use correct img and pixmap values on Haiku. (lookup_rgb_color): Use correct macro on Haiku. (image_to_emacs_colors): Implement on Haiku. (image_disable_image): Disable on Haiku. (image_can_use_native_api): Test for translator presence on Haiku. (native_image_load): Use translator on Haiku. (imagemagick_load_image): Add Haiku-specific quirks. (Fimage_transforms_p): Allow rotate90 on Haiku. (image_types): Enable native XPM support on Haiku. (syms_of_image): Enable XPM images on Haiku. * src/keyboard.c (kbd_buffer_get_event) (handle_async_input, handle_input_available_signal) (handle_user_signal, Fset_input_interrupt_mode) (init_keyboard): Check for USABLE_SIGPOLL along with USABLE_SIGIO. * src/lisp.h (pD): Work around broken Haiku headers. (HAVE_EXT_MENU_BAR): Define on Haiku. (handle_input_available_signal): Enable if we just have SIGPOLL as well. * src/menu.c (have_boxes): Return true on Haiku. (single_menu_item): Enable toolkit menus on Haiku. (find_and_call_menu_selection): Also enable on Haiku. * src/process.c (keyboard_bit_set): Enable with only usable SIGPOLL. (wait_reading_process_output): Test for SIGPOLL as well as SIGIO availability. * src/sound.c (sound_perror, vox_open) (vox_configure, vox_close): Enable for usable SIGPOLL as well. * src/sysdep.c (sys_subshell): Enable for usable SIGPOLL. (reset_sigio): Make conditional on F_SETOWN. (request_sigio, unrequest_sigio) (emacs_sigaction_init): Also handle SIGPOLLs. (init_sys_modes): Disable TCXONC usage on Haiku, as it doesn't have any ttys other than pseudo ttys, which don't support C-s/C-q flow control, and causes compiler warnings. (speeds): Disable high speeds if HAVE_TINY_SPEED_T. * src/termhooks.h (enum output_method): Add output_haiku. (struct terminal): Add Haiku display info. (TERMINAL_FONT_CACHE): Enable for Haiku. * src/terminal.c (Fterminal_live_p): Return `haiku' if appropriate. * src/verbose.mk.in (AM_V_CXX, AM_V_CXXLD): New logging variables. * src/xdisp.c (redisplay_internal) (note_mouse_highlight): Return on Haiku if a popup is activated. (display_menu_bar): Return on Haiku if frame is a Haiku frame. * src/xfaces.c (GCGraphicsExposures): Enable correctly on Haiku. (x_create_gc): Enable dummy GC code on Haiku. * src/xfns.c (x-server-version, x-file-dialog): Add Haiku specifics to doc strings. * src/xterm.c (syms_of_xterm): Add Haiku information to doc string.
2021-11-20 21:30:08 +08:00
/* 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 <https://www.gnu.org/licenses/>. */
#include <config.h>
#include <app/Application.h>
#include <app/Cursor.h>
#include <app/Messenger.h>
#include <interface/GraphicsDefs.h>
#include <interface/InterfaceDefs.h>
#include <interface/Bitmap.h>
#include <interface/Window.h>
#include <interface/View.h>
#include <interface/Screen.h>
#include <interface/ScrollBar.h>
#include <interface/Region.h>
#include <interface/Menu.h>
#include <interface/MenuItem.h>
#include <interface/PopUpMenu.h>
#include <interface/MenuBar.h>
#include <interface/Alert.h>
#include <interface/Button.h>
#include <locale/UnicodeChar.h>
#include <game/WindowScreen.h>
#include <game/DirectWindow.h>
#include <storage/Entry.h>
#include <storage/Path.h>
#include <storage/FilePanel.h>
#include <storage/AppFileInfo.h>
#include <storage/Path.h>
#include <storage/PathFinder.h>
#include <support/Beep.h>
#include <support/DataIO.h>
#include <support/Locker.h>
#include <translation/TranslatorRoster.h>
#include <translation/TranslationDefs.h>
#include <translation/TranslationUtils.h>
#include <kernel/OS.h>
#include <kernel/fs_attr.h>
#include <kernel/scheduler.h>
#include <private/interface/ToolTip.h>
#include <cmath>
#include <cstring>
#include <cstdint>
#include <cstdio>
#include <csignal>
#include <cfloat>
#include <pthread.h>
#ifdef USE_BE_CAIRO
#include <cairo.h>
#endif
#include "haiku_support.h"
#define SCROLL_BAR_UPDATE 3000
static color_space dpy_color_space = B_NO_COLOR_SPACE;
static key_map *key_map = NULL;
static char *key_chars = NULL;
static BLocker key_map_lock;
extern "C"
{
extern _Noreturn void emacs_abort (void);
/* Also defined in haikuterm.h. */
extern void be_app_quit (void);
}
static thread_id app_thread;
_Noreturn void
gui_abort (const char *msg)
{
fprintf (stderr, "Abort in GUI code: %s\n", msg);
fprintf (stderr, "Under Haiku, Emacs cannot recover from errors in GUI code\n");
fprintf (stderr, "App Server disconnects usually manifest as bitmap "
"initialization failures or lock failures.");
emacs_abort ();
}
#ifdef USE_BE_CAIRO
static cairo_format_t
cairo_format_from_color_space (color_space space)
{
switch (space)
{
case B_RGBA32:
return CAIRO_FORMAT_ARGB32;
case B_RGB32:
return CAIRO_FORMAT_RGB24;
case B_RGB16:
return CAIRO_FORMAT_RGB16_565;
case B_GRAY8:
return CAIRO_FORMAT_A8;
case B_GRAY1:
return CAIRO_FORMAT_A1;
default:
gui_abort ("Unsupported color space");
}
}
#endif
static void
map_key (char *chars, int32 offset, uint32_t *c)
{
int size = chars[offset++];
switch (size)
{
case 0:
break;
case 1:
*c = chars[offset];
break;
default:
{
char str[5];
int i = (size <= 4) ? size : 4;
strncpy (str, &(chars[offset]), i);
str[i] = '0';
*c = BUnicodeChar::FromUTF8 ((char *) &str);
break;
}
}
}
static void
map_shift (uint32_t kc, uint32_t *ch)
{
if (!key_map_lock.Lock ())
gui_abort ("Failed to lock keymap");
if (!key_map)
get_key_map (&key_map, &key_chars);
if (!key_map)
return;
if (kc >= 128)
return;
int32_t m = key_map->shift_map[kc];
map_key (key_chars, m, ch);
key_map_lock.Unlock ();
}
static void
map_normal (uint32_t kc, uint32_t *ch)
{
if (!key_map_lock.Lock ())
gui_abort ("Failed to lock keymap");
if (!key_map)
get_key_map (&key_map, &key_chars);
if (!key_map)
return;
if (kc >= 128)
return;
int32_t m = key_map->normal_map[kc];
map_key (key_chars, m, ch);
key_map_lock.Unlock ();
}
class Emacs : public BApplication
{
public:
Emacs () : BApplication ("application/x-vnd.GNU-emacs")
{
}
void
AboutRequested (void)
{
BAlert *about = new BAlert (PACKAGE_NAME,
PACKAGE_STRING
"\nThe extensible, self-documenting, real-time display editor.",
"Close");
about->Go ();
}
bool
QuitRequested (void)
{
struct haiku_app_quit_requested_event rq;
haiku_write (APP_QUIT_REQUESTED_EVENT, &rq);
return 0;
}
void
RefsReceived (BMessage *msg)
{
struct haiku_refs_event rq;
entry_ref ref;
BEntry entry;
BPath path;
int32 cookie = 0;
int32 x, y;
void *window;
if ((msg->FindPointer ("window", 0, &window) != B_OK)
|| (msg->FindInt32 ("x", 0, &x) != B_OK)
|| (msg->FindInt32 ("y", 0, &y) != B_OK))
return;
rq.window = window;
rq.x = x;
rq.y = y;
while (msg->FindRef ("refs", cookie++, &ref) == B_OK)
{
if (entry.SetTo (&ref, 0) == B_OK
&& entry.GetPath (&path) == B_OK)
{
rq.ref = strdup (path.Path ());
haiku_write (REFS_EVENT, &rq);
}
}
}
};
class EmacsWindow : public BDirectWindow
{
public:
struct child_frame
{
struct child_frame *next;
int xoff, yoff;
EmacsWindow *window;
} *subset_windows = NULL;
EmacsWindow *parent = NULL;
BRect pre_fullscreen_rect;
BRect pre_zoom_rect;
int x_before_zoom = INT_MIN;
int y_before_zoom = INT_MIN;
int fullscreen_p = 0;
int zoomed_p = 0;
int shown_flag = 0;
#ifdef USE_BE_CAIRO
BLocker surface_lock;
cairo_surface_t *cr_surface = NULL;
#endif
EmacsWindow () : BDirectWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK,
B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS)
{
}
~EmacsWindow ()
{
struct child_frame *next;
for (struct child_frame *f = subset_windows; f; f = next)
{
f->window->Unparent ();
next = f->next;
delete f;
}
if (this->parent)
UnparentAndUnlink ();
#ifdef USE_BE_CAIRO
if (!surface_lock.Lock ())
gui_abort ("Failed to lock cairo surface");
if (cr_surface)
{
cairo_surface_destroy (cr_surface);
cr_surface = NULL;
}
surface_lock.Unlock ();
#endif
}
void
UpwardsSubset (EmacsWindow *w)
{
for (; w; w = w->parent)
AddToSubset (w);
}
void
UpwardsSubsetChildren (EmacsWindow *w)
{
UpwardsSubset (w);
for (struct child_frame *f = subset_windows; f;
f = f->next)
f->window->UpwardsSubsetChildren (w);
}
void
UpwardsUnSubset (EmacsWindow *w)
{
for (; w; w = w->parent)
RemoveFromSubset (w);
}
void
UpwardsUnSubsetChildren (EmacsWindow *w)
{
UpwardsUnSubset (w);
for (struct child_frame *f = subset_windows; f;
f = f->next)
f->window->UpwardsUnSubsetChildren (w);
}
void
Unparent (void)
{
this->SetFeel (B_NORMAL_WINDOW_FEEL);
UpwardsUnSubsetChildren (parent);
this->RemoveFromSubset (this);
this->parent = NULL;
if (fullscreen_p)
{
fullscreen_p = 0;
MakeFullscreen (1);
}
}
void
UnparentAndUnlink (void)
{
this->parent->UnlinkChild (this);
this->Unparent ();
}
void
UnlinkChild (EmacsWindow *window)
{
struct child_frame *last = NULL;
struct child_frame *tem = subset_windows;
for (; tem; last = tem, tem = tem->next)
{
if (tem->window == window)
{
if (last)
last->next = tem->next;
if (tem == subset_windows)
subset_windows = NULL;
delete tem;
return;
}
}
gui_abort ("Failed to unlink child frame");
}
void
ParentTo (EmacsWindow *window)
{
if (this->parent)
UnparentAndUnlink ();
this->parent = window;
this->SetFeel (B_FLOATING_SUBSET_WINDOW_FEEL);
this->AddToSubset (this);
if (!IsHidden () && this->parent)
UpwardsSubsetChildren (parent);
if (fullscreen_p)
{
fullscreen_p = 0;
MakeFullscreen (1);
}
this->Sync ();
window->LinkChild (this);
}
void
LinkChild (EmacsWindow *window)
{
struct child_frame *f = new struct child_frame;
for (struct child_frame *f = subset_windows; f;
f = f->next)
{
if (window == f->window)
gui_abort ("Trying to link a child frame that is already present");
}
f->window = window;
f->next = subset_windows;
f->xoff = -1;
f->yoff = -1;
subset_windows = f;
}
void
DoMove (struct child_frame *f)
{
BRect frame = this->Frame ();
f->window->MoveTo (frame.left + f->xoff,
frame.top + f->yoff);
this->Sync ();
}
void
DoUpdateWorkspace (struct child_frame *f)
{
f->window->SetWorkspaces (this->Workspaces ());
}
void
MoveChild (EmacsWindow *window, int xoff, int yoff,
int weak_p)
{
for (struct child_frame *f = subset_windows; f;
f = f->next)
{
if (window == f->window)
{
f->xoff = xoff;
f->yoff = yoff;
if (!weak_p)
DoMove (f);
return;
}
}
gui_abort ("Trying to move a child frame that doesn't exist");
}
void
WindowActivated (bool activated)
{
struct haiku_activation_event rq;
rq.window = this;
rq.activated_p = activated;
haiku_write (ACTIVATION, &rq);
}
void
DirectConnected (direct_buffer_info *info)
{
#ifdef USE_BE_CAIRO
if (!surface_lock.Lock ())
gui_abort ("Failed to lock window direct cr surface");
if (cr_surface)
{
cairo_surface_destroy (cr_surface);
cr_surface = NULL;
}
if (info->buffer_state != B_DIRECT_STOP)
{
int left, top, right, bottom;
left = info->clip_bounds.left;
top = info->clip_bounds.top;
right = info->clip_bounds.right;
bottom = info->clip_bounds.bottom;
unsigned char *bits = (unsigned char *) info->bits;
if ((info->bits_per_pixel % 8) == 0)
{
bits += info->bytes_per_row * top;
bits += (left * info->bits_per_pixel / 8);
cr_surface = cairo_image_surface_create_for_data
(bits,
cairo_format_from_color_space (info->pixel_format),
right - left + 1,
bottom - top + 1,
info->bytes_per_row);
}
}
surface_lock.Unlock ();
#endif
}
void
MessageReceived (BMessage *msg)
{
int32 old_what = 0;
if (msg->WasDropped ())
{
entry_ref ref;
BPoint whereto;
if (msg->FindRef ("refs", &ref) == B_OK)
{
msg->what = B_REFS_RECEIVED;
msg->AddPointer ("window", this);
if (msg->FindPoint ("_drop_point_", &whereto) == B_OK)
{
this->ConvertFromScreen (&whereto);
msg->AddInt32 ("x", whereto.x);
msg->AddInt32 ("y", whereto.y);
}
be_app->PostMessage (msg);
msg->SendReply (B_OK);
}
}
else 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);
}
else if (msg->what == 'FPSE'
|| ((msg->FindInt32 ("old_what", &old_what) == B_OK
&& old_what == 'FPSE')))
{
struct haiku_file_panel_event rq;
BEntry entry;
BPath path;
entry_ref ref;
rq.ptr = NULL;
if (msg->FindRef ("refs", &ref) == B_OK &&
entry.SetTo (&ref, 0) == B_OK &&
entry.GetPath (&path) == B_OK)
{
const char *str_path = path.Path ();
if (str_path)
rq.ptr = strdup (str_path);
}
if (msg->FindRef ("directory", &ref),
entry.SetTo (&ref, 0) == B_OK &&
entry.GetPath (&path) == B_OK)
{
const char *name = msg->GetString ("name");
const char *str_path = path.Path ();
if (name)
{
char str_buf[std::strlen (str_path)
+ std::strlen (name) + 2];
snprintf ((char *) &str_buf,
std::strlen (str_path)
+ std::strlen (name) + 2, "%s/%s",
str_path, name);
rq.ptr = strdup (str_buf);
}
}
haiku_write (FILE_PANEL_EVENT, &rq);
}
else
BDirectWindow::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;
uint32_t mods = modifiers ();
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;
if (mods & B_OPTION_KEY)
rq.modifiers |= HAIKU_MODIFIER_SUPER;
rq.mb_char = code;
rq.kc = msg->GetInt32 ("key", -1);
rq.unraw_mb_char =
BUnicodeChar::FromUTF8 (msg->GetString ("bytes"));
if ((mods & B_SHIFT_KEY) && rq.kc >= 0)
map_shift (rq.kc, &rq.unraw_mb_char);
else if (rq.kc >= 0)
map_normal (rq.kc, &rq.unraw_mb_char);
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;
uint32_t mods = modifiers ();
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;
if (mods & B_OPTION_KEY)
rq.modifiers |= HAIKU_MODIFIER_SUPER;
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;
Add support for the Haiku operating system and its window system * .gitignore: Add binaries specific to Haiku. * Makefie.in (HAVE_BE_APP): New variable. (install-arch-dep): Install Emacs and Emacs.pdmp when using Haiku. * configure.ac: Detect and configure for Haiku and various related configurations. (be-app, be-freetype, be-cairo): New options. (HAVE_BE_APP, HAIKU_OBJ, HAIKU_CXX_OBJ) (HAIKU_LIBS, HAIKU_CFLAGS): New variables. (HAIKU, HAVE_TINY_SPEED_T): New define. (emacs_config_features): Add BE_APP. * doc/emacs/Makefile.in (EMACSSOURCES): Add Haiku appendix. * doc/emacs/emacs.texi: Add Haiku appendix to menus and include it. * doc/emacs/haiku.texi: New Haiku appendix. * doc/lispref/display.texi (Defining Faces, Window Systems): Explain meaning of `haiku' as a window system identifier. (haiku-use-system-tooltips): Explain meaning of system tooltips on Haiku. * doc/lispref/frames.texi (Multiple Terminals): Explain meaning of haiku as a display type. (Frame Layout): Clarify section for Haiku frames. (Size Parameters): Explain limitations of fullwidth and fullheight on Haiku. (Management Parameters): Explain limitations of inhibiting double buffering on builds with Cairo, and the inability of frames with no-accept-focus to receive keyboard input on Haiku. (Font and Color Parameters): Explain the different font backends available on Haiku. (Raising and Lowering): Explain that lowering and restacking frames doesn't work on Haiku. (Child Frames): Explain oddities of child frame visibility on Haiku. * doc/lispref/os.texi (System Environment): Explain meaning of haiku. * etc/MACHINES: Add appropriate notices for Haiku. * etc/NEWS: Document changes. * etc/PROBLEMS: Document font spacing bug on Haiku. * lib-src/Makefile.in: Build be-resources binary on Haiku. (CXX, CXXFLAGS, NON_CXX_FLAGS, ALL_CXXFLAGS) (HAVE_BE_APP, HAIKU_LIBS, HAIKU_CFLAGS): New variables. (DONT_INSTALL): Add be-resources binary if on Haiku. (be-resources): New target. * lib-src/be_resources: Add helper binary for setting resources on the Emacs application. * lib-src/emacsclient.c (decode_options): Set alt_display to "be" on Haiku. * lisp/cus-edit.el (custom-button, custom-button-mouse) (custom-button-unraised, custom-button-pressed): Update face definitions for Haiku. * lisp/cus-start.el: Add haiku-debug-on-fatal-error and haiku-use-system-tooltips. * lisp/faces.el (face-valid-attribute-values): Clarify attribute comment for Haiku. (tool-bar): Add appropriate toolbar color for Haiku. * lisp/frame.el (haiku-frame-geometry) (haiku-mouse-absolute-pixel-position) (haiku-set-mouse-absolute-pixel-position) (haiku-frame-edges) (haiku-frame-list-z-order): New function declarations. (frame-geometry, frame-edges) (mouse-absolute-pixel-position) (set-mouse-absolute-pixel-position) (frame-list-z-order): Call appropriate window system functions on Haiku. (display-mouse-p, display-graphic-p) (display-images-p, display-pixel-height) (display-pixel-width, display-mm-height) (display-mm-width, display-backing-store) (display-save-under, display-planes) (display-color-cells, display-visual-class): Update type tests for Haiku. * lisp/international/mule-cmds.el (set-coding-system-map): Also prevent set-terminal-coding-system from appearing in the menu bar on Haiku. * lisp/loadup.el: Load Haiku-specific files when built with Haiku, and don't rename newly built Emacs on Haiku as BFS doesn't support hard links. * lisp/menu-bar.el (menu-bar-open): Add for Haiku. * lisp/mwheel.el (mouse-wheel-down-event): Expect wheel-up on Haiku. (mouse-wheel-up-event): Expect wheel-down on Haiku. (mouse-wheel-left-event): Expect wheel-left on Haiku. (mouse-wheel-right-event): Expect wheel-right on Haiku. * lisp/net/browse-url.el (browse-url--browser-defcustom-type): Add option for WebPositive. (browse-url-webpositive-program): New variable. (browse-url-default-program): Search for WebPositive. (browse-url-webpositive): New function. * lisp/net/eww.el (eww-form-submit, eww-form-file) (eww-form-checkbox, eww-form-select): Define faces appropriately for Haiku. * lisp/term/haiku-win.el: New file. * lisp/tooltip.el (menu-or-popup-active-p): New function declaration. (tooltip-show-help): Don't use tooltips on Haiku when a menu is active. * lisp/version.el (haiku-get-version-string): New function declaration. (emacs-version): Add Haiku version string if appropriate. * src/Makefile.in: Also produce binary named "Emacs" with Haiku resources set. (CXX, HAIKU_OBJ, HAIKU_CXX_OBJ, HAIKU_LIBS) (HAIKU_CFLAGS, HAVE_BE_APP, NON_CXX_FLAGS) (ALL_CXX_FLAGS): New variables. (.SUFFIXES): Add .cc. (.cc.o): New target. (base_obj): Add Haiku C objects. (doc_obj, obj): Split objects that should scanned for documentation into doc_obj. (SOME_MACHINE_OBJECTS): Add appropriate Haiku C objects. (all): Depend on Emacs and Emacs.pdmp on Haiku. (LIBES): Add Haiku libraries. (gl-stamp) ($(etc)/DOC): Scan doc_obj instead of obj (temacs$(EXEEXT): Use C++ linker on Haiku. (ctagsfiles3): New variable. (TAGS): Scan C++ files. * src/alloc.c (garbage_collect): Mark Haiku display. * src/dispextern.h (HAVE_NATIVE_TRANSFORMS): Also enable on Haiku. (struct image): Add fields for Haiku transforms. (RGB_PIXEL_COLOR): Define to unsigned long on Haiku as well. (sit_for): Also check USABLE_SIGPOLL. (init_display_interactive): Set initial window system to Haiku on Haiku builds. * src/emacs.c (main): Define Haiku syms and init haiku clipboard. (shut_down_emacs): Quit BApplication on Haiku and trigger debug on aborts if haiku_debug_on_fatal_error. (Vsystem_type): Update docstring. * src/fileio.c (next-read-file-uses-dialog-p): Enable on Haiku. * src/filelock.c (WTMP_FILE): Only define if BOOT_TIME is also defined. * src/floatfns.c (double_integer_scale): Work around Haiku libroot brain damage. * src/font.c (syms_of_font): Define appropriate font driver symbols for Haiku builds with various options. * src/font.h: Also enable ftcrfont on Haiku builds with Cairo. (font_data_structures_may_be_ill_formed): Also enable on Haiku builds that have Cairo. * src/frame.c (Fframep): Update doc-string for Haiku builds and return haiku if appropriate. (syms_of_frame): New symbol `haiku'. * src/frame.h (struct frame): Add output data for Haiku. (FRAME_HAIKU_P): New macro. (FRAME_WINDOW_P): Test for Haiku frames as well. * src/ftcrfont.c (RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG): New macros. (ftcrfont_draw): Add haiku specific code for Haiku builds with Cairo. * src/ftfont.c (ftfont_open): Set face. (ftfont_has_char, ftfont_text_extents): Work around crash. (syms_of_ftfont): New symbol `mono'. * src/ftfont.h (struct font_info): Enable Cairo-specific fields for Cairo builds on Haiku. * src/haiku_draw_support.cc: * src/haiku_font_support.cc: * src/haiku_io.c: * src/haiku_select.cc: * src/haiku_support.cc: * src/haiku_support.h: * src/haikufns.c: * src/haikufont.c: * src/haikugui.h: * src/haikuimage.c: * src/haikumenu.c: * src/haikuselect.c: * src/haikuselect.h: * src/haikuterm.c: * src/haikuterm.h: Add new files for Haiku windowing support. * src/haiku.c: Add new files for Haiku operating system support. * src/image.c: Implement image transforms and native XPM support on Haiku. (GET_PIXEL, PUT_PIXEL, NO_PIXMAP) (PIX_MASK_RETAIN, PIX_MASK_DRAW) (RGB_TO_ULONG, RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG, RED16_FROM_ULONG, GREEN16_FROM_ULONG) (BLUE16_FROM_ULONG): Define to appropriate values on Haiku. (image_create_bitmap_from_data): Add Haiku support. (image_create_bitmap_from_file): Add TODO on Haiku. (free_bitmap_record): Free bitmap on Haiku. (image_size_in_bytes): Implement for Haiku bitmaps. (image_set_transform): Implement on Haiku. (image_create_x_image_and_pixmap_1): Implement on Haiku, 24-bit or 1-bit only. (image_destroy_x_image, image_get_x_image): Use correct img and pixmap values on Haiku. (lookup_rgb_color): Use correct macro on Haiku. (image_to_emacs_colors): Implement on Haiku. (image_disable_image): Disable on Haiku. (image_can_use_native_api): Test for translator presence on Haiku. (native_image_load): Use translator on Haiku. (imagemagick_load_image): Add Haiku-specific quirks. (Fimage_transforms_p): Allow rotate90 on Haiku. (image_types): Enable native XPM support on Haiku. (syms_of_image): Enable XPM images on Haiku. * src/keyboard.c (kbd_buffer_get_event) (handle_async_input, handle_input_available_signal) (handle_user_signal, Fset_input_interrupt_mode) (init_keyboard): Check for USABLE_SIGPOLL along with USABLE_SIGIO. * src/lisp.h (pD): Work around broken Haiku headers. (HAVE_EXT_MENU_BAR): Define on Haiku. (handle_input_available_signal): Enable if we just have SIGPOLL as well. * src/menu.c (have_boxes): Return true on Haiku. (single_menu_item): Enable toolkit menus on Haiku. (find_and_call_menu_selection): Also enable on Haiku. * src/process.c (keyboard_bit_set): Enable with only usable SIGPOLL. (wait_reading_process_output): Test for SIGPOLL as well as SIGIO availability. * src/sound.c (sound_perror, vox_open) (vox_configure, vox_close): Enable for usable SIGPOLL as well. * src/sysdep.c (sys_subshell): Enable for usable SIGPOLL. (reset_sigio): Make conditional on F_SETOWN. (request_sigio, unrequest_sigio) (emacs_sigaction_init): Also handle SIGPOLLs. (init_sys_modes): Disable TCXONC usage on Haiku, as it doesn't have any ttys other than pseudo ttys, which don't support C-s/C-q flow control, and causes compiler warnings. (speeds): Disable high speeds if HAVE_TINY_SPEED_T. * src/termhooks.h (enum output_method): Add output_haiku. (struct terminal): Add Haiku display info. (TERMINAL_FONT_CACHE): Enable for Haiku. * src/terminal.c (Fterminal_live_p): Return `haiku' if appropriate. * src/verbose.mk.in (AM_V_CXX, AM_V_CXXLD): New logging variables. * src/xdisp.c (redisplay_internal) (note_mouse_highlight): Return on Haiku if a popup is activated. (display_menu_bar): Return on Haiku if frame is a Haiku frame. * src/xfaces.c (GCGraphicsExposures): Enable correctly on Haiku. (x_create_gc): Enable dummy GC code on Haiku. * src/xfns.c (x-server-version, x-file-dialog): Add Haiku specifics to doc strings. * src/xterm.c (syms_of_xterm): Add Haiku information to doc string.
2021-11-20 21:30:08 +08:00
haiku_write (WHEEL_MOVE_EVENT, &rq);
};
}
else
BDirectWindow::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;
Add support for the Haiku operating system and its window system * .gitignore: Add binaries specific to Haiku. * Makefie.in (HAVE_BE_APP): New variable. (install-arch-dep): Install Emacs and Emacs.pdmp when using Haiku. * configure.ac: Detect and configure for Haiku and various related configurations. (be-app, be-freetype, be-cairo): New options. (HAVE_BE_APP, HAIKU_OBJ, HAIKU_CXX_OBJ) (HAIKU_LIBS, HAIKU_CFLAGS): New variables. (HAIKU, HAVE_TINY_SPEED_T): New define. (emacs_config_features): Add BE_APP. * doc/emacs/Makefile.in (EMACSSOURCES): Add Haiku appendix. * doc/emacs/emacs.texi: Add Haiku appendix to menus and include it. * doc/emacs/haiku.texi: New Haiku appendix. * doc/lispref/display.texi (Defining Faces, Window Systems): Explain meaning of `haiku' as a window system identifier. (haiku-use-system-tooltips): Explain meaning of system tooltips on Haiku. * doc/lispref/frames.texi (Multiple Terminals): Explain meaning of haiku as a display type. (Frame Layout): Clarify section for Haiku frames. (Size Parameters): Explain limitations of fullwidth and fullheight on Haiku. (Management Parameters): Explain limitations of inhibiting double buffering on builds with Cairo, and the inability of frames with no-accept-focus to receive keyboard input on Haiku. (Font and Color Parameters): Explain the different font backends available on Haiku. (Raising and Lowering): Explain that lowering and restacking frames doesn't work on Haiku. (Child Frames): Explain oddities of child frame visibility on Haiku. * doc/lispref/os.texi (System Environment): Explain meaning of haiku. * etc/MACHINES: Add appropriate notices for Haiku. * etc/NEWS: Document changes. * etc/PROBLEMS: Document font spacing bug on Haiku. * lib-src/Makefile.in: Build be-resources binary on Haiku. (CXX, CXXFLAGS, NON_CXX_FLAGS, ALL_CXXFLAGS) (HAVE_BE_APP, HAIKU_LIBS, HAIKU_CFLAGS): New variables. (DONT_INSTALL): Add be-resources binary if on Haiku. (be-resources): New target. * lib-src/be_resources: Add helper binary for setting resources on the Emacs application. * lib-src/emacsclient.c (decode_options): Set alt_display to "be" on Haiku. * lisp/cus-edit.el (custom-button, custom-button-mouse) (custom-button-unraised, custom-button-pressed): Update face definitions for Haiku. * lisp/cus-start.el: Add haiku-debug-on-fatal-error and haiku-use-system-tooltips. * lisp/faces.el (face-valid-attribute-values): Clarify attribute comment for Haiku. (tool-bar): Add appropriate toolbar color for Haiku. * lisp/frame.el (haiku-frame-geometry) (haiku-mouse-absolute-pixel-position) (haiku-set-mouse-absolute-pixel-position) (haiku-frame-edges) (haiku-frame-list-z-order): New function declarations. (frame-geometry, frame-edges) (mouse-absolute-pixel-position) (set-mouse-absolute-pixel-position) (frame-list-z-order): Call appropriate window system functions on Haiku. (display-mouse-p, display-graphic-p) (display-images-p, display-pixel-height) (display-pixel-width, display-mm-height) (display-mm-width, display-backing-store) (display-save-under, display-planes) (display-color-cells, display-visual-class): Update type tests for Haiku. * lisp/international/mule-cmds.el (set-coding-system-map): Also prevent set-terminal-coding-system from appearing in the menu bar on Haiku. * lisp/loadup.el: Load Haiku-specific files when built with Haiku, and don't rename newly built Emacs on Haiku as BFS doesn't support hard links. * lisp/menu-bar.el (menu-bar-open): Add for Haiku. * lisp/mwheel.el (mouse-wheel-down-event): Expect wheel-up on Haiku. (mouse-wheel-up-event): Expect wheel-down on Haiku. (mouse-wheel-left-event): Expect wheel-left on Haiku. (mouse-wheel-right-event): Expect wheel-right on Haiku. * lisp/net/browse-url.el (browse-url--browser-defcustom-type): Add option for WebPositive. (browse-url-webpositive-program): New variable. (browse-url-default-program): Search for WebPositive. (browse-url-webpositive): New function. * lisp/net/eww.el (eww-form-submit, eww-form-file) (eww-form-checkbox, eww-form-select): Define faces appropriately for Haiku. * lisp/term/haiku-win.el: New file. * lisp/tooltip.el (menu-or-popup-active-p): New function declaration. (tooltip-show-help): Don't use tooltips on Haiku when a menu is active. * lisp/version.el (haiku-get-version-string): New function declaration. (emacs-version): Add Haiku version string if appropriate. * src/Makefile.in: Also produce binary named "Emacs" with Haiku resources set. (CXX, HAIKU_OBJ, HAIKU_CXX_OBJ, HAIKU_LIBS) (HAIKU_CFLAGS, HAVE_BE_APP, NON_CXX_FLAGS) (ALL_CXX_FLAGS): New variables. (.SUFFIXES): Add .cc. (.cc.o): New target. (base_obj): Add Haiku C objects. (doc_obj, obj): Split objects that should scanned for documentation into doc_obj. (SOME_MACHINE_OBJECTS): Add appropriate Haiku C objects. (all): Depend on Emacs and Emacs.pdmp on Haiku. (LIBES): Add Haiku libraries. (gl-stamp) ($(etc)/DOC): Scan doc_obj instead of obj (temacs$(EXEEXT): Use C++ linker on Haiku. (ctagsfiles3): New variable. (TAGS): Scan C++ files. * src/alloc.c (garbage_collect): Mark Haiku display. * src/dispextern.h (HAVE_NATIVE_TRANSFORMS): Also enable on Haiku. (struct image): Add fields for Haiku transforms. (RGB_PIXEL_COLOR): Define to unsigned long on Haiku as well. (sit_for): Also check USABLE_SIGPOLL. (init_display_interactive): Set initial window system to Haiku on Haiku builds. * src/emacs.c (main): Define Haiku syms and init haiku clipboard. (shut_down_emacs): Quit BApplication on Haiku and trigger debug on aborts if haiku_debug_on_fatal_error. (Vsystem_type): Update docstring. * src/fileio.c (next-read-file-uses-dialog-p): Enable on Haiku. * src/filelock.c (WTMP_FILE): Only define if BOOT_TIME is also defined. * src/floatfns.c (double_integer_scale): Work around Haiku libroot brain damage. * src/font.c (syms_of_font): Define appropriate font driver symbols for Haiku builds with various options. * src/font.h: Also enable ftcrfont on Haiku builds with Cairo. (font_data_structures_may_be_ill_formed): Also enable on Haiku builds that have Cairo. * src/frame.c (Fframep): Update doc-string for Haiku builds and return haiku if appropriate. (syms_of_frame): New symbol `haiku'. * src/frame.h (struct frame): Add output data for Haiku. (FRAME_HAIKU_P): New macro. (FRAME_WINDOW_P): Test for Haiku frames as well. * src/ftcrfont.c (RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG): New macros. (ftcrfont_draw): Add haiku specific code for Haiku builds with Cairo. * src/ftfont.c (ftfont_open): Set face. (ftfont_has_char, ftfont_text_extents): Work around crash. (syms_of_ftfont): New symbol `mono'. * src/ftfont.h (struct font_info): Enable Cairo-specific fields for Cairo builds on Haiku. * src/haiku_draw_support.cc: * src/haiku_font_support.cc: * src/haiku_io.c: * src/haiku_select.cc: * src/haiku_support.cc: * src/haiku_support.h: * src/haikufns.c: * src/haikufont.c: * src/haikugui.h: * src/haikuimage.c: * src/haikumenu.c: * src/haikuselect.c: * src/haikuselect.h: * src/haikuterm.c: * src/haikuterm.h: Add new files for Haiku windowing support. * src/haiku.c: Add new files for Haiku operating system support. * src/image.c: Implement image transforms and native XPM support on Haiku. (GET_PIXEL, PUT_PIXEL, NO_PIXMAP) (PIX_MASK_RETAIN, PIX_MASK_DRAW) (RGB_TO_ULONG, RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG, RED16_FROM_ULONG, GREEN16_FROM_ULONG) (BLUE16_FROM_ULONG): Define to appropriate values on Haiku. (image_create_bitmap_from_data): Add Haiku support. (image_create_bitmap_from_file): Add TODO on Haiku. (free_bitmap_record): Free bitmap on Haiku. (image_size_in_bytes): Implement for Haiku bitmaps. (image_set_transform): Implement on Haiku. (image_create_x_image_and_pixmap_1): Implement on Haiku, 24-bit or 1-bit only. (image_destroy_x_image, image_get_x_image): Use correct img and pixmap values on Haiku. (lookup_rgb_color): Use correct macro on Haiku. (image_to_emacs_colors): Implement on Haiku. (image_disable_image): Disable on Haiku. (image_can_use_native_api): Test for translator presence on Haiku. (native_image_load): Use translator on Haiku. (imagemagick_load_image): Add Haiku-specific quirks. (Fimage_transforms_p): Allow rotate90 on Haiku. (image_types): Enable native XPM support on Haiku. (syms_of_image): Enable XPM images on Haiku. * src/keyboard.c (kbd_buffer_get_event) (handle_async_input, handle_input_available_signal) (handle_user_signal, Fset_input_interrupt_mode) (init_keyboard): Check for USABLE_SIGPOLL along with USABLE_SIGIO. * src/lisp.h (pD): Work around broken Haiku headers. (HAVE_EXT_MENU_BAR): Define on Haiku. (handle_input_available_signal): Enable if we just have SIGPOLL as well. * src/menu.c (have_boxes): Return true on Haiku. (single_menu_item): Enable toolkit menus on Haiku. (find_and_call_menu_selection): Also enable on Haiku. * src/process.c (keyboard_bit_set): Enable with only usable SIGPOLL. (wait_reading_process_output): Test for SIGPOLL as well as SIGIO availability. * src/sound.c (sound_perror, vox_open) (vox_configure, vox_close): Enable for usable SIGPOLL as well. * src/sysdep.c (sys_subshell): Enable for usable SIGPOLL. (reset_sigio): Make conditional on F_SETOWN. (request_sigio, unrequest_sigio) (emacs_sigaction_init): Also handle SIGPOLLs. (init_sys_modes): Disable TCXONC usage on Haiku, as it doesn't have any ttys other than pseudo ttys, which don't support C-s/C-q flow control, and causes compiler warnings. (speeds): Disable high speeds if HAVE_TINY_SPEED_T. * src/termhooks.h (enum output_method): Add output_haiku. (struct terminal): Add Haiku display info. (TERMINAL_FONT_CACHE): Enable for Haiku. * src/terminal.c (Fterminal_live_p): Return `haiku' if appropriate. * src/verbose.mk.in (AM_V_CXX, AM_V_CXXLD): New logging variables. * src/xdisp.c (redisplay_internal) (note_mouse_highlight): Return on Haiku if a popup is activated. (display_menu_bar): Return on Haiku if frame is a Haiku frame. * src/xfaces.c (GCGraphicsExposures): Enable correctly on Haiku. (x_create_gc): Enable dummy GC code on Haiku. * src/xfns.c (x-server-version, x-file-dialog): Add Haiku specifics to doc strings. * src/xterm.c (syms_of_xterm): Add Haiku information to doc string.
2021-11-20 21:30:08 +08:00
haiku_write (FRAME_RESIZED, &rq);
BDirectWindow::FrameResized (newWidth, newHeight);
}
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);
for (struct child_frame *f = subset_windows;
f; f = f->next)
DoMove (f);
BDirectWindow::FrameMoved (newPosition);
}
void
WorkspacesChanged (uint32_t old, uint32_t n)
{
for (struct child_frame *f = subset_windows;
f; f = f->next)
DoUpdateWorkspace (f);
}
void
EmacsMoveTo (int x, int y)
{
if (!this->parent)
this->MoveTo (x, y);
else
this->parent->MoveChild (this, x, y, 0);
}
bool
QuitRequested ()
{
struct haiku_quit_requested_event rq;
rq.window = this;
haiku_write (QUIT_REQUESTED, &rq);
return false;
}
void
Minimize (bool minimized_p)
{
BDirectWindow::Minimize (minimized_p);
struct haiku_iconification_event rq;
rq.window = this;
rq.iconified_p = !parent && minimized_p;
haiku_write (ICONIFICATION, &rq);
}
void
EmacsHide (void)
{
if (this->IsHidden ())
return;
Hide ();
if (this->parent)
UpwardsUnSubsetChildren (this->parent);
}
void
EmacsShow (void)
{
if (!this->IsHidden ())
return;
if (this->parent)
shown_flag = 1;
Show ();
if (this->parent)
UpwardsSubsetChildren (this->parent);
}
void
Zoom (BPoint o, float w, float h)
{
struct haiku_zoom_event rq;
rq.window = this;
rq.x = o.x;
rq.y = o.y;
rq.width = w;
rq.height = h;
if (fullscreen_p)
MakeFullscreen (0);
if (o.x != x_before_zoom ||
o.y != y_before_zoom)
{
x_before_zoom = Frame ().left;
y_before_zoom = Frame ().top;
pre_zoom_rect = Frame ();
zoomed_p = 1;
haiku_write (ZOOM_EVENT, &rq);
}
else
{
zoomed_p = 0;
x_before_zoom = y_before_zoom = INT_MIN;
}
BDirectWindow::Zoom (o, w, h);
}
void
UnZoom (void)
{
if (!zoomed_p)
return;
zoomed_p = 0;
EmacsMoveTo (pre_zoom_rect.left, pre_zoom_rect.top);
ResizeTo (pre_zoom_rect.Width (),
pre_zoom_rect.Height ());
}
void
GetParentWidthHeight (int *width, int *height)
{
if (parent)
{
*width = parent->Frame ().Width ();
*height = parent->Frame ().Height ();
}
else
{
BScreen s (this);
*width = s.Frame ().Width ();
*height = s.Frame ().Height ();
}
}
void
OffsetChildRect (BRect *r, EmacsWindow *c)
{
for (struct child_frame *f; f; f = f->next)
if (f->window == c)
{
r->top -= f->yoff;
r->bottom -= f->yoff;
r->left -= f->xoff;
r->right -= f->xoff;
return;
}
gui_abort ("Trying to calculate offsets for a child frame that doesn't exist");
}
void
MakeFullscreen (int make_fullscreen_p)
{
BScreen screen (this);
if (!screen.IsValid ())
gui_abort ("Trying to make a window fullscreen without a screen");
if (make_fullscreen_p == fullscreen_p)
return;
fullscreen_p = make_fullscreen_p;
uint32 flags = Flags ();
if (fullscreen_p)
{
if (zoomed_p)
UnZoom ();
flags |= B_NOT_MOVABLE | B_NOT_ZOOMABLE;
pre_fullscreen_rect = Frame ();
if (parent)
parent->OffsetChildRect (&pre_fullscreen_rect, this);
int w, h;
EmacsMoveTo (0, 0);
GetParentWidthHeight (&w, &h);
ResizeTo (w, h);
}
else
{
flags &= ~(B_NOT_MOVABLE | B_NOT_ZOOMABLE);
EmacsMoveTo (pre_fullscreen_rect.left,
pre_fullscreen_rect.top);
ResizeTo (pre_fullscreen_rect.Width (),
pre_fullscreen_rect.Height ());
}
SetFlags (flags);
}
};
class EmacsMenuBar : public 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
{
public:
uint32_t visible_bell_color = 0;
uint32_t previous_buttons = 0;
int looper_locked_count = 0;
BRegion sb_region;
BView *offscreen_draw_view = NULL;
BBitmap *offscreen_draw_bitmap_1 = NULL;
BBitmap *copy_bitmap = NULL;
#ifdef USE_BE_CAIRO
cairo_surface_t *cr_surface = NULL;
BLocker cr_surface_lock;
#endif
BPoint tt_absl_pos;
color_space cspace;
EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs", B_FOLLOW_NONE, B_WILL_DRAW)
{
}
~EmacsView ()
{
TearDownDoubleBuffering ();
}
void
AttachedToWindow (void)
{
cspace = B_RGBA32;
}
#ifdef USE_BE_CAIRO
void
DetachCairoSurface (void)
{
if (!cr_surface_lock.Lock ())
gui_abort ("Could not lock cr surface during detachment");
if (!cr_surface)
gui_abort ("Trying to detach window cr surface when none exists");
cairo_surface_destroy (cr_surface);
cr_surface = NULL;
cr_surface_lock.Unlock ();
}
void
AttachCairoSurface (void)
{
if (!cr_surface_lock.Lock ())
gui_abort ("Could not lock cr surface during attachment");
if (cr_surface)
gui_abort ("Trying to attach cr surface when one already exists");
cr_surface = cairo_image_surface_create_for_data
((unsigned char *) offscreen_draw_bitmap_1->Bits (),
CAIRO_FORMAT_ARGB32, offscreen_draw_bitmap_1->Bounds ().Width (),
offscreen_draw_bitmap_1->Bounds ().Height (),
offscreen_draw_bitmap_1->BytesPerRow ());
if (!cr_surface)
gui_abort ("Cr surface allocation failed for double-buffered view");
cr_surface_lock.Unlock ();
}
#endif
void
TearDownDoubleBuffering (void)
{
if (offscreen_draw_view)
{
if (Window ())
ClearViewBitmap ();
if (copy_bitmap)
{
delete copy_bitmap;
copy_bitmap = NULL;
}
if (!looper_locked_count)
if (!offscreen_draw_view->LockLooper ())
gui_abort ("Failed to lock offscreen draw view");
#ifdef USE_BE_CAIRO
if (cr_surface)
DetachCairoSurface ();
#endif
offscreen_draw_view->RemoveSelf ();
delete offscreen_draw_view;
offscreen_draw_view = NULL;
delete offscreen_draw_bitmap_1;
offscreen_draw_bitmap_1 = NULL;
}
}
void
AfterResize (float newWidth, float newHeight)
{
if (offscreen_draw_view)
{
if (!LockLooper ())
gui_abort ("Failed to lock looper after resize");
if (!offscreen_draw_view->LockLooper ())
gui_abort ("Failed to lock offscreen draw view after resize");
#ifdef USE_BE_CAIRO
DetachCairoSurface ();
#endif
offscreen_draw_view->RemoveSelf ();
delete offscreen_draw_bitmap_1;
offscreen_draw_bitmap_1 = new BBitmap (Frame (), cspace, 1);
if (offscreen_draw_bitmap_1->InitCheck () != B_OK)
gui_abort ("Offscreen draw bitmap initialization failed");
offscreen_draw_view->MoveTo (Frame ().left, Frame ().top);
offscreen_draw_view->ResizeTo (Frame ().Width (), Frame ().Height ());
offscreen_draw_bitmap_1->AddChild (offscreen_draw_view);
#ifdef USE_BE_CAIRO
AttachCairoSurface ();
#endif
if (looper_locked_count)
{
offscreen_draw_bitmap_1->Lock ();
}
UnlockLooper ();
}
}
void
Pulse (void)
{
visible_bell_color = 0;
SetFlags (Flags () & ~B_PULSE_NEEDED);
Window ()->SetPulseRate (0);
Invalidate ();
}
void
Draw (BRect expose_bounds)
{
struct haiku_expose_event rq;
EmacsWindow *w = (EmacsWindow *) Window ();
if (visible_bell_color > 0)
{
PushState ();
BView_SetHighColorForVisibleBell (this, visible_bell_color);
FillRect (Frame ());
PopState ();
return;
}
if (w->shown_flag)
{
PushState ();
SetDrawingMode (B_OP_ERASE);
FillRect (Frame ());
PopState ();
return;
}
if (!offscreen_draw_view)
{
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
DoVisibleBell (uint32_t color)
{
if (!LockLooper ())
gui_abort ("Failed to lock looper during visible bell");
visible_bell_color = color | (255 << 24);
SetFlags (Flags () | B_PULSE_NEEDED);
Window ()->SetPulseRate (100 * 1000);
Invalidate ();
UnlockLooper ();
}
void
FlipBuffers (void)
{
if (!LockLooper ())
gui_abort ("Failed to lock looper during buffer flip");
if (!offscreen_draw_view)
gui_abort ("Failed to lock offscreen view during buffer flip");
offscreen_draw_view->Flush ();
offscreen_draw_view->Sync ();
EmacsWindow *w = (EmacsWindow *) Window ();
w->shown_flag = 0;
if (copy_bitmap &&
copy_bitmap->Bounds () != offscreen_draw_bitmap_1->Bounds ())
{
delete copy_bitmap;
copy_bitmap = NULL;
}
if (!copy_bitmap)
copy_bitmap = new BBitmap (offscreen_draw_bitmap_1);
else
copy_bitmap->ImportBits (offscreen_draw_bitmap_1);
if (copy_bitmap->InitCheck () != B_OK)
gui_abort ("Failed to init copy bitmap during buffer flip");
SetViewBitmap (copy_bitmap,
Frame (), Frame (), B_FOLLOW_NONE, 0);
Invalidate ();
UnlockLooper ();
return;
}
void
SetUpDoubleBuffering (void)
{
if (!LockLooper ())
gui_abort ("Failed to lock self setting up double buffering");
if (offscreen_draw_view)
gui_abort ("Failed to lock offscreen view setting up double buffering");
offscreen_draw_bitmap_1 = new BBitmap (Frame (), cspace, 1);
if (offscreen_draw_bitmap_1->InitCheck () != B_OK)
gui_abort ("Failed to init offscreen bitmap");
#ifdef USE_BE_CAIRO
AttachCairoSurface ();
#endif
offscreen_draw_view = new BView (Frame (), NULL, B_FOLLOW_NONE, B_WILL_DRAW);
offscreen_draw_bitmap_1->AddChild (offscreen_draw_view);
if (looper_locked_count)
{
if (!offscreen_draw_bitmap_1->Lock ())
gui_abort ("Failed to lock bitmap after double buffering was set up.");
}
UnlockLooper ();
Invalidate ();
}
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 ();
if (ToolTip ())
ToolTip ()->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x),
-(point.y - tt_absl_pos.y)));
haiku_write (MOUSE_MOTION, &rq);
}
void
MouseDown (BPoint point)
{
struct haiku_button_event rq;
uint32 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;
if (mods & B_OPTION_KEY)
rq.modifiers |= HAIKU_MODIFIER_SUPER;
SetMouseEventMask (B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
haiku_write (BUTTON_DOWN, &rq);
}
void
MouseUp (BPoint point)
{
struct haiku_button_event rq;
uint32 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;
if (mods & B_OPTION_KEY)
rq.modifiers |= HAIKU_MODIFIER_SUPER;
if (!buttons)
SetMouseEventMask (0, 0);
haiku_write (BUTTON_UP, &rq);
}
};
class EmacsScrollBar : public 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->SetResizingMode (B_FOLLOW_NONE);
}
void
MessageReceived (BMessage *msg)
{
if (msg->what == SCROLL_BAR_UPDATE)
{
this->SetRange (0, msg->GetInt32 ("emacs:range", 0));
this->SetValue (msg->GetInt32 ("emacs:units", 0));
}
BScrollBar::MessageReceived (msg);
}
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);
}
};
class EmacsTitleMenuItem : public BMenuItem
{
public:
EmacsTitleMenuItem (const char *str) : BMenuItem (str, NULL)
{
SetEnabled (0);
}
void
DrawContent (void)
{
BMenu *menu = Menu ();
menu->PushState ();
menu->SetFont (be_bold_font);
BView_SetHighColorForVisibleBell (menu, 0);
BMenuItem::DrawContent ();
menu->PopState ();
}
};
class EmacsMenuItem : public BMenuItem
{
public:
int menu_bar_id = -1;
void *wind_ptr = NULL;
char *key = NULL;
char *help = NULL;
EmacsMenuItem (const char *ky,
const char *str,
const char *help,
BMessage *message = NULL) : BMenuItem (str, message)
{
if (ky)
{
key = strdup (ky);
if (!key)
gui_abort ("strdup failed");
}
if (help)
{
this->help = strdup (help);
if (!this->help)
gui_abort ("strdup failed");
}
}
~EmacsMenuItem ()
{
if (key)
free (key);
if (help)
free (help);
}
void
DrawContent (void)
{
BMenu *menu = Menu ();
BMenuItem::DrawContent ();
if (key)
{
BRect r = menu->Frame ();
int w = menu->StringWidth (key);
menu->MovePenTo (BPoint (r.Width () - w - 4,
menu->PenLocation ().y));
menu->DrawString (key);
}
}
void
GetContentSize (float *w, float *h)
{
BMenuItem::GetContentSize (w, h);
if (Menu () && key)
*w += 4 + Menu ()->StringWidth (key);
}
void
Highlight (bool highlight_p)
{
struct haiku_menu_bar_help_event rq;
if (menu_bar_id >= 0)
{
rq.window = wind_ptr;
rq.mb_idx = highlight_p ? menu_bar_id : -1;
haiku_write (MENU_BAR_HELP_EVENT, &rq);
}
else if (help)
{
Menu ()->SetToolTip (highlight_p ? help : NULL);
}
BMenuItem::Highlight (highlight_p);
}
};
class EmacsPopUpMenu : public BPopUpMenu
{
public:
EmacsPopUpMenu (const char *name) : BPopUpMenu (name, 0)
{
}
void
FrameResized (float w, float h)
{
Invalidate ();
BPopUpMenu::FrameResized (w, h);
}
};
static int32
start_running_application (void *data)
{
haiku_io_init_in_app_thread ();
if (!((Emacs *) data)->Lock ())
gui_abort ("Failed to lock application");
((Emacs *) data)->Run ();
((Emacs *) data)->Unlock ();
return 0;
}
/* Take BITMAP, a reference to a BBitmap, and return a pointer to its
data. */
void *
BBitmap_data (void *bitmap)
{
return ((BBitmap *) bitmap)->Bits ();
}
/* Convert bitmap if required, placing the new bitmap in NEW_BITMAP,
and return non-null if bitmap was successfully converted. Bitmaps
should be freed with `BBitmap_free'. */
int
BBitmap_convert (void *_bitmap, void **new_bitmap)
{
BBitmap *bitmap = (BBitmap *) _bitmap;
if (bitmap->ColorSpace () == B_RGBA32)
return -1;
BRect bounds = bitmap->Bounds ();
BBitmap *bmp = new (std::nothrow) BBitmap (bounds, B_RGBA32);
if (!bmp || bmp->InitCheck () != B_OK)
{
if (bmp)
delete 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;
}
/* Create new bitmap in RGB32 format, or in GRAY1 if MONO_P is
non-zero. */
void *
BBitmap_new (int width, int height, int mono_p)
{
BBitmap *bn = new (std::nothrow) BBitmap (BRect (0, 0, width - 1, height - 1),
mono_p ? B_GRAY1 : B_RGB32);
return bn->InitCheck () == B_OK ? (void *) bn : (void *) (delete bn, NULL);
}
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);
}
/* Set up an application and return it. If starting the application
thread fails, abort Emacs. */
void *
BApplication_setup (void)
{
if (be_app)
return be_app;
thread_id id;
Emacs *app;
app = new Emacs;
app->Unlock ();
if ((id = spawn_thread (start_running_application, "Emacs app thread",
B_DEFAULT_MEDIA_PRIORITY, app)) < 0)
gui_abort ("spawn_thread failed");
resume_thread (id);
app_thread = id;
return app;
}
/* Set up and return a window with its view put in VIEW. */
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->AddChild (vw);
*v = vw;
return window;
}
void
BWindow_quit (void *window)
{
((BWindow *) window)->Lock ();
((BWindow *) window)->Quit ();
}
/* Set WINDOW's offset to X, Y. */
void
BWindow_set_offset (void *window, int x, int y)
{
BWindow *wn = (BWindow *) window;
EmacsWindow *w = dynamic_cast<EmacsWindow *> (wn);
if (w)
{
if (!w->LockLooper ())
gui_abort ("Failed to lock window looper setting offset");
w->EmacsMoveTo (x, y);
w->UnlockLooper ();
}
else
wn->MoveTo (x, y);
}
/* Iconify WINDOW. */
void
BWindow_iconify (void *window)
{
if (((BWindow *) window)->IsHidden ())
BWindow_set_visible (window, true);
((BWindow *) window)->Minimize (true);
}
/* Show or hide WINDOW. */
void
BWindow_set_visible (void *window, int visible_p)
{
EmacsWindow *win = (EmacsWindow *) window;
if (visible_p)
{
if (win->IsMinimized ())
win->Minimize (false);
win->EmacsShow ();
}
else if (!win->IsHidden ())
{
if (win->IsMinimized ())
win->Minimize (false);
win->EmacsHide ();
}
win->Sync ();
}
/* Change the title of WINDOW to the multibyte string TITLE. */
void
BWindow_retitle (void *window, const char *title)
{
((BWindow *) window)->SetTitle (title);
}
/* Resize WINDOW to WIDTH by HEIGHT. */
void
BWindow_resize (void *window, int width, int height)
{
((BWindow *) window)->ResizeTo (width, height);
}
/* Activate WINDOW, making it the subject of keyboard focus and
bringing it to the front of the screen. */
void
BWindow_activate (void *window)
{
((BWindow *) window)->Activate ();
}
/* Return the pixel dimensions of the main screen in WIDTH and
HEIGHT. */
void
BScreen_px_dim (int *width, int *height)
{
BScreen screen;
if (!screen.IsValid ())
gui_abort ("Invalid screen");
BRect frame = screen.Frame ();
*width = frame.right - frame.left;
*height = frame.bottom - frame.top;
}
/* Resize VIEW to WIDTH, HEIGHT. */
void
BView_resize_to (void *view, int width, int height)
{
EmacsView *vw = (EmacsView *) view;
if (!vw->LockLooper ())
gui_abort ("Failed to lock view for resize");
vw->ResizeTo (width, height);
vw->AfterResize (width, height);
vw->UnlockLooper ();
}
void *
BCursor_create_default (void)
{
return new BCursor (B_CURSOR_ID_SYSTEM_DEFAULT);
}
void *
BCursor_create_modeline (void)
{
return new BCursor (B_CURSOR_ID_CONTEXT_MENU);
}
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 ())
gui_abort ("Failed to lock view setting cursor");
((BView *) view)->SetViewCursor ((BCursor *) cursor);
((BView *) view)->UnlockLooper ();
}
void
BWindow_Flush (void *window)
{
((BWindow *) window)->Flush ();
}
/* Map the keycode KC, storing the result in CODE and 1 in
NON_ASCII_P if it should be used. */
void
BMapKey (uint32_t kc, int *non_ascii_p, unsigned *code)
{
if (*code == 10 && kc != 0x42)
{
*code = XK_Return;
*non_ascii_p = 1;
return;
}
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 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;
}
/* Make a scrollbar, attach it to VIEW's window, and return it. */
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 ())
gui_abort ("Failed to lock scrollbar owner");
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 ())
gui_abort ("Failed to lock scrollbar parent");
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 ())
gui_abort ("Failed to lock view moving frame");
vw->MoveTo (x, y);
vw->ResizeTo (x1 - x, y1 - y);
vw->Flush ();
vw->Sync ();
vw->UnlockLooper ();
}
void
BView_scroll_bar_update (void *sb, int portion, int whole, int position)
{
BScrollBar *bar = (BScrollBar *) sb;
BMessage msg = BMessage (SCROLL_BAR_UPDATE);
BMessenger mr = BMessenger (bar);
msg.AddInt32 ("emacs:range", whole);
msg.AddInt32 ("emacs:units", position);
mr.SendMessage (&msg);
}
/* Return the default scrollbar size. */
int
BScrollBar_default_size (int horizontal_p)
{
return horizontal_p ? B_H_SCROLL_BAR_HEIGHT : B_V_SCROLL_BAR_WIDTH;
}
/* Invalidate VIEW, causing it to be drawn again. */
void
BView_invalidate (void *view)
{
BView *vw = (BView *) view;
if (!vw->LockLooper ())
gui_abort ("Couldn't lock view while invalidating it");
vw->Invalidate ();
vw->UnlockLooper ();
}
/* Lock VIEW in preparation for drawing operations. This should be
called before any attempt to draw onto VIEW or to lock it for Cairo
drawing. `BView_draw_unlock' should be called afterwards. */
void
BView_draw_lock (void *view)
{
EmacsView *vw = (EmacsView *) view;
if (vw->looper_locked_count)
{
vw->looper_locked_count++;
return;
}
BView *v = (BView *) find_appropriate_view_for_draw (vw);
if (v != vw)
{
if (!vw->offscreen_draw_bitmap_1->Lock ())
gui_abort ("Failed to lock offscreen bitmap while acquiring draw lock");
}
else if (!v->LockLooper ())
gui_abort ("Failed to lock draw view while acquiring draw lock");
if (v != vw && !vw->LockLooper ())
gui_abort ("Failed to lock view while acquiring draw lock");
vw->looper_locked_count++;
}
void
BView_draw_unlock (void *view)
{
EmacsView *vw = (EmacsView *) view;
if (--vw->looper_locked_count)
return;
BView *v = (BView *) find_appropriate_view_for_draw (view);
if (v == vw)
vw->UnlockLooper ();
else
{
vw->offscreen_draw_bitmap_1->Unlock ();
vw->UnlockLooper ();
}
}
void
BWindow_center_on_screen (void *window)
{
BWindow *w = (BWindow *) window;
w->CenterOnScreen ();
}
/* Tell VIEW it has been clicked at X by Y. */
void
BView_mouse_down (void *view, int x, int y)
{
BView *vw = (BView *) view;
if (vw->LockLooper ())
{
vw->MouseDown (BPoint (x, y));
vw->UnlockLooper ();
}
}
/* Tell VIEW the mouse has been released at X by Y. */
void
BView_mouse_up (void *view, int x, int y)
{
BView *vw = (BView *) view;
if (vw->LockLooper ())
{
vw->MouseUp (BPoint (x, y));
vw->UnlockLooper ();
}
}
/* Tell VIEW that the mouse has moved to Y by Y. */
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 ();
}
}
/* Import BITS into BITMAP using the B_GRAY1 colorspace. */
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 * (wd / 8)); i++)
{
*((unsigned short *) data) = bts[i];
data += bmp->BytesPerRow ();
}
}
/* Make a scrollbar at X, Y known to the view VIEW. */
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 ();
}
}
void
BView_get_mouse (void *view, int *x, int *y)
{
BPoint l;
BView *vw = (BView *) view;
if (!vw->LockLooper ())
gui_abort ("Failed to lock view in BView_get_mouse");
vw->GetMouse (&l, NULL, 1);
vw->UnlockLooper ();
*x = std::lrint (l.x);
*y = std::lrint (l.y);
}
/* Perform an in-place conversion of X and Y from VIEW's coordinate
system to its screen's coordinate system. */
void
BView_convert_to_screen (void *view, int *x, int *y)
{
BPoint l = BPoint (*x, *y);
BView *vw = (BView *) view;
if (!vw->LockLooper ())
gui_abort ("Failed to lock view in convert_to_screen");
vw->ConvertToScreen (&l);
vw->UnlockLooper ();
*x = std::lrint (l.x);
*y = std::lrint (l.y);
}
void
BView_convert_from_screen (void *view, int *x, int *y)
{
BPoint l = BPoint (*x, *y);
BView *vw = (BView *) view;
if (!vw->LockLooper ())
gui_abort ("Failed to lock view in convert_from_screen");
vw->ConvertFromScreen (&l);
vw->UnlockLooper ();
*x = std::lrint (l.x);
*y = std::lrint (l.y);
}
/* Decorate or undecorate WINDOW depending on DECORATE_P. */
void
BWindow_change_decoration (void *window, int decorate_p)
{
BWindow *w = (BWindow *) window;
if (!w->LockLooper ())
gui_abort ("Failed to lock window while changing its decorations");
if (decorate_p)
w->SetLook (B_TITLED_WINDOW_LOOK);
else
w->SetLook (B_NO_BORDER_WINDOW_LOOK);
w->UnlockLooper ();
}
/* Decorate WINDOW appropriately for use as a tooltip. */
void
BWindow_set_tooltip_decoration (void *window)
{
BWindow *w = (BWindow *) window;
if (!w->LockLooper ())
gui_abort ("Failed to lock window while setting ttip decoration");
w->SetLook (B_BORDERED_WINDOW_LOOK);
w->SetFeel (B_FLOATING_APP_WINDOW_FEEL);
w->UnlockLooper ();
}
/* Set B_AVOID_FOCUS on WINDOW if AVOID_FOCUS_P is non-nil, or clear
it otherwise. */
void
BWindow_set_avoid_focus (void *window, int avoid_focus_p)
{
BWindow *w = (BWindow *) window;
if (!w->LockLooper ())
gui_abort ("Failed to lock window while setting avoid focus");
if (!avoid_focus_p)
w->SetFlags (w->Flags () & ~B_AVOID_FOCUS);
else
w->SetFlags (w->Flags () | B_AVOID_FOCUS);
w->Sync ();
w->UnlockLooper ();
}
void
BView_emacs_delete (void *view)
{
EmacsView *vw = (EmacsView *) view;
if (!vw->LockLooper ())
gui_abort ("Failed to lock view while deleting it");
vw->RemoveSelf ();
delete vw;
}
/* Return the current workspace. */
uint32_t
haiku_current_workspace (void)
{
return current_workspace ();
}
/* Return a bitmask consisting of workspaces WINDOW is on. */
uint32_t
BWindow_workspaces (void *window)
{
return ((BWindow *) window)->Workspaces ();
}
/* Create a popup menu. */
void *
BPopUpMenu_new (const char *name)
{
BPopUpMenu *menu = new EmacsPopUpMenu (name);
menu->SetRadioMode (0);
return menu;
}
/* Add a title item to MENU. These items cannot be highlighted or
triggered, and their labels will display as bold text. */
void
BMenu_add_title (void *menu, const char *text)
{
EmacsTitleMenuItem *it = new EmacsTitleMenuItem (text);
BMenu *mn = (BMenu *) menu;
mn->AddItem (it);
}
/* Add an item to the menu MENU. */
void
BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p,
bool marked_p, bool mbar_p, void *mbw_ptr, const char *key,
const char *help)
{
BMenu *m = (BMenu *) menu;
BMessage *msg;
if (ptr)
msg = new BMessage ();
EmacsMenuItem *it = new EmacsMenuItem (key, label, help, ptr ? msg : NULL);
it->SetTarget (m->Window ());
it->SetEnabled (enabled_p);
it->SetMarked (marked_p);
if (mbar_p)
{
it->menu_bar_id = (intptr_t) ptr;
it->wind_ptr = mbw_ptr;
}
if (ptr)
msg->AddPointer ("menuptr", ptr);
m->AddItem (it);
}
/* Add a separator to the menu MENU. */
void
BMenu_add_separator (void *menu)
{
BMenu *m = (BMenu *) menu;
m->AddSeparatorItem ();
}
/* Create a submenu and attach it to MENU. */
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;
}
/* Create a submenu that notifies Emacs upon opening. */
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;
}
/* Run MENU, waiting for it to close, and return a pointer to the
data of the selected item (if one exists), or NULL. X, Y should
be in the screen coordinate system. */
void *
BMenu_run (void *menu, int x, int y)
{
BPopUpMenu *mn = (BPopUpMenu *) menu;
mn->SetRadioMode (0);
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;
}
/* Delete the entire menu hierarchy of MENU, and then delete MENU
itself. */
void
BPopUpMenu_delete (void *menu)
{
delete (BPopUpMenu *) menu;
}
/* Create a menubar, attach it to VIEW, and return it. */
void *
BMenuBar_new (void *view)
{
BView *vw = (BView *) view;
EmacsMenuBar *bar = new EmacsMenuBar ();
if (!vw->LockLooper ())
gui_abort ("Failed to lock menu bar parent");
vw->AddChild ((BView *) bar);
vw->UnlockLooper ();
return bar;
}
/* Delete MENUBAR along with all subitems. */
void
BMenuBar_delete (void *menubar)
{
BView *vw = (BView *) menubar;
BView *p = vw->Parent ();
if (!p->LockLooper ())
gui_abort ("Failed to lock menu bar parent while removing menubar");
vw->RemoveSelf ();
p->UnlockLooper ();
delete vw;
}
/* Delete all items from MENU. */
void
BMenu_delete_all (void *menu)
{
BMenu *mn = (BMenu *) menu;
mn->RemoveItems (0, mn->CountItems (), true);
}
/* Delete COUNT items from MENU starting from START. */
void
BMenu_delete_from (void *menu, int start, int count)
{
BMenu *mn = (BMenu *) menu;
mn->RemoveItems (start, count, true);
}
/* Count items in menu MENU. */
int
BMenu_count_items (void *menu)
{
return ((BMenu *) menu)->CountItems ();
}
/* Find the item in MENU at IDX. */
void *
BMenu_item_at (void *menu, int idx)
{
return ((BMenu *) menu)->ItemAt (idx);
}
/* Set ITEM's label to LABEL. */
void
BMenu_item_set_label (void *item, const char *label)
{
((BMenuItem *) item)->SetLabel (label);
}
/* Get ITEM's menu. */
void *
BMenu_item_get_menu (void *item)
{
return ((BMenuItem *) item)->Submenu ();
}
/* Emit a beep noise. */
void
haiku_ring_bell (void)
{
beep ();
}
/* Create a BAlert with TEXT. */
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);
}
/* Add a button to ALERT and return the button. */
void *
BAlert_add_button (void *alert, const char *text)
{
BAlert *al = (BAlert *) alert;
al->AddButton (text);
return al->ButtonAt (al->CountButtons () - 1);
}
/* Run ALERT, returning the number of the button that was selected,
or -1 if no button was selected before the alert was closed. */
int32_t
BAlert_go (void *alert)
{
return ((BAlert *) alert)->Go ();
}
/* Enable or disable BUTTON depending on ENABLED_P. */
void
BButton_set_enabled (void *button, int enabled_p)
{
((BButton *) button)->SetEnabled (enabled_p);
}
/* Set VIEW's tooltip to TOOLTIP. */
void
BView_set_tooltip (void *view, const char *tooltip)
{
((BView *) view)->SetToolTip (tooltip);
}
/* Set VIEW's tooltip to a sticky tooltip at X by Y. */
void
BView_set_and_show_sticky_tooltip (void *view, const char *tooltip,
int x, int y)
{
BToolTip *tip;
BView *vw = (BView *) view;
if (!vw->LockLooper ())
gui_abort ("Failed to lock view while showing sticky tooltip");
vw->SetToolTip (tooltip);
tip = vw->ToolTip ();
BPoint pt;
EmacsView *ev = dynamic_cast<EmacsView *> (vw);
if (ev)
ev->tt_absl_pos = BPoint (x, y);
vw->GetMouse (&pt, NULL, 1);
pt.x -= x;
pt.y -= y;
pt.x = -pt.x;
pt.y = -pt.y;
tip->SetMouseRelativeLocation (pt);
tip->SetSticky (1);
vw->ShowToolTip (tip);
vw->UnlockLooper ();
}
/* Delete ALERT. */
void
BAlert_delete (void *alert)
{
delete (BAlert *) alert;
}
/* Place the resolution of the monitor in DPI in RSSX and RSSY. */
void
BScreen_res (double *rrsx, double *rrsy)
{
BScreen s (B_MAIN_SCREEN_ID);
if (!s.IsValid ())
gui_abort ("Invalid screen for resolution checks");
monitor_info i;
if (s.GetMonitorInfo (&i) == B_OK)
{
*rrsx = (double) i.width / (double) 2.54;
*rrsy = (double) i.height / (double) 2.54;
}
else
{
*rrsx = 72.27;
*rrsy = 72.27;
}
}
/* Add WINDOW to OTHER_WINDOW's subset and parent it to
OTHER_WINDOW. */
void
EmacsWindow_parent_to (void *window, void *other_window)
{
EmacsWindow *w = (EmacsWindow *) window;
if (!w->LockLooper ())
gui_abort ("Failed to lock window while parenting");
w->ParentTo ((EmacsWindow *) other_window);
w->UnlockLooper ();
}
void
EmacsWindow_unparent (void *window)
{
EmacsWindow *w = (EmacsWindow *) window;
if (!w->LockLooper ())
gui_abort ("Failed to lock window while unparenting");
w->UnparentAndUnlink ();
w->UnlockLooper ();
}
/* Place text describing the current version of Haiku in VERSION,
which should be a buffer LEN bytes wide. */
void
be_get_version_string (char *version, int len)
{
std::strncpy (version, "Unknown Haiku release", len - 1);
BPath path;
if (find_directory (B_BEOS_LIB_DIRECTORY, &path) == B_OK)
{
path.Append ("libbe.so");
BAppFileInfo appFileInfo;
version_info versionInfo;
BFile file;
if (file.SetTo (path.Path (), B_READ_ONLY) == B_OK
&& appFileInfo.SetTo (&file) == B_OK
&& appFileInfo.GetVersionInfo (&versionInfo,
B_APP_VERSION_KIND) == B_OK
&& versionInfo.short_info[0] != '\0')
std::strncpy (version, versionInfo.short_info, len - 1);
}
}
/* Return the amount of color planes in the current display. */
int
be_get_display_planes (void)
{
color_space space = dpy_color_space;
if (space == B_NO_COLOR_SPACE)
{
BScreen screen; /* This is actually a very slow operation. */
if (!screen.IsValid ())
gui_abort ("Invalid screen");
space = dpy_color_space = screen.ColorSpace ();
}
if (space == B_RGB32 || space == B_RGB24)
return 24;
if (space == B_RGB16)
return 16;
if (space == B_RGB15)
return 15;
if (space == B_CMAP8)
return 8;
gui_abort ("Bad colorspace for screen");
/* https://www.haiku-os.org/docs/api/classBScreen.html
says a valid screen can't be anything else. */
return -1;
}
/* Return the amount of colors the display can handle. */
int
be_get_display_color_cells (void)
{
color_space space = dpy_color_space;
if (space == B_NO_COLOR_SPACE)
{
BScreen screen;
if (!screen.IsValid ())
gui_abort ("Invalid screen");
space = dpy_color_space = screen.ColorSpace ();
}
if (space == B_RGB32 || space == B_RGB24)
return 1677216;
if (space == B_RGB16)
return 65536;
if (space == B_RGB15)
return 32768;
if (space == B_CMAP8)
return 256;
gui_abort ("Bad colorspace for screen");
return -1;
}
/* Warp the pointer to X by Y. */
void
be_warp_pointer (int x, int y)
{
/* We're not supposed to use the following function without a
BWindowScreen object, but in Haiku nothing actually prevents us
from doing so. */
set_mouse_position (x, y);
}
/* Update the position of CHILD in WINDOW without actually moving
it. */
void
EmacsWindow_move_weak_child (void *window, void *child, int xoff, int yoff)
{
EmacsWindow *w = (EmacsWindow *) window;
EmacsWindow *c = (EmacsWindow *) child;
if (!w->LockLooper ())
gui_abort ("Couldn't lock window for weak move");
w->MoveChild (c, xoff, yoff, 1);
w->UnlockLooper ();
}
/* Find an appropriate view to draw onto. If VW is double-buffered,
this will be the view used for double buffering instead of VW
itself. */
void *
find_appropriate_view_for_draw (void *vw)
{
BView *v = (BView *) vw;
EmacsView *ev = dynamic_cast<EmacsView *>(v);
if (!ev)
return v;
return ev->offscreen_draw_view ? ev->offscreen_draw_view : vw;
}
/* Set up double buffering for VW. */
void
EmacsView_set_up_double_buffering (void *vw)
{
EmacsView *view = (EmacsView *) vw;
if (!view->LockLooper ())
gui_abort ("Couldn't lock view while setting up double buffering");
if (view->offscreen_draw_view)
{
view->UnlockLooper ();
return;
}
view->SetUpDoubleBuffering ();
view->UnlockLooper ();
}
/* Flip and invalidate the view VW. */
void
EmacsView_flip_and_blit (void *vw)
{
EmacsView *view = (EmacsView *) vw;
if (!view->offscreen_draw_view)
return;
if (!view->LockLooper ())
gui_abort ("Couldn't lock view in flip_and_blit");
view->FlipBuffers ();
view->UnlockLooper ();
}
/* Disable double buffering for VW. */
void
EmacsView_disable_double_buffering (void *vw)
{
EmacsView *view = (EmacsView *) vw;
if (!view->LockLooper ())
gui_abort ("Couldn't lock view tearing down double buffering");
view->TearDownDoubleBuffering ();
view->UnlockLooper ();
}
/* Return non-0 if VW is double-buffered. */
int
EmacsView_double_buffered_p (void *vw)
{
EmacsView *view = (EmacsView *) vw;
if (!view->LockLooper ())
gui_abort ("Couldn't lock view testing double buffering status");
int db_p = !!view->offscreen_draw_view;
view->UnlockLooper ();
return db_p;
}
struct popup_file_dialog_data
{
BMessage *msg;
BFilePanel *panel;
BEntry *entry;
};
static void
unwind_popup_file_dialog (void *ptr)
{
struct popup_file_dialog_data *data =
(struct popup_file_dialog_data *) ptr;
BFilePanel *panel = data->panel;
delete panel;
delete data->entry;
delete data->msg;
}
static void
be_popup_file_dialog_safe_set_target (BFilePanel *dialog, BWindow *window)
{
dialog->SetTarget (BMessenger (window));
}
/* Popup a file dialog. */
char *
be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p, int dir_only_p,
void *window, const char *save_text, const char *prompt,
void (*block_input_function) (void),
void (*unblock_input_function) (void))
{
ptrdiff_t idx = c_specpdl_idx_from_cxx ();
/* setjmp/longjmp is UB with automatic objects. */
block_input_function ();
BWindow *w = (BWindow *) window;
uint32_t mode = dir_only_p ? B_DIRECTORY_NODE : B_FILE_NODE | B_DIRECTORY_NODE;
BEntry *path = new BEntry;
BMessage *msg = new BMessage ('FPSE');
BFilePanel *panel = new BFilePanel (open_p ? B_OPEN_PANEL : B_SAVE_PANEL,
NULL, NULL, mode);
unblock_input_function ();
struct popup_file_dialog_data dat;
dat.entry = path;
dat.msg = msg;
dat.panel = panel;
record_c_unwind_protect_from_cxx (unwind_popup_file_dialog, &dat);
if (default_dir)
{
if (path->SetTo (default_dir, 0) != B_OK)
default_dir = NULL;
}
panel->SetMessage (msg);
if (default_dir)
panel->SetPanelDirectory (path);
if (save_text)
panel->SetSaveText (save_text);
panel->SetHideWhenDone (0);
panel->Window ()->SetTitle (prompt);
be_popup_file_dialog_safe_set_target (panel, w);
panel->Show ();
panel->Window ()->Show ();
void *buf = alloca (200);
while (1)
{
enum haiku_event_type type;
char *ptr = NULL;
if (!haiku_read_with_timeout (&type, buf, 200, 100000))
{
if (type != FILE_PANEL_EVENT)
haiku_write (type, buf);
else if (!ptr)
ptr = (char *) ((struct haiku_file_panel_event *) buf)->ptr;
}
ssize_t b_s;
haiku_read_size (&b_s);
if (!b_s || b_s == -1 || ptr || panel->Window ()->IsHidden ())
{
c_unbind_to_nil_from_cxx (idx);
return ptr;
}
}
}
void
be_app_quit (void)
{
if (be_app)
{
status_t e;
while (!be_app->Lock ());
be_app->Quit ();
wait_for_thread (app_thread, &e);
}
}
/* Temporarily fill VIEW with COLOR. */
void
EmacsView_do_visible_bell (void *view, uint32_t color)
{
EmacsView *vw = (EmacsView *) view;
vw->DoVisibleBell (color);
}
/* Zoom WINDOW. */
void
BWindow_zoom (void *window)
{
BWindow *w = (BWindow *) window;
w->Zoom ();
}
/* Make WINDOW fullscreen if FULLSCREEN_P. */
void
EmacsWindow_make_fullscreen (void *window, int fullscreen_p)
{
EmacsWindow *w = (EmacsWindow *) window;
w->MakeFullscreen (fullscreen_p);
}
/* Unzoom (maximize) WINDOW. */
void
EmacsWindow_unzoom (void *window)
{
EmacsWindow *w = (EmacsWindow *) window;
w->UnZoom ();
}
/* Move the pointer into MBAR and start tracking. */
void
BMenuBar_start_tracking (void *mbar)
{
EmacsMenuBar *mb = (EmacsMenuBar *) mbar;
if (!mb->LockLooper ())
gui_abort ("Couldn't lock menubar");
BRect frame = mb->Frame ();
BPoint pt = frame.LeftTop ();
BPoint l = pt;
mb->Parent ()->ConvertToScreen (&pt);
set_mouse_position (pt.x, pt.y);
mb->MouseDown (l);
mb->UnlockLooper ();
}
#ifdef HAVE_NATIVE_IMAGE_API
int
be_can_translate_type_to_bitmap_p (const char *mime)
{
BTranslatorRoster *r = BTranslatorRoster::Default ();
translator_id *ids;
int32 id_len;
if (r->GetAllTranslators (&ids, &id_len) != B_OK)
return 0;
int found_in = 0;
int found_out = 0;
for (int i = 0; i < id_len; ++i)
{
found_in = 0;
found_out = 0;
const translation_format *i_fmts;
const translation_format *o_fmts;
int32 i_count, o_count;
if (r->GetInputFormats (ids[i], &i_fmts, &i_count) != B_OK)
continue;
if (r->GetOutputFormats (ids[i], &o_fmts, &o_count) != B_OK)
continue;
for (int x = 0; x < i_count; ++x)
{
if (!strcmp (i_fmts[x].MIME, mime))
{
found_in = 1;
break;
}
}
for (int x = 0; x < i_count; ++x)
{
if (!strcmp (o_fmts[x].MIME, "image/x-be-bitmap") ||
!strcmp (o_fmts[x].MIME, "image/x-vnd.Be-bitmap"))
{
found_out = 1;
break;
}
}
if (found_in && found_out)
break;
}
delete [] ids;
return found_in && found_out;
}
void *
be_translate_bitmap_from_file_name (const char *filename)
{
BBitmap *bm = BTranslationUtils::GetBitmap (filename);
return bm;
}
void *
be_translate_bitmap_from_memory (const void *buf, size_t bytes)
{
BMemoryIO io (buf, bytes);
BBitmap *bm = BTranslationUtils::GetBitmap (&io);
return bm;
}
#endif
/* Return the size of BITMAP's data, in bytes. */
size_t
BBitmap_bytes_length (void *bitmap)
{
BBitmap *bm = (BBitmap *) bitmap;
return bm->BitsLength ();
}
/* Show VIEW's tooltip. */
void
BView_show_tooltip (void *view)
{
BView *vw = (BView *) view;
if (vw->LockLooper ())
{
vw->ShowToolTip (vw->ToolTip ());
vw->UnlockLooper ();
}
}
#ifdef USE_BE_CAIRO
/* Return VIEW's cairo surface. */
cairo_surface_t *
EmacsView_cairo_surface (void *view)
{
EmacsView *vw = (EmacsView *) view;
EmacsWindow *wn = (EmacsWindow *) vw->Window ();
return vw->cr_surface ? vw->cr_surface : wn->cr_surface;
}
/* Transfer each clip rectangle in VIEW to the cairo context
CTX. */
void
BView_cr_dump_clipping (void *view, cairo_t *ctx)
{
BView *vw = (BView *) find_appropriate_view_for_draw (view);
BRegion cr;
vw->GetClippingRegion (&cr);
for (int i = 0; i < cr.CountRects (); ++i)
{
BRect r = cr.RectAt (i);
cairo_rectangle (ctx, r.left, r.top, r.Width () + 1,
r.Height () + 1);
}
cairo_clip (ctx);
}
/* Lock WINDOW in preparation for drawing using Cairo. */
void
EmacsWindow_begin_cr_critical_section (void *window)
{
EmacsWindow *w = (EmacsWindow *) window;
if (!w->surface_lock.Lock ())
gui_abort ("Couldn't lock cairo surface");
BView *vw = (BView *) w->FindView ("Emacs");
EmacsView *ev = dynamic_cast <EmacsView *> (vw);
if (ev && !ev->cr_surface_lock.Lock ())
gui_abort ("Couldn't lock view cairo surface");
}
/* Unlock WINDOW in preparation for drawing using Cairo. */
void
EmacsWindow_end_cr_critical_section (void *window)
{
EmacsWindow *w = (EmacsWindow *) window;
w->surface_lock.Unlock ();
BView *vw = (BView *) w->FindView ("Emacs");
EmacsView *ev = dynamic_cast <EmacsView *> (vw);
if (ev)
ev->cr_surface_lock.Unlock ();
}
#endif
/* Get the width of STR in the plain font. */
int
be_string_width_with_plain_font (const char *str)
{
return be_plain_font->StringWidth (str);
}
/* Get the ascent + descent of the plain font. */
int
be_plain_font_height (void)
{
struct font_height fheight;
be_plain_font->GetHeight (&fheight);
return fheight.ascent + fheight.descent;
}
/* Return the number of physical displays connected. */
int
be_get_display_screens (void)
{
int count = 1;
BScreen scr;
if (!scr.IsValid ())
gui_abort ("Main screen vanished!");
while (scr.SetToNext () == B_OK && scr.IsValid ())
++count;
return count;
}
/* Set the minimum width the user can resize WINDOW to. */
void
BWindow_set_min_size (void *window, int width, int height)
{
BWindow *w = (BWindow *) window;
if (!w->LockLooper ())
gui_abort ("Failed to lock window looper setting min size");
w->SetSizeLimits (width, -1, height, -1);
w->UnlockLooper ();
}
/* Set the alignment of WINDOW's dimensions. */
void
BWindow_set_size_alignment (void *window, int align_width, int align_height)
{
BWindow *w = (BWindow *) window;
if (!w->LockLooper ())
gui_abort ("Failed to lock window looper setting alignment");
#if 0 /* Haiku does not currently implement SetWindowAlignment. */
if (w->SetWindowAlignment (B_PIXEL_ALIGNMENT, -1, -1, align_width,
align_width, -1, -1, align_height,
align_height) != B_NO_ERROR)
gui_abort ("Invalid pixel alignment");
#endif
w->UnlockLooper ();
}