From: Po Lu via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 51658@debbugs.gnu.org
Subject: bug#51658: [PATCH] Haiku port (again)
Date: Mon, 15 Nov 2021 10:59:48 +0800 [thread overview]
Message-ID: <87lf1q2kez.fsf@yahoo.com> (raw)
In-Reply-To: <875ysv58dz.fsf@yahoo.com> (Po Lu's message of "Sun, 14 Nov 2021 18:39:04 +0800")
[-- Attachment #1: Type: text/plain, Size: 10962 bytes --]
Po Lu <luangruo@yahoo.com> writes:
> AFAIU, POSITION is used to determine the window where the file should
> appear. It should be possible to fake.
>
> We could get the mouse position on-screen, but it may lead to odd
> results if the user asks Emacs to open a file through the Tracker or the
> Recents menu, and the mouse is not on top of an Emacs frame, or if the
> system starts Emacs to open a file.
>
> What position do you think would be reasonable to report here?
I moved the Haiku system-dependents from sysdep.c to a separate file
`haiku.c'. I also removed the extraneous events (drag-and-drop now
sends drag-n-drop events, like everywhere else, and haiku-quit-requested
has been removed for now.)
Here's an updated changelog. Please see the attached patch, thanks.
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
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 FreeType or 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.
(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.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: haiku-emacs.patch --]
[-- Type: text/x-patch, Size: 496409 bytes --]
diff --git a/.gitignore b/.gitignore
index ea1662c9b8..f1abb2ab68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -182,6 +182,7 @@ ID
# Executables.
*.exe
a.out
+lib-src/be-resources
lib-src/blessmail
lib-src/ctags
lib-src/ebrowse
@@ -203,6 +204,7 @@ nextstep/GNUstep/Emacs.base/Resources/Info-gnustep.plist
src/bootstrap-emacs
src/emacs
src/emacs-[0-9]*
+src/Emacs
src/temacs
src/dmpstruct.h
src/*.pdmp
diff --git a/Makefile.in b/Makefile.in
index ccb5d93f2f..3c092fa63d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -102,6 +102,8 @@ HAVE_NATIVE_COMP =
USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@
+HAVE_BE_APP = @HAVE_BE_APP@
+
# ==================== Where To Install Things ====================
# Location to install Emacs.app under GNUstep / macOS.
@@ -521,7 +523,13 @@ install-arch-dep:
$(MAKE) -C lib-src install
ifeq (${ns_self_contained},no)
${INSTALL_PROGRAM} $(INSTALL_STRIP) src/emacs${EXEEXT} "$(DESTDIR)${bindir}/$(EMACSFULL)"
+ifeq (${HAVE_BE_APP},yes)
+ ${INSTALL_PROGRAM} $(INSTALL_STRIP) src/Emacs "$(DESTDIR)${prefix}/apps/Emacs"
+endif
ifeq (${DUMPING},pdumper)
+ifeq (${HAVE_BE_APP},yes)
+ ${INSTALL_DATA} src/Emacs.pdmp "$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/Emacs.pdmp
+endif
${INSTALL_DATA} src/emacs.pdmp "$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/emacs-${EMACS_PDMP}
endif
-chmod 755 "$(DESTDIR)${bindir}/$(EMACSFULL)"
diff --git a/configure.ac b/configure.ac
index c231c2ceae..1ee5f0c6ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -510,6 +510,12 @@ AC_DEFUN
OPTION_DEFAULT_OFF([xwidgets],
[enable use of xwidgets in Emacs buffers (requires gtk3 or macOS Cocoa)])
+OPTION_DEFAULT_OFF([be-app],
+ [enable use of Haiku's Application Kit as a window system])
+
+OPTION_DEFAULT_OFF([be-cairo],
+ [enable use of cairo under Haiku's Application Kit])
+
## Makefile.in needs the cache file name.
AC_SUBST(cache_file)
@@ -786,6 +792,10 @@ AC_DEFUN
LDFLAGS="-N2M $LDFLAGS"
;;
+ *-haiku )
+ opsys=haiku
+ ;;
+
## Intel 386 machines where we don't care about the manufacturer.
i[3456]86-*-* )
case "${canonical}" in
@@ -907,7 +917,9 @@ AC_DEFUN
if test $emacs_cv_prog_cc_g3 != yes; then
CFLAGS=$emacs_save_CFLAGS
fi
- if test $opsys = mingw32; then
+ # Haiku also needs -gdwarf-2 because its GDB is too old
+ # to understand newer formats.
+ if test $opsys = mingw32 || test $opsys = haiku; then
CFLAGS="$CFLAGS -gdwarf-2"
fi
fi
@@ -1574,6 +1586,8 @@ AC_DEFUN
## Motif needs -lgen.
unixware) LIBS_SYSTEM="-lsocket -lnsl -lelf -lgen" ;;
+
+ haiku) LIBS_SYSTEM="-lnetwork" ;;
esac
AC_SUBST(LIBS_SYSTEM)
@@ -2079,6 +2093,22 @@ AC_DEFUN
fi
fi
+HAVE_BE_APP=no
+if test "${opsys}" = "haiku" && test "${with_be_app}" = "yes"; then
+ dnl Only GCC is supported. Clang might work, but it's
+ dnl not reliable, so don't check for it here.
+ AC_PROG_CXX([gcc g++])
+ CXXFLAGS="$CXXFLAGS $emacs_g3_CFLAGS"
+ AC_LANG_PUSH([C++])
+ AC_CHECK_HEADER([app/Application.h], [HAVE_BE_APP=yes],
+ [AC_MSG_ERROR([The Application Kit headers required for building
+with the Application Kit were not found or cannot be compiled. Either fix this, or
+re-configure with the option '--without-be-app'.])])
+ AC_LANG_POP([C++])
+fi
+
+AC_SUBST(HAVE_BE_APP)
+
HAVE_W32=no
W32_OBJ=
W32_LIBS=
@@ -2200,6 +2230,39 @@ AC_DEFUN
with_xft=no
fi
+HAIKU_OBJ=
+HAIKU_CXX_OBJ=
+HAIKU_LIBS=
+HAIKU_CFLAGS=
+
+if test "$opsys" = "haiku"; then
+ HAIKU_OBJ="$HAIKU_OBJ haiku.o"
+fi
+
+if test "${HAVE_BE_APP}" = "yes"; then
+ AC_DEFINE([HAVE_HAIKU], 1,
+ [Define if Emacs will be built with Haiku windowing support])
+fi
+
+if test "${HAVE_BE_APP}" = "yes"; then
+ window_system=haiku
+ with_xft=no
+ HAIKU_OBJ="$HAIKU_OBJ haikufns.o haikuterm.o haikumenu.o haikufont.o haikuselect.o haiku_io.o"
+ HAIKU_CXX_OBJ="haiku_support.o haiku_font_support.o haiku_draw_support.o haiku_select.o"
+ HAIKU_LIBS="-lbe -lgame -ltranslation -ltracker" # -lgame is needed for set_mouse_position.
+
+ if test "${with_native_image_api}" = yes; then
+ AC_DEFINE(HAVE_NATIVE_IMAGE_API, 1, [Define to use native OS APIs for images.])
+ NATIVE_IMAGE_API="yes (haiku)"
+ HAIKU_OBJ="$HAIKU_OBJ haikuimage.o"
+ fi
+fi
+
+AC_SUBST(HAIKU_LIBS)
+AC_SUBST(HAIKU_OBJ)
+AC_SUBST(HAIKU_CXX_OBJ)
+AC_SUBST(HAIKU_CFLAGS)
+
## $window_system is now set to the window system we will
## ultimately use.
@@ -2239,6 +2302,9 @@ AC_DEFUN
w32 )
term_header=w32term.h
;;
+ haiku )
+ term_header=haikuterm.h
+ ;;
esac
if test "$window_system" = none && test "X$with_x" != "Xno"; then
@@ -2570,7 +2636,8 @@ AC_DEFUN
### Use -lrsvg-2 if available, unless '--with-rsvg=no' is specified.
HAVE_RSVG=no
-if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${opsys}" = "mingw32"; then
+if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" \
+ || test "${opsys}" = "mingw32" || test "${HAVE_BE_APP}" = "yes"; then
if test "${with_rsvg}" != "no"; then
RSVG_REQUIRED=2.14.0
RSVG_MODULE="librsvg-2.0 >= $RSVG_REQUIRED"
@@ -2594,7 +2661,8 @@ AC_DEFUN
HAVE_WEBP=no
if test "${with_webp}" != "no"; then
if test "${HAVE_X11}" = "yes" || test "${opsys}" = "mingw32" \
- || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes"; then
+ || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \
+ || test "${HAVE_BE_APP}" = "yes"; then
WEBP_REQUIRED=0.6.0
WEBP_MODULE="libwebp >= $WEBP_REQUIRED"
@@ -2613,7 +2681,8 @@ AC_DEFUN
fi
HAVE_IMAGEMAGICK=no
-if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${HAVE_W32}" = "yes"; then
+if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${HAVE_W32}" = "yes" || \
+ test "${HAVE_BE_APP}" = "yes"; then
if test "${with_imagemagick}" != "no"; then
if test -n "$BREW"; then
# Homebrew doesn't link ImageMagick 6 by default, so make sure
@@ -3263,6 +3332,9 @@ AC_DEFUN
elif test "${HAVE_W32}" = "yes"; then
AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
USE_TOOLKIT_SCROLL_BARS=yes
+ elif test "${HAVE_BE_APP}" = "yes"; then
+ AC_DEFINE(USE_TOOLKIT_SCROLL_BARS)
+ USE_TOOLKIT_SCROLL_BARS=yes
fi
fi
@@ -3352,6 +3424,22 @@ AC_DEFUN
fi
fi
fi
+if test "${HAVE_BE_APP}" = "yes"; then
+ if test "${with_be_cairo}" != "no"; then
+ CAIRO_REQUIRED=1.8.0
+ CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
+ EMACS_CHECK_MODULES(CAIRO, $CAIRO_MODULE)
+ if test $HAVE_CAIRO = yes; then
+ AC_DEFINE(USE_BE_CAIRO, 1, [Define to 1 if using cairo on Haiku.])
+ CFLAGS="$CFLAGS $CAIRO_CFLAGS"
+ LIBS="$LIBS $CAIRO_LIBS"
+ AC_SUBST(CAIRO_CFLAGS)
+ AC_SUBST(CAIRO_LIBS)
+ else
+ AC_MSG_WARN([cairo requested but not found.])
+ fi
+ fi
+fi
### Start of font-backend (under any platform) section.
# (nothing here yet -- this is a placeholder)
@@ -3501,6 +3589,58 @@ AC_DEFUN
fi
fi
+### Start of font-backend (under Haiku) selectionn.
+if test "${HAVE_BE_APP}" = "yes"; then
+ if test $HAVE_CAIRO = "yes"; then
+ EMACS_CHECK_MODULES([FREETYPE], [freetype2 >= 2.5.0])
+ test "$HAVE_FREETYPE" = "no" && AC_MSG_ERROR(cairo on Haiku requires libfreetype)
+ EMACS_CHECK_MODULES([FONTCONFIG], [fontconfig >= 2.2.0])
+ test "$HAVE_FONTCONFIG" = "no" && AC_MSG_ERROR(cairo on Haiku requires libfontconfig)
+ fi
+
+ HAVE_LIBOTF=no
+
+ if test "${HAVE_FREETYPE}" = "yes"; then
+ AC_DEFINE(HAVE_FREETYPE, 1,
+ [Define to 1 if using the freetype and fontconfig libraries.])
+ OLD_CFLAGS=$CFLAGS
+ OLD_LIBS=$LIBS
+ CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
+ LIBS="$FREETYPE_LIBS $LIBS"
+ AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
+ CFLAGS=$OLD_CFLAGS
+ LIBS=$OLD_LIBS
+ if test "${with_libotf}" != "no"; then
+ EMACS_CHECK_MODULES([LIBOTF], [libotf])
+ if test "$HAVE_LIBOTF" = "yes"; then
+ AC_DEFINE(HAVE_LIBOTF, 1, [Define to 1 if using libotf.])
+ AC_CHECK_LIB(otf, OTF_get_variation_glyphs,
+ HAVE_OTF_GET_VARIATION_GLYPHS=yes,
+ HAVE_OTF_GET_VARIATION_GLYPHS=no)
+ if test "${HAVE_OTF_GET_VARIATION_GLYPHS}" = "yes"; then
+ AC_DEFINE(HAVE_OTF_GET_VARIATION_GLYPHS, 1,
+ [Define to 1 if libotf has OTF_get_variation_glyphs.])
+ fi
+ if ! $PKG_CONFIG --atleast-version=0.9.16 libotf; then
+ AC_DEFINE(HAVE_OTF_KANNADA_BUG, 1,
+[Define to 1 if libotf is affected by https://debbugs.gnu.org/28110.])
+ fi
+ fi
+ fi
+ dnl FIXME should there be an error if HAVE_FREETYPE != yes?
+ dnl Does the new font backend require it, or can it work without it?
+ fi
+fi
+
+if test "${HAVE_BE_APP}" = "yes" && test "${HAVE_FREETYPE}" = "yes"; then
+ if test "${with_harfbuzz}" != "no"; then
+ EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver])
+ if test "$HAVE_HARFBUZZ" = "yes"; then
+ AC_DEFINE(HAVE_HARFBUZZ, 1, [Define to 1 if using HarfBuzz.])
+ fi
+ fi
+fi
+
### End of font-backend section.
AC_SUBST(FREETYPE_CFLAGS)
@@ -3622,7 +3762,7 @@ AC_DEFUN
HAVE_JPEG=no
LIBJPEG=
if test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \
- || test "${HAVE_NS}" = "yes"; then
+ || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes"; then
if test "${with_jpeg}" != "no"; then
AC_CACHE_CHECK([for jpeglib 6b or later],
[emacs_cv_jpeglib],
@@ -3940,7 +4080,7 @@ AC_DEFUN
if test "$opsys" = mingw32; then
AC_CHECK_HEADER([png.h], [HAVE_PNG=yes])
elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \
- || test "${HAVE_NS}" = "yes"; then
+ || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes"; then
EMACS_CHECK_MODULES([PNG], [libpng >= 1.0.0])
if test $HAVE_PNG = yes; then
LIBPNG=$PNG_LIBS
@@ -4015,7 +4155,7 @@ AC_DEFUN
AC_DEFINE(HAVE_TIFF, 1, [Define to 1 if you have the tiff library (-ltiff).])
fi
elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \
- || test "${HAVE_NS}" = "yes"; then
+ || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes"; then
if test "${with_tiff}" != "no"; then
AC_CHECK_HEADER(tiffio.h,
[tifflibs="-lz -lm"
@@ -4044,7 +4184,8 @@ AC_DEFUN
AC_DEFINE(HAVE_GIF, 1, [Define to 1 if you have a gif (or ungif) library.])
fi
elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \
- || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes"; then
+ || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \
+ || test "${HAVE_BE_APP}" = "yes"; then
AC_CHECK_HEADER(gif_lib.h,
# EGifPutExtensionLast only exists from version libungif-4.1.0b1.
# Earlier versions can crash Emacs, but version 5.0 removes EGifPutExtensionLast.
@@ -4461,6 +4602,13 @@ AC_DEFUN
[AC_MSG_ERROR([Non-ELF systems are not supported on this platform.])]);;
esac
+if test "$with_unexec" = yes && test "$opsys" = "haiku"; then
+ dnl A serious attempt was actually made to port unexec to Haiku.
+ dnl Something in libstdc++ seems to prevent it from working.
+ AC_MSG_ERROR([Haiku is not supported by the legacy unexec dumper.
+Please use the portable dumper instead.])
+fi
+
# Dump loading
AC_CHECK_FUNCS([posix_madvise])
@@ -4814,7 +4962,7 @@ AC_DEFUN
LIBS="$OLDLIBS"])
if test "${emacs_cv_links_glib}" = "yes"; then
AC_DEFINE(HAVE_GLIB, 1, [Define to 1 if GLib is linked in.])
- if test "$HAVE_NS" = no;then
+ if test "$HAVE_NS" = no ; then
XGSELOBJ=xgselect.o
fi
fi
@@ -5069,7 +5217,7 @@ AC_DEFUN
dnl to read the input and send it to the true Emacs process
dnl through a pipe.
case $opsys in
- darwin | gnu-linux | gnu-kfreebsd )
+ darwin | gnu-linux | gnu-kfreebsd)
AC_DEFINE(INTERRUPT_INPUT, 1, [Define to read input using SIGIO.])
;;
esac
@@ -5165,6 +5313,14 @@ AC_DEFUN
AC_DEFINE(PTY_OPEN, [fd = open (pty_name, O_RDWR | O_NONBLOCK)])
AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptsname (int), *ptyname; int grantpt_result; sigset_t blocked; sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 0); grantpt_result = grantpt (fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1) fatal("could not grant slave pty"); if (unlockpt(fd) == -1) fatal("could not unlock slave pty"); if (!(ptyname = ptsname(fd))) fatal ("could not enable slave pty"); snprintf (pty_name, PTY_NAME_SIZE, "%s", ptyname); }])
;;
+
+ haiku*)
+ AC_DEFINE(FIRST_PTY_LETTER, ['s'])
+ AC_DEFINE(PTY_NAME_SPRINTF, [])
+ dnl on Haiku pty names aren't distinctive, thus the use of posix_openpt
+ AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_NONBLOCK)])
+ AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptyname; int grantpt_result; sigset_t blocked; sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask (SIG_BLOCK, &blocked, 0); grantpt_result = grantpt (fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if (grantpt_result == -1) fatal("could not grant slave pty"); if (unlockpt(fd) == -1) fatal("could not unlock slave pty"); if (!(ptyname = ptsname(fd))) fatal ("could not enable slave pty"); snprintf (pty_name, PTY_NAME_SIZE, "%s", ptyname); }])
+ ;;
esac
@@ -5386,8 +5542,25 @@ AC_DEFUN
AC_DEFINE(USG, [])
AC_DEFINE(USG5_4, [])
;;
+
+ haiku)
+ AC_DEFINE(HAIKU, [], [Define if the system is Haiku.])
+ ;;
esac
+AC_SYS_POSIX_TERMIOS
+if test $ac_cv_sys_posix_termios = yes; then
+ AC_CHECK_SIZEOF([speed_t], [], [#include <termios.h>])
+ dnl on Haiku, and possibly other platforms, speed_t is defined to
+ dnl unsigned char, even when speeds greater than 200 baud are
+ dnl defined.
+
+ if test ${ac_cv_sizeof_speed_t} -lt 2; then
+ AC_DEFINE([HAVE_TINY_SPEED_T], [1],
+ [Define to 1 if speed_t has some sort of nonsensically tiny size.])
+ fi
+fi
+
AC_CACHE_CHECK([for usable FIONREAD], [emacs_cv_usable_FIONREAD],
[case $opsys in
aix4-2 | nacl)
@@ -5430,6 +5603,22 @@ AC_DEFUN
AC_DEFINE([USABLE_SIGIO], [1], [Define to 1 if SIGIO is usable.])
fi
fi
+
+ if test $emacs_broken_SIGIO = no && test $emacs_cv_usable_SIGIO = no; then
+ AC_CACHE_CHECK([for usable SIGPOLL], [emacs_cv_usable_SIGPOLL],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[#include <fcntl.h>
+ #include <signal.h>
+ ]],
+ [[int foo = SIGPOLL | F_SETFL;]])],
+ [emacs_cv_usable_SIGPOLL=yes],
+ [emacs_cv_usable_SIGPOLL=no])],
+ [emacs_cv_usable_SIGPOLL=yes],
+ [emacs_cv_usable_SIGPOLL=no])
+ if test $emacs_cv_usable_SIGPOLL = yes; then
+ AC_DEFINE([USABLE_SIGPOLL], [1], [Define to 1 if SIGPOLL is usable but SIGIO is not.])
+ fi
+ fi
fi
case $opsys in
@@ -5542,6 +5731,17 @@ AC_DEFUN
FONT_OBJ="$FONT_OBJ ftfont.o"
fi
fi
+
+if test "${HAVE_BE_APP}" = "yes" ; then
+ if test "${HAVE_FREETYPE}" = "yes" || \
+ test "${HAVE_CAIRO}" = "yes"; then
+ FONT_OBJ="$FONT_OBJ ftfont.o"
+ fi
+ if test "${HAVE_CAIRO}" = "yes"; then
+ FONT_OBJ="$FONT_OBJ ftcrfont.o"
+ fi
+fi
+
if test "${HAVE_HARFBUZZ}" = "yes" ; then
FONT_OBJ="$FONT_OBJ hbfont.o"
fi
@@ -5930,7 +6130,7 @@ AC_DEFUN
#### Please respect alphabetical ordering when making additions.
optsep=
emacs_config_features=
-for opt in ACL CAIRO DBUS FREETYPE GCONF GIF GLIB GMP GNUTLS GPM GSETTINGS \
+for opt in ACL BE_APP CAIRO DBUS FREETYPE GCONF GIF GLIB GMP GNUTLS GPM GSETTINGS \
HARFBUZZ IMAGEMAGICK JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 \
M17N_FLT MODULES NATIVE_COMP NOTIFY NS OLDXMENU PDUMPER PNG RSVG SECCOMP \
SOUND THREADS TIFF TOOLKIT_SCROLL_BARS \
diff --git a/doc/emacs/Makefile.in b/doc/emacs/Makefile.in
index 69d39efa8b..dde3ae83c1 100644
--- a/doc/emacs/Makefile.in
+++ b/doc/emacs/Makefile.in
@@ -140,6 +140,7 @@ EMACSSOURCES=
${srcdir}/xresources.texi \
${srcdir}/anti.texi \
${srcdir}/macos.texi \
+ $(srcdir)/haiku.texi \
${srcdir}/msdos.texi \
${srcdir}/gnu.texi \
${srcdir}/glossary.texi \
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 83847fb8f1..ce92435ae7 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -221,6 +221,7 @@ Top
* X Resources:: X resources for customizing Emacs.
* Antinews:: Information about Emacs version 27.
* Mac OS / GNUstep:: Using Emacs under macOS and GNUstep.
+* Haiku:: Using Emacs on Haiku.
* Microsoft Windows:: Using Emacs on Microsoft Windows and MS-DOS.
* Manifesto:: What's GNU? Gnu's Not Unix!
@@ -1249,6 +1250,11 @@ Top
* Mac / GNUstep Events:: How window system events are handled.
* GNUstep Support:: Details on status of GNUstep support.
+Emacs and Haiku
+
+* Haiku Basics:: Basic Emacs usage and installation under Haiku.
+* Haiku Fonts:: The various options for displaying fonts on Haiku.
+
Emacs and Microsoft Windows/MS-DOS
* Windows Startup:: How to start Emacs on Windows.
@@ -1618,6 +1624,7 @@ GNU Free Documentation License
@include anti.texi
@include macos.texi
+@include haiku.texi
@c Includes msdos-xtra.
@include msdos.texi
@include gnu.texi
diff --git a/doc/emacs/haiku.texi b/doc/emacs/haiku.texi
new file mode 100644
index 0000000000..cf6f2c2b47
--- /dev/null
+++ b/doc/emacs/haiku.texi
@@ -0,0 +1,144 @@
+@c This is part of the Emacs manual.
+@c Copyright (C) 2021 Free Software Foundation, Inc.
+@c See file emacs.texi for copying conditions.
+@node Haiku
+@appendix Emacs and Haiku
+@cindex Haiku
+
+ Haiku is a Unix-like operating system that originated as a
+re-implementation of the operating system BeOS. As it is free
+software, this port of GNU Emacs is provided for the convenience of
+its users.
+
+ This section describes the peculiarities of using Emacs built with
+the Application Kit, the windowing system native to Haiku. The
+oddities described here do not apply to using Emacs on Haiku built
+without windowing support, or built with X11.
+
+@menu
+* Haiku Basics:: Basic Emacs usage and installation under Haiku.
+* Haiku Fonts:: The various options for displaying fonts on Haiku.
+@end menu
+
+@node Haiku Basics
+@section Installation and usage peculiarities under Haiku
+@cindex haiku application
+@cindex haiku installation
+
+ Emacs installs two separate executables under Haiku; it is up to the
+user to decide which one suits him best: A regular executable, with
+the lowercase name @code{emacs}, and a binary containing
+Haiku-specific application metadata, with the name @code{Emacs}.
+
+@cindex launching Emacs from the tracker
+@cindex tty Emacs in haiku
+ If you are launching Emacs from the Tracker, or want to make the
+Tracker open files using Emacs, you should use the binary named
+@code{Emacs}; ff you are going to use Emacs in the terminal, or wish
+to launch separate instances of Emacs, or do not care for the
+aforementioned system integration features, use the binary named
+@code{emacs} instead.
+
+@cindex modifier keys and system keymap (Haiku)
+@cindex haiku keymap
+ On Haiku, unusual modifier keys such as the Hyper key are
+unsupported. By default, the super key corresponds with the option
+key defined by the operating system, the meta key with the command
+key, the control key with the system control key, and the shift key
+with the system shift key. On a standard PC keyboard, Haiku should
+map these keys to positions familiar to those using a GNU system, but
+this may require some adjustment to your system's configuration to
+work.
+
+ It is impossible to type accented characters using the system super
+key map.
+
+ You can customize the correspondence between modifier keys known to
+the system, and those known to Emacs. The variables that allow for
+that are described below.
+
+@cindex modifier key customization (Haiku)
+You can customize which Emacs modifiers the various system modifier
+keys correspond to through the following variables:
+
+@table @code
+@vindex haiku-meta-keysym
+@item haiku-meta-keysym
+The system modifier key that will be treated as the Meta key by Emacs.
+It defaults to @code{command}.
+
+@vindex haiku-control-keysym
+@item haiku-control-keysym
+The system modifier key that will be treated as the Control key by
+Emacs. It defaults to @code{control}.
+
+@vindex haiku-super-keysym
+@item haiku-super-keysym
+The system modifier key that will be treated as the Super key by
+Emacs. It defaults to @code{option}.
+
+@vindex haiku-shift-keysym
+@item haiku-shift-keysym
+The system modifier key that will be treated as the Shift key by
+Emacs. It defaults to @code{shift}.
+@end table
+
+The value of each variable can one of the symbols @code{command},
+@code{control}, @code{option}, @code{shift}, or @code{nil}.
+@code{nil} or any other value will cause the default value to be used
+instead.
+
+@cindex tooltips (haiku)
+@cindex haiku tooltips
+ On Haiku, Emacs defaults to using the system tooltip mechanism.
+This usually leads to more responsive tooltips, but the tooltips will
+not be able to use advanced display features. If that is what you
+need, you can disable the use of system tooltips by setting the
+variable @code{haiku-use-system-tooltips} to nil. (@pxref{Tooltips,,,
+elisp, The Emacs Lisp Reference Manual}).
+
+@table @code
+@vindex haiku-use-system-tooltips
+@item haiku-use-system-tooltips
+This variable controls whether or not system tooltips will be used.
+
+When non-nil, tooltips are displayed by the Application Kit and not
+Emacs, and accordingly do not have a tooltip frame. As such, they are
+also unable to utilize any display properties.
+@end table
+
+@subsection What to do when Emacs crashes
+@cindex crashes, Haiku
+@cindex haiku debugger
+@vindex haiku-debug-on-fatal-error
+ If the variable @code{haiku-debug-on-fatal-error} is non-nil, Emacs
+will launch the system debugger when a fatal signal is received. It
+defaults to @code{t}. If GDB cannot be used on your system, please
+attach the report generated by the system debugger when reporting a
+bug.
+
+@table @code
+@vindex haiku-use-system-debugger
+@item haiku-use-system-debugger
+When non-nil, Emacs will ask the system to launch the system debugger
+whenever it experiences a fatal error. This behaviour is standard
+among Haiku applications.
+@end table
+
+@node Haiku Fonts
+@section Font and font backend selection on Haiku
+@cindex font backend selection (Haiku)
+
+ Emacs, when built with Haiku windowing support, can be built with
+several different font backends. You can specify font backends by
+specifying @kbd{-xrm Emacs.fontBackend:BACKEND} on the command line
+used to invoke Emacs, where @kbd{BACKEND} is one of the backends
+specified below, or on a per-frame basis by changing the
+@code{font-backend} frame parameter. (@pxref{Parameter Access,,,
+elisp, The Emacs Lisp Reference Manual}).
+
+ Two of these backends, @code{ftcr} and @code{ftcrfont} are identical
+to their counterparts on the X Window System. There is also a
+Haiku-specific backend named @code{haiku}, that uses the App Server to
+draw fonts, but does not at present support display of color font and
+emoji.
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index dd2c6e003f..0dd1b5bdd0 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -2767,8 +2767,9 @@ Defining Faces
@item type
The kind of window system the terminal uses---either @code{graphic}
(any graphics-capable display), @code{x}, @code{pc} (for the MS-DOS
-console), @code{w32} (for MS Windows 9X/NT/2K/XP), or @code{tty} (a
-non-graphics-capable display). @xref{Window Systems, window-system}.
+console), @code{w32} (for MS Windows 9X/NT/2K/XP), @code{haiku} (for
+Haiku), or @code{tty} (a non-graphics-capable display).
+@xref{Window Systems, window-system}.
@item class
What kinds of colors the terminal supports---either @code{color},
@@ -8247,6 +8248,8 @@ Window Systems
GNUstep and macOS).
@item pc
Emacs is displaying the frame using MS-DOS direct screen writes.
+@item haiku
+Emacs is displaying the frame using the Application Kit on Haiku.
@item nil
Emacs is displaying the frame on a character-based terminal.
@end table
@@ -8293,6 +8296,7 @@ Tooltips
displayed in the echo area.
@end defun
+@cindex system tooltips
@vindex x-gtk-use-system-tooltips
When Emacs is built with GTK+ support, it by default displays tooltips
using GTK+ functions, and the appearance of the tooltips is then
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 31ad82b7ad..56fc8859a0 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -214,7 +214,8 @@ Multiple Terminals
@item
The kind of display associated with the terminal. This is the symbol
returned by the function @code{terminal-live-p} (i.e., @code{x},
-@code{t}, @code{w32}, @code{ns}, or @code{pc}). @xref{Frames}.
+@code{t}, @code{w32}, @code{ns}, @code{pc}, or @code{haiku}).
+@xref{Frames}.
@item
A list of terminal parameters. @xref{Terminal Parameters}.
@@ -680,7 +681,7 @@ Frame Layout
@itemize @w{}
@item (1) non-toolkit and terminal frames
-@item (2) Lucid, Motif and MS-Windows frames
+@item (2) Lucid, Motif, MS-Windows, and Haiku frames
@item (3) GTK+ and NS frames
@end itemize
@@ -1756,6 +1757,9 @@ Size Parameters
both will be displayed if the mouse pointer is moved to the top of the
screen.
+@footnote{On Haiku, setting @code{fullscreen} to @code{fullwidth} or
+@code{fullheight} has no effect.}
+
@vindex fullscreen-restore@r{, a frame parameter}
@item fullscreen-restore
This parameter specifies the desired fullscreen state of the frame
@@ -2168,6 +2172,10 @@ Management Parameters
available, to reduce flicker. Set this property if you experience
display bugs or pine for that retro, flicker-y feeling.
+If Emacs is built with Haiku and Cairo, inhibiting double buffering on
+a frame may lead to severe artifacting when display elements such as
+the mouse cursor pass over a frame.
+
@vindex skip-taskbar@r{, a frame parameter}
@item skip-taskbar
If non-@code{nil}, this tells the window manager to remove the frame's
@@ -2191,7 +2199,8 @@ Management Parameters
@code{mouse-autoselect-window} (@pxref{Mouse Window Auto-selection}).
This may have the unwanted side-effect that a user cannot scroll a
non-selected frame with the mouse. Some window managers may not honor
-this parameter.
+this parameter. On Haiku, it also has the side-effect that the window
+will not be able to receive any keyboard input from the user.
@vindex undecorated@r{, a frame parameter}
@item undecorated
@@ -2352,7 +2361,10 @@ Font and Color Parameters
engine), and @code{harfbuzz} (font driver for OTF and TTF fonts with
HarfBuzz text shaping) (@pxref{Windows Fonts,,, emacs, The GNU Emacs
Manual}). The @code{harfbuzz} driver is similarly recommended. On
-other systems, there is only one available font backend, so it does
+Haiku, there can be several font drivers (@pxref{Haiku Fonts,,, emacs,
+The GNU Emacs Manual}).
+
+On other systems, there is only one available font backend, so it does
not make sense to modify this frame parameter.
@vindex background-mode@r{, a frame parameter}
@@ -3143,6 +3155,9 @@ Raising and Lowering
below all other frames belonging to the same or a higher z-group as
@var{frame}. If @var{frame} is a child frame (@pxref{Child Frames}),
this lowers @var{frame} below all other child frames of its parent.
+
+@footnote{Lowering frames is not supported on Haiku, due to limitations
+imposed by the system.}
@end deffn
@defun frame-restack frame1 frame2 &optional above
@@ -3163,6 +3178,9 @@ Raising and Lowering
@var{frame1} remains unaltered.
Some window managers may refuse to restack windows.
+
+@footnote{Restacking frames is not supported on Haiku, due to limitations
+imposed by the system.}
@end defun
Note that the effect of restacking will only hold as long as neither of
@@ -3272,6 +3290,12 @@ Child Frames
allowing them to be positioned so they do not obscure the parent frame
while still being visible themselves.
+@footnote{On Haiku, child frames are only visible when a parent frame is
+active, owing to a limitation of the Haiku windowing system. Owing to
+the same limitation, child frames are only guaranteed to appear above
+their top-level parent; that is to say, the top-most frame in the
+hierarchy, which does not have a parent frame.}
+
Usually, moving a parent frame moves along all its child frames and
their descendants as well, keeping their relative positions unaltered.
Note that the hook @code{move-frame-functions} (@pxref{Frame Position})
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 1fbd66458a..fb0f25fa3d 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -947,6 +947,9 @@ System Environment
@item gnu/kfreebsd
A GNU (glibc-based) system with a FreeBSD kernel.
+@item haiku
+The Haiku operating system, a derivative of the Be Operating System.
+
@item hpux
Hewlett-Packard HPUX operating system.
diff --git a/etc/MACHINES b/etc/MACHINES
index d8d0b86fb4..d883f1abd6 100644
--- a/etc/MACHINES
+++ b/etc/MACHINES
@@ -103,6 +103,34 @@ the list at the end of this file.
./configure CC='gcc -m64' # GCC
./configure CC='cc -m64' # Oracle Developer Studio
+** Haiku
+
+ On 32-bit Haiku it is required that the newer GCC 8 be used, instead
+ of the legacy GCC 2 used by default. This can be achieved by
+ invoking configure inside a shell launched by the 'setarch' program
+ invoked as 'setarch x86'.
+
+ When building with packages discovered through pkg-config, such as
+ libpng, on a GCC 2/GCC 8 hybrid system, simply evaluating 'setarch
+ x86' is insufficient to ensure that all required libraries are found
+ at their correct locations. To avoid this problem, set the
+ environment variable 'PKG_CONFIG_PATH' to the GCC 8 pkg-config
+ directory at '/system/develop/lib/x86/pkgconfig/' before configuring
+ Emacs.
+
+ If GCC complains about not being able to resolve symbols such as
+ "BHandler::LockLooper", you are almost certainly experiencing this
+ problem.
+
+ Haiku running on non-x86 systems has not been tested. It is
+ anticipated that Haiku running on big-endian systems will experience
+ problems when Emacs is built with Haiku windowing support, but there
+ doesn't seem to be any reliable way to get Haiku running on a
+ big-endian system at present.
+
+ The earliest release of Haiku that will successfully compile Emacs
+ is R1/Beta2. For windowing support, R1/Beta3 or later is required.
+
\f
* Obsolete platforms
diff --git a/etc/NEWS b/etc/NEWS
index 312fc18f4f..cc9335851b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -24,6 +24,25 @@ applies, and please also update docstrings as needed.
\f
* Installation Changes in Emacs 29.1
+** Emacs has been ported to the Haiku operating system.
+The configuration process should automatically detect and build for Haiku.
+There is also an optional window-system port to Haiku, which can be enabled
+by configuring Emacs with the option '--with-be-app', which will require
+the Haiku Application Kit development headers and a C++ compiler to be present
+on your system. If Emacs is not built with the option '--with-be-app', the
+resulting Emacs will only run in text-mode terminals.
+
++++
+*** Cairo drawing support has been enabled for Haiku builds.
+To enable Cairo support, ensure that the Cairo and FreeType development files
+are present on your system, and configure Emacs with '--with-be-cairo'.
+
+---
+*** Double buffering is now enabled on the Haiku operating system.
+Unlike X, there is no compile-time option to enable or disable double-buffering.
+If you wish to disable double-buffering, change the frame parameter
+`inhibit-double-buffering' instead.
+
** Emacs now installs the ".pdmp" file using a unique fingerprint in the name.
The file is typically installed using a file name akin to
"...dir/libexec/emacs/29.1/x86_64-pc-linux-gnu/emacs-<fingerprint>.pdmp".
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index f506881a4b..c548ee9b36 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -1022,6 +1022,15 @@ modern fonts are used, such as Noto Emoji or Ebrima.
The solution is to switch to a configuration that uses HarfBuzz as its
shaping engine, where these problems don't exist.
+** On Haiku, some proportionally-spaced fonts display with artifacting.
+
+This is a Haiku bug: https://dev.haiku-os.org/ticket/17229, which can
+be remedied by using a different font that does not exhibit this
+problem, or by compiling Emacs with the FreeType font driver.
+
+So far, Bitstream Charter and Noto Sans have been known to exhibit
+this problem, while Noto Sans Display is known to not do so.
+
* Internationalization problems
** M-{ does not work on a Spanish PC keyboard.
@@ -1105,6 +1114,13 @@ In your ~/.Xresources file, then run
And restart Emacs.
+** On Haiku, BeCJK doesn't work properly with Emacs
+
+Some popular Haiku input methods such BeCJK are known to behave badly
+when interacting with Emacs, in ways such as stealing input focus and
+displaying popup windows that don't disappear. If you are affected,
+you should use an Emacs input method instead.
+
* X runtime problems
** X keyboard problems
diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in
index e6cda73367..d062e78366 100644
--- a/lib-src/Makefile.in
+++ b/lib-src/Makefile.in
@@ -27,7 +27,9 @@ EMACSOPT =
# ==================== Things 'configure' will edit ====================
CC=@CC@
+CXX=@CXX@
CFLAGS=@CFLAGS@
+CXXFLAGS=@CXXFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
@@ -130,6 +132,11 @@ MKDIR_P =
# ========================== Lists of Files ===========================
+## Haiku build-time support
+HAVE_BE_APP=@HAVE_BE_APP@
+HAIKU_LIBS=@HAIKU_LIBS@
+HAIKU_CFLAGS=@HAIKU_CFLAGS@
+
# emacsclientw.exe for MinGW, empty otherwise
CLIENTW = @CLIENTW@
@@ -143,7 +150,11 @@ UTILITIES =
$(if $(with_mailutils), , movemail${EXEEXT}) \
$(and $(use_gamedir), update-game-score${EXEEXT})
+ifeq ($(HAVE_BE_APP),yes)
+DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT} be-resources
+else
DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT}
+endif
# Like UTILITIES, but they're not system-dependent, and should not be
# deleted by the distclean target.
@@ -230,6 +241,10 @@ WINDRES =
## Some systems define this to request special libraries.
LIBS_SYSTEM = @LIBS_SYSTEM@
+# Flags that could be in WARN_CFLAGS, but are invalid for C++.
+NON_CXX_CFLAGS = -Wmissing-prototypes -Wnested-externs -Wold-style-definition \
+ -Wstrict-prototypes -Wno-override-init
+
BASE_CFLAGS = $(C_SWITCH_SYSTEM) $(C_SWITCH_MACHINE) \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
-I. -I../src -I../lib \
@@ -238,6 +253,9 @@ BASE_CFLAGS =
ALL_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS}
CPP_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${CPPFLAGS} ${CFLAGS}
+ALL_CXXFLAGS = $(filter-out ${NON_CXX_CFLAGS},${BASE_CFLAGS}) \
+ ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} ${CFLAGS} ${CXXFLAGS} ${HAIKU_CFLAGS}
+
# Configuration files for .o files to depend on.
config_h = ../src/config.h $(srcdir)/../src/conf_post.h
@@ -407,6 +425,9 @@ emacsclientw${EXEEXT}:
$(LOADLIBES) \
$(LIB_WSOCK32) $(LIB_EACCESS) $(LIBS_ECLIENT) -o $@
+be-resources: ${srcdir}/be_resources.cc ${config_h}
+ $(AM_V_CXXLD)$(CXX) ${ALL_CXXFLAGS} ${HAIKU_LIBS} $< -o $@
+
NTINC = ${srcdir}/../nt/inc
NTDEPS = $(NTINC)/ms-w32.h $(NTINC)/sys/stat.h $(NTINC)/inttypes.h \
$(NTINC)/stdint.h $(NTINC)/pwd.h $(NTINC)/sys/time.h $(NTINC)/stdbool.h \
diff --git a/lib-src/be_resources.cc b/lib-src/be_resources.cc
new file mode 100644
index 0000000000..e6a14f037b
--- /dev/null
+++ b/lib-src/be_resources.cc
@@ -0,0 +1,144 @@
+/* Haiku window system support
+ 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 <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include <SupportDefs.h>
+#include <Path.h>
+#include <AppFileInfo.h>
+#include <TranslationUtils.h>
+#include <Application.h>
+#include <Catalog.h>
+#include <Roster.h>
+
+using namespace std;
+
+static void
+be_perror (status_t code, char *arg)
+{
+ if (code != B_OK)
+ {
+ switch (code)
+ {
+ case B_BAD_VALUE:
+ fprintf (stderr, "%s: Bad value\n", arg);
+ break;
+ case B_ENTRY_NOT_FOUND:
+ fprintf (stderr, "%s: Not found\n", arg);
+ break;
+ case B_PERMISSION_DENIED:
+ fprintf (stderr, "%s: Permission denied\n", arg);
+ break;
+ case B_NO_MEMORY:
+ fprintf (stderr, "%s: No memory\n", arg);
+ break;
+ case B_LINK_LIMIT:
+ fprintf (stderr, "%s: Link limit reached\n", arg);
+ break;
+ case B_BUSY:
+ fprintf (stderr, "%s: Busy\n", arg);
+ break;
+ case B_NO_MORE_FDS:
+ fprintf (stderr, "%s: No more file descriptors\n", arg);
+ break;
+ case B_FILE_ERROR:
+ fprintf (stderr, "%s: File error\n", arg);
+ break;
+ default:
+ fprintf (stderr, "%s: Unknown error\n", arg);
+ }
+ }
+ else
+ {
+ abort ();
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ BApplication app ("application/x-vnd.GNU-emacs-resource-helper");
+ BFile file;
+ BBitmap *icon;
+ BAppFileInfo info;
+ status_t code;
+ struct version_info vinfo;
+ char *v = strdup (PACKAGE_VERSION);
+
+ if (argc != 3)
+ {
+ printf ("be-resources ICON FILE: make FILE appropriate for Emacs.\n");
+ return EXIT_FAILURE;
+ }
+
+ code = file.SetTo (argv[2], B_READ_WRITE);
+ if (code != B_OK)
+ {
+ be_perror (code, argv[2]);
+ return EXIT_FAILURE;
+ }
+ code = info.SetTo (&file);
+ if (code != B_OK)
+ {
+ be_perror (code, argv[2]);
+ return EXIT_FAILURE;
+ }
+ code = info.SetAppFlags (B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY);
+ if (code != B_OK)
+ {
+ be_perror (code, argv[2]);
+ return EXIT_FAILURE;
+ }
+
+ icon = BTranslationUtils::GetBitmapFile (argv[1], NULL);
+
+ if (!icon)
+ {
+ be_perror (B_ERROR, argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ info.SetIcon (icon, B_MINI_ICON);
+ info.SetIcon (icon, B_LARGE_ICON);
+ info.SetSignature ("application/x-vnd.GNU-emacs");
+
+ v = strtok (v, ".");
+ vinfo.major = atoi (v);
+
+ v = strtok (NULL, ".");
+ vinfo.middle = atoi (v);
+
+ v = strtok (NULL, ".");
+ vinfo.minor = v ? atoi (v) : 0;
+
+ vinfo.variety = 0;
+ vinfo.internal = 0;
+
+ strncpy ((char *) &vinfo.short_info, PACKAGE_VERSION,
+ sizeof vinfo.short_info - 1);
+ strncpy ((char *) &vinfo.long_info, PACKAGE_STRING,
+ sizeof vinfo.long_info - 1);
+
+ info.SetVersionInfo (&vinfo, B_APP_VERSION_KIND);
+
+ return EXIT_SUCCESS;
+}
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index 0e800dd7e8..c55b29830d 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -603,6 +603,8 @@ decode_options (int argc, char **argv)
alt_display = "ns";
#elif defined (HAVE_NTGUI)
alt_display = "w32";
+#elif defined (HAVE_HAIKU)
+ alt_display = "be";
#endif
display = egetenv ("DISPLAY");
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 34a6db508d..219b5d68ac 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -2176,7 +2176,7 @@ custom-magic-reset
;;; The `custom' Widget.
(defface custom-button
- '((((type x w32 ns) (class color)) ; Like default mode line
+ '((((type x w32 ns haiku) (class color)) ; Like default mode line
:box (:line-width 2 :style released-button)
:background "lightgrey" :foreground "black"))
"Face for custom buffer buttons if `custom-raised-buttons' is non-nil."
@@ -2184,7 +2184,7 @@ custom-button
:group 'custom-faces)
(defface custom-button-mouse
- '((((type x w32 ns) (class color))
+ '((((type x w32 ns haiku) (class color))
:box (:line-width 2 :style released-button)
:background "grey90" :foreground "black")
(t
@@ -2209,7 +2209,7 @@ custom-button-unraised
(if custom-raised-buttons 'custom-button-mouse 'highlight))
(defface custom-button-pressed
- '((((type x w32 ns) (class color))
+ '((((type x w32 ns haiku) (class color))
:box (:line-width 2 :style pressed-button)
:background "lightgrey" :foreground "black")
(t :inverse-video t))
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index a46107a678..68019c038e 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -829,7 +829,11 @@ minibuffer-prompt-properties--setter
;; xselect.c
(x-select-enable-clipboard-manager killing boolean "24.1")
;; xsettings.c
- (font-use-system-font font-selection boolean "23.2")))
+ (font-use-system-font font-selection boolean "23.2")
+ ;; haikuterm.c
+ (haiku-debug-on-fatal-error debug boolean "29.1")
+ ;; haikufns.c
+ (haiku-use-system-tooltips tooltip boolean "29.1")))
(setq ;; If we did not specify any standard value expression above,
;; use the current value as the standard value.
standard (if (setq prop (memq :standard rest))
@@ -846,6 +850,8 @@ minibuffer-prompt-properties--setter
(eq system-type 'windows-nt))
((string-match "\\`ns-" (symbol-name symbol))
(featurep 'ns))
+ ((string-match "\\`haiku-" (symbol-name symbol))
+ (featurep 'haiku))
((string-match "\\`x-.*gtk" (symbol-name symbol))
(featurep 'gtk))
((string-match "clipboard-manager" (symbol-name symbol))
diff --git a/lisp/faces.el b/lisp/faces.el
index 9ec20c4298..b2498cda88 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -1172,7 +1172,7 @@ face-valid-attribute-values
(:height
'integerp)
(:stipple
- (and (memq (window-system frame) '(x ns)) ; No stipple on w32
+ (and (memq (window-system frame) '(x ns)) ; No stipple on w32 or haiku
(mapcar #'list
(apply #'nconc
(mapcar (lambda (dir)
@@ -2822,7 +2822,7 @@ tool-bar
'((default
:box (:line-width 1 :style released-button)
:foreground "black")
- (((type x w32 ns) (class color))
+ (((type x w32 ns haiku) (class color))
:background "grey75")
(((type x) (class mono))
:background "grey"))
diff --git a/lisp/frame.el b/lisp/frame.el
index 2c73737a54..1319759e74 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1633,6 +1633,7 @@ frame-current-scroll-bars
(declare-function x-frame-geometry "xfns.c" (&optional frame))
(declare-function w32-frame-geometry "w32fns.c" (&optional frame))
(declare-function ns-frame-geometry "nsfns.m" (&optional frame))
+(declare-function haiku-frame-geometry "haikufns.c" (&optional frame))
(defun frame-geometry (&optional frame)
"Return geometric attributes of FRAME.
@@ -1682,6 +1683,8 @@ frame-geometry
(w32-frame-geometry frame))
((eq frame-type 'ns)
(ns-frame-geometry frame))
+ ((eq frame-type 'haiku)
+ (haiku-frame-geometry frame))
(t
(list
'(outer-position 0 . 0)
@@ -1806,6 +1809,7 @@ frame--size-history
(declare-function x-frame-edges "xfns.c" (&optional frame type))
(declare-function w32-frame-edges "w32fns.c" (&optional frame type))
(declare-function ns-frame-edges "nsfns.m" (&optional frame type))
+(declare-function haiku-frame-edges "haikufns.c" (&optional frame type))
(defun frame-edges (&optional frame type)
"Return coordinates of FRAME's edges.
@@ -1829,12 +1833,15 @@ frame-edges
(w32-frame-edges frame type))
((eq frame-type 'ns)
(ns-frame-edges frame type))
+ ((eq frame-type 'haiku)
+ (haiku-frame-edges frame type))
(t
(list 0 0 (frame-width frame) (frame-height frame))))))
(declare-function w32-mouse-absolute-pixel-position "w32fns.c")
(declare-function x-mouse-absolute-pixel-position "xfns.c")
(declare-function ns-mouse-absolute-pixel-position "nsfns.m")
+(declare-function haiku-mouse-absolute-pixel-position "haikufns.c")
(defun mouse-absolute-pixel-position ()
"Return absolute position of mouse cursor in pixels.
@@ -1849,12 +1856,15 @@ mouse-absolute-pixel-position
(w32-mouse-absolute-pixel-position))
((eq frame-type 'ns)
(ns-mouse-absolute-pixel-position))
+ ((eq frame-type 'haiku)
+ (haiku-mouse-absolute-pixel-position))
(t
(cons 0 0)))))
(declare-function ns-set-mouse-absolute-pixel-position "nsfns.m" (x y))
(declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y))
(declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y))
+(declare-function haiku-set-mouse-absolute-pixel-position "haikufns.c" (x y))
(defun set-mouse-absolute-pixel-position (x y)
"Move mouse pointer to absolute pixel position (X, Y).
@@ -1867,7 +1877,9 @@ set-mouse-absolute-pixel-position
((eq frame-type 'x)
(x-set-mouse-absolute-pixel-position x y))
((eq frame-type 'w32)
- (w32-set-mouse-absolute-pixel-position x y)))))
+ (w32-set-mouse-absolute-pixel-position x y))
+ ((eq frame-type 'haiku)
+ (haiku-set-mouse-absolute-pixel-position x y)))))
(defun frame-monitor-attributes (&optional frame)
"Return the attributes of the physical monitor dominating FRAME.
@@ -1960,6 +1972,7 @@ frame-monitor-workarea
(declare-function x-frame-list-z-order "xfns.c" (&optional display))
(declare-function w32-frame-list-z-order "w32fns.c" (&optional display))
(declare-function ns-frame-list-z-order "nsfns.m" (&optional display))
+(declare-function haiku-frame-list-z-order "haikufns.c" (&optional display))
(defun frame-list-z-order (&optional display)
"Return list of Emacs' frames, in Z (stacking) order.
@@ -1979,7 +1992,9 @@ frame-list-z-order
((eq frame-type 'w32)
(w32-frame-list-z-order display))
((eq frame-type 'ns)
- (ns-frame-list-z-order display)))))
+ (ns-frame-list-z-order display))
+ ((eq frame-type 'haiku)
+ (haiku-frame-list-z-order display)))))
(declare-function x-frame-restack "xfns.c" (frame1 frame2 &optional above))
(declare-function w32-frame-restack "w32fns.c" (frame1 frame2 &optional above))
@@ -2060,8 +2075,8 @@ display-mouse-p
((eq frame-type 'w32)
(with-no-warnings
(> w32-num-mouse-buttons 0)))
- ((memq frame-type '(x ns))
- t) ;; We assume X and NeXTstep *always* have a pointing device
+ ((memq frame-type '(x ns haiku))
+ t) ;; We assume X, NeXTstep and Haiku *always* have a pointing device
(t
(or (and (featurep 'xt-mouse)
xterm-mouse-mode)
@@ -2086,7 +2101,7 @@ display-graphic-p
that use a window system such as X, and false for text-only terminals.
DISPLAY can be a display name, a frame, or nil (meaning the selected
frame's display)."
- (not (null (memq (framep-on-display display) '(x w32 ns)))))
+ (not (null (memq (framep-on-display display) '(x w32 ns haiku)))))
(defun display-images-p (&optional display)
"Return non-nil if DISPLAY can display images.
@@ -2137,7 +2152,7 @@ display-screens
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-screens display))
(t
1))))
@@ -2157,7 +2172,7 @@ display-pixel-height
`display-monitor-attributes-list'."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-pixel-height display))
(t
(frame-height (if (framep display) display (selected-frame)))))))
@@ -2177,7 +2192,7 @@ display-pixel-width
`display-monitor-attributes-list'."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-pixel-width display))
(t
(frame-width (if (framep display) display (selected-frame)))))))
@@ -2215,7 +2230,7 @@ display-mm-height
refers to the height in millimeters for all physical monitors
associated with DISPLAY. To get information for each physical
monitor, use `display-monitor-attributes-list'."
- (and (memq (framep-on-display display) '(x w32 ns))
+ (and (memq (framep-on-display display) '(x w32 ns haiku))
(or (cddr (assoc (or display (frame-parameter nil 'display))
display-mm-dimensions-alist))
(cddr (assoc t display-mm-dimensions-alist))
@@ -2236,7 +2251,7 @@ display-mm-width
refers to the width in millimeters for all physical monitors
associated with DISPLAY. To get information for each physical
monitor, use `display-monitor-attributes-list'."
- (and (memq (framep-on-display display) '(x w32 ns))
+ (and (memq (framep-on-display display) '(x w32 ns haiku))
(or (cadr (assoc (or display (frame-parameter nil 'display))
display-mm-dimensions-alist))
(cadr (assoc t display-mm-dimensions-alist))
@@ -2254,7 +2269,7 @@ display-backing-store
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-backing-store display))
(t
'not-useful))))
@@ -2267,7 +2282,7 @@ display-save-under
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-save-under display))
(t
'not-useful))))
@@ -2280,7 +2295,7 @@ display-planes
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-planes display))
((eq frame-type 'pc)
4)
@@ -2295,7 +2310,7 @@ display-color-cells
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-color-cells display))
((eq frame-type 'pc)
16)
@@ -2312,7 +2327,7 @@ display-visual-class
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku))
(x-display-visual-class display))
((and (memq frame-type '(pc t))
(tty-display-color-p display))
diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el
index 089decb83c..b922f192a9 100644
--- a/lisp/international/mule-cmds.el
+++ b/lisp/international/mule-cmds.el
@@ -88,7 +88,7 @@ set-coding-system-map
(bindings--define-key map [separator-3] menu-bar-separator)
(bindings--define-key map [set-terminal-coding-system]
'(menu-item "For Terminal" set-terminal-coding-system
- :enable (null (memq initial-window-system '(x w32 ns)))
+ :enable (null (memq initial-window-system '(x w32 ns haiku)))
:help "How to encode terminal output"))
(bindings--define-key map [set-keyboard-coding-system]
'(menu-item "For Keyboard" set-keyboard-coding-system
diff --git a/lisp/loadup.el b/lisp/loadup.el
index e8ecb67d56..5b16d63e54 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -302,6 +302,11 @@
(load "term/common-win")
(load "term/x-win")))
+(if (featurep 'haiku)
+ (progn
+ (load "term/common-win")
+ (load "term/haiku-win")))
+
(if (or (eq system-type 'windows-nt)
(featurep 'w32))
(progn
@@ -557,6 +562,7 @@
(delete-file output)))))
;; Recompute NAME now, so that it isn't set when we dump.
(if (not (or (eq system-type 'ms-dos)
+ (eq system-type 'haiku) ;; BFS doesn't support hard links
;; Don't bother adding another name if we're just
;; building bootstrap-emacs.
(member dump-mode '("pbootstrap" "bootstrap"))))
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index 1a81f1a3d0..2dfc946bb6 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -2665,9 +2665,10 @@ menu-bar-open
this is the numeric argument to the command.
This function decides which method to use to access the menu
depending on FRAME's terminal device. On X displays, it calls
-`x-menu-bar-open'; on Windows, `w32-menu-bar-open'; otherwise it
-calls either `popup-menu' or `tmm-menubar' depending on whether
-`tty-menu-open-use-tmm' is nil or not.
+`x-menu-bar-open'; on Windows, `w32-menu-bar-open'; on Haiku,
+`haiku-menu-bar-open'; otherwise it calls either `popup-menu'
+or `tmm-menubar' depending on whether `tty-menu-open-use-tmm'
+is nil or not.
If FRAME is nil or not given, use the selected frame."
(interactive
@@ -2676,6 +2677,7 @@ menu-bar-open
(cond
((eq type 'x) (x-menu-bar-open frame))
((eq type 'w32) (w32-menu-bar-open frame))
+ ((eq type 'haiku) (haiku-menu-bar-open frame))
((and (null tty-menu-open-use-tmm)
(not (zerop (or (frame-parameter nil 'menu-bar-lines) 0))))
;; Make sure the menu bar is up to date. One situation where
diff --git a/lisp/mwheel.el b/lisp/mwheel.el
index 51410e3ef4..2787d1e452 100644
--- a/lisp/mwheel.el
+++ b/lisp/mwheel.el
@@ -55,7 +55,8 @@ mouse-wheel-change-button
(mouse-wheel-mode 1)))
(defcustom mouse-wheel-down-event
- (if (or (featurep 'w32-win) (featurep 'ns-win))
+ (if (or (featurep 'w32-win) (featurep 'ns-win)
+ (featurep 'haiku-win))
'wheel-up
'mouse-4)
"Event used for scrolling down."
@@ -64,7 +65,8 @@ mouse-wheel-down-event
:set 'mouse-wheel-change-button)
(defcustom mouse-wheel-up-event
- (if (or (featurep 'w32-win) (featurep 'ns-win))
+ (if (or (featurep 'w32-win) (featurep 'ns-win)
+ (featurep 'haiku-win))
'wheel-down
'mouse-5)
"Event used for scrolling up."
@@ -221,13 +223,15 @@ mwheel-scroll-right-function
"Function that does the job of scrolling right.")
(defvar mouse-wheel-left-event
- (if (or (featurep 'w32-win) (featurep 'ns-win))
+ (if (or (featurep 'w32-win) (featurep 'ns-win)
+ (featurep 'haiku-win))
'wheel-left
'mouse-6)
"Event used for scrolling left.")
(defvar mouse-wheel-right-event
- (if (or (featurep 'w32-win) (featurep 'ns-win))
+ (if (or (featurep 'w32-win) (featurep 'ns-win)
+ (featurep 'haiku-win))
'wheel-right
'mouse-7)
"Event used for scrolling right.")
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el
index 3af37e412d..687bf6c884 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -39,6 +39,7 @@
;; browse-url-chrome Chrome 47.0.2526.111
;; browse-url-chromium Chromium 3.0
;; browse-url-epiphany Epiphany Don't know
+;; browse-url-webpositive WebPositive 1.2-alpha (Haiku R1/beta3)
;; browse-url-w3 w3 0
;; browse-url-text-* Any text browser 0
;; browse-url-generic arbitrary
@@ -156,6 +157,7 @@ browse-url--browser-defcustom-type
(function-item :tag "Google Chrome" :value browse-url-chrome)
(function-item :tag "Chromium" :value browse-url-chromium)
(function-item :tag "Epiphany" :value browse-url-epiphany)
+ (function-item :tag "WebPositive" :value browse-url-webpositive)
(function-item :tag "Text browser in an xterm window"
:value browse-url-text-xterm)
(function-item :tag "Text browser in an Emacs window"
@@ -366,6 +368,11 @@ browse-url-epiphany-startup-arguments
`browse-url' is loaded."
:type '(repeat (string :tag "Argument")))
+(defcustom browse-url-webpositive-program "WebPositive"
+ "The name by which to invoke WebPositive."
+ :type 'string
+ :version "28.1")
+
;; GNOME means of invoking either Mozilla or Netscape.
(defvar browse-url-gnome-moz-program "gnome-moz-remote")
@@ -1050,6 +1057,7 @@ browse-url-default-browser
((executable-find browse-url-kde-program) 'browse-url-kde)
;;; ((executable-find browse-url-netscape-program) 'browse-url-netscape)
((executable-find browse-url-chrome-program) 'browse-url-chrome)
+ ((executable-find browse-url-webpositive-program) 'browse-url-webpositive)
((executable-find browse-url-xterm-program) 'browse-url-text-xterm)
((locate-library "w3") 'browse-url-w3)
(t
@@ -1376,6 +1384,18 @@ browse-url-epiphany-sentinel
(defvar url-handler-regexp)
+;;;###autoload
+(defun browse-url-webpositive (url &optional _new-window)
+ "Ask the WebPositive WWW browser to load URL.
+Default to the URL around or before point.
+The optional argument NEW-WINDOW is not used."
+ (interactive (browse-url-interactive-arg "URL: "))
+ (setq url (browse-url-encode-url url))
+ (let* ((process-environment (browse-url-process-environment)))
+ (start-process (concat "WebPositive " url) nil "WebPositive" url)))
+
+(function-put 'browse-url-webpositive 'browse-url-browser-kind 'external)
+
;;;###autoload
(defun browse-url-emacs (url &optional same-window)
"Ask Emacs to load URL into a buffer and show it in another window.
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index 70ebc1d2ec..1dcb81252a 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -239,7 +239,7 @@ eww-url-transformers
:version "29.1")
(defface eww-form-submit
- '((((type x w32 ns) (class color)) ; Like default mode line
+ '((((type x w32 ns haiku) (class color)) ; Like default mode line
:box (:line-width 2 :style released-button)
:background "#808080" :foreground "black"))
"Face for eww buffer buttons."
@@ -247,7 +247,7 @@ eww-form-submit
:group 'eww)
(defface eww-form-file
- '((((type x w32 ns) (class color)) ; Like default mode line
+ '((((type x w32 ns haiku) (class color)) ; Like default mode line
:box (:line-width 2 :style released-button)
:background "#808080" :foreground "black"))
"Face for eww buffer buttons."
@@ -255,7 +255,7 @@ eww-form-file
:group 'eww)
(defface eww-form-checkbox
- '((((type x w32 ns) (class color)) ; Like default mode line
+ '((((type x w32 ns haiku) (class color)) ; Like default mode line
:box (:line-width 2 :style released-button)
:background "lightgrey" :foreground "black"))
"Face for eww buffer buttons."
@@ -263,7 +263,7 @@ eww-form-checkbox
:group 'eww)
(defface eww-form-select
- '((((type x w32 ns) (class color)) ; Like default mode line
+ '((((type x w32 ns haiku) (class color)) ; Like default mode line
:box (:line-width 2 :style released-button)
:background "lightgrey" :foreground "black"))
"Face for eww buffer buttons."
diff --git a/lisp/term/haiku-win.el b/lisp/term/haiku-win.el
new file mode 100644
index 0000000000..36af10d2c7
--- /dev/null
+++ b/lisp/term/haiku-win.el
@@ -0,0 +1,134 @@
+;;; haiku-win.el --- set up windowing on Haiku -*- lexical-binding: t -*-
+
+;; 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/>.
+
+;;; Commentary:
+
+;; Support for using Haiku's BeOS derived windowing system.
+
+;;; Code:
+
+(eval-when-compile (require 'cl-lib))
+(unless (featurep 'haiku)
+ (error "%s: Loading haiku-win without having Haiku"
+ invocation-name))
+
+;; Documentation-purposes only: actually loaded in loadup.el.
+(require 'frame)
+(require 'mouse)
+(require 'scroll-bar)
+(require 'menu-bar)
+(require 'fontset)
+(require 'dnd)
+
+(add-to-list 'display-format-alist '(".*" . haiku-win))
+
+;;;; Command line argument handling.
+
+(defvar x-invocation-args)
+(defvar x-command-line-resources)
+
+(defvar haiku-initialized)
+
+(declare-function x-open-connection "haikufns.c")
+(declare-function x-handle-args "common-win")
+(declare-function haiku-selection-data "haikuselect.c")
+(declare-function haiku-selection-put "haikuselect.c")
+(declare-function haiku-put-resource "haikufns.c")
+
+(defun haiku--handle-x-command-line-resources (command-line-resources)
+ "Handle command line X resources specified with the option `-xrm'.
+The resources should be a list of strings in COMMAND-LINE-RESOURCES."
+ (dolist (s command-line-resources)
+ (let ((components (split-string s ":")))
+ (when (car components)
+ (haiku-put-resource (car components)
+ (string-trim-left
+ (mapconcat #'identity (cdr components) ":")))))))
+
+(cl-defmethod window-system-initialization (&context (window-system haiku)
+ &optional display)
+ "Set up the window system. WINDOW-SYSTEM must be HAIKU.
+DISPLAY may be set to the name of a display that will be initialized."
+ (cl-assert (not haiku-initialized))
+
+ (create-default-fontset)
+ (when x-command-line-resources
+ (haiku--handle-x-command-line-resources
+ (split-string x-command-line-resources "\n")))
+ (x-open-connection (or display "be") x-command-line-resources t)
+ (setq haiku-initialized t))
+
+(cl-defmethod frame-creation-function (params &context (window-system haiku))
+ (x-create-frame-with-faces params))
+
+(cl-defmethod handle-args-function (args &context (window-system haiku))
+ (x-handle-args args))
+
+(defun haiku--selection-type-to-mime (type)
+ "Convert symbolic selection type TYPE to its MIME equivalent.
+If TYPE is nil, return \"text/plain\"."
+ (cond
+ ((memq type '(TEXT COMPOUND_TEXT STRING UTF8_STRING)) "text/plain")
+ ((stringp type) type)
+ (t "text/plain")))
+
+(cl-defmethod gui-backend-get-selection (type data-type
+ &context (window-system haiku))
+ (haiku-selection-data type (haiku--selection-type-to-mime data-type)))
+
+(cl-defmethod gui-backend-set-selection (type value
+ &context (window-system haiku))
+ (haiku-selection-put type "text/plain" value))
+
+(cl-defmethod gui-backend-selection-exists-p (selection
+ &context (window-system haiku))
+ (haiku-selection-data selection "text/plain"))
+
+(cl-defmethod gui-backend-selection-owner-p (_
+ &context (window-system haiku))
+ t)
+
+(declare-function haiku-read-file-name "haikufns.c")
+
+(defun x-file-dialog (prompt dir default_filename mustmatch only_dir_p)
+ "SKIP: real doc in xfns.c."
+ (if (eq (framep-on-display (selected-frame)) 'haiku)
+ (haiku-read-file-name prompt (selected-frame)
+ (or dir (and default_filename
+ (file-name-directory default_filename)))
+ mustmatch only_dir_p
+ (file-name-nondirectory default_filename))
+ (error "x-file-dialog on a tty frame")))
+
+(defun haiku-dnd-handle-drag-n-drop-event (event)
+ "Handle specified drag-n-drop EVENT."
+ (interactive "e")
+ (let* ((string (caddr event))
+ (window (posn-window (event-start event))))
+ (with-selected-window window
+ (raise-frame)
+ (dnd-handle-one-url window 'private (concat "file:" string)))))
+
+(define-key special-event-map [drag-n-drop]
+ 'haiku-dnd-handle-drag-n-drop-event)
+
+(provide 'haiku-win)
+(provide 'term/haiku-win)
+
+;;; haiku-win.el ends here
diff --git a/lisp/tooltip.el b/lisp/tooltip.el
index 23b67ee2ca..6cc482d012 100644
--- a/lisp/tooltip.el
+++ b/lisp/tooltip.el
@@ -368,10 +368,15 @@ tooltip-show-help-non-mode
((equal-including-properties tooltip-help-message (current-message))
(message nil)))))
+(declare-function menu-or-popup-active-p "xmenu.c" ())
+
(defun tooltip-show-help (msg)
"Function installed as `show-help-function'.
MSG is either a help string to display, or nil to cancel the display."
- (if (display-graphic-p)
+ (if (and (display-graphic-p)
+ (or (not (eq window-system 'haiku)) ;; On Haiku, there isn't a reliable way to show tooltips
+ ;; above menus.
+ (not (menu-or-popup-active-p))))
(let ((previous-help tooltip-help-message))
(setq tooltip-help-message msg)
(cond ((null msg)
diff --git a/lisp/version.el b/lisp/version.el
index 3a3093fdd4..5d0a1ae37d 100644
--- a/lisp/version.el
+++ b/lisp/version.el
@@ -53,6 +53,8 @@ gtk-version-string
(defvar ns-version-string)
(defvar cairo-version-string)
+(declare-function haiku-get-version-string "haikufns.c")
+
(defun emacs-version (&optional here)
"Return string describing the version of Emacs that is running.
If optional argument HERE is non-nil, insert string at point.
@@ -71,6 +73,8 @@ emacs-version
((featurep 'x-toolkit) ", X toolkit")
((featurep 'ns)
(format ", NS %s" ns-version-string))
+ ((featurep 'haiku)
+ (format ", Haiku %s" (haiku-get-version-string)))
(t ""))
(if (featurep 'cairo)
(format ", cairo version %s" cairo-version-string)
diff --git a/src/Makefile.in b/src/Makefile.in
index 4c5535f8ad..db6b603a7f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -34,6 +34,7 @@ top_builddir =
abs_top_srcdir=@abs_top_srcdir@
VPATH = $(srcdir)
CC = @CC@
+CXX = @CXX@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
@@ -343,10 +344,17 @@ BUILD_DETAILS =
UNEXEC_OBJ = @UNEXEC_OBJ@
+HAIKU_OBJ = @HAIKU_OBJ@
+HAIKU_CXX_OBJ = @HAIKU_CXX_OBJ@
+HAIKU_LIBS = @HAIKU_LIBS@
+HAIKU_CFLAGS = @HAIKU_CFLAGS@
+
DUMPING=@DUMPING@
CHECK_STRUCTS = @CHECK_STRUCTS@
HAVE_PDUMPER = @HAVE_PDUMPER@
+HAVE_BE_APP = @HAVE_BE_APP@
+
## ARM Macs require that all code have a valid signature. Since pdump
## invalidates the signature, we must re-sign to fix it.
DO_CODESIGN=$(patsubst aarch64-apple-darwin%,yes,@configuration@)
@@ -364,6 +372,9 @@ pdmp :=
# Flags that might be in WARN_CFLAGS but are not valid for Objective C.
NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd
+# Ditto, but for C++.
+NON_CXX_CFLAGS = -Wmissing-prototypes -Wnested-externs -Wold-style-definition \
+ -Wstrict-prototypes -Wno-override-init
# -Demacs makes some files produce the correct version for use in Emacs.
# MYCPPFLAGS is for by-hand Emacs-specific overrides, e.g.,
@@ -379,17 +390,21 @@ EMACS_CFLAGS=
$(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
$(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
$(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
- $(WERROR_CFLAGS)
+ $(WERROR_CFLAGS) $(HAIKU_CFLAGS)
ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS)
ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \
$(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \
$(GNU_OBJC_CFLAGS)
+ALL_CXX_CFLAGS = $(EMACS_CFLAGS) \
+ $(filter-out $(NON_CXX_CFLAGS),$(WARN_CFLAGS)) $(CXXFLAGS)
-.SUFFIXES: .m
+.SUFFIXES: .m .cc
.c.o:
$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $<
.m.o:
$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
+.cc.o:
+ $(AM_V_CXX)$(CXX) -c $(CPPFLAGS) $(ALL_CXX_CFLAGS) $(PROFILING_CFLAGS) $<
## lastfile must follow all files whose initialized data areas should
## be dumped as pure by dump-emacs.
@@ -411,8 +426,10 @@ base_obj =
thread.o systhread.o \
$(if $(HYBRID_MALLOC),sheap.o) \
$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
- $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ)
-obj = $(base_obj) $(NS_OBJC_OBJ)
+ $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \
+ $(HAIKU_OBJ)
+doc_obj = $(base_obj) $(NS_OBJC_OBJ)
+obj = $(doc_obj) $(HAIKU_CXX_OBJ)
## Object files used on some machine or other.
## These go in the DOC file on all machines in case they are needed.
@@ -426,7 +443,8 @@ SOME_MACHINE_OBJECTS =
w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \
w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \
- xsettings.o xgselect.o termcap.o hbfont.o
+ xsettings.o xgselect.o termcap.o hbfont.o \
+ haikuterm.o haikufns.o haikumenu.o haikufont.o
## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty.
GMALLOC_OBJ=@GMALLOC_OBJ@
@@ -452,7 +470,11 @@ FIRSTFILE_OBJ=
ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj)
# Must be first, before dep inclusion!
+ifneq ($(HAVE_BE_APP),yes)
all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES)
+else
+all: Emacs Emacs.pdmp $(OTHER_FILES)
+endif
ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
all: ../native-lisp
endif
@@ -524,7 +546,7 @@ LIBES =
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
$(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
- $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS)
+ $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(HAIKU_LIBS)
## FORCE it so that admin/unidata can decide whether this file is
## up-to-date. Although since charprop depends on bootstrap-emacs,
@@ -581,6 +603,18 @@ emacs$(EXEEXT):
rm -f $@ && cp -f temacs$(EXEEXT) $@
endif
+## On Haiku, also produce a binary named Emacs with the appropriate
+## icon set.
+
+ifeq ($(HAVE_BE_APP),yes)
+Emacs: emacs$(EXEEXT)
+ cp -f emacs$(EXEEXT) $@
+ $(AM_V_GEN) $(libsrc)/be-resources \
+ $(etc)/images/icons/hicolor/32x32/apps/emacs.png $@
+Emacs.pdmp: $(pdmp)
+ $(AM_V_GEN) cp -f $(pdmp) $@
+endif
+
ifeq ($(DUMPING),pdumper)
$(pdmp): emacs$(EXEEXT)
LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \
@@ -599,11 +633,11 @@ $(pdmp):
## for the first time, this prevents any variation between configurations
## in the contents of the DOC file.
##
-$(etc)/DOC: lisp.mk $(libsrc)/make-docfile$(EXEEXT) $(obj) $(lisp)
+$(etc)/DOC: lisp.mk $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) $(lisp)
$(AM_V_GEN)$(MKDIR_P) $(etc)
$(AM_V_at)rm -f $(etc)/DOC
$(AM_V_at)$(libsrc)/make-docfile -d $(srcdir) \
- $(SOME_MACHINE_OBJECTS) $(obj) > $(etc)/DOC
+ $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC
$(AM_V_at)$(libsrc)/make-docfile -a $(etc)/DOC -d $(lispsource) \
$(shortlisp)
@@ -621,7 +655,7 @@ buildobj.h:
GLOBAL_SOURCES = $(base_obj:.o=.c) $(NS_OBJC_OBJ:.o=.m)
gl-stamp: $(libsrc)/make-docfile$(EXEEXT) $(GLOBAL_SOURCES)
- $(AM_V_GLOBALS)$(libsrc)/make-docfile -d $(srcdir) -g $(obj) > globals.tmp
+ $(AM_V_GLOBALS)$(libsrc)/make-docfile -d $(srcdir) -g $(doc_obj) > globals.tmp
$(AM_V_at)$(top_srcdir)/build-aux/move-if-change globals.tmp globals.h
$(AM_V_at)echo timestamp > $@
@@ -646,9 +680,15 @@ $(LIBEGNU_ARCHIVE):
## to start if Vinstallation_directory has the wrong value.
temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \
$(charsets) $(charscript) ${emoji-zwj} $(MAKE_PDUMPER_FINGERPRINT)
- $(AM_V_CCLD)$(CC) -o $@.tmp \
+ifeq ($(HAVE_BE_APP),yes)
+ $(AM_V_CXXLD)$(CXX) -o $@.tmp \
$(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \
+ $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) -lstdc++
+else
+ $(AM_V_CCLD)$(CC) -o $@.tmp \
+ $(ALL_CFLAGS) $(CXXFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \
$(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES)
+endif
ifeq ($(HAVE_PDUMPER),yes)
$(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@.tmp
ifeq ($(DO_CODESIGN),yes)
@@ -733,6 +773,7 @@ ${ETAGS}:
# to be built before we can get TAGS.
ctagsfiles1 = $(filter-out ${srcdir}/macuvs.h, $(wildcard ${srcdir}/*.[hc]))
ctagsfiles2 = $(wildcard ${srcdir}/*.m)
+ctagsfiles3 = $(wildcard ${srcdir}/*.cc)
## In out-of-tree builds, TAGS are generated in the build dir, like
## other non-bootstrap build products (see Bug#31744).
@@ -747,7 +788,8 @@ TAGS:
$(ctagsfiles1) \
--regex='{objc}/[ ]*DEFVAR_[A-Z_ (]+"\([^"]+\)"/\1/' \
--regex='{objc}/[ ]*DEFVAR_[A-Z_ (]+"[^"]+",[ ]\([A-Za-z0-9_]+\)/\1/' \
- $(ctagsfiles2)
+ $(ctagsfiles2) \
+ $(ctagsfiles3)
## Arrange to make tags tables for ../lisp and ../lwlib,
## which the above TAGS file for the C files includes by reference.
diff --git a/src/alloc.c b/src/alloc.c
index aa790d3afa..f8908c91db 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6149,6 +6149,10 @@ garbage_collect (void)
xg_mark_data ();
#endif
+#ifdef HAVE_HAIKU
+ mark_haiku_display ();
+#endif
+
#ifdef HAVE_WINDOW_SYSTEM
mark_fringe_data ();
#endif
diff --git a/src/dispextern.h b/src/dispextern.h
index f17f095e0d..a698f6546b 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -134,6 +134,13 @@ #define FACE_COLOR_TO_PIXEL(face_color, frame) (FRAME_NS_P (frame) \
#define FACE_COLOR_TO_PIXEL(face_color, frame) face_color
#endif
+#ifdef HAVE_HAIKU
+#include "haikugui.h"
+typedef struct haiku_display_info Display_Info;
+typedef Emacs_Pixmap Emacs_Pix_Container;
+typedef Emacs_Pixmap Emacs_Pix_Context;
+#endif
+
#ifdef HAVE_WINDOW_SYSTEM
# include <time.h>
# include "fontset.h"
@@ -3011,7 +3018,7 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo)
#ifdef HAVE_WINDOW_SYSTEM
# if (defined USE_CAIRO || defined HAVE_XRENDER \
- || defined HAVE_NS || defined HAVE_NTGUI)
+ || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU)
# define HAVE_NATIVE_TRANSFORMS
# endif
@@ -3050,6 +3057,14 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo)
#ifdef HAVE_NTGUI
XFORM xform;
#endif
+#ifdef HAVE_HAIKU
+ /* Non-zero if the image has not yet been transformed for display. */
+ int have_be_transforms_p;
+
+ double be_rotate;
+ double be_scale_x;
+ double be_scale_y;
+#endif
/* Colors allocated for this image, if any. Allocated via xmalloc. */
unsigned long *colors;
@@ -3489,7 +3504,8 @@ #define TRY_WINDOW_IGNORE_FONTS_CHANGE (1 << 1)
void prepare_image_for_display (struct frame *, struct image *);
ptrdiff_t lookup_image (struct frame *, Lisp_Object, int);
-#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS
+#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS \
+ || defined HAVE_HAIKU
#define RGB_PIXEL_COLOR unsigned long
#endif
diff --git a/src/dispnew.c b/src/dispnew.c
index 632eec2f03..f3f110a8f2 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -6146,7 +6146,7 @@ sit_for (Lisp_Object timeout, bool reading, int display_option)
wrong_type_argument (Qnumberp, timeout);
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
gobble_input ();
#endif
@@ -6453,6 +6453,15 @@ init_display_interactive (void)
}
#endif
+#ifdef HAVE_HAIKU
+ if (!inhibit_window_system && !will_dump_p ())
+ {
+ Vinitial_window_system = Qhaiku;
+ Vwindow_system_version = make_fixnum (1);
+ return;
+ }
+#endif
+
/* If no window system has been specified, try to use the terminal. */
if (! isatty (STDIN_FILENO))
fatal ("standard input is not a tty");
diff --git a/src/emacs.c b/src/emacs.c
index 032b27fcf3..63f2a39308 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -109,6 +109,10 @@ #define MAIN_PROGRAM
#include "getpagesize.h"
#include "gnutls.h"
+#ifdef HAVE_HAIKU
+#include <kernel/OS.h>
+#endif
+
#ifdef PROFILING
# include <sys/gmon.h>
extern void moncontrol (int mode);
@@ -2207,6 +2211,18 @@ main (int argc, char **argv)
syms_of_fontset ();
#endif /* HAVE_NS */
+#ifdef HAVE_HAIKU
+ syms_of_haikuterm ();
+ syms_of_haikufns ();
+ syms_of_haikumenu ();
+ syms_of_haikufont ();
+ syms_of_haikuselect ();
+#ifdef HAVE_NATIVE_IMAGE_API
+ syms_of_haikuimage ();
+#endif
+ syms_of_fontset ();
+#endif /* HAVE_HAIKU */
+
syms_of_gnutls ();
#ifdef HAVE_INOTIFY
@@ -2261,6 +2277,10 @@ main (int argc, char **argv)
#if defined WINDOWSNT || defined HAVE_NTGUI
globals_of_w32select ();
#endif
+
+#ifdef HAVE_HAIKU
+ init_haiku_select ();
+#endif
}
init_charset ();
@@ -2728,6 +2748,9 @@ shut_down_emacs (int sig, Lisp_Object stuff)
/* Don't update display from now on. */
Vinhibit_redisplay = Qt;
+#ifdef HAVE_HAIKU
+ be_app_quit ();
+#endif
/* If we are controlling the terminal, reset terminal modes. */
#ifndef DOS_NT
pid_t tpgrp = tcgetpgrp (STDIN_FILENO);
@@ -2737,6 +2760,10 @@ shut_down_emacs (int sig, Lisp_Object stuff)
if (sig && sig != SIGTERM)
{
static char const fmt[] = "Fatal error %d: %n%s\n";
+#ifdef HAVE_HAIKU
+ if (haiku_debug_on_fatal_error)
+ debugger ("Fatal error in Emacs");
+#endif
char buf[max ((sizeof fmt - sizeof "%d%n%s\n"
+ INT_STRLEN_BOUND (int) + 1),
min (PIPE_BUF, MAX_ALLOCA))];
@@ -3229,6 +3256,7 @@ syms_of_emacs (void)
`ms-dos' compiled as an MS-DOS application.
`windows-nt' compiled as a native W32 application.
`cygwin' compiled using the Cygwin library.
+ `haiku' compiled for a Haiku system.
Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix,
hpux, usg-unix-v) indicates some sort of Unix system. */);
Vsystem_type = intern_c_string (SYSTEM_TYPE);
diff --git a/src/fileio.c b/src/fileio.c
index 4015448ece..859b30564a 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6190,7 +6190,7 @@ DEFUN ("next-read-file-uses-dialog-p", Fnext_read_file_uses_dialog_p,
(void)
{
#if (defined USE_GTK || defined USE_MOTIF \
- || defined HAVE_NS || defined HAVE_NTGUI)
+ || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU)
if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
&& use_dialog_box
&& use_file_dialog
diff --git a/src/filelock.c b/src/filelock.c
index cc185d96cd..c12776246b 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -65,7 +65,7 @@ Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2021 Free Software
#define BOOT_TIME_FILE "/var/run/random-seed"
#endif
-#if !defined WTMP_FILE && !defined WINDOWSNT
+#if !defined WTMP_FILE && !defined WINDOWSNT && defined BOOT_TIME
#define WTMP_FILE "/var/log/wtmp"
#endif
diff --git a/src/floatfns.c b/src/floatfns.c
index aadae4fd9d..f52dae4719 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -347,6 +347,21 @@ DEFUN ("logb", Flogb, Slogb, 1, 1, 0,
double_integer_scale (double d)
{
int exponent = ilogb (d);
+#ifdef HAIKU
+ /* On Haiku, the values returned by ilogb are nonsensical when
+ confronted with tiny numbers, inf, or NaN, which breaks the trick
+ used by code on other platforms, so we have to test for each case
+ manually, and return the appropriate value. */
+ if (exponent == FP_ILOGB0)
+ {
+ if (isnan (d))
+ return (DBL_MANT_DIG - DBL_MIN_EXP) + 2;
+ if (isinf (d))
+ return (DBL_MANT_DIG - DBL_MIN_EXP) + 1;
+
+ return (DBL_MANT_DIG - DBL_MIN_EXP);
+ }
+#endif
return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX
? DBL_MANT_DIG - 1 - exponent
: (DBL_MANT_DIG - DBL_MIN_EXP
diff --git a/src/font.c b/src/font.c
index b503123b96..d423fd46b7 100644
--- a/src/font.c
+++ b/src/font.c
@@ -5751,6 +5751,9 @@ syms_of_font (void)
#ifdef HAVE_NTGUI
syms_of_w32font ();
#endif /* HAVE_NTGUI */
+#ifdef USE_BE_CAIRO
+ syms_of_ftcrfont ();
+#endif
#endif /* HAVE_WINDOW_SYSTEM */
}
diff --git a/src/font.h b/src/font.h
index 6694164e09..2da5ec4504 100644
--- a/src/font.h
+++ b/src/font.h
@@ -965,7 +965,7 @@ valid_font_driver (struct font_driver const *d)
extern void syms_of_nsfont (void);
extern void syms_of_macfont (void);
#endif /* HAVE_NS */
-#ifdef USE_CAIRO
+#if defined (USE_CAIRO) || defined (USE_BE_CAIRO)
extern struct font_driver const ftcrfont_driver;
#ifdef HAVE_HARFBUZZ
extern struct font_driver ftcrhbfont_driver;
@@ -999,7 +999,7 @@ #define FONT_DEFERRED_LOG(ACTION, ARG, RESULT) \
INLINE bool
font_data_structures_may_be_ill_formed (void)
{
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined USE_BE_CAIRO
/* Although this works around Bug#20890, it is probably not the
right thing to do. */
return gc_in_progress;
diff --git a/src/frame.c b/src/frame.c
index 79a7c89e0d..a21dd0d927 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -226,6 +226,7 @@ DEFUN ("framep", Fframep, Sframep, 1, 1, 0,
`w32' for an Emacs frame that is a window on MS-Windows display,
`ns' for an Emacs frame on a GNUstep or Macintosh Cocoa display,
`pc' for a direct-write MS-DOS frame.
+ `haiku` for an Emacs frame running in Haiku.
See also `frame-live-p'. */)
(Lisp_Object object)
{
@@ -244,6 +245,8 @@ DEFUN ("framep", Fframep, Sframep, 1, 1, 0,
return Qpc;
case output_ns:
return Qns;
+ case output_haiku:
+ return Qhaiku;
default:
emacs_abort ();
}
@@ -6020,6 +6023,7 @@ syms_of_frame (void)
DEFSYM (Qw32, "w32");
DEFSYM (Qpc, "pc");
DEFSYM (Qns, "ns");
+ DEFSYM (Qhaiku, "haiku");
DEFSYM (Qvisible, "visible");
DEFSYM (Qbuffer_predicate, "buffer-predicate");
DEFSYM (Qbuffer_list, "buffer-list");
diff --git a/src/frame.h b/src/frame.h
index 3dd76805dd..cb2bad71c5 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -585,6 +585,7 @@ #define EMACS_FRAME_H
struct x_output *x; /* From xterm.h. */
struct w32_output *w32; /* From w32term.h. */
struct ns_output *ns; /* From nsterm.h. */
+ struct haiku_output *haiku; /* From haikuterm.h. */
}
output_data;
@@ -852,6 +853,11 @@ #define FRAME_NS_P(f) false
#else
#define FRAME_NS_P(f) ((f)->output_method == output_ns)
#endif
+#ifndef HAVE_HAIKU
+#define FRAME_HAIKU_P(f) false
+#else
+#define FRAME_HAIKU_P(f) ((f)->output_method == output_haiku)
+#endif
/* FRAME_WINDOW_P tests whether the frame is a graphical window system
frame. */
@@ -864,6 +870,9 @@ #define FRAME_WINDOW_P(f) FRAME_W32_P (f)
#ifdef HAVE_NS
#define FRAME_WINDOW_P(f) FRAME_NS_P(f)
#endif
+#ifdef HAVE_HAIKU
+#define FRAME_WINDOW_P(f) FRAME_HAIKU_P (f)
+#endif
#ifndef FRAME_WINDOW_P
#define FRAME_WINDOW_P(f) ((void) (f), false)
#endif
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index db417b3e77..5d75f18357 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -22,7 +22,13 @@
#include <cairo-ft.h>
#include "lisp.h"
+#ifdef HAVE_X_WINDOWS
#include "xterm.h"
+#else /* Otherwise, Haiku */
+#include "haikuterm.h"
+#include "haiku_support.h"
+#include "termchar.h"
+#endif
#include "blockinput.h"
#include "charset.h"
#include "composite.h"
@@ -30,6 +36,12 @@
#include "ftfont.h"
#include "pdumper.h"
+#ifdef USE_BE_CAIRO
+#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
+#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
+#define BLUE_FROM_ULONG(color) ((color) & 0xff)
+#endif
+
#define METRICS_NCOLS_PER_ROW (128)
enum metrics_status
@@ -513,11 +525,37 @@ ftcrfont_draw (struct glyph_string *s,
block_input ();
+#ifndef USE_BE_CAIRO
cr = x_begin_cr_clip (f, s->gc);
+#else
+ BView_draw_lock (FRAME_HAIKU_VIEW (f));
+ EmacsWindow_begin_cr_critical_section (FRAME_HAIKU_WINDOW (f));
+ cr = haiku_begin_cr_clip (f, s);
+ if (!cr)
+ {
+ BView_draw_unlock (FRAME_HAIKU_VIEW (f));
+ EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
+ unblock_input ();
+ return 0;
+ }
+ BView_cr_dump_clipping (FRAME_HAIKU_VIEW (f), cr);
+#endif
if (with_background)
{
+#ifndef USE_BE_CAIRO
x_set_cr_source_with_gc_background (f, s->gc);
+ s->background_filled_p = 1;
+#else
+ struct face *face = s->face;
+
+ uint32_t col = s->hl == DRAW_CURSOR ?
+ FRAME_CURSOR_COLOR (s->f).pixel : face->background;
+
+ cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
+ GREEN_FROM_ULONG (col) / 255.0,
+ BLUE_FROM_ULONG (col) / 255.0);
+#endif
cairo_rectangle (cr, x, y - FONT_BASE (face->font),
s->width, FONT_HEIGHT (face->font));
cairo_fill (cr);
@@ -533,13 +571,25 @@ ftcrfont_draw (struct glyph_string *s,
glyphs[i].index,
NULL));
}
-
+#ifndef USE_BE_CAIRO
x_set_cr_source_with_gc_foreground (f, s->gc);
+#else
+ uint32_t col = s->hl == DRAW_CURSOR ?
+ FRAME_OUTPUT_DATA (s->f)->cursor_fg : face->foreground;
+
+ cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
+ GREEN_FROM_ULONG (col) / 255.0,
+ BLUE_FROM_ULONG (col) / 255.0);
+#endif
cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font);
cairo_show_glyphs (cr, glyphs, len);
-
+#ifndef USE_BE_CAIRO
x_end_cr_clip (f);
-
+#else
+ haiku_end_cr_clip (cr);
+ EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
+ BView_draw_unlock (FRAME_HAIKU_VIEW (f));
+#endif
unblock_input ();
return len;
diff --git a/src/ftfont.c b/src/ftfont.c
index 03e44ec30e..cf592759ab 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -3108,6 +3108,10 @@ syms_of_ftfont (void)
Fput (Qfreetype, Qfont_driver_superseded_by, Qfreetypehb);
#endif /* HAVE_HARFBUZZ */
+#ifdef HAVE_HAIKU
+ DEFSYM (Qmono, "mono");
+#endif
+
/* Fontconfig's generic families and their aliases. */
DEFSYM (Qmonospace, "monospace");
DEFSYM (Qsans_serif, "sans-serif");
diff --git a/src/ftfont.h b/src/ftfont.h
index f771dc159b..a233b698eb 100644
--- a/src/ftfont.h
+++ b/src/ftfont.h
@@ -29,6 +29,10 @@ #define EMACS_FTFONT_H
# include FT_BDF_H
#endif
+#ifdef USE_BE_CAIRO
+#include <cairo.h>
+#endif
+
#ifdef HAVE_HARFBUZZ
#include <hb.h>
#include <hb-ft.h>
@@ -62,7 +66,7 @@ #define EMACS_FTFONT_H
hb_font_t *hb_font;
#endif /* HAVE_HARFBUZZ */
-#ifdef USE_CAIRO
+#if defined (USE_CAIRO) || defined (USE_BE_CAIRO)
cairo_scaled_font_t *cr_scaled_font;
/* Scale factor from the bitmap strike metrics in 1/64 pixels, used
as the hb_position_t value in HarfBuzz, to those in (scaled)
@@ -71,7 +75,8 @@ #define EMACS_FTFONT_H
/* Font metrics cache. */
struct font_metrics **metrics;
short metrics_nrows;
-#else
+#endif
+#ifndef HAVE_HAIKU
/* These are used by the XFT backend. */
Display *display;
XftFont *xftfont;
diff --git a/src/haiku.c b/src/haiku.c
new file mode 100644
index 0000000000..efed5d064f
--- /dev/null
+++ b/src/haiku.c
@@ -0,0 +1,288 @@
+/* Haiku subroutines that are general to the Haiku operating system.
+ 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 "lisp.h"
+#include "process.h"
+#include "coding.h"
+
+#include <kernel/OS.h>
+
+#include <pwd.h>
+#include <stdlib.h>
+
+Lisp_Object
+list_system_processes (void)
+{
+ team_info info;
+ int32 cookie = 0;
+ Lisp_Object lval = Qnil;
+
+ while (get_next_team_info (&cookie, &info) == B_OK)
+ {
+ lval = Fcons (make_fixnum (info.team), lval);
+ }
+
+ return lval;
+}
+
+Lisp_Object
+system_process_attributes (Lisp_Object pid)
+{
+ CHECK_FIXNUM (pid);
+
+ team_info info;
+ Lisp_Object lval = Qnil;
+ thread_info inf;
+ area_info area;
+ team_id id = (team_id) XFIXNUM (pid);
+ struct passwd *g;
+ size_t mem = 0;
+
+ if (get_team_info (id, &info) != B_OK)
+ return Qnil;
+
+ bigtime_t everything = 0, vsample = 0;
+ bigtime_t cpu_eaten = 0, esample = 0;
+
+ lval = Fcons (Fcons (Qeuid, make_fixnum (info.uid)), lval);
+ lval = Fcons (Fcons (Qegid, make_fixnum (info.gid)), lval);
+ lval = Fcons (Fcons (Qthcount, make_fixnum (info.thread_count)), lval);
+ lval = Fcons (Fcons (Qcomm, build_string_from_utf8 (info.args)), lval);
+
+ g = getpwuid (info.uid);
+
+ if (g && g->pw_name)
+ lval = Fcons (Fcons (Quser, build_string (g->pw_name)), lval);
+
+ /* FIXME: Calculating this makes Emacs show up as using 100% CPU! */
+
+ for (int32 team_cookie = 0;
+ get_next_team_info (&team_cookie, &info) == B_OK;)
+ for (int32 thread_cookie = 0;
+ get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
+ {
+ if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
+ cpu_eaten += inf.user_time + inf.kernel_time;
+ everything += inf.user_time + inf.kernel_time;
+ }
+
+ sleep (0.05);
+
+ for (int32 team_cookie = 0;
+ get_next_team_info (&team_cookie, &info) == B_OK;)
+ for (int32 thread_cookie = 0;
+ get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
+ {
+ if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
+ esample += inf.user_time + inf.kernel_time;
+ vsample += inf.user_time + inf.kernel_time;
+ }
+
+ cpu_eaten = esample - cpu_eaten;
+ everything = vsample - everything;
+
+ if (everything)
+ lval = Fcons (Fcons (Qpcpu, make_float (((double) (cpu_eaten) /
+ (double) (everything)) * 100)),
+ lval);
+ else
+ lval = Fcons (Fcons (Qpcpu, make_float (0.0)), lval);
+
+ for (ssize_t area_cookie = 0;
+ get_next_area_info (id, &area_cookie, &area) == B_OK;)
+ mem += area.ram_size;
+
+ system_info sinfo;
+ get_system_info (&sinfo);
+ int64 max = (int64) sinfo.max_pages * B_PAGE_SIZE;
+
+ lval = Fcons (Fcons (Qpmem, make_float (((double) mem /
+ (double) max) * 100)),
+ lval);
+ lval = Fcons (Fcons (Qrss, make_fixnum (mem / 1024)), lval);
+
+ return lval;
+}
+
+
+/* Borrowed from w32 implementation. */
+
+struct load_sample
+{
+ time_t sample_time;
+ bigtime_t idle;
+ bigtime_t kernel;
+ bigtime_t user;
+};
+
+/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
+static struct load_sample samples[16*60];
+static int first_idx = -1, last_idx = -1;
+static int max_idx = ARRAYELTS (samples);
+static unsigned num_of_processors = 0;
+
+static int
+buf_next (int from)
+{
+ int next_idx = from + 1;
+
+ if (next_idx >= max_idx)
+ next_idx = 0;
+
+ return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+ int prev_idx = from - 1;
+
+ if (prev_idx < 0)
+ prev_idx = max_idx - 1;
+
+ return prev_idx;
+}
+
+static double
+getavg (int which)
+{
+ double retval = -1.0;
+ double tdiff;
+ int idx;
+ double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+ time_t now = samples[last_idx].sample_time;
+
+ if (first_idx != last_idx)
+ {
+ for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+ {
+ tdiff = difftime (now, samples[idx].sample_time);
+ if (tdiff >= span - 2 * DBL_EPSILON * now)
+ {
+ long double sys =
+ (samples[last_idx].kernel + samples[last_idx].user) -
+ (samples[idx].kernel + samples[idx].user);
+ long double idl = samples[last_idx].idle - samples[idx].idle;
+
+ retval = (idl / (sys + idl)) * num_of_processors;
+ break;
+ }
+ if (idx == first_idx)
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static void
+sample_sys_load (bigtime_t *idle, bigtime_t *system, bigtime_t *user)
+{
+ bigtime_t i = 0, s = 0, u = 0;
+ team_info info;
+ thread_info inf;
+
+ for (int32 team_cookie = 0;
+ get_next_team_info (&team_cookie, &info) == B_OK;)
+ for (int32 thread_cookie = 0;
+ get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
+ {
+ if (!strncmp (inf.name, "idle thread ", 12))
+ i += inf.user_time + inf.kernel_time;
+ else
+ s += inf.kernel_time, u += inf.user_time;
+ }
+
+ *idle = i;
+ *system = s;
+ *user = u;
+}
+
+int
+getloadavg (double loadavg[], int nelem)
+{
+ int elem;
+ bigtime_t idle, kernel, user;
+ time_t now = time (NULL);
+
+ if (num_of_processors <= 0)
+ {
+ system_info i;
+ if (get_system_info (&i) == B_OK)
+ num_of_processors = i.cpu_count;
+ }
+
+ /* If system time jumped back for some reason, delete all samples
+ whose time is later than the current wall-clock time. This
+ prevents load average figures from becoming frozen for prolonged
+ periods of time, when system time is reset backwards. */
+ if (last_idx >= 0)
+ {
+ while (difftime (now, samples[last_idx].sample_time) < -1.0)
+ {
+ if (last_idx == first_idx)
+ {
+ first_idx = last_idx = -1;
+ break;
+ }
+ last_idx = buf_prev (last_idx);
+ }
+ }
+
+ /* Store another sample. We ignore samples that are less than 1 sec
+ apart. */
+ if (last_idx < 0
+ || (difftime (now, samples[last_idx].sample_time)
+ >= 1.0 - 2 * DBL_EPSILON * now))
+ {
+ sample_sys_load (&idle, &kernel, &user);
+ last_idx = buf_next (last_idx);
+ samples[last_idx].sample_time = now;
+ samples[last_idx].idle = idle;
+ samples[last_idx].kernel = kernel;
+ samples[last_idx].user = user;
+ /* If the buffer has more that 15 min worth of samples, discard
+ the old ones. */
+ if (first_idx == -1)
+ first_idx = last_idx;
+ while (first_idx != last_idx
+ && (difftime (now, samples[first_idx].sample_time)
+ >= 15.0 * 60 + 2 * DBL_EPSILON * now))
+ first_idx = buf_next (first_idx);
+ }
+
+ for (elem = 0; elem < nelem; elem++)
+ {
+ double avg = getavg (elem);
+
+ if (avg < 0)
+ break;
+ loadavg[elem] = avg;
+ }
+
+ /* Always return at least one element, otherwise load-average
+ returns nil, and Lisp programs might decide we cannot measure
+ system load. For example, jit-lock-stealth-load's defcustom
+ might decide that feature is "unsupported". */
+ if (elem == 0)
+ loadavg[elem++] = 0.09; /* < display-time-load-average-threshold */
+
+ return elem;
+}
diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc
new file mode 100644
index 0000000000..5b1eccfbe6
--- /dev/null
+++ b/src/haiku_draw_support.cc
@@ -0,0 +1,488 @@
+/* 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 <View.h>
+#include <Region.h>
+#include <Font.h>
+#include <Window.h>
+#include <Bitmap.h>
+
+#include <cmath>
+
+#include "haiku_support.h"
+
+#define RGB_TO_UINT32(r, g, b) ((255 << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
+#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
+#define BLUE_FROM_ULONG(color) ((color) & 0xff)
+
+#define RGB_COLOR_UINT32(r) RGB_TO_UINT32 ((r).red, (r).green, (r).blue)
+
+static void
+rgb32_to_rgb_color (uint32_t rgb, rgb_color *color)
+{
+ color->red = RED_FROM_ULONG (rgb);
+ color->green = GREEN_FROM_ULONG (rgb);
+ color->blue = BLUE_FROM_ULONG (rgb);
+ color->alpha = 255;
+}
+
+static BView *
+get_view (void *vw)
+{
+ BView *view = (BView *) find_appropriate_view_for_draw (vw);
+ return view;
+}
+
+void
+BView_StartClip (void *view)
+{
+ BView *vw = get_view (view);
+ vw->PushState ();
+}
+
+void
+BView_EndClip (void *view)
+{
+ BView *vw = get_view (view);
+ vw->PopState ();
+}
+
+void
+BView_SetHighColor (void *view, uint32_t color)
+{
+ BView *vw = get_view (view);
+ rgb_color col;
+ rgb32_to_rgb_color (color, &col);
+
+ vw->SetHighColor (col);
+}
+
+void
+BView_SetLowColor (void *view, uint32_t color)
+{
+ BView *vw = get_view (view);
+ rgb_color col;
+ rgb32_to_rgb_color (color, &col);
+
+ vw->SetLowColor (col);
+}
+
+void
+BView_SetPenSize (void *view, int u)
+{
+ BView *vw = get_view (view);
+ vw->SetPenSize (u);
+}
+
+void
+BView_FillRectangle (void *view, int x, int y, int width, int height)
+{
+ BView *vw = get_view (view);
+ BRect rect = BRect (x, y, x + width - 1, y + height - 1);
+
+ vw->FillRect (rect);
+}
+
+void
+BView_FillRectangleAbs (void *view, int x, int y, int x1, int y1)
+{
+ BView *vw = get_view (view);
+ BRect rect = BRect (x, y, x1, y1);
+
+ vw->FillRect (rect);
+}
+
+void
+BView_StrokeRectangle (void *view, int x, int y, int width, int height)
+{
+ BView *vw = get_view (view);
+ BRect rect = BRect (x, y, x + width - 1, y + height - 1);
+
+ vw->StrokeRect (rect);
+}
+
+void
+BView_SetViewColor (void *view, uint32_t color)
+{
+ BView *vw = get_view (view);
+ rgb_color col;
+ rgb32_to_rgb_color (color, &col);
+
+#ifndef USE_BE_CAIRO
+ vw->SetViewColor (col);
+#else
+ vw->SetViewColor (B_TRANSPARENT_32_BIT);
+#endif
+}
+
+void
+BView_ClipToRect (void *view, int x, int y, int width, int height)
+{
+ BView *vw = get_view (view);
+ BRect rect = BRect (x, y, x + width - 1, y + height - 1);
+
+ vw->ClipToRect (rect);
+}
+
+void
+BView_ClipToInverseRect (void *view, int x, int y, int width, int height)
+{
+ BView *vw = get_view (view);
+ BRect rect = BRect (x, y, x + width - 1, y + height - 1);
+
+ vw->ClipToInverseRect (rect);
+}
+
+void
+BView_StrokeLine (void *view, int sx, int sy, int tx, int ty)
+{
+ BView *vw = get_view (view);
+ BPoint from = BPoint (sx, sy);
+ BPoint to = BPoint (tx, ty);
+
+ vw->StrokeLine (from, to);
+}
+
+void
+BView_SetFont (void *view, void *font)
+{
+ BView *vw = get_view (view);
+
+ vw->SetFont ((BFont *) font);
+}
+
+void
+BView_MovePenTo (void *view, int x, int y)
+{
+ BView *vw = get_view (view);
+ BPoint pt = BPoint (x, y);
+
+ vw->MovePenTo (pt);
+}
+
+void
+BView_DrawString (void *view, const char *chr, ptrdiff_t len)
+{
+ BView *vw = get_view (view);
+
+ vw->DrawString (chr, len);
+}
+
+void
+BView_DrawChar (void *view, char chr)
+{
+ BView *vw = get_view (view);
+
+ vw->DrawChar (chr);
+}
+
+void
+BView_CopyBits (void *view, int x, int y, int width, int height,
+ int tox, int toy, int towidth, int toheight)
+{
+ BView *vw = get_view (view);
+
+ vw->CopyBits (BRect (x, y, x + width - 1, y + height - 1),
+ BRect (tox, toy, tox + towidth - 1, toy + toheight - 1));
+ vw->Sync ();
+}
+
+/* Convert RGB32 color color from RGB color space to its
+ HSL components pointed to by H, S and L. */
+void
+rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l)
+{
+ rgb_color col;
+ rgb32_to_rgb_color (rgb, &col);
+
+ double red = col.red / 255.0;
+ double green = col.green / 255.0;
+ double blue = col.blue / 255.0;
+
+ double max = std::fmax (std::fmax (red, blue), green);
+ double min = std::fmin (std::fmin (red, blue), green);
+ double delta = max - min;
+ *l = (max + min) / 2.0;
+
+ if (!delta)
+ {
+ *h = 0;
+ *s = 0;
+ return;
+ }
+
+ *s = (*l < 0.5) ? delta / (max + min) :
+ delta / (20 - max - min);
+ double rc = (max - red) / delta;
+ double gc = (max - green) / delta;
+ double bc = (max - blue) / delta;
+
+ if (red == max)
+ *h = bc - gc;
+ else if (green == max)
+ *h = 2.0 + rc + -bc;
+ else
+ *h = 4.0 + gc + -rc;
+ *h = std::fmod (*h / 6, 1.0);
+}
+
+static double
+hue_to_rgb (double v1, double v2, double h)
+{
+ if (h < 1 / 6)
+ return v1 + (v2 - v1) * h * 6.0;
+ else if (h < 0.5)
+ return v2;
+ else if (h < 2.0 / 3)
+ return v1 + (v2 - v1) * (2.0 / 3 - h) * 6.0;
+ return v1;
+}
+
+void
+hsl_color_rgb (double h, double s, double l, uint32_t *rgb)
+{
+ if (!s)
+ *rgb = RGB_TO_UINT32 (std::lrint (l * 255),
+ std::lrint (l * 255),
+ std::lrint (l * 255));
+ else
+ {
+ double m2 = l <= 0.5 ? l * (1 + s) : l + s - l * s;
+ double m1 = 2.0 * l - m2;
+
+ *rgb = RGB_TO_UINT32
+ (std::lrint (hue_to_rgb (m1, m2,
+ std::fmod (h + 1 / 3.0, 1)) * 255),
+ std::lrint (hue_to_rgb (m1, m2, h) * 255),
+ std::lrint (hue_to_rgb (m1, m2,
+ std::fmod (h - 1 / 3.0, 1)) * 255));
+ }
+}
+
+void
+BView_DrawBitmap (void *view, void *bitmap, int x, int y,
+ int width, int height, int vx, int vy, int vwidth,
+ int vheight)
+{
+ BView *vw = get_view (view);
+ BBitmap *bm = (BBitmap *) bitmap;
+
+ vw->PushState ();
+ vw->SetDrawingMode (B_OP_OVER);
+ vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
+ BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
+ vw->PopState ();
+}
+
+void
+BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
+ int y, int width, int height)
+{
+ BView *vw = get_view (view);
+ BBitmap *bm = (BBitmap *) bitmap;
+ BBitmap bc (bm->Bounds (), B_RGBA32);
+ BRect rect (x, y, x + width - 1, y + height - 1);
+
+ if (bc.InitCheck () != B_OK || bc.ImportBits (bm) != B_OK)
+ return;
+
+ uint32_t *bits = (uint32_t *) bc.Bits ();
+ size_t stride = bc.BytesPerRow ();
+
+ if (bm->ColorSpace () == B_GRAY1)
+ {
+ rgb_color low_color = vw->LowColor ();
+ for (int y = 0; y <= bc.Bounds ().Height (); ++y)
+ {
+ for (int x = 0; x <= bc.Bounds ().Width (); ++x)
+ {
+ if (bits[y * (stride / 4) + x] == 0xFF000000)
+ bits[y * (stride / 4) + x] = RGB_COLOR_UINT32 (low_color);
+ else
+ bits[y * (stride / 4) + x] = 0;
+ }
+ }
+ }
+
+ vw->PushState ();
+ vw->SetDrawingMode (bm->ColorSpace () == B_GRAY1 ? B_OP_OVER : B_OP_ERASE);
+ vw->DrawBitmap (&bc, rect);
+ vw->PopState ();
+}
+
+void
+BView_DrawMask (void *src, void *view,
+ int x, int y, int width, int height,
+ int vx, int vy, int vwidth, int vheight,
+ uint32_t color)
+{
+ BBitmap *source = (BBitmap *) src;
+ BBitmap bm (source->Bounds (), B_RGBA32);
+ if (bm.InitCheck () != B_OK)
+ return;
+ for (int y = 0; y <= bm.Bounds ().Height (); ++y)
+ {
+ for (int x = 0; x <= bm.Bounds ().Width (); ++x)
+ {
+ int bit = haiku_get_pixel ((void *) source, x, y);
+
+ if (!bit)
+ haiku_put_pixel ((void *) &bm, x, y, ((uint32_t) 255 << 24) | color);
+ else
+ haiku_put_pixel ((void *) &bm, x, y, 0);
+ }
+ }
+ BView *vw = get_view (view);
+ vw->SetDrawingMode (B_OP_OVER);
+ vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
+ BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
+}
+
+static BBitmap *
+rotate_bitmap_270 (BBitmap *bmp)
+{
+ BRect r = bmp->Bounds ();
+ BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
+ bmp->ColorSpace (), true);
+ if (bm->InitCheck () != B_OK)
+ gui_abort ("Failed to init bitmap for rotate");
+ int w = bmp->Bounds ().Width () + 1;
+ int h = bmp->Bounds ().Height () + 1;
+
+ for (int y = 0; y < h; ++y)
+ for (int x = 0; x < w; ++x)
+ haiku_put_pixel ((void *) bm, y, w - x - 1,
+ haiku_get_pixel ((void *) bmp, x, y));
+
+ return bm;
+}
+
+static BBitmap *
+rotate_bitmap_90 (BBitmap *bmp)
+{
+ BRect r = bmp->Bounds ();
+ BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
+ bmp->ColorSpace (), true);
+ if (bm->InitCheck () != B_OK)
+ gui_abort ("Failed to init bitmap for rotate");
+ int w = bmp->Bounds ().Width () + 1;
+ int h = bmp->Bounds ().Height () + 1;
+
+ for (int y = 0; y < h; ++y)
+ for (int x = 0; x < w; ++x)
+ haiku_put_pixel ((void *) bm, h - y - 1, x,
+ haiku_get_pixel ((void *) bmp, x, y));
+
+ return bm;
+}
+
+void *
+BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color,
+ double rot, int desw, int desh)
+{
+ BBitmap *bm = (BBitmap *) bitmap;
+ BBitmap *mk = (BBitmap *) mask;
+ int copied_p = 0;
+
+ if (rot == 90)
+ {
+ copied_p = 1;
+ bm = rotate_bitmap_90 (bm);
+ if (mk)
+ mk = rotate_bitmap_90 (mk);
+ }
+
+ if (rot == 270)
+ {
+ copied_p = 1;
+ bm = rotate_bitmap_270 (bm);
+ if (mk)
+ mk = rotate_bitmap_270 (mk);
+ }
+
+ BRect r = bm->Bounds ();
+ if (r.Width () != desw || r.Height () != desh)
+ {
+ BRect n = BRect (0, 0, desw - 1, desh - 1);
+ BView vw (n, NULL, B_FOLLOW_NONE, 0);
+ BBitmap *dst = new BBitmap (n, bm->ColorSpace (), true);
+ if (dst->InitCheck () != B_OK)
+ if (bm->InitCheck () != B_OK)
+ gui_abort ("Failed to init bitmap for scale");
+ dst->AddChild (&vw);
+
+ if (!vw.LockLooper ())
+ gui_abort ("Failed to lock offscreen view for scale");
+
+ if (rot != 90 && rot != 270)
+ {
+ BAffineTransform tr;
+ tr.RotateBy (BPoint (desw / 2, desh / 2), rot * M_PI / 180.0);
+ vw.SetTransform (tr);
+ }
+
+ vw.MovePenTo (0, 0);
+ vw.DrawBitmap (bm, n);
+ if (mk)
+ BView_DrawMask ((void *) mk, (void *) &vw,
+ 0, 0, mk->Bounds ().Width (),
+ mk->Bounds ().Height (),
+ 0, 0, desw, desh, m_color);
+ vw.Sync ();
+ vw.RemoveSelf ();
+
+ if (copied_p)
+ delete bm;
+ if (copied_p && mk)
+ delete mk;
+ return dst;
+ }
+
+ return bm;
+}
+
+void
+BView_FillTriangle (void *view, int x1, int y1,
+ int x2, int y2, int x3, int y3)
+{
+ BView *vw = get_view (view);
+ vw->FillTriangle (BPoint (x1, y1), BPoint (x2, y2),
+ BPoint (x3, y3));
+}
+
+void
+BView_SetHighColorForVisibleBell (void *view, uint32_t color)
+{
+ BView *vw = (BView *) view;
+ rgb_color col;
+ rgb32_to_rgb_color (color, &col);
+
+ vw->SetHighColor (col);
+}
+
+void
+BView_FillRectangleForVisibleBell (void *view, int x, int y, int width, int height)
+{
+ BView *vw = (BView *) view;
+ BRect rect = BRect (x, y, x + width - 1, y + height - 1);
+
+ vw->FillRect (rect);
+}
diff --git a/src/haiku_font_support.cc b/src/haiku_font_support.cc
new file mode 100644
index 0000000000..9ac0400969
--- /dev/null
+++ b/src/haiku_font_support.cc
@@ -0,0 +1,596 @@
+/* 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 <Font.h>
+#include <Rect.h>
+#include <AffineTransform.h>
+
+#include <cstring>
+#include <cmath>
+
+#include "haiku_support.h"
+
+/* Haiku doesn't expose font language data in BFont objects. Thus, we
+ select a few representative characters for each supported `:lang'
+ (currently Chinese, Korean and Japanese,) and test for those
+ instead. */
+
+static uint32_t language_code_points[MAX_LANGUAGE][4] =
+ {{20154, 20754, 22996, 0}, /* Chinese. */
+ {51312, 49440, 44544, 0}, /* Korean. */
+ {26085, 26412, 12371, 0}, /* Japanese. */};
+
+static void
+estimate_font_ascii (BFont *font, int *max_width,
+ int *min_width, int *avg_width)
+{
+ char ch[2];
+ bool tems[1];
+ int total = 0;
+ int count = 0;
+ int min = 0;
+ int max = 0;
+
+ std::memset (ch, 0, sizeof ch);
+ for (ch[0] = 32; ch[0] < 127; ++ch[0])
+ {
+ tems[0] = false;
+ font->GetHasGlyphs (ch, 1, tems);
+ if (tems[0])
+ {
+ int w = font->StringWidth (ch);
+ ++count;
+ total += w;
+
+ if (!min || min > w)
+ min = w;
+ if (max < w)
+ max = w;
+ }
+ }
+
+ *min_width = min;
+ *max_width = max;
+ *avg_width = total / count;
+}
+
+void
+BFont_close (void *font)
+{
+ if (font != (void *) be_fixed_font &&
+ font != (void *) be_plain_font &&
+ font != (void *) be_bold_font)
+ delete (BFont *) font;
+}
+
+void
+BFont_dat (void *font, int *px_size, int *min_width, int *max_width,
+ int *avg_width, int *height, int *space_width, int *ascent,
+ int *descent, int *underline_position, int *underline_thickness)
+{
+ BFont *ft = (BFont *) font;
+ struct font_height fheight;
+ bool have_space_p;
+
+ char atem[1];
+ bool otem[1];
+
+ ft->GetHeight (&fheight);
+ atem[0] = ' ';
+ otem[0] = false;
+ ft->GetHasGlyphs (atem, 1, otem);
+ have_space_p = otem[0];
+
+ estimate_font_ascii (ft, max_width, min_width, avg_width);
+ *ascent = std::lrint (fheight.ascent);
+ *descent = std::lrint (fheight.descent);
+ *height = *ascent + *descent;
+
+ *space_width = have_space_p ? ft->StringWidth (" ") : 0;
+
+ *px_size = std::lrint (ft->Size ());
+ *underline_position = 0;
+ *underline_thickness = 0;
+}
+
+/* Return non-null if FONT contains CHR, a Unicode code-point. */
+int
+BFont_have_char_p (void *font, int32_t chr)
+{
+ BFont *ft = (BFont *) font;
+ return ft->IncludesBlock (chr, chr);
+}
+
+/* Return non-null if font contains a block from BEG to END. */
+int
+BFont_have_char_block (void *font, int32_t beg, int32_t end)
+{
+ BFont *ft = (BFont *) font;
+ return ft->IncludesBlock (beg, end);
+}
+
+/* Compute bounds for MB_STR, a character in multibyte encoding,
+ used with font. The width (in pixels) is returned in ADVANCE,
+ the left bearing in LB, and the right bearing in RB. */
+void
+BFont_char_bounds (void *font, const char *mb_str, int *advance,
+ int *lb, int *rb)
+{
+ BFont *ft = (BFont *) font;
+ edge_info edge_info;
+ float size, escapement;
+ size = ft->Size ();
+
+ ft->GetEdges (mb_str, 1, &edge_info);
+ ft->GetEscapements (mb_str, 1, &escapement);
+ *advance = std::lrint (escapement * size);
+ *lb = std::lrint (edge_info.left * size);
+ *rb = *advance + std::lrint (edge_info.right * size);
+}
+
+/* The same, but for a variable amount of chars. */
+void
+BFont_nchar_bounds (void *font, const char *mb_str, int *advance,
+ int *lb, int *rb, int32_t n)
+{
+ BFont *ft = (BFont *) font;
+ edge_info edge_info[n];
+ float size;
+ float escapement[n];
+
+ size = ft->Size ();
+
+ ft->GetEdges (mb_str, n, edge_info);
+ ft->GetEscapements (mb_str, n, (float *) escapement);
+
+ for (int32_t i = 0; i < n; ++i)
+ {
+ advance[i] = std::lrint (escapement[i] * size);
+ lb[i] = advance[i] - std::lrint (edge_info[i].left * size);
+ rb[i] = advance[i] + std::lrint (edge_info[i].right * size);
+ }
+}
+
+static void
+font_style_to_flags (char *st, struct haiku_font_pattern *pattern)
+{
+ char *style = strdup (st);
+ char *token;
+ pattern->weight = -1;
+ pattern->width = NO_WIDTH;
+ pattern->slant = NO_SLANT;
+ int tok = 0;
+
+ while ((token = std::strtok (!tok ? style : NULL, " ")) && tok < 3)
+ {
+ if (token && !strcmp (token, "Thin"))
+ pattern->weight = HAIKU_THIN;
+ else if (token && !strcmp (token, "UltraLight"))
+ pattern->weight = HAIKU_ULTRALIGHT;
+ else if (token && !strcmp (token, "ExtraLight"))
+ pattern->weight = HAIKU_EXTRALIGHT;
+ else if (token && !strcmp (token, "Light"))
+ pattern->weight = HAIKU_LIGHT;
+ else if (token && !strcmp (token, "SemiLight"))
+ pattern->weight = HAIKU_SEMI_LIGHT;
+ else if (token && !strcmp (token, "Regular"))
+ {
+ if (pattern->slant == NO_SLANT)
+ pattern->slant = SLANT_REGULAR;
+
+ if (pattern->width == NO_WIDTH)
+ pattern->width = NORMAL_WIDTH;
+
+ if (pattern->weight == -1)
+ pattern->weight = HAIKU_REGULAR;
+ }
+ else if (token && !strcmp (token, "SemiBold"))
+ pattern->weight = HAIKU_SEMI_BOLD;
+ else if (token && !strcmp (token, "Bold"))
+ pattern->weight = HAIKU_BOLD;
+ else if (token && (!strcmp (token, "ExtraBold") ||
+ /* This has actually been seen in the wild. */
+ !strcmp (token, "Extrabold")))
+ pattern->weight = HAIKU_EXTRA_BOLD;
+ else if (token && !strcmp (token, "UltraBold"))
+ pattern->weight = HAIKU_ULTRA_BOLD;
+ else if (token && !strcmp (token, "Book"))
+ pattern->weight = HAIKU_BOOK;
+ else if (token && !strcmp (token, "Heavy"))
+ pattern->weight = HAIKU_HEAVY;
+ else if (token && !strcmp (token, "UltraHeavy"))
+ pattern->weight = HAIKU_ULTRA_HEAVY;
+ else if (token && !strcmp (token, "Black"))
+ pattern->weight = HAIKU_BLACK;
+ else if (token && !strcmp (token, "Medium"))
+ pattern->weight = HAIKU_MEDIUM;
+ else if (token && !strcmp (token, "Oblique"))
+ pattern->slant = SLANT_OBLIQUE;
+ else if (token && !strcmp (token, "Italic"))
+ pattern->slant = SLANT_ITALIC;
+ else if (token && !strcmp (token, "UltraCondensed"))
+ pattern->width = ULTRA_CONDENSED;
+ else if (token && !strcmp (token, "ExtraCondensed"))
+ pattern->width = EXTRA_CONDENSED;
+ else if (token && !strcmp (token, "Condensed"))
+ pattern->width = CONDENSED;
+ else if (token && !strcmp (token, "SemiCondensed"))
+ pattern->width = SEMI_CONDENSED;
+ else if (token && !strcmp (token, "SemiExpanded"))
+ pattern->width = SEMI_EXPANDED;
+ else if (token && !strcmp (token, "Expanded"))
+ pattern->width = EXPANDED;
+ else if (token && !strcmp (token, "ExtraExpanded"))
+ pattern->width = EXTRA_EXPANDED;
+ else if (token && !strcmp (token, "UltraExpanded"))
+ pattern->width = ULTRA_EXPANDED;
+ else
+ {
+ tok = 1000;
+ break;
+ }
+ tok++;
+ }
+
+ if (pattern->weight != -1)
+ pattern->specified |= FSPEC_WEIGHT;
+ if (pattern->slant != NO_SLANT)
+ pattern->specified |= FSPEC_SLANT;
+ if (pattern->width != NO_WIDTH)
+ pattern->specified |= FSPEC_WIDTH;
+
+ if (tok > 3)
+ {
+ pattern->specified &= ~FSPEC_SLANT;
+ pattern->specified &= ~FSPEC_WEIGHT;
+ pattern->specified &= ~FSPEC_WIDTH;
+ pattern->specified |= FSPEC_STYLE;
+ std::strncpy ((char *) &pattern->style, st,
+ sizeof pattern->style - 1);
+ }
+
+ free (style);
+}
+
+static bool
+font_check_wanted_chars (struct haiku_font_pattern *pattern, font_family family,
+ char *style)
+{
+ BFont ft;
+
+ if (ft.SetFamilyAndStyle (family, style) != B_OK)
+ return false;
+
+ for (int i = 0; i < pattern->want_chars_len; ++i)
+ if (!ft.IncludesBlock (pattern->wanted_chars[i],
+ pattern->wanted_chars[i]))
+ return false;
+
+ return true;
+}
+
+static bool
+font_check_one_of (struct haiku_font_pattern *pattern, font_family family,
+ char *style)
+{
+ BFont ft;
+
+ if (ft.SetFamilyAndStyle (family, style) != B_OK)
+ return false;
+
+ for (int i = 0; i < pattern->need_one_of_len; ++i)
+ if (ft.IncludesBlock (pattern->need_one_of[i],
+ pattern->need_one_of[i]))
+ return true;
+
+ return false;
+}
+
+static bool
+font_check_language (struct haiku_font_pattern *pattern, font_family family,
+ char *style)
+{
+ BFont ft;
+
+ if (ft.SetFamilyAndStyle (family, style) != B_OK)
+ return false;
+
+ if (pattern->language == MAX_LANGUAGE)
+ return false;
+
+ for (uint32_t *ch = (uint32_t *)
+ &language_code_points[pattern->language]; *ch; ch++)
+ if (!ft.IncludesBlock (*ch, *ch))
+ return false;
+
+ return true;
+}
+
+static bool
+font_family_style_matches_p (font_family family, char *style, uint32_t flags,
+ struct haiku_font_pattern *pattern,
+ int ignore_flags_p = 0)
+{
+ struct haiku_font_pattern m;
+ m.specified = 0;
+
+ if (style)
+ font_style_to_flags (style, &m);
+
+ if ((pattern->specified & FSPEC_FAMILY) &&
+ strcmp ((char *) &pattern->family, family))
+ return false;
+
+ if (!ignore_flags_p && (pattern->specified & FSPEC_SPACING) &&
+ !(pattern->mono_spacing_p) != !(flags & B_IS_FIXED))
+ return false;
+
+ if (pattern->specified & FSPEC_STYLE)
+ return style && !strcmp (style, pattern->style);
+
+ if ((pattern->specified & FSPEC_WEIGHT)
+ && (pattern->weight
+ != ((m.specified & FSPEC_WEIGHT) ? m.weight : HAIKU_REGULAR)))
+ return false;
+
+ if ((pattern->specified & FSPEC_SLANT)
+ && (pattern->slant
+ != ((m.specified & FSPEC_SLANT) ? m.slant : SLANT_REGULAR)))
+ return false;
+
+ if ((pattern->specified & FSPEC_WANTED)
+ && !font_check_wanted_chars (pattern, family, style))
+ return false;
+
+ if ((pattern->specified & FSPEC_WIDTH)
+ && (pattern->width !=
+ ((m.specified & FSPEC_WIDTH) ? m.width : NORMAL_WIDTH)))
+ return false;
+
+ if ((pattern->specified & FSPEC_NEED_ONE_OF)
+ && !font_check_one_of (pattern, family, style))
+ return false;
+
+ if ((pattern->specified & FSPEC_LANGUAGE)
+ && !font_check_language (pattern, family, style))
+ return false;
+
+ return true;
+}
+
+static void
+haiku_font_fill_pattern (struct haiku_font_pattern *pattern,
+ font_family family, char *style,
+ uint32_t flags)
+{
+ if (style)
+ font_style_to_flags (style, pattern);
+
+ pattern->specified |= FSPEC_FAMILY;
+ std::strncpy (pattern->family, family,
+ sizeof pattern->family - 1);
+ pattern->specified |= FSPEC_SPACING;
+ pattern->mono_spacing_p = flags & B_IS_FIXED;
+}
+
+/* Delete every element of the font pattern PT. */
+void
+haiku_font_pattern_free (struct haiku_font_pattern *pt)
+{
+ struct haiku_font_pattern *tem = pt;
+ while (tem)
+ {
+ struct haiku_font_pattern *t = tem;
+ tem = t->next;
+ delete t;
+ }
+}
+
+/* Find all fonts matching the font pattern PT. */
+struct haiku_font_pattern *
+BFont_find (struct haiku_font_pattern *pt)
+{
+ struct haiku_font_pattern *r = NULL;
+ font_family name;
+ font_style sname;
+ uint32 flags;
+ int sty_count;
+ int fam_count = count_font_families ();
+
+ for (int fi = 0; fi < fam_count; ++fi)
+ {
+ if (get_font_family (fi, &name, &flags) == B_OK)
+ {
+ sty_count = count_font_styles (name);
+ if (!sty_count &&
+ font_family_style_matches_p (name, NULL, flags, pt))
+ {
+ struct haiku_font_pattern *p = new struct haiku_font_pattern;
+ p->specified = 0;
+ p->oblique_seen_p = 1;
+ haiku_font_fill_pattern (p, name, NULL, flags);
+ p->next = r;
+ if (p->next)
+ p->next->last = p;
+ p->last = NULL;
+ p->next_family = r;
+ r = p;
+ }
+ else if (sty_count)
+ {
+ for (int si = 0; si < sty_count; ++si)
+ {
+ int oblique_seen_p = 0;
+ struct haiku_font_pattern *head = r;
+ struct haiku_font_pattern *p = NULL;
+
+ if (get_font_style (name, si, &sname, &flags) == B_OK)
+ {
+ if (font_family_style_matches_p (name, (char *) &sname, flags, pt))
+ {
+ p = new struct haiku_font_pattern;
+ p->specified = 0;
+ haiku_font_fill_pattern (p, name, (char *) &sname, flags);
+ if (p->specified & FSPEC_SLANT &&
+ ((p->slant == SLANT_OBLIQUE) || (p->slant == SLANT_ITALIC)))
+ oblique_seen_p = 1;
+
+ p->next = r;
+ if (p->next)
+ p->next->last = p;
+ r = p;
+ p->next_family = head;
+ }
+ }
+
+ if (p)
+ p->last = NULL;
+
+ for (; head; head = head->last)
+ {
+ head->oblique_seen_p = oblique_seen_p;
+ }
+ }
+ }
+ }
+ }
+
+ /* There's a very good chance that this result will get cached if no
+ slant is specified. Thus, we look through each font that hasn't
+ seen an oblique style, and add one. */
+
+ if (!(pt->specified & FSPEC_SLANT))
+ {
+ /* r->last is invalid from here onwards. */
+ for (struct haiku_font_pattern *p = r; p;)
+ {
+ if (!p->oblique_seen_p)
+ {
+ struct haiku_font_pattern *n = new haiku_font_pattern;
+ *n = *p;
+ n->slant = SLANT_OBLIQUE;
+ p->next = n;
+ p = p->next_family;
+ }
+ else
+ p = p->next_family;
+ }
+ }
+
+ return r;
+}
+
+/* Find and open a font matching the pattern PAT, which must have its
+ family set. */
+int
+BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size)
+{
+ int sty_count;
+ font_family name;
+ font_style sname;
+ uint32 flags = 0;
+ if (!(pat->specified & FSPEC_FAMILY))
+ return 1;
+ strncpy (name, pat->family, sizeof name - 1);
+ sty_count = count_font_styles (name);
+
+ if (!sty_count &&
+ font_family_style_matches_p (name, NULL, flags, pat, 1))
+ {
+ BFont *ft = new BFont;
+ if (ft->SetFamilyAndStyle (name, NULL) != B_OK)
+ {
+ delete ft;
+ return 1;
+ }
+ ft->SetSize (size);
+ ft->SetEncoding (B_UNICODE_UTF8);
+ ft->SetSpacing (B_BITMAP_SPACING);
+ *font = (void *) ft;
+ return 0;
+ }
+ else if (sty_count)
+ {
+ for (int si = 0; si < sty_count; ++si)
+ {
+ if (get_font_style (name, si, &sname, &flags) == B_OK &&
+ font_family_style_matches_p (name, (char *) &sname, flags, pat))
+ {
+ BFont *ft = new BFont;
+ if (ft->SetFamilyAndStyle (name, sname) != B_OK)
+ {
+ delete ft;
+ return 1;
+ }
+ ft->SetSize (size);
+ ft->SetEncoding (B_UNICODE_UTF8);
+ ft->SetSpacing (B_BITMAP_SPACING);
+ *font = (void *) ft;
+ return 0;
+ }
+ }
+ }
+
+ if (pat->specified & FSPEC_SLANT && pat->slant == SLANT_OBLIQUE)
+ {
+ struct haiku_font_pattern copy = *pat;
+ copy.slant = SLANT_REGULAR;
+ int code = BFont_open_pattern (©, font, size);
+ if (code)
+ return code;
+ BFont *ft = (BFont *) *font;
+ /* XXX Font measurements don't respect shear. Haiku bug?
+ This apparently worked in BeOS.
+ ft->SetShear (100.0); */
+ ft->SetFace (B_ITALIC_FACE);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Query the family of the default fixed font. */
+void
+BFont_populate_fixed_family (struct haiku_font_pattern *ptn)
+{
+ font_family f;
+ font_style s;
+ be_fixed_font->GetFamilyAndStyle (&f, &s);
+
+ ptn->specified |= FSPEC_FAMILY;
+ strncpy (ptn->family, f, sizeof ptn->family - 1);
+}
+
+void
+BFont_populate_plain_family (struct haiku_font_pattern *ptn)
+{
+ font_family f;
+ font_style s;
+ be_plain_font->GetFamilyAndStyle (&f, &s);
+
+ ptn->specified |= FSPEC_FAMILY;
+ strncpy (ptn->family, f, sizeof ptn->family - 1);
+}
+
+int
+BFont_string_width (void *font, const char *utf8)
+{
+ return ((BFont *) font)->StringWidth (utf8);
+}
diff --git a/src/haiku_io.c b/src/haiku_io.c
new file mode 100644
index 0000000000..c152d9b086
--- /dev/null
+++ b/src/haiku_io.c
@@ -0,0 +1,207 @@
+/* Haiku window system support.
+ 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 <signal.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <OS.h>
+
+#include "haiku_support.h"
+#include "lisp.h"
+#include "haikuterm.h"
+#include "blockinput.h"
+
+#define PORT_CAP 1200
+
+/* The port used to send messages from the application thread to
+ Emacs. */
+port_id port_application_to_emacs;
+
+void
+haiku_io_init (void)
+{
+ port_application_to_emacs = create_port (PORT_CAP, "application emacs port");
+}
+
+static ssize_t
+haiku_len (enum haiku_event_type type)
+{
+ switch (type)
+ {
+ case QUIT_REQUESTED:
+ return sizeof (struct haiku_quit_requested_event);
+ case FRAME_RESIZED:
+ return sizeof (struct haiku_resize_event);
+ case FRAME_EXPOSED:
+ return sizeof (struct haiku_expose_event);
+ case KEY_DOWN:
+ case KEY_UP:
+ return sizeof (struct haiku_key_event);
+ case ACTIVATION:
+ return sizeof (struct haiku_activation_event);
+ case MOUSE_MOTION:
+ return sizeof (struct haiku_mouse_motion_event);
+ case BUTTON_DOWN:
+ case BUTTON_UP:
+ return sizeof (struct haiku_button_event);
+ case ICONIFICATION:
+ return sizeof (struct haiku_iconification_event);
+ case MOVE_EVENT:
+ return sizeof (struct haiku_move_event);
+ case SCROLL_BAR_VALUE_EVENT:
+ return sizeof (struct haiku_scroll_bar_value_event);
+ case SCROLL_BAR_DRAG_EVENT:
+ return sizeof (struct haiku_scroll_bar_drag_event);
+ case WHEEL_MOVE_EVENT:
+ return sizeof (struct haiku_wheel_move_event);
+ case MENU_BAR_RESIZE:
+ return sizeof (struct haiku_menu_bar_resize_event);
+ case MENU_BAR_OPEN:
+ case MENU_BAR_CLOSE:
+ return sizeof (struct haiku_menu_bar_state_event);
+ case MENU_BAR_SELECT_EVENT:
+ return sizeof (struct haiku_menu_bar_select_event);
+ case FILE_PANEL_EVENT:
+ return sizeof (struct haiku_file_panel_event);
+ case MENU_BAR_HELP_EVENT:
+ return sizeof (struct haiku_menu_bar_help_event);
+ case ZOOM_EVENT:
+ return sizeof (struct haiku_zoom_event);
+ case REFS_EVENT:
+ return sizeof (struct haiku_refs_event);
+ case APP_QUIT_REQUESTED_EVENT:
+ return sizeof (struct haiku_app_quit_requested_event);
+ }
+
+ emacs_abort ();
+}
+
+/* Read the size of the next message into len, returning -1 if the
+ query fails or there is no next message. */
+void
+haiku_read_size (ssize_t *len)
+{
+ port_id from = port_application_to_emacs;
+ ssize_t size;
+
+ size = port_buffer_size_etc (from, B_TIMEOUT, 0);
+
+ if (size < B_OK)
+ *len = -1;
+ else
+ *len = size;
+}
+
+/* Read the next message into BUF, putting its type into TYPE,
+ assuming the message is at most LEN long. Return 0 if successful
+ and -1 if the read fails. */
+int
+haiku_read (enum haiku_event_type *type, void *buf, ssize_t len)
+{
+ int32 typ;
+ port_id from = port_application_to_emacs;
+
+ if (read_port (from, &typ, buf, len) < B_OK)
+ return -1;
+
+ *type = (enum haiku_event_type) typ;
+ eassert (len >= haiku_len (typ));
+ return 0;
+}
+
+/* The same as haiku_read, but time out after TIMEOUT microseconds.
+ Input is blocked when an attempt to read is in progress. */
+int
+haiku_read_with_timeout (enum haiku_event_type *type, void *buf, ssize_t len,
+ time_t timeout)
+{
+ int32 typ;
+ port_id from = port_application_to_emacs;
+
+ block_input ();
+ if (read_port_etc (from, &typ, buf, len,
+ B_TIMEOUT, (bigtime_t) timeout) < B_OK)
+ {
+ unblock_input ();
+ return -1;
+ }
+ unblock_input ();
+ *type = (enum haiku_event_type) typ;
+ eassert (len >= haiku_len (typ));
+ return 0;
+}
+
+/* Write a message with type TYPE into BUF. */
+int
+haiku_write (enum haiku_event_type type, void *buf)
+{
+ port_id to = port_application_to_emacs;
+
+ if (write_port (to, (int32_t) type, buf, haiku_len (type)) < B_OK)
+ return -1;
+
+ kill (getpid (), SIGPOLL);
+
+ return 0;
+}
+
+int
+haiku_write_without_signal (enum haiku_event_type type, void *buf)
+{
+ port_id to = port_application_to_emacs;
+
+ if (write_port (to, (int32_t) type, buf, haiku_len (type)) < B_OK)
+ return -1;
+
+ return 0;
+}
+
+void
+haiku_io_init_in_app_thread (void)
+{
+ sigset_t set;
+ sigfillset (&set);
+
+ if (pthread_sigmask (SIG_BLOCK, &set, NULL))
+ perror ("pthread_sigmask");
+}
+
+/* Record an unwind protect from C++ code. */
+void
+record_c_unwind_protect_from_cxx (void (*fn) (void *), void *r)
+{
+ record_unwind_protect_ptr (fn, r);
+}
+
+/* SPECPDL_IDX that is safe from C++ code. */
+ptrdiff_t
+c_specpdl_idx_from_cxx (void)
+{
+ return SPECPDL_INDEX ();
+}
+
+/* unbind_to (IDX, Qnil), but safe from C++ code. */
+void
+c_unbind_to_nil_from_cxx (ptrdiff_t idx)
+{
+ unbind_to (idx, Qnil);
+}
diff --git a/src/haiku_select.cc b/src/haiku_select.cc
new file mode 100644
index 0000000000..8d345ca661
--- /dev/null
+++ b/src/haiku_select.cc
@@ -0,0 +1,155 @@
+/* Haiku window system selection 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 <Clipboard.h>
+
+#include <cstdlib>
+#include <cstring>
+
+#include "haikuselect.h"
+
+
+static BClipboard *primary = NULL;
+static BClipboard *secondary = NULL;
+static BClipboard *system_clipboard = NULL;
+
+int selection_state_flag;
+
+static char *
+BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len)
+{
+ if (!cb->Lock ())
+ return 0;
+
+ BMessage *dat = cb->Data ();
+ if (!dat)
+ {
+ cb->Unlock ();
+ return 0;
+ }
+
+ const char *ptr;
+ ssize_t bt;
+ dat->FindData (type, B_MIME_TYPE, (const void **) &ptr, &bt);
+
+ if (!ptr)
+ {
+ cb->Unlock ();
+ return NULL;
+ }
+
+ if (len)
+ *len = bt;
+
+ cb->Unlock ();
+
+ return strndup (ptr, bt);
+}
+
+static void
+BClipboard_set_data (BClipboard *cb, const char *type, const char *dat,
+ ssize_t len)
+{
+ if (!cb->Lock ())
+ return;
+ cb->Clear ();
+ BMessage *mdat = cb->Data ();
+ if (!mdat)
+ {
+ cb->Unlock ();
+ return;
+ }
+
+ if (dat)
+ mdat->AddData (type, B_MIME_TYPE, dat, len);
+ cb->Commit ();
+ cb->Unlock ();
+}
+
+char *
+BClipboard_find_system_data (const char *type, ssize_t *len)
+{
+ if (!system_clipboard)
+ return 0;
+
+ return BClipboard_find_data (system_clipboard, type, len);
+}
+
+char *
+BClipboard_find_primary_selection_data (const char *type, ssize_t *len)
+{
+ if (!primary)
+ return 0;
+
+ return BClipboard_find_data (primary, type, len);
+}
+
+char *
+BClipboard_find_secondary_selection_data (const char *type, ssize_t *len)
+{
+ if (!secondary)
+ return 0;
+
+ return BClipboard_find_data (secondary, type, len);
+}
+
+void
+BClipboard_set_system_data (const char *type, const char *data,
+ ssize_t len)
+{
+ if (!system_clipboard)
+ return;
+
+ BClipboard_set_data (system_clipboard, type, data, len);
+}
+
+void
+BClipboard_set_primary_selection_data (const char *type, const char *data,
+ ssize_t len)
+{
+ if (!primary)
+ return;
+
+ BClipboard_set_data (primary, type, data, len);
+}
+
+void
+BClipboard_set_secondary_selection_data (const char *type, const char *data,
+ ssize_t len)
+{
+ if (!secondary)
+ return;
+
+ BClipboard_set_data (secondary, type, data, len);
+}
+
+void
+BClipboard_free_data (void *ptr)
+{
+ std::free (ptr);
+}
+
+void
+init_haiku_select (void)
+{
+ system_clipboard = new BClipboard ("system");
+ primary = new BClipboard ("primary");
+ secondary = new BClipboard ("secondary");
+}
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
new file mode 100644
index 0000000000..99d4ee7914
--- /dev/null
+++ b/src/haiku_support.cc
@@ -0,0 +1,2930 @@
+/* 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 * 10;
+ rq.delta_y = dy * 10;
+
+ 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;
+
+ 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 ();
+}
diff --git a/src/haiku_support.h b/src/haiku_support.h
new file mode 100644
index 0000000000..9f5f3c77e3
--- /dev/null
+++ b/src/haiku_support.h
@@ -0,0 +1,869 @@
+/* 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/>. */
+
+#ifndef _HAIKU_SUPPORT_H
+#define _HAIKU_SUPPORT_H
+
+#include <stdint.h>
+
+#ifdef HAVE_FREETYPE
+#include <ft2build.h>
+#include <fontconfig/fontconfig.h>
+#include FT_FREETYPE_H
+#include FT_SIZES_H
+#endif
+
+#ifdef USE_BE_CAIRO
+#include <cairo.h>
+#endif
+
+enum haiku_cursor
+ {
+ CURSOR_ID_NO_CURSOR = 12,
+ CURSOR_ID_RESIZE_NORTH = 15,
+ CURSOR_ID_RESIZE_EAST = 16,
+ CURSOR_ID_RESIZE_SOUTH = 17,
+ CURSOR_ID_RESIZE_WEST = 18,
+ CURSOR_ID_RESIZE_NORTH_EAST = 19,
+ CURSOR_ID_RESIZE_NORTH_WEST = 20,
+ CURSOR_ID_RESIZE_SOUTH_EAST = 21,
+ CURSOR_ID_RESIZE_SOUTH_WEST = 22,
+ CURSOR_ID_RESIZE_NORTH_SOUTH = 23,
+ CURSOR_ID_RESIZE_EAST_WEST = 24,
+ CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST = 25,
+ CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST = 26
+ };
+
+enum haiku_alert_type
+ {
+ HAIKU_EMPTY_ALERT = 0,
+ HAIKU_INFO_ALERT,
+ HAIKU_IDEA_ALERT,
+ HAIKU_WARNING_ALERT,
+ HAIKU_STOP_ALERT
+ };
+
+enum haiku_event_type
+ {
+ QUIT_REQUESTED,
+ FRAME_RESIZED,
+ FRAME_EXPOSED,
+ KEY_DOWN,
+ KEY_UP,
+ ACTIVATION,
+ MOUSE_MOTION,
+ BUTTON_DOWN,
+ BUTTON_UP,
+ ICONIFICATION,
+ MOVE_EVENT,
+ SCROLL_BAR_VALUE_EVENT,
+ SCROLL_BAR_DRAG_EVENT,
+ WHEEL_MOVE_EVENT,
+ MENU_BAR_RESIZE,
+ MENU_BAR_OPEN,
+ MENU_BAR_SELECT_EVENT,
+ MENU_BAR_CLOSE,
+ FILE_PANEL_EVENT,
+ MENU_BAR_HELP_EVENT,
+ ZOOM_EVENT,
+ REFS_EVENT,
+ APP_QUIT_REQUESTED_EVENT
+ };
+
+struct haiku_quit_requested_event
+{
+ void *window;
+};
+
+struct haiku_resize_event
+{
+ void *window;
+ float px_heightf;
+ float px_widthf;
+};
+
+struct haiku_expose_event
+{
+ void *window;
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+struct haiku_refs_event
+{
+ void *window;
+ int x, y;
+ /* Free this with free! */
+ char *ref;
+};
+
+struct haiku_app_quit_requested_event
+{
+ char dummy;
+};
+
+#define HAIKU_MODIFIER_ALT (1)
+#define HAIKU_MODIFIER_CTRL (1 << 1)
+#define HAIKU_MODIFIER_SHIFT (1 << 2)
+#define HAIKU_MODIFIER_SUPER (1 << 3)
+
+struct haiku_key_event
+{
+ void *window;
+ int modifiers;
+ uint32_t mb_char;
+ uint32_t unraw_mb_char;
+ short kc;
+};
+
+struct haiku_activation_event
+{
+ void *window;
+ int activated_p;
+};
+
+struct haiku_mouse_motion_event
+{
+ void *window;
+ bool just_exited_p;
+ int x;
+ int y;
+ uint32_t be_code;
+};
+
+struct haiku_button_event
+{
+ void *window;
+ int btn_no;
+ int modifiers;
+ int x;
+ int y;
+};
+
+struct haiku_iconification_event
+{
+ void *window;
+ int iconified_p;
+};
+
+struct haiku_move_event
+{
+ void *window;
+ int x;
+ int y;
+};
+
+struct haiku_wheel_move_event
+{
+ void *window;
+ int modifiers;
+ float delta_x;
+ float delta_y;
+};
+
+struct haiku_menu_bar_select_event
+{
+ void *window;
+ void *ptr;
+};
+
+struct haiku_file_panel_event
+{
+ void *ptr;
+};
+
+struct haiku_menu_bar_help_event
+{
+ void *window;
+ int mb_idx;
+};
+
+struct haiku_zoom_event
+{
+ void *window;
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+#define FSPEC_FAMILY 1
+#define FSPEC_STYLE (1 << 1)
+#define FSPEC_SLANT (1 << 2)
+#define FSPEC_WEIGHT (1 << 3)
+#define FSPEC_SPACING (1 << 4)
+#define FSPEC_WANTED (1 << 5)
+#define FSPEC_NEED_ONE_OF (1 << 6)
+#define FSPEC_WIDTH (1 << 7)
+#define FSPEC_LANGUAGE (1 << 8)
+
+typedef char haiku_font_family_or_style[64];
+
+enum haiku_font_slant
+ {
+ NO_SLANT = -1,
+ SLANT_OBLIQUE,
+ SLANT_REGULAR,
+ SLANT_ITALIC
+ };
+
+enum haiku_font_width
+ {
+ NO_WIDTH = -1,
+ ULTRA_CONDENSED,
+ EXTRA_CONDENSED,
+ CONDENSED,
+ SEMI_CONDENSED,
+ NORMAL_WIDTH,
+ SEMI_EXPANDED,
+ EXPANDED,
+ EXTRA_EXPANDED,
+ ULTRA_EXPANDED
+ };
+
+enum haiku_font_language
+ {
+ LANGUAGE_CN,
+ LANGUAGE_KO,
+ LANGUAGE_JP,
+ MAX_LANGUAGE /* This isn't a language. */
+ };
+
+struct haiku_font_pattern
+{
+ int specified;
+ struct haiku_font_pattern *next;
+ /* The next two fields are only temporarily used during the font
+ discovery process! Do not rely on them being correct outside
+ BFont_find. */
+ struct haiku_font_pattern *last;
+ struct haiku_font_pattern *next_family;
+ haiku_font_family_or_style family;
+ haiku_font_family_or_style style;
+ int weight;
+ int mono_spacing_p;
+ int want_chars_len;
+ int need_one_of_len;
+ enum haiku_font_slant slant;
+ enum haiku_font_width width;
+ enum haiku_font_language language;
+ uint32_t *wanted_chars;
+ uint32_t *need_one_of;
+
+ int oblique_seen_p;
+};
+
+struct haiku_scroll_bar_value_event
+{
+ void *scroll_bar;
+ int position;
+};
+
+struct haiku_scroll_bar_drag_event
+{
+ void *scroll_bar;
+ int dragging_p;
+};
+
+struct haiku_menu_bar_resize_event
+{
+ void *window;
+ int width;
+ int height;
+};
+
+struct haiku_menu_bar_state_event
+{
+ void *window;
+};
+
+#define HAIKU_THIN 0
+#define HAIKU_ULTRALIGHT 20
+#define HAIKU_EXTRALIGHT 40
+#define HAIKU_LIGHT 50
+#define HAIKU_SEMI_LIGHT 75
+#define HAIKU_REGULAR 100
+#define HAIKU_SEMI_BOLD 180
+#define HAIKU_BOLD 200
+#define HAIKU_EXTRA_BOLD 205
+#define HAIKU_ULTRA_BOLD 210
+#define HAIKU_BOOK 400
+#define HAIKU_HEAVY 800
+#define HAIKU_ULTRA_HEAVY 900
+#define HAIKU_BLACK 1000
+#define HAIKU_MEDIUM 2000
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include <pthread.h>
+#include <OS.h>
+
+#ifdef __cplusplus
+ typedef void *haiku;
+
+ extern void
+ haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel);
+
+ extern unsigned long
+ haiku_get_pixel (haiku bitmap, int x, int y);
+#endif
+
+ extern port_id port_application_to_emacs;
+
+ extern void haiku_io_init (void);
+ extern void haiku_io_init_in_app_thread (void);
+
+ extern void
+ haiku_read_size (ssize_t *len);
+
+ extern int
+ haiku_read (enum haiku_event_type *type, void *buf, ssize_t len);
+
+ extern int
+ haiku_read_with_timeout (enum haiku_event_type *type, void *buf, ssize_t len,
+ time_t timeout);
+
+ extern int
+ haiku_write (enum haiku_event_type type, void *buf);
+
+ extern int
+ haiku_write_without_signal (enum haiku_event_type type, void *buf);
+
+ extern void
+ rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l);
+
+ extern void
+ hsl_color_rgb (double h, double s, double l, uint32_t *rgb);
+
+ extern void *
+ BBitmap_new (int width, int height, int mono_p);
+
+ extern void *
+ BBitmap_data (void *bitmap);
+
+ extern int
+ BBitmap_convert (void *bitmap, void **new_bitmap);
+
+ extern void
+ BBitmap_free (void *bitmap);
+
+ extern void
+ BBitmap_dimensions (void *bitmap, int *left, int *top,
+ int *right, int *bottom, int32_t *bytes_per_row,
+ int *mono_p);
+
+ extern void *
+ BApplication_setup (void);
+
+ extern void *
+ BWindow_new (void *view);
+
+ extern void
+ BWindow_quit (void *window);
+
+ extern void
+ BWindow_set_offset (void *window, int x, int y);
+
+ extern void
+ BWindow_iconify (void *window);
+
+ extern void
+ BWindow_set_visible (void *window, int visible_p);
+
+ extern void
+ BFont_close (void *font);
+
+ extern void
+ BFont_dat (void *font, int *px_size, int *min_width, int *max_width,
+ int *avg_width, int *height, int *space_width, int *ascent,
+ int *descent, int *underline_position, int *underline_thickness);
+
+ extern int
+ BFont_have_char_p (void *font, int32_t chr);
+
+ extern int
+ BFont_have_char_block (void *font, int32_t beg, int32_t end);
+
+ extern void
+ BFont_char_bounds (void *font, const char *mb_str, int *advance,
+ int *lb, int *rb);
+
+ extern void
+ BFont_nchar_bounds (void *font, const char *mb_str, int *advance,
+ int *lb, int *rb, int32_t n);
+
+ extern void
+ BWindow_retitle (void *window, const char *title);
+
+ extern void
+ BWindow_resize (void *window, int width, int height);
+
+ extern void
+ BWindow_activate (void *window);
+
+ extern void
+ BView_StartClip (void *view);
+
+ extern void
+ BView_EndClip (void *view);
+
+ extern void
+ BView_SetHighColor (void *view, uint32_t color);
+
+ extern void
+ BView_SetHighColorForVisibleBell (void *view, uint32_t color);
+
+ extern void
+ BView_FillRectangleForVisibleBell (void *view, int x, int y, int width,
+ int height);
+
+ extern void
+ BView_SetLowColor (void *view, uint32_t color);
+
+ extern void
+ BView_SetPenSize (void *view, int u);
+
+ extern void
+ BView_SetFont (void *view, void *font);
+
+ extern void
+ BView_MovePenTo (void *view, int x, int y);
+
+ extern void
+ BView_DrawString (void *view, const char *chr, ptrdiff_t len);
+
+ extern void
+ BView_DrawChar (void *view, char chr);
+
+ extern void
+ BView_FillRectangle (void *view, int x, int y, int width, int height);
+
+ extern void
+ BView_FillRectangleAbs (void *view, int x, int y, int x1, int y1);
+
+ extern void
+ BView_FillTriangle (void *view, int x1, int y1,
+ int x2, int y2, int x3, int y3);
+
+ extern void
+ BView_StrokeRectangle (void *view, int x, int y, int width, int height);
+
+ extern void
+ BView_SetViewColor (void *view, uint32_t color);
+
+ extern void
+ BView_ClipToRect (void *view, int x, int y, int width, int height);
+
+ extern void
+ BView_ClipToInverseRect (void *view, int x, int y, int width, int height);
+
+ extern void
+ BView_StrokeLine (void *view, int sx, int sy, int tx, int ty);
+
+ extern void
+ BView_CopyBits (void *view, int x, int y, int width, int height,
+ int tox, int toy, int towidth, int toheight);
+
+ extern void
+ BView_DrawBitmap (void *view, void *bitmap, int x, int y,
+ int width, int height, int vx, int vy, int vwidth,
+ int vheight);
+
+ extern void
+ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
+ int y, int width, int height);
+
+ extern void
+ BView_DrawMask (void *src, void *view,
+ int x, int y, int width, int height,
+ int vx, int vy, int vwidth, int vheight,
+ uint32_t color);
+
+ extern void *
+ BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color,
+ double rot, int desw, int desh);
+
+ extern void
+ BScreen_px_dim (int *width, int *height);
+
+ extern void
+ BView_resize_to (void *view, int width, int height);
+
+ /* Functions for creating and freeing cursors. */
+ extern void *
+ BCursor_create_default (void);
+
+ extern void *
+ BCursor_from_id (enum haiku_cursor cursor);
+
+ extern void *
+ BCursor_create_modeline (void);
+
+ extern void *
+ BCursor_create_i_beam (void);
+
+ extern void *
+ BCursor_create_progress_cursor (void);
+
+ extern void *
+ BCursor_create_grab (void);
+
+ extern void
+ BCursor_delete (void *cursor);
+
+ extern void
+ BView_set_view_cursor (void *view, void *cursor);
+
+ extern void
+ BWindow_Flush (void *window);
+
+ extern void
+ BMapKey (uint32_t kc, int *non_ascii_p, unsigned *code);
+
+ extern void *
+ BScrollBar_make_for_view (void *view, int horizontal_p,
+ int x, int y, int x1, int y1,
+ void *scroll_bar_ptr);
+
+ extern void
+ BScrollBar_delete (void *sb);
+
+ extern void
+ BView_move_frame (void *view, int x, int y, int x1, int y1);
+
+ extern void
+ BView_scroll_bar_update (void *sb, int portion, int whole, int position);
+
+ extern int
+ BScrollBar_default_size (int horizontal_p);
+
+ extern void
+ BView_invalidate (void *view);
+
+ extern void
+ BView_draw_lock (void *view);
+
+ extern void
+ BView_draw_unlock (void *view);
+
+ extern void
+ BWindow_center_on_screen (void *window);
+
+ extern void
+ BView_mouse_moved (void *view, int x, int y, uint32_t transit);
+
+ extern void
+ BView_mouse_down (void *view, int x, int y);
+
+ extern void
+ BView_mouse_up (void *view, int x, int y);
+
+ extern void
+ BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h);
+
+ extern void
+ haiku_font_pattern_free (struct haiku_font_pattern *pt);
+
+ extern struct haiku_font_pattern *
+ BFont_find (struct haiku_font_pattern *pt);
+
+ extern int
+ BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size);
+
+ extern void
+ BFont_populate_fixed_family (struct haiku_font_pattern *ptn);
+
+ extern void
+ BFont_populate_plain_family (struct haiku_font_pattern *ptn);
+
+ extern void
+ BView_publish_scroll_bar (void *view, int x, int y, int width, int height);
+
+ extern void
+ BView_forget_scroll_bar (void *view, int x, int y, int width, int height);
+
+ extern void
+ BView_get_mouse (void *view, int *x, int *y);
+
+ extern void
+ BView_convert_to_screen (void *view, int *x, int *y);
+
+ extern void
+ BView_convert_from_screen (void *view, int *x, int *y);
+
+ extern void
+ BWindow_change_decoration (void *window, int decorate_p);
+
+ extern void
+ BWindow_set_tooltip_decoration (void *window);
+
+ extern void
+ BWindow_set_avoid_focus (void *window, int avoid_focus_p);
+
+ extern void
+ BView_emacs_delete (void *view);
+
+ extern uint32_t
+ haiku_current_workspace (void);
+
+ extern uint32_t
+ BWindow_workspaces (void *window);
+
+ extern void *
+ BPopUpMenu_new (const char *name);
+
+ extern 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);
+
+ extern void
+ BMenu_add_separator (void *menu);
+
+ extern void *
+ BMenu_new_submenu (void *menu, const char *label, bool enabled_p);
+
+ extern void *
+ BMenu_new_menu_bar_submenu (void *menu, const char *label);
+
+ extern int
+ BMenu_count_items (void *menu);
+
+ extern void *
+ BMenu_item_at (void *menu, int idx);
+
+ extern void *
+ BMenu_run (void *menu, int x, int y);
+
+ extern void
+ BPopUpMenu_delete (void *menu);
+
+ extern void *
+ BMenuBar_new (void *view);
+
+ extern void
+ BMenu_delete_all (void *menu);
+
+ extern void
+ BMenuBar_delete (void *menubar);
+
+ extern void
+ BMenu_item_set_label (void *item, const char *label);
+
+ extern void *
+ BMenu_item_get_menu (void *item);
+
+ extern void
+ BMenu_delete_from (void *menu, int start, int count);
+
+ extern void
+ haiku_ring_bell (void);
+
+ extern void *
+ BAlert_new (const char *text, enum haiku_alert_type type);
+
+ extern void *
+ BAlert_add_button (void *alert, const char *text);
+
+ extern int32_t
+ BAlert_go (void *alert);
+
+ extern void
+ BButton_set_enabled (void *button, int enabled_p);
+
+ extern void
+ BView_set_tooltip (void *view, const char *tooltip);
+
+ extern void
+ BAlert_delete (void *alert);
+
+ extern void
+ BScreen_res (double *rrsx, double *rrsy);
+
+ extern void
+ EmacsWindow_parent_to (void *window, void *other_window);
+
+ extern void
+ EmacsWindow_unparent (void *window);
+
+ extern int
+ BFont_string_width (void *font, const char *utf8);
+
+ extern void
+ be_get_version_string (char *version, int len);
+
+ extern int
+ be_get_display_planes (void);
+
+ extern int
+ be_get_display_color_cells (void);
+
+ extern void
+ be_warp_pointer (int x, int y);
+
+ extern void
+ EmacsWindow_move_weak_child (void *window, void *child, int xoff, int yoff);
+
+ extern void
+ EmacsView_set_up_double_buffering (void *vw);
+
+ extern void
+ EmacsView_disable_double_buffering (void *vw);
+
+ extern void
+ EmacsView_flip_and_blit (void *vw);
+
+ extern int
+ EmacsView_double_buffered_p (void *vw);
+
+ extern 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));
+
+ extern void
+ record_c_unwind_protect_from_cxx (void (*) (void *), void *);
+
+ extern ptrdiff_t
+ c_specpdl_idx_from_cxx (void);
+
+ extern void
+ c_unbind_to_nil_from_cxx (ptrdiff_t idx);
+
+ extern void
+ EmacsView_do_visible_bell (void *view, uint32_t color);
+
+ extern void
+ BWindow_zoom (void *window);
+
+ extern void
+ EmacsWindow_make_fullscreen (void *window, int fullscreen_p);
+
+ extern void
+ EmacsWindow_unzoom (void *window);
+
+#ifdef HAVE_NATIVE_IMAGE_API
+ extern int
+ be_can_translate_type_to_bitmap_p (const char *mime);
+
+ extern void *
+ be_translate_bitmap_from_file_name (const char *filename);
+
+ extern void *
+ be_translate_bitmap_from_memory (const void *buf, size_t bytes);
+#endif
+
+ extern void
+ BMenuBar_start_tracking (void *mbar);
+
+ extern size_t
+ BBitmap_bytes_length (void *bitmap);
+
+ extern void
+ BView_show_tooltip (void *view);
+
+#ifdef USE_BE_CAIRO
+ extern cairo_surface_t *
+ EmacsView_cairo_surface (void *view);
+
+ extern void
+ BView_cr_dump_clipping (void *view, cairo_t *ctx);
+
+ extern void
+ EmacsWindow_begin_cr_critical_section (void *window);
+
+ extern void
+ EmacsWindow_end_cr_critical_section (void *window);
+#endif
+
+ extern void
+ BView_set_and_show_sticky_tooltip (void *view, const char *tooltip,
+ int x, int y);
+
+ extern void
+ BMenu_add_title (void *menu, const char *text);
+
+ extern int
+ be_plain_font_height (void);
+
+ extern int
+ be_string_width_with_plain_font (const char *str);
+
+ extern int
+ be_get_display_screens (void);
+
+ extern void
+ BWindow_set_min_size (void *window, int width, int height);
+
+ extern void
+ BWindow_set_size_alignment (void *window, int align_width, int align_height);
+
+#ifdef __cplusplus
+ extern void *
+ find_appropriate_view_for_draw (void *vw);
+}
+
+extern _Noreturn void
+gui_abort (const char *msg);
+#endif /* _cplusplus */
+
+/* Borrowed from X.Org keysymdef.h */
+#define XK_BackSpace 0xff08 /* Back space, back char */
+#define XK_Tab 0xff09
+#define XK_Linefeed 0xff0a /* Linefeed, LF */
+#define XK_Clear 0xff0b
+#define XK_Return 0xff0d /* Return, enter */
+#define XK_Pause 0xff13 /* Pause, hold */
+#define XK_Scroll_Lock 0xff14
+#define XK_Sys_Req 0xff15
+#define XK_Escape 0xff1b
+#define XK_Delete 0xffff /* Delete, rubout */
+#define XK_Home 0xff50
+#define XK_Left 0xff51 /* Move left, left arrow */
+#define XK_Up 0xff52 /* Move up, up arrow */
+#define XK_Right 0xff53 /* Move right, right arrow */
+#define XK_Down 0xff54 /* Move down, down arrow */
+#define XK_Prior 0xff55 /* Prior, previous */
+#define XK_Page_Up 0xff55
+#define XK_Next 0xff56 /* Next */
+#define XK_Page_Down 0xff56
+#define XK_End 0xff57 /* EOL */
+#define XK_Begin 0xff58 /* BOL */
+#define XK_Select 0xff60 /* Select, mark */
+#define XK_Print 0xff61
+#define XK_Execute 0xff62 /* Execute, run, do */
+#define XK_Insert 0xff63 /* Insert, insert here */
+#define XK_Undo 0xff65
+#define XK_Redo 0xff66 /* Redo, again */
+#define XK_Menu 0xff67
+#define XK_Find 0xff68 /* Find, search */
+#define XK_Cancel 0xff69 /* Cancel, stop, abort, exit */
+#define XK_Help 0xff6a /* Help */
+#define XK_Break 0xff6b
+#define XK_Mode_switch 0xff7e /* Character set switch */
+#define XK_script_switch 0xff7e /* Alias for mode_switch */
+#define XK_Num_Lock 0xff7f
+#define XK_F1 0xffbe
+
+#endif /* _HAIKU_SUPPORT_H_ */
diff --git a/src/haikufns.c b/src/haikufns.c
new file mode 100644
index 0000000000..868fc71f97
--- /dev/null
+++ b/src/haikufns.c
@@ -0,0 +1,2448 @@
+/* Haiku window system support
+ 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 <math.h>
+
+#include "lisp.h"
+#include "frame.h"
+#include "blockinput.h"
+#include "termchar.h"
+#include "font.h"
+#include "keyboard.h"
+#include "buffer.h"
+#include "dispextern.h"
+
+#include "haikugui.h"
+#include "haikuterm.h"
+#include "haiku_support.h"
+#include "termhooks.h"
+
+#include <stdlib.h>
+
+#include <kernel/OS.h>
+
+#define RGB_TO_ULONG(r, g, b) \
+ (((r) << 16) | ((g) << 8) | (b));
+#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
+#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
+#define BLUE_FROM_ULONG(color) ((color) & 0xff)
+
+/* The frame of the currently visible tooltip. */
+static Lisp_Object tip_frame;
+
+/* The window-system window corresponding to the frame of the
+ currently visible tooltip. */
+static Window tip_window;
+
+/* A timer that hides or deletes the currently visible tooltip when it
+ fires. */
+static Lisp_Object tip_timer;
+
+/* STRING argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_string;
+
+/* Normalized FRAME argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_frame;
+
+/* PARMS argument of last `x-show-tip' call. */
+static Lisp_Object tip_last_parms;
+
+static void
+haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
+static void
+haiku_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name);
+
+static ptrdiff_t image_cache_refcount;
+
+static Lisp_Object
+get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
+ Lisp_Object parms)
+{
+ struct {
+ const char *val;
+ const char *cls;
+ Lisp_Object tem;
+ } r[] = {
+ { "width", "Width", Qwidth },
+ { "height", "Height", Qheight },
+ { "left", "Left", Qleft },
+ { "top", "Top", Qtop },
+ };
+
+ int i;
+ for (i = 0; i < ARRAYELTS (r); ++i)
+ {
+ if (NILP (Fassq (r[i].tem, parms)))
+ {
+ Lisp_Object value
+ = gui_display_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
+ RES_TYPE_NUMBER);
+ if (! EQ (value, Qunbound))
+ parms = Fcons (Fcons (r[i].tem, value), parms);
+ }
+ }
+
+ return parms;
+}
+
+void
+haiku_change_tool_bar_height (struct frame *f, int height)
+{
+ int unit = FRAME_LINE_HEIGHT (f);
+ int old_height = FRAME_TOOL_BAR_HEIGHT (f);
+ int lines = (height + unit - 1) / unit;
+ Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
+
+ /* Make sure we redisplay all windows in this frame. */
+ fset_redisplay (f);
+
+ FRAME_TOOL_BAR_HEIGHT (f) = height;
+ FRAME_TOOL_BAR_LINES (f) = lines;
+ store_frame_param (f, Qtool_bar_lines, make_fixnum (lines));
+
+ if (FRAME_HAIKU_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0)
+ {
+ clear_frame (f);
+ clear_current_matrices (f);
+ }
+
+ if ((height < old_height) && WINDOWP (f->tool_bar_window))
+ clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
+
+ if (!f->tool_bar_resized)
+ {
+ /* As long as tool_bar_resized is false, effectively try to change
+ F's native height. */
+ if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
+ adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+ 1, false, Qtool_bar_lines);
+ else
+ adjust_frame_size (f, -1, -1, 4, false, Qtool_bar_lines);
+
+ f->tool_bar_resized = f->tool_bar_redisplayed;
+ }
+ else
+ /* Any other change may leave the native size of F alone. */
+ adjust_frame_size (f, -1, -1, 3, false, Qtool_bar_lines);
+
+ /* adjust_frame_size might not have done anything, garbage frame
+ here. */
+ adjust_frame_glyphs (f);
+ SET_FRAME_GARBAGED (f);
+
+ if (FRAME_HAIKU_WINDOW (f))
+ haiku_clear_under_internal_border (f);
+}
+
+void
+haiku_change_tab_bar_height (struct frame *f, int height)
+{
+ int unit = FRAME_LINE_HEIGHT (f);
+ int old_height = FRAME_TAB_BAR_HEIGHT (f);
+ int lines = (height + unit - 1) / unit;
+ Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
+
+ /* Make sure we redisplay all windows in this frame. */
+ fset_redisplay (f);
+
+ /* Recalculate tab bar and frame text sizes. */
+ FRAME_TAB_BAR_HEIGHT (f) = height;
+ FRAME_TAB_BAR_LINES (f) = lines;
+ store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
+
+ if (FRAME_HAIKU_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
+ {
+ clear_frame (f);
+ clear_current_matrices (f);
+ }
+
+ if ((height < old_height) && WINDOWP (f->tab_bar_window))
+ clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
+
+ if (!f->tab_bar_resized)
+ {
+ /* As long as tab_bar_resized is false, effectively try to change
+ F's native height. */
+ if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
+ adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+ 1, false, Qtab_bar_lines);
+ else
+ adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines);
+
+ f->tab_bar_resized = f->tab_bar_redisplayed;
+ }
+ else
+ /* Any other change may leave the native size of F alone. */
+ adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines);
+
+ /* adjust_frame_size might not have done anything, garbage frame
+ here. */
+ adjust_frame_glyphs (f);
+ SET_FRAME_GARBAGED (f);
+ if (FRAME_HAIKU_WINDOW (f))
+ haiku_clear_under_internal_border (f);
+}
+
+static void
+haiku_set_no_focus_on_map (struct frame *f, Lisp_Object value,
+ Lisp_Object oldval)
+{
+ if (!EQ (value, oldval))
+ FRAME_NO_FOCUS_ON_MAP (f) = !NILP (value);
+}
+
+static void
+haiku_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
+{
+ if (FRAME_TOOLTIP_P (f))
+ return;
+ int nlines;
+
+ /* Treat tool bars like menu bars. */
+ if (FRAME_MINIBUF_ONLY_P (f))
+ return;
+
+ /* Use VALUE only if an int >= 0. */
+ if (RANGED_FIXNUMP (0, value, INT_MAX))
+ nlines = XFIXNAT (value);
+ else
+ nlines = 0;
+
+ haiku_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
+}
+
+static void
+haiku_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
+{
+ if (FRAME_TOOLTIP_P (f))
+ return;
+ int olines = FRAME_TAB_BAR_LINES (f);
+ int nlines;
+
+ /* Treat tab bars like menu bars. */
+ if (FRAME_MINIBUF_ONLY_P (f))
+ return;
+
+ /* Use VALUE only if an int >= 0. */
+ if (RANGED_FIXNUMP (0, value, INT_MAX))
+ nlines = XFIXNAT (value);
+ else
+ nlines = 0;
+
+ if (nlines != olines && (olines == 0 || nlines == 0))
+ haiku_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
+}
+
+
+int
+haiku_get_color (const char *name, Emacs_Color *color)
+{
+ unsigned short r16, g16, b16;
+ Lisp_Object tem;
+
+ if (parse_color_spec (name, &r16, &g16, &b16))
+ {
+ color->pixel = RGB_TO_ULONG (r16 / 256, g16 / 256, b16 / 256);
+ color->red = r16;
+ color->green = g16;
+ color->blue = b16;
+ return 0;
+ }
+ else
+ {
+ block_input ();
+ eassert (x_display_list && !NILP (x_display_list->color_map));
+ tem = x_display_list->color_map;
+ for (; CONSP (tem); tem = XCDR (tem))
+ {
+ Lisp_Object col = XCAR (tem);
+ if (CONSP (col) && !xstrcasecmp (SSDATA (XCAR (col)), name))
+ {
+ int32_t clr = XFIXNUM (XCDR (col));
+ color->pixel = clr;
+ color->red = RED_FROM_ULONG (clr) * 257;
+ color->green = GREEN_FROM_ULONG (clr) * 257;
+ color->blue = BLUE_FROM_ULONG (clr) * 257;
+ unblock_input ();
+ return 0;
+ }
+ }
+
+ unblock_input ();
+ }
+
+ return 1;
+}
+
+static struct haiku_display_info *
+haiku_display_info_for_name (Lisp_Object name)
+{
+ CHECK_STRING (name);
+
+ if (!NILP (Fstring_equal (name, build_string ("be"))))
+ {
+ if (!x_display_list)
+ return x_display_list;
+
+ error ("Be windowing not initialized");
+ }
+
+ error ("Be displays can only be named \"be\"");
+}
+
+static struct haiku_display_info *
+check_haiku_display_info (Lisp_Object object)
+{
+ struct haiku_display_info *dpyinfo = NULL;
+
+ if (NILP (object))
+ {
+ struct frame *sf = XFRAME (selected_frame);
+
+ if (FRAME_HAIKU_P (sf) && FRAME_LIVE_P (sf))
+ dpyinfo = FRAME_DISPLAY_INFO (sf);
+ else if (x_display_list)
+ dpyinfo = x_display_list;
+ else
+ error ("Be windowing not present");
+ }
+ else if (TERMINALP (object))
+ {
+ struct terminal *t = decode_live_terminal (object);
+
+ if (t->type != output_haiku)
+ error ("Terminal %d is not a Be display", t->id);
+
+ dpyinfo = t->display_info.haiku;
+ }
+ else if (STRINGP (object))
+ dpyinfo = haiku_display_info_for_name (object);
+ else
+ {
+ struct frame *f = decode_window_system_frame (object);
+ dpyinfo = FRAME_DISPLAY_INFO (f);
+ }
+
+ return dpyinfo;
+}
+
+static void
+haiku_set_title_bar_text (struct frame *f, Lisp_Object text)
+{
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+ block_input ();
+ BWindow_retitle (FRAME_HAIKU_WINDOW (f), SSDATA (ENCODE_UTF_8 (text)));
+ unblock_input ();
+ }
+}
+
+static void
+haiku_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
+{
+ /* Don't change the title if it's already NAME. */
+ if (EQ (name, f->title))
+ return;
+
+ update_mode_lines = 26;
+
+ fset_title (f, name);
+
+ if (NILP (name))
+ name = f->name;
+
+ haiku_set_title_bar_text (f, name);
+}
+
+static void
+haiku_set_child_frame_border_width (struct frame *f,
+ Lisp_Object arg, Lisp_Object oldval)
+{
+ int border;
+
+ if (NILP (arg))
+ border = -1;
+ else if (RANGED_FIXNUMP (0, arg, INT_MAX))
+ border = XFIXNAT (arg);
+ else
+ signal_error ("Invalid child frame border width", arg);
+
+ if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f))
+ {
+ f->child_frame_border_width = border;
+
+ if (FRAME_HAIKU_WINDOW (f))
+ adjust_frame_size (f, -1, -1, 3, 0, Qchild_frame_border_width);
+
+ SET_FRAME_GARBAGED (f);
+ }
+}
+
+static void
+haiku_set_parent_frame (struct frame *f,
+ Lisp_Object new_value, Lisp_Object old_value)
+{
+ struct frame *p = NULL;
+ block_input ();
+ if (!NILP (new_value)
+ && (!FRAMEP (new_value)
+ || !FRAME_LIVE_P (p = XFRAME (new_value))
+ || !FRAME_HAIKU_P (p)))
+ {
+ store_frame_param (f, Qparent_frame, old_value);
+ unblock_input ();
+ error ("Invalid specification of `parent-frame'");
+ }
+
+ if (EQ (new_value, old_value))
+ {
+ unblock_input ();
+ return;
+ }
+
+ if (!NILP (old_value))
+ EmacsWindow_unparent (FRAME_HAIKU_WINDOW (f));
+ if (!NILP (new_value))
+ {
+ EmacsWindow_parent_to (FRAME_HAIKU_WINDOW (f),
+ FRAME_HAIKU_WINDOW (p));
+ BWindow_set_offset (FRAME_HAIKU_WINDOW (f),
+ f->left_pos, f->top_pos);
+ }
+ fset_parent_frame (f, new_value);
+ unblock_input ();
+}
+
+static void
+haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ haiku_set_name (f, arg, 1);
+}
+
+static void
+haiku_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ block_input ();
+ if (!EQ (new_value, old_value))
+ FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
+
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+ BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f),
+ FRAME_NO_ACCEPT_FOCUS (f));
+ }
+ unblock_input ();
+}
+
+static void
+unwind_create_frame (Lisp_Object frame)
+{
+ struct frame *f = XFRAME (frame);
+
+ /* If frame is already dead, nothing to do. This can happen if the
+ display is disconnected after the frame has become official, but
+ before x_create_frame removes the unwind protect. */
+ if (!FRAME_LIVE_P (f))
+ return;
+
+ /* If frame is ``official'', nothing to do. */
+ if (NILP (Fmemq (frame, Vframe_list)))
+ {
+#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
+ struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+#endif
+
+ /* If the frame's image cache refcount is still the same as our
+ private shadow variable, it means we are unwinding a frame
+ for which we didn't yet call init_frame_faces, where the
+ refcount is incremented. Therefore, we increment it here, so
+ that free_frame_faces, called in free_frame_resources later,
+ will not mistakenly decrement the counter that was not
+ incremented yet to account for this new frame. */
+ if (FRAME_IMAGE_CACHE (f) != NULL
+ && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
+ FRAME_IMAGE_CACHE (f)->refcount++;
+
+ haiku_free_frame_resources (f);
+ free_glyphs (f);
+
+#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
+ /* Check that reference counts are indeed correct. */
+ if (dpyinfo->terminal->image_cache)
+ eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
+#endif
+ }
+}
+
+static void
+unwind_create_tip_frame (Lisp_Object frame)
+{
+ unwind_create_frame (frame);
+ tip_window = NULL;
+ tip_frame = Qnil;
+}
+
+static void
+haiku_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ struct haiku_output *output = FRAME_OUTPUT_DATA (f);
+ unsigned long old_fg;
+
+ Emacs_Color color;
+
+ if (haiku_get_color (SSDATA (arg), &color))
+ {
+ store_frame_param (f, Qforeground_color, oldval);
+ unblock_input ();
+ error ("Bad color");
+ }
+
+ old_fg = FRAME_FOREGROUND_PIXEL (f);
+ FRAME_FOREGROUND_PIXEL (f) = color.pixel;
+
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+
+ block_input ();
+ if (output->cursor_color.pixel == old_fg)
+ {
+ output->cursor_color.pixel = old_fg;
+ output->cursor_color.red = RED_FROM_ULONG (old_fg);
+ output->cursor_color.green = GREEN_FROM_ULONG (old_fg);
+ output->cursor_color.blue = BLUE_FROM_ULONG (old_fg);
+ }
+
+ unblock_input ();
+
+ update_face_from_frame_parameter (f, Qforeground_color, arg);
+
+ if (FRAME_VISIBLE_P (f))
+ redraw_frame (f);
+ }
+}
+
+static void
+unwind_popup (void)
+{
+ if (!popup_activated_p)
+ emacs_abort ();
+ --popup_activated_p;
+}
+
+static Lisp_Object
+haiku_create_frame (Lisp_Object parms, int ttip_p)
+{
+ struct frame *f;
+ Lisp_Object frame, tem;
+ Lisp_Object name;
+ bool minibuffer_only = false;
+ bool face_change_before = face_change;
+ long window_prompting = 0;
+ ptrdiff_t count = SPECPDL_INDEX ();
+ Lisp_Object display;
+ struct haiku_display_info *dpyinfo = NULL;
+ struct kboard *kb;
+
+ parms = Fcopy_alist (parms);
+
+ Vx_resource_name = Vinvocation_name;
+
+ display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0,
+ RES_TYPE_STRING);
+ if (EQ (display, Qunbound))
+ display = Qnil;
+ dpyinfo = check_haiku_display_info (display);
+ kb = dpyinfo->terminal->kboard;
+
+ if (!dpyinfo->terminal->name)
+ error ("Terminal is not live, can't create new frames on it");
+
+ name = gui_display_get_arg (dpyinfo, parms, Qname, 0, 0,
+ RES_TYPE_STRING);
+ if (!STRINGP (name)
+ && ! EQ (name, Qunbound)
+ && ! NILP (name))
+ error ("Invalid frame name--not a string or nil");
+
+ if (STRINGP (name))
+ Vx_resource_name = name;
+
+ block_input ();
+
+ /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
+ /* No need to protect DISPLAY because that's not used after passing
+ it to make_frame_without_minibuffer. */
+ frame = Qnil;
+ tem = gui_display_get_arg (dpyinfo, parms, Qminibuffer,
+ "minibuffer", "Minibuffer",
+ RES_TYPE_SYMBOL);
+ if (ttip_p)
+ f = make_frame (0);
+ else if (EQ (tem, Qnone) || NILP (tem))
+ f = make_frame_without_minibuffer (Qnil, kb, display);
+ else if (EQ (tem, Qonly))
+ {
+ f = make_minibuffer_frame ();
+ minibuffer_only = 1;
+ }
+ else if (WINDOWP (tem))
+ f = make_frame_without_minibuffer (tem, kb, display);
+ else
+ f = make_frame (1);
+ XSETFRAME (frame, f);
+
+ f->terminal = dpyinfo->terminal;
+
+ f->output_method = output_haiku;
+ f->output_data.haiku = xzalloc (sizeof *f->output_data.haiku);
+
+ f->output_data.haiku->pending_zoom_x = INT_MIN;
+ f->output_data.haiku->pending_zoom_y = INT_MIN;
+ f->output_data.haiku->pending_zoom_width = INT_MIN;
+ f->output_data.haiku->pending_zoom_height = INT_MIN;
+
+ if (ttip_p)
+ f->wants_modeline = false;
+
+ fset_icon_name (f, gui_display_get_arg (dpyinfo, parms, Qicon_name,
+ "iconName", "Title",
+ RES_TYPE_STRING));
+ if (! STRINGP (f->icon_name) || ttip_p)
+ fset_icon_name (f, Qnil);
+
+ FRAME_DISPLAY_INFO (f) = dpyinfo;
+
+ /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */
+ if (!ttip_p)
+ record_unwind_protect (unwind_create_frame, frame);
+ else
+ record_unwind_protect (unwind_create_tip_frame, frame);
+
+ FRAME_OUTPUT_DATA (f)->parent_desc = NULL;
+ FRAME_OUTPUT_DATA (f)->explicit_parent = 0;
+
+ /* Set the name; the functions to which we pass f expect the name to
+ be set. */
+ if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
+ {
+ fset_name (f, Vinvocation_name);
+ f->explicit_name = 0;
+ }
+ else
+ {
+ fset_name (f, name);
+ f->explicit_name = 1;
+ specbind (Qx_resource_name, name);
+ }
+
+#ifdef USE_BE_CAIRO
+ register_font_driver (&ftcrfont_driver, f);
+#ifdef HAVE_HARFBUZZ
+ register_font_driver (&ftcrhbfont_driver, f);
+#endif
+#endif
+ register_font_driver (&haikufont_driver, f);
+
+ f->tooltip = ttip_p;
+
+ image_cache_refcount =
+ FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
+
+ gui_default_parameter (f, parms, Qfont_backend, Qnil,
+ "fontBackend", "FontBackend", RES_TYPE_STRING);
+
+ FRAME_RIF (f)->default_font_parameter (f, parms);
+
+ unblock_input ();
+
+ gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
+ "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (ttip_p ? 1 : 2),
+ "internalBorderWidth", "InternalBorderWidth",
+ RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil,
+ "childFrameBorderWidth", "childFrameBorderWidth",
+ RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
+ NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
+ NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qvertical_scroll_bars, !ttip_p ? Qt : Qnil,
+ "verticalScrollBars", "VerticalScrollBars",
+ RES_TYPE_SYMBOL);
+ gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
+ "horizontalScrollBars", "HorizontalScrollBars",
+ RES_TYPE_SYMBOL);
+ gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
+ "foreground", "Foreground", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
+ "background", "Background", RES_TYPE_STRING);
+ gui_default_parameter (f, parms, Qline_spacing, Qnil,
+ "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qleft_fringe, Qnil,
+ "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qright_fringe, Qnil,
+ "rightFringe", "RightFringe", RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qno_special_glyphs, ttip_p ? Qnil : Qt,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+
+ init_frame_faces (f);
+
+ /* Read comment about this code in corresponding place in xfns.c. */
+ tem = gui_display_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL,
+ RES_TYPE_NUMBER);
+ if (FIXNUMP (tem))
+ store_frame_param (f, Qmin_width, tem);
+ tem = gui_display_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL,
+ RES_TYPE_NUMBER);
+ if (FIXNUMP (tem))
+ store_frame_param (f, Qmin_height, tem);
+ adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
+ FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1,
+ Qx_create_frame_1);
+
+ if (!ttip_p)
+ {
+ gui_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL);
+ gui_default_parameter (f, parms, Qno_focus_on_map, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qno_accept_focus, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+
+ /* The resources controlling the menu-bar, tool-bar, and tab-bar are
+ processed specially at startup, and reflected in the mode
+ variables; ignore them here. */
+ gui_default_parameter (f, parms, Qmenu_bar_lines,
+ NILP (Vmenu_bar_mode)
+ ? make_fixnum (0) : make_fixnum (1),
+ NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qtab_bar_lines,
+ NILP (Vtab_bar_mode)
+ ? make_fixnum (0) : make_fixnum (1),
+ NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qtool_bar_lines,
+ NILP (Vtool_bar_mode)
+ ? make_fixnum (0) : make_fixnum (1),
+ NULL, NULL, RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate",
+ "BufferPredicate", RES_TYPE_SYMBOL);
+ gui_default_parameter (f, parms, Qtitle, Qnil, "title", "Title",
+ RES_TYPE_STRING);
+ }
+
+ parms = get_geometry_from_preferences (dpyinfo, parms);
+ window_prompting = gui_figure_window_size (f, parms, false, true);
+
+ if (ttip_p)
+ {
+ /* No fringes on tip frame. */
+ f->fringe_cols = 0;
+ f->left_fringe_width = 0;
+ f->right_fringe_width = 0;
+ /* No dividers on tip frame. */
+ f->right_divider_width = 0;
+ f->bottom_divider_width = 0;
+ }
+
+ tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0,
+ RES_TYPE_BOOLEAN);
+ f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !NILP (tem));
+
+ /* Add `tooltip' frame parameter's default value. */
+ if (NILP (Fframe_parameter (frame, Qtooltip)) && ttip_p)
+ Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil));
+
+#define ASSIGN_CURSOR(cursor, be_cursor) \
+ (FRAME_OUTPUT_DATA (f)->cursor = be_cursor)
+
+ ASSIGN_CURSOR (text_cursor, BCursor_create_i_beam ());
+ ASSIGN_CURSOR (nontext_cursor, BCursor_create_default ());
+ ASSIGN_CURSOR (modeline_cursor, BCursor_create_modeline ());
+ ASSIGN_CURSOR (hand_cursor, BCursor_create_grab ());
+ ASSIGN_CURSOR (hourglass_cursor, BCursor_create_progress_cursor ());
+ ASSIGN_CURSOR (horizontal_drag_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_EAST_WEST));
+ ASSIGN_CURSOR (vertical_drag_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_NORTH_SOUTH));
+ ASSIGN_CURSOR (left_edge_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_WEST));
+ ASSIGN_CURSOR (top_left_corner_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_NORTH_WEST));
+ ASSIGN_CURSOR (top_edge_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_NORTH));
+ ASSIGN_CURSOR (top_right_corner_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_NORTH_EAST));
+ ASSIGN_CURSOR (right_edge_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_EAST));
+ ASSIGN_CURSOR (bottom_right_corner_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_EAST));
+ ASSIGN_CURSOR (bottom_edge_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_SOUTH));
+ ASSIGN_CURSOR (bottom_left_corner_cursor,
+ BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_WEST));
+ ASSIGN_CURSOR (no_cursor,
+ BCursor_from_id (CURSOR_ID_NO_CURSOR));
+
+ ASSIGN_CURSOR (current_cursor, FRAME_OUTPUT_DATA (f)->text_cursor);
+#undef ASSIGN_CURSOR
+
+
+ if (ttip_p)
+ f->no_split = true;
+ f->terminal->reference_count++;
+
+ FRAME_OUTPUT_DATA (f)->window = BWindow_new (&FRAME_OUTPUT_DATA (f)->view);
+ if (!FRAME_OUTPUT_DATA (f)->window)
+ xsignal1 (Qerror, build_unibyte_string ("Could not create window"));
+
+ if (!minibuffer_only && !ttip_p && FRAME_EXTERNAL_MENU_BAR (f))
+ initialize_frame_menubar (f);
+
+ FRAME_OUTPUT_DATA (f)->window_desc = FRAME_OUTPUT_DATA (f)->window;
+
+ Vframe_list = Fcons (frame, Vframe_list);
+
+ Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL,
+ RES_TYPE_SYMBOL);
+
+ if (EQ (parent_frame, Qunbound)
+ || NILP (parent_frame)
+ || !FRAMEP (parent_frame)
+ || !FRAME_LIVE_P (XFRAME (parent_frame)))
+ parent_frame = Qnil;
+
+ fset_parent_frame (f, parent_frame);
+ store_frame_param (f, Qparent_frame, parent_frame);
+
+ if (!NILP (parent_frame))
+ haiku_set_parent_frame (f, parent_frame, Qnil);
+
+ gui_default_parameter (f, parms, Qundecorated, Qnil, NULL, NULL, RES_TYPE_BOOLEAN);
+
+ gui_default_parameter (f, parms, Qicon_type, Qnil,
+ "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
+ if (ttip_p)
+ {
+ gui_default_parameter (f, parms, Qundecorated, Qt, NULL, NULL, RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qno_accept_focus, Qt, NULL, NULL,
+ RES_TYPE_BOOLEAN);
+ }
+ else
+ {
+ gui_default_parameter (f, parms, Qauto_raise, Qnil,
+ "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qauto_lower, Qnil,
+ "autoLower", "AutoLower", RES_TYPE_BOOLEAN);
+ gui_default_parameter (f, parms, Qcursor_type, Qbox,
+ "cursorType", "CursorType", RES_TYPE_SYMBOL);
+ gui_default_parameter (f, parms, Qscroll_bar_width, Qnil,
+ "scrollBarWidth", "ScrollBarWidth",
+ RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qscroll_bar_height, Qnil,
+ "scrollBarHeight", "ScrollBarHeight",
+ RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qalpha, Qnil,
+ "alpha", "Alpha", RES_TYPE_NUMBER);
+ gui_default_parameter (f, parms, Qfullscreen, Qnil,
+ "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
+ }
+
+ gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
+ "inhibitDoubleBuffering", "InhibitDoubleBuffering",
+ RES_TYPE_BOOLEAN);
+
+ if (ttip_p)
+ {
+ Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
+
+ call2 (Qface_set_after_frame_default, frame, Qnil);
+
+ if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
+ {
+ AUTO_FRAME_ARG (arg, Qbackground_color, bg);
+ Fmodify_frame_parameters (frame, arg);
+ }
+ }
+
+ if (ttip_p)
+ face_change = face_change_before;
+
+ f->can_set_window_size = true;
+
+ adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+ 0, true, ttip_p ? Qtip_frame : Qx_create_frame_2);
+
+ if (!FRAME_OUTPUT_DATA (f)->explicit_parent && !ttip_p)
+ {
+ Lisp_Object visibility;
+
+ visibility = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
+ RES_TYPE_SYMBOL);
+ if (EQ (visibility, Qunbound))
+ visibility = Qt;
+ if (EQ (visibility, Qicon))
+ haiku_iconify_frame (f);
+ else if (!NILP (visibility))
+ haiku_visualize_frame (f);
+ else /* Qnil */
+ {
+ f->was_invisible = true;
+ }
+ }
+
+ if (!ttip_p)
+ {
+ if (FRAME_HAS_MINIBUF_P (f)
+ && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
+ || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
+ kset_default_minibuffer_frame (kb, frame);
+ }
+
+ for (tem = parms; CONSP (tem); tem = XCDR (tem))
+ if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
+ fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
+
+ if (window_prompting & (USPosition | PPosition))
+ haiku_set_offset (f, f->left_pos, f->top_pos, 1);
+ else
+ BWindow_center_on_screen (FRAME_HAIKU_WINDOW (f));
+
+ /* Make sure windows on this frame appear in calls to next-window
+ and similar functions. */
+ Vwindow_list = Qnil;
+
+ if (ttip_p)
+ adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+ 0, true, Qtip_frame);
+
+ return unbind_to (count, frame);
+}
+
+static void
+compute_tip_xy (struct frame *f,
+ Lisp_Object parms, Lisp_Object dx, Lisp_Object dy,
+ int width, int height, int *root_x, int *root_y)
+{
+ Lisp_Object left, top, right, bottom;
+ int min_x = 0, min_y = 0, max_x = 0, max_y = 0;
+
+ /* User-specified position? */
+ left = Fcdr (Fassq (Qleft, parms));
+ top = Fcdr (Fassq (Qtop, parms));
+ right = Fcdr (Fassq (Qright, parms));
+ bottom = Fcdr (Fassq (Qbottom, parms));
+
+ /* Move the tooltip window where the mouse pointer is. Resize and
+ show it. */
+ if ((!FIXNUMP (left) && !FIXNUMP (right))
+ || (!FIXNUMP (top) && !FIXNUMP (bottom)))
+ {
+ int x, y;
+
+ /* Default min and max values. */
+ min_x = 0;
+ min_y = 0;
+ BScreen_px_dim (&max_x, &max_y);
+
+ block_input ();
+ BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y);
+ BView_convert_to_screen (FRAME_HAIKU_VIEW (f), &x, &y);
+ *root_x = x;
+ *root_y = y;
+ unblock_input ();
+ }
+
+ if (FIXNUMP (top))
+ *root_y = XFIXNUM (top);
+ else if (FIXNUMP (bottom))
+ *root_y = XFIXNUM (bottom) - height;
+ else if (*root_y + XFIXNUM (dy) <= min_y)
+ *root_y = min_y; /* Can happen for negative dy */
+ else if (*root_y + XFIXNUM (dy) + height <= max_y)
+ /* It fits below the pointer */
+ *root_y += XFIXNUM (dy);
+ else if (height + XFIXNUM (dy) + min_y <= *root_y)
+ /* It fits above the pointer. */
+ *root_y -= height + XFIXNUM (dy);
+ else
+ /* Put it on the top. */
+ *root_y = min_y;
+
+ if (FIXNUMP (left))
+ *root_x = XFIXNUM (left);
+ else if (FIXNUMP (right))
+ *root_x = XFIXNUM (right) - width;
+ else if (*root_x + XFIXNUM (dx) <= min_x)
+ *root_x = 0; /* Can happen for negative dx */
+ else if (*root_x + XFIXNUM (dx) + width <= max_x)
+ /* It fits to the right of the pointer. */
+ *root_x += XFIXNUM (dx);
+ else if (width + XFIXNUM (dx) + min_x <= *root_x)
+ /* It fits to the left of the pointer. */
+ *root_x -= width + XFIXNUM (dx);
+ else
+ /* Put it left justified on the screen -- it ought to fit that way. */
+ *root_x = min_x;
+}
+
+static Lisp_Object
+haiku_hide_tip (bool delete)
+{
+ if (!NILP (tip_timer))
+ {
+ call1 (Qcancel_timer, tip_timer);
+ tip_timer = Qnil;
+ }
+
+ Lisp_Object it, frame;
+ FOR_EACH_FRAME (it, frame)
+ if (FRAME_WINDOW_P (XFRAME (frame)) &&
+ FRAME_HAIKU_VIEW (XFRAME (frame)))
+ BView_set_tooltip (FRAME_HAIKU_VIEW (XFRAME (frame)), NULL);
+
+ if (NILP (tip_frame)
+ || (!delete && !NILP (tip_frame)
+ && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
+ return Qnil;
+ else
+ {
+ ptrdiff_t count;
+ Lisp_Object was_open = Qnil;
+
+ count = SPECPDL_INDEX ();
+ specbind (Qinhibit_redisplay, Qt);
+ specbind (Qinhibit_quit, Qt);
+
+ if (!NILP (tip_frame))
+ {
+ if (FRAME_LIVE_P (XFRAME (tip_frame)))
+ {
+ if (delete)
+ {
+ delete_frame (tip_frame, Qnil);
+ tip_frame = Qnil;
+ }
+ else
+ haiku_unvisualize_frame (XFRAME (tip_frame));
+
+ was_open = Qt;
+ }
+ else
+ tip_frame = Qnil;
+ }
+ else
+ tip_frame = Qnil;
+
+ return unbind_to (count, was_open);
+ }
+}
+
+static void
+haiku_set_undecorated (struct frame *f, Lisp_Object new_value,
+ Lisp_Object old_value)
+{
+ if (EQ (new_value, old_value))
+ return;
+
+ block_input ();
+ FRAME_UNDECORATED (f) = !NILP (new_value);
+ BWindow_change_decoration (FRAME_HAIKU_WINDOW (f), NILP (new_value));
+ unblock_input ();
+}
+
+static void
+haiku_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
+{
+ if (FRAME_TOOLTIP_P (f))
+ return;
+ int nlines;
+ if (TYPE_RANGED_FIXNUMP (int, value))
+ nlines = XFIXNUM (value);
+ else
+ nlines = 0;
+
+ fset_redisplay (f);
+
+ FRAME_MENU_BAR_LINES (f) = 0;
+ FRAME_MENU_BAR_HEIGHT (f) = 0;
+
+ if (nlines)
+ {
+ FRAME_EXTERNAL_MENU_BAR (f) = 1;
+ if (FRAME_HAIKU_P (f) && !FRAME_HAIKU_MENU_BAR (f))
+ XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = 1;
+ }
+ else
+ {
+ if (FRAME_EXTERNAL_MENU_BAR (f))
+ free_frame_menubar (f);
+ FRAME_EXTERNAL_MENU_BAR (f) = 0;
+ if (FRAME_HAIKU_P (f))
+ FRAME_HAIKU_MENU_BAR (f) = 0;
+ }
+
+ adjust_frame_glyphs (f);
+}
+
+/* Return geometric attributes of FRAME. According to the value of
+ ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the inner
+ edges of FRAME, the root window edges of frame (Qroot_edges). Any
+ other value means to return the geometry as returned by
+ Fx_frame_geometry. */
+static Lisp_Object
+frame_geometry (Lisp_Object frame, Lisp_Object attribute)
+{
+ struct frame *f = decode_live_frame (frame);
+ check_window_system (f);
+
+ if (EQ (attribute, Qouter_edges))
+ return list4i (f->left_pos, f->top_pos,
+ f->left_pos, f->top_pos);
+ else if (EQ (attribute, Qnative_edges))
+ return list4i (f->left_pos, f->top_pos,
+ f->left_pos + FRAME_PIXEL_WIDTH (f),
+ f->top_pos + FRAME_PIXEL_HEIGHT (f));
+ else if (EQ (attribute, Qinner_edges))
+ return list4i (f->left_pos + FRAME_INTERNAL_BORDER_WIDTH (f),
+ f->top_pos + FRAME_INTERNAL_BORDER_WIDTH (f) +
+ FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f),
+ f->left_pos - FRAME_INTERNAL_BORDER_WIDTH (f) +
+ FRAME_PIXEL_WIDTH (f),
+ f->top_pos + FRAME_PIXEL_HEIGHT (f) -
+ FRAME_INTERNAL_BORDER_WIDTH (f));
+
+ else
+ return
+ list (Fcons (Qouter_position,
+ Fcons (make_fixnum (f->left_pos),
+ make_fixnum (f->top_pos))),
+ Fcons (Qouter_size,
+ Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
+ make_fixnum (FRAME_PIXEL_HEIGHT (f)))),
+ Fcons (Qexternal_border_size,
+ Fcons (make_fixnum (0), make_fixnum (0))),
+ Fcons (Qtitle_bar_size,
+ Fcons (make_fixnum (0), make_fixnum (0))),
+ Fcons (Qmenu_bar_external, Qnil),
+ Fcons (Qmenu_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
+ (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
+ make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))),
+ Fcons (Qtool_bar_external, Qnil),
+ Fcons (Qtool_bar_position, Qtop),
+ Fcons (Qtool_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
+ (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
+ make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))),
+ Fcons (Qinternal_border_width, make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f))));
+}
+
+void
+haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ CHECK_STRING (arg);
+
+ block_input ();
+ Emacs_Color color;
+
+ if (haiku_get_color (SSDATA (arg), &color))
+ {
+ store_frame_param (f, Qbackground_color, oldval);
+ unblock_input ();
+ error ("Bad color");
+ }
+
+ FRAME_OUTPUT_DATA (f)->cursor_fg = color.pixel;
+ FRAME_BACKGROUND_PIXEL (f) = color.pixel;
+
+ if (FRAME_HAIKU_VIEW (f))
+ {
+ struct face *defface;
+
+ BView_draw_lock (FRAME_HAIKU_VIEW (f));
+ BView_SetViewColor (FRAME_HAIKU_VIEW (f), color.pixel);
+ BView_draw_unlock (FRAME_HAIKU_VIEW (f));
+
+ defface = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID);
+ if (defface)
+ {
+ defface->background = color.pixel;
+ update_face_from_frame_parameter (f, Qbackground_color, arg);
+ clear_frame (f);
+ }
+ }
+
+ if (FRAME_VISIBLE_P (f))
+ SET_FRAME_GARBAGED (f);
+ unblock_input ();
+}
+
+void
+haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ CHECK_STRING (arg);
+
+ block_input ();
+ Emacs_Color color;
+
+ if (haiku_get_color (SSDATA (arg), &color))
+ {
+ store_frame_param (f, Qcursor_color, oldval);
+ unblock_input ();
+ error ("Bad color");
+ }
+
+ FRAME_CURSOR_COLOR (f) = color;
+ if (FRAME_VISIBLE_P (f))
+ {
+ gui_update_cursor (f, 0);
+ gui_update_cursor (f, 1);
+ }
+ update_face_from_frame_parameter (f, Qcursor_color, arg);
+ unblock_input ();
+}
+
+void
+haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ set_frame_cursor_types (f, arg);
+}
+
+unsigned long
+haiku_get_pixel (haiku bitmap, int x, int y)
+{
+ unsigned char *data;
+ int32_t bytes_per_row;
+ int mono_p;
+ int left;
+ int right;
+ int top;
+ int bottom;
+
+ data = BBitmap_data (bitmap);
+ BBitmap_dimensions (bitmap, &left, &top, &right, &bottom,
+ &bytes_per_row, &mono_p);
+
+ if (x < left || x > right || y < top || y > bottom)
+ emacs_abort ();
+
+ if (!mono_p)
+ return ((uint32_t *) (data + (bytes_per_row * y)))[x];
+
+ int byte = y * bytes_per_row + x / 8;
+ return data[byte] & (1 << (x % 8));
+}
+
+void
+haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel)
+{
+ unsigned char *data;
+ int32_t bytes_per_row;
+ int mono_p;
+ int left;
+ int right;
+ int top;
+ int bottom;
+
+ data = BBitmap_data (bitmap);
+ BBitmap_dimensions (bitmap, &left, &top, &right, &bottom,
+ &bytes_per_row, &mono_p);
+
+ if (x < left || x > right || y < top || y > bottom)
+ emacs_abort ();
+
+ if (mono_p)
+ {
+ ptrdiff_t off = y * bytes_per_row;
+ ptrdiff_t bit = x % 8;
+ ptrdiff_t xoff = x / 8;
+
+ unsigned char *byte = data + off + xoff;
+ if (!pixel)
+ *byte &= ~(1 << bit);
+ else
+ *byte |= 1 << bit;
+ }
+ else
+ ((uint32_t *) (data + (bytes_per_row * y)))[x] = pixel;
+}
+
+void
+haiku_free_frame_resources (struct frame *f)
+{
+ haiku window, drawable, mbar;
+ Mouse_HLInfo *hlinfo;
+ struct haiku_display_info *dpyinfo;
+ Lisp_Object bar;
+ struct scroll_bar *b;
+
+ block_input ();
+ check_window_system (f);
+
+ hlinfo = MOUSE_HL_INFO (f);
+ window = FRAME_HAIKU_WINDOW (f);
+ drawable = FRAME_HAIKU_VIEW (f);
+ mbar = FRAME_HAIKU_MENU_BAR (f);
+ dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ free_frame_faces (f);
+
+ /* Free scroll bars */
+ for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
+ {
+ b = XSCROLL_BAR (bar);
+ haiku_scroll_bar_remove (b);
+ }
+
+ if (f == dpyinfo->highlight_frame)
+ dpyinfo->highlight_frame = 0;
+ if (f == dpyinfo->focused_frame)
+ dpyinfo->focused_frame = 0;
+ if (f == dpyinfo->last_mouse_motion_frame)
+ dpyinfo->last_mouse_motion_frame = NULL;
+ if (f == dpyinfo->last_mouse_frame)
+ dpyinfo->last_mouse_frame = NULL;
+ if (f == dpyinfo->focus_event_frame)
+ dpyinfo->focus_event_frame = NULL;
+
+ if (f == hlinfo->mouse_face_mouse_frame)
+ reset_mouse_highlight (hlinfo);
+
+ if (mbar)
+ {
+ BMenuBar_delete (mbar);
+ if (f->output_data.haiku->menu_bar_open_p)
+ {
+ --popup_activated_p;
+ f->output_data.haiku->menu_bar_open_p = 0;
+ }
+ }
+
+ if (drawable)
+ BView_emacs_delete (drawable);
+
+ if (window)
+ BWindow_quit (window);
+
+ /* Free cursors */
+
+ BCursor_delete (f->output_data.haiku->text_cursor);
+ BCursor_delete (f->output_data.haiku->nontext_cursor);
+ BCursor_delete (f->output_data.haiku->modeline_cursor);
+ BCursor_delete (f->output_data.haiku->hand_cursor);
+ BCursor_delete (f->output_data.haiku->hourglass_cursor);
+ BCursor_delete (f->output_data.haiku->horizontal_drag_cursor);
+ BCursor_delete (f->output_data.haiku->vertical_drag_cursor);
+ BCursor_delete (f->output_data.haiku->left_edge_cursor);
+ BCursor_delete (f->output_data.haiku->top_left_corner_cursor);
+ BCursor_delete (f->output_data.haiku->top_edge_cursor);
+ BCursor_delete (f->output_data.haiku->top_right_corner_cursor);
+ BCursor_delete (f->output_data.haiku->right_edge_cursor);
+ BCursor_delete (f->output_data.haiku->bottom_right_corner_cursor);
+ BCursor_delete (f->output_data.haiku->bottom_edge_cursor);
+ BCursor_delete (f->output_data.haiku->bottom_left_corner_cursor);
+ BCursor_delete (f->output_data.haiku->no_cursor);
+
+ xfree (FRAME_OUTPUT_DATA (f));
+ FRAME_OUTPUT_DATA (f) = NULL;
+
+ unblock_input ();
+}
+
+void
+haiku_iconify_frame (struct frame *frame)
+{
+ if (FRAME_ICONIFIED_P (frame))
+ return;
+
+ block_input ();
+
+ SET_FRAME_VISIBLE (frame, false);
+ SET_FRAME_ICONIFIED (frame, true);
+
+ BWindow_iconify (FRAME_HAIKU_WINDOW (frame));
+
+ unblock_input ();
+}
+
+void
+haiku_visualize_frame (struct frame *f)
+{
+ block_input ();
+
+ if (!FRAME_VISIBLE_P (f))
+ {
+ if (FRAME_NO_FOCUS_ON_MAP (f))
+ BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f), 1);
+ BWindow_set_visible (FRAME_HAIKU_WINDOW (f), 1);
+ if (FRAME_NO_FOCUS_ON_MAP (f) &&
+ !FRAME_NO_ACCEPT_FOCUS (f))
+ BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f), 0);
+
+ haiku_set_offset (f, f->left_pos, f->top_pos, 0);
+
+ SET_FRAME_VISIBLE (f, 1);
+ SET_FRAME_ICONIFIED (f, 0);
+ }
+
+ unblock_input ();
+}
+
+void
+haiku_unvisualize_frame (struct frame *f)
+{
+ block_input ();
+
+ BWindow_set_visible (FRAME_HAIKU_WINDOW (f), 0);
+ SET_FRAME_VISIBLE (f, 0);
+ SET_FRAME_ICONIFIED (f, 0);
+
+ unblock_input ();
+}
+
+void
+haiku_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ int old_width = FRAME_INTERNAL_BORDER_WIDTH (f);
+ int new_width = check_int_nonnegative (arg);
+
+ if (new_width == old_width)
+ return;
+ f->internal_border_width = new_width;
+
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+ adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width);
+ haiku_clear_under_internal_border (f);
+ }
+
+ SET_FRAME_GARBAGED (f);
+}
+
+void
+haiku_set_frame_visible_invisible (struct frame *f, bool visible_p)
+{
+ if (visible_p)
+ haiku_visualize_frame (f);
+ else
+ haiku_unvisualize_frame (f);
+}
+
+void
+frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
+{
+ block_input ();
+
+ BView_convert_to_screen (FRAME_HAIKU_VIEW (f), &pix_x, &pix_y);
+ be_warp_pointer (pix_x, pix_y);
+
+ unblock_input ();
+}
+
+void
+haiku_query_color (uint32_t col, Emacs_Color *color_def)
+{
+ color_def->red = RED_FROM_ULONG (col) * 257;
+ color_def->green = GREEN_FROM_ULONG (col) * 257;
+ color_def->blue = BLUE_FROM_ULONG (col) * 257;
+
+ color_def->pixel = col;
+}
+
+Display_Info *
+check_x_display_info (Lisp_Object object)
+{
+ return check_haiku_display_info (object);
+}
+
+/* Rename frame F to NAME. If NAME is nil, set F's name to "GNU
+ Emacs". If EXPLICIT_P is non-zero, that indicates Lisp code is
+ setting the name, not redisplay; in that case, set F's name to NAME
+ and set F->explicit_name; if NAME is nil, clear F->explicit_name.
+
+ If EXPLICIT_P is zero, it means redisplay is setting the name; the
+ name provided will be ignored if explicit_name is set. */
+void
+haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p)
+{
+ if (explicit_p)
+ {
+ if (f->explicit_name && NILP (name))
+ update_mode_lines = 24;
+
+ f->explicit_name = !NILP (name);
+ }
+ else if (f->explicit_name)
+ return;
+
+ if (NILP (name))
+ name = build_unibyte_string ("GNU Emacs");
+
+ if (!NILP (Fstring_equal (name, f->name)))
+ return;
+
+ fset_name (f, name);
+
+ if (!NILP (f->title))
+ name = f->title;
+
+ haiku_set_title_bar_text (f, name);
+}
+
+static void
+haiku_set_inhibit_double_buffering (struct frame *f,
+ Lisp_Object new_value,
+ Lisp_Object old_value)
+{
+ block_input ();
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+ if (NILP (new_value))
+ {
+ EmacsView_set_up_double_buffering (FRAME_HAIKU_VIEW (f));
+ if (!NILP (old_value))
+ {
+ SET_FRAME_GARBAGED (f);
+ expose_frame (f, 0, 0, 0, 0);
+ }
+ }
+ else
+ EmacsView_disable_double_buffering (FRAME_HAIKU_VIEW (f));
+ }
+ unblock_input ();
+}
+
+\f
+
+DEFUN ("haiku-set-mouse-absolute-pixel-position",
+ Fhaiku_set_mouse_absolute_pixel_position,
+ Shaiku_set_mouse_absolute_pixel_position, 2, 2, 0,
+ doc: /* Move mouse pointer to a pixel position at (X, Y). The
+coordinates X and Y are interpreted to start from the top-left
+corner of the screen. */)
+ (Lisp_Object x, Lisp_Object y)
+{
+ int xval = check_integer_range (x, INT_MIN, INT_MAX);
+ int yval = check_integer_range (y, INT_MIN, INT_MAX);
+
+ if (!x_display_list)
+ error ("Window system not initialized");
+
+ block_input ();
+ be_warp_pointer (xval, yval);
+ unblock_input ();
+ return Qnil;
+}
+
+DEFUN ("haiku-mouse-absolute-pixel-position", Fhaiku_mouse_absolute_pixel_position,
+ Shaiku_mouse_absolute_pixel_position, 0, 0, 0,
+ doc: /* Return absolute position of mouse cursor in pixels.
+The position is returned as a cons cell (X . Y) of the coordinates of
+the mouse cursor position in pixels relative to a position (0, 0) of the
+selected frame's display. */)
+ (void)
+{
+ if (!x_display_list)
+ return Qnil;
+
+ struct frame *f = SELECTED_FRAME ();
+
+ if (FRAME_INITIAL_P (f) || !FRAME_HAIKU_P (f)
+ || !FRAME_HAIKU_VIEW (f))
+ return Qnil;
+
+ block_input ();
+ void *view = FRAME_HAIKU_VIEW (f);
+
+ int x, y;
+ BView_get_mouse (view, &x, &y);
+ BView_convert_to_screen (view, &x, &y);
+ unblock_input ();
+
+ return Fcons (make_fixnum (x), make_fixnum (y));
+}
+
+DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ return Qt;
+}
+
+DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object color, Lisp_Object frame)
+{
+ Emacs_Color col;
+ CHECK_STRING (color);
+ decode_window_system_frame (frame);
+
+ return haiku_get_color (SSDATA (color), &col) ? Qnil : Qt;
+}
+
+DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object color, Lisp_Object frame)
+{
+ Emacs_Color col;
+ CHECK_STRING (color);
+ decode_window_system_frame (frame);
+
+ block_input ();
+ if (haiku_get_color (SSDATA (color), &col))
+ {
+ unblock_input ();
+ return Qnil;
+ }
+ unblock_input ();
+ return list3i (lrint (col.red), lrint (col.green), lrint (col.blue));
+}
+
+DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
+ 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ return Qnil;
+}
+
+DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
+ 1, 3, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
+{
+ struct haiku_display_info *dpy_info;
+ CHECK_STRING (display);
+
+ if (NILP (Fstring_equal (display, build_string ("be"))))
+ !NILP (must_succeed) ? fatal ("Bad display") : error ("Bad display");
+ dpy_info = haiku_term_init ();
+
+ if (!dpy_info)
+ !NILP (must_succeed) ? fatal ("Display not responding") :
+ error ("Display not responding");
+
+ return Qnil;
+}
+
+DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
+ 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+
+{
+ check_haiku_display_info (terminal);
+
+ int width, height;
+ BScreen_px_dim (&width, &height);
+ return make_fixnum (width);
+}
+
+DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_height,
+ 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+
+{
+ check_haiku_display_info (terminal);
+
+ int width, height;
+ BScreen_px_dim (&width, &height);
+ return make_fixnum (width);
+}
+
+DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal);
+
+ int width, height;
+ BScreen_px_dim (&width, &height);
+
+ return make_fixnum (height / (dpyinfo->resy / 25.4));
+}
+
+
+DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal);
+
+ int width, height;
+ BScreen_px_dim (&width, &height);
+
+ return make_fixnum (height / (dpyinfo->resy / 25.4));
+}
+
+DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
+ 1, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object parms)
+{
+ return haiku_create_frame (parms, 0);
+}
+
+DEFUN ("x-display-visual-class", Fx_display_visual_class,
+ Sx_display_visual_class, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+
+ int planes = be_get_display_planes ();
+
+ if (planes == 8)
+ return intern ("static-color");
+ else if (planes == 16 || planes == 15)
+ return intern ("pseudo-color");
+
+ return intern ("direct-color");
+}
+
+DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object string, Lisp_Object frame, Lisp_Object parms,
+ Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
+{
+ struct frame *tip_f;
+ struct window *w;
+ int root_x, root_y;
+ struct buffer *old_buffer;
+ struct text_pos pos;
+ int width, height;
+ int old_windows_or_buffers_changed = windows_or_buffers_changed;
+ ptrdiff_t count = SPECPDL_INDEX ();
+ ptrdiff_t count_1;
+ Lisp_Object window, size, tip_buf;
+
+ AUTO_STRING (tip, " *tip*");
+
+ specbind (Qinhibit_redisplay, Qt);
+
+ CHECK_STRING (string);
+
+ if (NILP (frame))
+ frame = selected_frame;
+ decode_window_system_frame (frame);
+
+ if (NILP (timeout))
+ timeout = make_fixnum (5);
+ else
+ CHECK_FIXNAT (timeout);
+
+ if (NILP (dx))
+ dx = make_fixnum (5);
+ else
+ CHECK_FIXNUM (dx);
+
+ if (NILP (dy))
+ dy = make_fixnum (-10);
+ else
+ CHECK_FIXNUM (dy);
+
+ if (haiku_use_system_tooltips)
+ {
+ int root_x, root_y;
+ CHECK_STRING (string);
+ if (STRING_MULTIBYTE (string))
+ string = ENCODE_UTF_8 (string);
+
+ if (NILP (frame))
+ frame = selected_frame;
+
+ struct frame *f = decode_window_system_frame (frame);
+ block_input ();
+
+ char *str = xstrdup (SSDATA (string));
+ int height = be_plain_font_height ();
+ int width;
+ char *tok = strtok (str, "\n");
+ width = be_string_width_with_plain_font (tok);
+
+ while ((tok = strtok (NULL, "\n")))
+ {
+ height = be_plain_font_height ();
+ int w = be_string_width_with_plain_font (tok);
+ if (w > width)
+ w = width;
+ }
+ free (str);
+
+ height += 16; /* Default margin. */
+ width += 16; /* Ditto. Unfortunately there isn't a more
+ reliable way to get it. */
+ compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
+ BView_convert_from_screen (FRAME_HAIKU_VIEW (f), &root_x, &root_y);
+ BView_set_and_show_sticky_tooltip (FRAME_HAIKU_VIEW (f), SSDATA (string),
+ root_x, root_y);
+ unblock_input ();
+ goto start_timer;
+ }
+
+ if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
+ {
+ if (FRAME_VISIBLE_P (XFRAME (tip_frame))
+ && EQ (frame, tip_last_frame)
+ && !NILP (Fequal_including_properties (string, tip_last_string))
+ && !NILP (Fequal (parms, tip_last_parms)))
+ {
+ /* Only DX and DY have changed. */
+ tip_f = XFRAME (tip_frame);
+ if (!NILP (tip_timer))
+ {
+ Lisp_Object timer = tip_timer;
+
+ tip_timer = Qnil;
+ call1 (Qcancel_timer, timer);
+ }
+
+ block_input ();
+ compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
+ FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
+ haiku_set_offset (tip_f, root_x, root_y, 1);
+ haiku_visualize_frame (tip_f);
+ unblock_input ();
+
+ goto start_timer;
+ }
+ else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame))
+ {
+ bool delete = false;
+ Lisp_Object tail, elt, parm, last;
+
+ /* Check if every parameter in PARMS has the same value in
+ tip_last_parms. This may destruct tip_last_parms
+ which, however, will be recreated below. */
+ for (tail = parms; CONSP (tail); tail = XCDR (tail))
+ {
+ elt = XCAR (tail);
+ parm = Fcar (elt);
+ /* The left, top, right and bottom parameters are handled
+ by compute_tip_xy so they can be ignored here. */
+ if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
+ && !EQ (parm, Qright) && !EQ (parm, Qbottom))
+ {
+ last = Fassq (parm, tip_last_parms);
+ if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
+ {
+ /* We lost, delete the old tooltip. */
+ delete = true;
+ break;
+ }
+ else
+ tip_last_parms =
+ call2 (Qassq_delete_all, parm, tip_last_parms);
+ }
+ else
+ tip_last_parms =
+ call2 (Qassq_delete_all, parm, tip_last_parms);
+ }
+
+ /* Now check if there's a parameter left in tip_last_parms with a
+ non-nil value. */
+ for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail))
+ {
+ elt = XCAR (tail);
+ parm = Fcar (elt);
+ if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
+ && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
+ {
+ /* We lost, delete the old tooltip. */
+ delete = true;
+ break;
+ }
+ }
+
+ haiku_hide_tip (delete);
+ }
+ else
+ haiku_hide_tip (true);
+ }
+ else
+ haiku_hide_tip (true);
+
+ tip_last_frame = frame;
+ tip_last_string = string;
+ tip_last_parms = parms;
+
+ /* Block input until the tip has been fully drawn, to avoid crashes
+ when drawing tips in menus. */
+ block_input ();
+
+ if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
+ {
+ /* Add default values to frame parameters. */
+ if (NILP (Fassq (Qname, parms)))
+ parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
+ if (NILP (Fassq (Qinternal_border_width, parms)))
+ parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)), parms);
+ if (NILP (Fassq (Qborder_width, parms)))
+ parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
+ if (NILP (Fassq (Qborder_color, parms)))
+ parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")),
+ parms);
+ if (NILP (Fassq (Qbackground_color, parms)))
+ parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
+ parms);
+
+ /* Create a frame for the tooltip and record it in the global
+ variable tip_frame. */
+
+ if (NILP (tip_frame = haiku_create_frame (parms, 1)))
+ {
+ /* Creating the tip frame failed. */
+ unblock_input ();
+ return unbind_to (count, Qnil);
+ }
+ }
+
+ tip_f = XFRAME (tip_frame);
+ window = FRAME_ROOT_WINDOW (tip_f);
+ tip_buf = Fget_buffer_create (tip, Qnil);
+ /* We will mark the tip window a "pseudo-window" below, and such
+ windows cannot have display margins. */
+ bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
+ bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
+ set_window_buffer (window, tip_buf, false, false);
+ w = XWINDOW (window);
+ w->pseudo_window_p = true;
+ /* Try to avoid that `other-window' select us (Bug#47207). */
+ Fset_window_parameter (window, Qno_other_window, Qt);
+
+ /* Set up the frame's root window. Note: The following code does not
+ try to size the window or its frame correctly. Its only purpose is
+ to make the subsequent text size calculations work. The right
+ sizes should get installed when the toolkit gets back to us. */
+ w->left_col = 0;
+ w->top_line = 0;
+ w->pixel_left = 0;
+ w->pixel_top = 0;
+
+ if (CONSP (Vx_max_tooltip_size)
+ && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
+ && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
+ {
+ w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
+ w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
+ }
+ else
+ {
+ w->total_cols = 80;
+ w->total_lines = 40;
+ }
+
+ w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
+ w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
+ FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w);
+ adjust_frame_glyphs (tip_f);
+
+ /* Insert STRING into the root window's buffer and fit the frame to
+ the buffer. */
+ count_1 = SPECPDL_INDEX ();
+ old_buffer = current_buffer;
+ set_buffer_internal_1 (XBUFFER (w->contents));
+ bset_truncate_lines (current_buffer, Qnil);
+ specbind (Qinhibit_read_only, Qt);
+ specbind (Qinhibit_modification_hooks, Qt);
+ specbind (Qinhibit_point_motion_hooks, Qt);
+ Ferase_buffer ();
+ Finsert (1, &string);
+ clear_glyph_matrix (w->desired_matrix);
+ clear_glyph_matrix (w->current_matrix);
+ SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
+ try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+ /* Calculate size of tooltip window. */
+ size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
+ make_fixnum (w->pixel_height), Qnil);
+ /* Add the frame's internal border to calculated size. */
+ width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+ height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+ /* Calculate position of tooltip frame. */
+ compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
+ BWindow_resize (FRAME_HAIKU_WINDOW (tip_f), width, height);
+ haiku_set_offset (tip_f, root_x, root_y, 1);
+ BWindow_set_tooltip_decoration (FRAME_HAIKU_WINDOW (tip_f));
+ BView_set_view_cursor (FRAME_HAIKU_VIEW (tip_f),
+ FRAME_OUTPUT_DATA (XFRAME (frame))->current_cursor);
+ SET_FRAME_VISIBLE (tip_f, 1);
+ BWindow_set_visible (FRAME_HAIKU_WINDOW (tip_f), 1);
+
+ w->must_be_updated_p = true;
+ flush_frame (tip_f);
+ update_single_window (w);
+ set_buffer_internal_1 (old_buffer);
+ unbind_to (count_1, Qnil);
+ unblock_input ();
+ windows_or_buffers_changed = old_windows_or_buffers_changed;
+
+ start_timer:
+ /* Let the tip disappear after timeout seconds. */
+ tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
+ intern ("x-hide-tip"));
+
+ return unbind_to (count, Qnil);
+}
+
+DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (void)
+{
+ return haiku_hide_tip (!tooltip_reuse_hidden_frame);
+}
+
+DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */
+ attributes: noreturn)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+
+ error ("Cannot close Haiku displays");
+}
+
+DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (void)
+{
+ if (!x_display_list)
+ return Qnil;
+
+ return list1 (XCAR (x_display_list->name_list_element));
+}
+
+DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+ return build_string ("Haiku, Inc.");
+}
+
+DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+ return list3i (5, 1, 1);
+}
+
+DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+ return make_fixnum (be_get_display_screens ());
+}
+
+DEFUN ("haiku-get-version-string", Fhaiku_get_version_string,
+ Shaiku_get_version_string, 0, 0, 0,
+ doc: /* Return a string describing the current Haiku version. */)
+ (void)
+{
+ char buf[1024];
+
+ be_get_version_string ((char *) &buf, sizeof buf);
+ return build_string (buf);
+}
+
+DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
+ 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+
+ return make_fixnum (be_get_display_color_cells ());
+}
+
+DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
+ 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+
+ return make_fixnum (be_get_display_planes ());
+}
+
+DEFUN ("x-double-buffered-p", Fx_double_buffered_p, Sx_double_buffered_p,
+ 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object frame)
+{
+ struct frame *f = decode_live_frame (frame);
+ check_window_system (f);
+
+ return EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)) ? Qt : Qnil;
+}
+
+DEFUN ("x-display-backing-store", Fx_display_backing_store, Sx_display_backing_store,
+ 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ if (FRAMEP (terminal))
+ {
+ CHECK_LIVE_FRAME (terminal);
+ struct frame *f = decode_window_system_frame (terminal);
+
+ if (FRAME_HAIKU_VIEW (f) &&
+ EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)))
+ return FRAME_PARENT_FRAME (f) ? Qwhen_mapped : Qalways;
+ else
+ return Qnot_useful;
+ }
+ else
+ {
+ check_haiku_display_info (terminal);
+ return Qnot_useful;
+ }
+}
+
+DEFUN ("haiku-frame-geometry", Fhaiku_frame_geometry, Shaiku_frame_geometry, 0, 1, 0,
+ doc: /* Return geometric attributes of FRAME.
+FRAME must be a live frame and defaults to the selected one. The return
+value is an association list of the attributes listed below. All height
+and width values are in pixels.
+
+`outer-position' is a cons of the outer left and top edges of FRAME
+ relative to the origin - the position (0, 0) - of FRAME's display.
+
+`outer-size' is a cons of the outer width and height of FRAME. The
+ outer size includes the title bar and the external borders as well as
+ any menu and/or tool bar of frame.
+
+`external-border-size' is a cons of the horizontal and vertical width of
+ FRAME's external borders as supplied by the window manager.
+
+`title-bar-size' is a cons of the width and height of the title bar of
+ FRAME as supplied by the window manager. If both of them are zero,
+ FRAME has no title bar. If only the width is zero, Emacs was not
+ able to retrieve the width information.
+
+`menu-bar-external', if non-nil, means the menu bar is external (never
+ included in the inner edges of FRAME).
+
+`menu-bar-size' is a cons of the width and height of the menu bar of
+ FRAME.
+
+`tool-bar-external', if non-nil, means the tool bar is external (never
+ included in the inner edges of FRAME).
+
+`tool-bar-position' tells on which side the tool bar on FRAME is and can
+ be one of `left', `top', `right' or `bottom'. If this is nil, FRAME
+ has no tool bar.
+
+`tool-bar-size' is a cons of the width and height of the tool bar of
+ FRAME.
+
+`internal-border-width' is the width of the internal border of
+ FRAME. */)
+ (Lisp_Object frame)
+{
+ return frame_geometry (frame, Qnil);
+}
+
+DEFUN ("haiku-frame-edges", Fhaiku_frame_edges, Shaiku_frame_edges, 0, 2, 0,
+ doc: /* Return edge coordinates of FRAME.
+FRAME must be a live frame and defaults to the selected one. The return
+value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are
+in pixels relative to the origin - the position (0, 0) - of FRAME's
+display.
+
+If optional argument TYPE is the symbol `outer-edges', return the outer
+edges of FRAME. The outer edges comprise the decorations of the window
+manager (like the title bar or external borders) as well as any external
+menu or tool bar of FRAME. If optional argument TYPE is the symbol
+`native-edges' or nil, return the native edges of FRAME. The native
+edges exclude the decorations of the window manager and any external
+menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return
+the inner edges of FRAME. These edges exclude title bar, any borders,
+menu bar or tool bar of FRAME. */)
+ (Lisp_Object frame, Lisp_Object type)
+{
+ return frame_geometry (frame, ((EQ (type, Qouter_edges)
+ || EQ (type, Qinner_edges))
+ ? type
+ : Qnative_edges));
+}
+
+DEFUN ("haiku-read-file-name", Fhaiku_read_file_name, Shaiku_read_file_name, 1, 6, 0,
+ doc: /* Use a graphical panel to read a file name, using prompt PROMPT.
+Optional arg FRAME specifies a frame on which to display the file panel.
+If it is nil, the current frame is used instead.
+The frame being used will be brought to the front of
+the display after the file panel is closed.
+Optional arg DIR, if non-nil, supplies a default directory.
+Optional arg MUSTMATCH, if non-nil, means the returned file or
+directory must exist.
+Optional arg DIR_ONLY_P, if non-nil, means choose only directories.
+Optional arg SAVE_TEXT, if non-nil, specifies some text to show in the entry field. */)
+ (Lisp_Object prompt, Lisp_Object frame,
+ Lisp_Object dir, Lisp_Object mustmatch,
+ Lisp_Object dir_only_p, Lisp_Object save_text)
+{
+ ptrdiff_t idx;
+ if (!x_display_list)
+ error ("Be windowing not initialized");
+
+ if (!NILP (dir))
+ CHECK_STRING (dir);
+
+ if (!NILP (save_text))
+ CHECK_STRING (save_text);
+
+ if (NILP (frame))
+ frame = selected_frame;
+
+ CHECK_STRING (prompt);
+
+ CHECK_LIVE_FRAME (frame);
+ check_window_system (XFRAME (frame));
+
+ idx = SPECPDL_INDEX ();
+ record_unwind_protect_void (unwind_popup);
+
+ struct frame *f = XFRAME (frame);
+
+ FRAME_DISPLAY_INFO (f)->focus_event_frame = f;
+
+ ++popup_activated_p;
+ char *fn = be_popup_file_dialog (!NILP (mustmatch) || !NILP (dir_only_p),
+ !NILP (dir) ? SSDATA (ENCODE_UTF_8 (dir)) : NULL,
+ !NILP (mustmatch), !NILP (dir_only_p),
+ FRAME_HAIKU_WINDOW (f),
+ !NILP (save_text) ? SSDATA (ENCODE_UTF_8 (save_text)) : NULL,
+ SSDATA (ENCODE_UTF_8 (prompt)),
+ block_input, unblock_input);
+
+ unbind_to (idx, Qnil);
+
+ block_input ();
+ BWindow_activate (FRAME_HAIKU_WINDOW (f));
+ unblock_input ();
+
+ if (!fn)
+ return Qnil;
+
+ Lisp_Object p = build_string_from_utf8 (fn);
+ free (fn);
+ return p;
+}
+
+DEFUN ("haiku-put-resource", Fhaiku_put_resource, Shaiku_put_resource,
+ 2, 2, 0, doc: /* Place STRING by the key RESOURCE in the resource database.
+It can later be retrieved with `x-get-resource'. */)
+ (Lisp_Object resource, Lisp_Object string)
+{
+ CHECK_STRING (resource);
+ if (!NILP (string))
+ CHECK_STRING (string);
+
+ put_xrm_resource (resource, string);
+ return Qnil;
+}
+
+DEFUN ("haiku-frame-list-z-order", Fhaiku_frame_list_z_order,
+ Shaiku_frame_list_z_order, 0, 1, 0,
+ doc: /* Return list of Emacs' frames, in Z (stacking) order.
+If TERMINAL is non-nil and specifies a live frame, return the child
+frames of that frame in Z (stacking) order.
+
+As it is impossible to reliably determine the frame stacking order on
+Haiku, the selected frame is always the first element of the returned
+list, while the rest are not guaranteed to be in any particular order.
+
+Frames are listed from topmost (first) to bottommost (last). */)
+ (Lisp_Object terminal)
+{
+ Lisp_Object frames = Qnil;
+ Lisp_Object head, tail;
+ Lisp_Object sel = Qnil;
+
+ FOR_EACH_FRAME (head, tail)
+ {
+ struct frame *f = XFRAME (tail);
+ if (!FRAME_HAIKU_P (f) ||
+ (FRAMEP (terminal) &&
+ FRAME_LIVE_P (XFRAME (terminal)) &&
+ !EQ (terminal, get_frame_param (f, Qparent_frame))))
+ continue;
+
+ if (EQ (tail, selected_frame))
+ sel = tail;
+ else
+ frames = Fcons (tail, frames);
+ }
+
+ if (NILP (sel))
+ return frames;
+ return Fcons (sel, frames);
+}
+
+DEFUN ("x-display-save-under", Fx_display_save_under,
+ Sx_display_save_under, 0, 1, 0,
+ doc: /* SKIP: real doc in xfns.c. */)
+ (Lisp_Object terminal)
+{
+ check_haiku_display_info (terminal);
+
+ if (FRAMEP (terminal))
+ {
+ struct frame *f = decode_window_system_frame (terminal);
+ return FRAME_HAIKU_VIEW (f) && EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)) ?
+ Qt : Qnil;
+ }
+
+ return Qnil;
+}
+
+frame_parm_handler haiku_frame_parm_handlers[] =
+ {
+ gui_set_autoraise,
+ gui_set_autolower,
+ haiku_set_background_color,
+ NULL, /* x_set_border_color */
+ gui_set_border_width,
+ haiku_set_cursor_color,
+ haiku_set_cursor_type,
+ gui_set_font,
+ haiku_set_foreground_color,
+ NULL, /* set icon name */
+ NULL, /* set icon type */
+ haiku_set_child_frame_border_width,
+ haiku_set_internal_border_width,
+ gui_set_right_divider_width,
+ gui_set_bottom_divider_width,
+ haiku_set_menu_bar_lines,
+ NULL, /* set mouse color */
+ haiku_explicitly_set_name,
+ gui_set_scroll_bar_width,
+ gui_set_scroll_bar_height,
+ haiku_set_title,
+ gui_set_unsplittable,
+ gui_set_vertical_scroll_bars,
+ gui_set_horizontal_scroll_bars,
+ gui_set_visibility,
+ haiku_set_tab_bar_lines,
+ haiku_set_tool_bar_lines,
+ NULL, /* set scroll bar fg */
+ NULL, /* set scroll bar bkg */
+ gui_set_screen_gamma,
+ gui_set_line_spacing,
+ gui_set_left_fringe,
+ gui_set_right_fringe,
+ NULL, /* x wait for wm */
+ gui_set_fullscreen,
+ gui_set_font_backend,
+ gui_set_alpha,
+ NULL, /* set sticky */
+ NULL, /* set tool bar pos */
+ haiku_set_inhibit_double_buffering,
+ haiku_set_undecorated,
+ haiku_set_parent_frame,
+ NULL, /* set skip taskbar */
+ haiku_set_no_focus_on_map,
+ haiku_set_no_accept_focus,
+ NULL, /* set z group */
+ NULL, /* set override redir */
+ gui_set_no_special_glyphs
+ };
+
+void
+syms_of_haikufns (void)
+{
+ DEFSYM (Qfont_parameter, "font-parameter");
+ DEFSYM (Qcancel_timer, "cancel-timer");
+ DEFSYM (Qassq_delete_all, "assq-delete-all");
+
+ DEFSYM (Qalways, "always");
+ DEFSYM (Qnot_useful, "not-useful");
+ DEFSYM (Qwhen_mapped, "when-mapped");
+
+ defsubr (&Sx_hide_tip);
+ defsubr (&Sxw_display_color_p);
+ defsubr (&Sx_display_grayscale_p);
+ defsubr (&Sx_open_connection);
+ defsubr (&Sx_create_frame);
+ defsubr (&Sx_display_pixel_width);
+ defsubr (&Sx_display_pixel_height);
+ defsubr (&Sxw_color_values);
+ defsubr (&Sxw_color_defined_p);
+ defsubr (&Sx_display_visual_class);
+ defsubr (&Sx_show_tip);
+ defsubr (&Sx_display_mm_height);
+ defsubr (&Sx_display_mm_width);
+ defsubr (&Sx_close_connection);
+ defsubr (&Sx_display_list);
+ defsubr (&Sx_server_vendor);
+ defsubr (&Sx_server_version);
+ defsubr (&Sx_display_screens);
+ defsubr (&Shaiku_get_version_string);
+ defsubr (&Sx_display_color_cells);
+ defsubr (&Sx_display_planes);
+ defsubr (&Shaiku_set_mouse_absolute_pixel_position);
+ defsubr (&Shaiku_mouse_absolute_pixel_position);
+ defsubr (&Shaiku_frame_geometry);
+ defsubr (&Shaiku_frame_edges);
+ defsubr (&Sx_double_buffered_p);
+ defsubr (&Sx_display_backing_store);
+ defsubr (&Shaiku_read_file_name);
+ defsubr (&Shaiku_put_resource);
+ defsubr (&Shaiku_frame_list_z_order);
+ defsubr (&Sx_display_save_under);
+
+ tip_timer = Qnil;
+ staticpro (&tip_timer);
+ tip_frame = Qnil;
+ staticpro (&tip_frame);
+ tip_last_frame = Qnil;
+ staticpro (&tip_last_frame);
+ tip_last_string = Qnil;
+ staticpro (&tip_last_string);
+ tip_last_parms = Qnil;
+ staticpro (&tip_last_parms);
+
+ DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
+ doc: /* SKIP: real doc in xfns.c. */);
+ Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
+
+ DEFVAR_BOOL ("haiku-use-system-tooltips", haiku_use_system_tooltips,
+ doc: /* When non-nil, Emacs will display tooltips using the App Kit.
+This can avoid a great deal of consing that does not play
+well with the Haiku memory allocator, but comes with the
+disadvantage of not being able to use special display properties
+within tooltips. */);
+ haiku_use_system_tooltips = 1;
+
+#ifdef USE_BE_CAIRO
+ DEFVAR_LISP ("cairo-version-string", Vcairo_version_string,
+ doc: /* Version info for cairo. */);
+ {
+ char cairo_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
+ int len = sprintf (cairo_version, "%d.%d.%d",
+ CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
+ CAIRO_VERSION_MICRO);
+ Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
+ }
+#endif
+
+ return;
+}
diff --git a/src/haikufont.c b/src/haikufont.c
new file mode 100644
index 0000000000..811fa62a84
--- /dev/null
+++ b/src/haikufont.c
@@ -0,0 +1,1072 @@
+/* Font support for Haiku windowing
+
+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 "lisp.h"
+#include "dispextern.h"
+#include "composite.h"
+#include "blockinput.h"
+#include "charset.h"
+#include "frame.h"
+#include "window.h"
+#include "fontset.h"
+#include "haikuterm.h"
+#include "character.h"
+#include "font.h"
+#include "termchar.h"
+#include "pdumper.h"
+#include "haiku_support.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+static Lisp_Object font_cache;
+
+#define METRICS_NCOLS_PER_ROW (128)
+
+enum metrics_status
+ {
+ METRICS_INVALID = -1, /* metrics entry is invalid */
+ };
+
+#define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent)
+#define METRICS_SET_STATUS(metrics, status) \
+ ((metrics)->ascent = 0, (metrics)->descent = (status))
+
+static struct
+{
+ /* registry name */
+ const char *name;
+ /* characters to distinguish the charset from the others */
+ int uniquifier[6];
+ /* additional constraint by language */
+ const char *lang;
+} em_charset_table[] =
+ { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
+ { "iso8859-2", { 0x00A0, 0x010E }},
+ { "iso8859-3", { 0x00A0, 0x0108 }},
+ { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
+ { "iso8859-5", { 0x00A0, 0x0401 }},
+ { "iso8859-6", { 0x00A0, 0x060C }},
+ { "iso8859-7", { 0x00A0, 0x0384 }},
+ { "iso8859-8", { 0x00A0, 0x05D0 }},
+ { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
+ { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
+ { "iso8859-11", { 0x00A0, 0x0E01 }},
+ { "iso8859-13", { 0x00A0, 0x201C }},
+ { "iso8859-14", { 0x00A0, 0x0174 }},
+ { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
+ { "iso8859-16", { 0x00A0, 0x0218}},
+ { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
+ { "big5-0", { 0x9C21 }, "zh-tw" },
+ { "jisx0208.1983-0", { 0x4E55 }, "ja"},
+ { "ksc5601.1985-0", { 0xAC00 }, "ko"},
+ { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
+ { "cns11643.1992-2", { 0x4E33, 0x7934 }},
+ { "cns11643.1992-3", { 0x201A9 }},
+ { "cns11643.1992-4", { 0x20057 }},
+ { "cns11643.1992-5", { 0x20000 }},
+ { "cns11643.1992-6", { 0x20003 }},
+ { "cns11643.1992-7", { 0x20055 }},
+ { "gbk-0", { 0x4E06 }, "zh-cn"},
+ { "jisx0212.1990-0", { 0x4E44 }},
+ { "jisx0213.2000-1", { 0xFA10 }, "ja"},
+ { "jisx0213.2000-2", { 0xFA49 }},
+ { "jisx0213.2004-1", { 0x20B9F }},
+ { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
+ { "tis620.2529-1", { 0x0E01 }, "th"},
+ { "microsoft-cp1251", { 0x0401, 0x0490 }, "ru"},
+ { "koi8-r", { 0x0401, 0x2219 }, "ru"},
+ { "mulelao-1", { 0x0E81 }, "lo"},
+ { "unicode-sip", { 0x20000 }},
+ { "mulearabic-0", { 0x628 }},
+ { "mulearabic-1", { 0x628 }},
+ { "mulearabic-2", { 0x628 }},
+ { NULL }
+ };
+
+static void
+haikufont_apply_registry (struct haiku_font_pattern *pattern,
+ Lisp_Object registry)
+{
+ char *str = SSDATA (SYMBOL_NAME (registry));
+ USE_SAFE_ALLOCA;
+ char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
+ int i, j;
+
+ for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
+ {
+ if (str[i] == '.')
+ re[j++] = '\\';
+ else if (str[i] == '*')
+ re[j++] = '.';
+ re[j] = str[i];
+ if (re[j] == '?')
+ re[j] = '.';
+ }
+ re[j] = '\0';
+ AUTO_STRING_WITH_LEN (regexp, re, j);
+ for (i = 0; em_charset_table[i].name; i++)
+ if (fast_c_string_match_ignore_case
+ (regexp, em_charset_table[i].name,
+ strlen (em_charset_table[i].name)) >= 0)
+ break;
+ SAFE_FREE ();
+ if (!em_charset_table[i].name)
+ return;
+ int *uniquifier = em_charset_table[i].uniquifier;
+ int l;
+
+ for (l = 0; uniquifier[l]; ++l);
+
+ uint32_t *a = xmalloc (l * sizeof *a);
+ for (l = 0; uniquifier[l]; ++l)
+ a[l] = uniquifier[l];
+
+ if (pattern->specified & FSPEC_WANTED)
+ {
+ int old_l = l;
+ l += pattern->want_chars_len;
+ a = xrealloc (a, l * sizeof *a);
+ memcpy (&a[old_l], pattern->wanted_chars, (l - old_l) * sizeof *a);
+ xfree (pattern->wanted_chars);
+ }
+ pattern->specified |= FSPEC_WANTED;
+ pattern->want_chars_len = l;
+ pattern->wanted_chars = a;
+
+ if (em_charset_table[i].lang)
+ {
+ if (!strncmp (em_charset_table[i].lang, "zh", 2))
+ {
+ pattern->specified |= FSPEC_LANGUAGE;
+ pattern->language = LANGUAGE_CN;
+ }
+ else if (!strncmp (em_charset_table[i].lang, "ko", 2))
+ {
+ pattern->specified |= FSPEC_LANGUAGE;
+ pattern->language = LANGUAGE_KO;
+ }
+ else if (!strncmp (em_charset_table[i].lang, "ja", 2))
+ {
+ pattern->specified |= FSPEC_LANGUAGE;
+ pattern->language = LANGUAGE_JP;
+ }
+ }
+
+ return;
+}
+
+static Lisp_Object
+haikufont_get_fallback_entity (void)
+{
+ Lisp_Object ent = font_make_entity ();
+ ASET (ent, FONT_TYPE_INDEX, Qhaiku);
+ ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku);
+ ASET (ent, FONT_FAMILY_INDEX, Qnil);
+ ASET (ent, FONT_ADSTYLE_INDEX, Qnil);
+ ASET (ent, FONT_REGISTRY_INDEX, Qutf_8);
+ ASET (ent, FONT_SIZE_INDEX, make_fixnum (0));
+ ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+ ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO));
+ FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnil);
+ FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnil);
+ FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnil);
+
+ return ent;
+}
+
+static Lisp_Object
+haikufont_get_cache (struct frame *frame)
+{
+ return font_cache;
+}
+
+static Lisp_Object
+haikufont_weight_to_lisp (int weight)
+{
+ switch (weight)
+ {
+ case HAIKU_THIN:
+ return Qthin;
+ case HAIKU_ULTRALIGHT:
+ return Qultra_light;
+ case HAIKU_EXTRALIGHT:
+ return Qextra_light;
+ case HAIKU_LIGHT:
+ return Qlight;
+ case HAIKU_SEMI_LIGHT:
+ return Qsemi_light;
+ case HAIKU_REGULAR:
+ return Qnormal;
+ case HAIKU_SEMI_BOLD:
+ return Qsemi_bold;
+ case HAIKU_BOLD:
+ return Qbold;
+ case HAIKU_EXTRA_BOLD:
+ return Qextra_bold;
+ case HAIKU_ULTRA_BOLD:
+ return Qultra_bold;
+ case HAIKU_BOOK:
+ return Qbook;
+ case HAIKU_HEAVY:
+ return Qheavy;
+ case HAIKU_ULTRA_HEAVY:
+ return Qultra_heavy;
+ case HAIKU_BLACK:
+ return Qblack;
+ case HAIKU_MEDIUM:
+ return Qmedium;
+ }
+ emacs_abort ();
+}
+
+static int
+haikufont_lisp_to_weight (Lisp_Object weight)
+{
+ if (EQ (weight, Qthin))
+ return HAIKU_THIN;
+ if (EQ (weight, Qultra_light))
+ return HAIKU_ULTRALIGHT;
+ if (EQ (weight, Qextra_light))
+ return HAIKU_EXTRALIGHT;
+ if (EQ (weight, Qlight))
+ return HAIKU_LIGHT;
+ if (EQ (weight, Qsemi_light))
+ return HAIKU_SEMI_LIGHT;
+ if (EQ (weight, Qnormal))
+ return HAIKU_REGULAR;
+ if (EQ (weight, Qsemi_bold))
+ return HAIKU_SEMI_BOLD;
+ if (EQ (weight, Qbold))
+ return HAIKU_BOLD;
+ if (EQ (weight, Qextra_bold))
+ return HAIKU_EXTRA_BOLD;
+ if (EQ (weight, Qultra_bold))
+ return HAIKU_ULTRA_BOLD;
+ if (EQ (weight, Qbook))
+ return HAIKU_BOOK;
+ if (EQ (weight, Qheavy))
+ return HAIKU_HEAVY;
+ if (EQ (weight, Qultra_heavy))
+ return HAIKU_ULTRA_HEAVY;
+ if (EQ (weight, Qblack))
+ return HAIKU_BLACK;
+ if (EQ (weight, Qmedium))
+ return HAIKU_MEDIUM;
+
+ emacs_abort ();
+}
+
+static Lisp_Object
+haikufont_slant_to_lisp (enum haiku_font_slant slant)
+{
+ switch (slant)
+ {
+ case NO_SLANT:
+ emacs_abort ();
+ case SLANT_ITALIC:
+ return Qitalic;
+ case SLANT_REGULAR:
+ return Qnormal;
+ case SLANT_OBLIQUE:
+ return Qoblique;
+ }
+ emacs_abort ();
+}
+
+static enum haiku_font_slant
+haikufont_lisp_to_slant (Lisp_Object slant)
+{
+ if (EQ (slant, Qitalic) ||
+ EQ (slant, Qreverse_italic))
+ return SLANT_ITALIC;
+ if (EQ (slant, Qoblique) ||
+ EQ (slant, Qreverse_oblique))
+ return SLANT_OBLIQUE;
+ if (EQ (slant, Qnormal))
+ return SLANT_REGULAR;
+ emacs_abort ();
+}
+
+static Lisp_Object
+haikufont_width_to_lisp (enum haiku_font_width width)
+{
+ switch (width)
+ {
+ case NO_WIDTH:
+ emacs_abort ();
+ case ULTRA_CONDENSED:
+ return Qultra_condensed;
+ case EXTRA_CONDENSED:
+ return Qextra_condensed;
+ case CONDENSED:
+ return Qcondensed;
+ case SEMI_CONDENSED:
+ return Qsemi_condensed;
+ case NORMAL_WIDTH:
+ return Qnormal;
+ case SEMI_EXPANDED:
+ return Qsemi_expanded;
+ case EXPANDED:
+ return Qexpanded;
+ case EXTRA_EXPANDED:
+ return Qextra_expanded;
+ case ULTRA_EXPANDED:
+ return Qultra_expanded;
+ }
+
+ emacs_abort ();
+}
+
+static enum haiku_font_width
+haikufont_lisp_to_width (Lisp_Object lisp)
+{
+ if (EQ (lisp, Qultra_condensed))
+ return ULTRA_CONDENSED;
+ if (EQ (lisp, Qextra_condensed))
+ return EXTRA_CONDENSED;
+ if (EQ (lisp, Qcondensed))
+ return CONDENSED;
+ if (EQ (lisp, Qsemi_condensed))
+ return SEMI_CONDENSED;
+ if (EQ (lisp, Qnormal))
+ return NORMAL_WIDTH;
+ if (EQ (lisp, Qexpanded))
+ return EXPANDED;
+ if (EQ (lisp, Qextra_expanded))
+ return EXTRA_EXPANDED;
+ if (EQ (lisp, Qultra_expanded))
+ return ULTRA_EXPANDED;
+ emacs_abort ();
+}
+
+static int
+haikufont_maybe_handle_special_family (Lisp_Object family,
+ struct haiku_font_pattern *ptn)
+{
+ CHECK_SYMBOL (family);
+
+ if (EQ (family, Qmonospace) || EQ (family, Qfixed) ||
+ EQ (family, Qdefault))
+ {
+ BFont_populate_fixed_family (ptn);
+ return 1;
+ }
+ else if (EQ (family, intern ("Sans Serif")))
+ {
+ BFont_populate_plain_family (ptn);
+ return 1;
+ }
+ return 0;
+}
+
+static Lisp_Object
+haikufont_pattern_to_entity (struct haiku_font_pattern *ptn)
+{
+ Lisp_Object ent = font_make_entity ();
+ ASET (ent, FONT_TYPE_INDEX, Qhaiku);
+ ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku);
+ ASET (ent, FONT_FAMILY_INDEX, Qdefault);
+ ASET (ent, FONT_ADSTYLE_INDEX, Qnil);
+ ASET (ent, FONT_REGISTRY_INDEX, Qutf_8);
+ ASET (ent, FONT_SIZE_INDEX, make_fixnum (0));
+ ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+ ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO));
+ FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnormal);
+ FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnormal);
+ FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnormal);
+
+ if (ptn->specified & FSPEC_FAMILY)
+ ASET (ent, FONT_FAMILY_INDEX, intern (ptn->family));
+ else
+ ASET (ent, FONT_FAMILY_INDEX, Qdefault);
+
+ if (ptn->specified & FSPEC_STYLE)
+ ASET (ent, FONT_ADSTYLE_INDEX, intern (ptn->style));
+ else
+ {
+ if (ptn->specified & FSPEC_WEIGHT)
+ FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX,
+ haikufont_weight_to_lisp (ptn->weight));
+ if (ptn->specified & FSPEC_SLANT)
+ FONT_SET_STYLE (ent, FONT_SLANT_INDEX,
+ haikufont_slant_to_lisp (ptn->slant));
+ if (ptn->specified & FSPEC_WIDTH)
+ FONT_SET_STYLE (ent, FONT_WIDTH_INDEX,
+ haikufont_width_to_lisp (ptn->width));
+ }
+
+ if (ptn->specified & FSPEC_SPACING)
+ ASET (ent, FONT_SPACING_INDEX,
+ make_fixnum (ptn->mono_spacing_p ?
+ FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
+ return ent;
+}
+
+static void
+haikufont_spec_or_entity_to_pattern (Lisp_Object ent,
+ int list_p,
+ struct haiku_font_pattern *ptn)
+{
+ Lisp_Object tem;
+ ptn->specified = 0;
+
+ tem = AREF (ent, FONT_ADSTYLE_INDEX);
+ if (!NILP (tem))
+ {
+ ptn->specified |= FSPEC_STYLE;
+ strncpy ((char *) &ptn->style,
+ SSDATA (SYMBOL_NAME (tem)),
+ sizeof ptn->style - 1);
+ }
+
+ tem = FONT_SLANT_SYMBOLIC (ent);
+ if (!NILP (tem))
+ {
+ ptn->specified |= FSPEC_SLANT;
+ ptn->slant = haikufont_lisp_to_slant (tem);
+ }
+
+ tem = FONT_WEIGHT_SYMBOLIC (ent);
+ if (!NILP (tem))
+ {
+ ptn->specified |= FSPEC_WEIGHT;
+ ptn->weight = haikufont_lisp_to_weight (tem);
+ }
+
+ tem = FONT_WIDTH_SYMBOLIC (ent);
+ if (!NILP (tem))
+ {
+ ptn->specified |= FSPEC_WIDTH;
+ ptn->width = haikufont_lisp_to_width (tem);
+ }
+
+ tem = AREF (ent, FONT_SPACING_INDEX);
+ if (FIXNUMP (tem))
+ {
+ ptn->specified |= FSPEC_SPACING;
+ ptn->mono_spacing_p = XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL;
+ }
+
+ tem = AREF (ent, FONT_FAMILY_INDEX);
+ if (!NILP (tem) &&
+ (list_p && !haikufont_maybe_handle_special_family (tem, ptn)))
+ {
+ ptn->specified |= FSPEC_FAMILY;
+ strncpy ((char *) &ptn->family,
+ SSDATA (SYMBOL_NAME (tem)),
+ sizeof ptn->family - 1);
+ }
+
+ tem = assq_no_quit (QCscript, AREF (ent, FONT_EXTRA_INDEX));
+ if (!NILP (tem))
+ {
+ tem = assq_no_quit (XCDR (tem), Vscript_representative_chars);
+
+ if (CONSP (tem) && VECTORP (XCDR (tem)))
+ {
+ tem = XCDR (tem);
+
+ int count = 0;
+
+ for (int j = 0; j < ASIZE (tem); ++j)
+ if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j)))
+ ++count;
+
+ if (count)
+ {
+ ptn->specified |= FSPEC_NEED_ONE_OF;
+ ptn->need_one_of_len = count;
+ ptn->need_one_of = xmalloc (count * sizeof *ptn->need_one_of);
+ count = 0;
+ for (int j = 0; j < ASIZE (tem); ++j)
+ if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j)))
+ {
+ ptn->need_one_of[j] = XFIXNAT (AREF (tem, j));
+ ++count;
+ }
+ }
+ }
+ else if (CONSP (tem) && CONSP (XCDR (tem)))
+ {
+ int count = 0;
+
+ for (Lisp_Object it = XCDR (tem); CONSP (it); it = XCDR (it))
+ if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (it)))
+ ++count;
+
+ if (count)
+ {
+ ptn->specified |= FSPEC_WANTED;
+ ptn->want_chars_len = count;
+ ptn->wanted_chars = xmalloc (count * sizeof *ptn->wanted_chars);
+ count = 0;
+
+ for (tem = XCDR (tem); CONSP (tem); tem = XCDR (tem))
+ if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (tem)))
+ {
+ ptn->wanted_chars[count] = XFIXNAT (XCAR (tem));
+ ++count;
+ }
+ }
+ }
+ }
+
+ tem = assq_no_quit (QClang, AREF (ent, FONT_EXTRA_INDEX));
+ if (CONSP (tem))
+ {
+ tem = XCDR (tem);
+ if (EQ (tem, Qzh))
+ {
+ ptn->specified |= FSPEC_LANGUAGE;
+ ptn->language = LANGUAGE_CN;
+ }
+ else if (EQ (tem, Qko))
+ {
+ ptn->specified |= FSPEC_LANGUAGE;
+ ptn->language = LANGUAGE_KO;
+ }
+ else if (EQ (tem, Qjp))
+ {
+ ptn->specified |= FSPEC_LANGUAGE;
+ ptn->language = LANGUAGE_JP;
+ }
+ }
+
+ tem = AREF (ent, FONT_REGISTRY_INDEX);
+ if (SYMBOLP (tem))
+ haikufont_apply_registry (ptn, tem);
+}
+
+static void
+haikufont_done_with_query_pattern (struct haiku_font_pattern *ptn)
+{
+ if (ptn->specified & FSPEC_WANTED)
+ xfree (ptn->wanted_chars);
+
+ if (ptn->specified & FSPEC_NEED_ONE_OF)
+ xfree (ptn->need_one_of);
+}
+
+static Lisp_Object
+haikufont_match (struct frame *f, Lisp_Object font_spec)
+{
+ block_input ();
+ Lisp_Object tem = Qnil;
+ struct haiku_font_pattern ptn;
+ haikufont_spec_or_entity_to_pattern (font_spec, 0, &ptn);
+ ptn.specified &= ~FSPEC_FAMILY;
+ struct haiku_font_pattern *found = BFont_find (&ptn);
+ haikufont_done_with_query_pattern (&ptn);
+ if (found)
+ {
+ tem = haikufont_pattern_to_entity (found);
+ haiku_font_pattern_free (found);
+ }
+ unblock_input ();
+ return !NILP (tem) ? tem : haikufont_get_fallback_entity ();
+}
+
+static Lisp_Object
+haikufont_list (struct frame *f, Lisp_Object font_spec)
+{
+ block_input ();
+ Lisp_Object lst = Qnil;
+
+ /* Returning irrelevant results on receiving an OTF form will cause
+ fontset.c to loop over and over, making displaying some
+ characters very slow. */
+ Lisp_Object tem = assq_no_quit (QCotf, AREF (font_spec, FONT_EXTRA_INDEX));
+ if (CONSP (tem) && !NILP (XCDR (tem)))
+ {
+ unblock_input ();
+ return Qnil;
+ }
+
+ struct haiku_font_pattern ptn;
+ haikufont_spec_or_entity_to_pattern (font_spec, 1, &ptn);
+ struct haiku_font_pattern *found = BFont_find (&ptn);
+ haikufont_done_with_query_pattern (&ptn);
+ if (found)
+ {
+ for (struct haiku_font_pattern *pt = found;
+ pt; pt = pt->next)
+ lst = Fcons (haikufont_pattern_to_entity (pt), lst);
+ haiku_font_pattern_free (found);
+ }
+ unblock_input ();
+ return lst;
+}
+
+static void
+haiku_bulk_encode (struct haikufont_info *font_info, int block)
+{
+ unsigned short *unichars = xmalloc (0x101 * sizeof (*unichars));
+ unsigned int i, idx;
+
+ block_input ();
+
+ font_info->glyphs[block] = unichars;
+ if (!unichars)
+ emacs_abort ();
+
+ for (idx = block << 8, i = 0; i < 0x100; idx++, i++)
+ unichars[i] = idx;
+ unichars[0x100] = 0;
+
+
+ /* If the font contains the entire block, just store it. */
+ if (!BFont_have_char_block (font_info->be_font,
+ unichars[0], unichars[0xff]))
+ {
+ for (int i = 0; i < 0x100; ++i)
+ if (!BFont_have_char_p (font_info->be_font, unichars[i]))
+ unichars[i] = 0xFFFF;
+ }
+
+ unblock_input ();
+}
+
+static unsigned int
+haikufont_encode_char (struct font *font, int c)
+{
+ struct haikufont_info *font_info = (struct haikufont_info *) font;
+ unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
+ unsigned short g;
+
+ if (c > 0xFFFF)
+ return FONT_INVALID_CODE;
+
+ if (!font_info->glyphs[high])
+ haiku_bulk_encode (font_info, high);
+ g = font_info->glyphs[high][low];
+ return g == 0xFFFF ? FONT_INVALID_CODE : g;
+}
+
+static Lisp_Object
+haikufont_open (struct frame *f, Lisp_Object font_entity, int x)
+{
+ struct haikufont_info *font_info;
+ struct haiku_font_pattern ptn;
+ struct font *font;
+ void *be_font;
+ Lisp_Object font_object;
+ Lisp_Object tem;
+
+ block_input ();
+ if (x <= 0)
+ {
+ /* Get pixel size from frame instead. */
+ tem = get_frame_param (f, Qfontsize);
+ x = NILP (tem) ? 0 : XFIXNAT (tem);
+ }
+
+ haikufont_spec_or_entity_to_pattern (font_entity, 1, &ptn);
+
+ if (BFont_open_pattern (&ptn, &be_font, x))
+ {
+ haikufont_done_with_query_pattern (&ptn);
+ unblock_input ();
+ return Qnil;
+ }
+
+ haikufont_done_with_query_pattern (&ptn);
+
+ font_object = font_make_object (VECSIZE (struct haikufont_info),
+ font_entity, x);
+
+ ASET (font_object, FONT_TYPE_INDEX, Qhaiku);
+ font_info = (struct haikufont_info *) XFONT_OBJECT (font_object);
+ font = (struct font *) font_info;
+
+ if (!font)
+ {
+ unblock_input ();
+ return Qnil;
+ }
+
+ font_info->be_font = be_font;
+ font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
+
+ font->pixel_size = 0;
+ font->driver = &haikufont_driver;
+ font->encoding_charset = -1;
+ font->repertory_charset = -1;
+ font->default_ascent = 0;
+ font->vertical_centering = 0;
+ font->baseline_offset = 0;
+ font->relative_compose = 0;
+
+ font_info->metrics = NULL;
+ font_info->metrics_nrows = 0;
+
+ int px_size, min_width, max_width,
+ avg_width, height, space_width, ascent,
+ descent, underline_pos, underline_thickness;
+
+ BFont_dat (be_font, &px_size, &min_width,
+ &max_width, &avg_width, &height,
+ &space_width, &ascent, &descent,
+ &underline_pos, &underline_thickness);
+
+ font->pixel_size = px_size;
+ font->min_width = min_width;
+ font->max_width = max_width;
+ font->average_width = avg_width;
+ font->height = height;
+ font->space_width = space_width;
+ font->ascent = ascent;
+ font->descent = descent;
+ font->default_ascent = ascent;
+ font->underline_position = underline_pos;
+ font->underline_thickness = underline_thickness;
+
+ font->vertical_centering = 0;
+ font->baseline_offset = 0;
+ font->relative_compose = 0;
+
+ font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
+
+ unblock_input ();
+ return font_object;
+}
+
+static void
+haikufont_close (struct font *font)
+{
+ if (font_data_structures_may_be_ill_formed ())
+ return;
+ struct haikufont_info *info = (struct haikufont_info *) font;
+
+ block_input ();
+ if (info && info->be_font)
+ BFont_close (info->be_font);
+
+ for (int i = 0; i < info->metrics_nrows; i++)
+ if (info->metrics[i])
+ xfree (info->metrics[i]);
+ if (info->metrics)
+ xfree (info->metrics);
+ for (int i = 0; i < 0x100; ++i)
+ if (info->glyphs[i])
+ xfree (info->glyphs[i]);
+ xfree (info->glyphs);
+ unblock_input ();
+}
+
+static void
+haikufont_prepare_face (struct frame *f, struct face *face)
+{
+
+}
+
+static void
+haikufont_glyph_extents (struct font *font, unsigned code,
+ struct font_metrics *metrics)
+{
+ struct haikufont_info *info = (struct haikufont_info *) font;
+
+ struct font_metrics *cache;
+ int row, col;
+
+ row = code / METRICS_NCOLS_PER_ROW;
+ col = code % METRICS_NCOLS_PER_ROW;
+ if (row >= info->metrics_nrows)
+ {
+ info->metrics =
+ xrealloc (info->metrics,
+ sizeof (struct font_metrics *) * (row + 1));
+ memset (info->metrics + info->metrics_nrows, 0,
+ (sizeof (struct font_metrics *)
+ * (row + 1 - info->metrics_nrows)));
+ info->metrics_nrows = row + 1;
+ }
+
+ if (info->metrics[row] == NULL)
+ {
+ struct font_metrics *new;
+ int i;
+
+ new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
+ for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
+ METRICS_SET_STATUS (new + i, METRICS_INVALID);
+ info->metrics[row] = new;
+ }
+ cache = info->metrics[row] + col;
+
+ if (METRICS_STATUS (cache) == METRICS_INVALID)
+ {
+ unsigned char utf8[MAX_MULTIBYTE_LENGTH];
+ memset (utf8, 0, MAX_MULTIBYTE_LENGTH);
+ CHAR_STRING (code, utf8);
+ int advance, lb, rb;
+ BFont_char_bounds (info->be_font, (const char *) utf8, &advance, &lb, &rb);
+
+ cache->lbearing = lb;
+ cache->rbearing = rb;
+ cache->width = advance;
+ cache->ascent = font->ascent;
+ cache->descent = font->descent;
+ }
+
+ if (metrics)
+ *metrics = *cache;
+}
+
+static void
+haikufont_text_extents (struct font *font, const unsigned int *code,
+ int nglyphs, struct font_metrics *metrics)
+{
+ int totalwidth = 0;
+ memset (metrics, 0, sizeof (struct font_metrics));
+
+ block_input ();
+ for (int i = 0; i < nglyphs; i++)
+ {
+ struct font_metrics m;
+ haikufont_glyph_extents (font, code[i], &m);
+ if (metrics)
+ {
+ if (totalwidth + m.lbearing < metrics->lbearing)
+ metrics->lbearing = totalwidth + m.lbearing;
+ if (totalwidth + m.rbearing > metrics->rbearing)
+ metrics->rbearing = totalwidth + m.rbearing;
+ if (m.ascent > metrics->ascent)
+ metrics->ascent = m.ascent;
+ if (m.descent > metrics->descent)
+ metrics->descent = m.descent;
+ }
+ totalwidth += m.width;
+ }
+
+ unblock_input ();
+
+ if (metrics)
+ metrics->width = totalwidth;
+}
+
+static Lisp_Object
+haikufont_shape (Lisp_Object lgstring, Lisp_Object direction)
+{
+ struct haikufont_info *font =
+ (struct haikufont_info *) CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
+ int *advance, *lb, *rb;
+ ptrdiff_t glyph_len, len, i, b_len;
+ Lisp_Object tem;
+ char *b;
+ uint32_t *mb_buf;
+
+ glyph_len = LGSTRING_GLYPH_LEN (lgstring);
+ for (i = 0; i < glyph_len; ++i)
+ {
+ tem = LGSTRING_GLYPH (lgstring, i);
+
+ if (NILP (tem))
+ break;
+ }
+
+ len = i;
+
+ if (INT_MAX / 2 < len)
+ memory_full (SIZE_MAX);
+
+ block_input ();
+
+ b_len = 0;
+ b = xmalloc (b_len);
+ mb_buf = alloca (len * sizeof *mb_buf);
+
+ for (i = b_len; i < len; ++i)
+ {
+ uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
+ mb_buf[i] = c;
+ unsigned char mb[MAX_MULTIBYTE_LENGTH];
+ int slen = CHAR_STRING (c, mb);
+
+ b = xrealloc (b, b_len = (b_len + slen));
+ if (len == 1)
+ b[b_len - slen] = mb[0];
+ else
+ memcpy (b + b_len - slen, mb, slen);
+ }
+
+ advance = alloca (len * sizeof *advance);
+ lb = alloca (len * sizeof *lb);
+ rb = alloca (len * sizeof *rb);
+
+ eassert (font->be_font);
+ BFont_nchar_bounds (font->be_font, b, advance, lb, rb, len);
+ xfree (b);
+
+ for (i = 0; i < len; ++i)
+ {
+ tem = LGSTRING_GLYPH (lgstring, i);
+ if (NILP (tem))
+ {
+ tem = LGLYPH_NEW ();
+ LGSTRING_SET_GLYPH (lgstring, i, tem);
+ }
+
+ LGLYPH_SET_FROM (tem, i);
+ LGLYPH_SET_TO (tem, i);
+ LGLYPH_SET_CHAR (tem, mb_buf[i]);
+ LGLYPH_SET_CODE (tem, mb_buf[i]);
+
+ LGLYPH_SET_WIDTH (tem, advance[i]);
+ LGLYPH_SET_LBEARING (tem, lb[i]);
+ LGLYPH_SET_RBEARING (tem, rb[i]);
+ LGLYPH_SET_ASCENT (tem, font->font.ascent);
+ LGLYPH_SET_DESCENT (tem, font->font.descent);
+ }
+
+ unblock_input ();
+
+ return make_fixnum (len);
+}
+
+static int
+haikufont_draw (struct glyph_string *s, int from, int to,
+ int x, int y, bool with_background)
+{
+ struct frame *f = s->f;
+ struct face *face = s->face;
+ struct font_info *info = (struct font_info *) s->font;
+ unsigned char mb[MAX_MULTIBYTE_LENGTH];
+ void *view = FRAME_HAIKU_VIEW (f);
+
+ block_input ();
+ prepare_face_for_display (s->f, face);
+
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ if (with_background)
+ {
+ int height = FONT_HEIGHT (s->font), ascent = FONT_BASE (s->font);
+
+ /* Font's global height and ascent values might be
+ preposterously large for some fonts. We fix here the case
+ when those fonts are used for display of glyphless
+ characters, because drawing background with font dimensions
+ in those cases makes the display illegible. There's only one
+ more call to the draw method with with_background set to
+ true, and that's in x_draw_glyph_string_foreground, when
+ drawing the cursor, where we have no such heuristics
+ available. FIXME. */
+ if (s->first_glyph->type == GLYPHLESS_GLYPH
+ && (s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE
+ || s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM))
+ height = ascent =
+ s->first_glyph->slice.glyphless.lower_yoff
+ - s->first_glyph->slice.glyphless.upper_yoff;
+
+ BView_SetHighColor (view, s->hl == DRAW_CURSOR ?
+ FRAME_CURSOR_COLOR (s->f).pixel : face->background);
+
+ BView_FillRectangle (view, x, y - ascent, s->width, height);
+ s->background_filled_p = 1;
+ }
+
+ if (s->left_overhang && s->clip_head && !s->for_overlaps)
+ {
+ /* XXX: Why is this neccessary? */
+ BView_ClipToRect (view, s->clip_head->x, 0,
+ FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
+ }
+
+ if (s->hl == DRAW_CURSOR)
+ BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
+ else
+ BView_SetHighColor (view, face->foreground);
+
+ BView_MovePenTo (view, x, y);
+ BView_SetFont (view, ((struct haikufont_info *) info)->be_font);
+
+ if (from == to)
+ {
+ int len = CHAR_STRING (s->char2b[from], mb);
+ BView_DrawString (view, (char *) mb, len);
+ }
+ else
+ {
+ ptrdiff_t b_len = 0;
+ char *b = xmalloc (b_len);
+
+ for (int idx = from; idx < to; ++idx)
+ {
+ int len = CHAR_STRING (s->char2b[idx], mb);
+ b = xrealloc (b, b_len = (b_len + len));
+ if (len == 1)
+ b[b_len - len] = mb[0];
+ else
+ memcpy (b + b_len - len, mb, len);
+ }
+
+ BView_DrawString (view, b, b_len);
+ xfree (b);
+ }
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+ unblock_input ();
+ return 1;
+}
+
+struct font_driver const haikufont_driver =
+ {
+ .type = LISPSYM_INITIALLY (Qhaiku),
+ .case_sensitive = true,
+ .get_cache = haikufont_get_cache,
+ .list = haikufont_list,
+ .match = haikufont_match,
+ .draw = haikufont_draw,
+ .open_font = haikufont_open,
+ .close_font = haikufont_close,
+ .prepare_face = haikufont_prepare_face,
+ .encode_char = haikufont_encode_char,
+ .text_extents = haikufont_text_extents,
+ .shape = haikufont_shape
+ };
+
+void
+syms_of_haikufont (void)
+{
+ DEFSYM (Qfontsize, "fontsize");
+ DEFSYM (Qfixed, "fixed");
+ DEFSYM (Qplain, "plain");
+ DEFSYM (Qultra_light, "ultra-light");
+ DEFSYM (Qthin, "thin");
+ DEFSYM (Qreverse_italic, "reverse-italic");
+ DEFSYM (Qreverse_oblique, "reverse-oblique");
+ DEFSYM (Qmonospace, "monospace");
+ DEFSYM (Qultra_condensed, "ultra-condensed");
+ DEFSYM (Qextra_condensed, "extra-condensed");
+ DEFSYM (Qcondensed, "condensed");
+ DEFSYM (Qsemi_condensed, "semi-condensed");
+ DEFSYM (Qsemi_expanded, "semi-expanded");
+ DEFSYM (Qexpanded, "expanded");
+ DEFSYM (Qextra_expanded, "extra-expanded");
+ DEFSYM (Qultra_expanded, "ultra-expanded");
+ DEFSYM (Qzh, "zh");
+ DEFSYM (Qko, "ko");
+ DEFSYM (Qjp, "jp");
+
+ font_cache = list (Qnil);
+ staticpro (&font_cache);
+}
diff --git a/src/haikugui.h b/src/haikugui.h
new file mode 100644
index 0000000000..cfc693fb55
--- /dev/null
+++ b/src/haikugui.h
@@ -0,0 +1,106 @@
+/* Haiku window system support
+ 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/>. */
+
+#ifndef _HAIKU_GUI_H_
+#define _HAIKU_GUI_H_
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif
+
+typedef struct haiku_char_struct
+{
+ int rbearing;
+ int lbearing;
+ int width;
+ int ascent;
+ int descent;
+} XCharStruct;
+
+struct haiku_rect
+{
+ int x, y;
+ int width, height;
+};
+
+typedef void *haiku;
+
+typedef haiku Emacs_Pixmap;
+typedef haiku Emacs_Window;
+typedef haiku Emacs_Cursor;
+typedef haiku Drawable;
+
+#define NativeRectangle struct haiku_rect
+#define CONVERT_TO_EMACS_RECT(xr, nr) \
+ ((xr).x = (nr).x, \
+ (xr).y = (nr).y, \
+ (xr).width = (nr).width, \
+ (xr).height = (nr).height)
+
+#define CONVERT_FROM_EMACS_RECT(xr, nr) \
+ ((nr).x = (xr).x, \
+ (nr).y = (xr).y, \
+ (nr).width = (xr).width, \
+ (nr).height = (xr).height)
+
+#define STORE_NATIVE_RECT(nr, px, py, pwidth, pheight) \
+ ((nr).x = (px), \
+ (nr).y = (py), \
+ (nr).width = (pwidth), \
+ (nr).height = (pheight))
+
+#define ForgetGravity 0
+#define NorthWestGravity 1
+#define NorthGravity 2
+#define NorthEastGravity 3
+#define WestGravity 4
+#define CenterGravity 5
+#define EastGravity 6
+#define SouthWestGravity 7
+#define SouthGravity 8
+#define SouthEastGravity 9
+#define StaticGravity 10
+
+#define NoValue 0x0000
+#define XValue 0x0001
+#define YValue 0x0002
+#define WidthValue 0x0004
+#define HeightValue 0x0008
+#define AllValues 0x000F
+#define XNegative 0x0010
+#define YNegative 0x0020
+
+#define USPosition (1L << 0) /* user specified x, y */
+#define USSize (1L << 1) /* user specified width, height */
+#define PPosition (1L << 2) /* program specified position */
+#define PSize (1L << 3) /* program specified size */
+#define PMinSize (1L << 4) /* program specified minimum size */
+#define PMaxSize (1L << 5) /* program specified maximum size */
+#define PResizeInc (1L << 6) /* program specified resize increments */
+#define PAspect (1L << 7) /* program specified min, max aspect ratios */
+#define PBaseSize (1L << 8) /* program specified base for incrementing */
+#define PWinGravity (1L << 9) /* program specified window gravity */
+
+typedef haiku Window;
+typedef int Display;
+
+#ifdef _cplusplus
+};
+#endif
+#endif /* _HAIKU_GUI_H_ */
diff --git a/src/haikuimage.c b/src/haikuimage.c
new file mode 100644
index 0000000000..138e5b84e6
--- /dev/null
+++ b/src/haikuimage.c
@@ -0,0 +1,109 @@
+/* Haiku window system support.
+ 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 "lisp.h"
+#include "dispextern.h"
+#include "haikuterm.h"
+#include "coding.h"
+
+#include "haiku_support.h"
+
+bool
+haiku_can_use_native_image_api (Lisp_Object type)
+{
+ const char *mime_type = NULL;
+
+ if (EQ (type, Qnative_image))
+ return 1;
+
+#ifdef HAVE_RSVG
+ if (EQ (type, Qsvg))
+ return 0;
+#endif
+
+ if (EQ (type, Qjpeg))
+ mime_type = "image/jpeg";
+ else if (EQ (type, Qpng))
+ mime_type = "image/png";
+ else if (EQ (type, Qgif))
+ mime_type = "image/gif";
+ else if (EQ (type, Qtiff))
+ mime_type = "image/tiff";
+ else if (EQ (type, Qbmp))
+ mime_type = "image/bmp";
+ else if (EQ (type, Qsvg))
+ mime_type = "image/svg";
+ else if (EQ (type, Qpbm))
+ mime_type = "image/pbm";
+
+ if (!mime_type)
+ return 0;
+
+ return be_can_translate_type_to_bitmap_p (mime_type);
+}
+
+extern int
+haiku_load_image (struct frame *f, struct image *img,
+ Lisp_Object spec_file, Lisp_Object spec_data)
+{
+ eassert (valid_image_p (img->spec));
+
+ void *pixmap = NULL;
+
+ if (STRINGP (spec_file))
+ {
+ pixmap = be_translate_bitmap_from_file_name
+ (SSDATA (ENCODE_UTF_8 (spec_file)));
+ }
+ else if (STRINGP (spec_data))
+ {
+ pixmap = be_translate_bitmap_from_memory
+ (SSDATA (spec_data), SBYTES (spec_data));
+ }
+
+ void *conv = NULL;
+
+ if (!pixmap || !BBitmap_convert (pixmap, &conv))
+ {
+ add_to_log ("Unable to load image %s", img->spec);
+ return 0;
+ }
+
+ if (conv)
+ {
+ BBitmap_free (pixmap);
+ pixmap = conv;
+ }
+
+ int left, top, right, bottom, stride, mono_p;
+ BBitmap_dimensions (pixmap, &left, &top, &right, &bottom, &stride, &mono_p);
+
+ img->width = (1 + right - left);
+ img->height = (1 + bottom - top);
+ img->pixmap = pixmap;
+
+ return 1;
+}
+
+void
+syms_of_haikuimage (void)
+{
+ DEFSYM (Qbmp, "bmp");
+}
diff --git a/src/haikumenu.c b/src/haikumenu.c
new file mode 100644
index 0000000000..698da9d639
--- /dev/null
+++ b/src/haikumenu.c
@@ -0,0 +1,656 @@
+/* Haiku window system support
+ 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 "lisp.h"
+#include "frame.h"
+#include "keyboard.h"
+#include "menu.h"
+#include "buffer.h"
+#include "blockinput.h"
+
+#include "haikuterm.h"
+#include "haiku_support.h"
+
+static Lisp_Object *volatile menu_item_selection;
+
+int popup_activated_p = 0;
+
+struct submenu_stack_cell
+{
+ void *parent_menu;
+ void *pane;
+};
+
+static void
+digest_menu_items (void *first_menu, int start, int menu_items_used,
+ int mbar_p)
+{
+ void **menus, **panes;
+ ssize_t menu_len = (menu_items_used + 1 - start) * sizeof *menus;
+ ssize_t pane_len = (menu_items_used + 1 - start) * sizeof *panes;
+
+ menus = alloca (menu_len);
+ panes = alloca (pane_len);
+
+ int i = start, menu_depth = 0;
+
+ memset (menus, 0, menu_len);
+ memset (panes, 0, pane_len);
+
+ void *menu = first_menu;
+
+ menus[0] = first_menu;
+
+ void *window = NULL;
+ if (FRAMEP (Vmenu_updating_frame) &&
+ FRAME_LIVE_P (XFRAME (Vmenu_updating_frame)) &&
+ FRAME_HAIKU_P (XFRAME (Vmenu_updating_frame)))
+ window = FRAME_HAIKU_WINDOW (XFRAME (Vmenu_updating_frame));
+
+ while (i < menu_items_used)
+ {
+ if (NILP (AREF (menu_items, i)))
+ {
+ menus[++menu_depth] = menu;
+ i++;
+ }
+ else if (EQ (AREF (menu_items, i), Qlambda))
+ {
+ panes[menu_depth] = NULL;
+ menu = panes[--menu_depth] ? panes[menu_depth] : menus[menu_depth];
+ i++;
+ }
+ else if (EQ (AREF (menu_items, i), Qquote))
+ i += 1;
+ else if (EQ (AREF (menu_items, i), Qt))
+ {
+ Lisp_Object pane_name, prefix;
+ const char *pane_string;
+
+ if (menu_items_n_panes == 1)
+ {
+ i += MENU_ITEMS_PANE_LENGTH;
+ continue;
+ }
+
+ pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
+ prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
+
+ if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+ {
+ pane_name = ENCODE_UTF_8 (pane_name);
+ ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+ }
+
+ pane_string = (NILP (pane_name)
+ ? "" : SSDATA (pane_name));
+ if (!NILP (prefix))
+ pane_string++;
+
+ if (strcmp (pane_string, ""))
+ {
+ panes[menu_depth] =
+ menu = BMenu_new_submenu (menus[menu_depth], pane_string, 1);
+ }
+
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ else
+ {
+ Lisp_Object item_name, enable, descrip, def, selected, help;
+ item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+ enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
+ descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
+ def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
+ selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
+ help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
+
+ if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
+ {
+ item_name = ENCODE_UTF_8 (item_name);
+ ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
+ }
+
+ if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+ {
+ descrip = ENCODE_UTF_8 (descrip);
+ ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
+ }
+
+ if (STRINGP (help) && STRING_MULTIBYTE (help))
+ {
+ help = ENCODE_UTF_8 (help);
+ ASET (menu_items, i + MENU_ITEMS_ITEM_HELP, help);
+ }
+
+ if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used &&
+ NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH)))
+ menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable));
+ else if (NILP (def) && menu_separator_name_p (SSDATA (item_name)))
+ BMenu_add_separator (menu);
+ else if (!mbar_p)
+ BMenu_add_item (menu, SSDATA (item_name),
+ !NILP (def) ? aref_addr (menu_items, i) : NULL,
+ !NILP (enable), !NILP (selected), 0, window,
+ !NILP (descrip) ? SSDATA (descrip) : NULL,
+ STRINGP (help) ? SSDATA (help) : NULL);
+ else
+ BMenu_add_item (menu, SSDATA (item_name),
+ !NILP (def) ? (void *) (intptr_t) i : NULL,
+ !NILP (enable), !NILP (selected), 1, window,
+ !NILP (descrip) ? SSDATA (descrip) : NULL,
+ STRINGP (help) ? SSDATA (help) : NULL);
+
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+}
+
+static Lisp_Object
+haiku_dialog_show (struct frame *f, Lisp_Object title,
+ Lisp_Object header, const char **error_name)
+{
+ int i, nb_buttons = 0;
+
+ *error_name = NULL;
+
+ if (menu_items_n_panes > 1)
+ {
+ *error_name = "Multiple panes in dialog box";
+ return Qnil;
+ }
+
+ Lisp_Object pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
+ i = MENU_ITEMS_PANE_LENGTH;
+
+ if (STRING_MULTIBYTE (pane_name))
+ pane_name = ENCODE_UTF_8 (pane_name);
+
+ block_input ();
+ void *alert = BAlert_new (SSDATA (pane_name), NILP (header) ? HAIKU_INFO_ALERT :
+ HAIKU_IDEA_ALERT);
+
+ Lisp_Object vals[10];
+
+ while (i < menu_items_used)
+ {
+ Lisp_Object item_name, enable, descrip, value;
+ item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+ enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
+ descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
+ value = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
+
+ if (NILP (item_name))
+ {
+ BAlert_delete (alert);
+ *error_name = "Submenu in dialog items";
+ unblock_input ();
+ return Qnil;
+ }
+
+ if (EQ (item_name, Qquote))
+ {
+ i++;
+ }
+
+ if (nb_buttons >= 9)
+ {
+ BAlert_delete (alert);
+ *error_name = "Too many dialog items";
+ unblock_input ();
+ return Qnil;
+ }
+
+ if (STRING_MULTIBYTE (item_name))
+ item_name = ENCODE_UTF_8 (item_name);
+ if (!NILP (descrip) && STRING_MULTIBYTE (descrip))
+ descrip = ENCODE_UTF_8 (descrip);
+
+ void *button = BAlert_add_button (alert, SSDATA (item_name));
+
+ BButton_set_enabled (button, !NILP (enable));
+ if (!NILP (descrip))
+ BView_set_tooltip (button, SSDATA (descrip));
+
+ vals[nb_buttons] = value;
+ ++nb_buttons;
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+
+ int32_t val = BAlert_go (alert);
+ unblock_input ();
+
+ if (val < 0)
+ quit ();
+ else
+ return vals[val];
+
+ return Qnil;
+}
+
+Lisp_Object
+haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
+{
+ Lisp_Object title;
+ const char *error_name = NULL;
+ Lisp_Object selection;
+ ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
+ check_window_system (f);
+
+ /* Decode the dialog items from what was specified. */
+ title = Fcar (contents);
+ CHECK_STRING (title);
+ record_unwind_protect_void (unuse_menu_items);
+
+ if (NILP (Fcar (Fcdr (contents))))
+ /* No buttons specified, add an "Ok" button so users can pop down
+ the dialog. Also, the lesstif/motif version crashes if there are
+ no buttons. */
+ contents = list2 (title, Fcons (build_string ("Ok"), Qt));
+
+ list_of_panes (list1 (contents));
+
+ /* Display them in a dialog box. */
+ block_input ();
+ selection = haiku_dialog_show (f, title, header, &error_name);
+ unblock_input ();
+
+ unbind_to (specpdl_count, Qnil);
+ discard_menu_items ();
+
+ if (error_name)
+ error ("%s", error_name);
+ return selection;
+}
+
+Lisp_Object
+haiku_menu_show (struct frame *f, int x, int y, int menuflags,
+ Lisp_Object title, const char **error_name)
+{
+ int i = 0, submenu_depth = 0;
+ void *view = FRAME_HAIKU_VIEW (f);
+ void *menu;
+
+ Lisp_Object *subprefix_stack =
+ alloca (menu_items_used * sizeof (Lisp_Object));
+
+ eassert (FRAME_HAIKU_P (f));
+
+ *error_name = NULL;
+
+ if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
+ {
+ *error_name = "Empty menu";
+ return Qnil;
+ }
+
+ block_input ();
+ if (STRINGP (title) && STRING_MULTIBYTE (title))
+ title = ENCODE_UTF_8 (title);
+
+ menu = BPopUpMenu_new (STRINGP (title) ? SSDATA (title) : NULL);
+ if (STRINGP (title))
+ {
+ BMenu_add_title (menu, SSDATA (title));
+ BMenu_add_separator (menu);
+ }
+ digest_menu_items (menu, 0, menu_items_used, 0);
+ BView_convert_to_screen (view, &x, &y);
+ unblock_input ();
+
+ menu_item_selection = BMenu_run (menu, x, y);
+
+ FRAME_DISPLAY_INFO (f)->grabbed = 0;
+
+ if (menu_item_selection)
+ {
+ Lisp_Object prefix, entry;
+
+ prefix = entry = Qnil;
+ i = 0;
+ while (i < menu_items_used)
+ {
+ if (NILP (AREF (menu_items, i)))
+ {
+ subprefix_stack[submenu_depth++] = prefix;
+ prefix = entry;
+ i++;
+ }
+ else if (EQ (AREF (menu_items, i), Qlambda))
+ {
+ prefix = subprefix_stack[--submenu_depth];
+ i++;
+ }
+ else if (EQ (AREF (menu_items, i), Qt))
+ {
+ prefix
+ = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
+ i += MENU_ITEMS_PANE_LENGTH;
+ }
+ /* Ignore a nil in the item list.
+ It's meaningful only for dialog boxes. */
+ else if (EQ (AREF (menu_items, i), Qquote))
+ i += 1;
+ else
+ {
+ entry
+ = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
+ if (menu_item_selection == aref_addr (menu_items, i))
+ {
+ if (menuflags & MENU_KEYMAPS)
+ {
+ int j;
+
+ entry = list1 (entry);
+ if (!NILP (prefix))
+ entry = Fcons (prefix, entry);
+ for (j = submenu_depth - 1; j >= 0; j--)
+ if (!NILP (subprefix_stack[j]))
+ entry = Fcons (subprefix_stack[j], entry);
+ }
+ BPopUpMenu_delete (menu);
+ return entry;
+ }
+ i += MENU_ITEMS_ITEM_LENGTH;
+ }
+ }
+ }
+ else if (!(menuflags & MENU_FOR_CLICK))
+ {
+ BPopUpMenu_delete (menu);
+ quit ();
+ }
+ BPopUpMenu_delete (menu);
+ return Qnil;
+}
+
+void
+free_frame_menubar (struct frame *f)
+{
+ FRAME_MENU_BAR_LINES (f) = 0;
+ FRAME_MENU_BAR_HEIGHT (f) = 0;
+ FRAME_EXTERNAL_MENU_BAR (f) = 0;
+
+ block_input ();
+ void *mbar = FRAME_HAIKU_MENU_BAR (f);
+ if (mbar)
+ BMenuBar_delete (mbar);
+ if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
+ --popup_activated_p;
+ FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0;
+ unblock_input ();
+
+ adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
+}
+
+void
+initialize_frame_menubar (struct frame *f)
+{
+ /* This function is called before the first chance to redisplay
+ the frame. It has to be, so the frame will have the right size. */
+ fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
+ set_frame_menubar (f, true);
+}
+
+void
+set_frame_menubar (struct frame *f, bool deep_p)
+{
+ void *mbar = FRAME_HAIKU_MENU_BAR (f);
+ void *view = FRAME_HAIKU_VIEW (f);
+
+ int first_time_p = 0;
+
+ if (!mbar)
+ {
+ mbar = FRAME_HAIKU_MENU_BAR (f) = BMenuBar_new (view);
+ first_time_p = 1;
+ }
+
+ Lisp_Object items;
+ struct buffer *prev = current_buffer;
+ Lisp_Object buffer;
+ ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+ int previous_menu_items_used = f->menu_bar_items_used;
+ Lisp_Object *previous_items
+ = alloca (previous_menu_items_used * sizeof *previous_items);
+
+ XSETFRAME (Vmenu_updating_frame, f);
+
+ if (!deep_p)
+ {
+ FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 0;
+ items = FRAME_MENU_BAR_ITEMS (f);
+ Lisp_Object string;
+
+ block_input ();
+ int count = BMenu_count_items (mbar);
+
+ int i;
+ for (i = 0; i < ASIZE (items); i += 4)
+ {
+ string = AREF (items, i + 1);
+
+ if (!STRINGP (string))
+ break;
+
+ if (STRING_MULTIBYTE (string))
+ string = ENCODE_UTF_8 (string);
+
+ if (i / 4 < count)
+ {
+ void *it = BMenu_item_at (mbar, i / 4);
+ BMenu_item_set_label (it, SSDATA (string));
+ }
+ else
+ BMenu_new_menu_bar_submenu (mbar, SSDATA (string));
+ }
+
+ if (i / 4 < count)
+ BMenu_delete_from (mbar, i / 4, count - i / 4 + 1);
+ unblock_input ();
+
+ f->menu_bar_items_used = 0;
+ }
+ else
+ {
+ /* If we are making a new widget, its contents are empty,
+ do always reinitialize them. */
+ if (first_time_p)
+ previous_menu_items_used = 0;
+ buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
+ specbind (Qinhibit_quit, Qt);
+ /* Don't let the debugger step into this code
+ because it is not reentrant. */
+ specbind (Qdebug_on_next_call, Qnil);
+
+ record_unwind_save_match_data ();
+ if (NILP (Voverriding_local_map_menu_flag))
+ {
+ specbind (Qoverriding_terminal_local_map, Qnil);
+ specbind (Qoverriding_local_map, Qnil);
+ }
+
+ set_buffer_internal_1 (XBUFFER (buffer));
+
+ /* Run the Lucid hook. */
+ safe_run_hooks (Qactivate_menubar_hook);
+
+ /* If it has changed current-menubar from previous value,
+ really recompute the menubar from the value. */
+ if (! NILP (Vlucid_menu_bar_dirty_flag))
+ call0 (Qrecompute_lucid_menubar);
+ safe_run_hooks (Qmenu_bar_update_hook);
+ fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
+
+ items = FRAME_MENU_BAR_ITEMS (f);
+
+ /* Save the frame's previous menu bar contents data. */
+ if (previous_menu_items_used)
+ memcpy (previous_items, xvector_contents (f->menu_bar_vector),
+ previous_menu_items_used * word_size);
+
+ /* Fill in menu_items with the current menu bar contents.
+ This can evaluate Lisp code. */
+ save_menu_items ();
+ menu_items = f->menu_bar_vector;
+ menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
+ init_menu_items ();
+ int i;
+ int count = BMenu_count_items (mbar);
+ int subitems = ASIZE (items) / 4;
+
+ int *submenu_start, *submenu_end, *submenu_n_panes;
+ Lisp_Object *submenu_names;
+
+ submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
+ submenu_end = alloca (subitems * sizeof *submenu_end);
+ submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
+ submenu_names = alloca (subitems * sizeof (Lisp_Object));
+
+ for (i = 0; i < subitems; ++i)
+ {
+ Lisp_Object key, string, maps;
+
+ key = AREF (items, i * 4);
+ string = AREF (items, i * 4 + 1);
+ maps = AREF (items, i * 4 + 2);
+
+ if (NILP (string))
+ break;
+
+ if (STRINGP (string) && STRING_MULTIBYTE (string))
+ string = ENCODE_UTF_8 (string);
+
+ submenu_start[i] = menu_items_used;
+ menu_items_n_panes = 0;
+ parse_single_submenu (key, string, maps);
+ submenu_n_panes[i] = menu_items_n_panes;
+ submenu_end[i] = menu_items_used;
+ submenu_names[i] = string;
+ }
+ finish_menu_items ();
+ submenu_start[i] = -1;
+
+ block_input ();
+ for (i = 0; submenu_start[i] >= 0; ++i)
+ {
+ void *mn = NULL;
+ if (i < count)
+ mn = BMenu_item_get_menu (BMenu_item_at (mbar, i));
+ if (mn)
+ BMenu_delete_all (mn);
+ else
+ mn = BMenu_new_menu_bar_submenu (mbar, SSDATA (submenu_names[i]));
+
+ menu_items_n_panes = submenu_n_panes[i];
+ digest_menu_items (mn, submenu_start[i], submenu_end[i], 1);
+ }
+ unblock_input ();
+
+ set_buffer_internal_1 (prev);
+
+ FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 1;
+ fset_menu_bar_vector (f, menu_items);
+ f->menu_bar_items_used = menu_items_used;
+ }
+ unbind_to (specpdl_count, Qnil);
+}
+
+void
+run_menu_bar_help_event (struct frame *f, int mb_idx)
+{
+ Lisp_Object frame;
+ Lisp_Object vec;
+ Lisp_Object help;
+
+ block_input ();
+ if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
+ {
+ unblock_input ();
+ return;
+ }
+
+ XSETFRAME (frame, f);
+
+ if (mb_idx < 0)
+ {
+ kbd_buffer_store_help_event (frame, Qnil);
+ unblock_input ();
+ return;
+ }
+
+ vec = f->menu_bar_vector;
+ if (mb_idx >= ASIZE (vec))
+ emacs_abort ();
+
+ help = AREF (vec, mb_idx + MENU_ITEMS_ITEM_HELP);
+ if (STRINGP (help) || NILP (help))
+ kbd_buffer_store_help_event (frame, help);
+ unblock_input ();
+}
+
+DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p,
+ 0, 0, 0, doc: /* SKIP: real doc in xmenu.c. */)
+ (void)
+{
+ return popup_activated_p ? Qt : Qnil;
+}
+
+DEFUN ("haiku-menu-bar-open", Fhaiku_menu_bar_open, Shaiku_menu_bar_open, 0, 1, "i",
+ doc: /* Show the menu bar in FRAME.
+
+Move the mouse pointer onto the first element of FRAME's menu bar, and
+cause it to be opened. If FRAME is nil or not given, use the selected
+frame. If FRAME has no menu bar, a pop-up is displayed at the position
+of the last non-menu event instead. */)
+ (Lisp_Object frame)
+{
+ struct frame *f = decode_window_system_frame (frame);
+
+ if (FRAME_EXTERNAL_MENU_BAR (f))
+ {
+ if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
+ set_frame_menubar (f, 1);
+ }
+ else
+ {
+ return call2 (Qpopup_menu, call0 (Qmouse_menu_bar_map),
+ last_nonmenu_event);
+ }
+
+ block_input ();
+ BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f));
+ unblock_input ();
+
+ return Qnil;
+}
+
+void
+syms_of_haikumenu (void)
+{
+ DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
+ DEFSYM (Qpopup_menu, "popup-menu");
+ DEFSYM (Qmouse_menu_bar_map, "mouse-menu-bar-map");
+
+ defsubr (&Smenu_or_popup_active_p);
+ defsubr (&Shaiku_menu_bar_open);
+ return;
+}
diff --git a/src/haikuselect.c b/src/haikuselect.c
new file mode 100644
index 0000000000..3f0441e077
--- /dev/null
+++ b/src/haikuselect.c
@@ -0,0 +1,134 @@
+/* Haiku window system selection support.
+ 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 "lisp.h"
+#include "blockinput.h"
+#include "coding.h"
+#include "haikuselect.h"
+#include "haikuterm.h"
+
+DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data,
+ 2, 2, 0,
+ doc: /* Retrieve content typed as NAME from the clipboard
+CLIPBOARD. CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or
+`CLIPBOARD'. NAME is a MIME type denoting the type of the data to
+fetch. */)
+ (Lisp_Object clipboard, Lisp_Object name)
+{
+ CHECK_SYMBOL (clipboard);
+ CHECK_STRING (name);
+ char *dat;
+ ssize_t len;
+
+ block_input ();
+ if (EQ (clipboard, QPRIMARY))
+ dat = BClipboard_find_primary_selection_data (SSDATA (name), &len);
+ else if (EQ (clipboard, QSECONDARY))
+ dat = BClipboard_find_secondary_selection_data (SSDATA (name), &len);
+ else if (EQ (clipboard, QCLIPBOARD))
+ dat = BClipboard_find_system_data (SSDATA (name), &len);
+ else
+ {
+ unblock_input ();
+ signal_error ("Bad clipboard", clipboard);
+ }
+ unblock_input ();
+
+ if (!dat)
+ return Qnil;
+
+ Lisp_Object str = make_unibyte_string (dat, len);
+ Lisp_Object lispy_type = Qnil;
+
+ if (!strcmp (SSDATA (name), "text/utf-8") ||
+ !strcmp (SSDATA (name), "text/plain"))
+ {
+ if (string_ascii_p (str))
+ lispy_type = QSTRING;
+ else
+ lispy_type = QUTF8_STRING;
+ }
+
+ if (!NILP (lispy_type))
+ Fput_text_property (make_fixnum (0), make_fixnum (len),
+ Qforeign_selection, lispy_type, str);
+
+ block_input ();
+ BClipboard_free_data (dat);
+ unblock_input ();
+
+ return str;
+}
+
+DEFUN ("haiku-selection-put", Fhaiku_selection_put, Shaiku_selection_put,
+ 3, 3, 0,
+ doc: /* Add or remove content from the clipboard CLIPBOARD.
+CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or `CLIPBOARD'. NAME
+is a MIME type denoting the type of the data to add. DATA is the
+string that will be placed in the clipboard, or nil if the content is
+to be removed. If NAME is the string `text/utf-8' or the string
+`text/plain', encode it as UTF-8 before storing it into the
+clipboard. */)
+ (Lisp_Object clipboard, Lisp_Object name, Lisp_Object data)
+{
+ CHECK_SYMBOL (clipboard);
+ CHECK_STRING (name);
+ if (!NILP (data))
+ CHECK_STRING (data);
+
+ block_input ();
+ /* It seems that Haiku applications counter-intuitively expect
+ UTF-8 data in both text/utf-8 and text/plain. */
+ if (!NILP (data) && STRING_MULTIBYTE (data) &&
+ (!strcmp (SSDATA (name), "text/utf-8") ||
+ !strcmp (SSDATA (name), "text/plain")))
+ data = ENCODE_UTF_8 (data);
+
+ char *dat = !NILP (data) ? SSDATA (data) : NULL;
+ ptrdiff_t len = !NILP (data) ? SBYTES (data) : 0;
+
+ if (EQ (clipboard, QPRIMARY))
+ BClipboard_set_primary_selection_data (SSDATA (name), dat, len);
+ else if (EQ (clipboard, QSECONDARY))
+ BClipboard_set_secondary_selection_data (SSDATA (name), dat, len);
+ else if (EQ (clipboard, QCLIPBOARD))
+ BClipboard_set_system_data (SSDATA (name), dat, len);
+ else
+ {
+ unblock_input ();
+ signal_error ("Bad clipboard", clipboard);
+ }
+ unblock_input ();
+
+ return Qnil;
+}
+
+void
+syms_of_haikuselect (void)
+{
+ DEFSYM (QSECONDARY, "SECONDARY");
+ DEFSYM (QCLIPBOARD, "CLIPBOARD");
+ DEFSYM (QSTRING, "STRING");
+ DEFSYM (QUTF8_STRING, "UTF8_STRING");
+ DEFSYM (Qforeign_selection, "foreign-selection");
+
+ defsubr (&Shaiku_selection_data);
+ defsubr (&Shaiku_selection_put);
+}
diff --git a/src/haikuselect.h b/src/haikuselect.h
new file mode 100644
index 0000000000..542d550d64
--- /dev/null
+++ b/src/haikuselect.h
@@ -0,0 +1,64 @@
+/* Haiku window system selection 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/>. */
+
+#ifndef _HAIKU_SELECT_H_
+#define _HAIKU_SELECT_H_
+
+#ifdef __cplusplus
+#include <cstdio>
+#endif
+
+#ifdef __cplusplus
+#include <stdio.h>
+extern "C"
+{
+ extern void init_haiku_select (void);
+#endif
+
+ /* Whether or not the selection was recently changed. */
+ extern int selection_state_flag;
+
+ /* Find a string with the MIME type TYPE in the system clipboard. */
+ extern char *
+ BClipboard_find_system_data (const char *type, ssize_t *len);
+
+ /* Ditto, but for the primary selection and not clipboard. */
+ extern char *
+ BClipboard_find_primary_selection_data (const char *type, ssize_t *len);
+
+ /* Ditto, this time for the secondary selection. */
+ extern char *
+ BClipboard_find_secondary_selection_data (const char *type, ssize_t *len);
+
+ extern void
+ BClipboard_set_system_data (const char *type, const char *data, ssize_t len);
+
+ extern void
+ BClipboard_set_primary_selection_data (const char *type, const char *data,
+ ssize_t len);
+
+ extern void
+ BClipboard_set_secondary_selection_data (const char *type, const char *data,
+ ssize_t len);
+
+ /* Free the returned data. */
+ extern void BClipboard_free_data (void *ptr);
+#ifdef __cplusplus
+};
+#endif
+#endif /* _HAIKU_SELECT_H_ */
diff --git a/src/haikuterm.c b/src/haikuterm.c
new file mode 100644
index 0000000000..05fbd1021b
--- /dev/null
+++ b/src/haikuterm.c
@@ -0,0 +1,3608 @@
+/* Haiku window system support
+ 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 "dispextern.h"
+#include "frame.h"
+#include "lisp.h"
+#include "haikugui.h"
+#include "keyboard.h"
+#include "haikuterm.h"
+#include "blockinput.h"
+#include "termchar.h"
+#include "termhooks.h"
+#include "menu.h"
+#include "buffer.h"
+#include "haiku_support.h"
+#include "thread.h"
+#include "window.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#ifdef USE_BE_CAIRO
+#include <cairo.h>
+#endif
+
+struct haiku_display_info *x_display_list = NULL;
+extern frame_parm_handler haiku_frame_parm_handlers[];
+
+static void **fringe_bmps;
+static int fringe_bitmap_fillptr = 0;
+
+static Lisp_Object rdb;
+
+struct unhandled_event
+{
+ struct unhandled_event *next;
+ enum haiku_event_type type;
+ uint8_t buffer[200];
+};
+
+char *
+get_keysym_name (int keysym)
+{
+ static char value[16];
+ sprintf (value, "%d", keysym);
+ return value;
+}
+
+static struct frame *
+haiku_window_to_frame (void *window)
+{
+ Lisp_Object tail, tem;
+ struct frame *f;
+
+ FOR_EACH_FRAME (tail, tem)
+ {
+ f = XFRAME (tem);
+ if (!FRAME_HAIKU_P (f))
+ continue;
+
+ eassert (FRAME_DISPLAY_INFO (f) == x_display_list);
+
+ if (FRAME_HAIKU_WINDOW (f) == window)
+ return f;
+ }
+
+ return 0;
+}
+
+static void
+haiku_coords_from_parent (struct frame *f, int *x, int *y)
+{
+ struct frame *p = FRAME_PARENT_FRAME (f);
+ eassert (p);
+
+ for (struct frame *parent = p; parent;
+ parent = FRAME_PARENT_FRAME (parent))
+ {
+ *x -= parent->left_pos;
+ *y -= parent->top_pos;
+ }
+}
+
+static void
+haiku_delete_terminal (struct terminal *terminal)
+{
+ emacs_abort ();
+}
+
+static const char *
+get_string_resource (void *ignored, const char *name, const char *class)
+{
+ if (!name)
+ return NULL;
+
+ Lisp_Object lval = assoc_no_quit (build_string (name), rdb);
+
+ if (!NILP (lval))
+ return SSDATA (XCDR (lval));
+
+ return NULL;
+}
+
+static void
+haiku_update_size_hints (struct frame *f)
+{
+ int base_width, base_height;
+ eassert (FRAME_HAIKU_P (f) && FRAME_HAIKU_WINDOW (f));
+
+ base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
+ base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
+
+ block_input ();
+ BWindow_set_size_alignment (FRAME_HAIKU_WINDOW (f),
+ frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f),
+ frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f));
+ BWindow_set_min_size (FRAME_HAIKU_WINDOW (f), base_width,
+ base_height
+ + FRAME_TOOL_BAR_HEIGHT (f)
+ + FRAME_MENU_BAR_HEIGHT (f));
+ unblock_input ();
+}
+
+static void
+haiku_clip_to_string (struct glyph_string *s)
+{
+ struct haiku_rect r[2];
+ int n = get_glyph_string_clip_rects (s, (struct haiku_rect *) &r, 2);
+
+ if (n)
+ BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[0].x, r[0].y,
+ r[0].width, r[0].height);
+ if (n > 1)
+ {
+ BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[1].x, r[1].y,
+ r[1].width, r[1].height);
+ }
+
+ s->num_clips = n;
+}
+
+static void
+haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst)
+{
+ BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y,
+ s->width, s->height);
+ dst->num_clips = 1;
+}
+
+static void
+haiku_flip_buffers (struct frame *f)
+{
+ void *view = FRAME_OUTPUT_DATA (f)->view;
+ block_input ();
+
+ BView_draw_lock (view);
+ FRAME_DIRTY_P (f) = 0;
+ EmacsView_flip_and_blit (view);
+ BView_draw_unlock (view);
+
+ unblock_input ();
+}
+
+static void
+haiku_frame_up_to_date (struct frame *f)
+{
+ block_input ();
+ FRAME_MOUSE_UPDATE (f);
+ if (FRAME_DIRTY_P (f) && !buffer_flipping_blocked_p ())
+ haiku_flip_buffers (f);
+ unblock_input ();
+}
+
+static void
+haiku_buffer_flipping_unblocked_hook (struct frame *f)
+{
+ if (FRAME_DIRTY_P (f))
+ haiku_flip_buffers (f);
+}
+
+static void
+haiku_clear_frame_area (struct frame *f, int x, int y,
+ int width, int height)
+{
+ void *vw = FRAME_HAIKU_VIEW (f);
+ block_input ();
+ BView_draw_lock (vw);
+ BView_StartClip (vw);
+ BView_ClipToRect (vw, x, y, width, height);
+ BView_SetHighColor (vw, FRAME_BACKGROUND_PIXEL (f));
+ BView_FillRectangle (vw, x, y, width, height);
+ BView_EndClip (vw);
+ BView_draw_unlock (vw);
+ unblock_input ();
+}
+
+static void
+haiku_clear_frame (struct frame *f)
+{
+ void *view = FRAME_HAIKU_VIEW (f);
+ block_input ();
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ BView_ClipToRect (view, 0, 0, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+ BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f));
+ BView_FillRectangle (view, 0, 0, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+ unblock_input ();
+}
+
+/* Give frame F the font FONT-OBJECT as its default font. The return
+ value is FONT-OBJECT. FONTSET is an ID of the fontset for the
+ frame. If it is negative, generate a new fontset from
+ FONT-OBJECT. */
+
+static Lisp_Object
+haiku_new_font (struct frame *f, Lisp_Object font_object, int fontset)
+{
+ struct font *font = XFONT_OBJECT (font_object);
+ if (fontset < 0)
+ fontset = fontset_from_font (font_object);
+
+ FRAME_FONTSET (f) = fontset;
+ if (FRAME_FONT (f) == font)
+ return font_object;
+
+ FRAME_FONT (f) = font;
+ FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
+ FRAME_COLUMN_WIDTH (f) = font->average_width;
+
+ int ascent, descent;
+ get_font_ascent_descent (font, &ascent, &descent);
+ FRAME_LINE_HEIGHT (f) = ascent + descent;
+ FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
+
+ int unit = FRAME_COLUMN_WIDTH (f);
+ if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
+ FRAME_CONFIG_SCROLL_BAR_COLS (f)
+ = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
+ else
+ FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
+
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+ adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
+ FRAME_LINES (f) * FRAME_LINE_HEIGHT (f),
+ 3, false, Qfont);
+
+ haiku_clear_under_internal_border (f);
+ }
+ return font_object;
+}
+
+static int
+haiku_valid_modifier_p (Lisp_Object sym)
+{
+ return EQ (sym, Qcommand) || EQ (sym, Qshift)
+ || EQ (sym, Qcontrol) || EQ (sym, Qoption);
+}
+
+#define MODIFIER_OR(obj, def) (haiku_valid_modifier_p (obj) ? obj : def)
+
+static void
+haiku_add_modifier (int modifier, int toput, Lisp_Object qtem, int *modifiers)
+{
+ if ((modifier & HAIKU_MODIFIER_ALT && EQ (qtem, Qcommand))
+ || (modifier & HAIKU_MODIFIER_SHIFT && EQ (qtem, Qshift))
+ || (modifier & HAIKU_MODIFIER_CTRL && EQ (qtem, Qcontrol))
+ || (modifier & HAIKU_MODIFIER_SUPER && EQ (qtem, Qoption)))
+ *modifiers |= toput;
+}
+
+static int
+haiku_modifiers_to_emacs (int haiku_key)
+{
+ int modifiers = 0;
+ haiku_add_modifier (haiku_key, shift_modifier,
+ MODIFIER_OR (Vhaiku_shift_keysym, Qshift), &modifiers);
+ haiku_add_modifier (haiku_key, super_modifier,
+ MODIFIER_OR (Vhaiku_super_keysym, Qoption), &modifiers);
+ haiku_add_modifier (haiku_key, meta_modifier,
+ MODIFIER_OR (Vhaiku_meta_keysym, Qcommand), &modifiers);
+ haiku_add_modifier (haiku_key, ctrl_modifier,
+ MODIFIER_OR (Vhaiku_control_keysym, Qcontrol), &modifiers);
+ return modifiers;
+}
+
+#undef MODIFIER_OR
+
+static void
+haiku_rehighlight (void)
+{
+ eassert (x_display_list && !x_display_list->next);
+
+ block_input ();
+
+ struct frame *old_hl = x_display_list->highlight_frame;
+
+ if (x_display_list->focused_frame)
+ {
+ x_display_list->highlight_frame
+ = ((FRAMEP (FRAME_FOCUS_FRAME (x_display_list->focused_frame)))
+ ? XFRAME (FRAME_FOCUS_FRAME (x_display_list->focused_frame))
+ : x_display_list->focused_frame);
+ if (!FRAME_LIVE_P (x_display_list->highlight_frame))
+ {
+ fset_focus_frame (x_display_list->focused_frame, Qnil);
+ x_display_list->highlight_frame = x_display_list->focused_frame;
+ }
+ }
+ else
+ x_display_list->highlight_frame = 0;
+
+ if (old_hl)
+ gui_update_cursor (old_hl, true);
+
+ if (x_display_list->highlight_frame)
+ gui_update_cursor (x_display_list->highlight_frame, true);
+ unblock_input ();
+}
+
+static void
+haiku_frame_raise_lower (struct frame *f, bool raise_p)
+{
+ if (raise_p)
+ {
+ block_input ();
+ BWindow_activate (FRAME_HAIKU_WINDOW (f));
+ flush_frame (f);
+ unblock_input ();
+ }
+}
+
+/* Unfortunately, NOACTIVATE is not implementable on Haiku. */
+static void
+haiku_focus_frame (struct frame *frame, bool noactivate)
+{
+ if (x_display_list->focused_frame != frame)
+ haiku_frame_raise_lower (frame, 1);
+}
+
+static void
+haiku_new_focus_frame (struct frame *frame)
+{
+ eassert (x_display_list && !x_display_list->next);
+
+ block_input ();
+ if (frame != x_display_list->focused_frame)
+ {
+ if (x_display_list->focused_frame &&
+ x_display_list->focused_frame->auto_lower)
+ haiku_frame_raise_lower (x_display_list->focused_frame, 0);
+
+ x_display_list->focused_frame = frame;
+
+ if (frame && frame->auto_raise)
+ haiku_frame_raise_lower (frame, 1);
+ }
+ unblock_input ();
+
+ haiku_rehighlight ();
+}
+
+static void
+haiku_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ haiku_set_name (f, arg, 0);
+}
+
+static void
+haiku_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor)
+{
+ haiku_query_color (FRAME_BACKGROUND_PIXEL (f), bgcolor);
+}
+
+static bool
+haiku_defined_color (struct frame *f,
+ const char *name,
+ Emacs_Color *color,
+ bool alloc,
+ bool make_index)
+{
+ return !haiku_get_color (name, color);
+}
+
+/* Adapted from xterm `x_draw_box_rect'. */
+static void
+haiku_draw_box_rect (struct glyph_string *s,
+ int left_x, int top_y, int right_x, int bottom_y, int hwidth,
+ int vwidth, bool left_p, bool right_p, struct haiku_rect *clip_rect)
+{
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ struct face *face = s->face;
+
+ BView_StartClip (view);
+ BView_SetHighColor (view, face->box_color);
+ if (clip_rect)
+ BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width,
+ clip_rect->height);
+ BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth);
+ if (left_p)
+ BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
+
+ BView_FillRectangle (view, left_x, bottom_y - hwidth + 1,
+ right_x - left_x + 1, hwidth);
+ if (right_p)
+ BView_FillRectangle (view, right_x - vwidth + 1,
+ top_y, vwidth, bottom_y - top_y + 1);
+ BView_EndClip (view);
+}
+
+static void
+haiku_calculate_relief_colors (struct glyph_string *s,
+ uint32_t *rgbout_w, uint32_t *rgbout_b,
+ uint32_t *rgbout_c)
+{
+ struct face *face = s->face;
+
+ prepare_face_for_display (s->f, s->face);
+
+ uint32_t rgbin = face->use_box_color_for_shadows_p
+ ? face->box_color : face->background;
+
+ if (s->hl == DRAW_CURSOR)
+ rgbin = FRAME_CURSOR_COLOR (s->f).pixel;
+
+ double h, cs, l;
+ rgb_color_hsl (rgbin, &h, &cs, &l);
+
+ hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 0.6), rgbout_b);
+ hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 1.2), rgbout_w);
+ hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 1.8), rgbout_c);
+}
+
+static void
+haiku_draw_relief_rect (struct glyph_string *s,
+ int left_x, int top_y, int right_x, int bottom_y,
+ int hwidth, int vwidth, bool raised_p, bool top_p, bool bot_p,
+ bool left_p, bool right_p,
+ struct haiku_rect *clip_rect, bool fancy_p)
+{
+ uint32_t color_white;
+ uint32_t color_black;
+ uint32_t color_corner;
+
+ haiku_calculate_relief_colors (s, &color_white, &color_black,
+ &color_corner);
+
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_StartClip (view);
+
+ BView_SetHighColor (view, raised_p ? color_white : color_black);
+ if (clip_rect)
+ BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width,
+ clip_rect->height);
+ if (top_p)
+ BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth);
+ if (left_p)
+ BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
+ BView_SetHighColor (view, !raised_p ? color_white : color_black);
+
+ if (bot_p)
+ BView_FillRectangle (view, left_x, bottom_y - hwidth + 1,
+ right_x - left_x + 1, hwidth);
+ if (right_p)
+ BView_FillRectangle (view, right_x - vwidth + 1, top_y,
+ vwidth, bottom_y - top_y + 1);
+
+ /* Draw the triangle for the bottom-left corner. */
+ if (bot_p && left_p)
+ {
+ BView_SetHighColor (view, raised_p ? color_white : color_black);
+ BView_FillTriangle (view, left_x, bottom_y - hwidth, left_x + vwidth,
+ bottom_y - hwidth, left_x, bottom_y);
+ }
+
+ /* Now draw the triangle for the top-right corner. */
+ if (top_p && right_p)
+ {
+ BView_SetHighColor (view, raised_p ? color_white : color_black);
+ BView_FillTriangle (view, right_x - vwidth, top_y,
+ right_x, top_y,
+ right_x - vwidth, top_y + hwidth);
+ }
+
+ /* If (h/v)width is > 1, we draw the outer-most line on each side in the
+ black relief color. */
+
+ BView_SetHighColor (view, color_black);
+
+ if (hwidth > 1 && top_p)
+ BView_StrokeLine (view, left_x, top_y, right_x, top_y);
+ if (hwidth > 1 && bot_p)
+ BView_StrokeLine (view, left_x, bottom_y, right_x, bottom_y);
+ if (vwidth > 1 && left_p)
+ BView_StrokeLine (view, left_x, top_y, left_x, bottom_y);
+ if (vwidth > 1 && right_p)
+ BView_StrokeLine (view, right_x, top_y, right_x, bottom_y);
+
+ BView_SetHighColor (view, color_corner);
+
+ /* Omit corner pixels. */
+ if (hwidth > 1 || vwidth > 1)
+ {
+ if (left_p && top_p)
+ BView_FillRectangle (view, left_x, top_y, 1, 1);
+ if (left_p && bot_p)
+ BView_FillRectangle (view, left_x, bottom_y, 1, 1);
+ if (right_p && top_p)
+ BView_FillRectangle (view, right_x, top_y, 1, 1);
+ if (right_p && bot_p)
+ BView_FillRectangle (view, right_x, bottom_y, 1, 1);
+ }
+
+ BView_EndClip (view);
+}
+
+static void
+haiku_draw_string_box (struct glyph_string *s, int clip_p)
+{
+ int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x;
+ bool raised_p, left_p, right_p;
+ struct glyph *last_glyph;
+ struct haiku_rect clip_rect;
+
+ struct face *face = s->face;
+
+ last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
+ ? WINDOW_RIGHT_EDGE_X (s->w)
+ : window_box_right (s->w, s->area));
+
+ /* The glyph that may have a right box line. For static
+ compositions and images, the right-box flag is on the first glyph
+ of the glyph string; for other types it's on the last glyph. */
+ if (s->cmp || s->img)
+ last_glyph = s->first_glyph;
+ else if (s->first_glyph->type == COMPOSITE_GLYPH
+ && s->first_glyph->u.cmp.automatic)
+ {
+ /* For automatic compositions, we need to look up the last glyph
+ in the composition. */
+ struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area];
+ struct glyph *g = s->first_glyph;
+ for (last_glyph = g++;
+ g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id
+ && g->slice.cmp.to < s->cmp_to;
+ last_glyph = g++)
+ ;
+ }
+ else
+ last_glyph = s->first_glyph + s->nchars - 1;
+
+ vwidth = eabs (face->box_vertical_line_width);
+ hwidth = eabs (face->box_horizontal_line_width);
+ raised_p = face->box == FACE_RAISED_BOX;
+ left_x = s->x;
+ right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
+ ? last_x - 1
+ : min (last_x, s->x + s->background_width) - 1);
+
+ top_y = s->y;
+ bottom_y = top_y + s->height - 1;
+
+ left_p = (s->first_glyph->left_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->prev == NULL
+ || s->prev->hl != s->hl)));
+ right_p = (last_glyph->right_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->next == NULL
+ || s->next->hl != s->hl)));
+
+ get_glyph_string_clip_rect (s, &clip_rect);
+
+ if (face->box == FACE_SIMPLE_BOX)
+ haiku_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
+ vwidth, left_p, right_p, &clip_rect);
+ else
+ haiku_draw_relief_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
+ vwidth, raised_p, true, true, left_p, right_p,
+ &clip_rect, 1);
+
+ if (clip_p)
+ {
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_ClipToInverseRect (view, left_x, top_y, right_x - left_x + 1, hwidth);
+ if (left_p)
+ BView_ClipToInverseRect (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
+ BView_ClipToInverseRect (view, left_x, bottom_y - hwidth + 1,
+ right_x - left_x + 1, hwidth);
+ if (right_p)
+ BView_ClipToInverseRect (view, right_x - vwidth + 1,
+ top_y, vwidth, bottom_y - top_y + 1);
+ }
+}
+
+static void
+haiku_draw_plain_background (struct glyph_string *s, struct face *face,
+ int box_line_hwidth, int box_line_vwidth)
+{
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_StartClip (view);
+ if (s->hl == DRAW_CURSOR)
+ BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
+ else
+ BView_SetHighColor (view, face->background_defaulted_p ?
+ FRAME_BACKGROUND_PIXEL (s->f) :
+ face->background);
+
+ BView_FillRectangle (view, s->x,
+ s->y + box_line_hwidth,
+ s->background_width,
+ s->height - 2 * box_line_hwidth);
+ BView_EndClip (view);
+}
+
+static void
+haiku_draw_stipple_background (struct glyph_string *s, struct face *face,
+ int box_line_hwidth, int box_line_vwidth)
+{
+}
+
+static void
+haiku_maybe_draw_background (struct glyph_string *s, int force_p)
+{
+ if ((s->first_glyph->type != IMAGE_GLYPH) && !s->background_filled_p)
+ {
+ struct face *face = s->face;
+ int box_line_width = max (face->box_horizontal_line_width, 0);
+ int box_vline_width = max (face->box_vertical_line_width, 0);
+
+ if (FONT_HEIGHT (s->font) < s->height - 2 * box_vline_width
+ || FONT_TOO_HIGH (s->font)
+ || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
+ {
+ if (!face->stipple)
+ haiku_draw_plain_background (s, face, box_line_width,
+ box_vline_width);
+ else
+ haiku_draw_stipple_background (s, face, box_line_width,
+ box_vline_width);
+ s->background_filled_p = 1;
+ }
+ }
+}
+
+static void
+haiku_mouse_face_colors (struct glyph_string *s, uint32_t *fg,
+ uint32_t *bg)
+{
+ int face_id;
+ struct face *face;
+
+ /* What face has to be used last for the mouse face? */
+ face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
+ face = FACE_FROM_ID_OR_NULL (s->f, face_id);
+ if (face == NULL)
+ face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+
+ if (s->first_glyph->type == CHAR_GLYPH)
+ face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
+ else
+ face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
+
+ face = FACE_FROM_ID (s->f, face_id);
+ prepare_face_for_display (s->f, s->face);
+
+ if (fg)
+ *fg = face->foreground;
+ if (bg)
+ *bg = face->background;
+}
+
+static void
+haiku_draw_underwave (struct glyph_string *s, int width, int x)
+{
+ int wave_height = 3, wave_length = 2;
+ int y, dx, dy, odd, xmax;
+ dx = wave_length;
+ dy = wave_height - 1;
+ y = s->ybase - wave_height + 3;
+
+ float ax, ay, bx, by;
+ xmax = x + width;
+
+ void *view = FRAME_HAIKU_VIEW (s->f);
+
+ BView_StartClip (view);
+ BView_ClipToRect (view, x, y, width, wave_height);
+ ax = x - ((int) (x) % dx) + (float) 0.5;
+ bx = ax + dx;
+ odd = (int) (ax / dx) % 2;
+ ay = by = y + 0.5;
+
+ if (odd)
+ ay += dy;
+ else
+ by += dy;
+
+ while (ax <= xmax)
+ {
+ BView_StrokeLine (view, ax, ay, bx, by);
+ ax = bx, ay = by;
+ bx += dx, by = y + 0.5 + odd * dy;
+ odd = !odd;
+ }
+ BView_EndClip (view);
+}
+
+static void
+haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
+ uint8_t dcol, int width, int x)
+{
+ if (s->for_overlaps)
+ return;
+
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_draw_lock (view);
+ BView_StartClip (view);
+
+ if (face->underline)
+ {
+ if (s->hl == DRAW_CURSOR)
+ BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
+ else if (!face->underline_defaulted_p)
+ BView_SetHighColor (view, face->underline_color);
+ else
+ BView_SetHighColor (view, dcol);
+
+ if (face->underline == FACE_UNDER_WAVE)
+ haiku_draw_underwave (s, width, x);
+ else if (face->underline == FACE_UNDER_LINE)
+ {
+ unsigned long thickness, position;
+ int y;
+
+ if (s->prev && s->prev && s->prev->hl == DRAW_MOUSE_FACE)
+ {
+ struct face *prev_face = s->prev->face;
+
+ if (prev_face && prev_face->underline == FACE_UNDER_LINE)
+ {
+ /* We use the same underline style as the previous one. */
+ thickness = s->prev->underline_thickness;
+ position = s->prev->underline_position;
+ }
+ else
+ goto calculate_underline_metrics;
+ }
+ else
+ {
+ calculate_underline_metrics:;
+ struct font *font = font_for_underline_metrics (s);
+ unsigned long minimum_offset;
+ bool underline_at_descent_line;
+ bool use_underline_position_properties;
+ Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE
+ (Qunderline_minimum_offset, s->w));
+
+ if (FIXNUMP (val))
+ minimum_offset = max (0, XFIXNUM (val));
+ else
+ minimum_offset = 1;
+
+ val = (WINDOW_BUFFER_LOCAL_VALUE
+ (Qx_underline_at_descent_line, s->w));
+ underline_at_descent_line
+ = !(NILP (val) || EQ (val, Qunbound));
+
+ val = (WINDOW_BUFFER_LOCAL_VALUE
+ (Qx_use_underline_position_properties, s->w));
+ use_underline_position_properties
+ = !(NILP (val) || EQ (val, Qunbound));
+
+ /* Get the underline thickness. Default is 1 pixel. */
+ if (font && font->underline_thickness > 0)
+ thickness = font->underline_thickness;
+ else
+ thickness = 1;
+ if (underline_at_descent_line)
+ position = (s->height - thickness) - (s->ybase - s->y);
+ else
+ {
+ /* Get the underline position. This is the
+ recommended vertical offset in pixels from
+ the baseline to the top of the underline.
+ This is a signed value according to the
+ specs, and its default is
+
+ ROUND ((maximum descent) / 2), with
+ ROUND(x) = floor (x + 0.5) */
+
+ if (use_underline_position_properties
+ && font && font->underline_position >= 0)
+ position = font->underline_position;
+ else if (font)
+ position = (font->descent + 1) / 2;
+ else
+ position = minimum_offset;
+ }
+ position = max (position, minimum_offset);
+ }
+ /* Check the sanity of thickness and position. We should
+ avoid drawing underline out of the current line area. */
+ if (s->y + s->height <= s->ybase + position)
+ position = (s->height - 1) - (s->ybase - s->y);
+ if (s->y + s->height < s->ybase + position + thickness)
+ thickness = (s->y + s->height) - (s->ybase + position);
+ s->underline_thickness = thickness;
+ s->underline_position = position;
+ y = s->ybase + position;
+
+ BView_FillRectangle (view, s->x, y, s->width, thickness);
+ }
+ }
+
+ if (face->overline_p)
+ {
+ unsigned long dy = 0, h = 1;
+ if (s->hl == DRAW_CURSOR)
+ BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
+ else if (!face->overline_color_defaulted_p)
+ BView_SetHighColor (view, face->overline_color);
+ else
+ BView_SetHighColor (view, dcol);
+
+ BView_FillRectangle (view, s->x, s->y + dy, s->width, h);
+ }
+
+ if (face->strike_through_p)
+ {
+ /* Y-coordinate and height of the glyph string's first
+ glyph. We cannot use s->y and s->height because those
+ could be larger if there are taller display elements
+ (e.g., characters displayed with a larger font) in the
+ same glyph row. */
+ int glyph_y = s->ybase - s->first_glyph->ascent;
+ int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
+ /* Strike-through width and offset from the glyph string's
+ top edge. */
+ unsigned long h = 1;
+ unsigned long dy = (glyph_height - h) / 2;
+
+ if (s->hl == DRAW_CURSOR)
+ BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
+ else if (!face->strike_through_color_defaulted_p)
+ BView_SetHighColor (view, face->strike_through_color);
+ else
+ BView_SetHighColor (view, dcol);
+
+ BView_FillRectangle (view, s->x, glyph_y + dy, s->width, h);
+ }
+
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+}
+
+static void
+haiku_draw_glyph_string_foreground (struct glyph_string *s)
+{
+ struct face *face = s->face;
+
+ int i, x;
+ if (face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + max (face->box_vertical_line_width, 0);
+ else
+ x = s->x;
+
+ void *view = FRAME_HAIKU_VIEW (s->f);
+
+ if (s->font_not_found_p)
+ {
+ BView_StartClip (view);
+ if (s->hl == DRAW_CURSOR)
+ BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
+ else
+ BView_SetHighColor (view, face->foreground);
+ for (i = 0; i < s->nchars; ++i)
+ {
+ struct glyph *g = s->first_glyph + i;
+ BView_StrokeRectangle (view, x, s->y, g->pixel_width,
+ s->height);
+ x += g->pixel_width;
+ }
+ BView_EndClip (view);
+ }
+ else
+ {
+ struct font *ft = s->font;
+ int off = ft->baseline_offset;
+ int y;
+
+ if (ft->vertical_centering)
+ off = VCENTER_BASELINE_OFFSET (ft, s->f) - off;
+ y = s->ybase - off;
+ if (s->for_overlaps || (s->background_filled_p && s->hl != DRAW_CURSOR))
+ ft->driver->draw (s, 0, s->nchars, x, y, false);
+ else
+ ft->driver->draw (s, 0, s->nchars, x, y, true);
+
+ if (face->overstrike)
+ ft->driver->draw (s, 0, s->nchars, x + 1, y, false);
+ }
+}
+
+static void
+haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
+{
+ struct glyph *glyph = s->first_glyph;
+ unsigned char2b[8];
+ int x, i, j;
+ struct face *face = s->face;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (face && face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + max (face->box_vertical_line_width, 0);
+ else
+ x = s->x;
+
+ s->char2b = char2b;
+
+ for (i = 0; i < s->nchars; i++, glyph++)
+ {
+#ifdef GCC_LINT
+ enum { PACIFY_GCC_BUG_81401 = 1 };
+#else
+ enum { PACIFY_GCC_BUG_81401 = 0 };
+#endif
+ char buf[7 + PACIFY_GCC_BUG_81401];
+ char *str = NULL;
+ int len = glyph->u.glyphless.len;
+
+ if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
+ {
+ if (len > 0
+ && CHAR_TABLE_P (Vglyphless_char_display)
+ && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
+ >= 1))
+ {
+ Lisp_Object acronym
+ = (! glyph->u.glyphless.for_no_font
+ ? CHAR_TABLE_REF (Vglyphless_char_display,
+ glyph->u.glyphless.ch)
+ : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+ if (STRINGP (acronym))
+ str = SSDATA (acronym);
+ }
+ }
+ else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
+ {
+ unsigned int ch = glyph->u.glyphless.ch;
+ eassume (ch <= MAX_CHAR);
+ sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch);
+ str = buf;
+ }
+
+ if (str)
+ {
+ int upper_len = (len + 1) / 2;
+
+ /* It is assured that all LEN characters in STR is ASCII. */
+ for (j = 0; j < len; j++)
+ char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF;
+
+ s->font->driver->draw (s, 0, upper_len,
+ x + glyph->slice.glyphless.upper_xoff,
+ s->ybase + glyph->slice.glyphless.upper_yoff,
+ false);
+ s->font->driver->draw (s, upper_len, len,
+ x + glyph->slice.glyphless.lower_xoff,
+ s->ybase + glyph->slice.glyphless.lower_yoff,
+ false);
+ }
+ BView_StartClip (FRAME_HAIKU_VIEW (s->f));
+ if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
+ BView_FillRectangle (FRAME_HAIKU_VIEW (s->f),
+ x, s->ybase - glyph->ascent,
+ glyph->pixel_width - 1,
+ glyph->ascent + glyph->descent - 1);
+ BView_EndClip (FRAME_HAIKU_VIEW (s->f));
+ x += glyph->pixel_width;
+ }
+}
+
+static void
+haiku_draw_stretch_glyph_string (struct glyph_string *s)
+{
+ eassert (s->first_glyph->type == STRETCH_GLYPH);
+
+ struct face *face = s->face;
+
+ if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p)
+ {
+ int width, background_width = s->background_width;
+ int x = s->x;
+
+ if (!s->row->reversed_p)
+ {
+ int left_x = window_box_left_offset (s->w, TEXT_AREA);
+
+ if (x < left_x)
+ {
+ background_width -= left_x - x;
+ x = left_x;
+ }
+ }
+ else
+ {
+ /* In R2L rows, draw the cursor on the right edge of the
+ stretch glyph. */
+ int right_x = window_box_right (s->w, TEXT_AREA);
+ if (x + background_width > right_x)
+ background_width -= x - right_x;
+ x += background_width;
+ }
+
+ width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
+ if (s->row->reversed_p)
+ x -= width;
+
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_StartClip (view);
+ BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
+ BView_FillRectangle (view, x, s->y, width, s->height);
+ BView_EndClip (view);
+
+ if (width < background_width)
+ {
+ if (!s->row->reversed_p)
+ x += width;
+ else
+ x = s->x;
+
+ int y = s->y;
+ int w = background_width - width, h = s->height;
+
+ if (!face->stipple)
+ {
+ uint32_t bkg;
+ if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR
+ && s->row->mouse_face_p
+ && cursor_in_mouse_face_p (s->w)))
+ haiku_mouse_face_colors (s, NULL, &bkg);
+ else
+ bkg = face->background;
+
+ BView_StartClip (view);
+ BView_SetHighColor (view, bkg);
+ BView_FillRectangle (view, x, y, w, h);
+ BView_EndClip (view);
+ }
+ }
+ }
+ else if (!s->background_filled_p)
+ {
+ int background_width = s->background_width;
+ int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA);
+
+ /* Don't draw into left fringe or scrollbar area except for
+ header line and mode line. */
+ if (s->area == TEXT_AREA
+ && x < text_left_x && !s->row->mode_line_p)
+ {
+ background_width -= text_left_x - x;
+ x = text_left_x;
+ }
+
+ if (background_width > 0)
+ {
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_StartClip (view);
+ uint32_t bkg;
+ if (s->hl == DRAW_MOUSE_FACE)
+ haiku_mouse_face_colors (s, NULL, &bkg);
+ else if (s->hl == DRAW_CURSOR)
+ bkg = FRAME_CURSOR_COLOR (s->f).pixel;
+ else
+ bkg = s->face->background;
+
+ BView_SetHighColor (view, bkg);
+ BView_FillRectangle (view, x, s->y, background_width, s->height);
+ BView_EndClip (view);
+ }
+ }
+ s->background_filled_p = 1;
+}
+
+static void
+haiku_start_clip (struct glyph_string *s)
+{
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_draw_lock (view);
+ BView_StartClip (view);
+}
+
+static void
+haiku_end_clip (struct glyph_string *s)
+{
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+}
+
+static void
+haiku_clip_to_row (struct window *w, struct glyph_row *row,
+ enum glyph_row_area area)
+{
+ struct frame *f = WINDOW_XFRAME (w);
+ int window_x, window_y, window_width;
+ int x, y, width, height;
+
+ window_box (w, area, &window_x, &window_y, &window_width, 0);
+
+ x = window_x;
+ y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
+ y = max (y, window_y);
+ width = window_width;
+ height = row->visible_height;
+
+ BView_ClipToRect (FRAME_HAIKU_VIEW (f), x, y, width, height);
+}
+
+static void
+haiku_update_begin (struct frame *f)
+{
+}
+
+static void
+haiku_update_end (struct frame *f)
+{
+ MOUSE_HL_INFO (f)->mouse_face_defer = false;
+ flush_frame (f);
+}
+
+static void
+haiku_draw_composite_glyph_string_foreground (struct glyph_string *s)
+{
+ int i, j, x;
+ struct font *font = s->font;
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ struct face *face = s->face;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (face && face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + max (face->box_vertical_line_width, 0);
+ else
+ x = s->x;
+
+ /* S is a glyph string for a composition. S->cmp_from is the index
+ of the first character drawn for glyphs of this composition.
+ S->cmp_from == 0 means we are drawing the very first character of
+ this composition. */
+
+ /* Draw a rectangle for the composition if the font for the very
+ first character of the composition could not be loaded. */
+
+ if (s->font_not_found_p && !s->cmp_from)
+ {
+ BView_StartClip (view);
+ if (s->hl == DRAW_CURSOR)
+ BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
+ else
+ BView_SetHighColor (view, s->face->foreground);
+ BView_StrokeRectangle (view, s->x, s->y, s->width - 1, s->height - 1);
+ BView_EndClip (view);
+ }
+ else if (!s->first_glyph->u.cmp.automatic)
+ {
+ int y = s->ybase;
+
+ for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
+ /* TAB in a composition means display glyphs with padding
+ space on the left or right. */
+ if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
+ {
+ int xx = x + s->cmp->offsets[j * 2];
+ int yy = y - s->cmp->offsets[j * 2 + 1];
+
+ font->driver->draw (s, j, j + 1, xx, yy, false);
+ if (face->overstrike)
+ font->driver->draw (s, j, j + 1, xx + 1, yy, false);
+ }
+ }
+ else
+ {
+ Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
+ Lisp_Object glyph;
+ int y = s->ybase;
+ int width = 0;
+
+ for (i = j = s->cmp_from; i < s->cmp_to; i++)
+ {
+ glyph = LGSTRING_GLYPH (gstring, i);
+ if (NILP (LGLYPH_ADJUSTMENT (glyph)))
+ width += LGLYPH_WIDTH (glyph);
+ else
+ {
+ int xoff, yoff, wadjust;
+
+ if (j < i)
+ {
+ font->driver->draw (s, j, i, x, y, false);
+ if (s->face->overstrike)
+ font->driver->draw (s, j, i, x + 1, y, false);
+ x += width;
+ }
+ xoff = LGLYPH_XOFF (glyph);
+ yoff = LGLYPH_YOFF (glyph);
+ wadjust = LGLYPH_WADJUST (glyph);
+ font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
+ if (face->overstrike)
+ font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
+ false);
+ x += wadjust;
+ j = i + 1;
+ width = 0;
+ }
+ }
+ if (j < i)
+ {
+ font->driver->draw (s, j, i, x, y, false);
+ if (face->overstrike)
+ font->driver->draw (s, j, i, x + 1, y, false);
+ }
+ }
+}
+
+static void
+haiku_draw_image_relief (struct glyph_string *s)
+{
+ int x1, y1, thick;
+ bool raised_p, top_p, bot_p, left_p, right_p;
+ int extra_x, extra_y;
+ struct haiku_rect r;
+ int x = s->x;
+ int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+
+ struct face *face = s->face;
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ x += max (face->box_vertical_line_width, 0);
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ if (s->slice.x == 0)
+ x += s->img->hmargin;
+ if (s->slice.y == 0)
+ y += s->img->vmargin;
+
+ if (s->hl == DRAW_IMAGE_SUNKEN
+ || s->hl == DRAW_IMAGE_RAISED)
+ {
+ if (s->face->id == TAB_BAR_FACE_ID)
+ thick = (tab_bar_button_relief < 0
+ ? DEFAULT_TAB_BAR_BUTTON_RELIEF
+ : min (tab_bar_button_relief, 1000000));
+ else
+ thick = (tool_bar_button_relief < 0
+ ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
+ : min (tool_bar_button_relief, 1000000));
+ raised_p = s->hl == DRAW_IMAGE_RAISED;
+ }
+ else
+ {
+ thick = eabs (s->img->relief);
+ raised_p = s->img->relief > 0;
+ }
+
+ x1 = x + s->slice.width - 1;
+ y1 = y + s->slice.height - 1;
+
+ extra_x = extra_y = 0;
+
+ if (s->face->id == TAB_BAR_FACE_ID)
+ {
+ if (CONSP (Vtab_bar_button_margin)
+ && FIXNUMP (XCAR (Vtab_bar_button_margin))
+ && FIXNUMP (XCDR (Vtab_bar_button_margin)))
+ {
+ extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
+ extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
+ }
+ else if (FIXNUMP (Vtab_bar_button_margin))
+ extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
+ }
+
+ if (s->face->id == TOOL_BAR_FACE_ID)
+ {
+ if (CONSP (Vtool_bar_button_margin)
+ && FIXNUMP (XCAR (Vtool_bar_button_margin))
+ && FIXNUMP (XCDR (Vtool_bar_button_margin)))
+ {
+ extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin));
+ extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin));
+ }
+ else if (FIXNUMP (Vtool_bar_button_margin))
+ extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin);
+ }
+
+ top_p = bot_p = left_p = right_p = 0;
+
+ if (s->slice.x == 0)
+ x -= thick + extra_x, left_p = 1;
+ if (s->slice.y == 0)
+ y -= thick + extra_y, top_p = 1;
+ if (s->slice.x + s->slice.width == s->img->width)
+ x1 += thick + extra_x, right_p = 1;
+ if (s->slice.y + s->slice.height == s->img->height)
+ y1 += thick + extra_y, bot_p = 1;
+
+ get_glyph_string_clip_rect (s, &r);
+ haiku_draw_relief_rect (s, x, y, x1, y1, thick, thick, raised_p,
+ top_p, bot_p, left_p, right_p, &r, 0);
+}
+
+static void
+haiku_draw_image_glyph_string (struct glyph_string *s)
+{
+ struct face *face = s->face;
+
+ int box_line_hwidth = max (face->box_vertical_line_width, 0);
+ int box_line_vwidth = max (face->box_horizontal_line_width, 0);
+
+ int x, y;
+ int height, width;
+
+ height = s->height;
+ if (s->slice.y == 0)
+ height -= box_line_vwidth;
+ if (s->slice.y + s->slice.height >= s->img->height)
+ height -= box_line_vwidth;
+
+ width = s->background_width;
+ x = s->x;
+ if (s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ {
+ x += box_line_hwidth;
+ width -= box_line_hwidth;
+ }
+
+ y = s->y;
+ if (s->slice.y == 0)
+ y += box_line_vwidth;
+
+ void *view = FRAME_HAIKU_VIEW (s->f);
+ void *bitmap = s->img->pixmap;
+
+ s->stippled_p = face->stipple != 0;
+
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ BView_SetHighColor (view, face->background);
+ BView_FillRectangle (view, x, y, width, height);
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+
+ if (bitmap)
+ {
+ struct haiku_rect nr;
+ Emacs_Rectangle cr, ir, r;
+
+ get_glyph_string_clip_rect (s, &nr);
+ CONVERT_TO_EMACS_RECT (cr, nr);
+ x = s->x;
+ y = s->ybase - image_ascent (s->img, face, &s->slice);
+
+ if (s->slice.x == 0)
+ x += s->img->hmargin;
+ if (s->slice.y == 0)
+ y += s->img->vmargin;
+
+ if (face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ x += max (face->box_vertical_line_width, 0);
+
+ ir.x = x;
+ ir.y = y;
+ ir.width = s->slice.width;
+ ir.height = s->slice.height;
+ r = ir;
+
+ void *mask = s->img->mask;
+
+ if (gui_intersect_rectangles (&cr, &ir, &r))
+ {
+ BView_draw_lock (view);
+ BView_StartClip (view);
+
+ haiku_clip_to_string (s);
+ if (s->img->have_be_transforms_p)
+ {
+ bitmap = BBitmap_transform_bitmap (bitmap,
+ s->img->mask,
+ face->background,
+ s->img->be_rotate,
+ s->img->width,
+ s->img->height);
+ mask = NULL;
+ }
+
+ BView_DrawBitmap (view, bitmap,
+ s->slice.x + r.x - x,
+ s->slice.y + r.y - y,
+ r.width, r.height,
+ r.x, r.y, r.width, r.height);
+ if (mask)
+ {
+ BView_DrawMask (mask, view,
+ s->slice.x + r.x - x,
+ s->slice.y + r.y - y,
+ r.width, r.height,
+ r.x, r.y, r.width, r.height,
+ face->background);
+ }
+
+ if (s->img->have_be_transforms_p)
+ BBitmap_free (bitmap);
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+ }
+
+ if (s->hl == DRAW_CURSOR)
+ {
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ BView_SetPenSize (view, 1);
+ BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
+ BView_StrokeRectangle (view, r.x, r.y, r.width, r.height);
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+ }
+ }
+
+ if (s->img->relief
+ || s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ haiku_draw_image_relief (s);
+}
+
+static void
+haiku_draw_glyph_string (struct glyph_string *s)
+{
+ block_input ();
+ prepare_face_for_display (s->f, s->face);
+
+ struct face *face = s->face;
+ if (face != s->face)
+ prepare_face_for_display (s->f, face);
+
+ if (s->next && s->right_overhang && !s->for_overlaps)
+ {
+ int width;
+ struct glyph_string *next;
+
+ for (width = 0, next = s->next;
+ next && width < s->right_overhang;
+ width += next->width, next = next->next)
+ if (next->first_glyph->type != IMAGE_GLYPH)
+ {
+ prepare_face_for_display (s->f, s->next->face);
+ haiku_start_clip (s->next);
+ haiku_clip_to_string (s->next);
+ if (next->first_glyph->type != STRETCH_GLYPH)
+ haiku_maybe_draw_background (s->next, 1);
+ else
+ haiku_draw_stretch_glyph_string (s->next);
+ next->num_clips = 0;
+ haiku_end_clip (s);
+ }
+ }
+
+ haiku_start_clip (s);
+
+ int box_filled_p = 0;
+
+ if (!s->for_overlaps && face->box != FACE_NO_BOX
+ && (s->first_glyph->type == CHAR_GLYPH
+ || s->first_glyph->type == COMPOSITE_GLYPH))
+ {
+ haiku_clip_to_string (s);
+ haiku_maybe_draw_background (s, 1);
+ box_filled_p = 1;
+ haiku_draw_string_box (s, 0);
+ }
+ else if (!s->clip_head && !s->clip_tail &&
+ ((s->prev && s->left_overhang && s->prev->hl != s->hl) ||
+ (s->next && s->right_overhang && s->next->hl != s->hl)))
+ haiku_clip_to_string_exactly (s, s);
+ else
+ haiku_clip_to_string (s);
+
+ if (s->for_overlaps)
+ s->background_filled_p = 1;
+
+ switch (s->first_glyph->type)
+ {
+ case COMPOSITE_GLYPH:
+ if (s->for_overlaps || (s->cmp_from > 0
+ && ! s->first_glyph->u.cmp.automatic))
+ s->background_filled_p = 1;
+ else
+ haiku_maybe_draw_background (s, 1);
+ haiku_draw_composite_glyph_string_foreground (s);
+ break;
+ case CHAR_GLYPH:
+ if (s->for_overlaps)
+ s->background_filled_p = 1;
+ else
+ haiku_maybe_draw_background (s, 0);
+ haiku_draw_glyph_string_foreground (s);
+ break;
+ case STRETCH_GLYPH:
+ haiku_draw_stretch_glyph_string (s);
+ break;
+ case IMAGE_GLYPH:
+ haiku_draw_image_glyph_string (s);
+ break;
+ case GLYPHLESS_GLYPH:
+ if (s->for_overlaps)
+ s->background_filled_p = 1;
+ else
+ haiku_maybe_draw_background (s, 1);
+ haiku_draw_glyphless_glyph_string_foreground (s);
+ break;
+ }
+
+ if (!box_filled_p && face->box != FACE_NO_BOX)
+ haiku_draw_string_box (s, 1);
+
+ if (!s->for_overlaps)
+ {
+ uint32_t dcol;
+ dcol = face->foreground;
+
+ haiku_draw_text_decoration (s, face, dcol, s->width, s->x);
+
+ if (s->prev)
+ {
+ struct glyph_string *prev;
+
+ for (prev = s->prev; prev; prev = prev->prev)
+ if (prev->hl != s->hl
+ && prev->x + prev->width + prev->right_overhang > s->x)
+ {
+ /* As prev was drawn while clipped to its own area, we
+ must draw the right_overhang part using s->hl now. */
+ enum draw_glyphs_face save = prev->hl;
+ struct face *save_face = prev->face;
+
+ prev->hl = s->hl;
+ prev->face = s->face;
+ haiku_start_clip (s);
+ haiku_clip_to_string_exactly (s, prev);
+ if (prev->first_glyph->type == CHAR_GLYPH)
+ haiku_draw_glyph_string_foreground (prev);
+ else
+ haiku_draw_composite_glyph_string_foreground (prev);
+ haiku_end_clip (s);
+ prev->hl = save;
+ prev->face = save_face;
+ prev->num_clips = 0;
+ }
+ }
+
+ if (s->next)
+ {
+ struct glyph_string *next;
+
+ for (next = s->next; next; next = next->next)
+ if (next->hl != s->hl
+ && next->x - next->left_overhang < s->x + s->width)
+ {
+ /* As next will be drawn while clipped to its own area,
+ we must draw the left_overhang part using s->hl now. */
+ enum draw_glyphs_face save = next->hl;
+ struct face *save_face = next->face;
+
+ next->hl = s->hl;
+ next->face = s->face;
+ haiku_start_clip (s);
+ haiku_clip_to_string_exactly (s, next);
+ if (next->first_glyph->type == CHAR_GLYPH)
+ haiku_draw_glyph_string_foreground (next);
+ else
+ haiku_draw_composite_glyph_string_foreground (next);
+ haiku_end_clip (s);
+
+ next->background_filled_p = 0;
+ next->hl = save;
+ next->face = save_face;
+ next->clip_head = next;
+ next->num_clips = 0;
+ }
+ }
+ }
+ s->num_clips = 0;
+ haiku_end_clip (s);
+ unblock_input ();
+}
+
+static void
+haiku_after_update_window_line (struct window *w,
+ struct glyph_row *desired_row)
+{
+ eassert (w);
+ struct frame *f;
+ int width, height;
+
+ if (!desired_row->mode_line_p && !w->pseudo_window_p)
+ desired_row->redraw_fringe_bitmaps_p = true;
+
+ if (windows_or_buffers_changed
+ && desired_row->full_width_p
+ && (f = XFRAME (w->frame),
+ width = FRAME_INTERNAL_BORDER_WIDTH (f),
+ width != 0)
+ && (height = desired_row->visible_height,
+ height > 0))
+ {
+ int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
+ int face_id =
+ !NILP (Vface_remapping_alist)
+ ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
+ : INTERNAL_BORDER_FACE_ID;
+ struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
+
+ block_input ();
+ if (face)
+ {
+ void *view = FRAME_HAIKU_VIEW (f);
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ BView_SetHighColor (view, face->background_defaulted_p ?
+ FRAME_BACKGROUND_PIXEL (f) : face->background);
+ BView_FillRectangle (view, 0, y, width, height);
+ BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width,
+ y, width, height);
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+ }
+ else
+ {
+ haiku_clear_frame_area (f, 0, y, width, height);
+ haiku_clear_frame_area (f, FRAME_PIXEL_WIDTH (f) - width,
+ y, width, height);
+ }
+ unblock_input ();
+ }
+}
+
+static void
+haiku_set_window_size (struct frame *f, bool change_gravity,
+ int width, int height)
+{
+ haiku_update_size_hints (f);
+
+ if (FRAME_HAIKU_WINDOW (f))
+ {
+ block_input ();
+ BWindow_resize (FRAME_HAIKU_WINDOW (f), width, height);
+ unblock_input ();
+ }
+}
+
+static void
+haiku_draw_window_cursor (struct window *w,
+ struct glyph_row *glyph_row,
+ int x, int y,
+ enum text_cursor_kinds cursor_type,
+ int cursor_width, bool on_p, bool active_p)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+ struct glyph *phys_cursor_glyph;
+ struct glyph *cursor_glyph;
+
+ void *view = FRAME_HAIKU_VIEW (f);
+
+ int fx, fy, h, cursor_height;
+
+ if (!on_p)
+ return;
+
+ if (cursor_type == NO_CURSOR)
+ {
+ w->phys_cursor_width = 0;
+ return;
+ }
+
+ w->phys_cursor_on_p = true;
+ w->phys_cursor_type = cursor_type;
+
+ phys_cursor_glyph = get_phys_cursor_glyph (w);
+
+ if (!phys_cursor_glyph)
+ {
+ if (glyph_row->exact_window_width_line_p
+ && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
+ {
+ glyph_row->cursor_in_fringe_p = 1;
+ draw_fringe_bitmap (w, glyph_row, 0);
+ }
+ return;
+ }
+
+ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
+
+ if (cursor_type == BAR_CURSOR)
+ {
+ if (cursor_width < 1)
+ cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
+ if (cursor_width < w->phys_cursor_width)
+ w->phys_cursor_width = cursor_width;
+ }
+ else if (cursor_type == HBAR_CURSOR)
+ {
+ cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
+ if (cursor_height > glyph_row->height)
+ cursor_height = glyph_row->height;
+ if (h > cursor_height)
+ fy += h - cursor_height;
+ h = cursor_height;
+ }
+
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ BView_SetHighColor (view, FRAME_CURSOR_COLOR (f).pixel);
+ haiku_clip_to_row (w, glyph_row, TEXT_AREA);
+
+ switch (cursor_type)
+ {
+ default:
+ case DEFAULT_CURSOR:
+ case NO_CURSOR:
+ break;
+ case HBAR_CURSOR:
+ BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
+ break;
+ case BAR_CURSOR:
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph->resolved_level & 1)
+ BView_FillRectangle (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width,
+ fy, w->phys_cursor_width, h);
+ else
+ BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
+ break;
+ case HOLLOW_BOX_CURSOR:
+ if (phys_cursor_glyph->type != IMAGE_GLYPH)
+ {
+ BView_SetPenSize (view, 1);
+ BView_StrokeRectangle (view, fx, fy, w->phys_cursor_width, h);
+ }
+ else
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ break;
+ case FILLED_BOX_CURSOR:
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ }
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+}
+
+static void
+haiku_show_hourglass (struct frame *f)
+{
+ if (FRAME_OUTPUT_DATA (f)->hourglass_p)
+ return;
+
+ block_input ();
+ FRAME_OUTPUT_DATA (f)->hourglass_p = 1;
+
+ if (FRAME_HAIKU_VIEW (f))
+ BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
+ FRAME_OUTPUT_DATA (f)->hourglass_cursor);
+ unblock_input ();
+}
+
+static void
+haiku_hide_hourglass (struct frame *f)
+{
+ if (!FRAME_OUTPUT_DATA (f)->hourglass_p)
+ return;
+
+ block_input ();
+ FRAME_OUTPUT_DATA (f)->hourglass_p = 0;
+
+ if (FRAME_HAIKU_VIEW (f))
+ BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
+ FRAME_OUTPUT_DATA (f)->current_cursor);
+ unblock_input ();
+}
+
+static void
+haiku_compute_glyph_string_overhangs (struct glyph_string *s)
+{
+ if (s->cmp == NULL
+ && (s->first_glyph->type == CHAR_GLYPH
+ || s->first_glyph->type == COMPOSITE_GLYPH))
+ {
+ struct font_metrics metrics;
+
+ if (s->first_glyph->type == CHAR_GLYPH)
+ {
+ struct font *font = s->font;
+ font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
+ }
+ else
+ {
+ Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
+
+ composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
+ }
+ s->right_overhang = (metrics.rbearing > metrics.width
+ ? metrics.rbearing - metrics.width : 0);
+ s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
+ }
+ else if (s->cmp)
+ {
+ s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
+ s->left_overhang = - s->cmp->lbearing;
+ }
+}
+
+static void
+haiku_draw_vertical_window_border (struct window *w,
+ int x, int y_0, int y_1)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct face *face;
+
+ face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
+ void *view = FRAME_HAIKU_VIEW (f);
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ if (face)
+ BView_SetHighColor (view, face->foreground);
+ BView_StrokeLine (view, x, y_0, x, y_1);
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+}
+
+static void
+haiku_set_scroll_bar_default_width (struct frame *f)
+{
+ int unit = FRAME_COLUMN_WIDTH (f);
+ FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = BScrollBar_default_size (0) + 1;
+ FRAME_CONFIG_SCROLL_BAR_COLS (f) =
+ (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
+}
+
+static void
+haiku_set_scroll_bar_default_height (struct frame *f)
+{
+ int height = FRAME_LINE_HEIGHT (f);
+ FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = BScrollBar_default_size (1) + 1;
+ FRAME_CONFIG_SCROLL_BAR_LINES (f) =
+ (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
+}
+
+static void
+haiku_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
+ struct face *face_first
+ = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
+ struct face *face_last
+ = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
+ unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
+ unsigned long color_first = (face_first
+ ? face_first->foreground
+ : FRAME_FOREGROUND_PIXEL (f));
+ unsigned long color_last = (face_last
+ ? face_last->foreground
+ : FRAME_FOREGROUND_PIXEL (f));
+ void *view = FRAME_HAIKU_VIEW (f);
+
+ BView_draw_lock (view);
+ BView_StartClip (view);
+
+ if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
+ /* A vertical divider, at least three pixels wide: Draw first and
+ last pixels differently. */
+ {
+ BView_SetHighColor (view, color_first);
+ BView_StrokeLine (view, x0, y0, x0, y1 - 1);
+ BView_SetHighColor (view, color);
+ BView_FillRectangle (view, x0 + 1, y0, x1 - x0 - 2, y1 - y0);
+ BView_SetHighColor (view, color_last);
+ BView_StrokeLine (view, x1 - 1, y0, x1 - 1, y1 - 1);
+ }
+ else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
+ /* A horizontal divider, at least three pixels high: Draw first and
+ last pixels differently. */
+ {
+ BView_SetHighColor (view, color_first);
+ BView_StrokeLine (f, x0, y0, x1 - 1, y0);
+ BView_SetHighColor (view, color);
+ BView_FillRectangle (view, x0, y0 + 1, x1 - x0, y1 - y0 - 2);
+ BView_SetHighColor (view, color_last);
+ BView_StrokeLine (view, x0, y1, x1 - 1, y1);
+ }
+ else
+ {
+ BView_SetHighColor (view, color);
+ BView_FillRectangleAbs (view, x0, y0, x1, y1);
+ }
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+}
+
+static void
+haiku_condemn_scroll_bars (struct frame *frame)
+{
+ if (!NILP (FRAME_SCROLL_BARS (frame)))
+ {
+ if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
+ {
+ /* Prepend scrollbars to already condemned ones. */
+ Lisp_Object last = FRAME_SCROLL_BARS (frame);
+
+ while (!NILP (XSCROLL_BAR (last)->next))
+ last = XSCROLL_BAR (last)->next;
+
+ XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
+ XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
+ }
+
+ fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
+ fset_scroll_bars (frame, Qnil);
+ }
+}
+
+static void
+haiku_redeem_scroll_bar (struct window *w)
+{
+ struct scroll_bar *bar;
+ Lisp_Object barobj;
+ struct frame *f;
+
+ if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+ {
+ bar = XSCROLL_BAR (w->vertical_scroll_bar);
+ /* Unlink it from the condemned list. */
+ f = XFRAME (WINDOW_FRAME (w));
+ if (NILP (bar->prev))
+ {
+ /* If the prev pointer is nil, it must be the first in one of
+ the lists. */
+ if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
+ /* It's not condemned. Everything's fine. */
+ goto horizontal;
+ else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+ w->vertical_scroll_bar))
+ fset_condemned_scroll_bars (f, bar->next);
+ else
+ /* If its prev pointer is nil, it must be at the front of
+ one or the other! */
+ emacs_abort ();
+ }
+ else
+ XSCROLL_BAR (bar->prev)->next = bar->next;
+
+ if (! NILP (bar->next))
+ XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (barobj, bar);
+ fset_scroll_bars (f, barobj);
+ if (! NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+ }
+ horizontal:
+ if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
+ {
+ bar = XSCROLL_BAR (w->horizontal_scroll_bar);
+ /* Unlink it from the condemned list. */
+ f = XFRAME (WINDOW_FRAME (w));
+ if (NILP (bar->prev))
+ {
+ /* If the prev pointer is nil, it must be the first in one of
+ the lists. */
+ if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
+ /* It's not condemned. Everything's fine. */
+ return;
+ else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+ w->horizontal_scroll_bar))
+ fset_condemned_scroll_bars (f, bar->next);
+ else
+ /* If its prev pointer is nil, it must be at the front of
+ one or the other! */
+ emacs_abort ();
+ }
+ else
+ XSCROLL_BAR (bar->prev)->next = bar->next;
+
+ if (! NILP (bar->next))
+ XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (barobj, bar);
+ fset_scroll_bars (f, barobj);
+ if (! NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+ }
+}
+
+static void
+haiku_judge_scroll_bars (struct frame *f)
+{
+ Lisp_Object bar, next;
+
+ bar = FRAME_CONDEMNED_SCROLL_BARS (f);
+
+ /* Clear out the condemned list now so we won't try to process any
+ more events on the hapless scroll bars. */
+ fset_condemned_scroll_bars (f, Qnil);
+
+ for (; ! NILP (bar); bar = next)
+ {
+ struct scroll_bar *b = XSCROLL_BAR (bar);
+
+ haiku_scroll_bar_remove (b);
+
+ next = b->next;
+ b->next = b->prev = Qnil;
+ }
+
+ /* Now there should be no references to the condemned scroll bars,
+ and they should get garbage-collected. */
+}
+
+static struct scroll_bar *
+haiku_scroll_bar_create (struct window *w, int left, int top,
+ int width, int height, bool horizontal_p)
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ Lisp_Object barobj;
+
+ void *sb = NULL;
+ void *vw = FRAME_HAIKU_VIEW (f);
+
+ block_input ();
+ struct scroll_bar *bar
+ = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
+
+ XSETWINDOW (bar->window, w);
+ bar->top = top;
+ bar->left = left;
+ bar->width = width;
+ bar->height = height;
+ bar->position = 0;
+ bar->total = 0;
+ bar->dragging = 0;
+ bar->update = -1;
+ bar->horizontal = horizontal_p;
+
+ sb = BScrollBar_make_for_view (vw, horizontal_p,
+ left, top, left + width - 1,
+ top + height - 1, bar);
+
+ BView_publish_scroll_bar (vw, left, top, width, height);
+
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ bar->scroll_bar = sb;
+ XSETVECTOR (barobj, bar);
+ fset_scroll_bars (f, barobj);
+
+ if (!NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+
+ unblock_input ();
+ return bar;
+}
+
+static void
+haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
+{
+ eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
+ Lisp_Object barobj;
+ struct scroll_bar *bar;
+ int top, height, left, width;
+ int window_x, window_width;
+
+ /* Get window dimensions. */
+ window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
+ left = window_x;
+ width = window_width;
+ top = WINDOW_SCROLL_BAR_AREA_Y (w);
+ height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
+
+ block_input ();
+
+ if (NILP (w->horizontal_scroll_bar))
+ {
+ bar = haiku_scroll_bar_create (w, left, top, width, height, true);
+ BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
+ bar->update = position;
+ bar->position = position;
+ bar->total = whole;
+ }
+ else
+ {
+ bar = XSCROLL_BAR (w->horizontal_scroll_bar);
+
+ if (bar->left != left || bar->top != top ||
+ bar->width != width || bar->height != height)
+ {
+ void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
+ BView_forget_scroll_bar (view, bar->left, bar->top,
+ bar->width, bar->height);
+ BView_move_frame (bar->scroll_bar, left, top,
+ left + width - 1, top + height - 1);
+ BView_publish_scroll_bar (view, left, top, width, height);
+ bar->left = left;
+ bar->top = top;
+ bar->width = width;
+ bar->height = height;
+ }
+
+ if (!bar->dragging)
+ {
+ BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
+ BView_invalidate (bar->scroll_bar);
+ }
+ }
+ bar->position = position;
+ bar->total = whole;
+ XSETVECTOR (barobj, bar);
+ wset_horizontal_scroll_bar (w, barobj);
+ unblock_input ();
+}
+
+static void
+haiku_set_vertical_scroll_bar (struct window *w,
+ int portion, int whole, int position)
+{
+ eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
+ Lisp_Object barobj;
+ struct scroll_bar *bar;
+ int top, height, left, width;
+ int window_y, window_height;
+
+ /* Get window dimensions. */
+ window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
+ top = window_y;
+ height = window_height;
+
+ /* Compute the left edge and the width of the scroll bar area. */
+ left = WINDOW_SCROLL_BAR_AREA_X (w);
+ width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+ block_input ();
+
+ if (NILP (w->vertical_scroll_bar))
+ {
+ bar = haiku_scroll_bar_create (w, left, top, width, height, false);
+ BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
+ bar->position = position;
+ bar->total = whole;
+ }
+ else
+ {
+ bar = XSCROLL_BAR (w->vertical_scroll_bar);
+
+ if (bar->left != left || bar->top != top ||
+ bar->width != width || bar->height != height)
+ {
+ void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
+ BView_forget_scroll_bar (view, bar->left, bar->top,
+ bar->width, bar->height);
+ BView_move_frame (bar->scroll_bar, left, top,
+ left + width - 1, top + height - 1);
+ flush_frame (WINDOW_XFRAME (w));
+ BView_publish_scroll_bar (view, left, top, width, height);
+ bar->left = left;
+ bar->top = top;
+ bar->width = width;
+ bar->height = height;
+ }
+
+ if (!bar->dragging)
+ {
+ BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
+ bar->update = position;
+ BView_invalidate (bar->scroll_bar);
+ }
+ }
+
+ bar->position = position;
+ bar->total = whole;
+
+ XSETVECTOR (barobj, bar);
+ wset_vertical_scroll_bar (w, barobj);
+ unblock_input ();
+}
+
+static void
+haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
+ struct draw_fringe_bitmap_params *p)
+{
+ void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w)));
+ struct face *face = p->face;
+
+ BView_draw_lock (view);
+ BView_StartClip (view);
+
+ haiku_clip_to_row (w, row, ANY_AREA);
+ if (p->bx >= 0 && !p->overlay_p)
+ {
+ BView_SetHighColor (view, face->background);
+ BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
+ }
+
+ if (p->which && p->which < fringe_bitmap_fillptr)
+ {
+ void *bitmap = fringe_bmps[p->which];
+
+ uint32_t col;
+
+ if (!p->cursor_p)
+ col = face->foreground;
+ else if (p->overlay_p)
+ col = face->background;
+ else
+ col = FRAME_CURSOR_COLOR (XFRAME (WINDOW_FRAME (w))).pixel;
+
+ if (!p->overlay_p)
+ {
+ BView_SetHighColor (view, face->background);
+ BView_FillRectangle (view, p->x, p->y, p->wd, p->h);
+ }
+
+ BView_SetLowColor (view, col);
+ BView_DrawBitmapWithEraseOp (view, bitmap, p->x, p->y, p->wd, p->h);
+ }
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+}
+
+static void
+haiku_define_fringe_bitmap (int which, unsigned short *bits,
+ int h, int wd)
+{
+ if (which >= fringe_bitmap_fillptr)
+ {
+ int i = fringe_bitmap_fillptr;
+ fringe_bitmap_fillptr = which + 20;
+ fringe_bmps = !i ? xmalloc (fringe_bitmap_fillptr * sizeof (void *)) :
+ xrealloc (fringe_bmps, fringe_bitmap_fillptr * sizeof (void *));
+
+ while (i < fringe_bitmap_fillptr)
+ fringe_bmps[i++] = NULL;
+ }
+
+ fringe_bmps[which] = BBitmap_new (wd, h, 1);
+ BBitmap_import_mono_bits (fringe_bmps[which], bits, wd, h);
+}
+
+static void
+haiku_destroy_fringe_bitmap (int which)
+{
+ if (which >= fringe_bitmap_fillptr)
+ return;
+
+ if (fringe_bmps[which])
+ BBitmap_free (fringe_bmps[which]);
+ fringe_bmps[which] = NULL;
+}
+
+static void
+haiku_scroll_run (struct window *w, struct run *run)
+{
+ struct frame *f = XFRAME (w->frame);
+ void *view = FRAME_HAIKU_VIEW (f);
+ int x, y, width, height, from_y, to_y, bottom_y;
+ window_box (w, ANY_AREA, &x, &y, &width, &height);
+
+ from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
+ to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
+ bottom_y = y + height;
+
+ if (to_y < from_y)
+ {
+ /* Scrolling up. Make sure we don't copy part of the mode
+ line at the bottom. */
+ if (from_y + run->height > bottom_y)
+ height = bottom_y - from_y;
+ else
+ height = run->height;
+ }
+ else
+ {
+ /* Scrolling down. Make sure we don't copy over the mode line.
+ at the bottom. */
+ if (to_y + run->height > bottom_y)
+ height = bottom_y - to_y;
+ else
+ height = run->height;
+ }
+
+ if (!height)
+ return;
+
+ block_input ();
+ gui_clear_cursor (w);
+ BView_draw_lock (view);
+#ifdef USE_BE_CAIRO
+ if (EmacsView_double_buffered_p (view))
+ {
+#endif
+ BView_StartClip (view);
+ BView_CopyBits (view, x, from_y, width, height,
+ x, to_y, width, height);
+ BView_EndClip (view);
+#ifdef USE_BE_CAIRO
+ }
+ else
+ {
+ EmacsWindow_begin_cr_critical_section (FRAME_HAIKU_WINDOW (f));
+ cairo_surface_t *surface = FRAME_CR_SURFACE (f);
+ cairo_surface_t *s
+ = cairo_surface_create_similar (surface,
+ cairo_surface_get_content (surface),
+ width, height);
+ cairo_t *cr = cairo_create (s);
+ if (surface)
+ {
+ cairo_set_source_surface (cr, surface, -x, -from_y);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ cr = haiku_begin_cr_clip (f, NULL);
+ cairo_save (cr);
+ cairo_set_source_surface (cr, s, x, to_y);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle (cr, x, to_y, width, height);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ cairo_surface_destroy (s);
+ haiku_end_cr_clip (cr);
+ }
+ EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
+ }
+#endif
+ BView_draw_unlock (view);
+
+ unblock_input ();
+}
+
+static void
+haiku_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
+ enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
+ Time *timestamp)
+{
+ block_input ();
+ if (!fp)
+ return;
+ Lisp_Object frame, tail;
+ struct frame *f1 = NULL;
+ FOR_EACH_FRAME (tail, frame)
+ XFRAME (frame)->mouse_moved = false;
+
+ if (gui_mouse_grabbed (x_display_list) && !EQ (track_mouse, Qdropping))
+ f1 = x_display_list->last_mouse_frame;
+
+ if (!f1 || FRAME_TOOLTIP_P (f1))
+ f1 = ((EQ (track_mouse, Qdropping) && gui_mouse_grabbed (x_display_list))
+ ? x_display_list->last_mouse_frame
+ : NULL);
+
+ if (!f1 && insist > 0)
+ f1 = SELECTED_FRAME ();
+
+ if (!f1 || (!FRAME_HAIKU_P (f1) && (insist > 0)))
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_HAIKU_P (XFRAME (frame)) &&
+ !FRAME_TOOLTIP_P (XFRAME (frame)))
+ f1 = XFRAME (frame);
+
+ if (FRAME_TOOLTIP_P (f1))
+ f1 = NULL;
+
+ if (f1 && FRAME_HAIKU_P (f1))
+ {
+ int sx, sy;
+ void *view = FRAME_HAIKU_VIEW (f1);
+ if (view)
+ {
+ BView_get_mouse (view, &sx, &sy);
+
+ remember_mouse_glyph (f1, sx, sy, &x_display_list->last_mouse_glyph);
+ x_display_list->last_mouse_glyph_frame = f1;
+
+ *bar_window = Qnil;
+ *part = scroll_bar_above_handle;
+ *fp = f1;
+ XSETINT (*x, sx);
+ XSETINT (*y, sy);
+ }
+ }
+
+ unblock_input ();
+}
+
+static void
+haiku_flush (struct frame *f)
+{
+ if (FRAME_VISIBLE_P (f))
+ BWindow_Flush (FRAME_HAIKU_WINDOW (f));
+}
+
+static void
+haiku_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
+{
+ if (f->tooltip)
+ return;
+ block_input ();
+ if (!f->pointer_invisible && FRAME_HAIKU_VIEW (f)
+ && !FRAME_OUTPUT_DATA (f)->hourglass_p)
+ BView_set_view_cursor (FRAME_HAIKU_VIEW (f), cursor);
+ unblock_input ();
+ FRAME_OUTPUT_DATA (f)->current_cursor = cursor;
+}
+
+static void
+haiku_update_window_end (struct window *w, bool cursor_on_p,
+ bool mouse_face_overwritten_p)
+{
+
+}
+
+static void
+haiku_default_font_parameter (struct frame *f, Lisp_Object parms)
+{
+ struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+ Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
+ RES_TYPE_STRING);
+ Lisp_Object font = Qnil;
+ if (EQ (font_param, Qunbound))
+ font_param = Qnil;
+
+ if (NILP (font_param))
+ {
+ /* System font should take precedence over X resources. We suggest this
+ regardless of font-use-system-font because .emacs may not have been
+ read yet. */
+ struct haiku_font_pattern ptn;
+ ptn.specified = 0;
+
+ if (f->tooltip)
+ BFont_populate_plain_family (&ptn);
+ else
+ BFont_populate_fixed_family (&ptn);
+
+ if (ptn.specified & FSPEC_FAMILY)
+ font = font_open_by_name (f, build_unibyte_string (ptn.family));
+ }
+
+ if (NILP (font))
+ font = !NILP (font_param) ? font_param
+ : gui_display_get_arg (dpyinfo, parms, Qfont, "font", "Font",
+ RES_TYPE_STRING);
+
+ if (! FONTP (font) && ! STRINGP (font))
+ {
+ const char **names = (const char *[]) { "monospace-12",
+ "Noto Sans Mono-12",
+ "Source Code Pro-12",
+ NULL };
+ int i;
+
+ for (i = 0; names[i]; i++)
+ {
+ font
+ = font_open_by_name (f, build_unibyte_string (names[i]));
+ if (!NILP (font))
+ break;
+ }
+ if (NILP (font))
+ error ("No suitable font was found");
+ }
+ else if (!NILP (font_param))
+ {
+ /* Remember the explicit font parameter, so we can re-apply it
+ after we've applied the `default' face settings. */
+ AUTO_FRAME_ARG (arg, Qfont_parameter, font_param);
+ gui_set_frame_parameters (f, arg);
+ }
+
+ gui_default_parameter (f, parms, Qfont, font, "font", "Font",
+ RES_TYPE_STRING);
+}
+
+static struct redisplay_interface haiku_redisplay_interface =
+ {
+ haiku_frame_parm_handlers,
+ gui_produce_glyphs,
+ gui_write_glyphs,
+ gui_insert_glyphs,
+ gui_clear_end_of_line,
+ haiku_scroll_run,
+ haiku_after_update_window_line,
+ NULL,
+ haiku_update_window_end,
+ haiku_flush,
+ gui_clear_window_mouse_face,
+ gui_get_glyph_overhangs,
+ gui_fix_overlapping_area,
+ haiku_draw_fringe_bitmap,
+ haiku_define_fringe_bitmap,
+ haiku_destroy_fringe_bitmap,
+ haiku_compute_glyph_string_overhangs,
+ haiku_draw_glyph_string,
+ haiku_define_frame_cursor,
+ haiku_clear_frame_area,
+ haiku_clear_under_internal_border,
+ haiku_draw_window_cursor,
+ haiku_draw_vertical_window_border,
+ haiku_draw_window_divider,
+ 0, /* shift glyphs for insert */
+ haiku_show_hourglass,
+ haiku_hide_hourglass,
+ haiku_default_font_parameter,
+ };
+
+static void
+haiku_make_fullscreen_consistent (struct frame *f)
+{
+ Lisp_Object lval = get_frame_param (f, Qfullscreen);
+
+ if (!EQ (lval, Qmaximized) && FRAME_OUTPUT_DATA (f)->zoomed_p)
+ lval = Qmaximized;
+ else if (EQ (lval, Qmaximized) && !FRAME_OUTPUT_DATA (f)->zoomed_p)
+ lval = Qnil;
+
+ store_frame_param (f, Qfullscreen, lval);
+}
+
+static int
+haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
+{
+ block_input ();
+ int message_count = 0;
+ static void *buf = NULL;
+ ssize_t b_size;
+ struct unhandled_event *unhandled_events = NULL;
+
+ if (!buf)
+ buf = xmalloc (200);
+ haiku_read_size (&b_size);
+ while (b_size >= 0)
+ {
+ enum haiku_event_type type;
+ struct input_event inev, inev2;
+
+ if (b_size > 200)
+ emacs_abort ();
+
+ EVENT_INIT (inev);
+ EVENT_INIT (inev2);
+ inev.kind = NO_EVENT;
+ inev2.kind = NO_EVENT;
+ inev.arg = Qnil;
+ inev2.arg = Qnil;
+
+ haiku_read (&type, buf, b_size);
+
+ switch (type)
+ {
+ case QUIT_REQUESTED:
+ {
+ struct haiku_quit_requested_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ inev.kind = DELETE_WINDOW_EVENT;
+ XSETFRAME (inev.frame_or_window, f);
+ break;
+ }
+ case FRAME_RESIZED:
+ {
+ struct haiku_resize_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ int width = (int) b->px_widthf;
+ int height = (int) b->px_heightf;
+
+ BView_draw_lock (FRAME_HAIKU_VIEW (f));
+ BView_resize_to (FRAME_HAIKU_VIEW (f), width, height);
+ BView_draw_unlock (FRAME_HAIKU_VIEW (f));
+ if (width != FRAME_PIXEL_WIDTH (f)
+ || height != FRAME_PIXEL_HEIGHT (f)
+ || (f->new_size_p
+ && ((f->new_width >= 0 && width != f->new_width)
+ || (f->new_height >= 0 && height != f->new_height))))
+ {
+ change_frame_size (f, width, height, false, true, false);
+ SET_FRAME_GARBAGED (f);
+ cancel_mouse_face (f);
+ haiku_clear_under_internal_border (f);
+ }
+
+ if (FRAME_OUTPUT_DATA (f)->pending_zoom_width != width ||
+ FRAME_OUTPUT_DATA (f)->pending_zoom_height != height)
+ {
+ FRAME_OUTPUT_DATA (f)->zoomed_p = 0;
+ haiku_make_fullscreen_consistent (f);
+ }
+ else
+ {
+ FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
+ FRAME_OUTPUT_DATA (f)->pending_zoom_width = INT_MIN;
+ FRAME_OUTPUT_DATA (f)->pending_zoom_height = INT_MIN;
+ }
+ break;
+ }
+ case FRAME_EXPOSED:
+ {
+ struct haiku_expose_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ expose_frame (f, b->x, b->y, b->width, b->height);
+
+ haiku_clear_under_internal_border (f);
+ break;
+ }
+ case KEY_DOWN:
+ {
+ struct haiku_key_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+ int non_ascii_p;
+ if (!f)
+ continue;
+
+ inev.code = b->unraw_mb_char;
+
+ BMapKey (b->kc, &non_ascii_p, &inev.code);
+
+ if (non_ascii_p)
+ inev.kind = NON_ASCII_KEYSTROKE_EVENT;
+ else
+ inev.kind = inev.code > 127 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT :
+ ASCII_KEYSTROKE_EVENT;
+
+ inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
+ XSETFRAME (inev.frame_or_window, f);
+ break;
+ }
+ case ACTIVATION:
+ {
+ struct haiku_activation_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ if ((x_display_list->focus_event_frame != f && b->activated_p) ||
+ (x_display_list->focus_event_frame == f && !b->activated_p))
+ {
+ haiku_new_focus_frame (b->activated_p ? f : NULL);
+ if (b->activated_p)
+ x_display_list->focus_event_frame = f;
+ else
+ x_display_list->focus_event_frame = NULL;
+ inev.kind = b->activated_p ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
+ XSETFRAME (inev.frame_or_window, f);
+ }
+
+ break;
+ }
+ case MOUSE_MOTION:
+ {
+ struct haiku_mouse_motion_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ Lisp_Object frame;
+ XSETFRAME (frame, f);
+
+ if (b->just_exited_p)
+ {
+ Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+ if (f == hlinfo->mouse_face_mouse_frame)
+ {
+ /* If we move outside the frame, then we're
+ certainly no longer on any text in the frame. */
+ clear_mouse_face (hlinfo);
+ hlinfo->mouse_face_mouse_frame = 0;
+ }
+
+ haiku_new_focus_frame (x_display_list->focused_frame);
+ help_echo_string = Qnil;
+ gen_help_event (Qnil, frame, Qnil, Qnil, 0);
+ }
+ else
+ {
+ struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+ struct haiku_rect r = dpyinfo->last_mouse_glyph;
+
+ dpyinfo->last_mouse_motion_x = b->x;
+ dpyinfo->last_mouse_motion_y = b->y;
+ dpyinfo->last_mouse_motion_frame = f;
+
+ previous_help_echo_string = help_echo_string;
+ help_echo_string = Qnil;
+
+ if (f != dpyinfo->last_mouse_glyph_frame ||
+ b->x < r.x || b->x >= r.x + r.width - 1 || b->y < r.y ||
+ b->y >= r.y + r.height - 1)
+ {
+ f->mouse_moved = true;
+ dpyinfo->last_mouse_scroll_bar = NULL;
+ note_mouse_highlight (f, b->x, b->y);
+ remember_mouse_glyph (f, b->x, b->y,
+ &FRAME_DISPLAY_INFO (f)->last_mouse_glyph);
+ dpyinfo->last_mouse_glyph_frame = f;
+ gen_help_event (help_echo_string, frame, help_echo_window,
+ help_echo_object, help_echo_pos);
+ }
+
+ if (MOUSE_HL_INFO (f)->mouse_face_hidden)
+ {
+ MOUSE_HL_INFO (f)->mouse_face_hidden = 0;
+ clear_mouse_face (MOUSE_HL_INFO (f));
+ }
+
+ if (!NILP (Vmouse_autoselect_window))
+ {
+ static Lisp_Object last_mouse_window;
+ Lisp_Object window = window_from_coordinates (f, b->x, b->y, 0, 0, 0);
+
+ if (WINDOWP (window)
+ && !EQ (window, last_mouse_window)
+ && !EQ (window, selected_window)
+ && (!NILP (focus_follows_mouse)
+ || (EQ (XWINDOW (window)->frame,
+ XWINDOW (selected_window)->frame))))
+ {
+ inev.kind = SELECT_WINDOW_EVENT;
+ inev.frame_or_window = window;
+ }
+
+ last_mouse_window = window;
+ }
+ }
+ break;
+ }
+ case BUTTON_UP:
+ case BUTTON_DOWN:
+ {
+ struct haiku_button_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+ Lisp_Object tab_bar_arg = Qnil;
+ int tab_bar_p = 0, tool_bar_p = 0;
+
+ if (!f)
+ continue;
+
+ struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
+
+ x_display_list->last_mouse_glyph_frame = 0;
+
+ /* Is this in the tab-bar? */
+ if (WINDOWP (f->tab_bar_window)
+ && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
+ {
+ Lisp_Object window;
+ int x = b->x;
+ int y = b->y;
+
+ window = window_from_coordinates (f, x, y, 0, true, true);
+ tab_bar_p = EQ (window, f->tab_bar_window);
+
+ if (tab_bar_p)
+ tab_bar_arg = handle_tab_bar_click
+ (f, x, y, type == BUTTON_DOWN, inev.modifiers);
+ }
+
+ if (WINDOWP (f->tool_bar_window)
+ && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
+ {
+ Lisp_Object window;
+ int x = b->x;
+ int y = b->y;
+
+ window = window_from_coordinates (f, x, y, 0, true, true);
+ tool_bar_p = EQ (window, f->tool_bar_window);
+
+ if (tool_bar_p)
+ handle_tool_bar_click
+ (f, x, y, type == BUTTON_DOWN, inev.modifiers);
+ }
+
+ if (type == BUTTON_UP)
+ {
+ inev.modifiers |= up_modifier;
+ dpyinfo->grabbed &= ~(1 << b->btn_no);
+ }
+ else
+ {
+ inev.modifiers |= down_modifier;
+ dpyinfo->last_mouse_frame = f;
+ dpyinfo->grabbed |= (1 << b->btn_no);
+ if (f && !tab_bar_p)
+ f->last_tab_bar_item = -1;
+ if (f && !tool_bar_p)
+ f->last_tool_bar_item = -1;
+ }
+
+ if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
+ inev.kind = MOUSE_CLICK_EVENT;
+ inev.arg = tab_bar_arg;
+ inev.code = b->btn_no;
+
+ inev.modifiers |= type == BUTTON_UP ?
+ up_modifier : down_modifier;
+
+ XSETINT (inev.x, b->x);
+ XSETINT (inev.y, b->y);
+
+ XSETFRAME (inev.frame_or_window, f);
+ break;
+ }
+ case ICONIFICATION:
+ {
+ struct haiku_iconification_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ if (!b->iconified_p)
+ {
+ SET_FRAME_VISIBLE (f, 1);
+ SET_FRAME_ICONIFIED (f, 0);
+ inev.kind = DEICONIFY_EVENT;
+
+
+ /* Haiku doesn't expose frames on deiconification, but
+ if we are double-buffered, the previous screen
+ contents should have been preserved. */
+ if (!EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)))
+ {
+ SET_FRAME_GARBAGED (f);
+ expose_frame (f, 0, 0, 0, 0);
+ }
+ }
+ else
+ {
+ SET_FRAME_VISIBLE (f, 0);
+ SET_FRAME_ICONIFIED (f, 1);
+ inev.kind = ICONIFY_EVENT;
+ }
+
+ XSETFRAME (inev.frame_or_window, f);
+ break;
+ }
+ case MOVE_EVENT:
+ {
+ struct haiku_move_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ if (FRAME_OUTPUT_DATA (f)->pending_zoom_x != b->x ||
+ FRAME_OUTPUT_DATA (f)->pending_zoom_y != b->y)
+ FRAME_OUTPUT_DATA (f)->zoomed_p = 0;
+ else
+ {
+ FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
+ FRAME_OUTPUT_DATA (f)->pending_zoom_x = INT_MIN;
+ FRAME_OUTPUT_DATA (f)->pending_zoom_y = INT_MIN;
+ }
+
+ if (FRAME_PARENT_FRAME (f))
+ haiku_coords_from_parent (f, &b->x, &b->y);
+
+ if (b->x != f->left_pos || b->y != f->top_pos)
+ {
+ inev.kind = MOVE_FRAME_EVENT;
+
+ XSETINT (inev.x, b->x);
+ XSETINT (inev.y, b->y);
+
+ f->left_pos = b->x;
+ f->top_pos = b->y;
+
+ struct frame *p;
+
+ if ((p = FRAME_PARENT_FRAME (f)))
+ {
+ void *window = FRAME_HAIKU_WINDOW (p);
+ EmacsWindow_move_weak_child (window, b->window, b->x, b->y);
+ }
+
+ XSETFRAME (inev.frame_or_window, f);
+ }
+
+ haiku_make_fullscreen_consistent (f);
+ break;
+ }
+ case SCROLL_BAR_VALUE_EVENT:
+ {
+ struct haiku_scroll_bar_value_event *b = buf;
+ struct scroll_bar *bar = b->scroll_bar;
+
+ struct window *w = XWINDOW (bar->window);
+
+ if (bar->update != -1)
+ {
+ bar->update = -1;
+ break;
+ }
+
+ if (bar->position != b->position)
+ {
+ inev.kind = bar->horizontal ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT :
+ SCROLL_BAR_CLICK_EVENT;
+ inev.part = bar->horizontal ?
+ scroll_bar_horizontal_handle : scroll_bar_handle;
+
+ XSETINT (inev.x, b->position);
+ XSETINT (inev.y, bar->total);
+ XSETWINDOW (inev.frame_or_window, w);
+ }
+ break;
+ }
+ case SCROLL_BAR_DRAG_EVENT:
+ {
+ struct haiku_scroll_bar_drag_event *b = buf;
+ struct scroll_bar *bar = b->scroll_bar;
+
+ bar->dragging = b->dragging_p;
+ if (!b->dragging_p && bar->horizontal)
+ set_horizontal_scroll_bar (XWINDOW (bar->window));
+ else if (!b->dragging_p)
+ set_vertical_scroll_bar (XWINDOW (bar->window));
+ break;
+ }
+ case WHEEL_MOVE_EVENT:
+ {
+ struct haiku_wheel_move_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+ int x, y;
+ static float px = 0.0f, py = 0.0f;
+
+ if (!f)
+ continue;
+ BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y);
+
+ inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
+
+ inev2.modifiers = inev.modifiers;
+
+ if (signbit (px) != signbit (b->delta_x))
+ px = 0;
+
+ if (signbit (py) != signbit (b->delta_y))
+ py = 0;
+
+ px += b->delta_x;
+ py += b->delta_y;
+
+ if (fabsf (py) >= FRAME_LINE_HEIGHT (f))
+ {
+ inev.kind = WHEEL_EVENT;
+ inev.code = 0;
+
+ XSETINT (inev.x, x);
+ XSETINT (inev.y, y);
+ XSETINT (inev.arg, lrint (fabsf (py) / FRAME_LINE_HEIGHT (f)));
+ XSETFRAME (inev.frame_or_window, f);
+
+ inev.modifiers |= signbit (py) ? up_modifier : down_modifier;
+ py = 0.0f;
+ }
+
+ if (fabsf (px) >= FRAME_COLUMN_WIDTH (f))
+ {
+ inev2.kind = HORIZ_WHEEL_EVENT;
+ inev2.code = 0;
+
+ XSETINT (inev2.x, x);
+ XSETINT (inev2.y, y);
+ XSETINT (inev2.arg, lrint (fabsf (px) / FRAME_COLUMN_WIDTH (f)));
+ XSETFRAME (inev2.frame_or_window, f);
+
+ inev2.modifiers |= signbit (px) ? up_modifier : down_modifier;
+ px = 0.0f;
+ }
+
+ break;
+ }
+
+ case MENU_BAR_RESIZE:
+ {
+ struct haiku_menu_bar_resize_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
+ continue;
+
+ int old_height = FRAME_MENU_BAR_HEIGHT (f);
+
+ FRAME_MENU_BAR_HEIGHT (f) = b->height + 1;
+ FRAME_MENU_BAR_LINES (f) =
+ (b->height + FRAME_LINE_HEIGHT (f)) / FRAME_LINE_HEIGHT (f);
+
+ if (old_height != b->height)
+ {
+ adjust_frame_size (f, -1, -1, 3, true, Qmenu_bar_lines);
+ haiku_clear_under_internal_border (f);
+ }
+ break;
+ }
+ case MENU_BAR_OPEN:
+ case MENU_BAR_CLOSE:
+ {
+ struct haiku_menu_bar_state_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
+ continue;
+
+ if (type == MENU_BAR_OPEN)
+ {
+ if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
+ {
+ BView_draw_lock (FRAME_HAIKU_VIEW (f));
+ /* This shouldn't be here, but nsmenu does it, so
+ it should probably be safe. */
+ int was_waiting_for_input_p = waiting_for_input;
+ if (waiting_for_input)
+ waiting_for_input = 0;
+ set_frame_menubar (f, 1);
+ waiting_for_input = was_waiting_for_input_p;
+ BView_draw_unlock (FRAME_HAIKU_VIEW (f));
+ }
+ FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
+ popup_activated_p += 1;
+ }
+ else
+ {
+ if (!popup_activated_p)
+ emacs_abort ();
+ if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
+ {
+ FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0;
+ popup_activated_p -= 1;
+ }
+ }
+ break;
+ }
+ case MENU_BAR_SELECT_EVENT:
+ {
+ struct haiku_menu_bar_select_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
+ continue;
+
+ if (FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
+ find_and_call_menu_selection (f, f->menu_bar_items_used,
+ f->menu_bar_vector, b->ptr);
+ break;
+ }
+ case FILE_PANEL_EVENT:
+ {
+ if (!popup_activated_p)
+ continue;
+
+ struct unhandled_event *ev = xmalloc (sizeof *ev);
+ ev->next = unhandled_events;
+ ev->type = type;
+ memcpy (&ev->buffer, buf, 200);
+
+ unhandled_events = ev;
+ break;
+ }
+ case MENU_BAR_HELP_EVENT:
+ {
+ struct haiku_menu_bar_help_event *b = buf;
+
+ if (!popup_activated_p)
+ continue;
+
+ struct frame *f = haiku_window_to_frame (b->window);
+ if (!f || !FRAME_EXTERNAL_MENU_BAR (f) ||
+ !FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
+ continue;
+
+ run_menu_bar_help_event (f, b->mb_idx);
+
+ break;
+ }
+ case ZOOM_EVENT:
+ {
+ struct haiku_zoom_event *b = buf;
+
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ FRAME_OUTPUT_DATA (f)->pending_zoom_height = b->height;
+ FRAME_OUTPUT_DATA (f)->pending_zoom_width = b->width;
+ FRAME_OUTPUT_DATA (f)->pending_zoom_x = b->x;
+ FRAME_OUTPUT_DATA (f)->pending_zoom_y = b->y;
+
+ FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
+ haiku_make_fullscreen_consistent (f);
+ break;
+ }
+ case REFS_EVENT:
+ {
+ struct haiku_refs_event *b = buf;
+ struct frame *f = haiku_window_to_frame (b->window);
+
+ if (!f)
+ continue;
+
+ inev.kind = DRAG_N_DROP_EVENT;
+ inev.arg = build_string_from_utf8 (b->ref);
+
+ XSETINT (inev.x, b->x);
+ XSETINT (inev.y, b->y);
+ XSETFRAME (inev.frame_or_window, f);
+
+ /* There should be no problem with calling free here.
+ free on Haiku is thread-safe. */
+ free (b->ref);
+ break;
+ }
+ case APP_QUIT_REQUESTED_EVENT:
+ case KEY_UP:
+ default:
+ break;
+ }
+
+ haiku_read_size (&b_size);
+
+ if (inev.kind != NO_EVENT)
+ {
+ kbd_buffer_store_event_hold (&inev, hold_quit);
+ ++message_count;
+ }
+
+ if (inev2.kind != NO_EVENT)
+ {
+ kbd_buffer_store_event_hold (&inev2, hold_quit);
+ ++message_count;
+ }
+ }
+
+ for (struct unhandled_event *ev = unhandled_events; ev;)
+ {
+ haiku_write_without_signal (ev->type, &ev->buffer);
+ struct unhandled_event *old = ev;
+ ev = old->next;
+ xfree (old);
+ }
+
+ unblock_input ();
+ return message_count;
+}
+
+static void
+haiku_frame_rehighlight (struct frame *frame)
+{
+ haiku_rehighlight ();
+}
+
+static void
+haiku_delete_window (struct frame *f)
+{
+ check_window_system (f);
+ haiku_free_frame_resources (f);
+}
+
+static void
+haiku_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
+{
+ BBitmap_free (pixmap);
+}
+
+static void
+haiku_beep (struct frame *f)
+{
+ if (visible_bell)
+ {
+ void *view = FRAME_HAIKU_VIEW (f);
+ if (view)
+ {
+ block_input ();
+ BView_draw_lock (view);
+ if (!EmacsView_double_buffered_p (view))
+ {
+ BView_SetHighColorForVisibleBell (view, FRAME_FOREGROUND_PIXEL (f));
+ BView_FillRectangleForVisibleBell (view, 0, 0, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+ SET_FRAME_GARBAGED (f);
+ expose_frame (f, 0, 0, 0, 0);
+ }
+ else
+ {
+ EmacsView_do_visible_bell (view, FRAME_FOREGROUND_PIXEL (f));
+ haiku_flip_buffers (f);
+ }
+ BView_draw_unlock (view);
+ unblock_input ();
+ }
+ }
+ else
+ haiku_ring_bell ();
+}
+
+static void
+haiku_toggle_invisible_pointer (struct frame *f, bool invisible_p)
+{
+ void *view = FRAME_HAIKU_VIEW (f);
+
+ if (view)
+ {
+ block_input ();
+ BView_set_view_cursor (view, invisible_p ?
+ FRAME_OUTPUT_DATA (f)->no_cursor :
+ FRAME_OUTPUT_DATA (f)->current_cursor);
+ f->pointer_invisible = invisible_p;
+ unblock_input ();
+ }
+}
+
+static void
+haiku_fullscreen (struct frame *f)
+{
+ if (f->want_fullscreen == FULLSCREEN_MAXIMIZED)
+ {
+ EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
+ BWindow_zoom (FRAME_HAIKU_WINDOW (f));
+ }
+ else if (f->want_fullscreen == FULLSCREEN_BOTH)
+ EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 1);
+ else if (f->want_fullscreen == FULLSCREEN_NONE)
+ {
+ EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
+ EmacsWindow_unzoom (FRAME_HAIKU_WINDOW (f));
+ }
+
+ f->want_fullscreen = FULLSCREEN_NONE;
+
+ haiku_update_size_hints (f);
+}
+
+static struct terminal *
+haiku_create_terminal (struct haiku_display_info *dpyinfo)
+{
+ struct terminal *terminal;
+
+ terminal = create_terminal (output_haiku, &haiku_redisplay_interface);
+
+ terminal->display_info.haiku = dpyinfo;
+ dpyinfo->terminal = terminal;
+ terminal->kboard = allocate_kboard (Qhaiku);
+
+ terminal->iconify_frame_hook = haiku_iconify_frame;
+ terminal->focus_frame_hook = haiku_focus_frame;
+ terminal->ring_bell_hook = haiku_beep;
+ terminal->popup_dialog_hook = haiku_popup_dialog;
+ terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible;
+ terminal->set_frame_offset_hook = haiku_set_offset;
+ terminal->delete_terminal_hook = haiku_delete_terminal;
+ terminal->get_string_resource_hook = get_string_resource;
+ terminal->set_new_font_hook = haiku_new_font;
+ terminal->defined_color_hook = haiku_defined_color;
+ terminal->set_window_size_hook = haiku_set_window_size;
+ terminal->read_socket_hook = haiku_read_socket;
+ terminal->implicit_set_name_hook = haiku_implicitly_set_name;
+ terminal->mouse_position_hook = haiku_mouse_position;
+ terminal->delete_frame_hook = haiku_delete_window;
+ terminal->frame_up_to_date_hook = haiku_frame_up_to_date;
+ terminal->buffer_flipping_unblocked_hook = haiku_buffer_flipping_unblocked_hook;
+ terminal->clear_frame_hook = haiku_clear_frame;
+ terminal->change_tab_bar_height_hook = haiku_change_tab_bar_height;
+ terminal->change_tool_bar_height_hook = haiku_change_tool_bar_height;
+ terminal->set_vertical_scroll_bar_hook = haiku_set_vertical_scroll_bar;
+ terminal->set_horizontal_scroll_bar_hook = haiku_set_horizontal_scroll_bar;
+ terminal->set_scroll_bar_default_height_hook = haiku_set_scroll_bar_default_height;
+ terminal->set_scroll_bar_default_width_hook = haiku_set_scroll_bar_default_width;
+ terminal->judge_scroll_bars_hook = haiku_judge_scroll_bars;
+ terminal->condemn_scroll_bars_hook = haiku_condemn_scroll_bars;
+ terminal->redeem_scroll_bar_hook = haiku_redeem_scroll_bar;
+ terminal->update_begin_hook = haiku_update_begin;
+ terminal->update_end_hook = haiku_update_end;
+ terminal->frame_rehighlight_hook = haiku_frame_rehighlight;
+ terminal->query_frame_background_color = haiku_query_frame_background_color;
+ terminal->free_pixmap = haiku_free_pixmap;
+ terminal->frame_raise_lower_hook = haiku_frame_raise_lower;
+ terminal->menu_show_hook = haiku_menu_show;
+ terminal->toggle_invisible_pointer_hook = haiku_toggle_invisible_pointer;
+ terminal->fullscreen_hook = haiku_fullscreen;
+
+ return terminal;
+}
+
+struct haiku_display_info *
+haiku_term_init (void)
+{
+ struct haiku_display_info *dpyinfo;
+ struct terminal *terminal;
+
+ Lisp_Object color_file, color_map;
+
+ block_input ();
+ Fset_input_interrupt_mode (Qnil);
+
+ baud_rate = 19200;
+
+ dpyinfo = xzalloc (sizeof *dpyinfo);
+
+ haiku_io_init ();
+
+ if (port_application_to_emacs < B_OK)
+ emacs_abort ();
+
+ color_file = Fexpand_file_name (build_string ("rgb.txt"),
+ Fsymbol_value (intern ("data-directory")));
+
+ color_map = Fx_load_color_file (color_file);
+ if (NILP (color_map))
+ fatal ("Could not read %s.\n", SDATA (color_file));
+
+ dpyinfo->color_map = color_map;
+
+ dpyinfo->display = BApplication_setup ();
+
+ BScreen_res (&dpyinfo->resx, &dpyinfo->resy);
+
+ dpyinfo->next = x_display_list;
+ dpyinfo->n_planes = be_get_display_planes ();
+ x_display_list = dpyinfo;
+
+ terminal = haiku_create_terminal (dpyinfo);
+ if (current_kboard == initial_kboard)
+ current_kboard = terminal->kboard;
+
+ terminal->kboard->reference_count++;
+ /* Never delete haiku displays -- there can only ever be one,
+ anyhow. */
+ terminal->reference_count++;
+ terminal->name = xstrdup ("be");
+
+ dpyinfo->name_list_element = Fcons (build_string ("be"), Qnil);
+ dpyinfo->smallest_font_height = 1;
+ dpyinfo->smallest_char_width = 1;
+
+ gui_init_fringe (terminal->rif);
+ unblock_input ();
+
+ return dpyinfo;
+}
+
+void
+put_xrm_resource (Lisp_Object name, Lisp_Object val)
+{
+ eassert (STRINGP (name));
+ eassert (STRINGP (val) || NILP (val));
+
+ Lisp_Object lval = assoc_no_quit (name, rdb);
+ if (!NILP (lval))
+ Fsetcdr (lval, val);
+ else
+ rdb = Fcons (Fcons (name, val), rdb);
+}
+
+void
+haiku_clear_under_internal_border (struct frame *f)
+{
+ if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
+ {
+ int border = FRAME_INTERNAL_BORDER_WIDTH (f);
+ int width = FRAME_PIXEL_WIDTH (f);
+ int height = FRAME_PIXEL_HEIGHT (f);
+ int margin = FRAME_TOP_MARGIN_HEIGHT (f);
+ int face_id =
+ (FRAME_PARENT_FRAME (f)
+ ? (!NILP (Vface_remapping_alist)
+ ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID)
+ : CHILD_FRAME_BORDER_FACE_ID)
+ : (!NILP (Vface_remapping_alist)
+ ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
+ : INTERNAL_BORDER_FACE_ID));
+ struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
+ void *view = FRAME_HAIKU_VIEW (f);
+ block_input ();
+ BView_draw_lock (view);
+ BView_StartClip (view);
+ BView_ClipToRect (view, 0, 0, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+
+ if (face)
+ BView_SetHighColor (view, face->background);
+ else
+ BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f));
+
+ BView_FillRectangle (view, 0, margin, width, border);
+ BView_FillRectangle (view, 0, 0, border, height);
+ BView_FillRectangle (view, 0, margin, width, border);
+ BView_FillRectangle (view, width - border, 0, border, height);
+ BView_FillRectangle (view, 0, height - border, width, border);
+ BView_EndClip (view);
+ BView_draw_unlock (view);
+ unblock_input ();
+ }
+}
+
+void
+mark_haiku_display (void)
+{
+ if (x_display_list)
+ mark_object (x_display_list->color_map);
+}
+
+void
+haiku_scroll_bar_remove (struct scroll_bar *bar)
+{
+ block_input ();
+ void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (XWINDOW (bar->window)));
+ BView_forget_scroll_bar (view, bar->left, bar->top, bar->width, bar->height);
+ BScrollBar_delete (bar->scroll_bar);
+ expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)),
+ bar->left, bar->top, bar->width, bar->height);
+
+ if (bar->horizontal)
+ wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
+ else
+ wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
+
+ unblock_input ();
+};
+
+void
+haiku_set_offset (struct frame *frame, int x, int y,
+ int change_gravity)
+{
+ if (change_gravity > 0)
+ {
+ frame->top_pos = y;
+ frame->left_pos = x;
+ frame->size_hint_flags &= ~ (XNegative | YNegative);
+ if (x < 0)
+ frame->size_hint_flags |= XNegative;
+ if (y < 0)
+ frame->size_hint_flags |= YNegative;
+ frame->win_gravity = NorthWestGravity;
+ }
+
+ haiku_update_size_hints (frame);
+
+ block_input ();
+ if (change_gravity)
+ BWindow_set_offset (FRAME_HAIKU_WINDOW (frame), x, y);
+ unblock_input ();
+}
+
+#ifdef USE_BE_CAIRO
+cairo_t *
+haiku_begin_cr_clip (struct frame *f, struct glyph_string *s)
+{
+ cairo_surface_t *surface = FRAME_CR_SURFACE (f);
+ if (!surface)
+ return NULL;
+
+ cairo_t *context = cairo_create (surface);
+ return context;
+}
+
+void
+haiku_end_cr_clip (cairo_t *cr)
+{
+ cairo_destroy (cr);
+}
+#endif
+
+void
+syms_of_haikuterm (void)
+{
+ DEFVAR_BOOL ("haiku-initialized", haiku_initialized,
+ doc: /* Non-nil if the Haiku terminal backend has been initialized. */);
+
+ DEFVAR_BOOL ("x-use-underline-position-properties",
+ x_use_underline_position_properties,
+ doc: /* SKIP: real doc in xterm.c. */);
+ x_use_underline_position_properties = 1;
+
+ DEFVAR_BOOL ("x-underline-at-descent-line",
+ x_underline_at_descent_line,
+ doc: /* SKIP: real doc in xterm.c. */);
+ x_underline_at_descent_line = 0;
+
+ DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
+ doc: /* SKIP: real doc in xterm.c. */);
+ Vx_toolkit_scroll_bars = Qt;
+
+ DEFVAR_BOOL ("haiku-debug-on-fatal-error", haiku_debug_on_fatal_error,
+ doc: /* If non-nil, Emacs will launch the system debugger upon a fatal error. */);
+ haiku_debug_on_fatal_error = 1;
+
+ DEFSYM (Qshift, "shift");
+ DEFSYM (Qcontrol, "control");
+ DEFSYM (Qoption, "option");
+ DEFSYM (Qcommand, "command");
+
+ DEFVAR_LISP ("haiku-meta-keysym", Vhaiku_meta_keysym,
+ doc: /* Which key Emacs uses as the meta modifier.
+This is either one of the symbols `shift', `control', `command', and
+`option', or nil, in which case it is treated as `command'.
+
+Setting it to any other value is equivalent to `command'. */);
+ Vhaiku_meta_keysym = Qnil;
+
+ DEFVAR_LISP ("haiku-control-keysym", Vhaiku_control_keysym,
+ doc: /* Which key Emacs uses as the control modifier.
+This is either one of the symbols `shift', `control', `command', and
+`option', or nil, in which case it is treated as `control'.
+
+Setting it to any other value is equivalent to `control'. */);
+ Vhaiku_control_keysym = Qnil;
+
+ DEFVAR_LISP ("haiku-super-keysym", Vhaiku_super_keysym,
+ doc: /* Which key Emacs uses as the super modifier.
+This is either one of the symbols `shift', `control', `command', and
+`option', or nil, in which case it is treated as `option'.
+
+Setting it to any other value is equivalent to `option'. */);
+ Vhaiku_super_keysym = Qnil;
+
+ DEFVAR_LISP ("haiku-shift-keysym", Vhaiku_shift_keysym,
+ doc: /* Which key Emacs uses as the shift modifier.
+This is either one of the symbols `shift', `control', `command', and
+`option', or nil, in which case it is treated as `shift'.
+
+Setting it to any other value is equivalent to `shift'. */);
+ Vhaiku_shift_keysym = Qnil;
+
+
+ DEFSYM (Qx_use_underline_position_properties,
+ "x-use-underline-position-properties");
+
+ DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
+
+ rdb = Qnil;
+ staticpro (&rdb);
+
+ Fprovide (Qhaiku, Qnil);
+#ifdef HAVE_BE_FREETYPE
+ Fprovide (Qfreetype, Qnil);
+#endif
+#ifdef USE_BE_CAIRO
+ Fprovide (intern_c_string ("cairo"), Qnil);
+#endif
+}
diff --git a/src/haikuterm.h b/src/haikuterm.h
new file mode 100644
index 0000000000..af55f68c67
--- /dev/null
+++ b/src/haikuterm.h
@@ -0,0 +1,293 @@
+/* Haiku window system support
+ 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/>. */
+
+#ifndef _HAIKU_TERM_H_
+#define _HAIKU_TERM_H_
+
+#include <pthread.h>
+
+#ifdef USE_BE_CAIRO
+#include <cairo.h>
+#endif
+
+#include "haikugui.h"
+#include "frame.h"
+#include "character.h"
+#include "dispextern.h"
+#include "font.h"
+
+#define C_FRAME struct frame *
+#define C_FONT struct font *
+#define C_TERMINAL struct terminal *
+
+#define HAVE_CHAR_CACHE_MAX 65535
+
+extern int popup_activated_p;
+
+extern void be_app_quit (void);
+
+struct haikufont_info
+{
+ struct font font;
+ haiku be_font;
+ struct font_metrics **metrics;
+ short metrics_nrows;
+
+ unsigned short **glyphs;
+};
+
+struct haiku_bitmap_record
+{
+ haiku img;
+ char *file;
+ int refcount;
+ int height, width, depth;
+};
+
+struct haiku_display_info
+{
+ /* Chain of all haiku_display_info structures. */
+ struct haiku_display_info *next;
+ C_TERMINAL terminal;
+
+ Lisp_Object name_list_element;
+ Lisp_Object color_map;
+
+ int n_fonts;
+
+ int smallest_char_width;
+ int smallest_font_height;
+
+ struct frame *focused_frame;
+ struct frame *focus_event_frame;
+ struct frame *last_mouse_glyph_frame;
+
+ struct haiku_bitmap_record *bitmaps;
+ ptrdiff_t bitmaps_size;
+ ptrdiff_t bitmaps_last;
+
+ int grabbed;
+ int n_planes;
+ int color_p;
+
+ Window root_window;
+ Lisp_Object rdb;
+
+ Emacs_Cursor vertical_scroll_bar_cursor;
+ Emacs_Cursor horizontal_scroll_bar_cursor;
+
+ Mouse_HLInfo mouse_highlight;
+
+ C_FRAME highlight_frame;
+ C_FRAME last_mouse_frame;
+ C_FRAME last_mouse_motion_frame;
+
+ int last_mouse_motion_x;
+ int last_mouse_motion_y;
+
+ struct haiku_rect last_mouse_glyph;
+
+ void *last_mouse_scroll_bar;
+
+ haiku display;
+
+ double resx, resy;
+};
+
+struct haiku_output
+{
+ Emacs_Cursor text_cursor;
+ Emacs_Cursor nontext_cursor;
+ Emacs_Cursor modeline_cursor;
+ Emacs_Cursor hand_cursor;
+ Emacs_Cursor hourglass_cursor;
+ Emacs_Cursor horizontal_drag_cursor;
+ Emacs_Cursor vertical_drag_cursor;
+ Emacs_Cursor left_edge_cursor;
+ Emacs_Cursor top_left_corner_cursor;
+ Emacs_Cursor top_edge_cursor;
+ Emacs_Cursor top_right_corner_cursor;
+ Emacs_Cursor right_edge_cursor;
+ Emacs_Cursor bottom_right_corner_cursor;
+ Emacs_Cursor bottom_edge_cursor;
+ Emacs_Cursor bottom_left_corner_cursor;
+ Emacs_Cursor no_cursor;
+
+ Emacs_Cursor current_cursor;
+
+ struct haiku_display_info *display_info;
+
+ int baseline_offset;
+ int fontset;
+
+ Emacs_Color cursor_color;
+
+ Window window_desc, parent_desc;
+ char explicit_parent;
+
+ int titlebar_height;
+ int toolbar_height;
+
+ haiku window;
+ haiku view;
+ haiku menubar;
+
+ int menu_up_to_date_p;
+ int zoomed_p;
+
+ int pending_zoom_x;
+ int pending_zoom_y;
+ int pending_zoom_width;
+ int pending_zoom_height;
+
+ int menu_bar_open_p;
+
+ C_FONT font;
+
+ int hourglass_p;
+ uint32_t cursor_fg;
+ bool dirty_p;
+
+ /* The pending position we're waiting for. */
+ int pending_top, pending_left;
+};
+
+struct x_output
+{
+ /* Unused, makes term.c happy. */
+};
+
+extern struct haiku_display_info *x_display_list;
+extern struct font_driver const haikufont_driver;
+
+struct scroll_bar
+{
+ /* These fields are shared by all vectors. */
+ union vectorlike_header header;
+
+ /* The window we're a scroll bar for. */
+ Lisp_Object window;
+
+ /* The next and previous in the chain of scroll bars in this frame. */
+ Lisp_Object next, prev;
+
+ /* Fields after 'prev' are not traced by the GC. */
+
+ /* The position and size of the scroll bar in pixels, relative to the
+ frame. */
+ int top, left, width, height;
+
+ /* The actual scrollbar. */
+ void *scroll_bar;
+
+ /* Non-nil if the scroll bar handle is currently being dragged by
+ the user. */
+ int dragging;
+
+ /* The update position if we are waiting for a scrollbar update, or
+ -1. */
+ int update;
+
+ /* The last known position of this scrollbar. */
+ int position;
+
+ /* The total number of units inside this scrollbar. */
+ int total;
+
+ /* True if the scroll bar is horizontal. */
+ bool horizontal;
+};
+
+#define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
+
+#define FRAME_DIRTY_P(f) (FRAME_OUTPUT_DATA (f)->dirty_p)
+#define MAKE_FRAME_DIRTY(f) (FRAME_DIRTY_P (f) = 1)
+#define FRAME_OUTPUT_DATA(f) ((f)->output_data.haiku)
+#define FRAME_HAIKU_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window)
+#define FRAME_HAIKU_VIEW(f) ((MAKE_FRAME_DIRTY (f)), FRAME_OUTPUT_DATA (f)->view)
+#define FRAME_HAIKU_MENU_BAR(f) (FRAME_OUTPUT_DATA (f)->menubar)
+#define FRAME_DISPLAY_INFO(f) (FRAME_OUTPUT_DATA (f)->display_info)
+#define FRAME_FONT(f) (FRAME_OUTPUT_DATA (f)->font)
+#define FRAME_FONTSET(f) (FRAME_OUTPUT_DATA (f)->fontset)
+#define FRAME_NATIVE_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window)
+#define FRAME_BASELINE_OFFSET(f) (FRAME_OUTPUT_DATA (f)->baseline_offset)
+#define FRAME_CURSOR_COLOR(f) (FRAME_OUTPUT_DATA (f)->cursor_color)
+
+#ifdef USE_BE_CAIRO
+#define FRAME_CR_SURFACE(f) \
+ (FRAME_HAIKU_VIEW (f) ? EmacsView_cairo_surface (FRAME_HAIKU_VIEW (f)) : 0);
+#endif
+
+extern void syms_of_haikuterm (void);
+extern void syms_of_haikufns (void);
+extern void syms_of_haikumenu (void);
+extern void syms_of_haikufont (void);
+extern void syms_of_haikuselect (void);
+extern void init_haiku_select (void);
+
+extern void haiku_iconify_frame (struct frame *);
+extern void haiku_visualize_frame (struct frame *);
+extern void haiku_unvisualize_frame (struct frame *);
+extern void haiku_set_offset (struct frame *, int, int, int);
+extern void haiku_set_frame_visible_invisible (struct frame *, bool);
+extern void haiku_free_frame_resources (struct frame *f);
+extern void haiku_scroll_bar_remove (struct scroll_bar *bar);
+extern void haiku_clear_under_internal_border (struct frame *f);
+extern void haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p);
+
+extern struct haiku_display_info *haiku_term_init (void);
+
+extern void mark_haiku_display (void);
+
+extern int haiku_get_color (const char *name, Emacs_Color *color);
+extern void haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
+extern void haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
+extern void haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
+extern void haiku_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
+extern void haiku_change_tab_bar_height (struct frame *f, int height);
+extern void haiku_change_tool_bar_height (struct frame *f, int height);
+
+extern void haiku_query_color (uint32_t col, Emacs_Color *color);
+
+extern unsigned long haiku_get_pixel (haiku bitmap, int x, int y);
+extern void haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel);
+
+extern Lisp_Object haiku_menu_show (struct frame *f, int x, int y, int menu_flags,
+ Lisp_Object title, const char **error_name);
+extern Lisp_Object haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents);
+
+extern void initialize_frame_menubar (struct frame *f);
+
+extern void run_menu_bar_help_event (struct frame *f, int mb_idx);
+extern void put_xrm_resource (Lisp_Object name, Lisp_Object val);
+
+#ifdef HAVE_NATIVE_IMAGE_API
+extern bool haiku_can_use_native_image_api (Lisp_Object type);
+extern int haiku_load_image (struct frame *f, struct image *img,
+ Lisp_Object spec_file, Lisp_Object spec_data);
+extern void syms_of_haikuimage (void);
+#endif
+
+#ifdef USE_BE_CAIRO
+extern cairo_t *
+haiku_begin_cr_clip (struct frame *f, struct glyph_string *s);
+
+extern void
+haiku_end_cr_clip (cairo_t *cr);
+#endif
+#endif /* _HAIKU_TERM_H_ */
diff --git a/src/image.c b/src/image.c
index 6769e49120..d2c2b55b29 100644
--- a/src/image.c
+++ b/src/image.c
@@ -20,6 +20,7 @@ Copyright (C) 1989, 1992-2021 Free Software Foundation, Inc.
#include <config.h>
#include <fcntl.h>
+#include <math.h>
#include <unistd.h>
/* Include this before including <setjmp.h> to work around bugs with
@@ -135,6 +136,27 @@ #define PIX_MASK_DRAW 1
# define COLOR_TABLE_SUPPORT 1
#endif
+#ifdef HAVE_HAIKU
+#include "haiku_support.h"
+typedef struct haiku_bitmap_record Bitmap_Record;
+
+#define GET_PIXEL(ximg, x, y) haiku_get_pixel (ximg, x, y)
+#define PUT_PIXEL haiku_put_pixel
+#define NO_PIXMAP 0
+
+#define PIX_MASK_RETAIN 0
+#define PIX_MASK_DRAW 1
+
+#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
+#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
+#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
+#define BLUE_FROM_ULONG(color) ((color) & 0xff)
+#define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101)
+#define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101)
+#define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101)
+
+#endif
+
static void image_disable_image (struct frame *, struct image *);
static void image_edge_detection (struct frame *, struct image *, Lisp_Object,
Lisp_Object);
@@ -430,6 +452,11 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
return -1;
#endif
+#ifdef HAVE_HAIKU
+ void *bitmap = BBitmap_new (width, height, 1);
+ BBitmap_import_mono_bits (bitmap, bits, width, height);
+#endif
+
id = image_allocate_bitmap_record (f);
#ifdef HAVE_NS
@@ -437,6 +464,11 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
dpyinfo->bitmaps[id - 1].depth = 1;
#endif
+#ifdef HAVE_HAIKU
+ dpyinfo->bitmaps[id - 1].img = bitmap;
+ dpyinfo->bitmaps[id - 1].depth = 1;
+#endif
+
dpyinfo->bitmaps[id - 1].file = NULL;
dpyinfo->bitmaps[id - 1].height = height;
dpyinfo->bitmaps[id - 1].width = width;
@@ -465,7 +497,7 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
ptrdiff_t
image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
{
-#ifdef HAVE_NTGUI
+#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
return -1; /* W32_TODO : bitmap support */
#else
Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
@@ -561,6 +593,10 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
ns_release_object (bm->img);
#endif
+#ifdef HAVE_HAIKU
+ BBitmap_free (bm->img);
+#endif
+
if (bm->file)
{
xfree (bm->file);
@@ -1834,6 +1870,11 @@ image_size_in_bytes (struct image *img)
if (img->mask)
size += w32_image_size (img->mask);
+#elif defined HAVE_HAIKU
+ if (img->pixmap)
+ size += BBitmap_bytes_length (img->pixmap);
+ if (img->mask)
+ size += BBitmap_bytes_length (img->mask);
#endif
return size;
@@ -2173,6 +2214,7 @@ compute_image_size (size_t width, size_t height,
single step, but the maths for each element is much more complex
and performing the steps separately makes for more readable code. */
+#ifndef HAVE_HAIKU
typedef double matrix3x3[3][3];
static void
@@ -2187,6 +2229,7 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result)
result[i][j] = sum;
}
}
+#endif /* not HAVE_HAIKU */
static void
compute_image_rotation (struct image *img, double *rotation)
@@ -2244,6 +2287,7 @@ image_set_transform (struct frame *f, struct image *img)
double rotation = 0.0;
compute_image_rotation (img, &rotation);
+#ifndef HAVE_HAIKU
# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS
/* We want scale up operations to use a nearest neighbor filter to
show real pixels instead of munging them, but scale down
@@ -2414,6 +2458,34 @@ image_set_transform (struct frame *f, struct image *img)
img->xform.eDx = matrix[2][0];
img->xform.eDy = matrix[2][1];
# endif
+#else
+ if (rotation != 0 &&
+ rotation != 90 &&
+ rotation != 180 &&
+ rotation != 270 &&
+ rotation != 360)
+ {
+ image_error ("No native support for rotation by %g degrees",
+ make_float (rotation));
+ return;
+ }
+
+ rotation = fmod (rotation, 360.0);
+
+ if (rotation == 90 || rotation == 270)
+ {
+ int w = width;
+ width = height;
+ height = w;
+ }
+
+ img->have_be_transforms_p = rotation != 0 || (img->width != width) || (img->height != height);
+ img->be_rotate = rotation;
+ img->be_scale_x = 1.0 / (img->width / (double) width);
+ img->be_scale_y = 1.0 / (img->height / (double) height);
+ img->width = width;
+ img->height = height;
+#endif /* not HAVE_HAIKU */
}
#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */
@@ -2820,6 +2892,29 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d
return 1;
#endif /* HAVE_X_WINDOWS */
+#ifdef HAVE_HAIKU
+ if (depth == 0)
+ depth = 24;
+
+ if (depth != 24 && depth != 1)
+ {
+ image_error ("Invalid image bit depth specified");
+ return 0;
+ }
+
+ *pixmap = BBitmap_new (width, height, depth == 1);
+
+ if (*pixmap == NO_PIXMAP)
+ {
+ *pimg = NULL;
+ image_error ("Unable to create pixmap", Qnil, Qnil);
+ return 0;
+ }
+
+ *pimg = *pixmap;
+ return 1;
+#endif
+
#ifdef HAVE_NTGUI
BITMAPINFOHEADER *header;
@@ -2960,7 +3055,7 @@ image_destroy_x_image (Emacs_Pix_Container pimg)
gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg,
Emacs_Pixmap pixmap, int width, int height)
{
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined HAVE_HAIKU
eassert (pimg == pixmap);
#elif defined HAVE_X_WINDOWS
GC gc;
@@ -3087,7 +3182,7 @@ image_unget_x_image_or_dc (struct image *img, bool mask_p,
static Emacs_Pix_Container
image_get_x_image (struct frame *f, struct image *img, bool mask_p)
{
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined (HAVE_HAIKU)
return !mask_p ? img->pixmap : img->mask;
#elif defined HAVE_X_WINDOWS
XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img;
@@ -4036,7 +4131,7 @@ #define Display xpm_Display
#endif /* not HAVE_NTGUI */
#endif /* HAVE_XPM */
-#if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS
+#if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU
/* Indices of image specification fields in xpm_format, below. */
@@ -4056,7 +4151,7 @@ #define Display xpm_Display
XPM_LAST
};
-#if defined HAVE_XPM || defined HAVE_NS
+#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU
/* Vector of image_keyword structures describing the format
of valid XPM image specifications. */
@@ -4074,7 +4169,7 @@ #define Display xpm_Display
{":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
{":background", IMAGE_STRING_OR_NIL_VALUE, 0}
};
-#endif /* HAVE_XPM || HAVE_NS */
+#endif /* HAVE_XPM || HAVE_NS || HAVE_HAIKU */
#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
@@ -4298,7 +4393,7 @@ init_xpm_functions (void)
#endif /* WINDOWSNT */
-#if defined HAVE_XPM || defined HAVE_NS
+#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU
/* Value is true if COLOR_SYMBOLS is a valid color symbols list
for XPM images. Such a list must consist of conses whose car and
cdr are strings. */
@@ -4334,9 +4429,9 @@ xpm_image_p (Lisp_Object object)
&& (! fmt[XPM_COLOR_SYMBOLS].count
|| xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
}
-#endif /* HAVE_XPM || HAVE_NS */
+#endif /* HAVE_XPM || HAVE_NS || HAVE_HAIKU */
-#endif /* HAVE_XPM || USE_CAIRO || HAVE_NS */
+#endif /* HAVE_XPM || USE_CAIRO || HAVE_NS || HAVE_HAIKU */
#if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK
ptrdiff_t
@@ -4705,9 +4800,10 @@ xpm_load (struct frame *f, struct image *img)
#endif /* HAVE_XPM && !USE_CAIRO */
#if (defined USE_CAIRO && defined HAVE_XPM) \
- || (defined HAVE_NS && !defined HAVE_XPM)
+ || (defined HAVE_NS && !defined HAVE_XPM) \
+ || (defined HAVE_HAIKU && !defined HAVE_XPM)
-/* XPM support functions for NS where libxpm is not available, and for
+/* XPM support functions for NS and Haiku where libxpm is not available, and for
Cairo. Only XPM version 3 (without any extensions) is supported. */
static void xpm_put_color_table_v (Lisp_Object, const char *,
@@ -5444,7 +5540,7 @@ lookup_rgb_color (struct frame *f, int r, int g, int b)
{
#ifdef HAVE_NTGUI
return PALETTERGB (r >> 8, g >> 8, b >> 8);
-#elif defined USE_CAIRO || defined HAVE_NS
+#elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU
return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
#else
xsignal1 (Qfile_error,
@@ -5517,7 +5613,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
p = colors;
for (y = 0; y < img->height; ++y)
{
-#if !defined USE_CAIRO && !defined HAVE_NS
+#if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU
Emacs_Color *row = p;
for (x = 0; x < img->width; ++x, ++p)
p->pixel = GET_PIXEL (ximg, x, y);
@@ -5525,7 +5621,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
{
FRAME_TERMINAL (f)->query_colors (f, row, img->width);
}
-#else /* USE_CAIRO || HAVE_NS */
+#else /* USE_CAIRO || HAVE_NS || HAVE_HAIKU */
for (x = 0; x < img->width; ++x, ++p)
{
p->pixel = GET_PIXEL (ximg, x, y);
@@ -5839,6 +5935,7 @@ image_disable_image (struct frame *f, struct image *img)
{
#ifndef HAVE_NTGUI
#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */
+#ifndef HAVE_HAIKU
#ifndef USE_CAIRO
#define CrossForeground(f) BLACK_PIX_DEFAULT (f)
@@ -5856,6 +5953,7 @@ #define MaskForeground(f) PIX_MASK_DRAW
if (img->mask)
image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height,
MaskForeground (f));
+#endif /* !HAVE_HAIKU */
#endif /* !HAVE_NS */
#else
HDC hdc, bmpdc;
@@ -6413,6 +6511,8 @@ image_can_use_native_api (Lisp_Object type)
return w32_can_use_native_image_api (type);
# elif defined HAVE_NS
return ns_can_use_native_image_api (type);
+# elif defined HAVE_HAIKU
+ return haiku_can_use_native_image_api (type);
# else
return false;
# endif
@@ -6486,6 +6586,9 @@ native_image_load (struct frame *f, struct image *img)
# elif defined HAVE_NS
return ns_load_image (f, img, image_file,
image_spec_value (img->spec, QCdata, NULL));
+# elif defined HAVE_HAIKU
+ return haiku_load_image (f, img, image_file,
+ image_spec_value (img->spec, QCdata, NULL));
# else
return 0;
# endif
@@ -9635,7 +9738,8 @@ imagemagick_load_image (struct frame *f, struct image *img,
init_color_table ();
-#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && ! defined (HAVE_NS)
+#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && \
+ ! defined (HAVE_NS) && ! defined (HAVE_HAIKU)
if (imagemagick_render_type != 0)
{
/* Magicexportimage is normally faster than pixelpushing. This
@@ -10925,7 +11029,8 @@ DEFUN ("image-transforms-p", Fimage_transforms_p, Simage_transforms_p, 0, 1, 0,
if (FRAME_WINDOW_P (f))
{
#ifdef HAVE_NATIVE_TRANSFORMS
-# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS)
+# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
+ || defined (HAVE_HAIKU)
return list2 (Qscale, Qrotate90);
# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
int event_basep, error_basep;
@@ -11015,7 +11120,7 @@ initialize_image_type (struct image_type const *type)
{ SYMBOL_INDEX (Qjpeg), jpeg_image_p, jpeg_load, image_clear_image,
IMAGE_TYPE_INIT (init_jpeg_functions) },
#endif
-#if defined HAVE_XPM || defined HAVE_NS
+#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU
{ SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image,
IMAGE_TYPE_INIT (init_xpm_functions) },
#endif
@@ -11163,7 +11268,7 @@ syms_of_image (void)
DEFSYM (Qxbm, "xbm");
add_image_type (Qxbm);
-#if defined (HAVE_XPM) || defined (HAVE_NS)
+#if defined (HAVE_XPM) || defined (HAVE_NS) || defined (HAVE_HAIKU)
DEFSYM (Qxpm, "xpm");
add_image_type (Qxpm);
#endif
diff --git a/src/keyboard.c b/src/keyboard.c
index de9805df32..2cae32d1c6 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3865,7 +3865,7 @@ kbd_buffer_get_event (KBOARD **kbp,
/* One way or another, wait until input is available; then, if
interrupt handlers have not read it, read it now. */
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
gobble_input ();
#endif
if (kbd_fetch_ptr != kbd_store_ptr)
@@ -6152,7 +6152,6 @@ make_lispy_event (struct input_event *event)
case CONFIG_CHANGED_EVENT:
return list3 (Qconfig_changed_event,
event->arg, event->frame_or_window);
-
/* The 'kind' field of the event is something we don't recognize. */
default:
emacs_abort ();
@@ -7180,7 +7179,7 @@ tty_read_avail_input (struct terminal *terminal,
static void
handle_async_input (void)
{
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
while (1)
{
int nread = gobble_input ();
@@ -7243,7 +7242,7 @@ totally_unblock_input (void)
unblock_input_to (0);
}
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
void
handle_input_available_signal (int sig)
@@ -7259,7 +7258,7 @@ deliver_input_available_signal (int sig)
{
deliver_process_signal (sig, handle_input_available_signal);
}
-#endif /* USABLE_SIGIO */
+#endif /* defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) */
\f
/* User signal events. */
@@ -7329,7 +7328,7 @@ handle_user_signal (int sig)
}
p->npending++;
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
if (interrupt_input)
handle_input_available_signal (sig);
else
@@ -11099,7 +11098,7 @@ DEFUN ("set-input-interrupt-mode", Fset_input_interrupt_mode,
(Lisp_Object interrupt)
{
bool new_interrupt_input;
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
#ifdef HAVE_X_WINDOWS
if (x_display_list != NULL)
{
@@ -11110,9 +11109,9 @@ DEFUN ("set-input-interrupt-mode", Fset_input_interrupt_mode,
else
#endif /* HAVE_X_WINDOWS */
new_interrupt_input = !NILP (interrupt);
-#else /* not USABLE_SIGIO */
+#else /* not USABLE_SIGIO || USABLE_SIGPOLL */
new_interrupt_input = false;
-#endif /* not USABLE_SIGIO */
+#endif /* not USABLE_SIGIO || USABLE_SIGPOLL */
if (new_interrupt_input != interrupt_input)
{
@@ -11541,12 +11540,16 @@ init_keyboard (void)
sigaction (SIGQUIT, &action, 0);
#endif /* not DOS_NT */
}
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
if (!noninteractive)
{
struct sigaction action;
emacs_sigaction_init (&action, deliver_input_available_signal);
+#ifdef USABLE_SIGIO
sigaction (SIGIO, &action, 0);
+#else
+ sigaction (SIGPOLL, &action, 0);
+#endif
}
#endif
diff --git a/src/lisp.h b/src/lisp.h
index 31656bb3b1..19caba4001 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -138,7 +138,12 @@ verify (BITS_WORD_MAX >> (BITS_PER_BITS_WORD - 1) == 1);
buffers and strings. Emacs never allocates objects larger than
PTRDIFF_MAX bytes, as they cause problems with pointer subtraction.
In C99, pD can always be "t"; configure it here for the sake of
- pre-C99 libraries such as glibc 2.0 and Solaris 8. */
+ pre-C99 libraries such as glibc 2.0 and Solaris 8.
+
+ On Haiku, the size of ptrdiff_t is inconsistent with the value of
+ PTRDIFF_MAX. In that case, "t" should be sufficient. */
+
+#ifndef HAIKU
#if PTRDIFF_MAX == INT_MAX
# define pD ""
#elif PTRDIFF_MAX == LONG_MAX
@@ -148,6 +153,9 @@ verify (BITS_WORD_MAX >> (BITS_PER_BITS_WORD - 1) == 1);
#else
# define pD "t"
#endif
+#else
+# define pD "t"
+#endif
/* Convenience macro for rarely-used functions that do not return. */
#define AVOID _Noreturn ATTRIBUTE_COLD void
@@ -3330,7 +3338,7 @@ rarely_quit (unsigned short int count)
/* Define if the windowing system provides a menu bar. */
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
- || defined (HAVE_NS) || defined (USE_GTK)
+ || defined (HAVE_NS) || defined (USE_GTK) || defined (HAVE_HAIKU)
#define HAVE_EXT_MENU_BAR true
#endif
@@ -4429,7 +4437,7 @@ fast_string_match_ignore_case (Lisp_Object regexp, Lisp_Object string)
extern Lisp_Object tab_bar_items (Lisp_Object, int *);
extern Lisp_Object tool_bar_items (Lisp_Object, int *);
extern void discard_mouse_events (void);
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
void handle_input_available_signal (int);
#endif
extern Lisp_Object pending_funcalls;
diff --git a/src/menu.c b/src/menu.c
index 1aafa78c3c..ab01e1bfad 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -50,7 +50,8 @@ Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2021 Free Software
static bool
have_boxes (void)
{
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined(HAVE_NS)
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined (HAVE_NS) \
+ || defined (HAVE_HAIKU)
if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)))
return 1;
#endif
@@ -422,7 +423,8 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
AREF (item_properties, ITEM_PROPERTY_SELECTED),
AREF (item_properties, ITEM_PROPERTY_HELP));
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \
+ || defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
/* Display a submenu using the toolkit. */
if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))
&& ! (NILP (map) || NILP (enabled)))
@@ -872,6 +874,10 @@ update_submenu_strings (widget_value *first_wv)
}
}
+#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \
+ || defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
+
/* Find the menu selection and store it in the keyboard buffer.
F is the frame the menu is on.
MENU_BAR_ITEMS_USED is the length of VECTOR.
@@ -959,7 +965,7 @@ find_and_call_menu_selection (struct frame *f, int menu_bar_items_used,
SAFE_FREE ();
}
-#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
+#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI || HAVE_HAIKU */
#ifdef HAVE_NS
/* As above, but return the menu selection instead of storing in kb buffer.
diff --git a/src/process.c b/src/process.c
index f923aff1cb..d0d604b05a 100644
--- a/src/process.c
+++ b/src/process.c
@@ -259,7 +259,7 @@ #define READ_OUTPUT_DELAY_MAX_MAX (READ_OUTPUT_DELAY_INCREMENT * 7)
static void start_process_unwind (Lisp_Object);
static void create_process (Lisp_Object, char **, Lisp_Object);
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
static bool keyboard_bit_set (fd_set *);
#endif
static void deactivate_process (Lisp_Object);
@@ -5721,7 +5721,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
break;
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
/* If we think we have keyboard input waiting, but didn't get SIGIO,
go read it. This can happen with X on BSD after logging out.
In that case, there really is no input and no SIGIO,
@@ -5729,7 +5729,11 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
if (read_kbd && interrupt_input
&& keyboard_bit_set (&Available) && ! noninteractive)
+#ifdef USABLE_SIGIO
handle_input_available_signal (SIGIO);
+#else
+ handle_input_available_signal (SIGPOLL);
+#endif
#endif
/* If checking input just got us a size-change event from X,
@@ -7723,7 +7727,7 @@ delete_gpm_wait_descriptor (int desc)
# endif
-# ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
/* Return true if *MASK has a bit set
that corresponds to one of the keyboard input descriptors. */
diff --git a/src/sound.c b/src/sound.c
index 9041076bdc..d42bc8550d 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -299,11 +299,15 @@ sound_perror (const char *msg)
int saved_errno = errno;
turn_on_atimers (1);
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
{
sigset_t unblocked;
sigemptyset (&unblocked);
+#ifdef USABLE_SIGIO
sigaddset (&unblocked, SIGIO);
+#else
+ sigaddset (&unblocked, SIGPOLL);
+#endif
pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
}
#endif
@@ -698,7 +702,7 @@ vox_open (struct sound_device *sd)
vox_configure (struct sound_device *sd)
{
int val;
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
sigset_t oldset, blocked;
#endif
@@ -708,9 +712,13 @@ vox_configure (struct sound_device *sd)
interrupted by a signal. Block the ones we know to cause
troubles. */
turn_on_atimers (0);
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
sigemptyset (&blocked);
+#ifdef USABLE_SIGIO
sigaddset (&blocked, SIGIO);
+#else
+ sigaddset (&blocked, SIGPOLL);
+#endif
pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
#endif
@@ -744,7 +752,7 @@ vox_configure (struct sound_device *sd)
}
turn_on_atimers (1);
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
pthread_sigmask (SIG_SETMASK, &oldset, 0);
#endif
}
@@ -760,10 +768,14 @@ vox_close (struct sound_device *sd)
/* On GNU/Linux, it seems that the device driver doesn't like to
be interrupted by a signal. Block the ones we know to cause
troubles. */
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
sigset_t blocked, oldset;
sigemptyset (&blocked);
+#ifdef USABLE_SIGIO
sigaddset (&blocked, SIGIO);
+#else
+ sigaddset (&blocked, SIGPOLL);
+#endif
pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
#endif
turn_on_atimers (0);
@@ -772,7 +784,7 @@ vox_close (struct sound_device *sd)
ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL);
turn_on_atimers (1);
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
pthread_sigmask (SIG_SETMASK, &oldset, 0);
#endif
diff --git a/src/sysdep.c b/src/sysdep.c
index 8eaee22498..67b6b2aa3d 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -71,6 +71,10 @@
# include <math.h>
#endif
+#ifdef HAIKU
+#include <kernel/OS.h>
+#endif
+
#ifdef HAVE_SOCKETS
#include <sys/socket.h>
#include <netdb.h>
@@ -678,6 +682,9 @@ sys_subshell (void)
#ifdef USABLE_SIGIO
saved_handlers[3].code = SIGIO;
saved_handlers[4].code = 0;
+#elif defined (USABLE_SIGPOLL)
+ saved_handlers[3].code = SIGPOLL;
+ saved_handlers[4].code = 0;
#else
saved_handlers[3].code = 0;
#endif
@@ -788,6 +795,7 @@ init_sigio (int fd)
}
#ifndef DOS_NT
+#ifdef F_SETOWN
static void
reset_sigio (int fd)
{
@@ -795,12 +803,13 @@ reset_sigio (int fd)
fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
#endif
}
+#endif /* F_SETOWN */
#endif
void
request_sigio (void)
{
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
sigset_t unblocked;
if (noninteractive)
@@ -810,7 +819,11 @@ request_sigio (void)
# ifdef SIGWINCH
sigaddset (&unblocked, SIGWINCH);
# endif
+# ifdef USABLE_SIGIO
sigaddset (&unblocked, SIGIO);
+# else
+ sigaddset (&unblocked, SIGPOLL);
+# endif
pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
interrupts_deferred = 0;
@@ -820,7 +833,7 @@ request_sigio (void)
void
unrequest_sigio (void)
{
-#ifdef USABLE_SIGIO
+#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
sigset_t blocked;
if (noninteractive)
@@ -830,7 +843,11 @@ unrequest_sigio (void)
# ifdef SIGWINCH
sigaddset (&blocked, SIGWINCH);
# endif
+# ifdef USABLE_SIGIO
sigaddset (&blocked, SIGIO);
+# else
+ sigaddset (&blocked, SIGPOLL);
+# endif
pthread_sigmask (SIG_BLOCK, &blocked, 0);
interrupts_deferred = 1;
#endif
@@ -1256,9 +1273,12 @@ init_sys_modes (struct tty_display_info *tty_out)
/* This code added to insure that, if flow-control is not to be used,
we have an unlocked terminal at the start. */
+#ifndef HAIKU /* On Haiku, TCXONC is a no-op and causes spurious
+ compiler warnings. */
#ifdef TCXONC
if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TCXONC, 1);
#endif
+#endif /* HAIKU */
#ifdef TIOCSTART
if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TIOCSTART, 0);
#endif
@@ -1674,6 +1694,8 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
sigaddset (&action->sa_mask, SIGQUIT);
#ifdef USABLE_SIGIO
sigaddset (&action->sa_mask, SIGIO);
+#elif defined (USABLE_SIGPOLL)
+ sigaddset (&action->sa_mask, SIGPOLL);
#endif
}
@@ -2772,6 +2794,7 @@ cfsetspeed (struct termios *termios_p, speed_t vitesse)
#ifdef B150
{ 150, B150 },
#endif
+#ifndef HAVE_TINY_SPEED_T
#ifdef B200
{ 200, B200 },
#endif
@@ -2859,6 +2882,7 @@ cfsetspeed (struct termios *termios_p, speed_t vitesse)
#ifdef B4000000
{ 4000000, B4000000 },
#endif
+#endif /* HAVE_TINY_SPEED_T */
};
/* Convert a numerical speed (e.g., 9600) to a Bnnn constant (e.g.,
@@ -3120,8 +3144,9 @@ list_system_processes (void)
}
/* The WINDOWSNT implementation is in w32.c.
- The MSDOS implementation is in dosfns.c. */
-#elif !defined (WINDOWSNT) && !defined (MSDOS)
+ The MSDOS implementation is in dosfns.c.
+ The Haiku implementation is in haiku.c. */
+#elif !defined (WINDOWSNT) && !defined (MSDOS) && !defined (HAIKU)
Lisp_Object
list_system_processes (void)
@@ -4200,8 +4225,9 @@ system_process_attributes (Lisp_Object pid)
}
/* The WINDOWSNT implementation is in w32.c.
- The MSDOS implementation is in dosfns.c. */
-#elif !defined (WINDOWSNT) && !defined (MSDOS)
+ The MSDOS implementation is in dosfns.c.
+ The HAIKU implementation is in haiku.c. */
+#elif !defined (WINDOWSNT) && !defined (MSDOS) && !defined (HAIKU)
Lisp_Object
system_process_attributes (Lisp_Object pid)
diff --git a/src/termhooks.h b/src/termhooks.h
index e7539bbce2..cf853e2885 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -60,7 +60,8 @@ #define EMACS_TERMHOOKS_H
output_x_window,
output_msdos_raw,
output_w32,
- output_ns
+ output_ns,
+ output_haiku
};
/* Input queue declarations and hooks. */
@@ -263,7 +264,6 @@ #define EMACS_TERMHOOKS_H
/* File or directory was changed. */
, FILE_NOTIFY_EVENT
#endif
-
};
/* Bit width of an enum event_kind tag at the start of structs and unions. */
@@ -444,6 +444,7 @@ #define EVENT_INIT(event) memset (&(event), 0, sizeof (struct input_event))
struct x_display_info *x; /* xterm.h */
struct w32_display_info *w32; /* w32term.h */
struct ns_display_info *ns; /* nsterm.h */
+ struct haiku_display_info *haiku; /* haikuterm.h */
} display_info;
\f
@@ -832,6 +833,9 @@ #define TERMINAL_FONT_CACHE(t) \
#elif defined (HAVE_NS)
#define TERMINAL_FONT_CACHE(t) \
(t->type == output_ns ? t->display_info.ns->name_list_element : Qnil)
+#elif defined (HAVE_HAIKU)
+#define TERMINAL_FONT_CACHE(t) \
+ (t->type == output_haiku ? t->display_info.haiku->name_list_element : Qnil)
#endif
extern struct terminal *decode_live_terminal (Lisp_Object);
diff --git a/src/terminal.c b/src/terminal.c
index b83adc596b..b5f244ee31 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -445,6 +445,8 @@ DEFUN ("terminal-live-p", Fterminal_live_p, Sterminal_live_p, 1, 1, 0,
return Qpc;
case output_ns:
return Qns;
+ case output_haiku:
+ return Qhaiku;
default:
emacs_abort ();
}
diff --git a/src/verbose.mk.in b/src/verbose.mk.in
index a5ff931ed0..9252971acc 100644
--- a/src/verbose.mk.in
+++ b/src/verbose.mk.in
@@ -23,7 +23,9 @@ ifeq (${V},1)
AM_V_AR =
AM_V_at =
AM_V_CC =
+AM_V_CXX =
AM_V_CCLD =
+AM_V_CXXLD =
AM_V_ELC =
AM_V_ELN =
AM_V_GEN =
@@ -34,7 +36,9 @@ else
AM_V_AR = @echo " AR " $@;
AM_V_at = @
AM_V_CC = @echo " CC " $@;
+AM_V_CXX = @echo " CXX " $@;
AM_V_CCLD = @echo " CCLD " $@;
+AM_V_CXXLD = @echo " CXXLD " $@;
ifeq ($(HAVE_NATIVE_COMP),yes)
ifeq ($(NATIVE_DISABLED),1)
AM_V_ELC = @echo " ELC " $@;
diff --git a/src/xdisp.c b/src/xdisp.c
index d7ad548917..b62332cc48 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -15657,6 +15657,11 @@ redisplay_internal (void)
}
#endif
+#if defined (HAVE_HAIKU)
+ if (popup_activated_p)
+ return;
+#endif
+
/* I don't think this happens but let's be paranoid. */
if (redisplaying_p)
return;
@@ -25247,6 +25252,11 @@ display_menu_bar (struct window *w)
return;
#endif /* HAVE_NS */
+#ifdef HAVE_HAIKU
+ if (FRAME_HAIKU_P (f))
+ return;
+#endif /* HAVE_HAIKU */
+
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
eassert (!FRAME_WINDOW_P (f));
init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID);
@@ -33698,6 +33708,11 @@ note_mouse_highlight (struct frame *f, int x, int y)
return;
#endif
+#if defined (HAVE_HAIKU)
+ if (popup_activated_p)
+ return;
+#endif
+
if (!f->glyphs_initialized_p
|| f->pointer_invisible)
return;
diff --git a/src/xfaces.c b/src/xfaces.c
index 442fcf47d3..1e9417b9f1 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -246,6 +246,10 @@ #define GCGraphicsExposures 0
#ifdef HAVE_NS
#define GCGraphicsExposures 0
#endif /* HAVE_NS */
+
+#ifdef HAVE_HAIKU
+#define GCGraphicsExposures 0
+#endif /* HAVE_HAIKU */
#endif /* HAVE_WINDOW_SYSTEM */
#include "buffer.h"
@@ -555,8 +559,8 @@ x_free_gc (struct frame *f, Emacs_GC *gc)
#endif /* HAVE_NTGUI */
-#ifdef HAVE_NS
-/* NS emulation of GCs */
+#if defined (HAVE_NS) || defined (HAVE_HAIKU)
+/* NS and Haiku emulation of GCs */
static Emacs_GC *
x_create_gc (struct frame *f,
diff --git a/src/xfns.c b/src/xfns.c
index 785ae3baca..68b6104757 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4416,7 +4416,8 @@ DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
Protocol used on TERMINAL and the 3rd number is the distributor-specific
release number. For MS Windows, the 3 numbers report the OS major and
minor version and build number. For Nextstep, the first 2 numbers are
-hard-coded and the 3rd represents the OS version.
+hard-coded and the 3rd represents the OS version. For Haiku, all 3
+numbers are hard-coded.
See also the function `x-server-vendor'.
@@ -7374,7 +7375,7 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
selection box, if specified. If MUSTMATCH is non-nil, the returned file
or directory must exist.
-This function is defined only on NS, MS Windows, and X Windows with the
+This function is defined only on NS, Haiku, MS Windows, and X Windows with the
Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored.
Otherwise, if ONLY-DIR-P is non-nil, the user can select only directories.
On MS Windows 7 and later, the file selection dialog "remembers" the last
diff --git a/src/xterm.c b/src/xterm.c
index 5988d3a15f..ed5af0a86d 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13842,7 +13842,7 @@ syms_of_xterm (void)
A value of nil means Emacs doesn't use toolkit scroll bars.
With the X Window system, the value is a symbol describing the
X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
-With MS Windows or Nextstep, the value is t. */);
+With MS Windows, Haiku windowing or Nextstep, the value is t. */);
#ifdef USE_TOOLKIT_SCROLL_BARS
#ifdef USE_MOTIF
Vx_toolkit_scroll_bars = intern_c_string ("motif");
[-- Attachment #3: Type: text/plain, Size: 185 bytes --]
> Yes, makes sense. It would be worthwhile just to solve this problem
> with the NS port. I will look into it.
I haven't had time to look at this yet, but I will in a bit. Thanks.
next prev parent reply other threads:[~2021-11-15 2:59 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <87ee7surtv.fsf.ref@yahoo.com>
2021-11-07 11:29 ` bug#51658: [PATCH] Haiku port (again) Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-09 17:58 ` Eli Zaretskii
2021-11-10 0:00 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-10 4:33 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-10 12:38 ` Eli Zaretskii
2021-11-10 12:56 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-10 14:19 ` Eli Zaretskii
2021-11-11 0:27 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-11 6:51 ` Eli Zaretskii
2021-11-11 7:40 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-13 18:31 ` Eli Zaretskii
2021-11-14 1:08 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-14 7:54 ` Eli Zaretskii
2021-11-14 9:36 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-14 10:28 ` Eli Zaretskii
2021-11-14 10:39 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-14 10:54 ` Eli Zaretskii
2021-11-14 11:06 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-15 2:59 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2021-11-20 7:03 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-20 8:33 ` Eli Zaretskii
2021-11-20 9:34 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-20 9:56 ` Eli Zaretskii
2021-11-20 13:08 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-20 13:30 ` Eli Zaretskii
2021-11-20 13:33 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-20 13:41 ` Eli Zaretskii
2021-11-20 13:45 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-20 13:55 ` Eli Zaretskii
2021-11-20 13:51 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-11-20 14:15 ` Eli Zaretskii
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87lf1q2kez.fsf@yahoo.com \
--to=bug-gnu-emacs@gnu.org \
--cc=51658@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=luangruo@yahoo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.