aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2021-11-20 21:30:08 +0800
committerPo Lu2021-11-20 21:46:07 +0800
commit85a078e7853d708e599f97a3de06aed3a1c090ea (patch)
tree082931cb8ad6b276d8eaafeda685c368e0510f05 /src
parentbfcc59371ba74e53c5ce1ba93bcddf9a9aa64230 (diff)
downloademacs-85a078e7853d708e599f97a3de06aed3a1c090ea.tar.gz
emacs-85a078e7853d708e599f97a3de06aed3a1c090ea.zip
Add support for the Haiku operating system and its window system
* .gitignore: Add binaries specific to Haiku. * Makefie.in (HAVE_BE_APP): New variable. (install-arch-dep): Install Emacs and Emacs.pdmp when using Haiku. * configure.ac: Detect and configure for Haiku and various related configurations. (be-app, be-freetype, be-cairo): New options. (HAVE_BE_APP, HAIKU_OBJ, HAIKU_CXX_OBJ) (HAIKU_LIBS, HAIKU_CFLAGS): New variables. (HAIKU, HAVE_TINY_SPEED_T): New define. (emacs_config_features): Add BE_APP. * doc/emacs/Makefile.in (EMACSSOURCES): Add Haiku appendix. * doc/emacs/emacs.texi: Add Haiku appendix to menus and include it. * doc/emacs/haiku.texi: New Haiku appendix. * doc/lispref/display.texi (Defining Faces, Window Systems): Explain meaning of `haiku' as a window system identifier. (haiku-use-system-tooltips): Explain meaning of system tooltips on Haiku. * doc/lispref/frames.texi (Multiple Terminals): Explain meaning of haiku as a display type. (Frame Layout): Clarify section for Haiku frames. (Size Parameters): Explain limitations of fullwidth and fullheight on Haiku. (Management Parameters): Explain limitations of inhibiting double buffering on builds with Cairo, and the inability of frames with no-accept-focus to receive keyboard input on Haiku. (Font and Color Parameters): Explain the different font backends available on Haiku. (Raising and Lowering): Explain that lowering and restacking frames doesn't work on Haiku. (Child Frames): Explain oddities of child frame visibility on Haiku. * doc/lispref/os.texi (System Environment): Explain meaning of haiku. * etc/MACHINES: Add appropriate notices for Haiku. * etc/NEWS: Document changes. * etc/PROBLEMS: Document font spacing bug on Haiku. * lib-src/Makefile.in: Build be-resources binary on Haiku. (CXX, CXXFLAGS, NON_CXX_FLAGS, ALL_CXXFLAGS) (HAVE_BE_APP, HAIKU_LIBS, HAIKU_CFLAGS): New variables. (DONT_INSTALL): Add be-resources binary if on Haiku. (be-resources): New target. * lib-src/be_resources: Add helper binary for setting resources on the Emacs application. * lib-src/emacsclient.c (decode_options): Set alt_display to "be" on Haiku. * lisp/cus-edit.el (custom-button, custom-button-mouse) (custom-button-unraised, custom-button-pressed): Update face definitions for Haiku. * lisp/cus-start.el: Add haiku-debug-on-fatal-error and haiku-use-system-tooltips. * lisp/faces.el (face-valid-attribute-values): Clarify attribute comment for Haiku. (tool-bar): Add appropriate toolbar color for Haiku. * lisp/frame.el (haiku-frame-geometry) (haiku-mouse-absolute-pixel-position) (haiku-set-mouse-absolute-pixel-position) (haiku-frame-edges) (haiku-frame-list-z-order): New function declarations. (frame-geometry, frame-edges) (mouse-absolute-pixel-position) (set-mouse-absolute-pixel-position) (frame-list-z-order): Call appropriate window system functions on Haiku. (display-mouse-p, display-graphic-p) (display-images-p, display-pixel-height) (display-pixel-width, display-mm-height) (display-mm-width, display-backing-store) (display-save-under, display-planes) (display-color-cells, display-visual-class): Update type tests for Haiku. * lisp/international/mule-cmds.el (set-coding-system-map): Also prevent set-terminal-coding-system from appearing in the menu bar on Haiku. * lisp/loadup.el: Load Haiku-specific files when built with Haiku, and don't rename newly built Emacs on Haiku as BFS doesn't support hard links. * lisp/menu-bar.el (menu-bar-open): Add for Haiku. * lisp/mwheel.el (mouse-wheel-down-event): Expect wheel-up on Haiku. (mouse-wheel-up-event): Expect wheel-down on Haiku. (mouse-wheel-left-event): Expect wheel-left on Haiku. (mouse-wheel-right-event): Expect wheel-right on Haiku. * lisp/net/browse-url.el (browse-url--browser-defcustom-type): Add option for WebPositive. (browse-url-webpositive-program): New variable. (browse-url-default-program): Search for WebPositive. (browse-url-webpositive): New function. * lisp/net/eww.el (eww-form-submit, eww-form-file) (eww-form-checkbox, eww-form-select): Define faces appropriately for Haiku. * lisp/term/haiku-win.el: New file. * lisp/tooltip.el (menu-or-popup-active-p): New function declaration. (tooltip-show-help): Don't use tooltips on Haiku when a menu is active. * lisp/version.el (haiku-get-version-string): New function declaration. (emacs-version): Add Haiku version string if appropriate. * src/Makefile.in: Also produce binary named "Emacs" with Haiku resources set. (CXX, HAIKU_OBJ, HAIKU_CXX_OBJ, HAIKU_LIBS) (HAIKU_CFLAGS, HAVE_BE_APP, NON_CXX_FLAGS) (ALL_CXX_FLAGS): New variables. (.SUFFIXES): Add .cc. (.cc.o): New target. (base_obj): Add Haiku C objects. (doc_obj, obj): Split objects that should scanned for documentation into doc_obj. (SOME_MACHINE_OBJECTS): Add appropriate Haiku C objects. (all): Depend on Emacs and Emacs.pdmp on Haiku. (LIBES): Add Haiku libraries. (gl-stamp) ($(etc)/DOC): Scan doc_obj instead of obj (temacs$(EXEEXT): Use C++ linker on Haiku. (ctagsfiles3): New variable. (TAGS): Scan C++ files. * src/alloc.c (garbage_collect): Mark Haiku display. * src/dispextern.h (HAVE_NATIVE_TRANSFORMS): Also enable on Haiku. (struct image): Add fields for Haiku transforms. (RGB_PIXEL_COLOR): Define to unsigned long on Haiku as well. (sit_for): Also check USABLE_SIGPOLL. (init_display_interactive): Set initial window system to Haiku on Haiku builds. * src/emacs.c (main): Define Haiku syms and init haiku clipboard. (shut_down_emacs): Quit BApplication on Haiku and trigger debug on aborts if haiku_debug_on_fatal_error. (Vsystem_type): Update docstring. * src/fileio.c (next-read-file-uses-dialog-p): Enable on Haiku. * src/filelock.c (WTMP_FILE): Only define if BOOT_TIME is also defined. * src/floatfns.c (double_integer_scale): Work around Haiku libroot brain damage. * src/font.c (syms_of_font): Define appropriate font driver symbols for Haiku builds with various options. * src/font.h: Also enable ftcrfont on Haiku builds with Cairo. (font_data_structures_may_be_ill_formed): Also enable on Haiku builds that have Cairo. * src/frame.c (Fframep): Update doc-string for Haiku builds and return haiku if appropriate. (syms_of_frame): New symbol `haiku'. * src/frame.h (struct frame): Add output data for Haiku. (FRAME_HAIKU_P): New macro. (FRAME_WINDOW_P): Test for Haiku frames as well. * src/ftcrfont.c (RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG): New macros. (ftcrfont_draw): Add haiku specific code for Haiku builds with Cairo. * src/ftfont.c (ftfont_open): Set face. (ftfont_has_char, ftfont_text_extents): Work around crash. (syms_of_ftfont): New symbol `mono'. * src/ftfont.h (struct font_info): Enable Cairo-specific fields for Cairo builds on Haiku. * src/haiku_draw_support.cc: * src/haiku_font_support.cc: * src/haiku_io.c: * src/haiku_select.cc: * src/haiku_support.cc: * src/haiku_support.h: * src/haikufns.c: * src/haikufont.c: * src/haikugui.h: * src/haikuimage.c: * src/haikumenu.c: * src/haikuselect.c: * src/haikuselect.h: * src/haikuterm.c: * src/haikuterm.h: Add new files for Haiku windowing support. * src/haiku.c: Add new files for Haiku operating system support. * src/image.c: Implement image transforms and native XPM support on Haiku. (GET_PIXEL, PUT_PIXEL, NO_PIXMAP) (PIX_MASK_RETAIN, PIX_MASK_DRAW) (RGB_TO_ULONG, RED_FROM_ULONG, GREEN_FROM_ULONG) (BLUE_FROM_ULONG, RED16_FROM_ULONG, GREEN16_FROM_ULONG) (BLUE16_FROM_ULONG): Define to appropriate values on Haiku. (image_create_bitmap_from_data): Add Haiku support. (image_create_bitmap_from_file): Add TODO on Haiku. (free_bitmap_record): Free bitmap on Haiku. (image_size_in_bytes): Implement for Haiku bitmaps. (image_set_transform): Implement on Haiku. (image_create_x_image_and_pixmap_1): Implement on Haiku, 24-bit or 1-bit only. (image_destroy_x_image, image_get_x_image): Use correct img and pixmap values on Haiku. (lookup_rgb_color): Use correct macro on Haiku. (image_to_emacs_colors): Implement on Haiku. (image_disable_image): Disable on Haiku. (image_can_use_native_api): Test for translator presence on Haiku. (native_image_load): Use translator on Haiku. (imagemagick_load_image): Add Haiku-specific quirks. (Fimage_transforms_p): Allow rotate90 on Haiku. (image_types): Enable native XPM support on Haiku. (syms_of_image): Enable XPM images on Haiku. * src/keyboard.c (kbd_buffer_get_event) (handle_async_input, handle_input_available_signal) (handle_user_signal, Fset_input_interrupt_mode) (init_keyboard): Check for USABLE_SIGPOLL along with USABLE_SIGIO. * src/lisp.h (pD): Work around broken Haiku headers. (HAVE_EXT_MENU_BAR): Define on Haiku. (handle_input_available_signal): Enable if we just have SIGPOLL as well. * src/menu.c (have_boxes): Return true on Haiku. (single_menu_item): Enable toolkit menus on Haiku. (find_and_call_menu_selection): Also enable on Haiku. * src/process.c (keyboard_bit_set): Enable with only usable SIGPOLL. (wait_reading_process_output): Test for SIGPOLL as well as SIGIO availability. * src/sound.c (sound_perror, vox_open) (vox_configure, vox_close): Enable for usable SIGPOLL as well. * src/sysdep.c (sys_subshell): Enable for usable SIGPOLL. (reset_sigio): Make conditional on F_SETOWN. (request_sigio, unrequest_sigio) (emacs_sigaction_init): Also handle SIGPOLLs. (init_sys_modes): Disable TCXONC usage on Haiku, as it doesn't have any ttys other than pseudo ttys, which don't support C-s/C-q flow control, and causes compiler warnings. (speeds): Disable high speeds if HAVE_TINY_SPEED_T. * src/termhooks.h (enum output_method): Add output_haiku. (struct terminal): Add Haiku display info. (TERMINAL_FONT_CACHE): Enable for Haiku. * src/terminal.c (Fterminal_live_p): Return `haiku' if appropriate. * src/verbose.mk.in (AM_V_CXX, AM_V_CXXLD): New logging variables. * src/xdisp.c (redisplay_internal) (note_mouse_highlight): Return on Haiku if a popup is activated. (display_menu_bar): Return on Haiku if frame is a Haiku frame. * src/xfaces.c (GCGraphicsExposures): Enable correctly on Haiku. (x_create_gc): Enable dummy GC code on Haiku. * src/xfns.c (x-server-version, x-file-dialog): Add Haiku specifics to doc strings. * src/xterm.c (syms_of_xterm): Add Haiku information to doc string.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in64
-rw-r--r--src/alloc.c4
-rw-r--r--src/dispextern.h20
-rw-r--r--src/dispnew.c11
-rw-r--r--src/emacs.c28
-rw-r--r--src/fileio.c2
-rw-r--r--src/filelock.c2
-rw-r--r--src/floatfns.c15
-rw-r--r--src/font.c3
-rw-r--r--src/font.h4
-rw-r--r--src/frame.c4
-rw-r--r--src/frame.h9
-rw-r--r--src/ftcrfont.c56
-rw-r--r--src/ftfont.c4
-rw-r--r--src/ftfont.h6
-rw-r--r--src/haiku.c286
-rw-r--r--src/haiku_draw_support.cc488
-rw-r--r--src/haiku_font_support.cc596
-rw-r--r--src/haiku_io.c207
-rw-r--r--src/haiku_select.cc155
-rw-r--r--src/haiku_support.cc2930
-rw-r--r--src/haiku_support.h869
-rw-r--r--src/haikufns.c2448
-rw-r--r--src/haikufont.c1072
-rw-r--r--src/haikugui.h106
-rw-r--r--src/haikuimage.c109
-rw-r--r--src/haikumenu.c656
-rw-r--r--src/haikuselect.c134
-rw-r--r--src/haikuselect.h64
-rw-r--r--src/haikuterm.c3608
-rw-r--r--src/haikuterm.h293
-rw-r--r--src/image.c142
-rw-r--r--src/keyboard.c21
-rw-r--r--src/lisp.h14
-rw-r--r--src/menu.c12
-rw-r--r--src/process.c10
-rw-r--r--src/sound.c24
-rw-r--r--src/sysdep.c34
-rw-r--r--src/termhooks.h8
-rw-r--r--src/terminal.c2
-rw-r--r--src/verbose.mk.in4
-rw-r--r--src/xdisp.c15
-rw-r--r--src/xfaces.c8
-rw-r--r--src/xfns.c5
-rw-r--r--src/xterm.c2
45 files changed, 14477 insertions, 77 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 0aaaf91d392..d276df22475 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -34,6 +34,7 @@ top_builddir = @top_builddir@
34abs_top_srcdir=@abs_top_srcdir@ 34abs_top_srcdir=@abs_top_srcdir@
35VPATH = $(srcdir) 35VPATH = $(srcdir)
36CC = @CC@ 36CC = @CC@
37CXX = @CXX@
37CFLAGS = @CFLAGS@ 38CFLAGS = @CFLAGS@
38CPPFLAGS = @CPPFLAGS@ 39CPPFLAGS = @CPPFLAGS@
39LDFLAGS = @LDFLAGS@ 40LDFLAGS = @LDFLAGS@
@@ -346,10 +347,17 @@ BUILD_DETAILS = @BUILD_DETAILS@
346 347
347UNEXEC_OBJ = @UNEXEC_OBJ@ 348UNEXEC_OBJ = @UNEXEC_OBJ@
348 349
350HAIKU_OBJ = @HAIKU_OBJ@
351HAIKU_CXX_OBJ = @HAIKU_CXX_OBJ@
352HAIKU_LIBS = @HAIKU_LIBS@
353HAIKU_CFLAGS = @HAIKU_CFLAGS@
354
349DUMPING=@DUMPING@ 355DUMPING=@DUMPING@
350CHECK_STRUCTS = @CHECK_STRUCTS@ 356CHECK_STRUCTS = @CHECK_STRUCTS@
351HAVE_PDUMPER = @HAVE_PDUMPER@ 357HAVE_PDUMPER = @HAVE_PDUMPER@
352 358
359HAVE_BE_APP = @HAVE_BE_APP@
360
353## ARM Macs require that all code have a valid signature. Since pdump 361## ARM Macs require that all code have a valid signature. Since pdump
354## invalidates the signature, we must re-sign to fix it. 362## invalidates the signature, we must re-sign to fix it.
355DO_CODESIGN=$(patsubst aarch64-apple-darwin%,yes,@configuration@) 363DO_CODESIGN=$(patsubst aarch64-apple-darwin%,yes,@configuration@)
@@ -367,6 +375,9 @@ endif
367 375
368# Flags that might be in WARN_CFLAGS but are not valid for Objective C. 376# Flags that might be in WARN_CFLAGS but are not valid for Objective C.
369NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd 377NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd
378# Ditto, but for C++.
379NON_CXX_CFLAGS = -Wmissing-prototypes -Wnested-externs -Wold-style-definition \
380 -Wstrict-prototypes -Wno-override-init
370 381
371# -Demacs makes some files produce the correct version for use in Emacs. 382# -Demacs makes some files produce the correct version for use in Emacs.
372# MYCPPFLAGS is for by-hand Emacs-specific overrides, e.g., 383# MYCPPFLAGS is for by-hand Emacs-specific overrides, e.g.,
@@ -382,17 +393,21 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
382 $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ 393 $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
383 $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \ 394 $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
384 $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ 395 $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
385 $(WERROR_CFLAGS) 396 $(WERROR_CFLAGS) $(HAIKU_CFLAGS)
386ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) 397ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS)
387ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ 398ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \
388 $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ 399 $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \
389 $(GNU_OBJC_CFLAGS) 400 $(GNU_OBJC_CFLAGS)
401ALL_CXX_CFLAGS = $(EMACS_CFLAGS) \
402 $(filter-out $(NON_CXX_CFLAGS),$(WARN_CFLAGS)) $(CXXFLAGS)
390 403
391.SUFFIXES: .m 404.SUFFIXES: .m .cc
392.c.o: 405.c.o:
393 $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $< 406 $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $(PROFILING_CFLAGS) $<
394.m.o: 407.m.o:
395 $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $< 408 $(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
409.cc.o:
410 $(AM_V_CXX)$(CXX) -c $(CPPFLAGS) $(ALL_CXX_CFLAGS) $(PROFILING_CFLAGS) $<
396 411
397## lastfile must follow all files whose initialized data areas should 412## lastfile must follow all files whose initialized data areas should
398## be dumped as pure by dump-emacs. 413## be dumped as pure by dump-emacs.
@@ -414,8 +429,10 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
414 thread.o systhread.o \ 429 thread.o systhread.o \
415 $(if $(HYBRID_MALLOC),sheap.o) \ 430 $(if $(HYBRID_MALLOC),sheap.o) \
416 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ 431 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
417 $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) 432 $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \
418obj = $(base_obj) $(NS_OBJC_OBJ) 433 $(HAIKU_OBJ)
434doc_obj = $(base_obj) $(NS_OBJC_OBJ)
435obj = $(doc_obj) $(HAIKU_CXX_OBJ)
419 436
420## Object files used on some machine or other. 437## Object files used on some machine or other.
421## These go in the DOC file on all machines in case they are needed. 438## These go in the DOC file on all machines in case they are needed.
@@ -429,7 +446,8 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \
429 w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \ 446 w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \
430 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ 447 w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
431 w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ 448 w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \
432 xsettings.o xgselect.o termcap.o hbfont.o 449 xsettings.o xgselect.o termcap.o hbfont.o \
450 haikuterm.o haikufns.o haikumenu.o haikufont.o
433 451
434## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty. 452## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty.
435GMALLOC_OBJ=@GMALLOC_OBJ@ 453GMALLOC_OBJ=@GMALLOC_OBJ@
@@ -455,7 +473,11 @@ FIRSTFILE_OBJ=@FIRSTFILE_OBJ@
455ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) 473ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj)
456 474
457# Must be first, before dep inclusion! 475# Must be first, before dep inclusion!
476ifneq ($(HAVE_BE_APP),yes)
458all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) 477all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES)
478else
479all: Emacs Emacs.pdmp $(OTHER_FILES)
480endif
459ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:) 481ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
460all: ../native-lisp 482all: ../native-lisp
461endif 483endif
@@ -527,7 +549,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
527 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ 549 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
528 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ 550 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
529 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ 551 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
530 $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS) 552 $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS) $(HAIKU_LIBS)
531 553
532## FORCE it so that admin/unidata can decide whether this file is 554## FORCE it so that admin/unidata can decide whether this file is
533## up-to-date. Although since charprop depends on bootstrap-emacs, 555## up-to-date. Although since charprop depends on bootstrap-emacs,
@@ -584,6 +606,18 @@ else
584 rm -f $@ && cp -f temacs$(EXEEXT) $@ 606 rm -f $@ && cp -f temacs$(EXEEXT) $@
585endif 607endif
586 608
609## On Haiku, also produce a binary named Emacs with the appropriate
610## icon set.
611
612ifeq ($(HAVE_BE_APP),yes)
613Emacs: emacs$(EXEEXT)
614 cp -f emacs$(EXEEXT) $@
615 $(AM_V_GEN) $(libsrc)/be-resources \
616 $(etc)/images/icons/hicolor/32x32/apps/emacs.png $@
617Emacs.pdmp: $(pdmp)
618 $(AM_V_GEN) cp -f $(pdmp) $@
619endif
620
587ifeq ($(DUMPING),pdumper) 621ifeq ($(DUMPING),pdumper)
588$(pdmp): emacs$(EXEEXT) 622$(pdmp): emacs$(EXEEXT)
589 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \ 623 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \
@@ -602,11 +636,11 @@ endif
602## for the first time, this prevents any variation between configurations 636## for the first time, this prevents any variation between configurations
603## in the contents of the DOC file. 637## in the contents of the DOC file.
604## 638##
605$(etc)/DOC: lisp.mk $(libsrc)/make-docfile$(EXEEXT) $(obj) $(lisp) 639$(etc)/DOC: lisp.mk $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) $(lisp)
606 $(AM_V_GEN)$(MKDIR_P) $(etc) 640 $(AM_V_GEN)$(MKDIR_P) $(etc)
607 $(AM_V_at)rm -f $(etc)/DOC 641 $(AM_V_at)rm -f $(etc)/DOC
608 $(AM_V_at)$(libsrc)/make-docfile -d $(srcdir) \ 642 $(AM_V_at)$(libsrc)/make-docfile -d $(srcdir) \
609 $(SOME_MACHINE_OBJECTS) $(obj) > $(etc)/DOC 643 $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC
610 $(AM_V_at)$(libsrc)/make-docfile -a $(etc)/DOC -d $(lispsource) \ 644 $(AM_V_at)$(libsrc)/make-docfile -a $(etc)/DOC -d $(lispsource) \
611 $(shortlisp) 645 $(shortlisp)
612 646
@@ -624,7 +658,7 @@ buildobj.h: Makefile
624GLOBAL_SOURCES = $(base_obj:.o=.c) $(NS_OBJC_OBJ:.o=.m) 658GLOBAL_SOURCES = $(base_obj:.o=.c) $(NS_OBJC_OBJ:.o=.m)
625 659
626gl-stamp: $(libsrc)/make-docfile$(EXEEXT) $(GLOBAL_SOURCES) 660gl-stamp: $(libsrc)/make-docfile$(EXEEXT) $(GLOBAL_SOURCES)
627 $(AM_V_GLOBALS)$(libsrc)/make-docfile -d $(srcdir) -g $(obj) > globals.tmp 661 $(AM_V_GLOBALS)$(libsrc)/make-docfile -d $(srcdir) -g $(doc_obj) > globals.tmp
628 $(AM_V_at)$(top_srcdir)/build-aux/move-if-change globals.tmp globals.h 662 $(AM_V_at)$(top_srcdir)/build-aux/move-if-change globals.tmp globals.h
629 $(AM_V_at)echo timestamp > $@ 663 $(AM_V_at)echo timestamp > $@
630 664
@@ -649,9 +683,15 @@ endif
649## to start if Vinstallation_directory has the wrong value. 683## to start if Vinstallation_directory has the wrong value.
650temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ 684temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \
651 $(charsets) $(charscript) ${emoji-zwj} $(MAKE_PDUMPER_FINGERPRINT) 685 $(charsets) $(charscript) ${emoji-zwj} $(MAKE_PDUMPER_FINGERPRINT)
652 $(AM_V_CCLD)$(CC) -o $@.tmp \ 686ifeq ($(HAVE_BE_APP),yes)
687 $(AM_V_CXXLD)$(CXX) -o $@.tmp \
653 $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ 688 $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \
689 $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) -lstdc++
690else
691 $(AM_V_CCLD)$(CC) -o $@.tmp \
692 $(ALL_CFLAGS) $(CXXFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \
654 $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) 693 $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES)
694endif
655ifeq ($(HAVE_PDUMPER),yes) 695ifeq ($(HAVE_PDUMPER),yes)
656 $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@.tmp 696 $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@.tmp
657ifeq ($(DO_CODESIGN),yes) 697ifeq ($(DO_CODESIGN),yes)
@@ -736,6 +776,7 @@ ${ETAGS}: FORCE
736# to be built before we can get TAGS. 776# to be built before we can get TAGS.
737ctagsfiles1 = $(filter-out ${srcdir}/macuvs.h, $(wildcard ${srcdir}/*.[hc])) 777ctagsfiles1 = $(filter-out ${srcdir}/macuvs.h, $(wildcard ${srcdir}/*.[hc]))
738ctagsfiles2 = $(wildcard ${srcdir}/*.m) 778ctagsfiles2 = $(wildcard ${srcdir}/*.m)
779ctagsfiles3 = $(wildcard ${srcdir}/*.cc)
739 780
740## In out-of-tree builds, TAGS are generated in the build dir, like 781## In out-of-tree builds, TAGS are generated in the build dir, like
741## other non-bootstrap build products (see Bug#31744). 782## other non-bootstrap build products (see Bug#31744).
@@ -750,7 +791,8 @@ TAGS: ${ETAGS} $(ctagsfiles1) $(ctagsfiles2)
750 $(ctagsfiles1) \ 791 $(ctagsfiles1) \
751 --regex='{objc}/[ ]*DEFVAR_[A-Z_ (]+"\([^"]+\)"/\1/' \ 792 --regex='{objc}/[ ]*DEFVAR_[A-Z_ (]+"\([^"]+\)"/\1/' \
752 --regex='{objc}/[ ]*DEFVAR_[A-Z_ (]+"[^"]+",[ ]\([A-Za-z0-9_]+\)/\1/' \ 793 --regex='{objc}/[ ]*DEFVAR_[A-Z_ (]+"[^"]+",[ ]\([A-Za-z0-9_]+\)/\1/' \
753 $(ctagsfiles2) 794 $(ctagsfiles2) \
795 $(ctagsfiles3)
754 796
755## Arrange to make tags tables for ../lisp and ../lwlib, 797## Arrange to make tags tables for ../lisp and ../lwlib,
756## which the above TAGS file for the C files includes by reference. 798## which the above TAGS file for the C files includes by reference.
diff --git a/src/alloc.c b/src/alloc.c
index aa790d3afae..f8908c91dba 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6149,6 +6149,10 @@ garbage_collect (void)
6149 xg_mark_data (); 6149 xg_mark_data ();
6150#endif 6150#endif
6151 6151
6152#ifdef HAVE_HAIKU
6153 mark_haiku_display ();
6154#endif
6155
6152#ifdef HAVE_WINDOW_SYSTEM 6156#ifdef HAVE_WINDOW_SYSTEM
6153 mark_fringe_data (); 6157 mark_fringe_data ();
6154#endif 6158#endif
diff --git a/src/dispextern.h b/src/dispextern.h
index f17f095e0d3..a698f6546b1 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -134,6 +134,13 @@ typedef Emacs_Pixmap Emacs_Pix_Context;
134#define FACE_COLOR_TO_PIXEL(face_color, frame) face_color 134#define FACE_COLOR_TO_PIXEL(face_color, frame) face_color
135#endif 135#endif
136 136
137#ifdef HAVE_HAIKU
138#include "haikugui.h"
139typedef struct haiku_display_info Display_Info;
140typedef Emacs_Pixmap Emacs_Pix_Container;
141typedef Emacs_Pixmap Emacs_Pix_Context;
142#endif
143
137#ifdef HAVE_WINDOW_SYSTEM 144#ifdef HAVE_WINDOW_SYSTEM
138# include <time.h> 145# include <time.h>
139# include "fontset.h" 146# include "fontset.h"
@@ -3011,7 +3018,7 @@ struct redisplay_interface
3011#ifdef HAVE_WINDOW_SYSTEM 3018#ifdef HAVE_WINDOW_SYSTEM
3012 3019
3013# if (defined USE_CAIRO || defined HAVE_XRENDER \ 3020# if (defined USE_CAIRO || defined HAVE_XRENDER \
3014 || defined HAVE_NS || defined HAVE_NTGUI) 3021 || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU)
3015# define HAVE_NATIVE_TRANSFORMS 3022# define HAVE_NATIVE_TRANSFORMS
3016# endif 3023# endif
3017 3024
@@ -3050,6 +3057,14 @@ struct image
3050#ifdef HAVE_NTGUI 3057#ifdef HAVE_NTGUI
3051 XFORM xform; 3058 XFORM xform;
3052#endif 3059#endif
3060#ifdef HAVE_HAIKU
3061 /* Non-zero if the image has not yet been transformed for display. */
3062 int have_be_transforms_p;
3063
3064 double be_rotate;
3065 double be_scale_x;
3066 double be_scale_y;
3067#endif
3053 3068
3054 /* Colors allocated for this image, if any. Allocated via xmalloc. */ 3069 /* Colors allocated for this image, if any. Allocated via xmalloc. */
3055 unsigned long *colors; 3070 unsigned long *colors;
@@ -3489,7 +3504,8 @@ bool valid_image_p (Lisp_Object);
3489void prepare_image_for_display (struct frame *, struct image *); 3504void prepare_image_for_display (struct frame *, struct image *);
3490ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); 3505ptrdiff_t lookup_image (struct frame *, Lisp_Object, int);
3491 3506
3492#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS 3507#if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS \
3508 || defined HAVE_HAIKU
3493#define RGB_PIXEL_COLOR unsigned long 3509#define RGB_PIXEL_COLOR unsigned long
3494#endif 3510#endif
3495 3511
diff --git a/src/dispnew.c b/src/dispnew.c
index 632eec2f031..f3f110a8f27 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -6146,7 +6146,7 @@ sit_for (Lisp_Object timeout, bool reading, int display_option)
6146 wrong_type_argument (Qnumberp, timeout); 6146 wrong_type_argument (Qnumberp, timeout);
6147 6147
6148 6148
6149#ifdef USABLE_SIGIO 6149#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
6150 gobble_input (); 6150 gobble_input ();
6151#endif 6151#endif
6152 6152
@@ -6453,6 +6453,15 @@ init_display_interactive (void)
6453 } 6453 }
6454#endif 6454#endif
6455 6455
6456#ifdef HAVE_HAIKU
6457 if (!inhibit_window_system && !will_dump_p ())
6458 {
6459 Vinitial_window_system = Qhaiku;
6460 Vwindow_system_version = make_fixnum (1);
6461 return;
6462 }
6463#endif
6464
6456 /* If no window system has been specified, try to use the terminal. */ 6465 /* If no window system has been specified, try to use the terminal. */
6457 if (! isatty (STDIN_FILENO)) 6466 if (! isatty (STDIN_FILENO))
6458 fatal ("standard input is not a tty"); 6467 fatal ("standard input is not a tty");
diff --git a/src/emacs.c b/src/emacs.c
index 032b27fcf3c..63f2a393085 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -109,6 +109,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
109#include "getpagesize.h" 109#include "getpagesize.h"
110#include "gnutls.h" 110#include "gnutls.h"
111 111
112#ifdef HAVE_HAIKU
113#include <kernel/OS.h>
114#endif
115
112#ifdef PROFILING 116#ifdef PROFILING
113# include <sys/gmon.h> 117# include <sys/gmon.h>
114extern void moncontrol (int mode); 118extern void moncontrol (int mode);
@@ -2207,6 +2211,18 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2207 syms_of_fontset (); 2211 syms_of_fontset ();
2208#endif /* HAVE_NS */ 2212#endif /* HAVE_NS */
2209 2213
2214#ifdef HAVE_HAIKU
2215 syms_of_haikuterm ();
2216 syms_of_haikufns ();
2217 syms_of_haikumenu ();
2218 syms_of_haikufont ();
2219 syms_of_haikuselect ();
2220#ifdef HAVE_NATIVE_IMAGE_API
2221 syms_of_haikuimage ();
2222#endif
2223 syms_of_fontset ();
2224#endif /* HAVE_HAIKU */
2225
2210 syms_of_gnutls (); 2226 syms_of_gnutls ();
2211 2227
2212#ifdef HAVE_INOTIFY 2228#ifdef HAVE_INOTIFY
@@ -2261,6 +2277,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2261#if defined WINDOWSNT || defined HAVE_NTGUI 2277#if defined WINDOWSNT || defined HAVE_NTGUI
2262 globals_of_w32select (); 2278 globals_of_w32select ();
2263#endif 2279#endif
2280
2281#ifdef HAVE_HAIKU
2282 init_haiku_select ();
2283#endif
2264 } 2284 }
2265 2285
2266 init_charset (); 2286 init_charset ();
@@ -2728,6 +2748,9 @@ shut_down_emacs (int sig, Lisp_Object stuff)
2728 /* Don't update display from now on. */ 2748 /* Don't update display from now on. */
2729 Vinhibit_redisplay = Qt; 2749 Vinhibit_redisplay = Qt;
2730 2750
2751#ifdef HAVE_HAIKU
2752 be_app_quit ();
2753#endif
2731 /* If we are controlling the terminal, reset terminal modes. */ 2754 /* If we are controlling the terminal, reset terminal modes. */
2732#ifndef DOS_NT 2755#ifndef DOS_NT
2733 pid_t tpgrp = tcgetpgrp (STDIN_FILENO); 2756 pid_t tpgrp = tcgetpgrp (STDIN_FILENO);
@@ -2737,6 +2760,10 @@ shut_down_emacs (int sig, Lisp_Object stuff)
2737 if (sig && sig != SIGTERM) 2760 if (sig && sig != SIGTERM)
2738 { 2761 {
2739 static char const fmt[] = "Fatal error %d: %n%s\n"; 2762 static char const fmt[] = "Fatal error %d: %n%s\n";
2763#ifdef HAVE_HAIKU
2764 if (haiku_debug_on_fatal_error)
2765 debugger ("Fatal error in Emacs");
2766#endif
2740 char buf[max ((sizeof fmt - sizeof "%d%n%s\n" 2767 char buf[max ((sizeof fmt - sizeof "%d%n%s\n"
2741 + INT_STRLEN_BOUND (int) + 1), 2768 + INT_STRLEN_BOUND (int) + 1),
2742 min (PIPE_BUF, MAX_ALLOCA))]; 2769 min (PIPE_BUF, MAX_ALLOCA))];
@@ -3229,6 +3256,7 @@ Special values:
3229 `ms-dos' compiled as an MS-DOS application. 3256 `ms-dos' compiled as an MS-DOS application.
3230 `windows-nt' compiled as a native W32 application. 3257 `windows-nt' compiled as a native W32 application.
3231 `cygwin' compiled using the Cygwin library. 3258 `cygwin' compiled using the Cygwin library.
3259 `haiku' compiled for a Haiku system.
3232Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, 3260Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix,
3233hpux, usg-unix-v) indicates some sort of Unix system. */); 3261hpux, usg-unix-v) indicates some sort of Unix system. */);
3234 Vsystem_type = intern_c_string (SYSTEM_TYPE); 3262 Vsystem_type = intern_c_string (SYSTEM_TYPE);
diff --git a/src/fileio.c b/src/fileio.c
index 4015448ecee..859b30564aa 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6190,7 +6190,7 @@ before any other event (mouse or keypress) is handled. */)
6190 (void) 6190 (void)
6191{ 6191{
6192#if (defined USE_GTK || defined USE_MOTIF \ 6192#if (defined USE_GTK || defined USE_MOTIF \
6193 || defined HAVE_NS || defined HAVE_NTGUI) 6193 || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU)
6194 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event)) 6194 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
6195 && use_dialog_box 6195 && use_dialog_box
6196 && use_file_dialog 6196 && use_file_dialog
diff --git a/src/filelock.c b/src/filelock.c
index cc185d96cdf..c12776246bd 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -65,7 +65,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
65#define BOOT_TIME_FILE "/var/run/random-seed" 65#define BOOT_TIME_FILE "/var/run/random-seed"
66#endif 66#endif
67 67
68#if !defined WTMP_FILE && !defined WINDOWSNT 68#if !defined WTMP_FILE && !defined WINDOWSNT && defined BOOT_TIME
69#define WTMP_FILE "/var/log/wtmp" 69#define WTMP_FILE "/var/log/wtmp"
70#endif 70#endif
71 71
diff --git a/src/floatfns.c b/src/floatfns.c
index aadae4fd9d6..f52dae47193 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -347,6 +347,21 @@ int
347double_integer_scale (double d) 347double_integer_scale (double d)
348{ 348{
349 int exponent = ilogb (d); 349 int exponent = ilogb (d);
350#ifdef HAIKU
351 /* On Haiku, the values returned by ilogb are nonsensical when
352 confronted with tiny numbers, inf, or NaN, which breaks the trick
353 used by code on other platforms, so we have to test for each case
354 manually, and return the appropriate value. */
355 if (exponent == FP_ILOGB0)
356 {
357 if (isnan (d))
358 return (DBL_MANT_DIG - DBL_MIN_EXP) + 2;
359 if (isinf (d))
360 return (DBL_MANT_DIG - DBL_MIN_EXP) + 1;
361
362 return (DBL_MANT_DIG - DBL_MIN_EXP);
363 }
364#endif
350 return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX 365 return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX
351 ? DBL_MANT_DIG - 1 - exponent 366 ? DBL_MANT_DIG - 1 - exponent
352 : (DBL_MANT_DIG - DBL_MIN_EXP 367 : (DBL_MANT_DIG - DBL_MIN_EXP
diff --git a/src/font.c b/src/font.c
index b503123b96e..d423fd46b70 100644
--- a/src/font.c
+++ b/src/font.c
@@ -5751,6 +5751,9 @@ match. */);
5751#ifdef HAVE_NTGUI 5751#ifdef HAVE_NTGUI
5752 syms_of_w32font (); 5752 syms_of_w32font ();
5753#endif /* HAVE_NTGUI */ 5753#endif /* HAVE_NTGUI */
5754#ifdef USE_BE_CAIRO
5755 syms_of_ftcrfont ();
5756#endif
5754#endif /* HAVE_WINDOW_SYSTEM */ 5757#endif /* HAVE_WINDOW_SYSTEM */
5755} 5758}
5756 5759
diff --git a/src/font.h b/src/font.h
index 6694164e09b..2da5ec45047 100644
--- a/src/font.h
+++ b/src/font.h
@@ -965,7 +965,7 @@ extern struct font_driver const nsfont_driver;
965extern void syms_of_nsfont (void); 965extern void syms_of_nsfont (void);
966extern void syms_of_macfont (void); 966extern void syms_of_macfont (void);
967#endif /* HAVE_NS */ 967#endif /* HAVE_NS */
968#ifdef USE_CAIRO 968#if defined (USE_CAIRO) || defined (USE_BE_CAIRO)
969extern struct font_driver const ftcrfont_driver; 969extern struct font_driver const ftcrfont_driver;
970#ifdef HAVE_HARFBUZZ 970#ifdef HAVE_HARFBUZZ
971extern struct font_driver ftcrhbfont_driver; 971extern struct font_driver ftcrhbfont_driver;
@@ -999,7 +999,7 @@ extern void font_deferred_log (const char *, Lisp_Object, Lisp_Object);
999INLINE bool 999INLINE bool
1000font_data_structures_may_be_ill_formed (void) 1000font_data_structures_may_be_ill_formed (void)
1001{ 1001{
1002#ifdef USE_CAIRO 1002#if defined USE_CAIRO || defined USE_BE_CAIRO
1003 /* Although this works around Bug#20890, it is probably not the 1003 /* Although this works around Bug#20890, it is probably not the
1004 right thing to do. */ 1004 right thing to do. */
1005 return gc_in_progress; 1005 return gc_in_progress;
diff --git a/src/frame.c b/src/frame.c
index 79a7c89e0dd..a21dd0d9275 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -226,6 +226,7 @@ Value is:
226 `w32' for an Emacs frame that is a window on MS-Windows display, 226 `w32' for an Emacs frame that is a window on MS-Windows display,
227 `ns' for an Emacs frame on a GNUstep or Macintosh Cocoa display, 227 `ns' for an Emacs frame on a GNUstep or Macintosh Cocoa display,
228 `pc' for a direct-write MS-DOS frame. 228 `pc' for a direct-write MS-DOS frame.
229 `haiku` for an Emacs frame running in Haiku.
229See also `frame-live-p'. */) 230See also `frame-live-p'. */)
230 (Lisp_Object object) 231 (Lisp_Object object)
231{ 232{
@@ -244,6 +245,8 @@ See also `frame-live-p'. */)
244 return Qpc; 245 return Qpc;
245 case output_ns: 246 case output_ns:
246 return Qns; 247 return Qns;
248 case output_haiku:
249 return Qhaiku;
247 default: 250 default:
248 emacs_abort (); 251 emacs_abort ();
249 } 252 }
@@ -6020,6 +6023,7 @@ syms_of_frame (void)
6020 DEFSYM (Qw32, "w32"); 6023 DEFSYM (Qw32, "w32");
6021 DEFSYM (Qpc, "pc"); 6024 DEFSYM (Qpc, "pc");
6022 DEFSYM (Qns, "ns"); 6025 DEFSYM (Qns, "ns");
6026 DEFSYM (Qhaiku, "haiku");
6023 DEFSYM (Qvisible, "visible"); 6027 DEFSYM (Qvisible, "visible");
6024 DEFSYM (Qbuffer_predicate, "buffer-predicate"); 6028 DEFSYM (Qbuffer_predicate, "buffer-predicate");
6025 DEFSYM (Qbuffer_list, "buffer-list"); 6029 DEFSYM (Qbuffer_list, "buffer-list");
diff --git a/src/frame.h b/src/frame.h
index 3dd76805dd2..cb2bad71c5d 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -585,6 +585,7 @@ struct frame
585 struct x_output *x; /* From xterm.h. */ 585 struct x_output *x; /* From xterm.h. */
586 struct w32_output *w32; /* From w32term.h. */ 586 struct w32_output *w32; /* From w32term.h. */
587 struct ns_output *ns; /* From nsterm.h. */ 587 struct ns_output *ns; /* From nsterm.h. */
588 struct haiku_output *haiku; /* From haikuterm.h. */
588 } 589 }
589 output_data; 590 output_data;
590 591
@@ -852,6 +853,11 @@ default_pixels_per_inch_y (void)
852#else 853#else
853#define FRAME_NS_P(f) ((f)->output_method == output_ns) 854#define FRAME_NS_P(f) ((f)->output_method == output_ns)
854#endif 855#endif
856#ifndef HAVE_HAIKU
857#define FRAME_HAIKU_P(f) false
858#else
859#define FRAME_HAIKU_P(f) ((f)->output_method == output_haiku)
860#endif
855 861
856/* FRAME_WINDOW_P tests whether the frame is a graphical window system 862/* FRAME_WINDOW_P tests whether the frame is a graphical window system
857 frame. */ 863 frame. */
@@ -864,6 +870,9 @@ default_pixels_per_inch_y (void)
864#ifdef HAVE_NS 870#ifdef HAVE_NS
865#define FRAME_WINDOW_P(f) FRAME_NS_P(f) 871#define FRAME_WINDOW_P(f) FRAME_NS_P(f)
866#endif 872#endif
873#ifdef HAVE_HAIKU
874#define FRAME_WINDOW_P(f) FRAME_HAIKU_P (f)
875#endif
867#ifndef FRAME_WINDOW_P 876#ifndef FRAME_WINDOW_P
868#define FRAME_WINDOW_P(f) ((void) (f), false) 877#define FRAME_WINDOW_P(f) ((void) (f), false)
869#endif 878#endif
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index db417b3e77d..5d75f183570 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -22,7 +22,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
22#include <cairo-ft.h> 22#include <cairo-ft.h>
23 23
24#include "lisp.h" 24#include "lisp.h"
25#ifdef HAVE_X_WINDOWS
25#include "xterm.h" 26#include "xterm.h"
27#else /* Otherwise, Haiku */
28#include "haikuterm.h"
29#include "haiku_support.h"
30#include "termchar.h"
31#endif
26#include "blockinput.h" 32#include "blockinput.h"
27#include "charset.h" 33#include "charset.h"
28#include "composite.h" 34#include "composite.h"
@@ -30,6 +36,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
30#include "ftfont.h" 36#include "ftfont.h"
31#include "pdumper.h" 37#include "pdumper.h"
32 38
39#ifdef USE_BE_CAIRO
40#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
41#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
42#define BLUE_FROM_ULONG(color) ((color) & 0xff)
43#endif
44
33#define METRICS_NCOLS_PER_ROW (128) 45#define METRICS_NCOLS_PER_ROW (128)
34 46
35enum metrics_status 47enum metrics_status
@@ -513,11 +525,37 @@ ftcrfont_draw (struct glyph_string *s,
513 525
514 block_input (); 526 block_input ();
515 527
528#ifndef USE_BE_CAIRO
516 cr = x_begin_cr_clip (f, s->gc); 529 cr = x_begin_cr_clip (f, s->gc);
530#else
531 BView_draw_lock (FRAME_HAIKU_VIEW (f));
532 EmacsWindow_begin_cr_critical_section (FRAME_HAIKU_WINDOW (f));
533 cr = haiku_begin_cr_clip (f, s);
534 if (!cr)
535 {
536 BView_draw_unlock (FRAME_HAIKU_VIEW (f));
537 EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
538 unblock_input ();
539 return 0;
540 }
541 BView_cr_dump_clipping (FRAME_HAIKU_VIEW (f), cr);
542#endif
517 543
518 if (with_background) 544 if (with_background)
519 { 545 {
546#ifndef USE_BE_CAIRO
520 x_set_cr_source_with_gc_background (f, s->gc); 547 x_set_cr_source_with_gc_background (f, s->gc);
548 s->background_filled_p = 1;
549#else
550 struct face *face = s->face;
551
552 uint32_t col = s->hl == DRAW_CURSOR ?
553 FRAME_CURSOR_COLOR (s->f).pixel : face->background;
554
555 cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
556 GREEN_FROM_ULONG (col) / 255.0,
557 BLUE_FROM_ULONG (col) / 255.0);
558#endif
521 cairo_rectangle (cr, x, y - FONT_BASE (face->font), 559 cairo_rectangle (cr, x, y - FONT_BASE (face->font),
522 s->width, FONT_HEIGHT (face->font)); 560 s->width, FONT_HEIGHT (face->font));
523 cairo_fill (cr); 561 cairo_fill (cr);
@@ -533,13 +571,25 @@ ftcrfont_draw (struct glyph_string *s,
533 glyphs[i].index, 571 glyphs[i].index,
534 NULL)); 572 NULL));
535 } 573 }
536 574#ifndef USE_BE_CAIRO
537 x_set_cr_source_with_gc_foreground (f, s->gc); 575 x_set_cr_source_with_gc_foreground (f, s->gc);
576#else
577 uint32_t col = s->hl == DRAW_CURSOR ?
578 FRAME_OUTPUT_DATA (s->f)->cursor_fg : face->foreground;
579
580 cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
581 GREEN_FROM_ULONG (col) / 255.0,
582 BLUE_FROM_ULONG (col) / 255.0);
583#endif
538 cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font); 584 cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font);
539 cairo_show_glyphs (cr, glyphs, len); 585 cairo_show_glyphs (cr, glyphs, len);
540 586#ifndef USE_BE_CAIRO
541 x_end_cr_clip (f); 587 x_end_cr_clip (f);
542 588#else
589 haiku_end_cr_clip (cr);
590 EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
591 BView_draw_unlock (FRAME_HAIKU_VIEW (f));
592#endif
543 unblock_input (); 593 unblock_input ();
544 594
545 return len; 595 return len;
diff --git a/src/ftfont.c b/src/ftfont.c
index 03e44ec30ee..cf592759ab6 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -3108,6 +3108,10 @@ syms_of_ftfont (void)
3108 Fput (Qfreetype, Qfont_driver_superseded_by, Qfreetypehb); 3108 Fput (Qfreetype, Qfont_driver_superseded_by, Qfreetypehb);
3109#endif /* HAVE_HARFBUZZ */ 3109#endif /* HAVE_HARFBUZZ */
3110 3110
3111#ifdef HAVE_HAIKU
3112 DEFSYM (Qmono, "mono");
3113#endif
3114
3111 /* Fontconfig's generic families and their aliases. */ 3115 /* Fontconfig's generic families and their aliases. */
3112 DEFSYM (Qmonospace, "monospace"); 3116 DEFSYM (Qmonospace, "monospace");
3113 DEFSYM (Qsans_serif, "sans-serif"); 3117 DEFSYM (Qsans_serif, "sans-serif");
diff --git a/src/ftfont.h b/src/ftfont.h
index f771dc159b0..0e0bebb6f6c 100644
--- a/src/ftfont.h
+++ b/src/ftfont.h
@@ -29,6 +29,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29# include FT_BDF_H 29# include FT_BDF_H
30#endif 30#endif
31 31
32#ifdef USE_BE_CAIRO
33#include <cairo.h>
34#endif
35
32#ifdef HAVE_HARFBUZZ 36#ifdef HAVE_HARFBUZZ
33#include <hb.h> 37#include <hb.h>
34#include <hb-ft.h> 38#include <hb-ft.h>
@@ -62,7 +66,7 @@ struct font_info
62 hb_font_t *hb_font; 66 hb_font_t *hb_font;
63#endif /* HAVE_HARFBUZZ */ 67#endif /* HAVE_HARFBUZZ */
64 68
65#ifdef USE_CAIRO 69#if defined (USE_CAIRO) || defined (USE_BE_CAIRO)
66 cairo_scaled_font_t *cr_scaled_font; 70 cairo_scaled_font_t *cr_scaled_font;
67 /* Scale factor from the bitmap strike metrics in 1/64 pixels, used 71 /* Scale factor from the bitmap strike metrics in 1/64 pixels, used
68 as the hb_position_t value in HarfBuzz, to those in (scaled) 72 as the hb_position_t value in HarfBuzz, to those in (scaled)
diff --git a/src/haiku.c b/src/haiku.c
new file mode 100644
index 00000000000..485d86983c2
--- /dev/null
+++ b/src/haiku.c
@@ -0,0 +1,286 @@
1/* Haiku subroutines that are general to the Haiku operating system.
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include "lisp.h"
22#include "process.h"
23#include "coding.h"
24
25#include <kernel/OS.h>
26
27#include <pwd.h>
28#include <stdlib.h>
29
30Lisp_Object
31list_system_processes (void)
32{
33 team_info info;
34 int32 cookie = 0;
35 Lisp_Object lval = Qnil;
36
37 while (get_next_team_info (&cookie, &info) == B_OK)
38 lval = Fcons (make_fixnum (info.team), lval);
39
40 return lval;
41}
42
43Lisp_Object
44system_process_attributes (Lisp_Object pid)
45{
46 CHECK_FIXNUM (pid);
47
48 team_info info;
49 Lisp_Object lval = Qnil;
50 thread_info inf;
51 area_info area;
52 team_id id = (team_id) XFIXNUM (pid);
53 struct passwd *g;
54 size_t mem = 0;
55
56 if (get_team_info (id, &info) != B_OK)
57 return Qnil;
58
59 bigtime_t everything = 0, vsample = 0;
60 bigtime_t cpu_eaten = 0, esample = 0;
61
62 lval = Fcons (Fcons (Qeuid, make_fixnum (info.uid)), lval);
63 lval = Fcons (Fcons (Qegid, make_fixnum (info.gid)), lval);
64 lval = Fcons (Fcons (Qthcount, make_fixnum (info.thread_count)), lval);
65 lval = Fcons (Fcons (Qcomm, build_string_from_utf8 (info.args)), lval);
66
67 g = getpwuid (info.uid);
68
69 if (g && g->pw_name)
70 lval = Fcons (Fcons (Quser, build_string (g->pw_name)), lval);
71
72 /* FIXME: Calculating this makes Emacs show up as using 100% CPU! */
73
74 for (int32 team_cookie = 0;
75 get_next_team_info (&team_cookie, &info) == B_OK;)
76 for (int32 thread_cookie = 0;
77 get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
78 {
79 if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
80 cpu_eaten += inf.user_time + inf.kernel_time;
81 everything += inf.user_time + inf.kernel_time;
82 }
83
84 sleep (0.05);
85
86 for (int32 team_cookie = 0;
87 get_next_team_info (&team_cookie, &info) == B_OK;)
88 for (int32 thread_cookie = 0;
89 get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
90 {
91 if (inf.team == id && strncmp (inf.name, "idle thread ", 12))
92 esample += inf.user_time + inf.kernel_time;
93 vsample += inf.user_time + inf.kernel_time;
94 }
95
96 cpu_eaten = esample - cpu_eaten;
97 everything = vsample - everything;
98
99 if (everything)
100 lval = Fcons (Fcons (Qpcpu, make_float (((double) (cpu_eaten) /
101 (double) (everything)) * 100)),
102 lval);
103 else
104 lval = Fcons (Fcons (Qpcpu, make_float (0.0)), lval);
105
106 for (ssize_t area_cookie = 0;
107 get_next_area_info (id, &area_cookie, &area) == B_OK;)
108 mem += area.ram_size;
109
110 system_info sinfo;
111 get_system_info (&sinfo);
112 int64 max = (int64) sinfo.max_pages * B_PAGE_SIZE;
113
114 lval = Fcons (Fcons (Qpmem, make_float (((double) mem /
115 (double) max) * 100)),
116 lval);
117 lval = Fcons (Fcons (Qrss, make_fixnum (mem / 1024)), lval);
118
119 return lval;
120}
121
122
123/* Borrowed from w32 implementation. */
124
125struct load_sample
126{
127 time_t sample_time;
128 bigtime_t idle;
129 bigtime_t kernel;
130 bigtime_t user;
131};
132
133/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
134static struct load_sample samples[16*60];
135static int first_idx = -1, last_idx = -1;
136static int max_idx = ARRAYELTS (samples);
137static unsigned num_of_processors = 0;
138
139static int
140buf_next (int from)
141{
142 int next_idx = from + 1;
143
144 if (next_idx >= max_idx)
145 next_idx = 0;
146
147 return next_idx;
148}
149
150static int
151buf_prev (int from)
152{
153 int prev_idx = from - 1;
154
155 if (prev_idx < 0)
156 prev_idx = max_idx - 1;
157
158 return prev_idx;
159}
160
161static double
162getavg (int which)
163{
164 double retval = -1.0;
165 double tdiff;
166 int idx;
167 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
168 time_t now = samples[last_idx].sample_time;
169
170 if (first_idx != last_idx)
171 {
172 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
173 {
174 tdiff = difftime (now, samples[idx].sample_time);
175 if (tdiff >= span - 2 * DBL_EPSILON * now)
176 {
177 long double sys =
178 (samples[last_idx].kernel + samples[last_idx].user) -
179 (samples[idx].kernel + samples[idx].user);
180 long double idl = samples[last_idx].idle - samples[idx].idle;
181
182 retval = (idl / (sys + idl)) * num_of_processors;
183 break;
184 }
185 if (idx == first_idx)
186 break;
187 }
188 }
189
190 return retval;
191}
192
193static void
194sample_sys_load (bigtime_t *idle, bigtime_t *system, bigtime_t *user)
195{
196 bigtime_t i = 0, s = 0, u = 0;
197 team_info info;
198 thread_info inf;
199
200 for (int32 team_cookie = 0;
201 get_next_team_info (&team_cookie, &info) == B_OK;)
202 for (int32 thread_cookie = 0;
203 get_next_thread_info (info.team, &thread_cookie, &inf) == B_OK;)
204 {
205 if (!strncmp (inf.name, "idle thread ", 12))
206 i += inf.user_time + inf.kernel_time;
207 else
208 s += inf.kernel_time, u += inf.user_time;
209 }
210
211 *idle = i;
212 *system = s;
213 *user = u;
214}
215
216int
217getloadavg (double loadavg[], int nelem)
218{
219 int elem;
220 bigtime_t idle, kernel, user;
221 time_t now = time (NULL);
222
223 if (num_of_processors <= 0)
224 {
225 system_info i;
226 if (get_system_info (&i) == B_OK)
227 num_of_processors = i.cpu_count;
228 }
229
230 /* If system time jumped back for some reason, delete all samples
231 whose time is later than the current wall-clock time. This
232 prevents load average figures from becoming frozen for prolonged
233 periods of time, when system time is reset backwards. */
234 if (last_idx >= 0)
235 {
236 while (difftime (now, samples[last_idx].sample_time) < -1.0)
237 {
238 if (last_idx == first_idx)
239 {
240 first_idx = last_idx = -1;
241 break;
242 }
243 last_idx = buf_prev (last_idx);
244 }
245 }
246
247 /* Store another sample. We ignore samples that are less than 1 sec
248 apart. */
249 if (last_idx < 0
250 || (difftime (now, samples[last_idx].sample_time)
251 >= 1.0 - 2 * DBL_EPSILON * now))
252 {
253 sample_sys_load (&idle, &kernel, &user);
254 last_idx = buf_next (last_idx);
255 samples[last_idx].sample_time = now;
256 samples[last_idx].idle = idle;
257 samples[last_idx].kernel = kernel;
258 samples[last_idx].user = user;
259 /* If the buffer has more that 15 min worth of samples, discard
260 the old ones. */
261 if (first_idx == -1)
262 first_idx = last_idx;
263 while (first_idx != last_idx
264 && (difftime (now, samples[first_idx].sample_time)
265 >= 15.0 * 60 + 2 * DBL_EPSILON * now))
266 first_idx = buf_next (first_idx);
267 }
268
269 for (elem = 0; elem < nelem; elem++)
270 {
271 double avg = getavg (elem);
272
273 if (avg < 0)
274 break;
275 loadavg[elem] = avg;
276 }
277
278 /* Always return at least one element, otherwise load-average
279 returns nil, and Lisp programs might decide we cannot measure
280 system load. For example, jit-lock-stealth-load's defcustom
281 might decide that feature is "unsupported". */
282 if (elem == 0)
283 loadavg[elem++] = 0.09; /* < display-time-load-average-threshold */
284
285 return elem;
286}
diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc
new file mode 100644
index 00000000000..5b1eccfbe6e
--- /dev/null
+++ b/src/haiku_draw_support.cc
@@ -0,0 +1,488 @@
1/* Haiku window system support. Hey, Emacs, this is -*- C++ -*-
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include <View.h>
22#include <Region.h>
23#include <Font.h>
24#include <Window.h>
25#include <Bitmap.h>
26
27#include <cmath>
28
29#include "haiku_support.h"
30
31#define RGB_TO_UINT32(r, g, b) ((255 << 24) | ((r) << 16) | ((g) << 8) | (b))
32#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
33#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
34#define BLUE_FROM_ULONG(color) ((color) & 0xff)
35
36#define RGB_COLOR_UINT32(r) RGB_TO_UINT32 ((r).red, (r).green, (r).blue)
37
38static void
39rgb32_to_rgb_color (uint32_t rgb, rgb_color *color)
40{
41 color->red = RED_FROM_ULONG (rgb);
42 color->green = GREEN_FROM_ULONG (rgb);
43 color->blue = BLUE_FROM_ULONG (rgb);
44 color->alpha = 255;
45}
46
47static BView *
48get_view (void *vw)
49{
50 BView *view = (BView *) find_appropriate_view_for_draw (vw);
51 return view;
52}
53
54void
55BView_StartClip (void *view)
56{
57 BView *vw = get_view (view);
58 vw->PushState ();
59}
60
61void
62BView_EndClip (void *view)
63{
64 BView *vw = get_view (view);
65 vw->PopState ();
66}
67
68void
69BView_SetHighColor (void *view, uint32_t color)
70{
71 BView *vw = get_view (view);
72 rgb_color col;
73 rgb32_to_rgb_color (color, &col);
74
75 vw->SetHighColor (col);
76}
77
78void
79BView_SetLowColor (void *view, uint32_t color)
80{
81 BView *vw = get_view (view);
82 rgb_color col;
83 rgb32_to_rgb_color (color, &col);
84
85 vw->SetLowColor (col);
86}
87
88void
89BView_SetPenSize (void *view, int u)
90{
91 BView *vw = get_view (view);
92 vw->SetPenSize (u);
93}
94
95void
96BView_FillRectangle (void *view, int x, int y, int width, int height)
97{
98 BView *vw = get_view (view);
99 BRect rect = BRect (x, y, x + width - 1, y + height - 1);
100
101 vw->FillRect (rect);
102}
103
104void
105BView_FillRectangleAbs (void *view, int x, int y, int x1, int y1)
106{
107 BView *vw = get_view (view);
108 BRect rect = BRect (x, y, x1, y1);
109
110 vw->FillRect (rect);
111}
112
113void
114BView_StrokeRectangle (void *view, int x, int y, int width, int height)
115{
116 BView *vw = get_view (view);
117 BRect rect = BRect (x, y, x + width - 1, y + height - 1);
118
119 vw->StrokeRect (rect);
120}
121
122void
123BView_SetViewColor (void *view, uint32_t color)
124{
125 BView *vw = get_view (view);
126 rgb_color col;
127 rgb32_to_rgb_color (color, &col);
128
129#ifndef USE_BE_CAIRO
130 vw->SetViewColor (col);
131#else
132 vw->SetViewColor (B_TRANSPARENT_32_BIT);
133#endif
134}
135
136void
137BView_ClipToRect (void *view, int x, int y, int width, int height)
138{
139 BView *vw = get_view (view);
140 BRect rect = BRect (x, y, x + width - 1, y + height - 1);
141
142 vw->ClipToRect (rect);
143}
144
145void
146BView_ClipToInverseRect (void *view, int x, int y, int width, int height)
147{
148 BView *vw = get_view (view);
149 BRect rect = BRect (x, y, x + width - 1, y + height - 1);
150
151 vw->ClipToInverseRect (rect);
152}
153
154void
155BView_StrokeLine (void *view, int sx, int sy, int tx, int ty)
156{
157 BView *vw = get_view (view);
158 BPoint from = BPoint (sx, sy);
159 BPoint to = BPoint (tx, ty);
160
161 vw->StrokeLine (from, to);
162}
163
164void
165BView_SetFont (void *view, void *font)
166{
167 BView *vw = get_view (view);
168
169 vw->SetFont ((BFont *) font);
170}
171
172void
173BView_MovePenTo (void *view, int x, int y)
174{
175 BView *vw = get_view (view);
176 BPoint pt = BPoint (x, y);
177
178 vw->MovePenTo (pt);
179}
180
181void
182BView_DrawString (void *view, const char *chr, ptrdiff_t len)
183{
184 BView *vw = get_view (view);
185
186 vw->DrawString (chr, len);
187}
188
189void
190BView_DrawChar (void *view, char chr)
191{
192 BView *vw = get_view (view);
193
194 vw->DrawChar (chr);
195}
196
197void
198BView_CopyBits (void *view, int x, int y, int width, int height,
199 int tox, int toy, int towidth, int toheight)
200{
201 BView *vw = get_view (view);
202
203 vw->CopyBits (BRect (x, y, x + width - 1, y + height - 1),
204 BRect (tox, toy, tox + towidth - 1, toy + toheight - 1));
205 vw->Sync ();
206}
207
208/* Convert RGB32 color color from RGB color space to its
209 HSL components pointed to by H, S and L. */
210void
211rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l)
212{
213 rgb_color col;
214 rgb32_to_rgb_color (rgb, &col);
215
216 double red = col.red / 255.0;
217 double green = col.green / 255.0;
218 double blue = col.blue / 255.0;
219
220 double max = std::fmax (std::fmax (red, blue), green);
221 double min = std::fmin (std::fmin (red, blue), green);
222 double delta = max - min;
223 *l = (max + min) / 2.0;
224
225 if (!delta)
226 {
227 *h = 0;
228 *s = 0;
229 return;
230 }
231
232 *s = (*l < 0.5) ? delta / (max + min) :
233 delta / (20 - max - min);
234 double rc = (max - red) / delta;
235 double gc = (max - green) / delta;
236 double bc = (max - blue) / delta;
237
238 if (red == max)
239 *h = bc - gc;
240 else if (green == max)
241 *h = 2.0 + rc + -bc;
242 else
243 *h = 4.0 + gc + -rc;
244 *h = std::fmod (*h / 6, 1.0);
245}
246
247static double
248hue_to_rgb (double v1, double v2, double h)
249{
250 if (h < 1 / 6)
251 return v1 + (v2 - v1) * h * 6.0;
252 else if (h < 0.5)
253 return v2;
254 else if (h < 2.0 / 3)
255 return v1 + (v2 - v1) * (2.0 / 3 - h) * 6.0;
256 return v1;
257}
258
259void
260hsl_color_rgb (double h, double s, double l, uint32_t *rgb)
261{
262 if (!s)
263 *rgb = RGB_TO_UINT32 (std::lrint (l * 255),
264 std::lrint (l * 255),
265 std::lrint (l * 255));
266 else
267 {
268 double m2 = l <= 0.5 ? l * (1 + s) : l + s - l * s;
269 double m1 = 2.0 * l - m2;
270
271 *rgb = RGB_TO_UINT32
272 (std::lrint (hue_to_rgb (m1, m2,
273 std::fmod (h + 1 / 3.0, 1)) * 255),
274 std::lrint (hue_to_rgb (m1, m2, h) * 255),
275 std::lrint (hue_to_rgb (m1, m2,
276 std::fmod (h - 1 / 3.0, 1)) * 255));
277 }
278}
279
280void
281BView_DrawBitmap (void *view, void *bitmap, int x, int y,
282 int width, int height, int vx, int vy, int vwidth,
283 int vheight)
284{
285 BView *vw = get_view (view);
286 BBitmap *bm = (BBitmap *) bitmap;
287
288 vw->PushState ();
289 vw->SetDrawingMode (B_OP_OVER);
290 vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
291 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
292 vw->PopState ();
293}
294
295void
296BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
297 int y, int width, int height)
298{
299 BView *vw = get_view (view);
300 BBitmap *bm = (BBitmap *) bitmap;
301 BBitmap bc (bm->Bounds (), B_RGBA32);
302 BRect rect (x, y, x + width - 1, y + height - 1);
303
304 if (bc.InitCheck () != B_OK || bc.ImportBits (bm) != B_OK)
305 return;
306
307 uint32_t *bits = (uint32_t *) bc.Bits ();
308 size_t stride = bc.BytesPerRow ();
309
310 if (bm->ColorSpace () == B_GRAY1)
311 {
312 rgb_color low_color = vw->LowColor ();
313 for (int y = 0; y <= bc.Bounds ().Height (); ++y)
314 {
315 for (int x = 0; x <= bc.Bounds ().Width (); ++x)
316 {
317 if (bits[y * (stride / 4) + x] == 0xFF000000)
318 bits[y * (stride / 4) + x] = RGB_COLOR_UINT32 (low_color);
319 else
320 bits[y * (stride / 4) + x] = 0;
321 }
322 }
323 }
324
325 vw->PushState ();
326 vw->SetDrawingMode (bm->ColorSpace () == B_GRAY1 ? B_OP_OVER : B_OP_ERASE);
327 vw->DrawBitmap (&bc, rect);
328 vw->PopState ();
329}
330
331void
332BView_DrawMask (void *src, void *view,
333 int x, int y, int width, int height,
334 int vx, int vy, int vwidth, int vheight,
335 uint32_t color)
336{
337 BBitmap *source = (BBitmap *) src;
338 BBitmap bm (source->Bounds (), B_RGBA32);
339 if (bm.InitCheck () != B_OK)
340 return;
341 for (int y = 0; y <= bm.Bounds ().Height (); ++y)
342 {
343 for (int x = 0; x <= bm.Bounds ().Width (); ++x)
344 {
345 int bit = haiku_get_pixel ((void *) source, x, y);
346
347 if (!bit)
348 haiku_put_pixel ((void *) &bm, x, y, ((uint32_t) 255 << 24) | color);
349 else
350 haiku_put_pixel ((void *) &bm, x, y, 0);
351 }
352 }
353 BView *vw = get_view (view);
354 vw->SetDrawingMode (B_OP_OVER);
355 vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
356 BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
357}
358
359static BBitmap *
360rotate_bitmap_270 (BBitmap *bmp)
361{
362 BRect r = bmp->Bounds ();
363 BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
364 bmp->ColorSpace (), true);
365 if (bm->InitCheck () != B_OK)
366 gui_abort ("Failed to init bitmap for rotate");
367 int w = bmp->Bounds ().Width () + 1;
368 int h = bmp->Bounds ().Height () + 1;
369
370 for (int y = 0; y < h; ++y)
371 for (int x = 0; x < w; ++x)
372 haiku_put_pixel ((void *) bm, y, w - x - 1,
373 haiku_get_pixel ((void *) bmp, x, y));
374
375 return bm;
376}
377
378static BBitmap *
379rotate_bitmap_90 (BBitmap *bmp)
380{
381 BRect r = bmp->Bounds ();
382 BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
383 bmp->ColorSpace (), true);
384 if (bm->InitCheck () != B_OK)
385 gui_abort ("Failed to init bitmap for rotate");
386 int w = bmp->Bounds ().Width () + 1;
387 int h = bmp->Bounds ().Height () + 1;
388
389 for (int y = 0; y < h; ++y)
390 for (int x = 0; x < w; ++x)
391 haiku_put_pixel ((void *) bm, h - y - 1, x,
392 haiku_get_pixel ((void *) bmp, x, y));
393
394 return bm;
395}
396
397void *
398BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color,
399 double rot, int desw, int desh)
400{
401 BBitmap *bm = (BBitmap *) bitmap;
402 BBitmap *mk = (BBitmap *) mask;
403 int copied_p = 0;
404
405 if (rot == 90)
406 {
407 copied_p = 1;
408 bm = rotate_bitmap_90 (bm);
409 if (mk)
410 mk = rotate_bitmap_90 (mk);
411 }
412
413 if (rot == 270)
414 {
415 copied_p = 1;
416 bm = rotate_bitmap_270 (bm);
417 if (mk)
418 mk = rotate_bitmap_270 (mk);
419 }
420
421 BRect r = bm->Bounds ();
422 if (r.Width () != desw || r.Height () != desh)
423 {
424 BRect n = BRect (0, 0, desw - 1, desh - 1);
425 BView vw (n, NULL, B_FOLLOW_NONE, 0);
426 BBitmap *dst = new BBitmap (n, bm->ColorSpace (), true);
427 if (dst->InitCheck () != B_OK)
428 if (bm->InitCheck () != B_OK)
429 gui_abort ("Failed to init bitmap for scale");
430 dst->AddChild (&vw);
431
432 if (!vw.LockLooper ())
433 gui_abort ("Failed to lock offscreen view for scale");
434
435 if (rot != 90 && rot != 270)
436 {
437 BAffineTransform tr;
438 tr.RotateBy (BPoint (desw / 2, desh / 2), rot * M_PI / 180.0);
439 vw.SetTransform (tr);
440 }
441
442 vw.MovePenTo (0, 0);
443 vw.DrawBitmap (bm, n);
444 if (mk)
445 BView_DrawMask ((void *) mk, (void *) &vw,
446 0, 0, mk->Bounds ().Width (),
447 mk->Bounds ().Height (),
448 0, 0, desw, desh, m_color);
449 vw.Sync ();
450 vw.RemoveSelf ();
451
452 if (copied_p)
453 delete bm;
454 if (copied_p && mk)
455 delete mk;
456 return dst;
457 }
458
459 return bm;
460}
461
462void
463BView_FillTriangle (void *view, int x1, int y1,
464 int x2, int y2, int x3, int y3)
465{
466 BView *vw = get_view (view);
467 vw->FillTriangle (BPoint (x1, y1), BPoint (x2, y2),
468 BPoint (x3, y3));
469}
470
471void
472BView_SetHighColorForVisibleBell (void *view, uint32_t color)
473{
474 BView *vw = (BView *) view;
475 rgb_color col;
476 rgb32_to_rgb_color (color, &col);
477
478 vw->SetHighColor (col);
479}
480
481void
482BView_FillRectangleForVisibleBell (void *view, int x, int y, int width, int height)
483{
484 BView *vw = (BView *) view;
485 BRect rect = BRect (x, y, x + width - 1, y + height - 1);
486
487 vw->FillRect (rect);
488}
diff --git a/src/haiku_font_support.cc b/src/haiku_font_support.cc
new file mode 100644
index 00000000000..9ac0400969b
--- /dev/null
+++ b/src/haiku_font_support.cc
@@ -0,0 +1,596 @@
1/* Haiku window system support. Hey, Emacs, this is -*- C++ -*-
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include <Font.h>
22#include <Rect.h>
23#include <AffineTransform.h>
24
25#include <cstring>
26#include <cmath>
27
28#include "haiku_support.h"
29
30/* Haiku doesn't expose font language data in BFont objects. Thus, we
31 select a few representative characters for each supported `:lang'
32 (currently Chinese, Korean and Japanese,) and test for those
33 instead. */
34
35static uint32_t language_code_points[MAX_LANGUAGE][4] =
36 {{20154, 20754, 22996, 0}, /* Chinese. */
37 {51312, 49440, 44544, 0}, /* Korean. */
38 {26085, 26412, 12371, 0}, /* Japanese. */};
39
40static void
41estimate_font_ascii (BFont *font, int *max_width,
42 int *min_width, int *avg_width)
43{
44 char ch[2];
45 bool tems[1];
46 int total = 0;
47 int count = 0;
48 int min = 0;
49 int max = 0;
50
51 std::memset (ch, 0, sizeof ch);
52 for (ch[0] = 32; ch[0] < 127; ++ch[0])
53 {
54 tems[0] = false;
55 font->GetHasGlyphs (ch, 1, tems);
56 if (tems[0])
57 {
58 int w = font->StringWidth (ch);
59 ++count;
60 total += w;
61
62 if (!min || min > w)
63 min = w;
64 if (max < w)
65 max = w;
66 }
67 }
68
69 *min_width = min;
70 *max_width = max;
71 *avg_width = total / count;
72}
73
74void
75BFont_close (void *font)
76{
77 if (font != (void *) be_fixed_font &&
78 font != (void *) be_plain_font &&
79 font != (void *) be_bold_font)
80 delete (BFont *) font;
81}
82
83void
84BFont_dat (void *font, int *px_size, int *min_width, int *max_width,
85 int *avg_width, int *height, int *space_width, int *ascent,
86 int *descent, int *underline_position, int *underline_thickness)
87{
88 BFont *ft = (BFont *) font;
89 struct font_height fheight;
90 bool have_space_p;
91
92 char atem[1];
93 bool otem[1];
94
95 ft->GetHeight (&fheight);
96 atem[0] = ' ';
97 otem[0] = false;
98 ft->GetHasGlyphs (atem, 1, otem);
99 have_space_p = otem[0];
100
101 estimate_font_ascii (ft, max_width, min_width, avg_width);
102 *ascent = std::lrint (fheight.ascent);
103 *descent = std::lrint (fheight.descent);
104 *height = *ascent + *descent;
105
106 *space_width = have_space_p ? ft->StringWidth (" ") : 0;
107
108 *px_size = std::lrint (ft->Size ());
109 *underline_position = 0;
110 *underline_thickness = 0;
111}
112
113/* Return non-null if FONT contains CHR, a Unicode code-point. */
114int
115BFont_have_char_p (void *font, int32_t chr)
116{
117 BFont *ft = (BFont *) font;
118 return ft->IncludesBlock (chr, chr);
119}
120
121/* Return non-null if font contains a block from BEG to END. */
122int
123BFont_have_char_block (void *font, int32_t beg, int32_t end)
124{
125 BFont *ft = (BFont *) font;
126 return ft->IncludesBlock (beg, end);
127}
128
129/* Compute bounds for MB_STR, a character in multibyte encoding,
130 used with font. The width (in pixels) is returned in ADVANCE,
131 the left bearing in LB, and the right bearing in RB. */
132void
133BFont_char_bounds (void *font, const char *mb_str, int *advance,
134 int *lb, int *rb)
135{
136 BFont *ft = (BFont *) font;
137 edge_info edge_info;
138 float size, escapement;
139 size = ft->Size ();
140
141 ft->GetEdges (mb_str, 1, &edge_info);
142 ft->GetEscapements (mb_str, 1, &escapement);
143 *advance = std::lrint (escapement * size);
144 *lb = std::lrint (edge_info.left * size);
145 *rb = *advance + std::lrint (edge_info.right * size);
146}
147
148/* The same, but for a variable amount of chars. */
149void
150BFont_nchar_bounds (void *font, const char *mb_str, int *advance,
151 int *lb, int *rb, int32_t n)
152{
153 BFont *ft = (BFont *) font;
154 edge_info edge_info[n];
155 float size;
156 float escapement[n];
157
158 size = ft->Size ();
159
160 ft->GetEdges (mb_str, n, edge_info);
161 ft->GetEscapements (mb_str, n, (float *) escapement);
162
163 for (int32_t i = 0; i < n; ++i)
164 {
165 advance[i] = std::lrint (escapement[i] * size);
166 lb[i] = advance[i] - std::lrint (edge_info[i].left * size);
167 rb[i] = advance[i] + std::lrint (edge_info[i].right * size);
168 }
169}
170
171static void
172font_style_to_flags (char *st, struct haiku_font_pattern *pattern)
173{
174 char *style = strdup (st);
175 char *token;
176 pattern->weight = -1;
177 pattern->width = NO_WIDTH;
178 pattern->slant = NO_SLANT;
179 int tok = 0;
180
181 while ((token = std::strtok (!tok ? style : NULL, " ")) && tok < 3)
182 {
183 if (token && !strcmp (token, "Thin"))
184 pattern->weight = HAIKU_THIN;
185 else if (token && !strcmp (token, "UltraLight"))
186 pattern->weight = HAIKU_ULTRALIGHT;
187 else if (token && !strcmp (token, "ExtraLight"))
188 pattern->weight = HAIKU_EXTRALIGHT;
189 else if (token && !strcmp (token, "Light"))
190 pattern->weight = HAIKU_LIGHT;
191 else if (token && !strcmp (token, "SemiLight"))
192 pattern->weight = HAIKU_SEMI_LIGHT;
193 else if (token && !strcmp (token, "Regular"))
194 {
195 if (pattern->slant == NO_SLANT)
196 pattern->slant = SLANT_REGULAR;
197
198 if (pattern->width == NO_WIDTH)
199 pattern->width = NORMAL_WIDTH;
200
201 if (pattern->weight == -1)
202 pattern->weight = HAIKU_REGULAR;
203 }
204 else if (token && !strcmp (token, "SemiBold"))
205 pattern->weight = HAIKU_SEMI_BOLD;
206 else if (token && !strcmp (token, "Bold"))
207 pattern->weight = HAIKU_BOLD;
208 else if (token && (!strcmp (token, "ExtraBold") ||
209 /* This has actually been seen in the wild. */
210 !strcmp (token, "Extrabold")))
211 pattern->weight = HAIKU_EXTRA_BOLD;
212 else if (token && !strcmp (token, "UltraBold"))
213 pattern->weight = HAIKU_ULTRA_BOLD;
214 else if (token && !strcmp (token, "Book"))
215 pattern->weight = HAIKU_BOOK;
216 else if (token && !strcmp (token, "Heavy"))
217 pattern->weight = HAIKU_HEAVY;
218 else if (token && !strcmp (token, "UltraHeavy"))
219 pattern->weight = HAIKU_ULTRA_HEAVY;
220 else if (token && !strcmp (token, "Black"))
221 pattern->weight = HAIKU_BLACK;
222 else if (token && !strcmp (token, "Medium"))
223 pattern->weight = HAIKU_MEDIUM;
224 else if (token && !strcmp (token, "Oblique"))
225 pattern->slant = SLANT_OBLIQUE;
226 else if (token && !strcmp (token, "Italic"))
227 pattern->slant = SLANT_ITALIC;
228 else if (token && !strcmp (token, "UltraCondensed"))
229 pattern->width = ULTRA_CONDENSED;
230 else if (token && !strcmp (token, "ExtraCondensed"))
231 pattern->width = EXTRA_CONDENSED;
232 else if (token && !strcmp (token, "Condensed"))
233 pattern->width = CONDENSED;
234 else if (token && !strcmp (token, "SemiCondensed"))
235 pattern->width = SEMI_CONDENSED;
236 else if (token && !strcmp (token, "SemiExpanded"))
237 pattern->width = SEMI_EXPANDED;
238 else if (token && !strcmp (token, "Expanded"))
239 pattern->width = EXPANDED;
240 else if (token && !strcmp (token, "ExtraExpanded"))
241 pattern->width = EXTRA_EXPANDED;
242 else if (token && !strcmp (token, "UltraExpanded"))
243 pattern->width = ULTRA_EXPANDED;
244 else
245 {
246 tok = 1000;
247 break;
248 }
249 tok++;
250 }
251
252 if (pattern->weight != -1)
253 pattern->specified |= FSPEC_WEIGHT;
254 if (pattern->slant != NO_SLANT)
255 pattern->specified |= FSPEC_SLANT;
256 if (pattern->width != NO_WIDTH)
257 pattern->specified |= FSPEC_WIDTH;
258
259 if (tok > 3)
260 {
261 pattern->specified &= ~FSPEC_SLANT;
262 pattern->specified &= ~FSPEC_WEIGHT;
263 pattern->specified &= ~FSPEC_WIDTH;
264 pattern->specified |= FSPEC_STYLE;
265 std::strncpy ((char *) &pattern->style, st,
266 sizeof pattern->style - 1);
267 }
268
269 free (style);
270}
271
272static bool
273font_check_wanted_chars (struct haiku_font_pattern *pattern, font_family family,
274 char *style)
275{
276 BFont ft;
277
278 if (ft.SetFamilyAndStyle (family, style) != B_OK)
279 return false;
280
281 for (int i = 0; i < pattern->want_chars_len; ++i)
282 if (!ft.IncludesBlock (pattern->wanted_chars[i],
283 pattern->wanted_chars[i]))
284 return false;
285
286 return true;
287}
288
289static bool
290font_check_one_of (struct haiku_font_pattern *pattern, font_family family,
291 char *style)
292{
293 BFont ft;
294
295 if (ft.SetFamilyAndStyle (family, style) != B_OK)
296 return false;
297
298 for (int i = 0; i < pattern->need_one_of_len; ++i)
299 if (ft.IncludesBlock (pattern->need_one_of[i],
300 pattern->need_one_of[i]))
301 return true;
302
303 return false;
304}
305
306static bool
307font_check_language (struct haiku_font_pattern *pattern, font_family family,
308 char *style)
309{
310 BFont ft;
311
312 if (ft.SetFamilyAndStyle (family, style) != B_OK)
313 return false;
314
315 if (pattern->language == MAX_LANGUAGE)
316 return false;
317
318 for (uint32_t *ch = (uint32_t *)
319 &language_code_points[pattern->language]; *ch; ch++)
320 if (!ft.IncludesBlock (*ch, *ch))
321 return false;
322
323 return true;
324}
325
326static bool
327font_family_style_matches_p (font_family family, char *style, uint32_t flags,
328 struct haiku_font_pattern *pattern,
329 int ignore_flags_p = 0)
330{
331 struct haiku_font_pattern m;
332 m.specified = 0;
333
334 if (style)
335 font_style_to_flags (style, &m);
336
337 if ((pattern->specified & FSPEC_FAMILY) &&
338 strcmp ((char *) &pattern->family, family))
339 return false;
340
341 if (!ignore_flags_p && (pattern->specified & FSPEC_SPACING) &&
342 !(pattern->mono_spacing_p) != !(flags & B_IS_FIXED))
343 return false;
344
345 if (pattern->specified & FSPEC_STYLE)
346 return style && !strcmp (style, pattern->style);
347
348 if ((pattern->specified & FSPEC_WEIGHT)
349 && (pattern->weight
350 != ((m.specified & FSPEC_WEIGHT) ? m.weight : HAIKU_REGULAR)))
351 return false;
352
353 if ((pattern->specified & FSPEC_SLANT)
354 && (pattern->slant
355 != ((m.specified & FSPEC_SLANT) ? m.slant : SLANT_REGULAR)))
356 return false;
357
358 if ((pattern->specified & FSPEC_WANTED)
359 && !font_check_wanted_chars (pattern, family, style))
360 return false;
361
362 if ((pattern->specified & FSPEC_WIDTH)
363 && (pattern->width !=
364 ((m.specified & FSPEC_WIDTH) ? m.width : NORMAL_WIDTH)))
365 return false;
366
367 if ((pattern->specified & FSPEC_NEED_ONE_OF)
368 && !font_check_one_of (pattern, family, style))
369 return false;
370
371 if ((pattern->specified & FSPEC_LANGUAGE)
372 && !font_check_language (pattern, family, style))
373 return false;
374
375 return true;
376}
377
378static void
379haiku_font_fill_pattern (struct haiku_font_pattern *pattern,
380 font_family family, char *style,
381 uint32_t flags)
382{
383 if (style)
384 font_style_to_flags (style, pattern);
385
386 pattern->specified |= FSPEC_FAMILY;
387 std::strncpy (pattern->family, family,
388 sizeof pattern->family - 1);
389 pattern->specified |= FSPEC_SPACING;
390 pattern->mono_spacing_p = flags & B_IS_FIXED;
391}
392
393/* Delete every element of the font pattern PT. */
394void
395haiku_font_pattern_free (struct haiku_font_pattern *pt)
396{
397 struct haiku_font_pattern *tem = pt;
398 while (tem)
399 {
400 struct haiku_font_pattern *t = tem;
401 tem = t->next;
402 delete t;
403 }
404}
405
406/* Find all fonts matching the font pattern PT. */
407struct haiku_font_pattern *
408BFont_find (struct haiku_font_pattern *pt)
409{
410 struct haiku_font_pattern *r = NULL;
411 font_family name;
412 font_style sname;
413 uint32 flags;
414 int sty_count;
415 int fam_count = count_font_families ();
416
417 for (int fi = 0; fi < fam_count; ++fi)
418 {
419 if (get_font_family (fi, &name, &flags) == B_OK)
420 {
421 sty_count = count_font_styles (name);
422 if (!sty_count &&
423 font_family_style_matches_p (name, NULL, flags, pt))
424 {
425 struct haiku_font_pattern *p = new struct haiku_font_pattern;
426 p->specified = 0;
427 p->oblique_seen_p = 1;
428 haiku_font_fill_pattern (p, name, NULL, flags);
429 p->next = r;
430 if (p->next)
431 p->next->last = p;
432 p->last = NULL;
433 p->next_family = r;
434 r = p;
435 }
436 else if (sty_count)
437 {
438 for (int si = 0; si < sty_count; ++si)
439 {
440 int oblique_seen_p = 0;
441 struct haiku_font_pattern *head = r;
442 struct haiku_font_pattern *p = NULL;
443
444 if (get_font_style (name, si, &sname, &flags) == B_OK)
445 {
446 if (font_family_style_matches_p (name, (char *) &sname, flags, pt))
447 {
448 p = new struct haiku_font_pattern;
449 p->specified = 0;
450 haiku_font_fill_pattern (p, name, (char *) &sname, flags);
451 if (p->specified & FSPEC_SLANT &&
452 ((p->slant == SLANT_OBLIQUE) || (p->slant == SLANT_ITALIC)))
453 oblique_seen_p = 1;
454
455 p->next = r;
456 if (p->next)
457 p->next->last = p;
458 r = p;
459 p->next_family = head;
460 }
461 }
462
463 if (p)
464 p->last = NULL;
465
466 for (; head; head = head->last)
467 {
468 head->oblique_seen_p = oblique_seen_p;
469 }
470 }
471 }
472 }
473 }
474
475 /* There's a very good chance that this result will get cached if no
476 slant is specified. Thus, we look through each font that hasn't
477 seen an oblique style, and add one. */
478
479 if (!(pt->specified & FSPEC_SLANT))
480 {
481 /* r->last is invalid from here onwards. */
482 for (struct haiku_font_pattern *p = r; p;)
483 {
484 if (!p->oblique_seen_p)
485 {
486 struct haiku_font_pattern *n = new haiku_font_pattern;
487 *n = *p;
488 n->slant = SLANT_OBLIQUE;
489 p->next = n;
490 p = p->next_family;
491 }
492 else
493 p = p->next_family;
494 }
495 }
496
497 return r;
498}
499
500/* Find and open a font matching the pattern PAT, which must have its
501 family set. */
502int
503BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size)
504{
505 int sty_count;
506 font_family name;
507 font_style sname;
508 uint32 flags = 0;
509 if (!(pat->specified & FSPEC_FAMILY))
510 return 1;
511 strncpy (name, pat->family, sizeof name - 1);
512 sty_count = count_font_styles (name);
513
514 if (!sty_count &&
515 font_family_style_matches_p (name, NULL, flags, pat, 1))
516 {
517 BFont *ft = new BFont;
518 if (ft->SetFamilyAndStyle (name, NULL) != B_OK)
519 {
520 delete ft;
521 return 1;
522 }
523 ft->SetSize (size);
524 ft->SetEncoding (B_UNICODE_UTF8);
525 ft->SetSpacing (B_BITMAP_SPACING);
526 *font = (void *) ft;
527 return 0;
528 }
529 else if (sty_count)
530 {
531 for (int si = 0; si < sty_count; ++si)
532 {
533 if (get_font_style (name, si, &sname, &flags) == B_OK &&
534 font_family_style_matches_p (name, (char *) &sname, flags, pat))
535 {
536 BFont *ft = new BFont;
537 if (ft->SetFamilyAndStyle (name, sname) != B_OK)
538 {
539 delete ft;
540 return 1;
541 }
542 ft->SetSize (size);
543 ft->SetEncoding (B_UNICODE_UTF8);
544 ft->SetSpacing (B_BITMAP_SPACING);
545 *font = (void *) ft;
546 return 0;
547 }
548 }
549 }
550
551 if (pat->specified & FSPEC_SLANT && pat->slant == SLANT_OBLIQUE)
552 {
553 struct haiku_font_pattern copy = *pat;
554 copy.slant = SLANT_REGULAR;
555 int code = BFont_open_pattern (&copy, font, size);
556 if (code)
557 return code;
558 BFont *ft = (BFont *) *font;
559 /* XXX Font measurements don't respect shear. Haiku bug?
560 This apparently worked in BeOS.
561 ft->SetShear (100.0); */
562 ft->SetFace (B_ITALIC_FACE);
563 return 0;
564 }
565
566 return 1;
567}
568
569/* Query the family of the default fixed font. */
570void
571BFont_populate_fixed_family (struct haiku_font_pattern *ptn)
572{
573 font_family f;
574 font_style s;
575 be_fixed_font->GetFamilyAndStyle (&f, &s);
576
577 ptn->specified |= FSPEC_FAMILY;
578 strncpy (ptn->family, f, sizeof ptn->family - 1);
579}
580
581void
582BFont_populate_plain_family (struct haiku_font_pattern *ptn)
583{
584 font_family f;
585 font_style s;
586 be_plain_font->GetFamilyAndStyle (&f, &s);
587
588 ptn->specified |= FSPEC_FAMILY;
589 strncpy (ptn->family, f, sizeof ptn->family - 1);
590}
591
592int
593BFont_string_width (void *font, const char *utf8)
594{
595 return ((BFont *) font)->StringWidth (utf8);
596}
diff --git a/src/haiku_io.c b/src/haiku_io.c
new file mode 100644
index 00000000000..c152d9b086a
--- /dev/null
+++ b/src/haiku_io.c
@@ -0,0 +1,207 @@
1/* Haiku window system support.
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include <signal.h>
22#include <stdio.h>
23#include <pthread.h>
24#include <unistd.h>
25
26#include <OS.h>
27
28#include "haiku_support.h"
29#include "lisp.h"
30#include "haikuterm.h"
31#include "blockinput.h"
32
33#define PORT_CAP 1200
34
35/* The port used to send messages from the application thread to
36 Emacs. */
37port_id port_application_to_emacs;
38
39void
40haiku_io_init (void)
41{
42 port_application_to_emacs = create_port (PORT_CAP, "application emacs port");
43}
44
45static ssize_t
46haiku_len (enum haiku_event_type type)
47{
48 switch (type)
49 {
50 case QUIT_REQUESTED:
51 return sizeof (struct haiku_quit_requested_event);
52 case FRAME_RESIZED:
53 return sizeof (struct haiku_resize_event);
54 case FRAME_EXPOSED:
55 return sizeof (struct haiku_expose_event);
56 case KEY_DOWN:
57 case KEY_UP:
58 return sizeof (struct haiku_key_event);
59 case ACTIVATION:
60 return sizeof (struct haiku_activation_event);
61 case MOUSE_MOTION:
62 return sizeof (struct haiku_mouse_motion_event);
63 case BUTTON_DOWN:
64 case BUTTON_UP:
65 return sizeof (struct haiku_button_event);
66 case ICONIFICATION:
67 return sizeof (struct haiku_iconification_event);
68 case MOVE_EVENT:
69 return sizeof (struct haiku_move_event);
70 case SCROLL_BAR_VALUE_EVENT:
71 return sizeof (struct haiku_scroll_bar_value_event);
72 case SCROLL_BAR_DRAG_EVENT:
73 return sizeof (struct haiku_scroll_bar_drag_event);
74 case WHEEL_MOVE_EVENT:
75 return sizeof (struct haiku_wheel_move_event);
76 case MENU_BAR_RESIZE:
77 return sizeof (struct haiku_menu_bar_resize_event);
78 case MENU_BAR_OPEN:
79 case MENU_BAR_CLOSE:
80 return sizeof (struct haiku_menu_bar_state_event);
81 case MENU_BAR_SELECT_EVENT:
82 return sizeof (struct haiku_menu_bar_select_event);
83 case FILE_PANEL_EVENT:
84 return sizeof (struct haiku_file_panel_event);
85 case MENU_BAR_HELP_EVENT:
86 return sizeof (struct haiku_menu_bar_help_event);
87 case ZOOM_EVENT:
88 return sizeof (struct haiku_zoom_event);
89 case REFS_EVENT:
90 return sizeof (struct haiku_refs_event);
91 case APP_QUIT_REQUESTED_EVENT:
92 return sizeof (struct haiku_app_quit_requested_event);
93 }
94
95 emacs_abort ();
96}
97
98/* Read the size of the next message into len, returning -1 if the
99 query fails or there is no next message. */
100void
101haiku_read_size (ssize_t *len)
102{
103 port_id from = port_application_to_emacs;
104 ssize_t size;
105
106 size = port_buffer_size_etc (from, B_TIMEOUT, 0);
107
108 if (size < B_OK)
109 *len = -1;
110 else
111 *len = size;
112}
113
114/* Read the next message into BUF, putting its type into TYPE,
115 assuming the message is at most LEN long. Return 0 if successful
116 and -1 if the read fails. */
117int
118haiku_read (enum haiku_event_type *type, void *buf, ssize_t len)
119{
120 int32 typ;
121 port_id from = port_application_to_emacs;
122
123 if (read_port (from, &typ, buf, len) < B_OK)
124 return -1;
125
126 *type = (enum haiku_event_type) typ;
127 eassert (len >= haiku_len (typ));
128 return 0;
129}
130
131/* The same as haiku_read, but time out after TIMEOUT microseconds.
132 Input is blocked when an attempt to read is in progress. */
133int
134haiku_read_with_timeout (enum haiku_event_type *type, void *buf, ssize_t len,
135 time_t timeout)
136{
137 int32 typ;
138 port_id from = port_application_to_emacs;
139
140 block_input ();
141 if (read_port_etc (from, &typ, buf, len,
142 B_TIMEOUT, (bigtime_t) timeout) < B_OK)
143 {
144 unblock_input ();
145 return -1;
146 }
147 unblock_input ();
148 *type = (enum haiku_event_type) typ;
149 eassert (len >= haiku_len (typ));
150 return 0;
151}
152
153/* Write a message with type TYPE into BUF. */
154int
155haiku_write (enum haiku_event_type type, void *buf)
156{
157 port_id to = port_application_to_emacs;
158
159 if (write_port (to, (int32_t) type, buf, haiku_len (type)) < B_OK)
160 return -1;
161
162 kill (getpid (), SIGPOLL);
163
164 return 0;
165}
166
167int
168haiku_write_without_signal (enum haiku_event_type type, void *buf)
169{
170 port_id to = port_application_to_emacs;
171
172 if (write_port (to, (int32_t) type, buf, haiku_len (type)) < B_OK)
173 return -1;
174
175 return 0;
176}
177
178void
179haiku_io_init_in_app_thread (void)
180{
181 sigset_t set;
182 sigfillset (&set);
183
184 if (pthread_sigmask (SIG_BLOCK, &set, NULL))
185 perror ("pthread_sigmask");
186}
187
188/* Record an unwind protect from C++ code. */
189void
190record_c_unwind_protect_from_cxx (void (*fn) (void *), void *r)
191{
192 record_unwind_protect_ptr (fn, r);
193}
194
195/* SPECPDL_IDX that is safe from C++ code. */
196ptrdiff_t
197c_specpdl_idx_from_cxx (void)
198{
199 return SPECPDL_INDEX ();
200}
201
202/* unbind_to (IDX, Qnil), but safe from C++ code. */
203void
204c_unbind_to_nil_from_cxx (ptrdiff_t idx)
205{
206 unbind_to (idx, Qnil);
207}
diff --git a/src/haiku_select.cc b/src/haiku_select.cc
new file mode 100644
index 00000000000..8d345ca6617
--- /dev/null
+++ b/src/haiku_select.cc
@@ -0,0 +1,155 @@
1/* Haiku window system selection support. Hey Emacs, this is -*- C++ -*-
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include <Clipboard.h>
22
23#include <cstdlib>
24#include <cstring>
25
26#include "haikuselect.h"
27
28
29static BClipboard *primary = NULL;
30static BClipboard *secondary = NULL;
31static BClipboard *system_clipboard = NULL;
32
33int selection_state_flag;
34
35static char *
36BClipboard_find_data (BClipboard *cb, const char *type, ssize_t *len)
37{
38 if (!cb->Lock ())
39 return 0;
40
41 BMessage *dat = cb->Data ();
42 if (!dat)
43 {
44 cb->Unlock ();
45 return 0;
46 }
47
48 const char *ptr;
49 ssize_t bt;
50 dat->FindData (type, B_MIME_TYPE, (const void **) &ptr, &bt);
51
52 if (!ptr)
53 {
54 cb->Unlock ();
55 return NULL;
56 }
57
58 if (len)
59 *len = bt;
60
61 cb->Unlock ();
62
63 return strndup (ptr, bt);
64}
65
66static void
67BClipboard_set_data (BClipboard *cb, const char *type, const char *dat,
68 ssize_t len)
69{
70 if (!cb->Lock ())
71 return;
72 cb->Clear ();
73 BMessage *mdat = cb->Data ();
74 if (!mdat)
75 {
76 cb->Unlock ();
77 return;
78 }
79
80 if (dat)
81 mdat->AddData (type, B_MIME_TYPE, dat, len);
82 cb->Commit ();
83 cb->Unlock ();
84}
85
86char *
87BClipboard_find_system_data (const char *type, ssize_t *len)
88{
89 if (!system_clipboard)
90 return 0;
91
92 return BClipboard_find_data (system_clipboard, type, len);
93}
94
95char *
96BClipboard_find_primary_selection_data (const char *type, ssize_t *len)
97{
98 if (!primary)
99 return 0;
100
101 return BClipboard_find_data (primary, type, len);
102}
103
104char *
105BClipboard_find_secondary_selection_data (const char *type, ssize_t *len)
106{
107 if (!secondary)
108 return 0;
109
110 return BClipboard_find_data (secondary, type, len);
111}
112
113void
114BClipboard_set_system_data (const char *type, const char *data,
115 ssize_t len)
116{
117 if (!system_clipboard)
118 return;
119
120 BClipboard_set_data (system_clipboard, type, data, len);
121}
122
123void
124BClipboard_set_primary_selection_data (const char *type, const char *data,
125 ssize_t len)
126{
127 if (!primary)
128 return;
129
130 BClipboard_set_data (primary, type, data, len);
131}
132
133void
134BClipboard_set_secondary_selection_data (const char *type, const char *data,
135 ssize_t len)
136{
137 if (!secondary)
138 return;
139
140 BClipboard_set_data (secondary, type, data, len);
141}
142
143void
144BClipboard_free_data (void *ptr)
145{
146 std::free (ptr);
147}
148
149void
150init_haiku_select (void)
151{
152 system_clipboard = new BClipboard ("system");
153 primary = new BClipboard ("primary");
154 secondary = new BClipboard ("secondary");
155}
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
new file mode 100644
index 00000000000..99d4ee79140
--- /dev/null
+++ b/src/haiku_support.cc
@@ -0,0 +1,2930 @@
1/* Haiku window system support. Hey, Emacs, this is -*- C++ -*-
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include <app/Application.h>
22#include <app/Cursor.h>
23#include <app/Messenger.h>
24
25#include <interface/GraphicsDefs.h>
26#include <interface/InterfaceDefs.h>
27#include <interface/Bitmap.h>
28#include <interface/Window.h>
29#include <interface/View.h>
30#include <interface/Screen.h>
31#include <interface/ScrollBar.h>
32#include <interface/Region.h>
33#include <interface/Menu.h>
34#include <interface/MenuItem.h>
35#include <interface/PopUpMenu.h>
36#include <interface/MenuBar.h>
37#include <interface/Alert.h>
38#include <interface/Button.h>
39
40#include <locale/UnicodeChar.h>
41
42#include <game/WindowScreen.h>
43#include <game/DirectWindow.h>
44
45#include <storage/Entry.h>
46#include <storage/Path.h>
47#include <storage/FilePanel.h>
48#include <storage/AppFileInfo.h>
49#include <storage/Path.h>
50#include <storage/PathFinder.h>
51
52#include <support/Beep.h>
53#include <support/DataIO.h>
54#include <support/Locker.h>
55
56#include <translation/TranslatorRoster.h>
57#include <translation/TranslationDefs.h>
58#include <translation/TranslationUtils.h>
59
60#include <kernel/OS.h>
61#include <kernel/fs_attr.h>
62#include <kernel/scheduler.h>
63
64#include <private/interface/ToolTip.h>
65
66#include <cmath>
67#include <cstring>
68#include <cstdint>
69#include <cstdio>
70#include <csignal>
71#include <cfloat>
72
73#include <pthread.h>
74
75#ifdef USE_BE_CAIRO
76#include <cairo.h>
77#endif
78
79#include "haiku_support.h"
80
81#define SCROLL_BAR_UPDATE 3000
82
83static color_space dpy_color_space = B_NO_COLOR_SPACE;
84static key_map *key_map = NULL;
85static char *key_chars = NULL;
86static BLocker key_map_lock;
87
88extern "C"
89{
90 extern _Noreturn void emacs_abort (void);
91 /* Also defined in haikuterm.h. */
92 extern void be_app_quit (void);
93}
94
95static thread_id app_thread;
96
97_Noreturn void
98gui_abort (const char *msg)
99{
100 fprintf (stderr, "Abort in GUI code: %s\n", msg);
101 fprintf (stderr, "Under Haiku, Emacs cannot recover from errors in GUI code\n");
102 fprintf (stderr, "App Server disconnects usually manifest as bitmap "
103 "initialization failures or lock failures.");
104 emacs_abort ();
105}
106
107#ifdef USE_BE_CAIRO
108static cairo_format_t
109cairo_format_from_color_space (color_space space)
110{
111 switch (space)
112 {
113 case B_RGBA32:
114 return CAIRO_FORMAT_ARGB32;
115 case B_RGB32:
116 return CAIRO_FORMAT_RGB24;
117 case B_RGB16:
118 return CAIRO_FORMAT_RGB16_565;
119 case B_GRAY8:
120 return CAIRO_FORMAT_A8;
121 case B_GRAY1:
122 return CAIRO_FORMAT_A1;
123 default:
124 gui_abort ("Unsupported color space");
125 }
126}
127#endif
128
129static void
130map_key (char *chars, int32 offset, uint32_t *c)
131{
132 int size = chars[offset++];
133 switch (size)
134 {
135 case 0:
136 break;
137
138 case 1:
139 *c = chars[offset];
140 break;
141
142 default:
143 {
144 char str[5];
145 int i = (size <= 4) ? size : 4;
146 strncpy (str, &(chars[offset]), i);
147 str[i] = '0';
148 *c = BUnicodeChar::FromUTF8 ((char *) &str);
149 break;
150 }
151 }
152}
153
154static void
155map_shift (uint32_t kc, uint32_t *ch)
156{
157 if (!key_map_lock.Lock ())
158 gui_abort ("Failed to lock keymap");
159 if (!key_map)
160 get_key_map (&key_map, &key_chars);
161 if (!key_map)
162 return;
163 if (kc >= 128)
164 return;
165
166 int32_t m = key_map->shift_map[kc];
167 map_key (key_chars, m, ch);
168 key_map_lock.Unlock ();
169}
170
171static void
172map_normal (uint32_t kc, uint32_t *ch)
173{
174 if (!key_map_lock.Lock ())
175 gui_abort ("Failed to lock keymap");
176 if (!key_map)
177 get_key_map (&key_map, &key_chars);
178 if (!key_map)
179 return;
180 if (kc >= 128)
181 return;
182
183 int32_t m = key_map->normal_map[kc];
184 map_key (key_chars, m, ch);
185 key_map_lock.Unlock ();
186}
187
188class Emacs : public BApplication
189{
190public:
191 Emacs () : BApplication ("application/x-vnd.GNU-emacs")
192 {
193 }
194
195 void
196 AboutRequested (void)
197 {
198 BAlert *about = new BAlert (PACKAGE_NAME,
199 PACKAGE_STRING
200 "\nThe extensible, self-documenting, real-time display editor.",
201 "Close");
202 about->Go ();
203 }
204
205 bool
206 QuitRequested (void)
207 {
208 struct haiku_app_quit_requested_event rq;
209 haiku_write (APP_QUIT_REQUESTED_EVENT, &rq);
210 return 0;
211 }
212
213 void
214 RefsReceived (BMessage *msg)
215 {
216 struct haiku_refs_event rq;
217 entry_ref ref;
218 BEntry entry;
219 BPath path;
220 int32 cookie = 0;
221 int32 x, y;
222 void *window;
223
224 if ((msg->FindPointer ("window", 0, &window) != B_OK)
225 || (msg->FindInt32 ("x", 0, &x) != B_OK)
226 || (msg->FindInt32 ("y", 0, &y) != B_OK))
227 return;
228
229 rq.window = window;
230 rq.x = x;
231 rq.y = y;
232
233 while (msg->FindRef ("refs", cookie++, &ref) == B_OK)
234 {
235 if (entry.SetTo (&ref, 0) == B_OK
236 && entry.GetPath (&path) == B_OK)
237 {
238 rq.ref = strdup (path.Path ());
239 haiku_write (REFS_EVENT, &rq);
240 }
241 }
242 }
243};
244
245class EmacsWindow : public BDirectWindow
246{
247public:
248 struct child_frame
249 {
250 struct child_frame *next;
251 int xoff, yoff;
252 EmacsWindow *window;
253 } *subset_windows = NULL;
254
255 EmacsWindow *parent = NULL;
256 BRect pre_fullscreen_rect;
257 BRect pre_zoom_rect;
258 int x_before_zoom = INT_MIN;
259 int y_before_zoom = INT_MIN;
260 int fullscreen_p = 0;
261 int zoomed_p = 0;
262 int shown_flag = 0;
263
264#ifdef USE_BE_CAIRO
265 BLocker surface_lock;
266 cairo_surface_t *cr_surface = NULL;
267#endif
268
269 EmacsWindow () : BDirectWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK,
270 B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS)
271 {
272
273 }
274
275 ~EmacsWindow ()
276 {
277 struct child_frame *next;
278 for (struct child_frame *f = subset_windows; f; f = next)
279 {
280 f->window->Unparent ();
281 next = f->next;
282 delete f;
283 }
284
285 if (this->parent)
286 UnparentAndUnlink ();
287
288#ifdef USE_BE_CAIRO
289 if (!surface_lock.Lock ())
290 gui_abort ("Failed to lock cairo surface");
291 if (cr_surface)
292 {
293 cairo_surface_destroy (cr_surface);
294 cr_surface = NULL;
295 }
296 surface_lock.Unlock ();
297#endif
298 }
299
300 void
301 UpwardsSubset (EmacsWindow *w)
302 {
303 for (; w; w = w->parent)
304 AddToSubset (w);
305 }
306
307 void
308 UpwardsSubsetChildren (EmacsWindow *w)
309 {
310 UpwardsSubset (w);
311 for (struct child_frame *f = subset_windows; f;
312 f = f->next)
313 f->window->UpwardsSubsetChildren (w);
314 }
315
316 void
317 UpwardsUnSubset (EmacsWindow *w)
318 {
319 for (; w; w = w->parent)
320 RemoveFromSubset (w);
321 }
322
323 void
324 UpwardsUnSubsetChildren (EmacsWindow *w)
325 {
326 UpwardsUnSubset (w);
327 for (struct child_frame *f = subset_windows; f;
328 f = f->next)
329 f->window->UpwardsUnSubsetChildren (w);
330 }
331
332 void
333 Unparent (void)
334 {
335 this->SetFeel (B_NORMAL_WINDOW_FEEL);
336 UpwardsUnSubsetChildren (parent);
337 this->RemoveFromSubset (this);
338 this->parent = NULL;
339 if (fullscreen_p)
340 {
341 fullscreen_p = 0;
342 MakeFullscreen (1);
343 }
344 }
345
346 void
347 UnparentAndUnlink (void)
348 {
349 this->parent->UnlinkChild (this);
350 this->Unparent ();
351 }
352
353 void
354 UnlinkChild (EmacsWindow *window)
355 {
356 struct child_frame *last = NULL;
357 struct child_frame *tem = subset_windows;
358
359 for (; tem; last = tem, tem = tem->next)
360 {
361 if (tem->window == window)
362 {
363 if (last)
364 last->next = tem->next;
365 if (tem == subset_windows)
366 subset_windows = NULL;
367 delete tem;
368 return;
369 }
370 }
371
372 gui_abort ("Failed to unlink child frame");
373 }
374
375 void
376 ParentTo (EmacsWindow *window)
377 {
378 if (this->parent)
379 UnparentAndUnlink ();
380
381 this->parent = window;
382 this->SetFeel (B_FLOATING_SUBSET_WINDOW_FEEL);
383 this->AddToSubset (this);
384 if (!IsHidden () && this->parent)
385 UpwardsSubsetChildren (parent);
386 if (fullscreen_p)
387 {
388 fullscreen_p = 0;
389 MakeFullscreen (1);
390 }
391 this->Sync ();
392 window->LinkChild (this);
393 }
394
395 void
396 LinkChild (EmacsWindow *window)
397 {
398 struct child_frame *f = new struct child_frame;
399
400 for (struct child_frame *f = subset_windows; f;
401 f = f->next)
402 {
403 if (window == f->window)
404 gui_abort ("Trying to link a child frame that is already present");
405 }
406
407 f->window = window;
408 f->next = subset_windows;
409 f->xoff = -1;
410 f->yoff = -1;
411
412 subset_windows = f;
413 }
414
415 void
416 DoMove (struct child_frame *f)
417 {
418 BRect frame = this->Frame ();
419 f->window->MoveTo (frame.left + f->xoff,
420 frame.top + f->yoff);
421 this->Sync ();
422 }
423
424 void
425 DoUpdateWorkspace (struct child_frame *f)
426 {
427 f->window->SetWorkspaces (this->Workspaces ());
428 }
429
430 void
431 MoveChild (EmacsWindow *window, int xoff, int yoff,
432 int weak_p)
433 {
434 for (struct child_frame *f = subset_windows; f;
435 f = f->next)
436 {
437 if (window == f->window)
438 {
439 f->xoff = xoff;
440 f->yoff = yoff;
441 if (!weak_p)
442 DoMove (f);
443 return;
444 }
445 }
446
447 gui_abort ("Trying to move a child frame that doesn't exist");
448 }
449
450 void
451 WindowActivated (bool activated)
452 {
453 struct haiku_activation_event rq;
454 rq.window = this;
455 rq.activated_p = activated;
456
457 haiku_write (ACTIVATION, &rq);
458 }
459
460 void
461 DirectConnected (direct_buffer_info *info)
462 {
463#ifdef USE_BE_CAIRO
464 if (!surface_lock.Lock ())
465 gui_abort ("Failed to lock window direct cr surface");
466 if (cr_surface)
467 {
468 cairo_surface_destroy (cr_surface);
469 cr_surface = NULL;
470 }
471
472 if (info->buffer_state != B_DIRECT_STOP)
473 {
474 int left, top, right, bottom;
475 left = info->clip_bounds.left;
476 top = info->clip_bounds.top;
477 right = info->clip_bounds.right;
478 bottom = info->clip_bounds.bottom;
479
480 unsigned char *bits = (unsigned char *) info->bits;
481 if ((info->bits_per_pixel % 8) == 0)
482 {
483 bits += info->bytes_per_row * top;
484 bits += (left * info->bits_per_pixel / 8);
485 cr_surface = cairo_image_surface_create_for_data
486 (bits,
487 cairo_format_from_color_space (info->pixel_format),
488 right - left + 1,
489 bottom - top + 1,
490 info->bytes_per_row);
491 }
492 }
493 surface_lock.Unlock ();
494#endif
495 }
496
497 void
498 MessageReceived (BMessage *msg)
499 {
500 int32 old_what = 0;
501
502 if (msg->WasDropped ())
503 {
504 entry_ref ref;
505 BPoint whereto;
506
507 if (msg->FindRef ("refs", &ref) == B_OK)
508 {
509 msg->what = B_REFS_RECEIVED;
510 msg->AddPointer ("window", this);
511 if (msg->FindPoint ("_drop_point_", &whereto) == B_OK)
512 {
513 this->ConvertFromScreen (&whereto);
514 msg->AddInt32 ("x", whereto.x);
515 msg->AddInt32 ("y", whereto.y);
516 }
517 be_app->PostMessage (msg);
518 msg->SendReply (B_OK);
519 }
520 }
521 else if (msg->GetPointer ("menuptr"))
522 {
523 struct haiku_menu_bar_select_event rq;
524 rq.window = this;
525 rq.ptr = (void *) msg->GetPointer ("menuptr");
526 haiku_write (MENU_BAR_SELECT_EVENT, &rq);
527 }
528 else if (msg->what == 'FPSE'
529 || ((msg->FindInt32 ("old_what", &old_what) == B_OK
530 && old_what == 'FPSE')))
531 {
532 struct haiku_file_panel_event rq;
533 BEntry entry;
534 BPath path;
535 entry_ref ref;
536
537 rq.ptr = NULL;
538
539 if (msg->FindRef ("refs", &ref) == B_OK &&
540 entry.SetTo (&ref, 0) == B_OK &&
541 entry.GetPath (&path) == B_OK)
542 {
543 const char *str_path = path.Path ();
544 if (str_path)
545 rq.ptr = strdup (str_path);
546 }
547
548 if (msg->FindRef ("directory", &ref),
549 entry.SetTo (&ref, 0) == B_OK &&
550 entry.GetPath (&path) == B_OK)
551 {
552 const char *name = msg->GetString ("name");
553 const char *str_path = path.Path ();
554
555 if (name)
556 {
557 char str_buf[std::strlen (str_path)
558 + std::strlen (name) + 2];
559 snprintf ((char *) &str_buf,
560 std::strlen (str_path)
561 + std::strlen (name) + 2, "%s/%s",
562 str_path, name);
563 rq.ptr = strdup (str_buf);
564 }
565 }
566
567 haiku_write (FILE_PANEL_EVENT, &rq);
568 }
569 else
570 BDirectWindow::MessageReceived (msg);
571 }
572
573 void
574 DispatchMessage (BMessage *msg, BHandler *handler)
575 {
576 if (msg->what == B_KEY_DOWN || msg->what == B_KEY_UP)
577 {
578 struct haiku_key_event rq;
579 rq.window = this;
580
581 int32_t code = msg->GetInt32 ("raw_char", 0);
582
583 rq.modifiers = 0;
584 uint32_t mods = modifiers ();
585
586 if (mods & B_SHIFT_KEY)
587 rq.modifiers |= HAIKU_MODIFIER_SHIFT;
588
589 if (mods & B_CONTROL_KEY)
590 rq.modifiers |= HAIKU_MODIFIER_CTRL;
591
592 if (mods & B_COMMAND_KEY)
593 rq.modifiers |= HAIKU_MODIFIER_ALT;
594
595 if (mods & B_OPTION_KEY)
596 rq.modifiers |= HAIKU_MODIFIER_SUPER;
597
598 rq.mb_char = code;
599 rq.kc = msg->GetInt32 ("key", -1);
600 rq.unraw_mb_char =
601 BUnicodeChar::FromUTF8 (msg->GetString ("bytes"));
602
603 if ((mods & B_SHIFT_KEY) && rq.kc >= 0)
604 map_shift (rq.kc, &rq.unraw_mb_char);
605 else if (rq.kc >= 0)
606 map_normal (rq.kc, &rq.unraw_mb_char);
607
608 haiku_write (msg->what == B_KEY_DOWN ? KEY_DOWN : KEY_UP, &rq);
609 }
610 else if (msg->what == B_MOUSE_WHEEL_CHANGED)
611 {
612 struct haiku_wheel_move_event rq;
613 rq.window = this;
614 rq.modifiers = 0;
615
616 uint32_t mods = modifiers ();
617
618 if (mods & B_SHIFT_KEY)
619 rq.modifiers |= HAIKU_MODIFIER_SHIFT;
620
621 if (mods & B_CONTROL_KEY)
622 rq.modifiers |= HAIKU_MODIFIER_CTRL;
623
624 if (mods & B_COMMAND_KEY)
625 rq.modifiers |= HAIKU_MODIFIER_ALT;
626
627 if (mods & B_OPTION_KEY)
628 rq.modifiers |= HAIKU_MODIFIER_SUPER;
629
630 float dx, dy;
631 if (msg->FindFloat ("be:wheel_delta_x", &dx) == B_OK &&
632 msg->FindFloat ("be:wheel_delta_y", &dy) == B_OK)
633 {
634 rq.delta_x = dx * 10;
635 rq.delta_y = dy * 10;
636
637 haiku_write (WHEEL_MOVE_EVENT, &rq);
638 };
639 }
640 else
641 BDirectWindow::DispatchMessage (msg, handler);
642 }
643
644 void
645 MenusBeginning ()
646 {
647 struct haiku_menu_bar_state_event rq;
648 rq.window = this;
649
650 haiku_write (MENU_BAR_OPEN, &rq);
651 }
652
653 void
654 MenusEnded ()
655 {
656 struct haiku_menu_bar_state_event rq;
657 rq.window = this;
658
659 haiku_write (MENU_BAR_CLOSE, &rq);
660 }
661
662 void
663 FrameResized (float newWidth, float newHeight)
664 {
665 struct haiku_resize_event rq;
666 rq.window = this;
667 rq.px_heightf = newHeight;
668 rq.px_widthf = newWidth;
669
670 haiku_write (FRAME_RESIZED, &rq);
671 BDirectWindow::FrameResized (newWidth, newHeight);
672 }
673
674 void
675 FrameMoved (BPoint newPosition)
676 {
677 struct haiku_move_event rq;
678 rq.window = this;
679 rq.x = std::lrint (newPosition.x);
680 rq.y = std::lrint (newPosition.y);
681
682 haiku_write (MOVE_EVENT, &rq);
683
684 for (struct child_frame *f = subset_windows;
685 f; f = f->next)
686 DoMove (f);
687 BDirectWindow::FrameMoved (newPosition);
688 }
689
690 void
691 WorkspacesChanged (uint32_t old, uint32_t n)
692 {
693 for (struct child_frame *f = subset_windows;
694 f; f = f->next)
695 DoUpdateWorkspace (f);
696 }
697
698 void
699 EmacsMoveTo (int x, int y)
700 {
701 if (!this->parent)
702 this->MoveTo (x, y);
703 else
704 this->parent->MoveChild (this, x, y, 0);
705 }
706
707 bool
708 QuitRequested ()
709 {
710 struct haiku_quit_requested_event rq;
711 rq.window = this;
712 haiku_write (QUIT_REQUESTED, &rq);
713 return false;
714 }
715
716 void
717 Minimize (bool minimized_p)
718 {
719 BDirectWindow::Minimize (minimized_p);
720 struct haiku_iconification_event rq;
721 rq.window = this;
722 rq.iconified_p = !parent && minimized_p;
723
724 haiku_write (ICONIFICATION, &rq);
725 }
726
727 void
728 EmacsHide (void)
729 {
730 if (this->IsHidden ())
731 return;
732 Hide ();
733 if (this->parent)
734 UpwardsUnSubsetChildren (this->parent);
735 }
736
737 void
738 EmacsShow (void)
739 {
740 if (!this->IsHidden ())
741 return;
742 if (this->parent)
743 shown_flag = 1;
744 Show ();
745 if (this->parent)
746 UpwardsSubsetChildren (this->parent);
747 }
748
749 void
750 Zoom (BPoint o, float w, float h)
751 {
752 struct haiku_zoom_event rq;
753 rq.window = this;
754
755 rq.x = o.x;
756 rq.y = o.y;
757
758 rq.width = w;
759 rq.height = h;
760
761 if (fullscreen_p)
762 MakeFullscreen (0);
763
764 if (o.x != x_before_zoom ||
765 o.y != y_before_zoom)
766 {
767 x_before_zoom = Frame ().left;
768 y_before_zoom = Frame ().top;
769 pre_zoom_rect = Frame ();
770 zoomed_p = 1;
771 haiku_write (ZOOM_EVENT, &rq);
772 }
773 else
774 {
775 zoomed_p = 0;
776 x_before_zoom = y_before_zoom = INT_MIN;
777 }
778
779 BDirectWindow::Zoom (o, w, h);
780 }
781
782 void
783 UnZoom (void)
784 {
785 if (!zoomed_p)
786 return;
787 zoomed_p = 0;
788
789 EmacsMoveTo (pre_zoom_rect.left, pre_zoom_rect.top);
790 ResizeTo (pre_zoom_rect.Width (),
791 pre_zoom_rect.Height ());
792 }
793
794 void
795 GetParentWidthHeight (int *width, int *height)
796 {
797 if (parent)
798 {
799 *width = parent->Frame ().Width ();
800 *height = parent->Frame ().Height ();
801 }
802 else
803 {
804 BScreen s (this);
805 *width = s.Frame ().Width ();
806 *height = s.Frame ().Height ();
807 }
808 }
809
810 void
811 OffsetChildRect (BRect *r, EmacsWindow *c)
812 {
813 for (struct child_frame *f; f; f = f->next)
814 if (f->window == c)
815 {
816 r->top -= f->yoff;
817 r->bottom -= f->yoff;
818 r->left -= f->xoff;
819 r->right -= f->xoff;
820 return;
821 }
822
823 gui_abort ("Trying to calculate offsets for a child frame that doesn't exist");
824 }
825
826 void
827 MakeFullscreen (int make_fullscreen_p)
828 {
829 BScreen screen (this);
830
831 if (!screen.IsValid ())
832 gui_abort ("Trying to make a window fullscreen without a screen");
833
834 if (make_fullscreen_p == fullscreen_p)
835 return;
836
837 fullscreen_p = make_fullscreen_p;
838 uint32 flags = Flags ();
839 if (fullscreen_p)
840 {
841 if (zoomed_p)
842 UnZoom ();
843
844 flags |= B_NOT_MOVABLE | B_NOT_ZOOMABLE;
845 pre_fullscreen_rect = Frame ();
846 if (parent)
847 parent->OffsetChildRect (&pre_fullscreen_rect, this);
848
849 int w, h;
850 EmacsMoveTo (0, 0);
851 GetParentWidthHeight (&w, &h);
852 ResizeTo (w, h);
853 }
854 else
855 {
856 flags &= ~(B_NOT_MOVABLE | B_NOT_ZOOMABLE);
857 EmacsMoveTo (pre_fullscreen_rect.left,
858 pre_fullscreen_rect.top);
859 ResizeTo (pre_fullscreen_rect.Width (),
860 pre_fullscreen_rect.Height ());
861 }
862 SetFlags (flags);
863 }
864};
865
866class EmacsMenuBar : public BMenuBar
867{
868public:
869 EmacsMenuBar () : BMenuBar (BRect (0, 0, 0, 0), NULL)
870 {
871 }
872
873 void
874 FrameResized (float newWidth, float newHeight)
875 {
876 struct haiku_menu_bar_resize_event rq;
877 rq.window = this->Window ();
878 rq.height = std::lrint (newHeight);
879 rq.width = std::lrint (newWidth);
880
881 haiku_write (MENU_BAR_RESIZE, &rq);
882 BMenuBar::FrameResized (newWidth, newHeight);
883 }
884};
885
886class EmacsView : public BView
887{
888public:
889 uint32_t visible_bell_color = 0;
890 uint32_t previous_buttons = 0;
891 int looper_locked_count = 0;
892 BRegion sb_region;
893
894 BView *offscreen_draw_view = NULL;
895 BBitmap *offscreen_draw_bitmap_1 = NULL;
896 BBitmap *copy_bitmap = NULL;
897
898#ifdef USE_BE_CAIRO
899 cairo_surface_t *cr_surface = NULL;
900 BLocker cr_surface_lock;
901#endif
902
903 BPoint tt_absl_pos;
904
905 color_space cspace;
906
907 EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs", B_FOLLOW_NONE, B_WILL_DRAW)
908 {
909
910 }
911
912 ~EmacsView ()
913 {
914 TearDownDoubleBuffering ();
915 }
916
917 void
918 AttachedToWindow (void)
919 {
920 cspace = B_RGBA32;
921 }
922
923#ifdef USE_BE_CAIRO
924 void
925 DetachCairoSurface (void)
926 {
927 if (!cr_surface_lock.Lock ())
928 gui_abort ("Could not lock cr surface during detachment");
929 if (!cr_surface)
930 gui_abort ("Trying to detach window cr surface when none exists");
931 cairo_surface_destroy (cr_surface);
932 cr_surface = NULL;
933 cr_surface_lock.Unlock ();
934 }
935
936 void
937 AttachCairoSurface (void)
938 {
939 if (!cr_surface_lock.Lock ())
940 gui_abort ("Could not lock cr surface during attachment");
941 if (cr_surface)
942 gui_abort ("Trying to attach cr surface when one already exists");
943 cr_surface = cairo_image_surface_create_for_data
944 ((unsigned char *) offscreen_draw_bitmap_1->Bits (),
945 CAIRO_FORMAT_ARGB32, offscreen_draw_bitmap_1->Bounds ().Width (),
946 offscreen_draw_bitmap_1->Bounds ().Height (),
947 offscreen_draw_bitmap_1->BytesPerRow ());
948 if (!cr_surface)
949 gui_abort ("Cr surface allocation failed for double-buffered view");
950 cr_surface_lock.Unlock ();
951 }
952#endif
953
954 void
955 TearDownDoubleBuffering (void)
956 {
957 if (offscreen_draw_view)
958 {
959 if (Window ())
960 ClearViewBitmap ();
961 if (copy_bitmap)
962 {
963 delete copy_bitmap;
964 copy_bitmap = NULL;
965 }
966 if (!looper_locked_count)
967 if (!offscreen_draw_view->LockLooper ())
968 gui_abort ("Failed to lock offscreen draw view");
969#ifdef USE_BE_CAIRO
970 if (cr_surface)
971 DetachCairoSurface ();
972#endif
973 offscreen_draw_view->RemoveSelf ();
974 delete offscreen_draw_view;
975 offscreen_draw_view = NULL;
976 delete offscreen_draw_bitmap_1;
977 offscreen_draw_bitmap_1 = NULL;
978 }
979 }
980
981 void
982 AfterResize (float newWidth, float newHeight)
983 {
984 if (offscreen_draw_view)
985 {
986 if (!LockLooper ())
987 gui_abort ("Failed to lock looper after resize");
988
989 if (!offscreen_draw_view->LockLooper ())
990 gui_abort ("Failed to lock offscreen draw view after resize");
991#ifdef USE_BE_CAIRO
992 DetachCairoSurface ();
993#endif
994 offscreen_draw_view->RemoveSelf ();
995 delete offscreen_draw_bitmap_1;
996 offscreen_draw_bitmap_1 = new BBitmap (Frame (), cspace, 1);
997 if (offscreen_draw_bitmap_1->InitCheck () != B_OK)
998 gui_abort ("Offscreen draw bitmap initialization failed");
999
1000 offscreen_draw_view->MoveTo (Frame ().left, Frame ().top);
1001 offscreen_draw_view->ResizeTo (Frame ().Width (), Frame ().Height ());
1002 offscreen_draw_bitmap_1->AddChild (offscreen_draw_view);
1003#ifdef USE_BE_CAIRO
1004 AttachCairoSurface ();
1005#endif
1006
1007 if (looper_locked_count)
1008 {
1009 offscreen_draw_bitmap_1->Lock ();
1010 }
1011
1012 UnlockLooper ();
1013 }
1014 }
1015
1016 void
1017 Pulse (void)
1018 {
1019 visible_bell_color = 0;
1020 SetFlags (Flags () & ~B_PULSE_NEEDED);
1021 Window ()->SetPulseRate (0);
1022 Invalidate ();
1023 }
1024
1025 void
1026 Draw (BRect expose_bounds)
1027 {
1028 struct haiku_expose_event rq;
1029 EmacsWindow *w = (EmacsWindow *) Window ();
1030
1031 if (visible_bell_color > 0)
1032 {
1033 PushState ();
1034 BView_SetHighColorForVisibleBell (this, visible_bell_color);
1035 FillRect (Frame ());
1036 PopState ();
1037 return;
1038 }
1039
1040 if (w->shown_flag)
1041 {
1042 PushState ();
1043 SetDrawingMode (B_OP_ERASE);
1044 FillRect (Frame ());
1045 PopState ();
1046 return;
1047 }
1048
1049 if (!offscreen_draw_view)
1050 {
1051 if (sb_region.Contains (std::lrint (expose_bounds.left),
1052 std::lrint (expose_bounds.top)) &&
1053 sb_region.Contains (std::lrint (expose_bounds.right),
1054 std::lrint (expose_bounds.top)) &&
1055 sb_region.Contains (std::lrint (expose_bounds.left),
1056 std::lrint (expose_bounds.bottom)) &&
1057 sb_region.Contains (std::lrint (expose_bounds.right),
1058 std::lrint (expose_bounds.bottom)))
1059 return;
1060
1061 rq.x = std::floor (expose_bounds.left);
1062 rq.y = std::floor (expose_bounds.top);
1063 rq.width = std::ceil (expose_bounds.right - expose_bounds.left + 1);
1064 rq.height = std::ceil (expose_bounds.bottom - expose_bounds.top + 1);
1065 if (!rq.width)
1066 rq.width = 1;
1067 if (!rq.height)
1068 rq.height = 1;
1069 rq.window = this->Window ();
1070
1071 haiku_write (FRAME_EXPOSED, &rq);
1072 }
1073 }
1074
1075 void
1076 DoVisibleBell (uint32_t color)
1077 {
1078 if (!LockLooper ())
1079 gui_abort ("Failed to lock looper during visible bell");
1080 visible_bell_color = color | (255 << 24);
1081 SetFlags (Flags () | B_PULSE_NEEDED);
1082 Window ()->SetPulseRate (100 * 1000);
1083 Invalidate ();
1084 UnlockLooper ();
1085 }
1086
1087 void
1088 FlipBuffers (void)
1089 {
1090 if (!LockLooper ())
1091 gui_abort ("Failed to lock looper during buffer flip");
1092 if (!offscreen_draw_view)
1093 gui_abort ("Failed to lock offscreen view during buffer flip");
1094
1095 offscreen_draw_view->Flush ();
1096 offscreen_draw_view->Sync ();
1097
1098 EmacsWindow *w = (EmacsWindow *) Window ();
1099 w->shown_flag = 0;
1100
1101 if (copy_bitmap &&
1102 copy_bitmap->Bounds () != offscreen_draw_bitmap_1->Bounds ())
1103 {
1104 delete copy_bitmap;
1105 copy_bitmap = NULL;
1106 }
1107 if (!copy_bitmap)
1108 copy_bitmap = new BBitmap (offscreen_draw_bitmap_1);
1109 else
1110 copy_bitmap->ImportBits (offscreen_draw_bitmap_1);
1111
1112 if (copy_bitmap->InitCheck () != B_OK)
1113 gui_abort ("Failed to init copy bitmap during buffer flip");
1114
1115 SetViewBitmap (copy_bitmap,
1116 Frame (), Frame (), B_FOLLOW_NONE, 0);
1117
1118 Invalidate ();
1119 UnlockLooper ();
1120 return;
1121 }
1122
1123 void
1124 SetUpDoubleBuffering (void)
1125 {
1126 if (!LockLooper ())
1127 gui_abort ("Failed to lock self setting up double buffering");
1128 if (offscreen_draw_view)
1129 gui_abort ("Failed to lock offscreen view setting up double buffering");
1130
1131 offscreen_draw_bitmap_1 = new BBitmap (Frame (), cspace, 1);
1132 if (offscreen_draw_bitmap_1->InitCheck () != B_OK)
1133 gui_abort ("Failed to init offscreen bitmap");
1134#ifdef USE_BE_CAIRO
1135 AttachCairoSurface ();
1136#endif
1137 offscreen_draw_view = new BView (Frame (), NULL, B_FOLLOW_NONE, B_WILL_DRAW);
1138 offscreen_draw_bitmap_1->AddChild (offscreen_draw_view);
1139
1140 if (looper_locked_count)
1141 {
1142 if (!offscreen_draw_bitmap_1->Lock ())
1143 gui_abort ("Failed to lock bitmap after double buffering was set up.");
1144 }
1145
1146 UnlockLooper ();
1147 Invalidate ();
1148 }
1149
1150 void
1151 MouseMoved (BPoint point, uint32 transit, const BMessage *msg)
1152 {
1153 struct haiku_mouse_motion_event rq;
1154
1155 rq.just_exited_p = transit == B_EXITED_VIEW;
1156 rq.x = point.x;
1157 rq.y = point.y;
1158 rq.be_code = transit;
1159 rq.window = this->Window ();
1160
1161 if (ToolTip ())
1162 ToolTip ()->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x),
1163 -(point.y - tt_absl_pos.y)));
1164
1165 haiku_write (MOUSE_MOTION, &rq);
1166 }
1167
1168 void
1169 MouseDown (BPoint point)
1170 {
1171 struct haiku_button_event rq;
1172 uint32 buttons;
1173
1174 this->GetMouse (&point, &buttons, false);
1175
1176 rq.window = this->Window ();
1177 rq.btn_no = 0;
1178
1179 if (!(previous_buttons & B_PRIMARY_MOUSE_BUTTON) &&
1180 (buttons & B_PRIMARY_MOUSE_BUTTON))
1181 rq.btn_no = 0;
1182 else if (!(previous_buttons & B_SECONDARY_MOUSE_BUTTON) &&
1183 (buttons & B_SECONDARY_MOUSE_BUTTON))
1184 rq.btn_no = 2;
1185 else if (!(previous_buttons & B_TERTIARY_MOUSE_BUTTON) &&
1186 (buttons & B_TERTIARY_MOUSE_BUTTON))
1187 rq.btn_no = 1;
1188 previous_buttons = buttons;
1189
1190 rq.x = point.x;
1191 rq.y = point.y;
1192
1193 uint32_t mods = modifiers ();
1194
1195 rq.modifiers = 0;
1196 if (mods & B_SHIFT_KEY)
1197 rq.modifiers |= HAIKU_MODIFIER_SHIFT;
1198
1199 if (mods & B_CONTROL_KEY)
1200 rq.modifiers |= HAIKU_MODIFIER_CTRL;
1201
1202 if (mods & B_COMMAND_KEY)
1203 rq.modifiers |= HAIKU_MODIFIER_ALT;
1204
1205 if (mods & B_OPTION_KEY)
1206 rq.modifiers |= HAIKU_MODIFIER_SUPER;
1207
1208 SetMouseEventMask (B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1209
1210 haiku_write (BUTTON_DOWN, &rq);
1211 }
1212
1213 void
1214 MouseUp (BPoint point)
1215 {
1216 struct haiku_button_event rq;
1217 uint32 buttons;
1218
1219 this->GetMouse (&point, &buttons, false);
1220
1221 rq.window = this->Window ();
1222 rq.btn_no = 0;
1223
1224 if ((previous_buttons & B_PRIMARY_MOUSE_BUTTON)
1225 && !(buttons & B_PRIMARY_MOUSE_BUTTON))
1226 rq.btn_no = 0;
1227 else if ((previous_buttons & B_SECONDARY_MOUSE_BUTTON)
1228 && !(buttons & B_SECONDARY_MOUSE_BUTTON))
1229 rq.btn_no = 2;
1230 else if ((previous_buttons & B_TERTIARY_MOUSE_BUTTON)
1231 && !(buttons & B_TERTIARY_MOUSE_BUTTON))
1232 rq.btn_no = 1;
1233 previous_buttons = buttons;
1234
1235 rq.x = point.x;
1236 rq.y = point.y;
1237
1238 uint32_t mods = modifiers ();
1239
1240 rq.modifiers = 0;
1241 if (mods & B_SHIFT_KEY)
1242 rq.modifiers |= HAIKU_MODIFIER_SHIFT;
1243
1244 if (mods & B_CONTROL_KEY)
1245 rq.modifiers |= HAIKU_MODIFIER_CTRL;
1246
1247 if (mods & B_COMMAND_KEY)
1248 rq.modifiers |= HAIKU_MODIFIER_ALT;
1249
1250 if (mods & B_OPTION_KEY)
1251 rq.modifiers |= HAIKU_MODIFIER_SUPER;
1252
1253 if (!buttons)
1254 SetMouseEventMask (0, 0);
1255
1256 haiku_write (BUTTON_UP, &rq);
1257 }
1258};
1259
1260class EmacsScrollBar : public BScrollBar
1261{
1262public:
1263 void *scroll_bar;
1264
1265 EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p) :
1266 BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ?
1267 B_HORIZONTAL : B_VERTICAL)
1268 {
1269 BView *vw = (BView *) this;
1270 vw->SetResizingMode (B_FOLLOW_NONE);
1271 }
1272
1273 void
1274 MessageReceived (BMessage *msg)
1275 {
1276 if (msg->what == SCROLL_BAR_UPDATE)
1277 {
1278 this->SetRange (0, msg->GetInt32 ("emacs:range", 0));
1279 this->SetValue (msg->GetInt32 ("emacs:units", 0));
1280 }
1281
1282 BScrollBar::MessageReceived (msg);
1283 }
1284
1285 void
1286 ValueChanged (float new_value)
1287 {
1288 struct haiku_scroll_bar_value_event rq;
1289 rq.scroll_bar = scroll_bar;
1290 rq.position = new_value;
1291
1292 haiku_write (SCROLL_BAR_VALUE_EVENT, &rq);
1293 }
1294
1295 void
1296 MouseDown (BPoint pt)
1297 {
1298 struct haiku_scroll_bar_drag_event rq;
1299 rq.dragging_p = 1;
1300 rq.scroll_bar = scroll_bar;
1301
1302 haiku_write (SCROLL_BAR_DRAG_EVENT, &rq);
1303 BScrollBar::MouseDown (pt);
1304 }
1305
1306 void
1307 MouseUp (BPoint pt)
1308 {
1309 struct haiku_scroll_bar_drag_event rq;
1310 rq.dragging_p = 0;
1311 rq.scroll_bar = scroll_bar;
1312
1313 haiku_write (SCROLL_BAR_DRAG_EVENT, &rq);
1314 BScrollBar::MouseUp (pt);
1315 }
1316};
1317
1318class EmacsTitleMenuItem : public BMenuItem
1319{
1320public:
1321 EmacsTitleMenuItem (const char *str) : BMenuItem (str, NULL)
1322 {
1323 SetEnabled (0);
1324 }
1325
1326 void
1327 DrawContent (void)
1328 {
1329 BMenu *menu = Menu ();
1330
1331 menu->PushState ();
1332 menu->SetFont (be_bold_font);
1333 BView_SetHighColorForVisibleBell (menu, 0);
1334 BMenuItem::DrawContent ();
1335 menu->PopState ();
1336 }
1337};
1338
1339class EmacsMenuItem : public BMenuItem
1340{
1341public:
1342 int menu_bar_id = -1;
1343 void *wind_ptr = NULL;
1344 char *key = NULL;
1345 char *help = NULL;
1346
1347 EmacsMenuItem (const char *ky,
1348 const char *str,
1349 const char *help,
1350 BMessage *message = NULL) : BMenuItem (str, message)
1351 {
1352 if (ky)
1353 {
1354 key = strdup (ky);
1355 if (!key)
1356 gui_abort ("strdup failed");
1357 }
1358
1359 if (help)
1360 {
1361 this->help = strdup (help);
1362 if (!this->help)
1363 gui_abort ("strdup failed");
1364 }
1365 }
1366
1367 ~EmacsMenuItem ()
1368 {
1369 if (key)
1370 free (key);
1371 if (help)
1372 free (help);
1373 }
1374
1375 void
1376 DrawContent (void)
1377 {
1378 BMenu *menu = Menu ();
1379
1380 BMenuItem::DrawContent ();
1381
1382 if (key)
1383 {
1384 BRect r = menu->Frame ();
1385 int w = menu->StringWidth (key);
1386 menu->MovePenTo (BPoint (r.Width () - w - 4,
1387 menu->PenLocation ().y));
1388 menu->DrawString (key);
1389 }
1390 }
1391
1392 void
1393 GetContentSize (float *w, float *h)
1394 {
1395 BMenuItem::GetContentSize (w, h);
1396 if (Menu () && key)
1397 *w += 4 + Menu ()->StringWidth (key);
1398 }
1399
1400 void
1401 Highlight (bool highlight_p)
1402 {
1403 struct haiku_menu_bar_help_event rq;
1404
1405 if (menu_bar_id >= 0)
1406 {
1407 rq.window = wind_ptr;
1408 rq.mb_idx = highlight_p ? menu_bar_id : -1;
1409
1410 haiku_write (MENU_BAR_HELP_EVENT, &rq);
1411 }
1412 else if (help)
1413 {
1414 Menu ()->SetToolTip (highlight_p ? help : NULL);
1415 }
1416
1417 BMenuItem::Highlight (highlight_p);
1418 }
1419};
1420
1421class EmacsPopUpMenu : public BPopUpMenu
1422{
1423public:
1424 EmacsPopUpMenu (const char *name) : BPopUpMenu (name, 0)
1425 {
1426
1427 }
1428
1429 void
1430 FrameResized (float w, float h)
1431 {
1432 Invalidate ();
1433 BPopUpMenu::FrameResized (w, h);
1434 }
1435};
1436
1437static int32
1438start_running_application (void *data)
1439{
1440 haiku_io_init_in_app_thread ();
1441
1442 if (!((Emacs *) data)->Lock ())
1443 gui_abort ("Failed to lock application");
1444
1445 ((Emacs *) data)->Run ();
1446 ((Emacs *) data)->Unlock ();
1447 return 0;
1448}
1449
1450/* Take BITMAP, a reference to a BBitmap, and return a pointer to its
1451 data. */
1452void *
1453BBitmap_data (void *bitmap)
1454{
1455 return ((BBitmap *) bitmap)->Bits ();
1456}
1457
1458/* Convert bitmap if required, placing the new bitmap in NEW_BITMAP,
1459 and return non-null if bitmap was successfully converted. Bitmaps
1460 should be freed with `BBitmap_free'. */
1461int
1462BBitmap_convert (void *_bitmap, void **new_bitmap)
1463{
1464 BBitmap *bitmap = (BBitmap *) _bitmap;
1465 if (bitmap->ColorSpace () == B_RGBA32)
1466 return -1;
1467 BRect bounds = bitmap->Bounds ();
1468 BBitmap *bmp = new (std::nothrow) BBitmap (bounds, B_RGBA32);
1469 if (!bmp || bmp->InitCheck () != B_OK)
1470 {
1471 if (bmp)
1472 delete bmp;
1473 return 0;
1474 }
1475 if (bmp->ImportBits (bitmap) != B_OK)
1476 {
1477 delete bmp;
1478 return 0;
1479 }
1480 *(BBitmap **) new_bitmap = bmp;
1481 return 1;
1482}
1483
1484void
1485BBitmap_free (void *bitmap)
1486{
1487 delete (BBitmap *) bitmap;
1488}
1489
1490/* Create new bitmap in RGB32 format, or in GRAY1 if MONO_P is
1491 non-zero. */
1492void *
1493BBitmap_new (int width, int height, int mono_p)
1494{
1495 BBitmap *bn = new (std::nothrow) BBitmap (BRect (0, 0, width - 1, height - 1),
1496 mono_p ? B_GRAY1 : B_RGB32);
1497
1498 return bn->InitCheck () == B_OK ? (void *) bn : (void *) (delete bn, NULL);
1499}
1500
1501void
1502BBitmap_dimensions (void *bitmap, int *left, int *top,
1503 int *right, int *bottom,
1504 int32_t *bytes_per_row, int *mono_p)
1505{
1506 BRect rect = ((BBitmap *) bitmap)->Bounds ();
1507 *left = rect.left;
1508 *top = rect.top;
1509 *right = rect.right;
1510 *bottom = rect.bottom;
1511
1512 *bytes_per_row = ((BBitmap *) bitmap)->BytesPerRow ();
1513 *mono_p = (((BBitmap *) bitmap)->ColorSpace () == B_GRAY1);
1514}
1515
1516/* Set up an application and return it. If starting the application
1517 thread fails, abort Emacs. */
1518void *
1519BApplication_setup (void)
1520{
1521 if (be_app)
1522 return be_app;
1523 thread_id id;
1524 Emacs *app;
1525
1526 app = new Emacs;
1527 app->Unlock ();
1528 if ((id = spawn_thread (start_running_application, "Emacs app thread",
1529 B_DEFAULT_MEDIA_PRIORITY, app)) < 0)
1530 gui_abort ("spawn_thread failed");
1531
1532 resume_thread (id);
1533
1534 app_thread = id;
1535 return app;
1536}
1537
1538/* Set up and return a window with its view put in VIEW. */
1539void *
1540BWindow_new (void *_view)
1541{
1542 BWindow *window = new (std::nothrow) EmacsWindow;
1543 BView **v = (BView **) _view;
1544 if (!window)
1545 {
1546 *v = NULL;
1547 return window;
1548 }
1549
1550 BView *vw = new (std::nothrow) EmacsView;
1551 if (!vw)
1552 {
1553 *v = NULL;
1554 window->Lock ();
1555 window->Quit ();
1556 return NULL;
1557 }
1558 window->AddChild (vw);
1559 *v = vw;
1560 return window;
1561}
1562
1563void
1564BWindow_quit (void *window)
1565{
1566 ((BWindow *) window)->Lock ();
1567 ((BWindow *) window)->Quit ();
1568}
1569
1570/* Set WINDOW's offset to X, Y. */
1571void
1572BWindow_set_offset (void *window, int x, int y)
1573{
1574 BWindow *wn = (BWindow *) window;
1575 EmacsWindow *w = dynamic_cast<EmacsWindow *> (wn);
1576 if (w)
1577 {
1578 if (!w->LockLooper ())
1579 gui_abort ("Failed to lock window looper setting offset");
1580 w->EmacsMoveTo (x, y);
1581 w->UnlockLooper ();
1582 }
1583 else
1584 wn->MoveTo (x, y);
1585}
1586
1587/* Iconify WINDOW. */
1588void
1589BWindow_iconify (void *window)
1590{
1591 if (((BWindow *) window)->IsHidden ())
1592 BWindow_set_visible (window, true);
1593 ((BWindow *) window)->Minimize (true);
1594}
1595
1596/* Show or hide WINDOW. */
1597void
1598BWindow_set_visible (void *window, int visible_p)
1599{
1600 EmacsWindow *win = (EmacsWindow *) window;
1601 if (visible_p)
1602 {
1603 if (win->IsMinimized ())
1604 win->Minimize (false);
1605 win->EmacsShow ();
1606 }
1607 else if (!win->IsHidden ())
1608 {
1609 if (win->IsMinimized ())
1610 win->Minimize (false);
1611 win->EmacsHide ();
1612 }
1613 win->Sync ();
1614}
1615
1616/* Change the title of WINDOW to the multibyte string TITLE. */
1617void
1618BWindow_retitle (void *window, const char *title)
1619{
1620 ((BWindow *) window)->SetTitle (title);
1621}
1622
1623/* Resize WINDOW to WIDTH by HEIGHT. */
1624void
1625BWindow_resize (void *window, int width, int height)
1626{
1627 ((BWindow *) window)->ResizeTo (width, height);
1628}
1629
1630/* Activate WINDOW, making it the subject of keyboard focus and
1631 bringing it to the front of the screen. */
1632void
1633BWindow_activate (void *window)
1634{
1635 ((BWindow *) window)->Activate ();
1636}
1637
1638/* Return the pixel dimensions of the main screen in WIDTH and
1639 HEIGHT. */
1640void
1641BScreen_px_dim (int *width, int *height)
1642{
1643 BScreen screen;
1644 if (!screen.IsValid ())
1645 gui_abort ("Invalid screen");
1646 BRect frame = screen.Frame ();
1647
1648 *width = frame.right - frame.left;
1649 *height = frame.bottom - frame.top;
1650}
1651
1652/* Resize VIEW to WIDTH, HEIGHT. */
1653void
1654BView_resize_to (void *view, int width, int height)
1655{
1656 EmacsView *vw = (EmacsView *) view;
1657 if (!vw->LockLooper ())
1658 gui_abort ("Failed to lock view for resize");
1659 vw->ResizeTo (width, height);
1660 vw->AfterResize (width, height);
1661 vw->UnlockLooper ();
1662}
1663
1664void *
1665BCursor_create_default (void)
1666{
1667 return new BCursor (B_CURSOR_ID_SYSTEM_DEFAULT);
1668}
1669
1670void *
1671BCursor_create_modeline (void)
1672{
1673 return new BCursor (B_CURSOR_ID_CONTEXT_MENU);
1674}
1675
1676void *
1677BCursor_from_id (enum haiku_cursor cursor)
1678{
1679 return new BCursor ((enum BCursorID) cursor);
1680}
1681
1682void *
1683BCursor_create_i_beam (void)
1684{
1685 return new BCursor (B_CURSOR_ID_I_BEAM);
1686}
1687
1688void *
1689BCursor_create_progress_cursor (void)
1690{
1691 return new BCursor (B_CURSOR_ID_PROGRESS);
1692}
1693
1694void *
1695BCursor_create_grab (void)
1696{
1697 return new BCursor (B_CURSOR_ID_GRAB);
1698}
1699
1700void
1701BCursor_delete (void *cursor)
1702{
1703 delete (BCursor *) cursor;
1704}
1705
1706void
1707BView_set_view_cursor (void *view, void *cursor)
1708{
1709 if (!((BView *) view)->LockLooper ())
1710 gui_abort ("Failed to lock view setting cursor");
1711 ((BView *) view)->SetViewCursor ((BCursor *) cursor);
1712 ((BView *) view)->UnlockLooper ();
1713}
1714
1715void
1716BWindow_Flush (void *window)
1717{
1718 ((BWindow *) window)->Flush ();
1719}
1720
1721/* Map the keycode KC, storing the result in CODE and 1 in
1722 NON_ASCII_P if it should be used. */
1723void
1724BMapKey (uint32_t kc, int *non_ascii_p, unsigned *code)
1725{
1726 if (*code == 10 && kc != 0x42)
1727 {
1728 *code = XK_Return;
1729 *non_ascii_p = 1;
1730 return;
1731 }
1732
1733 switch (kc)
1734 {
1735 default:
1736 *non_ascii_p = 0;
1737 if (kc < 0xe && kc > 0x1)
1738 {
1739 *code = XK_F1 + kc - 2;
1740 *non_ascii_p = 1;
1741 }
1742 return;
1743 case 0x1e:
1744 *code = XK_BackSpace;
1745 break;
1746 case 0x61:
1747 *code = XK_Left;
1748 break;
1749 case 0x63:
1750 *code = XK_Right;
1751 break;
1752 case 0x57:
1753 *code = XK_Up;
1754 break;
1755 case 0x62:
1756 *code = XK_Down;
1757 break;
1758 case 0x64:
1759 *code = XK_Insert;
1760 break;
1761 case 0x65:
1762 *code = XK_Delete;
1763 break;
1764 case 0x37:
1765 *code = XK_Home;
1766 break;
1767 case 0x58:
1768 *code = XK_End;
1769 break;
1770 case 0x39:
1771 *code = XK_Page_Up;
1772 break;
1773 case 0x5a:
1774 *code = XK_Page_Down;
1775 break;
1776 case 0x1:
1777 *code = XK_Escape;
1778 break;
1779 case 0x68:
1780 *code = XK_Menu;
1781 break;
1782 }
1783 *non_ascii_p = 1;
1784}
1785
1786/* Make a scrollbar, attach it to VIEW's window, and return it. */
1787void *
1788BScrollBar_make_for_view (void *view, int horizontal_p,
1789 int x, int y, int x1, int y1,
1790 void *scroll_bar_ptr)
1791{
1792 EmacsScrollBar *sb = new EmacsScrollBar (x, y, x1, y1, horizontal_p);
1793 sb->scroll_bar = scroll_bar_ptr;
1794
1795 BView *vw = (BView *) view;
1796 BView *sv = (BView *) sb;
1797 if (!vw->LockLooper ())
1798 gui_abort ("Failed to lock scrollbar owner");
1799 vw->AddChild ((BView *) sb);
1800 sv->WindowActivated (vw->Window ()->IsActive ());
1801 vw->UnlockLooper ();
1802 return sb;
1803}
1804
1805void
1806BScrollBar_delete (void *sb)
1807{
1808 BView *view = (BView *) sb;
1809 BView *pr = view->Parent ();
1810
1811 if (!pr->LockLooper ())
1812 gui_abort ("Failed to lock scrollbar parent");
1813 pr->RemoveChild (view);
1814 pr->UnlockLooper ();
1815
1816 delete (EmacsScrollBar *) sb;
1817}
1818
1819void
1820BView_move_frame (void *view, int x, int y, int x1, int y1)
1821{
1822 BView *vw = (BView *) view;
1823
1824 if (!vw->LockLooper ())
1825 gui_abort ("Failed to lock view moving frame");
1826 vw->MoveTo (x, y);
1827 vw->ResizeTo (x1 - x, y1 - y);
1828 vw->Flush ();
1829 vw->Sync ();
1830 vw->UnlockLooper ();
1831}
1832
1833void
1834BView_scroll_bar_update (void *sb, int portion, int whole, int position)
1835{
1836 BScrollBar *bar = (BScrollBar *) sb;
1837 BMessage msg = BMessage (SCROLL_BAR_UPDATE);
1838 BMessenger mr = BMessenger (bar);
1839 msg.AddInt32 ("emacs:range", whole);
1840 msg.AddInt32 ("emacs:units", position);
1841
1842 mr.SendMessage (&msg);
1843}
1844
1845/* Return the default scrollbar size. */
1846int
1847BScrollBar_default_size (int horizontal_p)
1848{
1849 return horizontal_p ? B_H_SCROLL_BAR_HEIGHT : B_V_SCROLL_BAR_WIDTH;
1850}
1851
1852/* Invalidate VIEW, causing it to be drawn again. */
1853void
1854BView_invalidate (void *view)
1855{
1856 BView *vw = (BView *) view;
1857 if (!vw->LockLooper ())
1858 gui_abort ("Couldn't lock view while invalidating it");
1859 vw->Invalidate ();
1860 vw->UnlockLooper ();
1861}
1862
1863/* Lock VIEW in preparation for drawing operations. This should be
1864 called before any attempt to draw onto VIEW or to lock it for Cairo
1865 drawing. `BView_draw_unlock' should be called afterwards. */
1866void
1867BView_draw_lock (void *view)
1868{
1869 EmacsView *vw = (EmacsView *) view;
1870 if (vw->looper_locked_count)
1871 {
1872 vw->looper_locked_count++;
1873 return;
1874 }
1875 BView *v = (BView *) find_appropriate_view_for_draw (vw);
1876 if (v != vw)
1877 {
1878 if (!vw->offscreen_draw_bitmap_1->Lock ())
1879 gui_abort ("Failed to lock offscreen bitmap while acquiring draw lock");
1880 }
1881 else if (!v->LockLooper ())
1882 gui_abort ("Failed to lock draw view while acquiring draw lock");
1883
1884 if (v != vw && !vw->LockLooper ())
1885 gui_abort ("Failed to lock view while acquiring draw lock");
1886 vw->looper_locked_count++;
1887}
1888
1889void
1890BView_draw_unlock (void *view)
1891{
1892 EmacsView *vw = (EmacsView *) view;
1893 if (--vw->looper_locked_count)
1894 return;
1895
1896 BView *v = (BView *) find_appropriate_view_for_draw (view);
1897 if (v == vw)
1898 vw->UnlockLooper ();
1899 else
1900 {
1901 vw->offscreen_draw_bitmap_1->Unlock ();
1902 vw->UnlockLooper ();
1903 }
1904}
1905
1906void
1907BWindow_center_on_screen (void *window)
1908{
1909 BWindow *w = (BWindow *) window;
1910 w->CenterOnScreen ();
1911}
1912
1913/* Tell VIEW it has been clicked at X by Y. */
1914void
1915BView_mouse_down (void *view, int x, int y)
1916{
1917 BView *vw = (BView *) view;
1918 if (vw->LockLooper ())
1919 {
1920 vw->MouseDown (BPoint (x, y));
1921 vw->UnlockLooper ();
1922 }
1923}
1924
1925/* Tell VIEW the mouse has been released at X by Y. */
1926void
1927BView_mouse_up (void *view, int x, int y)
1928{
1929 BView *vw = (BView *) view;
1930 if (vw->LockLooper ())
1931 {
1932 vw->MouseUp (BPoint (x, y));
1933 vw->UnlockLooper ();
1934 }
1935}
1936
1937/* Tell VIEW that the mouse has moved to Y by Y. */
1938void
1939BView_mouse_moved (void *view, int x, int y, uint32_t transit)
1940{
1941 BView *vw = (BView *) view;
1942 if (vw->LockLooper ())
1943 {
1944 vw->MouseMoved (BPoint (x, y), transit, NULL);
1945 vw->UnlockLooper ();
1946 }
1947}
1948
1949/* Import BITS into BITMAP using the B_GRAY1 colorspace. */
1950void
1951BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h)
1952{
1953 BBitmap *bmp = (BBitmap *) bitmap;
1954 unsigned char *data = (unsigned char *) bmp->Bits ();
1955 unsigned short *bts = (unsigned short *) bits;
1956
1957 for (int i = 0; i < (h * (wd / 8)); i++)
1958 {
1959 *((unsigned short *) data) = bts[i];
1960 data += bmp->BytesPerRow ();
1961 }
1962}
1963
1964/* Make a scrollbar at X, Y known to the view VIEW. */
1965void
1966BView_publish_scroll_bar (void *view, int x, int y, int width, int height)
1967{
1968 EmacsView *vw = (EmacsView *) view;
1969 if (vw->LockLooper ())
1970 {
1971 vw->sb_region.Include (BRect (x, y, x - 1 + width,
1972 y - 1 + height));
1973 vw->UnlockLooper ();
1974 }
1975}
1976
1977void
1978BView_forget_scroll_bar (void *view, int x, int y, int width, int height)
1979{
1980 EmacsView *vw = (EmacsView *) view;
1981 if (vw->LockLooper ())
1982 {
1983 vw->sb_region.Exclude (BRect (x, y, x - 1 + width,
1984 y - 1 + height));
1985 vw->UnlockLooper ();
1986 }
1987}
1988
1989void
1990BView_get_mouse (void *view, int *x, int *y)
1991{
1992 BPoint l;
1993 BView *vw = (BView *) view;
1994 if (!vw->LockLooper ())
1995 gui_abort ("Failed to lock view in BView_get_mouse");
1996 vw->GetMouse (&l, NULL, 1);
1997 vw->UnlockLooper ();
1998
1999 *x = std::lrint (l.x);
2000 *y = std::lrint (l.y);
2001}
2002
2003/* Perform an in-place conversion of X and Y from VIEW's coordinate
2004 system to its screen's coordinate system. */
2005void
2006BView_convert_to_screen (void *view, int *x, int *y)
2007{
2008 BPoint l = BPoint (*x, *y);
2009 BView *vw = (BView *) view;
2010 if (!vw->LockLooper ())
2011 gui_abort ("Failed to lock view in convert_to_screen");
2012 vw->ConvertToScreen (&l);
2013 vw->UnlockLooper ();
2014
2015 *x = std::lrint (l.x);
2016 *y = std::lrint (l.y);
2017}
2018
2019void
2020BView_convert_from_screen (void *view, int *x, int *y)
2021{
2022 BPoint l = BPoint (*x, *y);
2023 BView *vw = (BView *) view;
2024 if (!vw->LockLooper ())
2025 gui_abort ("Failed to lock view in convert_from_screen");
2026 vw->ConvertFromScreen (&l);
2027 vw->UnlockLooper ();
2028
2029 *x = std::lrint (l.x);
2030 *y = std::lrint (l.y);
2031}
2032
2033/* Decorate or undecorate WINDOW depending on DECORATE_P. */
2034void
2035BWindow_change_decoration (void *window, int decorate_p)
2036{
2037 BWindow *w = (BWindow *) window;
2038 if (!w->LockLooper ())
2039 gui_abort ("Failed to lock window while changing its decorations");
2040 if (decorate_p)
2041 w->SetLook (B_TITLED_WINDOW_LOOK);
2042 else
2043 w->SetLook (B_NO_BORDER_WINDOW_LOOK);
2044 w->UnlockLooper ();
2045}
2046
2047/* Decorate WINDOW appropriately for use as a tooltip. */
2048void
2049BWindow_set_tooltip_decoration (void *window)
2050{
2051 BWindow *w = (BWindow *) window;
2052 if (!w->LockLooper ())
2053 gui_abort ("Failed to lock window while setting ttip decoration");
2054 w->SetLook (B_BORDERED_WINDOW_LOOK);
2055 w->SetFeel (B_FLOATING_APP_WINDOW_FEEL);
2056 w->UnlockLooper ();
2057}
2058
2059/* Set B_AVOID_FOCUS on WINDOW if AVOID_FOCUS_P is non-nil, or clear
2060 it otherwise. */
2061void
2062BWindow_set_avoid_focus (void *window, int avoid_focus_p)
2063{
2064 BWindow *w = (BWindow *) window;
2065 if (!w->LockLooper ())
2066 gui_abort ("Failed to lock window while setting avoid focus");
2067
2068 if (!avoid_focus_p)
2069 w->SetFlags (w->Flags () & ~B_AVOID_FOCUS);
2070 else
2071 w->SetFlags (w->Flags () | B_AVOID_FOCUS);
2072 w->Sync ();
2073 w->UnlockLooper ();
2074}
2075
2076void
2077BView_emacs_delete (void *view)
2078{
2079 EmacsView *vw = (EmacsView *) view;
2080 if (!vw->LockLooper ())
2081 gui_abort ("Failed to lock view while deleting it");
2082 vw->RemoveSelf ();
2083 delete vw;
2084}
2085
2086/* Return the current workspace. */
2087uint32_t
2088haiku_current_workspace (void)
2089{
2090 return current_workspace ();
2091}
2092
2093/* Return a bitmask consisting of workspaces WINDOW is on. */
2094uint32_t
2095BWindow_workspaces (void *window)
2096{
2097 return ((BWindow *) window)->Workspaces ();
2098}
2099
2100/* Create a popup menu. */
2101void *
2102BPopUpMenu_new (const char *name)
2103{
2104 BPopUpMenu *menu = new EmacsPopUpMenu (name);
2105 menu->SetRadioMode (0);
2106 return menu;
2107}
2108
2109/* Add a title item to MENU. These items cannot be highlighted or
2110 triggered, and their labels will display as bold text. */
2111void
2112BMenu_add_title (void *menu, const char *text)
2113{
2114 EmacsTitleMenuItem *it = new EmacsTitleMenuItem (text);
2115 BMenu *mn = (BMenu *) menu;
2116 mn->AddItem (it);
2117}
2118
2119/* Add an item to the menu MENU. */
2120void
2121BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p,
2122 bool marked_p, bool mbar_p, void *mbw_ptr, const char *key,
2123 const char *help)
2124{
2125 BMenu *m = (BMenu *) menu;
2126 BMessage *msg;
2127 if (ptr)
2128 msg = new BMessage ();
2129 EmacsMenuItem *it = new EmacsMenuItem (key, label, help, ptr ? msg : NULL);
2130 it->SetTarget (m->Window ());
2131 it->SetEnabled (enabled_p);
2132 it->SetMarked (marked_p);
2133 if (mbar_p)
2134 {
2135 it->menu_bar_id = (intptr_t) ptr;
2136 it->wind_ptr = mbw_ptr;
2137 }
2138 if (ptr)
2139 msg->AddPointer ("menuptr", ptr);
2140 m->AddItem (it);
2141}
2142
2143/* Add a separator to the menu MENU. */
2144void
2145BMenu_add_separator (void *menu)
2146{
2147 BMenu *m = (BMenu *) menu;
2148
2149 m->AddSeparatorItem ();
2150}
2151
2152/* Create a submenu and attach it to MENU. */
2153void *
2154BMenu_new_submenu (void *menu, const char *label, bool enabled_p)
2155{
2156 BMenu *m = (BMenu *) menu;
2157 BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN);
2158 mn->SetRadioMode (0);
2159 BMenuItem *i = new BMenuItem (mn);
2160 i->SetEnabled (enabled_p);
2161 m->AddItem (i);
2162 return mn;
2163}
2164
2165/* Create a submenu that notifies Emacs upon opening. */
2166void *
2167BMenu_new_menu_bar_submenu (void *menu, const char *label)
2168{
2169 BMenu *m = (BMenu *) menu;
2170 BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN);
2171 mn->SetRadioMode (0);
2172 BMenuItem *i = new BMenuItem (mn);
2173 i->SetEnabled (1);
2174 m->AddItem (i);
2175 return mn;
2176}
2177
2178/* Run MENU, waiting for it to close, and return a pointer to the
2179 data of the selected item (if one exists), or NULL. X, Y should
2180 be in the screen coordinate system. */
2181void *
2182BMenu_run (void *menu, int x, int y)
2183{
2184 BPopUpMenu *mn = (BPopUpMenu *) menu;
2185 mn->SetRadioMode (0);
2186 BMenuItem *it = mn->Go (BPoint (x, y));
2187 if (it)
2188 {
2189 BMessage *mg = it->Message ();
2190 if (mg)
2191 return (void *) mg->GetPointer ("menuptr");
2192 else
2193 return NULL;
2194 }
2195 return NULL;
2196}
2197
2198/* Delete the entire menu hierarchy of MENU, and then delete MENU
2199 itself. */
2200void
2201BPopUpMenu_delete (void *menu)
2202{
2203 delete (BPopUpMenu *) menu;
2204}
2205
2206/* Create a menubar, attach it to VIEW, and return it. */
2207void *
2208BMenuBar_new (void *view)
2209{
2210 BView *vw = (BView *) view;
2211 EmacsMenuBar *bar = new EmacsMenuBar ();
2212
2213 if (!vw->LockLooper ())
2214 gui_abort ("Failed to lock menu bar parent");
2215 vw->AddChild ((BView *) bar);
2216 vw->UnlockLooper ();
2217
2218 return bar;
2219}
2220
2221/* Delete MENUBAR along with all subitems. */
2222void
2223BMenuBar_delete (void *menubar)
2224{
2225 BView *vw = (BView *) menubar;
2226 BView *p = vw->Parent ();
2227 if (!p->LockLooper ())
2228 gui_abort ("Failed to lock menu bar parent while removing menubar");
2229 vw->RemoveSelf ();
2230 p->UnlockLooper ();
2231 delete vw;
2232}
2233
2234/* Delete all items from MENU. */
2235void
2236BMenu_delete_all (void *menu)
2237{
2238 BMenu *mn = (BMenu *) menu;
2239 mn->RemoveItems (0, mn->CountItems (), true);
2240}
2241
2242/* Delete COUNT items from MENU starting from START. */
2243void
2244BMenu_delete_from (void *menu, int start, int count)
2245{
2246 BMenu *mn = (BMenu *) menu;
2247 mn->RemoveItems (start, count, true);
2248}
2249
2250/* Count items in menu MENU. */
2251int
2252BMenu_count_items (void *menu)
2253{
2254 return ((BMenu *) menu)->CountItems ();
2255}
2256
2257/* Find the item in MENU at IDX. */
2258void *
2259BMenu_item_at (void *menu, int idx)
2260{
2261 return ((BMenu *) menu)->ItemAt (idx);
2262}
2263
2264/* Set ITEM's label to LABEL. */
2265void
2266BMenu_item_set_label (void *item, const char *label)
2267{
2268 ((BMenuItem *) item)->SetLabel (label);
2269}
2270
2271/* Get ITEM's menu. */
2272void *
2273BMenu_item_get_menu (void *item)
2274{
2275 return ((BMenuItem *) item)->Submenu ();
2276}
2277
2278/* Emit a beep noise. */
2279void
2280haiku_ring_bell (void)
2281{
2282 beep ();
2283}
2284
2285/* Create a BAlert with TEXT. */
2286void *
2287BAlert_new (const char *text, enum haiku_alert_type type)
2288{
2289 return new BAlert (NULL, text, NULL, NULL, NULL, B_WIDTH_AS_USUAL,
2290 (enum alert_type) type);
2291}
2292
2293/* Add a button to ALERT and return the button. */
2294void *
2295BAlert_add_button (void *alert, const char *text)
2296{
2297 BAlert *al = (BAlert *) alert;
2298 al->AddButton (text);
2299 return al->ButtonAt (al->CountButtons () - 1);
2300}
2301
2302/* Run ALERT, returning the number of the button that was selected,
2303 or -1 if no button was selected before the alert was closed. */
2304int32_t
2305BAlert_go (void *alert)
2306{
2307 return ((BAlert *) alert)->Go ();
2308}
2309
2310/* Enable or disable BUTTON depending on ENABLED_P. */
2311void
2312BButton_set_enabled (void *button, int enabled_p)
2313{
2314 ((BButton *) button)->SetEnabled (enabled_p);
2315}
2316
2317/* Set VIEW's tooltip to TOOLTIP. */
2318void
2319BView_set_tooltip (void *view, const char *tooltip)
2320{
2321 ((BView *) view)->SetToolTip (tooltip);
2322}
2323
2324/* Set VIEW's tooltip to a sticky tooltip at X by Y. */
2325void
2326BView_set_and_show_sticky_tooltip (void *view, const char *tooltip,
2327 int x, int y)
2328{
2329 BToolTip *tip;
2330 BView *vw = (BView *) view;
2331 if (!vw->LockLooper ())
2332 gui_abort ("Failed to lock view while showing sticky tooltip");
2333 vw->SetToolTip (tooltip);
2334 tip = vw->ToolTip ();
2335 BPoint pt;
2336 EmacsView *ev = dynamic_cast<EmacsView *> (vw);
2337 if (ev)
2338 ev->tt_absl_pos = BPoint (x, y);
2339
2340 vw->GetMouse (&pt, NULL, 1);
2341 pt.x -= x;
2342 pt.y -= y;
2343
2344 pt.x = -pt.x;
2345 pt.y = -pt.y;
2346
2347 tip->SetMouseRelativeLocation (pt);
2348 tip->SetSticky (1);
2349 vw->ShowToolTip (tip);
2350 vw->UnlockLooper ();
2351}
2352
2353/* Delete ALERT. */
2354void
2355BAlert_delete (void *alert)
2356{
2357 delete (BAlert *) alert;
2358}
2359
2360/* Place the resolution of the monitor in DPI in RSSX and RSSY. */
2361void
2362BScreen_res (double *rrsx, double *rrsy)
2363{
2364 BScreen s (B_MAIN_SCREEN_ID);
2365 if (!s.IsValid ())
2366 gui_abort ("Invalid screen for resolution checks");
2367 monitor_info i;
2368
2369 if (s.GetMonitorInfo (&i) == B_OK)
2370 {
2371 *rrsx = (double) i.width / (double) 2.54;
2372 *rrsy = (double) i.height / (double) 2.54;
2373 }
2374 else
2375 {
2376 *rrsx = 72.27;
2377 *rrsy = 72.27;
2378 }
2379}
2380
2381/* Add WINDOW to OTHER_WINDOW's subset and parent it to
2382 OTHER_WINDOW. */
2383void
2384EmacsWindow_parent_to (void *window, void *other_window)
2385{
2386 EmacsWindow *w = (EmacsWindow *) window;
2387 if (!w->LockLooper ())
2388 gui_abort ("Failed to lock window while parenting");
2389 w->ParentTo ((EmacsWindow *) other_window);
2390 w->UnlockLooper ();
2391}
2392
2393void
2394EmacsWindow_unparent (void *window)
2395{
2396 EmacsWindow *w = (EmacsWindow *) window;
2397 if (!w->LockLooper ())
2398 gui_abort ("Failed to lock window while unparenting");
2399 w->UnparentAndUnlink ();
2400 w->UnlockLooper ();
2401}
2402
2403/* Place text describing the current version of Haiku in VERSION,
2404 which should be a buffer LEN bytes wide. */
2405void
2406be_get_version_string (char *version, int len)
2407{
2408 std::strncpy (version, "Unknown Haiku release", len - 1);
2409 BPath path;
2410 if (find_directory (B_BEOS_LIB_DIRECTORY, &path) == B_OK)
2411 {
2412 path.Append ("libbe.so");
2413
2414 BAppFileInfo appFileInfo;
2415 version_info versionInfo;
2416 BFile file;
2417 if (file.SetTo (path.Path (), B_READ_ONLY) == B_OK
2418 && appFileInfo.SetTo (&file) == B_OK
2419 && appFileInfo.GetVersionInfo (&versionInfo,
2420 B_APP_VERSION_KIND) == B_OK
2421 && versionInfo.short_info[0] != '\0')
2422 std::strncpy (version, versionInfo.short_info, len - 1);
2423 }
2424}
2425
2426/* Return the amount of color planes in the current display. */
2427int
2428be_get_display_planes (void)
2429{
2430 color_space space = dpy_color_space;
2431 if (space == B_NO_COLOR_SPACE)
2432 {
2433 BScreen screen; /* This is actually a very slow operation. */
2434 if (!screen.IsValid ())
2435 gui_abort ("Invalid screen");
2436 space = dpy_color_space = screen.ColorSpace ();
2437 }
2438
2439 if (space == B_RGB32 || space == B_RGB24)
2440 return 24;
2441 if (space == B_RGB16)
2442 return 16;
2443 if (space == B_RGB15)
2444 return 15;
2445 if (space == B_CMAP8)
2446 return 8;
2447
2448 gui_abort ("Bad colorspace for screen");
2449 /* https://www.haiku-os.org/docs/api/classBScreen.html
2450 says a valid screen can't be anything else. */
2451 return -1;
2452}
2453
2454/* Return the amount of colors the display can handle. */
2455int
2456be_get_display_color_cells (void)
2457{
2458 color_space space = dpy_color_space;
2459 if (space == B_NO_COLOR_SPACE)
2460 {
2461 BScreen screen;
2462 if (!screen.IsValid ())
2463 gui_abort ("Invalid screen");
2464 space = dpy_color_space = screen.ColorSpace ();
2465 }
2466
2467 if (space == B_RGB32 || space == B_RGB24)
2468 return 1677216;
2469 if (space == B_RGB16)
2470 return 65536;
2471 if (space == B_RGB15)
2472 return 32768;
2473 if (space == B_CMAP8)
2474 return 256;
2475
2476 gui_abort ("Bad colorspace for screen");
2477 return -1;
2478}
2479
2480/* Warp the pointer to X by Y. */
2481void
2482be_warp_pointer (int x, int y)
2483{
2484 /* We're not supposed to use the following function without a
2485 BWindowScreen object, but in Haiku nothing actually prevents us
2486 from doing so. */
2487
2488 set_mouse_position (x, y);
2489}
2490
2491/* Update the position of CHILD in WINDOW without actually moving
2492 it. */
2493void
2494EmacsWindow_move_weak_child (void *window, void *child, int xoff, int yoff)
2495{
2496 EmacsWindow *w = (EmacsWindow *) window;
2497 EmacsWindow *c = (EmacsWindow *) child;
2498
2499 if (!w->LockLooper ())
2500 gui_abort ("Couldn't lock window for weak move");
2501 w->MoveChild (c, xoff, yoff, 1);
2502 w->UnlockLooper ();
2503}
2504
2505/* Find an appropriate view to draw onto. If VW is double-buffered,
2506 this will be the view used for double buffering instead of VW
2507 itself. */
2508void *
2509find_appropriate_view_for_draw (void *vw)
2510{
2511 BView *v = (BView *) vw;
2512 EmacsView *ev = dynamic_cast<EmacsView *>(v);
2513 if (!ev)
2514 return v;
2515
2516 return ev->offscreen_draw_view ? ev->offscreen_draw_view : vw;
2517}
2518
2519/* Set up double buffering for VW. */
2520void
2521EmacsView_set_up_double_buffering (void *vw)
2522{
2523 EmacsView *view = (EmacsView *) vw;
2524 if (!view->LockLooper ())
2525 gui_abort ("Couldn't lock view while setting up double buffering");
2526 if (view->offscreen_draw_view)
2527 {
2528 view->UnlockLooper ();
2529 return;
2530 }
2531 view->SetUpDoubleBuffering ();
2532 view->UnlockLooper ();
2533}
2534
2535/* Flip and invalidate the view VW. */
2536void
2537EmacsView_flip_and_blit (void *vw)
2538{
2539 EmacsView *view = (EmacsView *) vw;
2540 if (!view->offscreen_draw_view)
2541 return;
2542 if (!view->LockLooper ())
2543 gui_abort ("Couldn't lock view in flip_and_blit");
2544 view->FlipBuffers ();
2545 view->UnlockLooper ();
2546}
2547
2548/* Disable double buffering for VW. */
2549void
2550EmacsView_disable_double_buffering (void *vw)
2551{
2552 EmacsView *view = (EmacsView *) vw;
2553 if (!view->LockLooper ())
2554 gui_abort ("Couldn't lock view tearing down double buffering");
2555 view->TearDownDoubleBuffering ();
2556 view->UnlockLooper ();
2557}
2558
2559/* Return non-0 if VW is double-buffered. */
2560int
2561EmacsView_double_buffered_p (void *vw)
2562{
2563 EmacsView *view = (EmacsView *) vw;
2564 if (!view->LockLooper ())
2565 gui_abort ("Couldn't lock view testing double buffering status");
2566 int db_p = !!view->offscreen_draw_view;
2567 view->UnlockLooper ();
2568 return db_p;
2569}
2570
2571struct popup_file_dialog_data
2572{
2573 BMessage *msg;
2574 BFilePanel *panel;
2575 BEntry *entry;
2576};
2577
2578static void
2579unwind_popup_file_dialog (void *ptr)
2580{
2581 struct popup_file_dialog_data *data =
2582 (struct popup_file_dialog_data *) ptr;
2583 BFilePanel *panel = data->panel;
2584 delete panel;
2585 delete data->entry;
2586 delete data->msg;
2587}
2588
2589static void
2590be_popup_file_dialog_safe_set_target (BFilePanel *dialog, BWindow *window)
2591{
2592 dialog->SetTarget (BMessenger (window));
2593}
2594
2595/* Popup a file dialog. */
2596char *
2597be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p, int dir_only_p,
2598 void *window, const char *save_text, const char *prompt,
2599 void (*block_input_function) (void),
2600 void (*unblock_input_function) (void))
2601{
2602 ptrdiff_t idx = c_specpdl_idx_from_cxx ();
2603 /* setjmp/longjmp is UB with automatic objects. */
2604 block_input_function ();
2605 BWindow *w = (BWindow *) window;
2606 uint32_t mode = dir_only_p ? B_DIRECTORY_NODE : B_FILE_NODE | B_DIRECTORY_NODE;
2607 BEntry *path = new BEntry;
2608 BMessage *msg = new BMessage ('FPSE');
2609 BFilePanel *panel = new BFilePanel (open_p ? B_OPEN_PANEL : B_SAVE_PANEL,
2610 NULL, NULL, mode);
2611 unblock_input_function ();
2612
2613 struct popup_file_dialog_data dat;
2614 dat.entry = path;
2615 dat.msg = msg;
2616 dat.panel = panel;
2617
2618 record_c_unwind_protect_from_cxx (unwind_popup_file_dialog, &dat);
2619 if (default_dir)
2620 {
2621 if (path->SetTo (default_dir, 0) != B_OK)
2622 default_dir = NULL;
2623 }
2624
2625 panel->SetMessage (msg);
2626 if (default_dir)
2627 panel->SetPanelDirectory (path);
2628 if (save_text)
2629 panel->SetSaveText (save_text);
2630 panel->SetHideWhenDone (0);
2631 panel->Window ()->SetTitle (prompt);
2632 be_popup_file_dialog_safe_set_target (panel, w);
2633
2634 panel->Show ();
2635 panel->Window ()->Show ();
2636
2637 void *buf = alloca (200);
2638 while (1)
2639 {
2640 enum haiku_event_type type;
2641 char *ptr = NULL;
2642
2643 if (!haiku_read_with_timeout (&type, buf, 200, 100000))
2644 {
2645 if (type != FILE_PANEL_EVENT)
2646 haiku_write (type, buf);
2647 else if (!ptr)
2648 ptr = (char *) ((struct haiku_file_panel_event *) buf)->ptr;
2649 }
2650
2651 ssize_t b_s;
2652 haiku_read_size (&b_s);
2653 if (!b_s || b_s == -1 || ptr || panel->Window ()->IsHidden ())
2654 {
2655 c_unbind_to_nil_from_cxx (idx);
2656 return ptr;
2657 }
2658 }
2659}
2660
2661void
2662be_app_quit (void)
2663{
2664 if (be_app)
2665 {
2666 status_t e;
2667 while (!be_app->Lock ());
2668 be_app->Quit ();
2669 wait_for_thread (app_thread, &e);
2670 }
2671}
2672
2673/* Temporarily fill VIEW with COLOR. */
2674void
2675EmacsView_do_visible_bell (void *view, uint32_t color)
2676{
2677 EmacsView *vw = (EmacsView *) view;
2678 vw->DoVisibleBell (color);
2679}
2680
2681/* Zoom WINDOW. */
2682void
2683BWindow_zoom (void *window)
2684{
2685 BWindow *w = (BWindow *) window;
2686 w->Zoom ();
2687}
2688
2689/* Make WINDOW fullscreen if FULLSCREEN_P. */
2690void
2691EmacsWindow_make_fullscreen (void *window, int fullscreen_p)
2692{
2693 EmacsWindow *w = (EmacsWindow *) window;
2694 w->MakeFullscreen (fullscreen_p);
2695}
2696
2697/* Unzoom (maximize) WINDOW. */
2698void
2699EmacsWindow_unzoom (void *window)
2700{
2701 EmacsWindow *w = (EmacsWindow *) window;
2702 w->UnZoom ();
2703}
2704
2705/* Move the pointer into MBAR and start tracking. */
2706void
2707BMenuBar_start_tracking (void *mbar)
2708{
2709 EmacsMenuBar *mb = (EmacsMenuBar *) mbar;
2710 if (!mb->LockLooper ())
2711 gui_abort ("Couldn't lock menubar");
2712 BRect frame = mb->Frame ();
2713 BPoint pt = frame.LeftTop ();
2714 BPoint l = pt;
2715 mb->Parent ()->ConvertToScreen (&pt);
2716 set_mouse_position (pt.x, pt.y);
2717 mb->MouseDown (l);
2718 mb->UnlockLooper ();
2719}
2720
2721#ifdef HAVE_NATIVE_IMAGE_API
2722int
2723be_can_translate_type_to_bitmap_p (const char *mime)
2724{
2725 BTranslatorRoster *r = BTranslatorRoster::Default ();
2726 translator_id *ids;
2727 int32 id_len;
2728
2729 if (r->GetAllTranslators (&ids, &id_len) != B_OK)
2730 return 0;
2731
2732 int found_in = 0;
2733 int found_out = 0;
2734
2735 for (int i = 0; i < id_len; ++i)
2736 {
2737 found_in = 0;
2738 found_out = 0;
2739 const translation_format *i_fmts;
2740 const translation_format *o_fmts;
2741
2742 int32 i_count, o_count;
2743
2744 if (r->GetInputFormats (ids[i], &i_fmts, &i_count) != B_OK)
2745 continue;
2746
2747 if (r->GetOutputFormats (ids[i], &o_fmts, &o_count) != B_OK)
2748 continue;
2749
2750 for (int x = 0; x < i_count; ++x)
2751 {
2752 if (!strcmp (i_fmts[x].MIME, mime))
2753 {
2754 found_in = 1;
2755 break;
2756 }
2757 }
2758
2759 for (int x = 0; x < i_count; ++x)
2760 {
2761 if (!strcmp (o_fmts[x].MIME, "image/x-be-bitmap") ||
2762 !strcmp (o_fmts[x].MIME, "image/x-vnd.Be-bitmap"))
2763 {
2764 found_out = 1;
2765 break;
2766 }
2767 }
2768
2769 if (found_in && found_out)
2770 break;
2771 }
2772
2773 delete [] ids;
2774
2775 return found_in && found_out;
2776}
2777
2778void *
2779be_translate_bitmap_from_file_name (const char *filename)
2780{
2781 BBitmap *bm = BTranslationUtils::GetBitmap (filename);
2782 return bm;
2783}
2784
2785void *
2786be_translate_bitmap_from_memory (const void *buf, size_t bytes)
2787{
2788 BMemoryIO io (buf, bytes);
2789 BBitmap *bm = BTranslationUtils::GetBitmap (&io);
2790 return bm;
2791}
2792#endif
2793
2794/* Return the size of BITMAP's data, in bytes. */
2795size_t
2796BBitmap_bytes_length (void *bitmap)
2797{
2798 BBitmap *bm = (BBitmap *) bitmap;
2799 return bm->BitsLength ();
2800}
2801
2802/* Show VIEW's tooltip. */
2803void
2804BView_show_tooltip (void *view)
2805{
2806 BView *vw = (BView *) view;
2807 if (vw->LockLooper ())
2808 {
2809 vw->ShowToolTip (vw->ToolTip ());
2810 vw->UnlockLooper ();
2811 }
2812}
2813
2814
2815#ifdef USE_BE_CAIRO
2816/* Return VIEW's cairo surface. */
2817cairo_surface_t *
2818EmacsView_cairo_surface (void *view)
2819{
2820 EmacsView *vw = (EmacsView *) view;
2821 EmacsWindow *wn = (EmacsWindow *) vw->Window ();
2822 return vw->cr_surface ? vw->cr_surface : wn->cr_surface;
2823}
2824
2825/* Transfer each clip rectangle in VIEW to the cairo context
2826 CTX. */
2827void
2828BView_cr_dump_clipping (void *view, cairo_t *ctx)
2829{
2830 BView *vw = (BView *) find_appropriate_view_for_draw (view);
2831 BRegion cr;
2832 vw->GetClippingRegion (&cr);
2833
2834 for (int i = 0; i < cr.CountRects (); ++i)
2835 {
2836 BRect r = cr.RectAt (i);
2837 cairo_rectangle (ctx, r.left, r.top, r.Width () + 1,
2838 r.Height () + 1);
2839 }
2840
2841 cairo_clip (ctx);
2842}
2843
2844/* Lock WINDOW in preparation for drawing using Cairo. */
2845void
2846EmacsWindow_begin_cr_critical_section (void *window)
2847{
2848 EmacsWindow *w = (EmacsWindow *) window;
2849 if (!w->surface_lock.Lock ())
2850 gui_abort ("Couldn't lock cairo surface");
2851
2852 BView *vw = (BView *) w->FindView ("Emacs");
2853 EmacsView *ev = dynamic_cast <EmacsView *> (vw);
2854 if (ev && !ev->cr_surface_lock.Lock ())
2855 gui_abort ("Couldn't lock view cairo surface");
2856}
2857
2858/* Unlock WINDOW in preparation for drawing using Cairo. */
2859void
2860EmacsWindow_end_cr_critical_section (void *window)
2861{
2862 EmacsWindow *w = (EmacsWindow *) window;
2863 w->surface_lock.Unlock ();
2864 BView *vw = (BView *) w->FindView ("Emacs");
2865 EmacsView *ev = dynamic_cast <EmacsView *> (vw);
2866 if (ev)
2867 ev->cr_surface_lock.Unlock ();
2868}
2869#endif
2870
2871/* Get the width of STR in the plain font. */
2872int
2873be_string_width_with_plain_font (const char *str)
2874{
2875 return be_plain_font->StringWidth (str);
2876}
2877
2878/* Get the ascent + descent of the plain font. */
2879int
2880be_plain_font_height (void)
2881{
2882 struct font_height fheight;
2883 be_plain_font->GetHeight (&fheight);
2884
2885 return fheight.ascent + fheight.descent;
2886}
2887
2888/* Return the number of physical displays connected. */
2889int
2890be_get_display_screens (void)
2891{
2892 int count = 1;
2893 BScreen scr;
2894
2895 if (!scr.IsValid ())
2896 gui_abort ("Main screen vanished!");
2897 while (scr.SetToNext () == B_OK && scr.IsValid ())
2898 ++count;
2899
2900 return count;
2901}
2902
2903/* Set the minimum width the user can resize WINDOW to. */
2904void
2905BWindow_set_min_size (void *window, int width, int height)
2906{
2907 BWindow *w = (BWindow *) window;
2908
2909 if (!w->LockLooper ())
2910 gui_abort ("Failed to lock window looper setting min size");
2911 w->SetSizeLimits (width, -1, height, -1);
2912 w->UnlockLooper ();
2913}
2914
2915/* Set the alignment of WINDOW's dimensions. */
2916void
2917BWindow_set_size_alignment (void *window, int align_width, int align_height)
2918{
2919 BWindow *w = (BWindow *) window;
2920
2921 if (!w->LockLooper ())
2922 gui_abort ("Failed to lock window looper setting alignment");
2923#if 0 /* Haiku does not currently implement SetWindowAlignment. */
2924 if (w->SetWindowAlignment (B_PIXEL_ALIGNMENT, -1, -1, align_width,
2925 align_width, -1, -1, align_height,
2926 align_height) != B_NO_ERROR)
2927 gui_abort ("Invalid pixel alignment");
2928#endif
2929 w->UnlockLooper ();
2930}
diff --git a/src/haiku_support.h b/src/haiku_support.h
new file mode 100644
index 00000000000..9f5f3c77e3d
--- /dev/null
+++ b/src/haiku_support.h
@@ -0,0 +1,869 @@
1/* Haiku window system support. Hey Emacs, this is -*- C++ -*-
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#ifndef _HAIKU_SUPPORT_H
20#define _HAIKU_SUPPORT_H
21
22#include <stdint.h>
23
24#ifdef HAVE_FREETYPE
25#include <ft2build.h>
26#include <fontconfig/fontconfig.h>
27#include FT_FREETYPE_H
28#include FT_SIZES_H
29#endif
30
31#ifdef USE_BE_CAIRO
32#include <cairo.h>
33#endif
34
35enum haiku_cursor
36 {
37 CURSOR_ID_NO_CURSOR = 12,
38 CURSOR_ID_RESIZE_NORTH = 15,
39 CURSOR_ID_RESIZE_EAST = 16,
40 CURSOR_ID_RESIZE_SOUTH = 17,
41 CURSOR_ID_RESIZE_WEST = 18,
42 CURSOR_ID_RESIZE_NORTH_EAST = 19,
43 CURSOR_ID_RESIZE_NORTH_WEST = 20,
44 CURSOR_ID_RESIZE_SOUTH_EAST = 21,
45 CURSOR_ID_RESIZE_SOUTH_WEST = 22,
46 CURSOR_ID_RESIZE_NORTH_SOUTH = 23,
47 CURSOR_ID_RESIZE_EAST_WEST = 24,
48 CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST = 25,
49 CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST = 26
50 };
51
52enum haiku_alert_type
53 {
54 HAIKU_EMPTY_ALERT = 0,
55 HAIKU_INFO_ALERT,
56 HAIKU_IDEA_ALERT,
57 HAIKU_WARNING_ALERT,
58 HAIKU_STOP_ALERT
59 };
60
61enum haiku_event_type
62 {
63 QUIT_REQUESTED,
64 FRAME_RESIZED,
65 FRAME_EXPOSED,
66 KEY_DOWN,
67 KEY_UP,
68 ACTIVATION,
69 MOUSE_MOTION,
70 BUTTON_DOWN,
71 BUTTON_UP,
72 ICONIFICATION,
73 MOVE_EVENT,
74 SCROLL_BAR_VALUE_EVENT,
75 SCROLL_BAR_DRAG_EVENT,
76 WHEEL_MOVE_EVENT,
77 MENU_BAR_RESIZE,
78 MENU_BAR_OPEN,
79 MENU_BAR_SELECT_EVENT,
80 MENU_BAR_CLOSE,
81 FILE_PANEL_EVENT,
82 MENU_BAR_HELP_EVENT,
83 ZOOM_EVENT,
84 REFS_EVENT,
85 APP_QUIT_REQUESTED_EVENT
86 };
87
88struct haiku_quit_requested_event
89{
90 void *window;
91};
92
93struct haiku_resize_event
94{
95 void *window;
96 float px_heightf;
97 float px_widthf;
98};
99
100struct haiku_expose_event
101{
102 void *window;
103 int x;
104 int y;
105 int width;
106 int height;
107};
108
109struct haiku_refs_event
110{
111 void *window;
112 int x, y;
113 /* Free this with free! */
114 char *ref;
115};
116
117struct haiku_app_quit_requested_event
118{
119 char dummy;
120};
121
122#define HAIKU_MODIFIER_ALT (1)
123#define HAIKU_MODIFIER_CTRL (1 << 1)
124#define HAIKU_MODIFIER_SHIFT (1 << 2)
125#define HAIKU_MODIFIER_SUPER (1 << 3)
126
127struct haiku_key_event
128{
129 void *window;
130 int modifiers;
131 uint32_t mb_char;
132 uint32_t unraw_mb_char;
133 short kc;
134};
135
136struct haiku_activation_event
137{
138 void *window;
139 int activated_p;
140};
141
142struct haiku_mouse_motion_event
143{
144 void *window;
145 bool just_exited_p;
146 int x;
147 int y;
148 uint32_t be_code;
149};
150
151struct haiku_button_event
152{
153 void *window;
154 int btn_no;
155 int modifiers;
156 int x;
157 int y;
158};
159
160struct haiku_iconification_event
161{
162 void *window;
163 int iconified_p;
164};
165
166struct haiku_move_event
167{
168 void *window;
169 int x;
170 int y;
171};
172
173struct haiku_wheel_move_event
174{
175 void *window;
176 int modifiers;
177 float delta_x;
178 float delta_y;
179};
180
181struct haiku_menu_bar_select_event
182{
183 void *window;
184 void *ptr;
185};
186
187struct haiku_file_panel_event
188{
189 void *ptr;
190};
191
192struct haiku_menu_bar_help_event
193{
194 void *window;
195 int mb_idx;
196};
197
198struct haiku_zoom_event
199{
200 void *window;
201 int x;
202 int y;
203 int width;
204 int height;
205};
206
207#define FSPEC_FAMILY 1
208#define FSPEC_STYLE (1 << 1)
209#define FSPEC_SLANT (1 << 2)
210#define FSPEC_WEIGHT (1 << 3)
211#define FSPEC_SPACING (1 << 4)
212#define FSPEC_WANTED (1 << 5)
213#define FSPEC_NEED_ONE_OF (1 << 6)
214#define FSPEC_WIDTH (1 << 7)
215#define FSPEC_LANGUAGE (1 << 8)
216
217typedef char haiku_font_family_or_style[64];
218
219enum haiku_font_slant
220 {
221 NO_SLANT = -1,
222 SLANT_OBLIQUE,
223 SLANT_REGULAR,
224 SLANT_ITALIC
225 };
226
227enum haiku_font_width
228 {
229 NO_WIDTH = -1,
230 ULTRA_CONDENSED,
231 EXTRA_CONDENSED,
232 CONDENSED,
233 SEMI_CONDENSED,
234 NORMAL_WIDTH,
235 SEMI_EXPANDED,
236 EXPANDED,
237 EXTRA_EXPANDED,
238 ULTRA_EXPANDED
239 };
240
241enum haiku_font_language
242 {
243 LANGUAGE_CN,
244 LANGUAGE_KO,
245 LANGUAGE_JP,
246 MAX_LANGUAGE /* This isn't a language. */
247 };
248
249struct haiku_font_pattern
250{
251 int specified;
252 struct haiku_font_pattern *next;
253 /* The next two fields are only temporarily used during the font
254 discovery process! Do not rely on them being correct outside
255 BFont_find. */
256 struct haiku_font_pattern *last;
257 struct haiku_font_pattern *next_family;
258 haiku_font_family_or_style family;
259 haiku_font_family_or_style style;
260 int weight;
261 int mono_spacing_p;
262 int want_chars_len;
263 int need_one_of_len;
264 enum haiku_font_slant slant;
265 enum haiku_font_width width;
266 enum haiku_font_language language;
267 uint32_t *wanted_chars;
268 uint32_t *need_one_of;
269
270 int oblique_seen_p;
271};
272
273struct haiku_scroll_bar_value_event
274{
275 void *scroll_bar;
276 int position;
277};
278
279struct haiku_scroll_bar_drag_event
280{
281 void *scroll_bar;
282 int dragging_p;
283};
284
285struct haiku_menu_bar_resize_event
286{
287 void *window;
288 int width;
289 int height;
290};
291
292struct haiku_menu_bar_state_event
293{
294 void *window;
295};
296
297#define HAIKU_THIN 0
298#define HAIKU_ULTRALIGHT 20
299#define HAIKU_EXTRALIGHT 40
300#define HAIKU_LIGHT 50
301#define HAIKU_SEMI_LIGHT 75
302#define HAIKU_REGULAR 100
303#define HAIKU_SEMI_BOLD 180
304#define HAIKU_BOLD 200
305#define HAIKU_EXTRA_BOLD 205
306#define HAIKU_ULTRA_BOLD 210
307#define HAIKU_BOOK 400
308#define HAIKU_HEAVY 800
309#define HAIKU_ULTRA_HEAVY 900
310#define HAIKU_BLACK 1000
311#define HAIKU_MEDIUM 2000
312
313#ifdef __cplusplus
314extern "C"
315{
316#endif
317#include <pthread.h>
318#include <OS.h>
319
320#ifdef __cplusplus
321 typedef void *haiku;
322
323 extern void
324 haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel);
325
326 extern unsigned long
327 haiku_get_pixel (haiku bitmap, int x, int y);
328#endif
329
330 extern port_id port_application_to_emacs;
331
332 extern void haiku_io_init (void);
333 extern void haiku_io_init_in_app_thread (void);
334
335 extern void
336 haiku_read_size (ssize_t *len);
337
338 extern int
339 haiku_read (enum haiku_event_type *type, void *buf, ssize_t len);
340
341 extern int
342 haiku_read_with_timeout (enum haiku_event_type *type, void *buf, ssize_t len,
343 time_t timeout);
344
345 extern int
346 haiku_write (enum haiku_event_type type, void *buf);
347
348 extern int
349 haiku_write_without_signal (enum haiku_event_type type, void *buf);
350
351 extern void
352 rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l);
353
354 extern void
355 hsl_color_rgb (double h, double s, double l, uint32_t *rgb);
356
357 extern void *
358 BBitmap_new (int width, int height, int mono_p);
359
360 extern void *
361 BBitmap_data (void *bitmap);
362
363 extern int
364 BBitmap_convert (void *bitmap, void **new_bitmap);
365
366 extern void
367 BBitmap_free (void *bitmap);
368
369 extern void
370 BBitmap_dimensions (void *bitmap, int *left, int *top,
371 int *right, int *bottom, int32_t *bytes_per_row,
372 int *mono_p);
373
374 extern void *
375 BApplication_setup (void);
376
377 extern void *
378 BWindow_new (void *view);
379
380 extern void
381 BWindow_quit (void *window);
382
383 extern void
384 BWindow_set_offset (void *window, int x, int y);
385
386 extern void
387 BWindow_iconify (void *window);
388
389 extern void
390 BWindow_set_visible (void *window, int visible_p);
391
392 extern void
393 BFont_close (void *font);
394
395 extern void
396 BFont_dat (void *font, int *px_size, int *min_width, int *max_width,
397 int *avg_width, int *height, int *space_width, int *ascent,
398 int *descent, int *underline_position, int *underline_thickness);
399
400 extern int
401 BFont_have_char_p (void *font, int32_t chr);
402
403 extern int
404 BFont_have_char_block (void *font, int32_t beg, int32_t end);
405
406 extern void
407 BFont_char_bounds (void *font, const char *mb_str, int *advance,
408 int *lb, int *rb);
409
410 extern void
411 BFont_nchar_bounds (void *font, const char *mb_str, int *advance,
412 int *lb, int *rb, int32_t n);
413
414 extern void
415 BWindow_retitle (void *window, const char *title);
416
417 extern void
418 BWindow_resize (void *window, int width, int height);
419
420 extern void
421 BWindow_activate (void *window);
422
423 extern void
424 BView_StartClip (void *view);
425
426 extern void
427 BView_EndClip (void *view);
428
429 extern void
430 BView_SetHighColor (void *view, uint32_t color);
431
432 extern void
433 BView_SetHighColorForVisibleBell (void *view, uint32_t color);
434
435 extern void
436 BView_FillRectangleForVisibleBell (void *view, int x, int y, int width,
437 int height);
438
439 extern void
440 BView_SetLowColor (void *view, uint32_t color);
441
442 extern void
443 BView_SetPenSize (void *view, int u);
444
445 extern void
446 BView_SetFont (void *view, void *font);
447
448 extern void
449 BView_MovePenTo (void *view, int x, int y);
450
451 extern void
452 BView_DrawString (void *view, const char *chr, ptrdiff_t len);
453
454 extern void
455 BView_DrawChar (void *view, char chr);
456
457 extern void
458 BView_FillRectangle (void *view, int x, int y, int width, int height);
459
460 extern void
461 BView_FillRectangleAbs (void *view, int x, int y, int x1, int y1);
462
463 extern void
464 BView_FillTriangle (void *view, int x1, int y1,
465 int x2, int y2, int x3, int y3);
466
467 extern void
468 BView_StrokeRectangle (void *view, int x, int y, int width, int height);
469
470 extern void
471 BView_SetViewColor (void *view, uint32_t color);
472
473 extern void
474 BView_ClipToRect (void *view, int x, int y, int width, int height);
475
476 extern void
477 BView_ClipToInverseRect (void *view, int x, int y, int width, int height);
478
479 extern void
480 BView_StrokeLine (void *view, int sx, int sy, int tx, int ty);
481
482 extern void
483 BView_CopyBits (void *view, int x, int y, int width, int height,
484 int tox, int toy, int towidth, int toheight);
485
486 extern void
487 BView_DrawBitmap (void *view, void *bitmap, int x, int y,
488 int width, int height, int vx, int vy, int vwidth,
489 int vheight);
490
491 extern void
492 BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
493 int y, int width, int height);
494
495 extern void
496 BView_DrawMask (void *src, void *view,
497 int x, int y, int width, int height,
498 int vx, int vy, int vwidth, int vheight,
499 uint32_t color);
500
501 extern void *
502 BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color,
503 double rot, int desw, int desh);
504
505 extern void
506 BScreen_px_dim (int *width, int *height);
507
508 extern void
509 BView_resize_to (void *view, int width, int height);
510
511 /* Functions for creating and freeing cursors. */
512 extern void *
513 BCursor_create_default (void);
514
515 extern void *
516 BCursor_from_id (enum haiku_cursor cursor);
517
518 extern void *
519 BCursor_create_modeline (void);
520
521 extern void *
522 BCursor_create_i_beam (void);
523
524 extern void *
525 BCursor_create_progress_cursor (void);
526
527 extern void *
528 BCursor_create_grab (void);
529
530 extern void
531 BCursor_delete (void *cursor);
532
533 extern void
534 BView_set_view_cursor (void *view, void *cursor);
535
536 extern void
537 BWindow_Flush (void *window);
538
539 extern void
540 BMapKey (uint32_t kc, int *non_ascii_p, unsigned *code);
541
542 extern void *
543 BScrollBar_make_for_view (void *view, int horizontal_p,
544 int x, int y, int x1, int y1,
545 void *scroll_bar_ptr);
546
547 extern void
548 BScrollBar_delete (void *sb);
549
550 extern void
551 BView_move_frame (void *view, int x, int y, int x1, int y1);
552
553 extern void
554 BView_scroll_bar_update (void *sb, int portion, int whole, int position);
555
556 extern int
557 BScrollBar_default_size (int horizontal_p);
558
559 extern void
560 BView_invalidate (void *view);
561
562 extern void
563 BView_draw_lock (void *view);
564
565 extern void
566 BView_draw_unlock (void *view);
567
568 extern void
569 BWindow_center_on_screen (void *window);
570
571 extern void
572 BView_mouse_moved (void *view, int x, int y, uint32_t transit);
573
574 extern void
575 BView_mouse_down (void *view, int x, int y);
576
577 extern void
578 BView_mouse_up (void *view, int x, int y);
579
580 extern void
581 BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h);
582
583 extern void
584 haiku_font_pattern_free (struct haiku_font_pattern *pt);
585
586 extern struct haiku_font_pattern *
587 BFont_find (struct haiku_font_pattern *pt);
588
589 extern int
590 BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size);
591
592 extern void
593 BFont_populate_fixed_family (struct haiku_font_pattern *ptn);
594
595 extern void
596 BFont_populate_plain_family (struct haiku_font_pattern *ptn);
597
598 extern void
599 BView_publish_scroll_bar (void *view, int x, int y, int width, int height);
600
601 extern void
602 BView_forget_scroll_bar (void *view, int x, int y, int width, int height);
603
604 extern void
605 BView_get_mouse (void *view, int *x, int *y);
606
607 extern void
608 BView_convert_to_screen (void *view, int *x, int *y);
609
610 extern void
611 BView_convert_from_screen (void *view, int *x, int *y);
612
613 extern void
614 BWindow_change_decoration (void *window, int decorate_p);
615
616 extern void
617 BWindow_set_tooltip_decoration (void *window);
618
619 extern void
620 BWindow_set_avoid_focus (void *window, int avoid_focus_p);
621
622 extern void
623 BView_emacs_delete (void *view);
624
625 extern uint32_t
626 haiku_current_workspace (void);
627
628 extern uint32_t
629 BWindow_workspaces (void *window);
630
631 extern void *
632 BPopUpMenu_new (const char *name);
633
634 extern void
635 BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p,
636 bool marked_p, bool mbar_p, void *mbw_ptr, const char *key,
637 const char *help);
638
639 extern void
640 BMenu_add_separator (void *menu);
641
642 extern void *
643 BMenu_new_submenu (void *menu, const char *label, bool enabled_p);
644
645 extern void *
646 BMenu_new_menu_bar_submenu (void *menu, const char *label);
647
648 extern int
649 BMenu_count_items (void *menu);
650
651 extern void *
652 BMenu_item_at (void *menu, int idx);
653
654 extern void *
655 BMenu_run (void *menu, int x, int y);
656
657 extern void
658 BPopUpMenu_delete (void *menu);
659
660 extern void *
661 BMenuBar_new (void *view);
662
663 extern void
664 BMenu_delete_all (void *menu);
665
666 extern void
667 BMenuBar_delete (void *menubar);
668
669 extern void
670 BMenu_item_set_label (void *item, const char *label);
671
672 extern void *
673 BMenu_item_get_menu (void *item);
674
675 extern void
676 BMenu_delete_from (void *menu, int start, int count);
677
678 extern void
679 haiku_ring_bell (void);
680
681 extern void *
682 BAlert_new (const char *text, enum haiku_alert_type type);
683
684 extern void *
685 BAlert_add_button (void *alert, const char *text);
686
687 extern int32_t
688 BAlert_go (void *alert);
689
690 extern void
691 BButton_set_enabled (void *button, int enabled_p);
692
693 extern void
694 BView_set_tooltip (void *view, const char *tooltip);
695
696 extern void
697 BAlert_delete (void *alert);
698
699 extern void
700 BScreen_res (double *rrsx, double *rrsy);
701
702 extern void
703 EmacsWindow_parent_to (void *window, void *other_window);
704
705 extern void
706 EmacsWindow_unparent (void *window);
707
708 extern int
709 BFont_string_width (void *font, const char *utf8);
710
711 extern void
712 be_get_version_string (char *version, int len);
713
714 extern int
715 be_get_display_planes (void);
716
717 extern int
718 be_get_display_color_cells (void);
719
720 extern void
721 be_warp_pointer (int x, int y);
722
723 extern void
724 EmacsWindow_move_weak_child (void *window, void *child, int xoff, int yoff);
725
726 extern void
727 EmacsView_set_up_double_buffering (void *vw);
728
729 extern void
730 EmacsView_disable_double_buffering (void *vw);
731
732 extern void
733 EmacsView_flip_and_blit (void *vw);
734
735 extern int
736 EmacsView_double_buffered_p (void *vw);
737
738 extern char *
739 be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p,
740 int dir_only_p, void *window, const char *save_text,
741 const char *prompt,
742 void (*block_input_function) (void),
743 void (*unblock_input_function) (void));
744
745 extern void
746 record_c_unwind_protect_from_cxx (void (*) (void *), void *);
747
748 extern ptrdiff_t
749 c_specpdl_idx_from_cxx (void);
750
751 extern void
752 c_unbind_to_nil_from_cxx (ptrdiff_t idx);
753
754 extern void
755 EmacsView_do_visible_bell (void *view, uint32_t color);
756
757 extern void
758 BWindow_zoom (void *window);
759
760 extern void
761 EmacsWindow_make_fullscreen (void *window, int fullscreen_p);
762
763 extern void
764 EmacsWindow_unzoom (void *window);
765
766#ifdef HAVE_NATIVE_IMAGE_API
767 extern int
768 be_can_translate_type_to_bitmap_p (const char *mime);
769
770 extern void *
771 be_translate_bitmap_from_file_name (const char *filename);
772
773 extern void *
774 be_translate_bitmap_from_memory (const void *buf, size_t bytes);
775#endif
776
777 extern void
778 BMenuBar_start_tracking (void *mbar);
779
780 extern size_t
781 BBitmap_bytes_length (void *bitmap);
782
783 extern void
784 BView_show_tooltip (void *view);
785
786#ifdef USE_BE_CAIRO
787 extern cairo_surface_t *
788 EmacsView_cairo_surface (void *view);
789
790 extern void
791 BView_cr_dump_clipping (void *view, cairo_t *ctx);
792
793 extern void
794 EmacsWindow_begin_cr_critical_section (void *window);
795
796 extern void
797 EmacsWindow_end_cr_critical_section (void *window);
798#endif
799
800 extern void
801 BView_set_and_show_sticky_tooltip (void *view, const char *tooltip,
802 int x, int y);
803
804 extern void
805 BMenu_add_title (void *menu, const char *text);
806
807 extern int
808 be_plain_font_height (void);
809
810 extern int
811 be_string_width_with_plain_font (const char *str);
812
813 extern int
814 be_get_display_screens (void);
815
816 extern void
817 BWindow_set_min_size (void *window, int width, int height);
818
819 extern void
820 BWindow_set_size_alignment (void *window, int align_width, int align_height);
821
822#ifdef __cplusplus
823 extern void *
824 find_appropriate_view_for_draw (void *vw);
825}
826
827extern _Noreturn void
828gui_abort (const char *msg);
829#endif /* _cplusplus */
830
831/* Borrowed from X.Org keysymdef.h */
832#define XK_BackSpace 0xff08 /* Back space, back char */
833#define XK_Tab 0xff09
834#define XK_Linefeed 0xff0a /* Linefeed, LF */
835#define XK_Clear 0xff0b
836#define XK_Return 0xff0d /* Return, enter */
837#define XK_Pause 0xff13 /* Pause, hold */
838#define XK_Scroll_Lock 0xff14
839#define XK_Sys_Req 0xff15
840#define XK_Escape 0xff1b
841#define XK_Delete 0xffff /* Delete, rubout */
842#define XK_Home 0xff50
843#define XK_Left 0xff51 /* Move left, left arrow */
844#define XK_Up 0xff52 /* Move up, up arrow */
845#define XK_Right 0xff53 /* Move right, right arrow */
846#define XK_Down 0xff54 /* Move down, down arrow */
847#define XK_Prior 0xff55 /* Prior, previous */
848#define XK_Page_Up 0xff55
849#define XK_Next 0xff56 /* Next */
850#define XK_Page_Down 0xff56
851#define XK_End 0xff57 /* EOL */
852#define XK_Begin 0xff58 /* BOL */
853#define XK_Select 0xff60 /* Select, mark */
854#define XK_Print 0xff61
855#define XK_Execute 0xff62 /* Execute, run, do */
856#define XK_Insert 0xff63 /* Insert, insert here */
857#define XK_Undo 0xff65
858#define XK_Redo 0xff66 /* Redo, again */
859#define XK_Menu 0xff67
860#define XK_Find 0xff68 /* Find, search */
861#define XK_Cancel 0xff69 /* Cancel, stop, abort, exit */
862#define XK_Help 0xff6a /* Help */
863#define XK_Break 0xff6b
864#define XK_Mode_switch 0xff7e /* Character set switch */
865#define XK_script_switch 0xff7e /* Alias for mode_switch */
866#define XK_Num_Lock 0xff7f
867#define XK_F1 0xffbe
868
869#endif /* _HAIKU_SUPPORT_H_ */
diff --git a/src/haikufns.c b/src/haikufns.c
new file mode 100644
index 00000000000..868fc71f979
--- /dev/null
+++ b/src/haikufns.c
@@ -0,0 +1,2448 @@
1/* Haiku window system support
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include <math.h>
22
23#include "lisp.h"
24#include "frame.h"
25#include "blockinput.h"
26#include "termchar.h"
27#include "font.h"
28#include "keyboard.h"
29#include "buffer.h"
30#include "dispextern.h"
31
32#include "haikugui.h"
33#include "haikuterm.h"
34#include "haiku_support.h"
35#include "termhooks.h"
36
37#include <stdlib.h>
38
39#include <kernel/OS.h>
40
41#define RGB_TO_ULONG(r, g, b) \
42 (((r) << 16) | ((g) << 8) | (b));
43#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
44#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
45#define BLUE_FROM_ULONG(color) ((color) & 0xff)
46
47/* The frame of the currently visible tooltip. */
48static Lisp_Object tip_frame;
49
50/* The window-system window corresponding to the frame of the
51 currently visible tooltip. */
52static Window tip_window;
53
54/* A timer that hides or deletes the currently visible tooltip when it
55 fires. */
56static Lisp_Object tip_timer;
57
58/* STRING argument of last `x-show-tip' call. */
59static Lisp_Object tip_last_string;
60
61/* Normalized FRAME argument of last `x-show-tip' call. */
62static Lisp_Object tip_last_frame;
63
64/* PARMS argument of last `x-show-tip' call. */
65static Lisp_Object tip_last_parms;
66
67static void
68haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
69static void
70haiku_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name);
71
72static ptrdiff_t image_cache_refcount;
73
74static Lisp_Object
75get_geometry_from_preferences (struct haiku_display_info *dpyinfo,
76 Lisp_Object parms)
77{
78 struct {
79 const char *val;
80 const char *cls;
81 Lisp_Object tem;
82 } r[] = {
83 { "width", "Width", Qwidth },
84 { "height", "Height", Qheight },
85 { "left", "Left", Qleft },
86 { "top", "Top", Qtop },
87 };
88
89 int i;
90 for (i = 0; i < ARRAYELTS (r); ++i)
91 {
92 if (NILP (Fassq (r[i].tem, parms)))
93 {
94 Lisp_Object value
95 = gui_display_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
96 RES_TYPE_NUMBER);
97 if (! EQ (value, Qunbound))
98 parms = Fcons (Fcons (r[i].tem, value), parms);
99 }
100 }
101
102 return parms;
103}
104
105void
106haiku_change_tool_bar_height (struct frame *f, int height)
107{
108 int unit = FRAME_LINE_HEIGHT (f);
109 int old_height = FRAME_TOOL_BAR_HEIGHT (f);
110 int lines = (height + unit - 1) / unit;
111 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
112
113 /* Make sure we redisplay all windows in this frame. */
114 fset_redisplay (f);
115
116 FRAME_TOOL_BAR_HEIGHT (f) = height;
117 FRAME_TOOL_BAR_LINES (f) = lines;
118 store_frame_param (f, Qtool_bar_lines, make_fixnum (lines));
119
120 if (FRAME_HAIKU_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0)
121 {
122 clear_frame (f);
123 clear_current_matrices (f);
124 }
125
126 if ((height < old_height) && WINDOWP (f->tool_bar_window))
127 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
128
129 if (!f->tool_bar_resized)
130 {
131 /* As long as tool_bar_resized is false, effectively try to change
132 F's native height. */
133 if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
134 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
135 1, false, Qtool_bar_lines);
136 else
137 adjust_frame_size (f, -1, -1, 4, false, Qtool_bar_lines);
138
139 f->tool_bar_resized = f->tool_bar_redisplayed;
140 }
141 else
142 /* Any other change may leave the native size of F alone. */
143 adjust_frame_size (f, -1, -1, 3, false, Qtool_bar_lines);
144
145 /* adjust_frame_size might not have done anything, garbage frame
146 here. */
147 adjust_frame_glyphs (f);
148 SET_FRAME_GARBAGED (f);
149
150 if (FRAME_HAIKU_WINDOW (f))
151 haiku_clear_under_internal_border (f);
152}
153
154void
155haiku_change_tab_bar_height (struct frame *f, int height)
156{
157 int unit = FRAME_LINE_HEIGHT (f);
158 int old_height = FRAME_TAB_BAR_HEIGHT (f);
159 int lines = (height + unit - 1) / unit;
160 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
161
162 /* Make sure we redisplay all windows in this frame. */
163 fset_redisplay (f);
164
165 /* Recalculate tab bar and frame text sizes. */
166 FRAME_TAB_BAR_HEIGHT (f) = height;
167 FRAME_TAB_BAR_LINES (f) = lines;
168 store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
169
170 if (FRAME_HAIKU_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
171 {
172 clear_frame (f);
173 clear_current_matrices (f);
174 }
175
176 if ((height < old_height) && WINDOWP (f->tab_bar_window))
177 clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
178
179 if (!f->tab_bar_resized)
180 {
181 /* As long as tab_bar_resized is false, effectively try to change
182 F's native height. */
183 if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
184 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
185 1, false, Qtab_bar_lines);
186 else
187 adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines);
188
189 f->tab_bar_resized = f->tab_bar_redisplayed;
190 }
191 else
192 /* Any other change may leave the native size of F alone. */
193 adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines);
194
195 /* adjust_frame_size might not have done anything, garbage frame
196 here. */
197 adjust_frame_glyphs (f);
198 SET_FRAME_GARBAGED (f);
199 if (FRAME_HAIKU_WINDOW (f))
200 haiku_clear_under_internal_border (f);
201}
202
203static void
204haiku_set_no_focus_on_map (struct frame *f, Lisp_Object value,
205 Lisp_Object oldval)
206{
207 if (!EQ (value, oldval))
208 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (value);
209}
210
211static void
212haiku_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
213{
214 if (FRAME_TOOLTIP_P (f))
215 return;
216 int nlines;
217
218 /* Treat tool bars like menu bars. */
219 if (FRAME_MINIBUF_ONLY_P (f))
220 return;
221
222 /* Use VALUE only if an int >= 0. */
223 if (RANGED_FIXNUMP (0, value, INT_MAX))
224 nlines = XFIXNAT (value);
225 else
226 nlines = 0;
227
228 haiku_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
229}
230
231static void
232haiku_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
233{
234 if (FRAME_TOOLTIP_P (f))
235 return;
236 int olines = FRAME_TAB_BAR_LINES (f);
237 int nlines;
238
239 /* Treat tab bars like menu bars. */
240 if (FRAME_MINIBUF_ONLY_P (f))
241 return;
242
243 /* Use VALUE only if an int >= 0. */
244 if (RANGED_FIXNUMP (0, value, INT_MAX))
245 nlines = XFIXNAT (value);
246 else
247 nlines = 0;
248
249 if (nlines != olines && (olines == 0 || nlines == 0))
250 haiku_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
251}
252
253
254int
255haiku_get_color (const char *name, Emacs_Color *color)
256{
257 unsigned short r16, g16, b16;
258 Lisp_Object tem;
259
260 if (parse_color_spec (name, &r16, &g16, &b16))
261 {
262 color->pixel = RGB_TO_ULONG (r16 / 256, g16 / 256, b16 / 256);
263 color->red = r16;
264 color->green = g16;
265 color->blue = b16;
266 return 0;
267 }
268 else
269 {
270 block_input ();
271 eassert (x_display_list && !NILP (x_display_list->color_map));
272 tem = x_display_list->color_map;
273 for (; CONSP (tem); tem = XCDR (tem))
274 {
275 Lisp_Object col = XCAR (tem);
276 if (CONSP (col) && !xstrcasecmp (SSDATA (XCAR (col)), name))
277 {
278 int32_t clr = XFIXNUM (XCDR (col));
279 color->pixel = clr;
280 color->red = RED_FROM_ULONG (clr) * 257;
281 color->green = GREEN_FROM_ULONG (clr) * 257;
282 color->blue = BLUE_FROM_ULONG (clr) * 257;
283 unblock_input ();
284 return 0;
285 }
286 }
287
288 unblock_input ();
289 }
290
291 return 1;
292}
293
294static struct haiku_display_info *
295haiku_display_info_for_name (Lisp_Object name)
296{
297 CHECK_STRING (name);
298
299 if (!NILP (Fstring_equal (name, build_string ("be"))))
300 {
301 if (!x_display_list)
302 return x_display_list;
303
304 error ("Be windowing not initialized");
305 }
306
307 error ("Be displays can only be named \"be\"");
308}
309
310static struct haiku_display_info *
311check_haiku_display_info (Lisp_Object object)
312{
313 struct haiku_display_info *dpyinfo = NULL;
314
315 if (NILP (object))
316 {
317 struct frame *sf = XFRAME (selected_frame);
318
319 if (FRAME_HAIKU_P (sf) && FRAME_LIVE_P (sf))
320 dpyinfo = FRAME_DISPLAY_INFO (sf);
321 else if (x_display_list)
322 dpyinfo = x_display_list;
323 else
324 error ("Be windowing not present");
325 }
326 else if (TERMINALP (object))
327 {
328 struct terminal *t = decode_live_terminal (object);
329
330 if (t->type != output_haiku)
331 error ("Terminal %d is not a Be display", t->id);
332
333 dpyinfo = t->display_info.haiku;
334 }
335 else if (STRINGP (object))
336 dpyinfo = haiku_display_info_for_name (object);
337 else
338 {
339 struct frame *f = decode_window_system_frame (object);
340 dpyinfo = FRAME_DISPLAY_INFO (f);
341 }
342
343 return dpyinfo;
344}
345
346static void
347haiku_set_title_bar_text (struct frame *f, Lisp_Object text)
348{
349 if (FRAME_HAIKU_WINDOW (f))
350 {
351 block_input ();
352 BWindow_retitle (FRAME_HAIKU_WINDOW (f), SSDATA (ENCODE_UTF_8 (text)));
353 unblock_input ();
354 }
355}
356
357static void
358haiku_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
359{
360 /* Don't change the title if it's already NAME. */
361 if (EQ (name, f->title))
362 return;
363
364 update_mode_lines = 26;
365
366 fset_title (f, name);
367
368 if (NILP (name))
369 name = f->name;
370
371 haiku_set_title_bar_text (f, name);
372}
373
374static void
375haiku_set_child_frame_border_width (struct frame *f,
376 Lisp_Object arg, Lisp_Object oldval)
377{
378 int border;
379
380 if (NILP (arg))
381 border = -1;
382 else if (RANGED_FIXNUMP (0, arg, INT_MAX))
383 border = XFIXNAT (arg);
384 else
385 signal_error ("Invalid child frame border width", arg);
386
387 if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f))
388 {
389 f->child_frame_border_width = border;
390
391 if (FRAME_HAIKU_WINDOW (f))
392 adjust_frame_size (f, -1, -1, 3, 0, Qchild_frame_border_width);
393
394 SET_FRAME_GARBAGED (f);
395 }
396}
397
398static void
399haiku_set_parent_frame (struct frame *f,
400 Lisp_Object new_value, Lisp_Object old_value)
401{
402 struct frame *p = NULL;
403 block_input ();
404 if (!NILP (new_value)
405 && (!FRAMEP (new_value)
406 || !FRAME_LIVE_P (p = XFRAME (new_value))
407 || !FRAME_HAIKU_P (p)))
408 {
409 store_frame_param (f, Qparent_frame, old_value);
410 unblock_input ();
411 error ("Invalid specification of `parent-frame'");
412 }
413
414 if (EQ (new_value, old_value))
415 {
416 unblock_input ();
417 return;
418 }
419
420 if (!NILP (old_value))
421 EmacsWindow_unparent (FRAME_HAIKU_WINDOW (f));
422 if (!NILP (new_value))
423 {
424 EmacsWindow_parent_to (FRAME_HAIKU_WINDOW (f),
425 FRAME_HAIKU_WINDOW (p));
426 BWindow_set_offset (FRAME_HAIKU_WINDOW (f),
427 f->left_pos, f->top_pos);
428 }
429 fset_parent_frame (f, new_value);
430 unblock_input ();
431}
432
433static void
434haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
435{
436 haiku_set_name (f, arg, 1);
437}
438
439static void
440haiku_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
441{
442 block_input ();
443 if (!EQ (new_value, old_value))
444 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
445
446 if (FRAME_HAIKU_WINDOW (f))
447 {
448 BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f),
449 FRAME_NO_ACCEPT_FOCUS (f));
450 }
451 unblock_input ();
452}
453
454static void
455unwind_create_frame (Lisp_Object frame)
456{
457 struct frame *f = XFRAME (frame);
458
459 /* If frame is already dead, nothing to do. This can happen if the
460 display is disconnected after the frame has become official, but
461 before x_create_frame removes the unwind protect. */
462 if (!FRAME_LIVE_P (f))
463 return;
464
465 /* If frame is ``official'', nothing to do. */
466 if (NILP (Fmemq (frame, Vframe_list)))
467 {
468#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
469 struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
470#endif
471
472 /* If the frame's image cache refcount is still the same as our
473 private shadow variable, it means we are unwinding a frame
474 for which we didn't yet call init_frame_faces, where the
475 refcount is incremented. Therefore, we increment it here, so
476 that free_frame_faces, called in free_frame_resources later,
477 will not mistakenly decrement the counter that was not
478 incremented yet to account for this new frame. */
479 if (FRAME_IMAGE_CACHE (f) != NULL
480 && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
481 FRAME_IMAGE_CACHE (f)->refcount++;
482
483 haiku_free_frame_resources (f);
484 free_glyphs (f);
485
486#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
487 /* Check that reference counts are indeed correct. */
488 if (dpyinfo->terminal->image_cache)
489 eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
490#endif
491 }
492}
493
494static void
495unwind_create_tip_frame (Lisp_Object frame)
496{
497 unwind_create_frame (frame);
498 tip_window = NULL;
499 tip_frame = Qnil;
500}
501
502static void
503haiku_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
504{
505 struct haiku_output *output = FRAME_OUTPUT_DATA (f);
506 unsigned long old_fg;
507
508 Emacs_Color color;
509
510 if (haiku_get_color (SSDATA (arg), &color))
511 {
512 store_frame_param (f, Qforeground_color, oldval);
513 unblock_input ();
514 error ("Bad color");
515 }
516
517 old_fg = FRAME_FOREGROUND_PIXEL (f);
518 FRAME_FOREGROUND_PIXEL (f) = color.pixel;
519
520 if (FRAME_HAIKU_WINDOW (f))
521 {
522
523 block_input ();
524 if (output->cursor_color.pixel == old_fg)
525 {
526 output->cursor_color.pixel = old_fg;
527 output->cursor_color.red = RED_FROM_ULONG (old_fg);
528 output->cursor_color.green = GREEN_FROM_ULONG (old_fg);
529 output->cursor_color.blue = BLUE_FROM_ULONG (old_fg);
530 }
531
532 unblock_input ();
533
534 update_face_from_frame_parameter (f, Qforeground_color, arg);
535
536 if (FRAME_VISIBLE_P (f))
537 redraw_frame (f);
538 }
539}
540
541static void
542unwind_popup (void)
543{
544 if (!popup_activated_p)
545 emacs_abort ();
546 --popup_activated_p;
547}
548
549static Lisp_Object
550haiku_create_frame (Lisp_Object parms, int ttip_p)
551{
552 struct frame *f;
553 Lisp_Object frame, tem;
554 Lisp_Object name;
555 bool minibuffer_only = false;
556 bool face_change_before = face_change;
557 long window_prompting = 0;
558 ptrdiff_t count = SPECPDL_INDEX ();
559 Lisp_Object display;
560 struct haiku_display_info *dpyinfo = NULL;
561 struct kboard *kb;
562
563 parms = Fcopy_alist (parms);
564
565 Vx_resource_name = Vinvocation_name;
566
567 display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0,
568 RES_TYPE_STRING);
569 if (EQ (display, Qunbound))
570 display = Qnil;
571 dpyinfo = check_haiku_display_info (display);
572 kb = dpyinfo->terminal->kboard;
573
574 if (!dpyinfo->terminal->name)
575 error ("Terminal is not live, can't create new frames on it");
576
577 name = gui_display_get_arg (dpyinfo, parms, Qname, 0, 0,
578 RES_TYPE_STRING);
579 if (!STRINGP (name)
580 && ! EQ (name, Qunbound)
581 && ! NILP (name))
582 error ("Invalid frame name--not a string or nil");
583
584 if (STRINGP (name))
585 Vx_resource_name = name;
586
587 block_input ();
588
589 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
590 /* No need to protect DISPLAY because that's not used after passing
591 it to make_frame_without_minibuffer. */
592 frame = Qnil;
593 tem = gui_display_get_arg (dpyinfo, parms, Qminibuffer,
594 "minibuffer", "Minibuffer",
595 RES_TYPE_SYMBOL);
596 if (ttip_p)
597 f = make_frame (0);
598 else if (EQ (tem, Qnone) || NILP (tem))
599 f = make_frame_without_minibuffer (Qnil, kb, display);
600 else if (EQ (tem, Qonly))
601 {
602 f = make_minibuffer_frame ();
603 minibuffer_only = 1;
604 }
605 else if (WINDOWP (tem))
606 f = make_frame_without_minibuffer (tem, kb, display);
607 else
608 f = make_frame (1);
609 XSETFRAME (frame, f);
610
611 f->terminal = dpyinfo->terminal;
612
613 f->output_method = output_haiku;
614 f->output_data.haiku = xzalloc (sizeof *f->output_data.haiku);
615
616 f->output_data.haiku->pending_zoom_x = INT_MIN;
617 f->output_data.haiku->pending_zoom_y = INT_MIN;
618 f->output_data.haiku->pending_zoom_width = INT_MIN;
619 f->output_data.haiku->pending_zoom_height = INT_MIN;
620
621 if (ttip_p)
622 f->wants_modeline = false;
623
624 fset_icon_name (f, gui_display_get_arg (dpyinfo, parms, Qicon_name,
625 "iconName", "Title",
626 RES_TYPE_STRING));
627 if (! STRINGP (f->icon_name) || ttip_p)
628 fset_icon_name (f, Qnil);
629
630 FRAME_DISPLAY_INFO (f) = dpyinfo;
631
632 /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */
633 if (!ttip_p)
634 record_unwind_protect (unwind_create_frame, frame);
635 else
636 record_unwind_protect (unwind_create_tip_frame, frame);
637
638 FRAME_OUTPUT_DATA (f)->parent_desc = NULL;
639 FRAME_OUTPUT_DATA (f)->explicit_parent = 0;
640
641 /* Set the name; the functions to which we pass f expect the name to
642 be set. */
643 if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
644 {
645 fset_name (f, Vinvocation_name);
646 f->explicit_name = 0;
647 }
648 else
649 {
650 fset_name (f, name);
651 f->explicit_name = 1;
652 specbind (Qx_resource_name, name);
653 }
654
655#ifdef USE_BE_CAIRO
656 register_font_driver (&ftcrfont_driver, f);
657#ifdef HAVE_HARFBUZZ
658 register_font_driver (&ftcrhbfont_driver, f);
659#endif
660#endif
661 register_font_driver (&haikufont_driver, f);
662
663 f->tooltip = ttip_p;
664
665 image_cache_refcount =
666 FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
667
668 gui_default_parameter (f, parms, Qfont_backend, Qnil,
669 "fontBackend", "FontBackend", RES_TYPE_STRING);
670
671 FRAME_RIF (f)->default_font_parameter (f, parms);
672
673 unblock_input ();
674
675 gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
676 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
677 gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (ttip_p ? 1 : 2),
678 "internalBorderWidth", "InternalBorderWidth",
679 RES_TYPE_NUMBER);
680 gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil,
681 "childFrameBorderWidth", "childFrameBorderWidth",
682 RES_TYPE_NUMBER);
683 gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
684 NULL, NULL, RES_TYPE_NUMBER);
685 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
686 NULL, NULL, RES_TYPE_NUMBER);
687 gui_default_parameter (f, parms, Qvertical_scroll_bars, !ttip_p ? Qt : Qnil,
688 "verticalScrollBars", "VerticalScrollBars",
689 RES_TYPE_SYMBOL);
690 gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
691 "horizontalScrollBars", "HorizontalScrollBars",
692 RES_TYPE_SYMBOL);
693 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
694 "foreground", "Foreground", RES_TYPE_STRING);
695 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
696 "background", "Background", RES_TYPE_STRING);
697 gui_default_parameter (f, parms, Qline_spacing, Qnil,
698 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
699 gui_default_parameter (f, parms, Qleft_fringe, Qnil,
700 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
701 gui_default_parameter (f, parms, Qright_fringe, Qnil,
702 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
703 gui_default_parameter (f, parms, Qno_special_glyphs, ttip_p ? Qnil : Qt,
704 NULL, NULL, RES_TYPE_BOOLEAN);
705
706 init_frame_faces (f);
707
708 /* Read comment about this code in corresponding place in xfns.c. */
709 tem = gui_display_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL,
710 RES_TYPE_NUMBER);
711 if (FIXNUMP (tem))
712 store_frame_param (f, Qmin_width, tem);
713 tem = gui_display_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL,
714 RES_TYPE_NUMBER);
715 if (FIXNUMP (tem))
716 store_frame_param (f, Qmin_height, tem);
717 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
718 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1,
719 Qx_create_frame_1);
720
721 if (!ttip_p)
722 {
723 gui_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL);
724 gui_default_parameter (f, parms, Qno_focus_on_map, Qnil,
725 NULL, NULL, RES_TYPE_BOOLEAN);
726 gui_default_parameter (f, parms, Qno_accept_focus, Qnil,
727 NULL, NULL, RES_TYPE_BOOLEAN);
728
729 /* The resources controlling the menu-bar, tool-bar, and tab-bar are
730 processed specially at startup, and reflected in the mode
731 variables; ignore them here. */
732 gui_default_parameter (f, parms, Qmenu_bar_lines,
733 NILP (Vmenu_bar_mode)
734 ? make_fixnum (0) : make_fixnum (1),
735 NULL, NULL, RES_TYPE_NUMBER);
736 gui_default_parameter (f, parms, Qtab_bar_lines,
737 NILP (Vtab_bar_mode)
738 ? make_fixnum (0) : make_fixnum (1),
739 NULL, NULL, RES_TYPE_NUMBER);
740 gui_default_parameter (f, parms, Qtool_bar_lines,
741 NILP (Vtool_bar_mode)
742 ? make_fixnum (0) : make_fixnum (1),
743 NULL, NULL, RES_TYPE_NUMBER);
744 gui_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate",
745 "BufferPredicate", RES_TYPE_SYMBOL);
746 gui_default_parameter (f, parms, Qtitle, Qnil, "title", "Title",
747 RES_TYPE_STRING);
748 }
749
750 parms = get_geometry_from_preferences (dpyinfo, parms);
751 window_prompting = gui_figure_window_size (f, parms, false, true);
752
753 if (ttip_p)
754 {
755 /* No fringes on tip frame. */
756 f->fringe_cols = 0;
757 f->left_fringe_width = 0;
758 f->right_fringe_width = 0;
759 /* No dividers on tip frame. */
760 f->right_divider_width = 0;
761 f->bottom_divider_width = 0;
762 }
763
764 tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0,
765 RES_TYPE_BOOLEAN);
766 f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !NILP (tem));
767
768 /* Add `tooltip' frame parameter's default value. */
769 if (NILP (Fframe_parameter (frame, Qtooltip)) && ttip_p)
770 Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil));
771
772#define ASSIGN_CURSOR(cursor, be_cursor) \
773 (FRAME_OUTPUT_DATA (f)->cursor = be_cursor)
774
775 ASSIGN_CURSOR (text_cursor, BCursor_create_i_beam ());
776 ASSIGN_CURSOR (nontext_cursor, BCursor_create_default ());
777 ASSIGN_CURSOR (modeline_cursor, BCursor_create_modeline ());
778 ASSIGN_CURSOR (hand_cursor, BCursor_create_grab ());
779 ASSIGN_CURSOR (hourglass_cursor, BCursor_create_progress_cursor ());
780 ASSIGN_CURSOR (horizontal_drag_cursor,
781 BCursor_from_id (CURSOR_ID_RESIZE_EAST_WEST));
782 ASSIGN_CURSOR (vertical_drag_cursor,
783 BCursor_from_id (CURSOR_ID_RESIZE_NORTH_SOUTH));
784 ASSIGN_CURSOR (left_edge_cursor,
785 BCursor_from_id (CURSOR_ID_RESIZE_WEST));
786 ASSIGN_CURSOR (top_left_corner_cursor,
787 BCursor_from_id (CURSOR_ID_RESIZE_NORTH_WEST));
788 ASSIGN_CURSOR (top_edge_cursor,
789 BCursor_from_id (CURSOR_ID_RESIZE_NORTH));
790 ASSIGN_CURSOR (top_right_corner_cursor,
791 BCursor_from_id (CURSOR_ID_RESIZE_NORTH_EAST));
792 ASSIGN_CURSOR (right_edge_cursor,
793 BCursor_from_id (CURSOR_ID_RESIZE_EAST));
794 ASSIGN_CURSOR (bottom_right_corner_cursor,
795 BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_EAST));
796 ASSIGN_CURSOR (bottom_edge_cursor,
797 BCursor_from_id (CURSOR_ID_RESIZE_SOUTH));
798 ASSIGN_CURSOR (bottom_left_corner_cursor,
799 BCursor_from_id (CURSOR_ID_RESIZE_SOUTH_WEST));
800 ASSIGN_CURSOR (no_cursor,
801 BCursor_from_id (CURSOR_ID_NO_CURSOR));
802
803 ASSIGN_CURSOR (current_cursor, FRAME_OUTPUT_DATA (f)->text_cursor);
804#undef ASSIGN_CURSOR
805
806
807 if (ttip_p)
808 f->no_split = true;
809 f->terminal->reference_count++;
810
811 FRAME_OUTPUT_DATA (f)->window = BWindow_new (&FRAME_OUTPUT_DATA (f)->view);
812 if (!FRAME_OUTPUT_DATA (f)->window)
813 xsignal1 (Qerror, build_unibyte_string ("Could not create window"));
814
815 if (!minibuffer_only && !ttip_p && FRAME_EXTERNAL_MENU_BAR (f))
816 initialize_frame_menubar (f);
817
818 FRAME_OUTPUT_DATA (f)->window_desc = FRAME_OUTPUT_DATA (f)->window;
819
820 Vframe_list = Fcons (frame, Vframe_list);
821
822 Lisp_Object parent_frame = gui_display_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL,
823 RES_TYPE_SYMBOL);
824
825 if (EQ (parent_frame, Qunbound)
826 || NILP (parent_frame)
827 || !FRAMEP (parent_frame)
828 || !FRAME_LIVE_P (XFRAME (parent_frame)))
829 parent_frame = Qnil;
830
831 fset_parent_frame (f, parent_frame);
832 store_frame_param (f, Qparent_frame, parent_frame);
833
834 if (!NILP (parent_frame))
835 haiku_set_parent_frame (f, parent_frame, Qnil);
836
837 gui_default_parameter (f, parms, Qundecorated, Qnil, NULL, NULL, RES_TYPE_BOOLEAN);
838
839 gui_default_parameter (f, parms, Qicon_type, Qnil,
840 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
841 if (ttip_p)
842 {
843 gui_default_parameter (f, parms, Qundecorated, Qt, NULL, NULL, RES_TYPE_BOOLEAN);
844 gui_default_parameter (f, parms, Qno_accept_focus, Qt, NULL, NULL,
845 RES_TYPE_BOOLEAN);
846 }
847 else
848 {
849 gui_default_parameter (f, parms, Qauto_raise, Qnil,
850 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
851 gui_default_parameter (f, parms, Qauto_lower, Qnil,
852 "autoLower", "AutoLower", RES_TYPE_BOOLEAN);
853 gui_default_parameter (f, parms, Qcursor_type, Qbox,
854 "cursorType", "CursorType", RES_TYPE_SYMBOL);
855 gui_default_parameter (f, parms, Qscroll_bar_width, Qnil,
856 "scrollBarWidth", "ScrollBarWidth",
857 RES_TYPE_NUMBER);
858 gui_default_parameter (f, parms, Qscroll_bar_height, Qnil,
859 "scrollBarHeight", "ScrollBarHeight",
860 RES_TYPE_NUMBER);
861 gui_default_parameter (f, parms, Qalpha, Qnil,
862 "alpha", "Alpha", RES_TYPE_NUMBER);
863 gui_default_parameter (f, parms, Qfullscreen, Qnil,
864 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
865 }
866
867 gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
868 "inhibitDoubleBuffering", "InhibitDoubleBuffering",
869 RES_TYPE_BOOLEAN);
870
871 if (ttip_p)
872 {
873 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
874
875 call2 (Qface_set_after_frame_default, frame, Qnil);
876
877 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
878 {
879 AUTO_FRAME_ARG (arg, Qbackground_color, bg);
880 Fmodify_frame_parameters (frame, arg);
881 }
882 }
883
884 if (ttip_p)
885 face_change = face_change_before;
886
887 f->can_set_window_size = true;
888
889 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
890 0, true, ttip_p ? Qtip_frame : Qx_create_frame_2);
891
892 if (!FRAME_OUTPUT_DATA (f)->explicit_parent && !ttip_p)
893 {
894 Lisp_Object visibility;
895
896 visibility = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
897 RES_TYPE_SYMBOL);
898 if (EQ (visibility, Qunbound))
899 visibility = Qt;
900 if (EQ (visibility, Qicon))
901 haiku_iconify_frame (f);
902 else if (!NILP (visibility))
903 haiku_visualize_frame (f);
904 else /* Qnil */
905 {
906 f->was_invisible = true;
907 }
908 }
909
910 if (!ttip_p)
911 {
912 if (FRAME_HAS_MINIBUF_P (f)
913 && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
914 || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
915 kset_default_minibuffer_frame (kb, frame);
916 }
917
918 for (tem = parms; CONSP (tem); tem = XCDR (tem))
919 if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
920 fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
921
922 if (window_prompting & (USPosition | PPosition))
923 haiku_set_offset (f, f->left_pos, f->top_pos, 1);
924 else
925 BWindow_center_on_screen (FRAME_HAIKU_WINDOW (f));
926
927 /* Make sure windows on this frame appear in calls to next-window
928 and similar functions. */
929 Vwindow_list = Qnil;
930
931 if (ttip_p)
932 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
933 0, true, Qtip_frame);
934
935 return unbind_to (count, frame);
936}
937
938static void
939compute_tip_xy (struct frame *f,
940 Lisp_Object parms, Lisp_Object dx, Lisp_Object dy,
941 int width, int height, int *root_x, int *root_y)
942{
943 Lisp_Object left, top, right, bottom;
944 int min_x = 0, min_y = 0, max_x = 0, max_y = 0;
945
946 /* User-specified position? */
947 left = Fcdr (Fassq (Qleft, parms));
948 top = Fcdr (Fassq (Qtop, parms));
949 right = Fcdr (Fassq (Qright, parms));
950 bottom = Fcdr (Fassq (Qbottom, parms));
951
952 /* Move the tooltip window where the mouse pointer is. Resize and
953 show it. */
954 if ((!FIXNUMP (left) && !FIXNUMP (right))
955 || (!FIXNUMP (top) && !FIXNUMP (bottom)))
956 {
957 int x, y;
958
959 /* Default min and max values. */
960 min_x = 0;
961 min_y = 0;
962 BScreen_px_dim (&max_x, &max_y);
963
964 block_input ();
965 BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y);
966 BView_convert_to_screen (FRAME_HAIKU_VIEW (f), &x, &y);
967 *root_x = x;
968 *root_y = y;
969 unblock_input ();
970 }
971
972 if (FIXNUMP (top))
973 *root_y = XFIXNUM (top);
974 else if (FIXNUMP (bottom))
975 *root_y = XFIXNUM (bottom) - height;
976 else if (*root_y + XFIXNUM (dy) <= min_y)
977 *root_y = min_y; /* Can happen for negative dy */
978 else if (*root_y + XFIXNUM (dy) + height <= max_y)
979 /* It fits below the pointer */
980 *root_y += XFIXNUM (dy);
981 else if (height + XFIXNUM (dy) + min_y <= *root_y)
982 /* It fits above the pointer. */
983 *root_y -= height + XFIXNUM (dy);
984 else
985 /* Put it on the top. */
986 *root_y = min_y;
987
988 if (FIXNUMP (left))
989 *root_x = XFIXNUM (left);
990 else if (FIXNUMP (right))
991 *root_x = XFIXNUM (right) - width;
992 else if (*root_x + XFIXNUM (dx) <= min_x)
993 *root_x = 0; /* Can happen for negative dx */
994 else if (*root_x + XFIXNUM (dx) + width <= max_x)
995 /* It fits to the right of the pointer. */
996 *root_x += XFIXNUM (dx);
997 else if (width + XFIXNUM (dx) + min_x <= *root_x)
998 /* It fits to the left of the pointer. */
999 *root_x -= width + XFIXNUM (dx);
1000 else
1001 /* Put it left justified on the screen -- it ought to fit that way. */
1002 *root_x = min_x;
1003}
1004
1005static Lisp_Object
1006haiku_hide_tip (bool delete)
1007{
1008 if (!NILP (tip_timer))
1009 {
1010 call1 (Qcancel_timer, tip_timer);
1011 tip_timer = Qnil;
1012 }
1013
1014 Lisp_Object it, frame;
1015 FOR_EACH_FRAME (it, frame)
1016 if (FRAME_WINDOW_P (XFRAME (frame)) &&
1017 FRAME_HAIKU_VIEW (XFRAME (frame)))
1018 BView_set_tooltip (FRAME_HAIKU_VIEW (XFRAME (frame)), NULL);
1019
1020 if (NILP (tip_frame)
1021 || (!delete && !NILP (tip_frame)
1022 && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
1023 return Qnil;
1024 else
1025 {
1026 ptrdiff_t count;
1027 Lisp_Object was_open = Qnil;
1028
1029 count = SPECPDL_INDEX ();
1030 specbind (Qinhibit_redisplay, Qt);
1031 specbind (Qinhibit_quit, Qt);
1032
1033 if (!NILP (tip_frame))
1034 {
1035 if (FRAME_LIVE_P (XFRAME (tip_frame)))
1036 {
1037 if (delete)
1038 {
1039 delete_frame (tip_frame, Qnil);
1040 tip_frame = Qnil;
1041 }
1042 else
1043 haiku_unvisualize_frame (XFRAME (tip_frame));
1044
1045 was_open = Qt;
1046 }
1047 else
1048 tip_frame = Qnil;
1049 }
1050 else
1051 tip_frame = Qnil;
1052
1053 return unbind_to (count, was_open);
1054 }
1055}
1056
1057static void
1058haiku_set_undecorated (struct frame *f, Lisp_Object new_value,
1059 Lisp_Object old_value)
1060{
1061 if (EQ (new_value, old_value))
1062 return;
1063
1064 block_input ();
1065 FRAME_UNDECORATED (f) = !NILP (new_value);
1066 BWindow_change_decoration (FRAME_HAIKU_WINDOW (f), NILP (new_value));
1067 unblock_input ();
1068}
1069
1070static void
1071haiku_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1072{
1073 if (FRAME_TOOLTIP_P (f))
1074 return;
1075 int nlines;
1076 if (TYPE_RANGED_FIXNUMP (int, value))
1077 nlines = XFIXNUM (value);
1078 else
1079 nlines = 0;
1080
1081 fset_redisplay (f);
1082
1083 FRAME_MENU_BAR_LINES (f) = 0;
1084 FRAME_MENU_BAR_HEIGHT (f) = 0;
1085
1086 if (nlines)
1087 {
1088 FRAME_EXTERNAL_MENU_BAR (f) = 1;
1089 if (FRAME_HAIKU_P (f) && !FRAME_HAIKU_MENU_BAR (f))
1090 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = 1;
1091 }
1092 else
1093 {
1094 if (FRAME_EXTERNAL_MENU_BAR (f))
1095 free_frame_menubar (f);
1096 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1097 if (FRAME_HAIKU_P (f))
1098 FRAME_HAIKU_MENU_BAR (f) = 0;
1099 }
1100
1101 adjust_frame_glyphs (f);
1102}
1103
1104/* Return geometric attributes of FRAME. According to the value of
1105 ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the inner
1106 edges of FRAME, the root window edges of frame (Qroot_edges). Any
1107 other value means to return the geometry as returned by
1108 Fx_frame_geometry. */
1109static Lisp_Object
1110frame_geometry (Lisp_Object frame, Lisp_Object attribute)
1111{
1112 struct frame *f = decode_live_frame (frame);
1113 check_window_system (f);
1114
1115 if (EQ (attribute, Qouter_edges))
1116 return list4i (f->left_pos, f->top_pos,
1117 f->left_pos, f->top_pos);
1118 else if (EQ (attribute, Qnative_edges))
1119 return list4i (f->left_pos, f->top_pos,
1120 f->left_pos + FRAME_PIXEL_WIDTH (f),
1121 f->top_pos + FRAME_PIXEL_HEIGHT (f));
1122 else if (EQ (attribute, Qinner_edges))
1123 return list4i (f->left_pos + FRAME_INTERNAL_BORDER_WIDTH (f),
1124 f->top_pos + FRAME_INTERNAL_BORDER_WIDTH (f) +
1125 FRAME_MENU_BAR_HEIGHT (f) + FRAME_TOOL_BAR_HEIGHT (f),
1126 f->left_pos - FRAME_INTERNAL_BORDER_WIDTH (f) +
1127 FRAME_PIXEL_WIDTH (f),
1128 f->top_pos + FRAME_PIXEL_HEIGHT (f) -
1129 FRAME_INTERNAL_BORDER_WIDTH (f));
1130
1131 else
1132 return
1133 list (Fcons (Qouter_position,
1134 Fcons (make_fixnum (f->left_pos),
1135 make_fixnum (f->top_pos))),
1136 Fcons (Qouter_size,
1137 Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
1138 make_fixnum (FRAME_PIXEL_HEIGHT (f)))),
1139 Fcons (Qexternal_border_size,
1140 Fcons (make_fixnum (0), make_fixnum (0))),
1141 Fcons (Qtitle_bar_size,
1142 Fcons (make_fixnum (0), make_fixnum (0))),
1143 Fcons (Qmenu_bar_external, Qnil),
1144 Fcons (Qmenu_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
1145 (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
1146 make_fixnum (FRAME_MENU_BAR_HEIGHT (f)))),
1147 Fcons (Qtool_bar_external, Qnil),
1148 Fcons (Qtool_bar_position, Qtop),
1149 Fcons (Qtool_bar_size, Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f) -
1150 (FRAME_INTERNAL_BORDER_WIDTH (f) * 2)),
1151 make_fixnum (FRAME_TOOL_BAR_HEIGHT (f)))),
1152 Fcons (Qinternal_border_width, make_fixnum (FRAME_INTERNAL_BORDER_WIDTH (f))));
1153}
1154
1155void
1156haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1157{
1158 CHECK_STRING (arg);
1159
1160 block_input ();
1161 Emacs_Color color;
1162
1163 if (haiku_get_color (SSDATA (arg), &color))
1164 {
1165 store_frame_param (f, Qbackground_color, oldval);
1166 unblock_input ();
1167 error ("Bad color");
1168 }
1169
1170 FRAME_OUTPUT_DATA (f)->cursor_fg = color.pixel;
1171 FRAME_BACKGROUND_PIXEL (f) = color.pixel;
1172
1173 if (FRAME_HAIKU_VIEW (f))
1174 {
1175 struct face *defface;
1176
1177 BView_draw_lock (FRAME_HAIKU_VIEW (f));
1178 BView_SetViewColor (FRAME_HAIKU_VIEW (f), color.pixel);
1179 BView_draw_unlock (FRAME_HAIKU_VIEW (f));
1180
1181 defface = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID);
1182 if (defface)
1183 {
1184 defface->background = color.pixel;
1185 update_face_from_frame_parameter (f, Qbackground_color, arg);
1186 clear_frame (f);
1187 }
1188 }
1189
1190 if (FRAME_VISIBLE_P (f))
1191 SET_FRAME_GARBAGED (f);
1192 unblock_input ();
1193}
1194
1195void
1196haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1197{
1198 CHECK_STRING (arg);
1199
1200 block_input ();
1201 Emacs_Color color;
1202
1203 if (haiku_get_color (SSDATA (arg), &color))
1204 {
1205 store_frame_param (f, Qcursor_color, oldval);
1206 unblock_input ();
1207 error ("Bad color");
1208 }
1209
1210 FRAME_CURSOR_COLOR (f) = color;
1211 if (FRAME_VISIBLE_P (f))
1212 {
1213 gui_update_cursor (f, 0);
1214 gui_update_cursor (f, 1);
1215 }
1216 update_face_from_frame_parameter (f, Qcursor_color, arg);
1217 unblock_input ();
1218}
1219
1220void
1221haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1222{
1223 set_frame_cursor_types (f, arg);
1224}
1225
1226unsigned long
1227haiku_get_pixel (haiku bitmap, int x, int y)
1228{
1229 unsigned char *data;
1230 int32_t bytes_per_row;
1231 int mono_p;
1232 int left;
1233 int right;
1234 int top;
1235 int bottom;
1236
1237 data = BBitmap_data (bitmap);
1238 BBitmap_dimensions (bitmap, &left, &top, &right, &bottom,
1239 &bytes_per_row, &mono_p);
1240
1241 if (x < left || x > right || y < top || y > bottom)
1242 emacs_abort ();
1243
1244 if (!mono_p)
1245 return ((uint32_t *) (data + (bytes_per_row * y)))[x];
1246
1247 int byte = y * bytes_per_row + x / 8;
1248 return data[byte] & (1 << (x % 8));
1249}
1250
1251void
1252haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel)
1253{
1254 unsigned char *data;
1255 int32_t bytes_per_row;
1256 int mono_p;
1257 int left;
1258 int right;
1259 int top;
1260 int bottom;
1261
1262 data = BBitmap_data (bitmap);
1263 BBitmap_dimensions (bitmap, &left, &top, &right, &bottom,
1264 &bytes_per_row, &mono_p);
1265
1266 if (x < left || x > right || y < top || y > bottom)
1267 emacs_abort ();
1268
1269 if (mono_p)
1270 {
1271 ptrdiff_t off = y * bytes_per_row;
1272 ptrdiff_t bit = x % 8;
1273 ptrdiff_t xoff = x / 8;
1274
1275 unsigned char *byte = data + off + xoff;
1276 if (!pixel)
1277 *byte &= ~(1 << bit);
1278 else
1279 *byte |= 1 << bit;
1280 }
1281 else
1282 ((uint32_t *) (data + (bytes_per_row * y)))[x] = pixel;
1283}
1284
1285void
1286haiku_free_frame_resources (struct frame *f)
1287{
1288 haiku window, drawable, mbar;
1289 Mouse_HLInfo *hlinfo;
1290 struct haiku_display_info *dpyinfo;
1291 Lisp_Object bar;
1292 struct scroll_bar *b;
1293
1294 block_input ();
1295 check_window_system (f);
1296
1297 hlinfo = MOUSE_HL_INFO (f);
1298 window = FRAME_HAIKU_WINDOW (f);
1299 drawable = FRAME_HAIKU_VIEW (f);
1300 mbar = FRAME_HAIKU_MENU_BAR (f);
1301 dpyinfo = FRAME_DISPLAY_INFO (f);
1302
1303 free_frame_faces (f);
1304
1305 /* Free scroll bars */
1306 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
1307 {
1308 b = XSCROLL_BAR (bar);
1309 haiku_scroll_bar_remove (b);
1310 }
1311
1312 if (f == dpyinfo->highlight_frame)
1313 dpyinfo->highlight_frame = 0;
1314 if (f == dpyinfo->focused_frame)
1315 dpyinfo->focused_frame = 0;
1316 if (f == dpyinfo->last_mouse_motion_frame)
1317 dpyinfo->last_mouse_motion_frame = NULL;
1318 if (f == dpyinfo->last_mouse_frame)
1319 dpyinfo->last_mouse_frame = NULL;
1320 if (f == dpyinfo->focus_event_frame)
1321 dpyinfo->focus_event_frame = NULL;
1322
1323 if (f == hlinfo->mouse_face_mouse_frame)
1324 reset_mouse_highlight (hlinfo);
1325
1326 if (mbar)
1327 {
1328 BMenuBar_delete (mbar);
1329 if (f->output_data.haiku->menu_bar_open_p)
1330 {
1331 --popup_activated_p;
1332 f->output_data.haiku->menu_bar_open_p = 0;
1333 }
1334 }
1335
1336 if (drawable)
1337 BView_emacs_delete (drawable);
1338
1339 if (window)
1340 BWindow_quit (window);
1341
1342 /* Free cursors */
1343
1344 BCursor_delete (f->output_data.haiku->text_cursor);
1345 BCursor_delete (f->output_data.haiku->nontext_cursor);
1346 BCursor_delete (f->output_data.haiku->modeline_cursor);
1347 BCursor_delete (f->output_data.haiku->hand_cursor);
1348 BCursor_delete (f->output_data.haiku->hourglass_cursor);
1349 BCursor_delete (f->output_data.haiku->horizontal_drag_cursor);
1350 BCursor_delete (f->output_data.haiku->vertical_drag_cursor);
1351 BCursor_delete (f->output_data.haiku->left_edge_cursor);
1352 BCursor_delete (f->output_data.haiku->top_left_corner_cursor);
1353 BCursor_delete (f->output_data.haiku->top_edge_cursor);
1354 BCursor_delete (f->output_data.haiku->top_right_corner_cursor);
1355 BCursor_delete (f->output_data.haiku->right_edge_cursor);
1356 BCursor_delete (f->output_data.haiku->bottom_right_corner_cursor);
1357 BCursor_delete (f->output_data.haiku->bottom_edge_cursor);
1358 BCursor_delete (f->output_data.haiku->bottom_left_corner_cursor);
1359 BCursor_delete (f->output_data.haiku->no_cursor);
1360
1361 xfree (FRAME_OUTPUT_DATA (f));
1362 FRAME_OUTPUT_DATA (f) = NULL;
1363
1364 unblock_input ();
1365}
1366
1367void
1368haiku_iconify_frame (struct frame *frame)
1369{
1370 if (FRAME_ICONIFIED_P (frame))
1371 return;
1372
1373 block_input ();
1374
1375 SET_FRAME_VISIBLE (frame, false);
1376 SET_FRAME_ICONIFIED (frame, true);
1377
1378 BWindow_iconify (FRAME_HAIKU_WINDOW (frame));
1379
1380 unblock_input ();
1381}
1382
1383void
1384haiku_visualize_frame (struct frame *f)
1385{
1386 block_input ();
1387
1388 if (!FRAME_VISIBLE_P (f))
1389 {
1390 if (FRAME_NO_FOCUS_ON_MAP (f))
1391 BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f), 1);
1392 BWindow_set_visible (FRAME_HAIKU_WINDOW (f), 1);
1393 if (FRAME_NO_FOCUS_ON_MAP (f) &&
1394 !FRAME_NO_ACCEPT_FOCUS (f))
1395 BWindow_set_avoid_focus (FRAME_HAIKU_WINDOW (f), 0);
1396
1397 haiku_set_offset (f, f->left_pos, f->top_pos, 0);
1398
1399 SET_FRAME_VISIBLE (f, 1);
1400 SET_FRAME_ICONIFIED (f, 0);
1401 }
1402
1403 unblock_input ();
1404}
1405
1406void
1407haiku_unvisualize_frame (struct frame *f)
1408{
1409 block_input ();
1410
1411 BWindow_set_visible (FRAME_HAIKU_WINDOW (f), 0);
1412 SET_FRAME_VISIBLE (f, 0);
1413 SET_FRAME_ICONIFIED (f, 0);
1414
1415 unblock_input ();
1416}
1417
1418void
1419haiku_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1420{
1421 int old_width = FRAME_INTERNAL_BORDER_WIDTH (f);
1422 int new_width = check_int_nonnegative (arg);
1423
1424 if (new_width == old_width)
1425 return;
1426 f->internal_border_width = new_width;
1427
1428 if (FRAME_HAIKU_WINDOW (f))
1429 {
1430 adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width);
1431 haiku_clear_under_internal_border (f);
1432 }
1433
1434 SET_FRAME_GARBAGED (f);
1435}
1436
1437void
1438haiku_set_frame_visible_invisible (struct frame *f, bool visible_p)
1439{
1440 if (visible_p)
1441 haiku_visualize_frame (f);
1442 else
1443 haiku_unvisualize_frame (f);
1444}
1445
1446void
1447frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1448{
1449 block_input ();
1450
1451 BView_convert_to_screen (FRAME_HAIKU_VIEW (f), &pix_x, &pix_y);
1452 be_warp_pointer (pix_x, pix_y);
1453
1454 unblock_input ();
1455}
1456
1457void
1458haiku_query_color (uint32_t col, Emacs_Color *color_def)
1459{
1460 color_def->red = RED_FROM_ULONG (col) * 257;
1461 color_def->green = GREEN_FROM_ULONG (col) * 257;
1462 color_def->blue = BLUE_FROM_ULONG (col) * 257;
1463
1464 color_def->pixel = col;
1465}
1466
1467Display_Info *
1468check_x_display_info (Lisp_Object object)
1469{
1470 return check_haiku_display_info (object);
1471}
1472
1473/* Rename frame F to NAME. If NAME is nil, set F's name to "GNU
1474 Emacs". If EXPLICIT_P is non-zero, that indicates Lisp code is
1475 setting the name, not redisplay; in that case, set F's name to NAME
1476 and set F->explicit_name; if NAME is nil, clear F->explicit_name.
1477
1478 If EXPLICIT_P is zero, it means redisplay is setting the name; the
1479 name provided will be ignored if explicit_name is set. */
1480void
1481haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p)
1482{
1483 if (explicit_p)
1484 {
1485 if (f->explicit_name && NILP (name))
1486 update_mode_lines = 24;
1487
1488 f->explicit_name = !NILP (name);
1489 }
1490 else if (f->explicit_name)
1491 return;
1492
1493 if (NILP (name))
1494 name = build_unibyte_string ("GNU Emacs");
1495
1496 if (!NILP (Fstring_equal (name, f->name)))
1497 return;
1498
1499 fset_name (f, name);
1500
1501 if (!NILP (f->title))
1502 name = f->title;
1503
1504 haiku_set_title_bar_text (f, name);
1505}
1506
1507static void
1508haiku_set_inhibit_double_buffering (struct frame *f,
1509 Lisp_Object new_value,
1510 Lisp_Object old_value)
1511{
1512 block_input ();
1513 if (FRAME_HAIKU_WINDOW (f))
1514 {
1515 if (NILP (new_value))
1516 {
1517 EmacsView_set_up_double_buffering (FRAME_HAIKU_VIEW (f));
1518 if (!NILP (old_value))
1519 {
1520 SET_FRAME_GARBAGED (f);
1521 expose_frame (f, 0, 0, 0, 0);
1522 }
1523 }
1524 else
1525 EmacsView_disable_double_buffering (FRAME_HAIKU_VIEW (f));
1526 }
1527 unblock_input ();
1528}
1529
1530
1531
1532DEFUN ("haiku-set-mouse-absolute-pixel-position",
1533 Fhaiku_set_mouse_absolute_pixel_position,
1534 Shaiku_set_mouse_absolute_pixel_position, 2, 2, 0,
1535 doc: /* Move mouse pointer to a pixel position at (X, Y). The
1536coordinates X and Y are interpreted to start from the top-left
1537corner of the screen. */)
1538 (Lisp_Object x, Lisp_Object y)
1539{
1540 int xval = check_integer_range (x, INT_MIN, INT_MAX);
1541 int yval = check_integer_range (y, INT_MIN, INT_MAX);
1542
1543 if (!x_display_list)
1544 error ("Window system not initialized");
1545
1546 block_input ();
1547 be_warp_pointer (xval, yval);
1548 unblock_input ();
1549 return Qnil;
1550}
1551
1552DEFUN ("haiku-mouse-absolute-pixel-position", Fhaiku_mouse_absolute_pixel_position,
1553 Shaiku_mouse_absolute_pixel_position, 0, 0, 0,
1554 doc: /* Return absolute position of mouse cursor in pixels.
1555The position is returned as a cons cell (X . Y) of the coordinates of
1556the mouse cursor position in pixels relative to a position (0, 0) of the
1557selected frame's display. */)
1558 (void)
1559{
1560 if (!x_display_list)
1561 return Qnil;
1562
1563 struct frame *f = SELECTED_FRAME ();
1564
1565 if (FRAME_INITIAL_P (f) || !FRAME_HAIKU_P (f)
1566 || !FRAME_HAIKU_VIEW (f))
1567 return Qnil;
1568
1569 block_input ();
1570 void *view = FRAME_HAIKU_VIEW (f);
1571
1572 int x, y;
1573 BView_get_mouse (view, &x, &y);
1574 BView_convert_to_screen (view, &x, &y);
1575 unblock_input ();
1576
1577 return Fcons (make_fixnum (x), make_fixnum (y));
1578}
1579
1580DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
1581 doc: /* SKIP: real doc in xfns.c. */)
1582 (Lisp_Object terminal)
1583{
1584 return Qt;
1585}
1586
1587DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
1588 doc: /* SKIP: real doc in xfns.c. */)
1589 (Lisp_Object color, Lisp_Object frame)
1590{
1591 Emacs_Color col;
1592 CHECK_STRING (color);
1593 decode_window_system_frame (frame);
1594
1595 return haiku_get_color (SSDATA (color), &col) ? Qnil : Qt;
1596}
1597
1598DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
1599 doc: /* SKIP: real doc in xfns.c. */)
1600 (Lisp_Object color, Lisp_Object frame)
1601{
1602 Emacs_Color col;
1603 CHECK_STRING (color);
1604 decode_window_system_frame (frame);
1605
1606 block_input ();
1607 if (haiku_get_color (SSDATA (color), &col))
1608 {
1609 unblock_input ();
1610 return Qnil;
1611 }
1612 unblock_input ();
1613 return list3i (lrint (col.red), lrint (col.green), lrint (col.blue));
1614}
1615
1616DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
1617 0, 1, 0,
1618 doc: /* SKIP: real doc in xfns.c. */)
1619 (Lisp_Object terminal)
1620{
1621 return Qnil;
1622}
1623
1624DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
1625 1, 3, 0,
1626 doc: /* SKIP: real doc in xfns.c. */)
1627 (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
1628{
1629 struct haiku_display_info *dpy_info;
1630 CHECK_STRING (display);
1631
1632 if (NILP (Fstring_equal (display, build_string ("be"))))
1633 !NILP (must_succeed) ? fatal ("Bad display") : error ("Bad display");
1634 dpy_info = haiku_term_init ();
1635
1636 if (!dpy_info)
1637 !NILP (must_succeed) ? fatal ("Display not responding") :
1638 error ("Display not responding");
1639
1640 return Qnil;
1641}
1642
1643DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
1644 0, 1, 0,
1645 doc: /* SKIP: real doc in xfns.c. */)
1646 (Lisp_Object terminal)
1647
1648{
1649 check_haiku_display_info (terminal);
1650
1651 int width, height;
1652 BScreen_px_dim (&width, &height);
1653 return make_fixnum (width);
1654}
1655
1656DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_height,
1657 0, 1, 0,
1658 doc: /* SKIP: real doc in xfns.c. */)
1659 (Lisp_Object terminal)
1660
1661{
1662 check_haiku_display_info (terminal);
1663
1664 int width, height;
1665 BScreen_px_dim (&width, &height);
1666 return make_fixnum (width);
1667}
1668
1669DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
1670 doc: /* SKIP: real doc in xfns.c. */)
1671 (Lisp_Object terminal)
1672{
1673 struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal);
1674
1675 int width, height;
1676 BScreen_px_dim (&width, &height);
1677
1678 return make_fixnum (height / (dpyinfo->resy / 25.4));
1679}
1680
1681
1682DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
1683 doc: /* SKIP: real doc in xfns.c. */)
1684 (Lisp_Object terminal)
1685{
1686 struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal);
1687
1688 int width, height;
1689 BScreen_px_dim (&width, &height);
1690
1691 return make_fixnum (height / (dpyinfo->resy / 25.4));
1692}
1693
1694DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1695 1, 1, 0,
1696 doc: /* SKIP: real doc in xfns.c. */)
1697 (Lisp_Object parms)
1698{
1699 return haiku_create_frame (parms, 0);
1700}
1701
1702DEFUN ("x-display-visual-class", Fx_display_visual_class,
1703 Sx_display_visual_class, 0, 1, 0,
1704 doc: /* SKIP: real doc in xfns.c. */)
1705 (Lisp_Object terminal)
1706{
1707 check_haiku_display_info (terminal);
1708
1709 int planes = be_get_display_planes ();
1710
1711 if (planes == 8)
1712 return intern ("static-color");
1713 else if (planes == 16 || planes == 15)
1714 return intern ("pseudo-color");
1715
1716 return intern ("direct-color");
1717}
1718
1719DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
1720 doc: /* SKIP: real doc in xfns.c. */)
1721 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms,
1722 Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
1723{
1724 struct frame *tip_f;
1725 struct window *w;
1726 int root_x, root_y;
1727 struct buffer *old_buffer;
1728 struct text_pos pos;
1729 int width, height;
1730 int old_windows_or_buffers_changed = windows_or_buffers_changed;
1731 ptrdiff_t count = SPECPDL_INDEX ();
1732 ptrdiff_t count_1;
1733 Lisp_Object window, size, tip_buf;
1734
1735 AUTO_STRING (tip, " *tip*");
1736
1737 specbind (Qinhibit_redisplay, Qt);
1738
1739 CHECK_STRING (string);
1740
1741 if (NILP (frame))
1742 frame = selected_frame;
1743 decode_window_system_frame (frame);
1744
1745 if (NILP (timeout))
1746 timeout = make_fixnum (5);
1747 else
1748 CHECK_FIXNAT (timeout);
1749
1750 if (NILP (dx))
1751 dx = make_fixnum (5);
1752 else
1753 CHECK_FIXNUM (dx);
1754
1755 if (NILP (dy))
1756 dy = make_fixnum (-10);
1757 else
1758 CHECK_FIXNUM (dy);
1759
1760 if (haiku_use_system_tooltips)
1761 {
1762 int root_x, root_y;
1763 CHECK_STRING (string);
1764 if (STRING_MULTIBYTE (string))
1765 string = ENCODE_UTF_8 (string);
1766
1767 if (NILP (frame))
1768 frame = selected_frame;
1769
1770 struct frame *f = decode_window_system_frame (frame);
1771 block_input ();
1772
1773 char *str = xstrdup (SSDATA (string));
1774 int height = be_plain_font_height ();
1775 int width;
1776 char *tok = strtok (str, "\n");
1777 width = be_string_width_with_plain_font (tok);
1778
1779 while ((tok = strtok (NULL, "\n")))
1780 {
1781 height = be_plain_font_height ();
1782 int w = be_string_width_with_plain_font (tok);
1783 if (w > width)
1784 w = width;
1785 }
1786 free (str);
1787
1788 height += 16; /* Default margin. */
1789 width += 16; /* Ditto. Unfortunately there isn't a more
1790 reliable way to get it. */
1791 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
1792 BView_convert_from_screen (FRAME_HAIKU_VIEW (f), &root_x, &root_y);
1793 BView_set_and_show_sticky_tooltip (FRAME_HAIKU_VIEW (f), SSDATA (string),
1794 root_x, root_y);
1795 unblock_input ();
1796 goto start_timer;
1797 }
1798
1799 if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
1800 {
1801 if (FRAME_VISIBLE_P (XFRAME (tip_frame))
1802 && EQ (frame, tip_last_frame)
1803 && !NILP (Fequal_including_properties (string, tip_last_string))
1804 && !NILP (Fequal (parms, tip_last_parms)))
1805 {
1806 /* Only DX and DY have changed. */
1807 tip_f = XFRAME (tip_frame);
1808 if (!NILP (tip_timer))
1809 {
1810 Lisp_Object timer = tip_timer;
1811
1812 tip_timer = Qnil;
1813 call1 (Qcancel_timer, timer);
1814 }
1815
1816 block_input ();
1817 compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
1818 FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
1819 haiku_set_offset (tip_f, root_x, root_y, 1);
1820 haiku_visualize_frame (tip_f);
1821 unblock_input ();
1822
1823 goto start_timer;
1824 }
1825 else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame))
1826 {
1827 bool delete = false;
1828 Lisp_Object tail, elt, parm, last;
1829
1830 /* Check if every parameter in PARMS has the same value in
1831 tip_last_parms. This may destruct tip_last_parms
1832 which, however, will be recreated below. */
1833 for (tail = parms; CONSP (tail); tail = XCDR (tail))
1834 {
1835 elt = XCAR (tail);
1836 parm = Fcar (elt);
1837 /* The left, top, right and bottom parameters are handled
1838 by compute_tip_xy so they can be ignored here. */
1839 if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
1840 && !EQ (parm, Qright) && !EQ (parm, Qbottom))
1841 {
1842 last = Fassq (parm, tip_last_parms);
1843 if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
1844 {
1845 /* We lost, delete the old tooltip. */
1846 delete = true;
1847 break;
1848 }
1849 else
1850 tip_last_parms =
1851 call2 (Qassq_delete_all, parm, tip_last_parms);
1852 }
1853 else
1854 tip_last_parms =
1855 call2 (Qassq_delete_all, parm, tip_last_parms);
1856 }
1857
1858 /* Now check if there's a parameter left in tip_last_parms with a
1859 non-nil value. */
1860 for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail))
1861 {
1862 elt = XCAR (tail);
1863 parm = Fcar (elt);
1864 if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
1865 && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
1866 {
1867 /* We lost, delete the old tooltip. */
1868 delete = true;
1869 break;
1870 }
1871 }
1872
1873 haiku_hide_tip (delete);
1874 }
1875 else
1876 haiku_hide_tip (true);
1877 }
1878 else
1879 haiku_hide_tip (true);
1880
1881 tip_last_frame = frame;
1882 tip_last_string = string;
1883 tip_last_parms = parms;
1884
1885 /* Block input until the tip has been fully drawn, to avoid crashes
1886 when drawing tips in menus. */
1887 block_input ();
1888
1889 if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
1890 {
1891 /* Add default values to frame parameters. */
1892 if (NILP (Fassq (Qname, parms)))
1893 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
1894 if (NILP (Fassq (Qinternal_border_width, parms)))
1895 parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)), parms);
1896 if (NILP (Fassq (Qborder_width, parms)))
1897 parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
1898 if (NILP (Fassq (Qborder_color, parms)))
1899 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")),
1900 parms);
1901 if (NILP (Fassq (Qbackground_color, parms)))
1902 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
1903 parms);
1904
1905 /* Create a frame for the tooltip and record it in the global
1906 variable tip_frame. */
1907
1908 if (NILP (tip_frame = haiku_create_frame (parms, 1)))
1909 {
1910 /* Creating the tip frame failed. */
1911 unblock_input ();
1912 return unbind_to (count, Qnil);
1913 }
1914 }
1915
1916 tip_f = XFRAME (tip_frame);
1917 window = FRAME_ROOT_WINDOW (tip_f);
1918 tip_buf = Fget_buffer_create (tip, Qnil);
1919 /* We will mark the tip window a "pseudo-window" below, and such
1920 windows cannot have display margins. */
1921 bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
1922 bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
1923 set_window_buffer (window, tip_buf, false, false);
1924 w = XWINDOW (window);
1925 w->pseudo_window_p = true;
1926 /* Try to avoid that `other-window' select us (Bug#47207). */
1927 Fset_window_parameter (window, Qno_other_window, Qt);
1928
1929 /* Set up the frame's root window. Note: The following code does not
1930 try to size the window or its frame correctly. Its only purpose is
1931 to make the subsequent text size calculations work. The right
1932 sizes should get installed when the toolkit gets back to us. */
1933 w->left_col = 0;
1934 w->top_line = 0;
1935 w->pixel_left = 0;
1936 w->pixel_top = 0;
1937
1938 if (CONSP (Vx_max_tooltip_size)
1939 && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
1940 && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
1941 {
1942 w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
1943 w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
1944 }
1945 else
1946 {
1947 w->total_cols = 80;
1948 w->total_lines = 40;
1949 }
1950
1951 w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
1952 w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
1953 FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w);
1954 adjust_frame_glyphs (tip_f);
1955
1956 /* Insert STRING into the root window's buffer and fit the frame to
1957 the buffer. */
1958 count_1 = SPECPDL_INDEX ();
1959 old_buffer = current_buffer;
1960 set_buffer_internal_1 (XBUFFER (w->contents));
1961 bset_truncate_lines (current_buffer, Qnil);
1962 specbind (Qinhibit_read_only, Qt);
1963 specbind (Qinhibit_modification_hooks, Qt);
1964 specbind (Qinhibit_point_motion_hooks, Qt);
1965 Ferase_buffer ();
1966 Finsert (1, &string);
1967 clear_glyph_matrix (w->desired_matrix);
1968 clear_glyph_matrix (w->current_matrix);
1969 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
1970 try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
1971 /* Calculate size of tooltip window. */
1972 size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
1973 make_fixnum (w->pixel_height), Qnil);
1974 /* Add the frame's internal border to calculated size. */
1975 width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
1976 height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
1977 /* Calculate position of tooltip frame. */
1978 compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
1979 BWindow_resize (FRAME_HAIKU_WINDOW (tip_f), width, height);
1980 haiku_set_offset (tip_f, root_x, root_y, 1);
1981 BWindow_set_tooltip_decoration (FRAME_HAIKU_WINDOW (tip_f));
1982 BView_set_view_cursor (FRAME_HAIKU_VIEW (tip_f),
1983 FRAME_OUTPUT_DATA (XFRAME (frame))->current_cursor);
1984 SET_FRAME_VISIBLE (tip_f, 1);
1985 BWindow_set_visible (FRAME_HAIKU_WINDOW (tip_f), 1);
1986
1987 w->must_be_updated_p = true;
1988 flush_frame (tip_f);
1989 update_single_window (w);
1990 set_buffer_internal_1 (old_buffer);
1991 unbind_to (count_1, Qnil);
1992 unblock_input ();
1993 windows_or_buffers_changed = old_windows_or_buffers_changed;
1994
1995 start_timer:
1996 /* Let the tip disappear after timeout seconds. */
1997 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
1998 intern ("x-hide-tip"));
1999
2000 return unbind_to (count, Qnil);
2001}
2002
2003DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
2004 doc: /* SKIP: real doc in xfns.c. */)
2005 (void)
2006{
2007 return haiku_hide_tip (!tooltip_reuse_hidden_frame);
2008}
2009
2010DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1, 1, 0,
2011 doc: /* SKIP: real doc in xfns.c. */
2012 attributes: noreturn)
2013 (Lisp_Object terminal)
2014{
2015 check_haiku_display_info (terminal);
2016
2017 error ("Cannot close Haiku displays");
2018}
2019
2020DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
2021 doc: /* SKIP: real doc in xfns.c. */)
2022 (void)
2023{
2024 if (!x_display_list)
2025 return Qnil;
2026
2027 return list1 (XCAR (x_display_list->name_list_element));
2028}
2029
2030DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
2031 doc: /* SKIP: real doc in xfns.c. */)
2032 (Lisp_Object terminal)
2033{
2034 check_haiku_display_info (terminal);
2035 return build_string ("Haiku, Inc.");
2036}
2037
2038DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
2039 doc: /* SKIP: real doc in xfns.c. */)
2040 (Lisp_Object terminal)
2041{
2042 check_haiku_display_info (terminal);
2043 return list3i (5, 1, 1);
2044}
2045
2046DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
2047 doc: /* SKIP: real doc in xfns.c. */)
2048 (Lisp_Object terminal)
2049{
2050 check_haiku_display_info (terminal);
2051 return make_fixnum (be_get_display_screens ());
2052}
2053
2054DEFUN ("haiku-get-version-string", Fhaiku_get_version_string,
2055 Shaiku_get_version_string, 0, 0, 0,
2056 doc: /* Return a string describing the current Haiku version. */)
2057 (void)
2058{
2059 char buf[1024];
2060
2061 be_get_version_string ((char *) &buf, sizeof buf);
2062 return build_string (buf);
2063}
2064
2065DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
2066 0, 1, 0,
2067 doc: /* SKIP: real doc in xfns.c. */)
2068 (Lisp_Object terminal)
2069{
2070 check_haiku_display_info (terminal);
2071
2072 return make_fixnum (be_get_display_color_cells ());
2073}
2074
2075DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
2076 0, 1, 0,
2077 doc: /* SKIP: real doc in xfns.c. */)
2078 (Lisp_Object terminal)
2079{
2080 check_haiku_display_info (terminal);
2081
2082 return make_fixnum (be_get_display_planes ());
2083}
2084
2085DEFUN ("x-double-buffered-p", Fx_double_buffered_p, Sx_double_buffered_p,
2086 0, 1, 0,
2087 doc: /* SKIP: real doc in xfns.c. */)
2088 (Lisp_Object frame)
2089{
2090 struct frame *f = decode_live_frame (frame);
2091 check_window_system (f);
2092
2093 return EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)) ? Qt : Qnil;
2094}
2095
2096DEFUN ("x-display-backing-store", Fx_display_backing_store, Sx_display_backing_store,
2097 0, 1, 0,
2098 doc: /* SKIP: real doc in xfns.c. */)
2099 (Lisp_Object terminal)
2100{
2101 if (FRAMEP (terminal))
2102 {
2103 CHECK_LIVE_FRAME (terminal);
2104 struct frame *f = decode_window_system_frame (terminal);
2105
2106 if (FRAME_HAIKU_VIEW (f) &&
2107 EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)))
2108 return FRAME_PARENT_FRAME (f) ? Qwhen_mapped : Qalways;
2109 else
2110 return Qnot_useful;
2111 }
2112 else
2113 {
2114 check_haiku_display_info (terminal);
2115 return Qnot_useful;
2116 }
2117}
2118
2119DEFUN ("haiku-frame-geometry", Fhaiku_frame_geometry, Shaiku_frame_geometry, 0, 1, 0,
2120 doc: /* Return geometric attributes of FRAME.
2121FRAME must be a live frame and defaults to the selected one. The return
2122value is an association list of the attributes listed below. All height
2123and width values are in pixels.
2124
2125`outer-position' is a cons of the outer left and top edges of FRAME
2126 relative to the origin - the position (0, 0) - of FRAME's display.
2127
2128`outer-size' is a cons of the outer width and height of FRAME. The
2129 outer size includes the title bar and the external borders as well as
2130 any menu and/or tool bar of frame.
2131
2132`external-border-size' is a cons of the horizontal and vertical width of
2133 FRAME's external borders as supplied by the window manager.
2134
2135`title-bar-size' is a cons of the width and height of the title bar of
2136 FRAME as supplied by the window manager. If both of them are zero,
2137 FRAME has no title bar. If only the width is zero, Emacs was not
2138 able to retrieve the width information.
2139
2140`menu-bar-external', if non-nil, means the menu bar is external (never
2141 included in the inner edges of FRAME).
2142
2143`menu-bar-size' is a cons of the width and height of the menu bar of
2144 FRAME.
2145
2146`tool-bar-external', if non-nil, means the tool bar is external (never
2147 included in the inner edges of FRAME).
2148
2149`tool-bar-position' tells on which side the tool bar on FRAME is and can
2150 be one of `left', `top', `right' or `bottom'. If this is nil, FRAME
2151 has no tool bar.
2152
2153`tool-bar-size' is a cons of the width and height of the tool bar of
2154 FRAME.
2155
2156`internal-border-width' is the width of the internal border of
2157 FRAME. */)
2158 (Lisp_Object frame)
2159{
2160 return frame_geometry (frame, Qnil);
2161}
2162
2163DEFUN ("haiku-frame-edges", Fhaiku_frame_edges, Shaiku_frame_edges, 0, 2, 0,
2164 doc: /* Return edge coordinates of FRAME.
2165FRAME must be a live frame and defaults to the selected one. The return
2166value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are
2167in pixels relative to the origin - the position (0, 0) - of FRAME's
2168display.
2169
2170If optional argument TYPE is the symbol `outer-edges', return the outer
2171edges of FRAME. The outer edges comprise the decorations of the window
2172manager (like the title bar or external borders) as well as any external
2173menu or tool bar of FRAME. If optional argument TYPE is the symbol
2174`native-edges' or nil, return the native edges of FRAME. The native
2175edges exclude the decorations of the window manager and any external
2176menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return
2177the inner edges of FRAME. These edges exclude title bar, any borders,
2178menu bar or tool bar of FRAME. */)
2179 (Lisp_Object frame, Lisp_Object type)
2180{
2181 return frame_geometry (frame, ((EQ (type, Qouter_edges)
2182 || EQ (type, Qinner_edges))
2183 ? type
2184 : Qnative_edges));
2185}
2186
2187DEFUN ("haiku-read-file-name", Fhaiku_read_file_name, Shaiku_read_file_name, 1, 6, 0,
2188 doc: /* Use a graphical panel to read a file name, using prompt PROMPT.
2189Optional arg FRAME specifies a frame on which to display the file panel.
2190If it is nil, the current frame is used instead.
2191The frame being used will be brought to the front of
2192the display after the file panel is closed.
2193Optional arg DIR, if non-nil, supplies a default directory.
2194Optional arg MUSTMATCH, if non-nil, means the returned file or
2195directory must exist.
2196Optional arg DIR_ONLY_P, if non-nil, means choose only directories.
2197Optional arg SAVE_TEXT, if non-nil, specifies some text to show in the entry field. */)
2198 (Lisp_Object prompt, Lisp_Object frame,
2199 Lisp_Object dir, Lisp_Object mustmatch,
2200 Lisp_Object dir_only_p, Lisp_Object save_text)
2201{
2202 ptrdiff_t idx;
2203 if (!x_display_list)
2204 error ("Be windowing not initialized");
2205
2206 if (!NILP (dir))
2207 CHECK_STRING (dir);
2208
2209 if (!NILP (save_text))
2210 CHECK_STRING (save_text);
2211
2212 if (NILP (frame))
2213 frame = selected_frame;
2214
2215 CHECK_STRING (prompt);
2216
2217 CHECK_LIVE_FRAME (frame);
2218 check_window_system (XFRAME (frame));
2219
2220 idx = SPECPDL_INDEX ();
2221 record_unwind_protect_void (unwind_popup);
2222
2223 struct frame *f = XFRAME (frame);
2224
2225 FRAME_DISPLAY_INFO (f)->focus_event_frame = f;
2226
2227 ++popup_activated_p;
2228 char *fn = be_popup_file_dialog (!NILP (mustmatch) || !NILP (dir_only_p),
2229 !NILP (dir) ? SSDATA (ENCODE_UTF_8 (dir)) : NULL,
2230 !NILP (mustmatch), !NILP (dir_only_p),
2231 FRAME_HAIKU_WINDOW (f),
2232 !NILP (save_text) ? SSDATA (ENCODE_UTF_8 (save_text)) : NULL,
2233 SSDATA (ENCODE_UTF_8 (prompt)),
2234 block_input, unblock_input);
2235
2236 unbind_to (idx, Qnil);
2237
2238 block_input ();
2239 BWindow_activate (FRAME_HAIKU_WINDOW (f));
2240 unblock_input ();
2241
2242 if (!fn)
2243 return Qnil;
2244
2245 Lisp_Object p = build_string_from_utf8 (fn);
2246 free (fn);
2247 return p;
2248}
2249
2250DEFUN ("haiku-put-resource", Fhaiku_put_resource, Shaiku_put_resource,
2251 2, 2, 0, doc: /* Place STRING by the key RESOURCE in the resource database.
2252It can later be retrieved with `x-get-resource'. */)
2253 (Lisp_Object resource, Lisp_Object string)
2254{
2255 CHECK_STRING (resource);
2256 if (!NILP (string))
2257 CHECK_STRING (string);
2258
2259 put_xrm_resource (resource, string);
2260 return Qnil;
2261}
2262
2263DEFUN ("haiku-frame-list-z-order", Fhaiku_frame_list_z_order,
2264 Shaiku_frame_list_z_order, 0, 1, 0,
2265 doc: /* Return list of Emacs' frames, in Z (stacking) order.
2266If TERMINAL is non-nil and specifies a live frame, return the child
2267frames of that frame in Z (stacking) order.
2268
2269As it is impossible to reliably determine the frame stacking order on
2270Haiku, the selected frame is always the first element of the returned
2271list, while the rest are not guaranteed to be in any particular order.
2272
2273Frames are listed from topmost (first) to bottommost (last). */)
2274 (Lisp_Object terminal)
2275{
2276 Lisp_Object frames = Qnil;
2277 Lisp_Object head, tail;
2278 Lisp_Object sel = Qnil;
2279
2280 FOR_EACH_FRAME (head, tail)
2281 {
2282 struct frame *f = XFRAME (tail);
2283 if (!FRAME_HAIKU_P (f) ||
2284 (FRAMEP (terminal) &&
2285 FRAME_LIVE_P (XFRAME (terminal)) &&
2286 !EQ (terminal, get_frame_param (f, Qparent_frame))))
2287 continue;
2288
2289 if (EQ (tail, selected_frame))
2290 sel = tail;
2291 else
2292 frames = Fcons (tail, frames);
2293 }
2294
2295 if (NILP (sel))
2296 return frames;
2297 return Fcons (sel, frames);
2298}
2299
2300DEFUN ("x-display-save-under", Fx_display_save_under,
2301 Sx_display_save_under, 0, 1, 0,
2302 doc: /* SKIP: real doc in xfns.c. */)
2303 (Lisp_Object terminal)
2304{
2305 check_haiku_display_info (terminal);
2306
2307 if (FRAMEP (terminal))
2308 {
2309 struct frame *f = decode_window_system_frame (terminal);
2310 return FRAME_HAIKU_VIEW (f) && EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)) ?
2311 Qt : Qnil;
2312 }
2313
2314 return Qnil;
2315}
2316
2317frame_parm_handler haiku_frame_parm_handlers[] =
2318 {
2319 gui_set_autoraise,
2320 gui_set_autolower,
2321 haiku_set_background_color,
2322 NULL, /* x_set_border_color */
2323 gui_set_border_width,
2324 haiku_set_cursor_color,
2325 haiku_set_cursor_type,
2326 gui_set_font,
2327 haiku_set_foreground_color,
2328 NULL, /* set icon name */
2329 NULL, /* set icon type */
2330 haiku_set_child_frame_border_width,
2331 haiku_set_internal_border_width,
2332 gui_set_right_divider_width,
2333 gui_set_bottom_divider_width,
2334 haiku_set_menu_bar_lines,
2335 NULL, /* set mouse color */
2336 haiku_explicitly_set_name,
2337 gui_set_scroll_bar_width,
2338 gui_set_scroll_bar_height,
2339 haiku_set_title,
2340 gui_set_unsplittable,
2341 gui_set_vertical_scroll_bars,
2342 gui_set_horizontal_scroll_bars,
2343 gui_set_visibility,
2344 haiku_set_tab_bar_lines,
2345 haiku_set_tool_bar_lines,
2346 NULL, /* set scroll bar fg */
2347 NULL, /* set scroll bar bkg */
2348 gui_set_screen_gamma,
2349 gui_set_line_spacing,
2350 gui_set_left_fringe,
2351 gui_set_right_fringe,
2352 NULL, /* x wait for wm */
2353 gui_set_fullscreen,
2354 gui_set_font_backend,
2355 gui_set_alpha,
2356 NULL, /* set sticky */
2357 NULL, /* set tool bar pos */
2358 haiku_set_inhibit_double_buffering,
2359 haiku_set_undecorated,
2360 haiku_set_parent_frame,
2361 NULL, /* set skip taskbar */
2362 haiku_set_no_focus_on_map,
2363 haiku_set_no_accept_focus,
2364 NULL, /* set z group */
2365 NULL, /* set override redir */
2366 gui_set_no_special_glyphs
2367 };
2368
2369void
2370syms_of_haikufns (void)
2371{
2372 DEFSYM (Qfont_parameter, "font-parameter");
2373 DEFSYM (Qcancel_timer, "cancel-timer");
2374 DEFSYM (Qassq_delete_all, "assq-delete-all");
2375
2376 DEFSYM (Qalways, "always");
2377 DEFSYM (Qnot_useful, "not-useful");
2378 DEFSYM (Qwhen_mapped, "when-mapped");
2379
2380 defsubr (&Sx_hide_tip);
2381 defsubr (&Sxw_display_color_p);
2382 defsubr (&Sx_display_grayscale_p);
2383 defsubr (&Sx_open_connection);
2384 defsubr (&Sx_create_frame);
2385 defsubr (&Sx_display_pixel_width);
2386 defsubr (&Sx_display_pixel_height);
2387 defsubr (&Sxw_color_values);
2388 defsubr (&Sxw_color_defined_p);
2389 defsubr (&Sx_display_visual_class);
2390 defsubr (&Sx_show_tip);
2391 defsubr (&Sx_display_mm_height);
2392 defsubr (&Sx_display_mm_width);
2393 defsubr (&Sx_close_connection);
2394 defsubr (&Sx_display_list);
2395 defsubr (&Sx_server_vendor);
2396 defsubr (&Sx_server_version);
2397 defsubr (&Sx_display_screens);
2398 defsubr (&Shaiku_get_version_string);
2399 defsubr (&Sx_display_color_cells);
2400 defsubr (&Sx_display_planes);
2401 defsubr (&Shaiku_set_mouse_absolute_pixel_position);
2402 defsubr (&Shaiku_mouse_absolute_pixel_position);
2403 defsubr (&Shaiku_frame_geometry);
2404 defsubr (&Shaiku_frame_edges);
2405 defsubr (&Sx_double_buffered_p);
2406 defsubr (&Sx_display_backing_store);
2407 defsubr (&Shaiku_read_file_name);
2408 defsubr (&Shaiku_put_resource);
2409 defsubr (&Shaiku_frame_list_z_order);
2410 defsubr (&Sx_display_save_under);
2411
2412 tip_timer = Qnil;
2413 staticpro (&tip_timer);
2414 tip_frame = Qnil;
2415 staticpro (&tip_frame);
2416 tip_last_frame = Qnil;
2417 staticpro (&tip_last_frame);
2418 tip_last_string = Qnil;
2419 staticpro (&tip_last_string);
2420 tip_last_parms = Qnil;
2421 staticpro (&tip_last_parms);
2422
2423 DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
2424 doc: /* SKIP: real doc in xfns.c. */);
2425 Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40));
2426
2427 DEFVAR_BOOL ("haiku-use-system-tooltips", haiku_use_system_tooltips,
2428 doc: /* When non-nil, Emacs will display tooltips using the App Kit.
2429This can avoid a great deal of consing that does not play
2430well with the Haiku memory allocator, but comes with the
2431disadvantage of not being able to use special display properties
2432within tooltips. */);
2433 haiku_use_system_tooltips = 1;
2434
2435#ifdef USE_BE_CAIRO
2436 DEFVAR_LISP ("cairo-version-string", Vcairo_version_string,
2437 doc: /* Version info for cairo. */);
2438 {
2439 char cairo_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
2440 int len = sprintf (cairo_version, "%d.%d.%d",
2441 CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
2442 CAIRO_VERSION_MICRO);
2443 Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
2444 }
2445#endif
2446
2447 return;
2448}
diff --git a/src/haikufont.c b/src/haikufont.c
new file mode 100644
index 00000000000..811fa62a848
--- /dev/null
+++ b/src/haikufont.c
@@ -0,0 +1,1072 @@
1/* Font support for Haiku windowing
2
3Copyright (C) 2021 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20#include <config.h>
21
22#include "lisp.h"
23#include "dispextern.h"
24#include "composite.h"
25#include "blockinput.h"
26#include "charset.h"
27#include "frame.h"
28#include "window.h"
29#include "fontset.h"
30#include "haikuterm.h"
31#include "character.h"
32#include "font.h"
33#include "termchar.h"
34#include "pdumper.h"
35#include "haiku_support.h"
36
37#include <math.h>
38#include <stdlib.h>
39
40static Lisp_Object font_cache;
41
42#define METRICS_NCOLS_PER_ROW (128)
43
44enum metrics_status
45 {
46 METRICS_INVALID = -1, /* metrics entry is invalid */
47 };
48
49#define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent)
50#define METRICS_SET_STATUS(metrics, status) \
51 ((metrics)->ascent = 0, (metrics)->descent = (status))
52
53static struct
54{
55 /* registry name */
56 const char *name;
57 /* characters to distinguish the charset from the others */
58 int uniquifier[6];
59 /* additional constraint by language */
60 const char *lang;
61} em_charset_table[] =
62 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
63 { "iso8859-2", { 0x00A0, 0x010E }},
64 { "iso8859-3", { 0x00A0, 0x0108 }},
65 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
66 { "iso8859-5", { 0x00A0, 0x0401 }},
67 { "iso8859-6", { 0x00A0, 0x060C }},
68 { "iso8859-7", { 0x00A0, 0x0384 }},
69 { "iso8859-8", { 0x00A0, 0x05D0 }},
70 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
71 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
72 { "iso8859-11", { 0x00A0, 0x0E01 }},
73 { "iso8859-13", { 0x00A0, 0x201C }},
74 { "iso8859-14", { 0x00A0, 0x0174 }},
75 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
76 { "iso8859-16", { 0x00A0, 0x0218}},
77 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
78 { "big5-0", { 0x9C21 }, "zh-tw" },
79 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
80 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
81 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
82 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
83 { "cns11643.1992-3", { 0x201A9 }},
84 { "cns11643.1992-4", { 0x20057 }},
85 { "cns11643.1992-5", { 0x20000 }},
86 { "cns11643.1992-6", { 0x20003 }},
87 { "cns11643.1992-7", { 0x20055 }},
88 { "gbk-0", { 0x4E06 }, "zh-cn"},
89 { "jisx0212.1990-0", { 0x4E44 }},
90 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
91 { "jisx0213.2000-2", { 0xFA49 }},
92 { "jisx0213.2004-1", { 0x20B9F }},
93 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
94 { "tis620.2529-1", { 0x0E01 }, "th"},
95 { "microsoft-cp1251", { 0x0401, 0x0490 }, "ru"},
96 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
97 { "mulelao-1", { 0x0E81 }, "lo"},
98 { "unicode-sip", { 0x20000 }},
99 { "mulearabic-0", { 0x628 }},
100 { "mulearabic-1", { 0x628 }},
101 { "mulearabic-2", { 0x628 }},
102 { NULL }
103 };
104
105static void
106haikufont_apply_registry (struct haiku_font_pattern *pattern,
107 Lisp_Object registry)
108{
109 char *str = SSDATA (SYMBOL_NAME (registry));
110 USE_SAFE_ALLOCA;
111 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
112 int i, j;
113
114 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
115 {
116 if (str[i] == '.')
117 re[j++] = '\\';
118 else if (str[i] == '*')
119 re[j++] = '.';
120 re[j] = str[i];
121 if (re[j] == '?')
122 re[j] = '.';
123 }
124 re[j] = '\0';
125 AUTO_STRING_WITH_LEN (regexp, re, j);
126 for (i = 0; em_charset_table[i].name; i++)
127 if (fast_c_string_match_ignore_case
128 (regexp, em_charset_table[i].name,
129 strlen (em_charset_table[i].name)) >= 0)
130 break;
131 SAFE_FREE ();
132 if (!em_charset_table[i].name)
133 return;
134 int *uniquifier = em_charset_table[i].uniquifier;
135 int l;
136
137 for (l = 0; uniquifier[l]; ++l);
138
139 uint32_t *a = xmalloc (l * sizeof *a);
140 for (l = 0; uniquifier[l]; ++l)
141 a[l] = uniquifier[l];
142
143 if (pattern->specified & FSPEC_WANTED)
144 {
145 int old_l = l;
146 l += pattern->want_chars_len;
147 a = xrealloc (a, l * sizeof *a);
148 memcpy (&a[old_l], pattern->wanted_chars, (l - old_l) * sizeof *a);
149 xfree (pattern->wanted_chars);
150 }
151 pattern->specified |= FSPEC_WANTED;
152 pattern->want_chars_len = l;
153 pattern->wanted_chars = a;
154
155 if (em_charset_table[i].lang)
156 {
157 if (!strncmp (em_charset_table[i].lang, "zh", 2))
158 {
159 pattern->specified |= FSPEC_LANGUAGE;
160 pattern->language = LANGUAGE_CN;
161 }
162 else if (!strncmp (em_charset_table[i].lang, "ko", 2))
163 {
164 pattern->specified |= FSPEC_LANGUAGE;
165 pattern->language = LANGUAGE_KO;
166 }
167 else if (!strncmp (em_charset_table[i].lang, "ja", 2))
168 {
169 pattern->specified |= FSPEC_LANGUAGE;
170 pattern->language = LANGUAGE_JP;
171 }
172 }
173
174 return;
175}
176
177static Lisp_Object
178haikufont_get_fallback_entity (void)
179{
180 Lisp_Object ent = font_make_entity ();
181 ASET (ent, FONT_TYPE_INDEX, Qhaiku);
182 ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku);
183 ASET (ent, FONT_FAMILY_INDEX, Qnil);
184 ASET (ent, FONT_ADSTYLE_INDEX, Qnil);
185 ASET (ent, FONT_REGISTRY_INDEX, Qutf_8);
186 ASET (ent, FONT_SIZE_INDEX, make_fixnum (0));
187 ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0));
188 ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO));
189 FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnil);
190 FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnil);
191 FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnil);
192
193 return ent;
194}
195
196static Lisp_Object
197haikufont_get_cache (struct frame *frame)
198{
199 return font_cache;
200}
201
202static Lisp_Object
203haikufont_weight_to_lisp (int weight)
204{
205 switch (weight)
206 {
207 case HAIKU_THIN:
208 return Qthin;
209 case HAIKU_ULTRALIGHT:
210 return Qultra_light;
211 case HAIKU_EXTRALIGHT:
212 return Qextra_light;
213 case HAIKU_LIGHT:
214 return Qlight;
215 case HAIKU_SEMI_LIGHT:
216 return Qsemi_light;
217 case HAIKU_REGULAR:
218 return Qnormal;
219 case HAIKU_SEMI_BOLD:
220 return Qsemi_bold;
221 case HAIKU_BOLD:
222 return Qbold;
223 case HAIKU_EXTRA_BOLD:
224 return Qextra_bold;
225 case HAIKU_ULTRA_BOLD:
226 return Qultra_bold;
227 case HAIKU_BOOK:
228 return Qbook;
229 case HAIKU_HEAVY:
230 return Qheavy;
231 case HAIKU_ULTRA_HEAVY:
232 return Qultra_heavy;
233 case HAIKU_BLACK:
234 return Qblack;
235 case HAIKU_MEDIUM:
236 return Qmedium;
237 }
238 emacs_abort ();
239}
240
241static int
242haikufont_lisp_to_weight (Lisp_Object weight)
243{
244 if (EQ (weight, Qthin))
245 return HAIKU_THIN;
246 if (EQ (weight, Qultra_light))
247 return HAIKU_ULTRALIGHT;
248 if (EQ (weight, Qextra_light))
249 return HAIKU_EXTRALIGHT;
250 if (EQ (weight, Qlight))
251 return HAIKU_LIGHT;
252 if (EQ (weight, Qsemi_light))
253 return HAIKU_SEMI_LIGHT;
254 if (EQ (weight, Qnormal))
255 return HAIKU_REGULAR;
256 if (EQ (weight, Qsemi_bold))
257 return HAIKU_SEMI_BOLD;
258 if (EQ (weight, Qbold))
259 return HAIKU_BOLD;
260 if (EQ (weight, Qextra_bold))
261 return HAIKU_EXTRA_BOLD;
262 if (EQ (weight, Qultra_bold))
263 return HAIKU_ULTRA_BOLD;
264 if (EQ (weight, Qbook))
265 return HAIKU_BOOK;
266 if (EQ (weight, Qheavy))
267 return HAIKU_HEAVY;
268 if (EQ (weight, Qultra_heavy))
269 return HAIKU_ULTRA_HEAVY;
270 if (EQ (weight, Qblack))
271 return HAIKU_BLACK;
272 if (EQ (weight, Qmedium))
273 return HAIKU_MEDIUM;
274
275 emacs_abort ();
276}
277
278static Lisp_Object
279haikufont_slant_to_lisp (enum haiku_font_slant slant)
280{
281 switch (slant)
282 {
283 case NO_SLANT:
284 emacs_abort ();
285 case SLANT_ITALIC:
286 return Qitalic;
287 case SLANT_REGULAR:
288 return Qnormal;
289 case SLANT_OBLIQUE:
290 return Qoblique;
291 }
292 emacs_abort ();
293}
294
295static enum haiku_font_slant
296haikufont_lisp_to_slant (Lisp_Object slant)
297{
298 if (EQ (slant, Qitalic) ||
299 EQ (slant, Qreverse_italic))
300 return SLANT_ITALIC;
301 if (EQ (slant, Qoblique) ||
302 EQ (slant, Qreverse_oblique))
303 return SLANT_OBLIQUE;
304 if (EQ (slant, Qnormal))
305 return SLANT_REGULAR;
306 emacs_abort ();
307}
308
309static Lisp_Object
310haikufont_width_to_lisp (enum haiku_font_width width)
311{
312 switch (width)
313 {
314 case NO_WIDTH:
315 emacs_abort ();
316 case ULTRA_CONDENSED:
317 return Qultra_condensed;
318 case EXTRA_CONDENSED:
319 return Qextra_condensed;
320 case CONDENSED:
321 return Qcondensed;
322 case SEMI_CONDENSED:
323 return Qsemi_condensed;
324 case NORMAL_WIDTH:
325 return Qnormal;
326 case SEMI_EXPANDED:
327 return Qsemi_expanded;
328 case EXPANDED:
329 return Qexpanded;
330 case EXTRA_EXPANDED:
331 return Qextra_expanded;
332 case ULTRA_EXPANDED:
333 return Qultra_expanded;
334 }
335
336 emacs_abort ();
337}
338
339static enum haiku_font_width
340haikufont_lisp_to_width (Lisp_Object lisp)
341{
342 if (EQ (lisp, Qultra_condensed))
343 return ULTRA_CONDENSED;
344 if (EQ (lisp, Qextra_condensed))
345 return EXTRA_CONDENSED;
346 if (EQ (lisp, Qcondensed))
347 return CONDENSED;
348 if (EQ (lisp, Qsemi_condensed))
349 return SEMI_CONDENSED;
350 if (EQ (lisp, Qnormal))
351 return NORMAL_WIDTH;
352 if (EQ (lisp, Qexpanded))
353 return EXPANDED;
354 if (EQ (lisp, Qextra_expanded))
355 return EXTRA_EXPANDED;
356 if (EQ (lisp, Qultra_expanded))
357 return ULTRA_EXPANDED;
358 emacs_abort ();
359}
360
361static int
362haikufont_maybe_handle_special_family (Lisp_Object family,
363 struct haiku_font_pattern *ptn)
364{
365 CHECK_SYMBOL (family);
366
367 if (EQ (family, Qmonospace) || EQ (family, Qfixed) ||
368 EQ (family, Qdefault))
369 {
370 BFont_populate_fixed_family (ptn);
371 return 1;
372 }
373 else if (EQ (family, intern ("Sans Serif")))
374 {
375 BFont_populate_plain_family (ptn);
376 return 1;
377 }
378 return 0;
379}
380
381static Lisp_Object
382haikufont_pattern_to_entity (struct haiku_font_pattern *ptn)
383{
384 Lisp_Object ent = font_make_entity ();
385 ASET (ent, FONT_TYPE_INDEX, Qhaiku);
386 ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku);
387 ASET (ent, FONT_FAMILY_INDEX, Qdefault);
388 ASET (ent, FONT_ADSTYLE_INDEX, Qnil);
389 ASET (ent, FONT_REGISTRY_INDEX, Qutf_8);
390 ASET (ent, FONT_SIZE_INDEX, make_fixnum (0));
391 ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0));
392 ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO));
393 FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnormal);
394 FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnormal);
395 FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnormal);
396
397 if (ptn->specified & FSPEC_FAMILY)
398 ASET (ent, FONT_FAMILY_INDEX, intern (ptn->family));
399 else
400 ASET (ent, FONT_FAMILY_INDEX, Qdefault);
401
402 if (ptn->specified & FSPEC_STYLE)
403 ASET (ent, FONT_ADSTYLE_INDEX, intern (ptn->style));
404 else
405 {
406 if (ptn->specified & FSPEC_WEIGHT)
407 FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX,
408 haikufont_weight_to_lisp (ptn->weight));
409 if (ptn->specified & FSPEC_SLANT)
410 FONT_SET_STYLE (ent, FONT_SLANT_INDEX,
411 haikufont_slant_to_lisp (ptn->slant));
412 if (ptn->specified & FSPEC_WIDTH)
413 FONT_SET_STYLE (ent, FONT_WIDTH_INDEX,
414 haikufont_width_to_lisp (ptn->width));
415 }
416
417 if (ptn->specified & FSPEC_SPACING)
418 ASET (ent, FONT_SPACING_INDEX,
419 make_fixnum (ptn->mono_spacing_p ?
420 FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
421 return ent;
422}
423
424static void
425haikufont_spec_or_entity_to_pattern (Lisp_Object ent,
426 int list_p,
427 struct haiku_font_pattern *ptn)
428{
429 Lisp_Object tem;
430 ptn->specified = 0;
431
432 tem = AREF (ent, FONT_ADSTYLE_INDEX);
433 if (!NILP (tem))
434 {
435 ptn->specified |= FSPEC_STYLE;
436 strncpy ((char *) &ptn->style,
437 SSDATA (SYMBOL_NAME (tem)),
438 sizeof ptn->style - 1);
439 }
440
441 tem = FONT_SLANT_SYMBOLIC (ent);
442 if (!NILP (tem))
443 {
444 ptn->specified |= FSPEC_SLANT;
445 ptn->slant = haikufont_lisp_to_slant (tem);
446 }
447
448 tem = FONT_WEIGHT_SYMBOLIC (ent);
449 if (!NILP (tem))
450 {
451 ptn->specified |= FSPEC_WEIGHT;
452 ptn->weight = haikufont_lisp_to_weight (tem);
453 }
454
455 tem = FONT_WIDTH_SYMBOLIC (ent);
456 if (!NILP (tem))
457 {
458 ptn->specified |= FSPEC_WIDTH;
459 ptn->width = haikufont_lisp_to_width (tem);
460 }
461
462 tem = AREF (ent, FONT_SPACING_INDEX);
463 if (FIXNUMP (tem))
464 {
465 ptn->specified |= FSPEC_SPACING;
466 ptn->mono_spacing_p = XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL;
467 }
468
469 tem = AREF (ent, FONT_FAMILY_INDEX);
470 if (!NILP (tem) &&
471 (list_p && !haikufont_maybe_handle_special_family (tem, ptn)))
472 {
473 ptn->specified |= FSPEC_FAMILY;
474 strncpy ((char *) &ptn->family,
475 SSDATA (SYMBOL_NAME (tem)),
476 sizeof ptn->family - 1);
477 }
478
479 tem = assq_no_quit (QCscript, AREF (ent, FONT_EXTRA_INDEX));
480 if (!NILP (tem))
481 {
482 tem = assq_no_quit (XCDR (tem), Vscript_representative_chars);
483
484 if (CONSP (tem) && VECTORP (XCDR (tem)))
485 {
486 tem = XCDR (tem);
487
488 int count = 0;
489
490 for (int j = 0; j < ASIZE (tem); ++j)
491 if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j)))
492 ++count;
493
494 if (count)
495 {
496 ptn->specified |= FSPEC_NEED_ONE_OF;
497 ptn->need_one_of_len = count;
498 ptn->need_one_of = xmalloc (count * sizeof *ptn->need_one_of);
499 count = 0;
500 for (int j = 0; j < ASIZE (tem); ++j)
501 if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j)))
502 {
503 ptn->need_one_of[j] = XFIXNAT (AREF (tem, j));
504 ++count;
505 }
506 }
507 }
508 else if (CONSP (tem) && CONSP (XCDR (tem)))
509 {
510 int count = 0;
511
512 for (Lisp_Object it = XCDR (tem); CONSP (it); it = XCDR (it))
513 if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (it)))
514 ++count;
515
516 if (count)
517 {
518 ptn->specified |= FSPEC_WANTED;
519 ptn->want_chars_len = count;
520 ptn->wanted_chars = xmalloc (count * sizeof *ptn->wanted_chars);
521 count = 0;
522
523 for (tem = XCDR (tem); CONSP (tem); tem = XCDR (tem))
524 if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (tem)))
525 {
526 ptn->wanted_chars[count] = XFIXNAT (XCAR (tem));
527 ++count;
528 }
529 }
530 }
531 }
532
533 tem = assq_no_quit (QClang, AREF (ent, FONT_EXTRA_INDEX));
534 if (CONSP (tem))
535 {
536 tem = XCDR (tem);
537 if (EQ (tem, Qzh))
538 {
539 ptn->specified |= FSPEC_LANGUAGE;
540 ptn->language = LANGUAGE_CN;
541 }
542 else if (EQ (tem, Qko))
543 {
544 ptn->specified |= FSPEC_LANGUAGE;
545 ptn->language = LANGUAGE_KO;
546 }
547 else if (EQ (tem, Qjp))
548 {
549 ptn->specified |= FSPEC_LANGUAGE;
550 ptn->language = LANGUAGE_JP;
551 }
552 }
553
554 tem = AREF (ent, FONT_REGISTRY_INDEX);
555 if (SYMBOLP (tem))
556 haikufont_apply_registry (ptn, tem);
557}
558
559static void
560haikufont_done_with_query_pattern (struct haiku_font_pattern *ptn)
561{
562 if (ptn->specified & FSPEC_WANTED)
563 xfree (ptn->wanted_chars);
564
565 if (ptn->specified & FSPEC_NEED_ONE_OF)
566 xfree (ptn->need_one_of);
567}
568
569static Lisp_Object
570haikufont_match (struct frame *f, Lisp_Object font_spec)
571{
572 block_input ();
573 Lisp_Object tem = Qnil;
574 struct haiku_font_pattern ptn;
575 haikufont_spec_or_entity_to_pattern (font_spec, 0, &ptn);
576 ptn.specified &= ~FSPEC_FAMILY;
577 struct haiku_font_pattern *found = BFont_find (&ptn);
578 haikufont_done_with_query_pattern (&ptn);
579 if (found)
580 {
581 tem = haikufont_pattern_to_entity (found);
582 haiku_font_pattern_free (found);
583 }
584 unblock_input ();
585 return !NILP (tem) ? tem : haikufont_get_fallback_entity ();
586}
587
588static Lisp_Object
589haikufont_list (struct frame *f, Lisp_Object font_spec)
590{
591 block_input ();
592 Lisp_Object lst = Qnil;
593
594 /* Returning irrelevant results on receiving an OTF form will cause
595 fontset.c to loop over and over, making displaying some
596 characters very slow. */
597 Lisp_Object tem = assq_no_quit (QCotf, AREF (font_spec, FONT_EXTRA_INDEX));
598 if (CONSP (tem) && !NILP (XCDR (tem)))
599 {
600 unblock_input ();
601 return Qnil;
602 }
603
604 struct haiku_font_pattern ptn;
605 haikufont_spec_or_entity_to_pattern (font_spec, 1, &ptn);
606 struct haiku_font_pattern *found = BFont_find (&ptn);
607 haikufont_done_with_query_pattern (&ptn);
608 if (found)
609 {
610 for (struct haiku_font_pattern *pt = found;
611 pt; pt = pt->next)
612 lst = Fcons (haikufont_pattern_to_entity (pt), lst);
613 haiku_font_pattern_free (found);
614 }
615 unblock_input ();
616 return lst;
617}
618
619static void
620haiku_bulk_encode (struct haikufont_info *font_info, int block)
621{
622 unsigned short *unichars = xmalloc (0x101 * sizeof (*unichars));
623 unsigned int i, idx;
624
625 block_input ();
626
627 font_info->glyphs[block] = unichars;
628 if (!unichars)
629 emacs_abort ();
630
631 for (idx = block << 8, i = 0; i < 0x100; idx++, i++)
632 unichars[i] = idx;
633 unichars[0x100] = 0;
634
635
636 /* If the font contains the entire block, just store it. */
637 if (!BFont_have_char_block (font_info->be_font,
638 unichars[0], unichars[0xff]))
639 {
640 for (int i = 0; i < 0x100; ++i)
641 if (!BFont_have_char_p (font_info->be_font, unichars[i]))
642 unichars[i] = 0xFFFF;
643 }
644
645 unblock_input ();
646}
647
648static unsigned int
649haikufont_encode_char (struct font *font, int c)
650{
651 struct haikufont_info *font_info = (struct haikufont_info *) font;
652 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
653 unsigned short g;
654
655 if (c > 0xFFFF)
656 return FONT_INVALID_CODE;
657
658 if (!font_info->glyphs[high])
659 haiku_bulk_encode (font_info, high);
660 g = font_info->glyphs[high][low];
661 return g == 0xFFFF ? FONT_INVALID_CODE : g;
662}
663
664static Lisp_Object
665haikufont_open (struct frame *f, Lisp_Object font_entity, int x)
666{
667 struct haikufont_info *font_info;
668 struct haiku_font_pattern ptn;
669 struct font *font;
670 void *be_font;
671 Lisp_Object font_object;
672 Lisp_Object tem;
673
674 block_input ();
675 if (x <= 0)
676 {
677 /* Get pixel size from frame instead. */
678 tem = get_frame_param (f, Qfontsize);
679 x = NILP (tem) ? 0 : XFIXNAT (tem);
680 }
681
682 haikufont_spec_or_entity_to_pattern (font_entity, 1, &ptn);
683
684 if (BFont_open_pattern (&ptn, &be_font, x))
685 {
686 haikufont_done_with_query_pattern (&ptn);
687 unblock_input ();
688 return Qnil;
689 }
690
691 haikufont_done_with_query_pattern (&ptn);
692
693 font_object = font_make_object (VECSIZE (struct haikufont_info),
694 font_entity, x);
695
696 ASET (font_object, FONT_TYPE_INDEX, Qhaiku);
697 font_info = (struct haikufont_info *) XFONT_OBJECT (font_object);
698 font = (struct font *) font_info;
699
700 if (!font)
701 {
702 unblock_input ();
703 return Qnil;
704 }
705
706 font_info->be_font = be_font;
707 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
708
709 font->pixel_size = 0;
710 font->driver = &haikufont_driver;
711 font->encoding_charset = -1;
712 font->repertory_charset = -1;
713 font->default_ascent = 0;
714 font->vertical_centering = 0;
715 font->baseline_offset = 0;
716 font->relative_compose = 0;
717
718 font_info->metrics = NULL;
719 font_info->metrics_nrows = 0;
720
721 int px_size, min_width, max_width,
722 avg_width, height, space_width, ascent,
723 descent, underline_pos, underline_thickness;
724
725 BFont_dat (be_font, &px_size, &min_width,
726 &max_width, &avg_width, &height,
727 &space_width, &ascent, &descent,
728 &underline_pos, &underline_thickness);
729
730 font->pixel_size = px_size;
731 font->min_width = min_width;
732 font->max_width = max_width;
733 font->average_width = avg_width;
734 font->height = height;
735 font->space_width = space_width;
736 font->ascent = ascent;
737 font->descent = descent;
738 font->default_ascent = ascent;
739 font->underline_position = underline_pos;
740 font->underline_thickness = underline_thickness;
741
742 font->vertical_centering = 0;
743 font->baseline_offset = 0;
744 font->relative_compose = 0;
745
746 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
747
748 unblock_input ();
749 return font_object;
750}
751
752static void
753haikufont_close (struct font *font)
754{
755 if (font_data_structures_may_be_ill_formed ())
756 return;
757 struct haikufont_info *info = (struct haikufont_info *) font;
758
759 block_input ();
760 if (info && info->be_font)
761 BFont_close (info->be_font);
762
763 for (int i = 0; i < info->metrics_nrows; i++)
764 if (info->metrics[i])
765 xfree (info->metrics[i]);
766 if (info->metrics)
767 xfree (info->metrics);
768 for (int i = 0; i < 0x100; ++i)
769 if (info->glyphs[i])
770 xfree (info->glyphs[i]);
771 xfree (info->glyphs);
772 unblock_input ();
773}
774
775static void
776haikufont_prepare_face (struct frame *f, struct face *face)
777{
778
779}
780
781static void
782haikufont_glyph_extents (struct font *font, unsigned code,
783 struct font_metrics *metrics)
784{
785 struct haikufont_info *info = (struct haikufont_info *) font;
786
787 struct font_metrics *cache;
788 int row, col;
789
790 row = code / METRICS_NCOLS_PER_ROW;
791 col = code % METRICS_NCOLS_PER_ROW;
792 if (row >= info->metrics_nrows)
793 {
794 info->metrics =
795 xrealloc (info->metrics,
796 sizeof (struct font_metrics *) * (row + 1));
797 memset (info->metrics + info->metrics_nrows, 0,
798 (sizeof (struct font_metrics *)
799 * (row + 1 - info->metrics_nrows)));
800 info->metrics_nrows = row + 1;
801 }
802
803 if (info->metrics[row] == NULL)
804 {
805 struct font_metrics *new;
806 int i;
807
808 new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
809 for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
810 METRICS_SET_STATUS (new + i, METRICS_INVALID);
811 info->metrics[row] = new;
812 }
813 cache = info->metrics[row] + col;
814
815 if (METRICS_STATUS (cache) == METRICS_INVALID)
816 {
817 unsigned char utf8[MAX_MULTIBYTE_LENGTH];
818 memset (utf8, 0, MAX_MULTIBYTE_LENGTH);
819 CHAR_STRING (code, utf8);
820 int advance, lb, rb;
821 BFont_char_bounds (info->be_font, (const char *) utf8, &advance, &lb, &rb);
822
823 cache->lbearing = lb;
824 cache->rbearing = rb;
825 cache->width = advance;
826 cache->ascent = font->ascent;
827 cache->descent = font->descent;
828 }
829
830 if (metrics)
831 *metrics = *cache;
832}
833
834static void
835haikufont_text_extents (struct font *font, const unsigned int *code,
836 int nglyphs, struct font_metrics *metrics)
837{
838 int totalwidth = 0;
839 memset (metrics, 0, sizeof (struct font_metrics));
840
841 block_input ();
842 for (int i = 0; i < nglyphs; i++)
843 {
844 struct font_metrics m;
845 haikufont_glyph_extents (font, code[i], &m);
846 if (metrics)
847 {
848 if (totalwidth + m.lbearing < metrics->lbearing)
849 metrics->lbearing = totalwidth + m.lbearing;
850 if (totalwidth + m.rbearing > metrics->rbearing)
851 metrics->rbearing = totalwidth + m.rbearing;
852 if (m.ascent > metrics->ascent)
853 metrics->ascent = m.ascent;
854 if (m.descent > metrics->descent)
855 metrics->descent = m.descent;
856 }
857 totalwidth += m.width;
858 }
859
860 unblock_input ();
861
862 if (metrics)
863 metrics->width = totalwidth;
864}
865
866static Lisp_Object
867haikufont_shape (Lisp_Object lgstring, Lisp_Object direction)
868{
869 struct haikufont_info *font =
870 (struct haikufont_info *) CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
871 int *advance, *lb, *rb;
872 ptrdiff_t glyph_len, len, i, b_len;
873 Lisp_Object tem;
874 char *b;
875 uint32_t *mb_buf;
876
877 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
878 for (i = 0; i < glyph_len; ++i)
879 {
880 tem = LGSTRING_GLYPH (lgstring, i);
881
882 if (NILP (tem))
883 break;
884 }
885
886 len = i;
887
888 if (INT_MAX / 2 < len)
889 memory_full (SIZE_MAX);
890
891 block_input ();
892
893 b_len = 0;
894 b = xmalloc (b_len);
895 mb_buf = alloca (len * sizeof *mb_buf);
896
897 for (i = b_len; i < len; ++i)
898 {
899 uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
900 mb_buf[i] = c;
901 unsigned char mb[MAX_MULTIBYTE_LENGTH];
902 int slen = CHAR_STRING (c, mb);
903
904 b = xrealloc (b, b_len = (b_len + slen));
905 if (len == 1)
906 b[b_len - slen] = mb[0];
907 else
908 memcpy (b + b_len - slen, mb, slen);
909 }
910
911 advance = alloca (len * sizeof *advance);
912 lb = alloca (len * sizeof *lb);
913 rb = alloca (len * sizeof *rb);
914
915 eassert (font->be_font);
916 BFont_nchar_bounds (font->be_font, b, advance, lb, rb, len);
917 xfree (b);
918
919 for (i = 0; i < len; ++i)
920 {
921 tem = LGSTRING_GLYPH (lgstring, i);
922 if (NILP (tem))
923 {
924 tem = LGLYPH_NEW ();
925 LGSTRING_SET_GLYPH (lgstring, i, tem);
926 }
927
928 LGLYPH_SET_FROM (tem, i);
929 LGLYPH_SET_TO (tem, i);
930 LGLYPH_SET_CHAR (tem, mb_buf[i]);
931 LGLYPH_SET_CODE (tem, mb_buf[i]);
932
933 LGLYPH_SET_WIDTH (tem, advance[i]);
934 LGLYPH_SET_LBEARING (tem, lb[i]);
935 LGLYPH_SET_RBEARING (tem, rb[i]);
936 LGLYPH_SET_ASCENT (tem, font->font.ascent);
937 LGLYPH_SET_DESCENT (tem, font->font.descent);
938 }
939
940 unblock_input ();
941
942 return make_fixnum (len);
943}
944
945static int
946haikufont_draw (struct glyph_string *s, int from, int to,
947 int x, int y, bool with_background)
948{
949 struct frame *f = s->f;
950 struct face *face = s->face;
951 struct font_info *info = (struct font_info *) s->font;
952 unsigned char mb[MAX_MULTIBYTE_LENGTH];
953 void *view = FRAME_HAIKU_VIEW (f);
954
955 block_input ();
956 prepare_face_for_display (s->f, face);
957
958 BView_draw_lock (view);
959 BView_StartClip (view);
960 if (with_background)
961 {
962 int height = FONT_HEIGHT (s->font), ascent = FONT_BASE (s->font);
963
964 /* Font's global height and ascent values might be
965 preposterously large for some fonts. We fix here the case
966 when those fonts are used for display of glyphless
967 characters, because drawing background with font dimensions
968 in those cases makes the display illegible. There's only one
969 more call to the draw method with with_background set to
970 true, and that's in x_draw_glyph_string_foreground, when
971 drawing the cursor, where we have no such heuristics
972 available. FIXME. */
973 if (s->first_glyph->type == GLYPHLESS_GLYPH
974 && (s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE
975 || s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM))
976 height = ascent =
977 s->first_glyph->slice.glyphless.lower_yoff
978 - s->first_glyph->slice.glyphless.upper_yoff;
979
980 BView_SetHighColor (view, s->hl == DRAW_CURSOR ?
981 FRAME_CURSOR_COLOR (s->f).pixel : face->background);
982
983 BView_FillRectangle (view, x, y - ascent, s->width, height);
984 s->background_filled_p = 1;
985 }
986
987 if (s->left_overhang && s->clip_head && !s->for_overlaps)
988 {
989 /* XXX: Why is this neccessary? */
990 BView_ClipToRect (view, s->clip_head->x, 0,
991 FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
992 }
993
994 if (s->hl == DRAW_CURSOR)
995 BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
996 else
997 BView_SetHighColor (view, face->foreground);
998
999 BView_MovePenTo (view, x, y);
1000 BView_SetFont (view, ((struct haikufont_info *) info)->be_font);
1001
1002 if (from == to)
1003 {
1004 int len = CHAR_STRING (s->char2b[from], mb);
1005 BView_DrawString (view, (char *) mb, len);
1006 }
1007 else
1008 {
1009 ptrdiff_t b_len = 0;
1010 char *b = xmalloc (b_len);
1011
1012 for (int idx = from; idx < to; ++idx)
1013 {
1014 int len = CHAR_STRING (s->char2b[idx], mb);
1015 b = xrealloc (b, b_len = (b_len + len));
1016 if (len == 1)
1017 b[b_len - len] = mb[0];
1018 else
1019 memcpy (b + b_len - len, mb, len);
1020 }
1021
1022 BView_DrawString (view, b, b_len);
1023 xfree (b);
1024 }
1025 BView_EndClip (view);
1026 BView_draw_unlock (view);
1027 unblock_input ();
1028 return 1;
1029}
1030
1031struct font_driver const haikufont_driver =
1032 {
1033 .type = LISPSYM_INITIALLY (Qhaiku),
1034 .case_sensitive = true,
1035 .get_cache = haikufont_get_cache,
1036 .list = haikufont_list,
1037 .match = haikufont_match,
1038 .draw = haikufont_draw,
1039 .open_font = haikufont_open,
1040 .close_font = haikufont_close,
1041 .prepare_face = haikufont_prepare_face,
1042 .encode_char = haikufont_encode_char,
1043 .text_extents = haikufont_text_extents,
1044 .shape = haikufont_shape
1045 };
1046
1047void
1048syms_of_haikufont (void)
1049{
1050 DEFSYM (Qfontsize, "fontsize");
1051 DEFSYM (Qfixed, "fixed");
1052 DEFSYM (Qplain, "plain");
1053 DEFSYM (Qultra_light, "ultra-light");
1054 DEFSYM (Qthin, "thin");
1055 DEFSYM (Qreverse_italic, "reverse-italic");
1056 DEFSYM (Qreverse_oblique, "reverse-oblique");
1057 DEFSYM (Qmonospace, "monospace");
1058 DEFSYM (Qultra_condensed, "ultra-condensed");
1059 DEFSYM (Qextra_condensed, "extra-condensed");
1060 DEFSYM (Qcondensed, "condensed");
1061 DEFSYM (Qsemi_condensed, "semi-condensed");
1062 DEFSYM (Qsemi_expanded, "semi-expanded");
1063 DEFSYM (Qexpanded, "expanded");
1064 DEFSYM (Qextra_expanded, "extra-expanded");
1065 DEFSYM (Qultra_expanded, "ultra-expanded");
1066 DEFSYM (Qzh, "zh");
1067 DEFSYM (Qko, "ko");
1068 DEFSYM (Qjp, "jp");
1069
1070 font_cache = list (Qnil);
1071 staticpro (&font_cache);
1072}
diff --git a/src/haikugui.h b/src/haikugui.h
new file mode 100644
index 00000000000..cfc693fb552
--- /dev/null
+++ b/src/haikugui.h
@@ -0,0 +1,106 @@
1/* Haiku window system support
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#ifndef _HAIKU_GUI_H_
20#define _HAIKU_GUI_H_
21
22#ifdef _cplusplus
23extern "C"
24{
25#endif
26
27typedef struct haiku_char_struct
28{
29 int rbearing;
30 int lbearing;
31 int width;
32 int ascent;
33 int descent;
34} XCharStruct;
35
36struct haiku_rect
37{
38 int x, y;
39 int width, height;
40};
41
42typedef void *haiku;
43
44typedef haiku Emacs_Pixmap;
45typedef haiku Emacs_Window;
46typedef haiku Emacs_Cursor;
47typedef haiku Drawable;
48
49#define NativeRectangle struct haiku_rect
50#define CONVERT_TO_EMACS_RECT(xr, nr) \
51 ((xr).x = (nr).x, \
52 (xr).y = (nr).y, \
53 (xr).width = (nr).width, \
54 (xr).height = (nr).height)
55
56#define CONVERT_FROM_EMACS_RECT(xr, nr) \
57 ((nr).x = (xr).x, \
58 (nr).y = (xr).y, \
59 (nr).width = (xr).width, \
60 (nr).height = (xr).height)
61
62#define STORE_NATIVE_RECT(nr, px, py, pwidth, pheight) \
63 ((nr).x = (px), \
64 (nr).y = (py), \
65 (nr).width = (pwidth), \
66 (nr).height = (pheight))
67
68#define ForgetGravity 0
69#define NorthWestGravity 1
70#define NorthGravity 2
71#define NorthEastGravity 3
72#define WestGravity 4
73#define CenterGravity 5
74#define EastGravity 6
75#define SouthWestGravity 7
76#define SouthGravity 8
77#define SouthEastGravity 9
78#define StaticGravity 10
79
80#define NoValue 0x0000
81#define XValue 0x0001
82#define YValue 0x0002
83#define WidthValue 0x0004
84#define HeightValue 0x0008
85#define AllValues 0x000F
86#define XNegative 0x0010
87#define YNegative 0x0020
88
89#define USPosition (1L << 0) /* user specified x, y */
90#define USSize (1L << 1) /* user specified width, height */
91#define PPosition (1L << 2) /* program specified position */
92#define PSize (1L << 3) /* program specified size */
93#define PMinSize (1L << 4) /* program specified minimum size */
94#define PMaxSize (1L << 5) /* program specified maximum size */
95#define PResizeInc (1L << 6) /* program specified resize increments */
96#define PAspect (1L << 7) /* program specified min, max aspect ratios */
97#define PBaseSize (1L << 8) /* program specified base for incrementing */
98#define PWinGravity (1L << 9) /* program specified window gravity */
99
100typedef haiku Window;
101typedef int Display;
102
103#ifdef _cplusplus
104};
105#endif
106#endif /* _HAIKU_GUI_H_ */
diff --git a/src/haikuimage.c b/src/haikuimage.c
new file mode 100644
index 00000000000..138e5b84e6a
--- /dev/null
+++ b/src/haikuimage.c
@@ -0,0 +1,109 @@
1/* Haiku window system support.
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include "lisp.h"
22#include "dispextern.h"
23#include "haikuterm.h"
24#include "coding.h"
25
26#include "haiku_support.h"
27
28bool
29haiku_can_use_native_image_api (Lisp_Object type)
30{
31 const char *mime_type = NULL;
32
33 if (EQ (type, Qnative_image))
34 return 1;
35
36#ifdef HAVE_RSVG
37 if (EQ (type, Qsvg))
38 return 0;
39#endif
40
41 if (EQ (type, Qjpeg))
42 mime_type = "image/jpeg";
43 else if (EQ (type, Qpng))
44 mime_type = "image/png";
45 else if (EQ (type, Qgif))
46 mime_type = "image/gif";
47 else if (EQ (type, Qtiff))
48 mime_type = "image/tiff";
49 else if (EQ (type, Qbmp))
50 mime_type = "image/bmp";
51 else if (EQ (type, Qsvg))
52 mime_type = "image/svg";
53 else if (EQ (type, Qpbm))
54 mime_type = "image/pbm";
55
56 if (!mime_type)
57 return 0;
58
59 return be_can_translate_type_to_bitmap_p (mime_type);
60}
61
62extern int
63haiku_load_image (struct frame *f, struct image *img,
64 Lisp_Object spec_file, Lisp_Object spec_data)
65{
66 eassert (valid_image_p (img->spec));
67
68 void *pixmap = NULL;
69
70 if (STRINGP (spec_file))
71 {
72 pixmap = be_translate_bitmap_from_file_name
73 (SSDATA (ENCODE_UTF_8 (spec_file)));
74 }
75 else if (STRINGP (spec_data))
76 {
77 pixmap = be_translate_bitmap_from_memory
78 (SSDATA (spec_data), SBYTES (spec_data));
79 }
80
81 void *conv = NULL;
82
83 if (!pixmap || !BBitmap_convert (pixmap, &conv))
84 {
85 add_to_log ("Unable to load image %s", img->spec);
86 return 0;
87 }
88
89 if (conv)
90 {
91 BBitmap_free (pixmap);
92 pixmap = conv;
93 }
94
95 int left, top, right, bottom, stride, mono_p;
96 BBitmap_dimensions (pixmap, &left, &top, &right, &bottom, &stride, &mono_p);
97
98 img->width = (1 + right - left);
99 img->height = (1 + bottom - top);
100 img->pixmap = pixmap;
101
102 return 1;
103}
104
105void
106syms_of_haikuimage (void)
107{
108 DEFSYM (Qbmp, "bmp");
109}
diff --git a/src/haikumenu.c b/src/haikumenu.c
new file mode 100644
index 00000000000..698da9d639c
--- /dev/null
+++ b/src/haikumenu.c
@@ -0,0 +1,656 @@
1/* Haiku window system support
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include "lisp.h"
22#include "frame.h"
23#include "keyboard.h"
24#include "menu.h"
25#include "buffer.h"
26#include "blockinput.h"
27
28#include "haikuterm.h"
29#include "haiku_support.h"
30
31static Lisp_Object *volatile menu_item_selection;
32
33int popup_activated_p = 0;
34
35struct submenu_stack_cell
36{
37 void *parent_menu;
38 void *pane;
39};
40
41static void
42digest_menu_items (void *first_menu, int start, int menu_items_used,
43 int mbar_p)
44{
45 void **menus, **panes;
46 ssize_t menu_len = (menu_items_used + 1 - start) * sizeof *menus;
47 ssize_t pane_len = (menu_items_used + 1 - start) * sizeof *panes;
48
49 menus = alloca (menu_len);
50 panes = alloca (pane_len);
51
52 int i = start, menu_depth = 0;
53
54 memset (menus, 0, menu_len);
55 memset (panes, 0, pane_len);
56
57 void *menu = first_menu;
58
59 menus[0] = first_menu;
60
61 void *window = NULL;
62 if (FRAMEP (Vmenu_updating_frame) &&
63 FRAME_LIVE_P (XFRAME (Vmenu_updating_frame)) &&
64 FRAME_HAIKU_P (XFRAME (Vmenu_updating_frame)))
65 window = FRAME_HAIKU_WINDOW (XFRAME (Vmenu_updating_frame));
66
67 while (i < menu_items_used)
68 {
69 if (NILP (AREF (menu_items, i)))
70 {
71 menus[++menu_depth] = menu;
72 i++;
73 }
74 else if (EQ (AREF (menu_items, i), Qlambda))
75 {
76 panes[menu_depth] = NULL;
77 menu = panes[--menu_depth] ? panes[menu_depth] : menus[menu_depth];
78 i++;
79 }
80 else if (EQ (AREF (menu_items, i), Qquote))
81 i += 1;
82 else if (EQ (AREF (menu_items, i), Qt))
83 {
84 Lisp_Object pane_name, prefix;
85 const char *pane_string;
86
87 if (menu_items_n_panes == 1)
88 {
89 i += MENU_ITEMS_PANE_LENGTH;
90 continue;
91 }
92
93 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
94 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
95
96 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
97 {
98 pane_name = ENCODE_UTF_8 (pane_name);
99 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
100 }
101
102 pane_string = (NILP (pane_name)
103 ? "" : SSDATA (pane_name));
104 if (!NILP (prefix))
105 pane_string++;
106
107 if (strcmp (pane_string, ""))
108 {
109 panes[menu_depth] =
110 menu = BMenu_new_submenu (menus[menu_depth], pane_string, 1);
111 }
112
113 i += MENU_ITEMS_PANE_LENGTH;
114 }
115 else
116 {
117 Lisp_Object item_name, enable, descrip, def, selected, help;
118 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
119 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
120 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
121 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
122 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
123 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
124
125 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
126 {
127 item_name = ENCODE_UTF_8 (item_name);
128 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
129 }
130
131 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
132 {
133 descrip = ENCODE_UTF_8 (descrip);
134 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
135 }
136
137 if (STRINGP (help) && STRING_MULTIBYTE (help))
138 {
139 help = ENCODE_UTF_8 (help);
140 ASET (menu_items, i + MENU_ITEMS_ITEM_HELP, help);
141 }
142
143 if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used &&
144 NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH)))
145 menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable));
146 else if (NILP (def) && menu_separator_name_p (SSDATA (item_name)))
147 BMenu_add_separator (menu);
148 else if (!mbar_p)
149 BMenu_add_item (menu, SSDATA (item_name),
150 !NILP (def) ? aref_addr (menu_items, i) : NULL,
151 !NILP (enable), !NILP (selected), 0, window,
152 !NILP (descrip) ? SSDATA (descrip) : NULL,
153 STRINGP (help) ? SSDATA (help) : NULL);
154 else
155 BMenu_add_item (menu, SSDATA (item_name),
156 !NILP (def) ? (void *) (intptr_t) i : NULL,
157 !NILP (enable), !NILP (selected), 1, window,
158 !NILP (descrip) ? SSDATA (descrip) : NULL,
159 STRINGP (help) ? SSDATA (help) : NULL);
160
161 i += MENU_ITEMS_ITEM_LENGTH;
162 }
163 }
164}
165
166static Lisp_Object
167haiku_dialog_show (struct frame *f, Lisp_Object title,
168 Lisp_Object header, const char **error_name)
169{
170 int i, nb_buttons = 0;
171
172 *error_name = NULL;
173
174 if (menu_items_n_panes > 1)
175 {
176 *error_name = "Multiple panes in dialog box";
177 return Qnil;
178 }
179
180 Lisp_Object pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
181 i = MENU_ITEMS_PANE_LENGTH;
182
183 if (STRING_MULTIBYTE (pane_name))
184 pane_name = ENCODE_UTF_8 (pane_name);
185
186 block_input ();
187 void *alert = BAlert_new (SSDATA (pane_name), NILP (header) ? HAIKU_INFO_ALERT :
188 HAIKU_IDEA_ALERT);
189
190 Lisp_Object vals[10];
191
192 while (i < menu_items_used)
193 {
194 Lisp_Object item_name, enable, descrip, value;
195 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
196 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
197 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
198 value = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
199
200 if (NILP (item_name))
201 {
202 BAlert_delete (alert);
203 *error_name = "Submenu in dialog items";
204 unblock_input ();
205 return Qnil;
206 }
207
208 if (EQ (item_name, Qquote))
209 {
210 i++;
211 }
212
213 if (nb_buttons >= 9)
214 {
215 BAlert_delete (alert);
216 *error_name = "Too many dialog items";
217 unblock_input ();
218 return Qnil;
219 }
220
221 if (STRING_MULTIBYTE (item_name))
222 item_name = ENCODE_UTF_8 (item_name);
223 if (!NILP (descrip) && STRING_MULTIBYTE (descrip))
224 descrip = ENCODE_UTF_8 (descrip);
225
226 void *button = BAlert_add_button (alert, SSDATA (item_name));
227
228 BButton_set_enabled (button, !NILP (enable));
229 if (!NILP (descrip))
230 BView_set_tooltip (button, SSDATA (descrip));
231
232 vals[nb_buttons] = value;
233 ++nb_buttons;
234 i += MENU_ITEMS_ITEM_LENGTH;
235 }
236
237 int32_t val = BAlert_go (alert);
238 unblock_input ();
239
240 if (val < 0)
241 quit ();
242 else
243 return vals[val];
244
245 return Qnil;
246}
247
248Lisp_Object
249haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
250{
251 Lisp_Object title;
252 const char *error_name = NULL;
253 Lisp_Object selection;
254 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
255
256 check_window_system (f);
257
258 /* Decode the dialog items from what was specified. */
259 title = Fcar (contents);
260 CHECK_STRING (title);
261 record_unwind_protect_void (unuse_menu_items);
262
263 if (NILP (Fcar (Fcdr (contents))))
264 /* No buttons specified, add an "Ok" button so users can pop down
265 the dialog. Also, the lesstif/motif version crashes if there are
266 no buttons. */
267 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
268
269 list_of_panes (list1 (contents));
270
271 /* Display them in a dialog box. */
272 block_input ();
273 selection = haiku_dialog_show (f, title, header, &error_name);
274 unblock_input ();
275
276 unbind_to (specpdl_count, Qnil);
277 discard_menu_items ();
278
279 if (error_name)
280 error ("%s", error_name);
281 return selection;
282}
283
284Lisp_Object
285haiku_menu_show (struct frame *f, int x, int y, int menuflags,
286 Lisp_Object title, const char **error_name)
287{
288 int i = 0, submenu_depth = 0;
289 void *view = FRAME_HAIKU_VIEW (f);
290 void *menu;
291
292 Lisp_Object *subprefix_stack =
293 alloca (menu_items_used * sizeof (Lisp_Object));
294
295 eassert (FRAME_HAIKU_P (f));
296
297 *error_name = NULL;
298
299 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
300 {
301 *error_name = "Empty menu";
302 return Qnil;
303 }
304
305 block_input ();
306 if (STRINGP (title) && STRING_MULTIBYTE (title))
307 title = ENCODE_UTF_8 (title);
308
309 menu = BPopUpMenu_new (STRINGP (title) ? SSDATA (title) : NULL);
310 if (STRINGP (title))
311 {
312 BMenu_add_title (menu, SSDATA (title));
313 BMenu_add_separator (menu);
314 }
315 digest_menu_items (menu, 0, menu_items_used, 0);
316 BView_convert_to_screen (view, &x, &y);
317 unblock_input ();
318
319 menu_item_selection = BMenu_run (menu, x, y);
320
321 FRAME_DISPLAY_INFO (f)->grabbed = 0;
322
323 if (menu_item_selection)
324 {
325 Lisp_Object prefix, entry;
326
327 prefix = entry = Qnil;
328 i = 0;
329 while (i < menu_items_used)
330 {
331 if (NILP (AREF (menu_items, i)))
332 {
333 subprefix_stack[submenu_depth++] = prefix;
334 prefix = entry;
335 i++;
336 }
337 else if (EQ (AREF (menu_items, i), Qlambda))
338 {
339 prefix = subprefix_stack[--submenu_depth];
340 i++;
341 }
342 else if (EQ (AREF (menu_items, i), Qt))
343 {
344 prefix
345 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
346 i += MENU_ITEMS_PANE_LENGTH;
347 }
348 /* Ignore a nil in the item list.
349 It's meaningful only for dialog boxes. */
350 else if (EQ (AREF (menu_items, i), Qquote))
351 i += 1;
352 else
353 {
354 entry
355 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
356 if (menu_item_selection == aref_addr (menu_items, i))
357 {
358 if (menuflags & MENU_KEYMAPS)
359 {
360 int j;
361
362 entry = list1 (entry);
363 if (!NILP (prefix))
364 entry = Fcons (prefix, entry);
365 for (j = submenu_depth - 1; j >= 0; j--)
366 if (!NILP (subprefix_stack[j]))
367 entry = Fcons (subprefix_stack[j], entry);
368 }
369 BPopUpMenu_delete (menu);
370 return entry;
371 }
372 i += MENU_ITEMS_ITEM_LENGTH;
373 }
374 }
375 }
376 else if (!(menuflags & MENU_FOR_CLICK))
377 {
378 BPopUpMenu_delete (menu);
379 quit ();
380 }
381 BPopUpMenu_delete (menu);
382 return Qnil;
383}
384
385void
386free_frame_menubar (struct frame *f)
387{
388 FRAME_MENU_BAR_LINES (f) = 0;
389 FRAME_MENU_BAR_HEIGHT (f) = 0;
390 FRAME_EXTERNAL_MENU_BAR (f) = 0;
391
392 block_input ();
393 void *mbar = FRAME_HAIKU_MENU_BAR (f);
394 if (mbar)
395 BMenuBar_delete (mbar);
396 if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
397 --popup_activated_p;
398 FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0;
399 unblock_input ();
400
401 adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
402}
403
404void
405initialize_frame_menubar (struct frame *f)
406{
407 /* This function is called before the first chance to redisplay
408 the frame. It has to be, so the frame will have the right size. */
409 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
410 set_frame_menubar (f, true);
411}
412
413void
414set_frame_menubar (struct frame *f, bool deep_p)
415{
416 void *mbar = FRAME_HAIKU_MENU_BAR (f);
417 void *view = FRAME_HAIKU_VIEW (f);
418
419 int first_time_p = 0;
420
421 if (!mbar)
422 {
423 mbar = FRAME_HAIKU_MENU_BAR (f) = BMenuBar_new (view);
424 first_time_p = 1;
425 }
426
427 Lisp_Object items;
428 struct buffer *prev = current_buffer;
429 Lisp_Object buffer;
430 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
431 int previous_menu_items_used = f->menu_bar_items_used;
432 Lisp_Object *previous_items
433 = alloca (previous_menu_items_used * sizeof *previous_items);
434
435 XSETFRAME (Vmenu_updating_frame, f);
436
437 if (!deep_p)
438 {
439 FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 0;
440 items = FRAME_MENU_BAR_ITEMS (f);
441 Lisp_Object string;
442
443 block_input ();
444 int count = BMenu_count_items (mbar);
445
446 int i;
447 for (i = 0; i < ASIZE (items); i += 4)
448 {
449 string = AREF (items, i + 1);
450
451 if (!STRINGP (string))
452 break;
453
454 if (STRING_MULTIBYTE (string))
455 string = ENCODE_UTF_8 (string);
456
457 if (i / 4 < count)
458 {
459 void *it = BMenu_item_at (mbar, i / 4);
460 BMenu_item_set_label (it, SSDATA (string));
461 }
462 else
463 BMenu_new_menu_bar_submenu (mbar, SSDATA (string));
464 }
465
466 if (i / 4 < count)
467 BMenu_delete_from (mbar, i / 4, count - i / 4 + 1);
468 unblock_input ();
469
470 f->menu_bar_items_used = 0;
471 }
472 else
473 {
474 /* If we are making a new widget, its contents are empty,
475 do always reinitialize them. */
476 if (first_time_p)
477 previous_menu_items_used = 0;
478 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
479 specbind (Qinhibit_quit, Qt);
480 /* Don't let the debugger step into this code
481 because it is not reentrant. */
482 specbind (Qdebug_on_next_call, Qnil);
483
484 record_unwind_save_match_data ();
485 if (NILP (Voverriding_local_map_menu_flag))
486 {
487 specbind (Qoverriding_terminal_local_map, Qnil);
488 specbind (Qoverriding_local_map, Qnil);
489 }
490
491 set_buffer_internal_1 (XBUFFER (buffer));
492
493 /* Run the Lucid hook. */
494 safe_run_hooks (Qactivate_menubar_hook);
495
496 /* If it has changed current-menubar from previous value,
497 really recompute the menubar from the value. */
498 if (! NILP (Vlucid_menu_bar_dirty_flag))
499 call0 (Qrecompute_lucid_menubar);
500 safe_run_hooks (Qmenu_bar_update_hook);
501 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
502
503 items = FRAME_MENU_BAR_ITEMS (f);
504
505 /* Save the frame's previous menu bar contents data. */
506 if (previous_menu_items_used)
507 memcpy (previous_items, xvector_contents (f->menu_bar_vector),
508 previous_menu_items_used * word_size);
509
510 /* Fill in menu_items with the current menu bar contents.
511 This can evaluate Lisp code. */
512 save_menu_items ();
513 menu_items = f->menu_bar_vector;
514 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
515 init_menu_items ();
516 int i;
517 int count = BMenu_count_items (mbar);
518 int subitems = ASIZE (items) / 4;
519
520 int *submenu_start, *submenu_end, *submenu_n_panes;
521 Lisp_Object *submenu_names;
522
523 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
524 submenu_end = alloca (subitems * sizeof *submenu_end);
525 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
526 submenu_names = alloca (subitems * sizeof (Lisp_Object));
527
528 for (i = 0; i < subitems; ++i)
529 {
530 Lisp_Object key, string, maps;
531
532 key = AREF (items, i * 4);
533 string = AREF (items, i * 4 + 1);
534 maps = AREF (items, i * 4 + 2);
535
536 if (NILP (string))
537 break;
538
539 if (STRINGP (string) && STRING_MULTIBYTE (string))
540 string = ENCODE_UTF_8 (string);
541
542 submenu_start[i] = menu_items_used;
543 menu_items_n_panes = 0;
544 parse_single_submenu (key, string, maps);
545 submenu_n_panes[i] = menu_items_n_panes;
546 submenu_end[i] = menu_items_used;
547 submenu_names[i] = string;
548 }
549 finish_menu_items ();
550 submenu_start[i] = -1;
551
552 block_input ();
553 for (i = 0; submenu_start[i] >= 0; ++i)
554 {
555 void *mn = NULL;
556 if (i < count)
557 mn = BMenu_item_get_menu (BMenu_item_at (mbar, i));
558 if (mn)
559 BMenu_delete_all (mn);
560 else
561 mn = BMenu_new_menu_bar_submenu (mbar, SSDATA (submenu_names[i]));
562
563 menu_items_n_panes = submenu_n_panes[i];
564 digest_menu_items (mn, submenu_start[i], submenu_end[i], 1);
565 }
566 unblock_input ();
567
568 set_buffer_internal_1 (prev);
569
570 FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 1;
571 fset_menu_bar_vector (f, menu_items);
572 f->menu_bar_items_used = menu_items_used;
573 }
574 unbind_to (specpdl_count, Qnil);
575}
576
577void
578run_menu_bar_help_event (struct frame *f, int mb_idx)
579{
580 Lisp_Object frame;
581 Lisp_Object vec;
582 Lisp_Object help;
583
584 block_input ();
585 if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
586 {
587 unblock_input ();
588 return;
589 }
590
591 XSETFRAME (frame, f);
592
593 if (mb_idx < 0)
594 {
595 kbd_buffer_store_help_event (frame, Qnil);
596 unblock_input ();
597 return;
598 }
599
600 vec = f->menu_bar_vector;
601 if (mb_idx >= ASIZE (vec))
602 emacs_abort ();
603
604 help = AREF (vec, mb_idx + MENU_ITEMS_ITEM_HELP);
605 if (STRINGP (help) || NILP (help))
606 kbd_buffer_store_help_event (frame, help);
607 unblock_input ();
608}
609
610DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p,
611 0, 0, 0, doc: /* SKIP: real doc in xmenu.c. */)
612 (void)
613{
614 return popup_activated_p ? Qt : Qnil;
615}
616
617DEFUN ("haiku-menu-bar-open", Fhaiku_menu_bar_open, Shaiku_menu_bar_open, 0, 1, "i",
618 doc: /* Show the menu bar in FRAME.
619
620Move the mouse pointer onto the first element of FRAME's menu bar, and
621cause it to be opened. If FRAME is nil or not given, use the selected
622frame. If FRAME has no menu bar, a pop-up is displayed at the position
623of the last non-menu event instead. */)
624 (Lisp_Object frame)
625{
626 struct frame *f = decode_window_system_frame (frame);
627
628 if (FRAME_EXTERNAL_MENU_BAR (f))
629 {
630 if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
631 set_frame_menubar (f, 1);
632 }
633 else
634 {
635 return call2 (Qpopup_menu, call0 (Qmouse_menu_bar_map),
636 last_nonmenu_event);
637 }
638
639 block_input ();
640 BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f));
641 unblock_input ();
642
643 return Qnil;
644}
645
646void
647syms_of_haikumenu (void)
648{
649 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
650 DEFSYM (Qpopup_menu, "popup-menu");
651 DEFSYM (Qmouse_menu_bar_map, "mouse-menu-bar-map");
652
653 defsubr (&Smenu_or_popup_active_p);
654 defsubr (&Shaiku_menu_bar_open);
655 return;
656}
diff --git a/src/haikuselect.c b/src/haikuselect.c
new file mode 100644
index 00000000000..3f0441e0779
--- /dev/null
+++ b/src/haikuselect.c
@@ -0,0 +1,134 @@
1/* Haiku window system selection support.
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include "lisp.h"
22#include "blockinput.h"
23#include "coding.h"
24#include "haikuselect.h"
25#include "haikuterm.h"
26
27DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data,
28 2, 2, 0,
29 doc: /* Retrieve content typed as NAME from the clipboard
30CLIPBOARD. CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or
31`CLIPBOARD'. NAME is a MIME type denoting the type of the data to
32fetch. */)
33 (Lisp_Object clipboard, Lisp_Object name)
34{
35 CHECK_SYMBOL (clipboard);
36 CHECK_STRING (name);
37 char *dat;
38 ssize_t len;
39
40 block_input ();
41 if (EQ (clipboard, QPRIMARY))
42 dat = BClipboard_find_primary_selection_data (SSDATA (name), &len);
43 else if (EQ (clipboard, QSECONDARY))
44 dat = BClipboard_find_secondary_selection_data (SSDATA (name), &len);
45 else if (EQ (clipboard, QCLIPBOARD))
46 dat = BClipboard_find_system_data (SSDATA (name), &len);
47 else
48 {
49 unblock_input ();
50 signal_error ("Bad clipboard", clipboard);
51 }
52 unblock_input ();
53
54 if (!dat)
55 return Qnil;
56
57 Lisp_Object str = make_unibyte_string (dat, len);
58 Lisp_Object lispy_type = Qnil;
59
60 if (!strcmp (SSDATA (name), "text/utf-8") ||
61 !strcmp (SSDATA (name), "text/plain"))
62 {
63 if (string_ascii_p (str))
64 lispy_type = QSTRING;
65 else
66 lispy_type = QUTF8_STRING;
67 }
68
69 if (!NILP (lispy_type))
70 Fput_text_property (make_fixnum (0), make_fixnum (len),
71 Qforeign_selection, lispy_type, str);
72
73 block_input ();
74 BClipboard_free_data (dat);
75 unblock_input ();
76
77 return str;
78}
79
80DEFUN ("haiku-selection-put", Fhaiku_selection_put, Shaiku_selection_put,
81 3, 3, 0,
82 doc: /* Add or remove content from the clipboard CLIPBOARD.
83CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or `CLIPBOARD'. NAME
84is a MIME type denoting the type of the data to add. DATA is the
85string that will be placed in the clipboard, or nil if the content is
86to be removed. If NAME is the string `text/utf-8' or the string
87`text/plain', encode it as UTF-8 before storing it into the
88clipboard. */)
89 (Lisp_Object clipboard, Lisp_Object name, Lisp_Object data)
90{
91 CHECK_SYMBOL (clipboard);
92 CHECK_STRING (name);
93 if (!NILP (data))
94 CHECK_STRING (data);
95
96 block_input ();
97 /* It seems that Haiku applications counter-intuitively expect
98 UTF-8 data in both text/utf-8 and text/plain. */
99 if (!NILP (data) && STRING_MULTIBYTE (data) &&
100 (!strcmp (SSDATA (name), "text/utf-8") ||
101 !strcmp (SSDATA (name), "text/plain")))
102 data = ENCODE_UTF_8 (data);
103
104 char *dat = !NILP (data) ? SSDATA (data) : NULL;
105 ptrdiff_t len = !NILP (data) ? SBYTES (data) : 0;
106
107 if (EQ (clipboard, QPRIMARY))
108 BClipboard_set_primary_selection_data (SSDATA (name), dat, len);
109 else if (EQ (clipboard, QSECONDARY))
110 BClipboard_set_secondary_selection_data (SSDATA (name), dat, len);
111 else if (EQ (clipboard, QCLIPBOARD))
112 BClipboard_set_system_data (SSDATA (name), dat, len);
113 else
114 {
115 unblock_input ();
116 signal_error ("Bad clipboard", clipboard);
117 }
118 unblock_input ();
119
120 return Qnil;
121}
122
123void
124syms_of_haikuselect (void)
125{
126 DEFSYM (QSECONDARY, "SECONDARY");
127 DEFSYM (QCLIPBOARD, "CLIPBOARD");
128 DEFSYM (QSTRING, "STRING");
129 DEFSYM (QUTF8_STRING, "UTF8_STRING");
130 DEFSYM (Qforeign_selection, "foreign-selection");
131
132 defsubr (&Shaiku_selection_data);
133 defsubr (&Shaiku_selection_put);
134}
diff --git a/src/haikuselect.h b/src/haikuselect.h
new file mode 100644
index 00000000000..542d550d64e
--- /dev/null
+++ b/src/haikuselect.h
@@ -0,0 +1,64 @@
1/* Haiku window system selection support. Hey Emacs, this is -*- C++ -*-
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#ifndef _HAIKU_SELECT_H_
20#define _HAIKU_SELECT_H_
21
22#ifdef __cplusplus
23#include <cstdio>
24#endif
25
26#ifdef __cplusplus
27#include <stdio.h>
28extern "C"
29{
30 extern void init_haiku_select (void);
31#endif
32
33 /* Whether or not the selection was recently changed. */
34 extern int selection_state_flag;
35
36 /* Find a string with the MIME type TYPE in the system clipboard. */
37 extern char *
38 BClipboard_find_system_data (const char *type, ssize_t *len);
39
40 /* Ditto, but for the primary selection and not clipboard. */
41 extern char *
42 BClipboard_find_primary_selection_data (const char *type, ssize_t *len);
43
44 /* Ditto, this time for the secondary selection. */
45 extern char *
46 BClipboard_find_secondary_selection_data (const char *type, ssize_t *len);
47
48 extern void
49 BClipboard_set_system_data (const char *type, const char *data, ssize_t len);
50
51 extern void
52 BClipboard_set_primary_selection_data (const char *type, const char *data,
53 ssize_t len);
54
55 extern void
56 BClipboard_set_secondary_selection_data (const char *type, const char *data,
57 ssize_t len);
58
59 /* Free the returned data. */
60 extern void BClipboard_free_data (void *ptr);
61#ifdef __cplusplus
62};
63#endif
64#endif /* _HAIKU_SELECT_H_ */
diff --git a/src/haikuterm.c b/src/haikuterm.c
new file mode 100644
index 00000000000..05fbd1021b8
--- /dev/null
+++ b/src/haikuterm.c
@@ -0,0 +1,3608 @@
1/* Haiku window system support
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#include <config.h>
20
21#include "dispextern.h"
22#include "frame.h"
23#include "lisp.h"
24#include "haikugui.h"
25#include "keyboard.h"
26#include "haikuterm.h"
27#include "blockinput.h"
28#include "termchar.h"
29#include "termhooks.h"
30#include "menu.h"
31#include "buffer.h"
32#include "haiku_support.h"
33#include "thread.h"
34#include "window.h"
35
36#include <math.h>
37#include <stdlib.h>
38
39#ifdef USE_BE_CAIRO
40#include <cairo.h>
41#endif
42
43struct haiku_display_info *x_display_list = NULL;
44extern frame_parm_handler haiku_frame_parm_handlers[];
45
46static void **fringe_bmps;
47static int fringe_bitmap_fillptr = 0;
48
49static Lisp_Object rdb;
50
51struct unhandled_event
52{
53 struct unhandled_event *next;
54 enum haiku_event_type type;
55 uint8_t buffer[200];
56};
57
58char *
59get_keysym_name (int keysym)
60{
61 static char value[16];
62 sprintf (value, "%d", keysym);
63 return value;
64}
65
66static struct frame *
67haiku_window_to_frame (void *window)
68{
69 Lisp_Object tail, tem;
70 struct frame *f;
71
72 FOR_EACH_FRAME (tail, tem)
73 {
74 f = XFRAME (tem);
75 if (!FRAME_HAIKU_P (f))
76 continue;
77
78 eassert (FRAME_DISPLAY_INFO (f) == x_display_list);
79
80 if (FRAME_HAIKU_WINDOW (f) == window)
81 return f;
82 }
83
84 return 0;
85}
86
87static void
88haiku_coords_from_parent (struct frame *f, int *x, int *y)
89{
90 struct frame *p = FRAME_PARENT_FRAME (f);
91 eassert (p);
92
93 for (struct frame *parent = p; parent;
94 parent = FRAME_PARENT_FRAME (parent))
95 {
96 *x -= parent->left_pos;
97 *y -= parent->top_pos;
98 }
99}
100
101static void
102haiku_delete_terminal (struct terminal *terminal)
103{
104 emacs_abort ();
105}
106
107static const char *
108get_string_resource (void *ignored, const char *name, const char *class)
109{
110 if (!name)
111 return NULL;
112
113 Lisp_Object lval = assoc_no_quit (build_string (name), rdb);
114
115 if (!NILP (lval))
116 return SSDATA (XCDR (lval));
117
118 return NULL;
119}
120
121static void
122haiku_update_size_hints (struct frame *f)
123{
124 int base_width, base_height;
125 eassert (FRAME_HAIKU_P (f) && FRAME_HAIKU_WINDOW (f));
126
127 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
128 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
129
130 block_input ();
131 BWindow_set_size_alignment (FRAME_HAIKU_WINDOW (f),
132 frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f),
133 frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f));
134 BWindow_set_min_size (FRAME_HAIKU_WINDOW (f), base_width,
135 base_height
136 + FRAME_TOOL_BAR_HEIGHT (f)
137 + FRAME_MENU_BAR_HEIGHT (f));
138 unblock_input ();
139}
140
141static void
142haiku_clip_to_string (struct glyph_string *s)
143{
144 struct haiku_rect r[2];
145 int n = get_glyph_string_clip_rects (s, (struct haiku_rect *) &r, 2);
146
147 if (n)
148 BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[0].x, r[0].y,
149 r[0].width, r[0].height);
150 if (n > 1)
151 {
152 BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[1].x, r[1].y,
153 r[1].width, r[1].height);
154 }
155
156 s->num_clips = n;
157}
158
159static void
160haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst)
161{
162 BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y,
163 s->width, s->height);
164 dst->num_clips = 1;
165}
166
167static void
168haiku_flip_buffers (struct frame *f)
169{
170 void *view = FRAME_OUTPUT_DATA (f)->view;
171 block_input ();
172
173 BView_draw_lock (view);
174 FRAME_DIRTY_P (f) = 0;
175 EmacsView_flip_and_blit (view);
176 BView_draw_unlock (view);
177
178 unblock_input ();
179}
180
181static void
182haiku_frame_up_to_date (struct frame *f)
183{
184 block_input ();
185 FRAME_MOUSE_UPDATE (f);
186 if (FRAME_DIRTY_P (f) && !buffer_flipping_blocked_p ())
187 haiku_flip_buffers (f);
188 unblock_input ();
189}
190
191static void
192haiku_buffer_flipping_unblocked_hook (struct frame *f)
193{
194 if (FRAME_DIRTY_P (f))
195 haiku_flip_buffers (f);
196}
197
198static void
199haiku_clear_frame_area (struct frame *f, int x, int y,
200 int width, int height)
201{
202 void *vw = FRAME_HAIKU_VIEW (f);
203 block_input ();
204 BView_draw_lock (vw);
205 BView_StartClip (vw);
206 BView_ClipToRect (vw, x, y, width, height);
207 BView_SetHighColor (vw, FRAME_BACKGROUND_PIXEL (f));
208 BView_FillRectangle (vw, x, y, width, height);
209 BView_EndClip (vw);
210 BView_draw_unlock (vw);
211 unblock_input ();
212}
213
214static void
215haiku_clear_frame (struct frame *f)
216{
217 void *view = FRAME_HAIKU_VIEW (f);
218 block_input ();
219 BView_draw_lock (view);
220 BView_StartClip (view);
221 BView_ClipToRect (view, 0, 0, FRAME_PIXEL_WIDTH (f),
222 FRAME_PIXEL_HEIGHT (f));
223 BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f));
224 BView_FillRectangle (view, 0, 0, FRAME_PIXEL_WIDTH (f),
225 FRAME_PIXEL_HEIGHT (f));
226 BView_EndClip (view);
227 BView_draw_unlock (view);
228 unblock_input ();
229}
230
231/* Give frame F the font FONT-OBJECT as its default font. The return
232 value is FONT-OBJECT. FONTSET is an ID of the fontset for the
233 frame. If it is negative, generate a new fontset from
234 FONT-OBJECT. */
235
236static Lisp_Object
237haiku_new_font (struct frame *f, Lisp_Object font_object, int fontset)
238{
239 struct font *font = XFONT_OBJECT (font_object);
240 if (fontset < 0)
241 fontset = fontset_from_font (font_object);
242
243 FRAME_FONTSET (f) = fontset;
244 if (FRAME_FONT (f) == font)
245 return font_object;
246
247 FRAME_FONT (f) = font;
248 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
249 FRAME_COLUMN_WIDTH (f) = font->average_width;
250
251 int ascent, descent;
252 get_font_ascent_descent (font, &ascent, &descent);
253 FRAME_LINE_HEIGHT (f) = ascent + descent;
254 FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
255
256 int unit = FRAME_COLUMN_WIDTH (f);
257 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
258 FRAME_CONFIG_SCROLL_BAR_COLS (f)
259 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
260 else
261 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
262
263 if (FRAME_HAIKU_WINDOW (f))
264 {
265 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
266 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f),
267 3, false, Qfont);
268
269 haiku_clear_under_internal_border (f);
270 }
271 return font_object;
272}
273
274static int
275haiku_valid_modifier_p (Lisp_Object sym)
276{
277 return EQ (sym, Qcommand) || EQ (sym, Qshift)
278 || EQ (sym, Qcontrol) || EQ (sym, Qoption);
279}
280
281#define MODIFIER_OR(obj, def) (haiku_valid_modifier_p (obj) ? obj : def)
282
283static void
284haiku_add_modifier (int modifier, int toput, Lisp_Object qtem, int *modifiers)
285{
286 if ((modifier & HAIKU_MODIFIER_ALT && EQ (qtem, Qcommand))
287 || (modifier & HAIKU_MODIFIER_SHIFT && EQ (qtem, Qshift))
288 || (modifier & HAIKU_MODIFIER_CTRL && EQ (qtem, Qcontrol))
289 || (modifier & HAIKU_MODIFIER_SUPER && EQ (qtem, Qoption)))
290 *modifiers |= toput;
291}
292
293static int
294haiku_modifiers_to_emacs (int haiku_key)
295{
296 int modifiers = 0;
297 haiku_add_modifier (haiku_key, shift_modifier,
298 MODIFIER_OR (Vhaiku_shift_keysym, Qshift), &modifiers);
299 haiku_add_modifier (haiku_key, super_modifier,
300 MODIFIER_OR (Vhaiku_super_keysym, Qoption), &modifiers);
301 haiku_add_modifier (haiku_key, meta_modifier,
302 MODIFIER_OR (Vhaiku_meta_keysym, Qcommand), &modifiers);
303 haiku_add_modifier (haiku_key, ctrl_modifier,
304 MODIFIER_OR (Vhaiku_control_keysym, Qcontrol), &modifiers);
305 return modifiers;
306}
307
308#undef MODIFIER_OR
309
310static void
311haiku_rehighlight (void)
312{
313 eassert (x_display_list && !x_display_list->next);
314
315 block_input ();
316
317 struct frame *old_hl = x_display_list->highlight_frame;
318
319 if (x_display_list->focused_frame)
320 {
321 x_display_list->highlight_frame
322 = ((FRAMEP (FRAME_FOCUS_FRAME (x_display_list->focused_frame)))
323 ? XFRAME (FRAME_FOCUS_FRAME (x_display_list->focused_frame))
324 : x_display_list->focused_frame);
325 if (!FRAME_LIVE_P (x_display_list->highlight_frame))
326 {
327 fset_focus_frame (x_display_list->focused_frame, Qnil);
328 x_display_list->highlight_frame = x_display_list->focused_frame;
329 }
330 }
331 else
332 x_display_list->highlight_frame = 0;
333
334 if (old_hl)
335 gui_update_cursor (old_hl, true);
336
337 if (x_display_list->highlight_frame)
338 gui_update_cursor (x_display_list->highlight_frame, true);
339 unblock_input ();
340}
341
342static void
343haiku_frame_raise_lower (struct frame *f, bool raise_p)
344{
345 if (raise_p)
346 {
347 block_input ();
348 BWindow_activate (FRAME_HAIKU_WINDOW (f));
349 flush_frame (f);
350 unblock_input ();
351 }
352}
353
354/* Unfortunately, NOACTIVATE is not implementable on Haiku. */
355static void
356haiku_focus_frame (struct frame *frame, bool noactivate)
357{
358 if (x_display_list->focused_frame != frame)
359 haiku_frame_raise_lower (frame, 1);
360}
361
362static void
363haiku_new_focus_frame (struct frame *frame)
364{
365 eassert (x_display_list && !x_display_list->next);
366
367 block_input ();
368 if (frame != x_display_list->focused_frame)
369 {
370 if (x_display_list->focused_frame &&
371 x_display_list->focused_frame->auto_lower)
372 haiku_frame_raise_lower (x_display_list->focused_frame, 0);
373
374 x_display_list->focused_frame = frame;
375
376 if (frame && frame->auto_raise)
377 haiku_frame_raise_lower (frame, 1);
378 }
379 unblock_input ();
380
381 haiku_rehighlight ();
382}
383
384static void
385haiku_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
386{
387 haiku_set_name (f, arg, 0);
388}
389
390static void
391haiku_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor)
392{
393 haiku_query_color (FRAME_BACKGROUND_PIXEL (f), bgcolor);
394}
395
396static bool
397haiku_defined_color (struct frame *f,
398 const char *name,
399 Emacs_Color *color,
400 bool alloc,
401 bool make_index)
402{
403 return !haiku_get_color (name, color);
404}
405
406/* Adapted from xterm `x_draw_box_rect'. */
407static void
408haiku_draw_box_rect (struct glyph_string *s,
409 int left_x, int top_y, int right_x, int bottom_y, int hwidth,
410 int vwidth, bool left_p, bool right_p, struct haiku_rect *clip_rect)
411{
412 void *view = FRAME_HAIKU_VIEW (s->f);
413 struct face *face = s->face;
414
415 BView_StartClip (view);
416 BView_SetHighColor (view, face->box_color);
417 if (clip_rect)
418 BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width,
419 clip_rect->height);
420 BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth);
421 if (left_p)
422 BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
423
424 BView_FillRectangle (view, left_x, bottom_y - hwidth + 1,
425 right_x - left_x + 1, hwidth);
426 if (right_p)
427 BView_FillRectangle (view, right_x - vwidth + 1,
428 top_y, vwidth, bottom_y - top_y + 1);
429 BView_EndClip (view);
430}
431
432static void
433haiku_calculate_relief_colors (struct glyph_string *s,
434 uint32_t *rgbout_w, uint32_t *rgbout_b,
435 uint32_t *rgbout_c)
436{
437 struct face *face = s->face;
438
439 prepare_face_for_display (s->f, s->face);
440
441 uint32_t rgbin = face->use_box_color_for_shadows_p
442 ? face->box_color : face->background;
443
444 if (s->hl == DRAW_CURSOR)
445 rgbin = FRAME_CURSOR_COLOR (s->f).pixel;
446
447 double h, cs, l;
448 rgb_color_hsl (rgbin, &h, &cs, &l);
449
450 hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 0.6), rgbout_b);
451 hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 1.2), rgbout_w);
452 hsl_color_rgb (h, cs, fmin (1.0, fmax (0.2, l) * 1.8), rgbout_c);
453}
454
455static void
456haiku_draw_relief_rect (struct glyph_string *s,
457 int left_x, int top_y, int right_x, int bottom_y,
458 int hwidth, int vwidth, bool raised_p, bool top_p, bool bot_p,
459 bool left_p, bool right_p,
460 struct haiku_rect *clip_rect, bool fancy_p)
461{
462 uint32_t color_white;
463 uint32_t color_black;
464 uint32_t color_corner;
465
466 haiku_calculate_relief_colors (s, &color_white, &color_black,
467 &color_corner);
468
469 void *view = FRAME_HAIKU_VIEW (s->f);
470 BView_StartClip (view);
471
472 BView_SetHighColor (view, raised_p ? color_white : color_black);
473 if (clip_rect)
474 BView_ClipToRect (view, clip_rect->x, clip_rect->y, clip_rect->width,
475 clip_rect->height);
476 if (top_p)
477 BView_FillRectangle (view, left_x, top_y, right_x - left_x + 1, hwidth);
478 if (left_p)
479 BView_FillRectangle (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
480 BView_SetHighColor (view, !raised_p ? color_white : color_black);
481
482 if (bot_p)
483 BView_FillRectangle (view, left_x, bottom_y - hwidth + 1,
484 right_x - left_x + 1, hwidth);
485 if (right_p)
486 BView_FillRectangle (view, right_x - vwidth + 1, top_y,
487 vwidth, bottom_y - top_y + 1);
488
489 /* Draw the triangle for the bottom-left corner. */
490 if (bot_p && left_p)
491 {
492 BView_SetHighColor (view, raised_p ? color_white : color_black);
493 BView_FillTriangle (view, left_x, bottom_y - hwidth, left_x + vwidth,
494 bottom_y - hwidth, left_x, bottom_y);
495 }
496
497 /* Now draw the triangle for the top-right corner. */
498 if (top_p && right_p)
499 {
500 BView_SetHighColor (view, raised_p ? color_white : color_black);
501 BView_FillTriangle (view, right_x - vwidth, top_y,
502 right_x, top_y,
503 right_x - vwidth, top_y + hwidth);
504 }
505
506 /* If (h/v)width is > 1, we draw the outer-most line on each side in the
507 black relief color. */
508
509 BView_SetHighColor (view, color_black);
510
511 if (hwidth > 1 && top_p)
512 BView_StrokeLine (view, left_x, top_y, right_x, top_y);
513 if (hwidth > 1 && bot_p)
514 BView_StrokeLine (view, left_x, bottom_y, right_x, bottom_y);
515 if (vwidth > 1 && left_p)
516 BView_StrokeLine (view, left_x, top_y, left_x, bottom_y);
517 if (vwidth > 1 && right_p)
518 BView_StrokeLine (view, right_x, top_y, right_x, bottom_y);
519
520 BView_SetHighColor (view, color_corner);
521
522 /* Omit corner pixels. */
523 if (hwidth > 1 || vwidth > 1)
524 {
525 if (left_p && top_p)
526 BView_FillRectangle (view, left_x, top_y, 1, 1);
527 if (left_p && bot_p)
528 BView_FillRectangle (view, left_x, bottom_y, 1, 1);
529 if (right_p && top_p)
530 BView_FillRectangle (view, right_x, top_y, 1, 1);
531 if (right_p && bot_p)
532 BView_FillRectangle (view, right_x, bottom_y, 1, 1);
533 }
534
535 BView_EndClip (view);
536}
537
538static void
539haiku_draw_string_box (struct glyph_string *s, int clip_p)
540{
541 int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x;
542 bool raised_p, left_p, right_p;
543 struct glyph *last_glyph;
544 struct haiku_rect clip_rect;
545
546 struct face *face = s->face;
547
548 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
549 ? WINDOW_RIGHT_EDGE_X (s->w)
550 : window_box_right (s->w, s->area));
551
552 /* The glyph that may have a right box line. For static
553 compositions and images, the right-box flag is on the first glyph
554 of the glyph string; for other types it's on the last glyph. */
555 if (s->cmp || s->img)
556 last_glyph = s->first_glyph;
557 else if (s->first_glyph->type == COMPOSITE_GLYPH
558 && s->first_glyph->u.cmp.automatic)
559 {
560 /* For automatic compositions, we need to look up the last glyph
561 in the composition. */
562 struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area];
563 struct glyph *g = s->first_glyph;
564 for (last_glyph = g++;
565 g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id
566 && g->slice.cmp.to < s->cmp_to;
567 last_glyph = g++)
568 ;
569 }
570 else
571 last_glyph = s->first_glyph + s->nchars - 1;
572
573 vwidth = eabs (face->box_vertical_line_width);
574 hwidth = eabs (face->box_horizontal_line_width);
575 raised_p = face->box == FACE_RAISED_BOX;
576 left_x = s->x;
577 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
578 ? last_x - 1
579 : min (last_x, s->x + s->background_width) - 1);
580
581 top_y = s->y;
582 bottom_y = top_y + s->height - 1;
583
584 left_p = (s->first_glyph->left_box_line_p
585 || (s->hl == DRAW_MOUSE_FACE
586 && (s->prev == NULL
587 || s->prev->hl != s->hl)));
588 right_p = (last_glyph->right_box_line_p
589 || (s->hl == DRAW_MOUSE_FACE
590 && (s->next == NULL
591 || s->next->hl != s->hl)));
592
593 get_glyph_string_clip_rect (s, &clip_rect);
594
595 if (face->box == FACE_SIMPLE_BOX)
596 haiku_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
597 vwidth, left_p, right_p, &clip_rect);
598 else
599 haiku_draw_relief_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
600 vwidth, raised_p, true, true, left_p, right_p,
601 &clip_rect, 1);
602
603 if (clip_p)
604 {
605 void *view = FRAME_HAIKU_VIEW (s->f);
606 BView_ClipToInverseRect (view, left_x, top_y, right_x - left_x + 1, hwidth);
607 if (left_p)
608 BView_ClipToInverseRect (view, left_x, top_y, vwidth, bottom_y - top_y + 1);
609 BView_ClipToInverseRect (view, left_x, bottom_y - hwidth + 1,
610 right_x - left_x + 1, hwidth);
611 if (right_p)
612 BView_ClipToInverseRect (view, right_x - vwidth + 1,
613 top_y, vwidth, bottom_y - top_y + 1);
614 }
615}
616
617static void
618haiku_draw_plain_background (struct glyph_string *s, struct face *face,
619 int box_line_hwidth, int box_line_vwidth)
620{
621 void *view = FRAME_HAIKU_VIEW (s->f);
622 BView_StartClip (view);
623 if (s->hl == DRAW_CURSOR)
624 BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
625 else
626 BView_SetHighColor (view, face->background_defaulted_p ?
627 FRAME_BACKGROUND_PIXEL (s->f) :
628 face->background);
629
630 BView_FillRectangle (view, s->x,
631 s->y + box_line_hwidth,
632 s->background_width,
633 s->height - 2 * box_line_hwidth);
634 BView_EndClip (view);
635}
636
637static void
638haiku_draw_stipple_background (struct glyph_string *s, struct face *face,
639 int box_line_hwidth, int box_line_vwidth)
640{
641}
642
643static void
644haiku_maybe_draw_background (struct glyph_string *s, int force_p)
645{
646 if ((s->first_glyph->type != IMAGE_GLYPH) && !s->background_filled_p)
647 {
648 struct face *face = s->face;
649 int box_line_width = max (face->box_horizontal_line_width, 0);
650 int box_vline_width = max (face->box_vertical_line_width, 0);
651
652 if (FONT_HEIGHT (s->font) < s->height - 2 * box_vline_width
653 || FONT_TOO_HIGH (s->font)
654 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
655 {
656 if (!face->stipple)
657 haiku_draw_plain_background (s, face, box_line_width,
658 box_vline_width);
659 else
660 haiku_draw_stipple_background (s, face, box_line_width,
661 box_vline_width);
662 s->background_filled_p = 1;
663 }
664 }
665}
666
667static void
668haiku_mouse_face_colors (struct glyph_string *s, uint32_t *fg,
669 uint32_t *bg)
670{
671 int face_id;
672 struct face *face;
673
674 /* What face has to be used last for the mouse face? */
675 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
676 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
677 if (face == NULL)
678 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
679
680 if (s->first_glyph->type == CHAR_GLYPH)
681 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
682 else
683 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
684
685 face = FACE_FROM_ID (s->f, face_id);
686 prepare_face_for_display (s->f, s->face);
687
688 if (fg)
689 *fg = face->foreground;
690 if (bg)
691 *bg = face->background;
692}
693
694static void
695haiku_draw_underwave (struct glyph_string *s, int width, int x)
696{
697 int wave_height = 3, wave_length = 2;
698 int y, dx, dy, odd, xmax;
699 dx = wave_length;
700 dy = wave_height - 1;
701 y = s->ybase - wave_height + 3;
702
703 float ax, ay, bx, by;
704 xmax = x + width;
705
706 void *view = FRAME_HAIKU_VIEW (s->f);
707
708 BView_StartClip (view);
709 BView_ClipToRect (view, x, y, width, wave_height);
710 ax = x - ((int) (x) % dx) + (float) 0.5;
711 bx = ax + dx;
712 odd = (int) (ax / dx) % 2;
713 ay = by = y + 0.5;
714
715 if (odd)
716 ay += dy;
717 else
718 by += dy;
719
720 while (ax <= xmax)
721 {
722 BView_StrokeLine (view, ax, ay, bx, by);
723 ax = bx, ay = by;
724 bx += dx, by = y + 0.5 + odd * dy;
725 odd = !odd;
726 }
727 BView_EndClip (view);
728}
729
730static void
731haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
732 uint8_t dcol, int width, int x)
733{
734 if (s->for_overlaps)
735 return;
736
737 void *view = FRAME_HAIKU_VIEW (s->f);
738 BView_draw_lock (view);
739 BView_StartClip (view);
740
741 if (face->underline)
742 {
743 if (s->hl == DRAW_CURSOR)
744 BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
745 else if (!face->underline_defaulted_p)
746 BView_SetHighColor (view, face->underline_color);
747 else
748 BView_SetHighColor (view, dcol);
749
750 if (face->underline == FACE_UNDER_WAVE)
751 haiku_draw_underwave (s, width, x);
752 else if (face->underline == FACE_UNDER_LINE)
753 {
754 unsigned long thickness, position;
755 int y;
756
757 if (s->prev && s->prev && s->prev->hl == DRAW_MOUSE_FACE)
758 {
759 struct face *prev_face = s->prev->face;
760
761 if (prev_face && prev_face->underline == FACE_UNDER_LINE)
762 {
763 /* We use the same underline style as the previous one. */
764 thickness = s->prev->underline_thickness;
765 position = s->prev->underline_position;
766 }
767 else
768 goto calculate_underline_metrics;
769 }
770 else
771 {
772 calculate_underline_metrics:;
773 struct font *font = font_for_underline_metrics (s);
774 unsigned long minimum_offset;
775 bool underline_at_descent_line;
776 bool use_underline_position_properties;
777 Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE
778 (Qunderline_minimum_offset, s->w));
779
780 if (FIXNUMP (val))
781 minimum_offset = max (0, XFIXNUM (val));
782 else
783 minimum_offset = 1;
784
785 val = (WINDOW_BUFFER_LOCAL_VALUE
786 (Qx_underline_at_descent_line, s->w));
787 underline_at_descent_line
788 = !(NILP (val) || EQ (val, Qunbound));
789
790 val = (WINDOW_BUFFER_LOCAL_VALUE
791 (Qx_use_underline_position_properties, s->w));
792 use_underline_position_properties
793 = !(NILP (val) || EQ (val, Qunbound));
794
795 /* Get the underline thickness. Default is 1 pixel. */
796 if (font && font->underline_thickness > 0)
797 thickness = font->underline_thickness;
798 else
799 thickness = 1;
800 if (underline_at_descent_line)
801 position = (s->height - thickness) - (s->ybase - s->y);
802 else
803 {
804 /* Get the underline position. This is the
805 recommended vertical offset in pixels from
806 the baseline to the top of the underline.
807 This is a signed value according to the
808 specs, and its default is
809
810 ROUND ((maximum descent) / 2), with
811 ROUND(x) = floor (x + 0.5) */
812
813 if (use_underline_position_properties
814 && font && font->underline_position >= 0)
815 position = font->underline_position;
816 else if (font)
817 position = (font->descent + 1) / 2;
818 else
819 position = minimum_offset;
820 }
821 position = max (position, minimum_offset);
822 }
823 /* Check the sanity of thickness and position. We should
824 avoid drawing underline out of the current line area. */
825 if (s->y + s->height <= s->ybase + position)
826 position = (s->height - 1) - (s->ybase - s->y);
827 if (s->y + s->height < s->ybase + position + thickness)
828 thickness = (s->y + s->height) - (s->ybase + position);
829 s->underline_thickness = thickness;
830 s->underline_position = position;
831 y = s->ybase + position;
832
833 BView_FillRectangle (view, s->x, y, s->width, thickness);
834 }
835 }
836
837 if (face->overline_p)
838 {
839 unsigned long dy = 0, h = 1;
840 if (s->hl == DRAW_CURSOR)
841 BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
842 else if (!face->overline_color_defaulted_p)
843 BView_SetHighColor (view, face->overline_color);
844 else
845 BView_SetHighColor (view, dcol);
846
847 BView_FillRectangle (view, s->x, s->y + dy, s->width, h);
848 }
849
850 if (face->strike_through_p)
851 {
852 /* Y-coordinate and height of the glyph string's first
853 glyph. We cannot use s->y and s->height because those
854 could be larger if there are taller display elements
855 (e.g., characters displayed with a larger font) in the
856 same glyph row. */
857 int glyph_y = s->ybase - s->first_glyph->ascent;
858 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
859 /* Strike-through width and offset from the glyph string's
860 top edge. */
861 unsigned long h = 1;
862 unsigned long dy = (glyph_height - h) / 2;
863
864 if (s->hl == DRAW_CURSOR)
865 BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
866 else if (!face->strike_through_color_defaulted_p)
867 BView_SetHighColor (view, face->strike_through_color);
868 else
869 BView_SetHighColor (view, dcol);
870
871 BView_FillRectangle (view, s->x, glyph_y + dy, s->width, h);
872 }
873
874 BView_EndClip (view);
875 BView_draw_unlock (view);
876}
877
878static void
879haiku_draw_glyph_string_foreground (struct glyph_string *s)
880{
881 struct face *face = s->face;
882
883 int i, x;
884 if (face->box != FACE_NO_BOX
885 && s->first_glyph->left_box_line_p)
886 x = s->x + max (face->box_vertical_line_width, 0);
887 else
888 x = s->x;
889
890 void *view = FRAME_HAIKU_VIEW (s->f);
891
892 if (s->font_not_found_p)
893 {
894 BView_StartClip (view);
895 if (s->hl == DRAW_CURSOR)
896 BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
897 else
898 BView_SetHighColor (view, face->foreground);
899 for (i = 0; i < s->nchars; ++i)
900 {
901 struct glyph *g = s->first_glyph + i;
902 BView_StrokeRectangle (view, x, s->y, g->pixel_width,
903 s->height);
904 x += g->pixel_width;
905 }
906 BView_EndClip (view);
907 }
908 else
909 {
910 struct font *ft = s->font;
911 int off = ft->baseline_offset;
912 int y;
913
914 if (ft->vertical_centering)
915 off = VCENTER_BASELINE_OFFSET (ft, s->f) - off;
916 y = s->ybase - off;
917 if (s->for_overlaps || (s->background_filled_p && s->hl != DRAW_CURSOR))
918 ft->driver->draw (s, 0, s->nchars, x, y, false);
919 else
920 ft->driver->draw (s, 0, s->nchars, x, y, true);
921
922 if (face->overstrike)
923 ft->driver->draw (s, 0, s->nchars, x + 1, y, false);
924 }
925}
926
927static void
928haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
929{
930 struct glyph *glyph = s->first_glyph;
931 unsigned char2b[8];
932 int x, i, j;
933 struct face *face = s->face;
934
935 /* If first glyph of S has a left box line, start drawing the text
936 of S to the right of that box line. */
937 if (face && face->box != FACE_NO_BOX
938 && s->first_glyph->left_box_line_p)
939 x = s->x + max (face->box_vertical_line_width, 0);
940 else
941 x = s->x;
942
943 s->char2b = char2b;
944
945 for (i = 0; i < s->nchars; i++, glyph++)
946 {
947#ifdef GCC_LINT
948 enum { PACIFY_GCC_BUG_81401 = 1 };
949#else
950 enum { PACIFY_GCC_BUG_81401 = 0 };
951#endif
952 char buf[7 + PACIFY_GCC_BUG_81401];
953 char *str = NULL;
954 int len = glyph->u.glyphless.len;
955
956 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
957 {
958 if (len > 0
959 && CHAR_TABLE_P (Vglyphless_char_display)
960 && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
961 >= 1))
962 {
963 Lisp_Object acronym
964 = (! glyph->u.glyphless.for_no_font
965 ? CHAR_TABLE_REF (Vglyphless_char_display,
966 glyph->u.glyphless.ch)
967 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
968 if (STRINGP (acronym))
969 str = SSDATA (acronym);
970 }
971 }
972 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
973 {
974 unsigned int ch = glyph->u.glyphless.ch;
975 eassume (ch <= MAX_CHAR);
976 sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch);
977 str = buf;
978 }
979
980 if (str)
981 {
982 int upper_len = (len + 1) / 2;
983
984 /* It is assured that all LEN characters in STR is ASCII. */
985 for (j = 0; j < len; j++)
986 char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF;
987
988 s->font->driver->draw (s, 0, upper_len,
989 x + glyph->slice.glyphless.upper_xoff,
990 s->ybase + glyph->slice.glyphless.upper_yoff,
991 false);
992 s->font->driver->draw (s, upper_len, len,
993 x + glyph->slice.glyphless.lower_xoff,
994 s->ybase + glyph->slice.glyphless.lower_yoff,
995 false);
996 }
997 BView_StartClip (FRAME_HAIKU_VIEW (s->f));
998 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
999 BView_FillRectangle (FRAME_HAIKU_VIEW (s->f),
1000 x, s->ybase - glyph->ascent,
1001 glyph->pixel_width - 1,
1002 glyph->ascent + glyph->descent - 1);
1003 BView_EndClip (FRAME_HAIKU_VIEW (s->f));
1004 x += glyph->pixel_width;
1005 }
1006}
1007
1008static void
1009haiku_draw_stretch_glyph_string (struct glyph_string *s)
1010{
1011 eassert (s->first_glyph->type == STRETCH_GLYPH);
1012
1013 struct face *face = s->face;
1014
1015 if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p)
1016 {
1017 int width, background_width = s->background_width;
1018 int x = s->x;
1019
1020 if (!s->row->reversed_p)
1021 {
1022 int left_x = window_box_left_offset (s->w, TEXT_AREA);
1023
1024 if (x < left_x)
1025 {
1026 background_width -= left_x - x;
1027 x = left_x;
1028 }
1029 }
1030 else
1031 {
1032 /* In R2L rows, draw the cursor on the right edge of the
1033 stretch glyph. */
1034 int right_x = window_box_right (s->w, TEXT_AREA);
1035 if (x + background_width > right_x)
1036 background_width -= x - right_x;
1037 x += background_width;
1038 }
1039
1040 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
1041 if (s->row->reversed_p)
1042 x -= width;
1043
1044 void *view = FRAME_HAIKU_VIEW (s->f);
1045 BView_StartClip (view);
1046 BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
1047 BView_FillRectangle (view, x, s->y, width, s->height);
1048 BView_EndClip (view);
1049
1050 if (width < background_width)
1051 {
1052 if (!s->row->reversed_p)
1053 x += width;
1054 else
1055 x = s->x;
1056
1057 int y = s->y;
1058 int w = background_width - width, h = s->height;
1059
1060 if (!face->stipple)
1061 {
1062 uint32_t bkg;
1063 if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR
1064 && s->row->mouse_face_p
1065 && cursor_in_mouse_face_p (s->w)))
1066 haiku_mouse_face_colors (s, NULL, &bkg);
1067 else
1068 bkg = face->background;
1069
1070 BView_StartClip (view);
1071 BView_SetHighColor (view, bkg);
1072 BView_FillRectangle (view, x, y, w, h);
1073 BView_EndClip (view);
1074 }
1075 }
1076 }
1077 else if (!s->background_filled_p)
1078 {
1079 int background_width = s->background_width;
1080 int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA);
1081
1082 /* Don't draw into left fringe or scrollbar area except for
1083 header line and mode line. */
1084 if (s->area == TEXT_AREA
1085 && x < text_left_x && !s->row->mode_line_p)
1086 {
1087 background_width -= text_left_x - x;
1088 x = text_left_x;
1089 }
1090
1091 if (background_width > 0)
1092 {
1093 void *view = FRAME_HAIKU_VIEW (s->f);
1094 BView_StartClip (view);
1095 uint32_t bkg;
1096 if (s->hl == DRAW_MOUSE_FACE)
1097 haiku_mouse_face_colors (s, NULL, &bkg);
1098 else if (s->hl == DRAW_CURSOR)
1099 bkg = FRAME_CURSOR_COLOR (s->f).pixel;
1100 else
1101 bkg = s->face->background;
1102
1103 BView_SetHighColor (view, bkg);
1104 BView_FillRectangle (view, x, s->y, background_width, s->height);
1105 BView_EndClip (view);
1106 }
1107 }
1108 s->background_filled_p = 1;
1109}
1110
1111static void
1112haiku_start_clip (struct glyph_string *s)
1113{
1114 void *view = FRAME_HAIKU_VIEW (s->f);
1115 BView_draw_lock (view);
1116 BView_StartClip (view);
1117}
1118
1119static void
1120haiku_end_clip (struct glyph_string *s)
1121{
1122 void *view = FRAME_HAIKU_VIEW (s->f);
1123 BView_EndClip (view);
1124 BView_draw_unlock (view);
1125}
1126
1127static void
1128haiku_clip_to_row (struct window *w, struct glyph_row *row,
1129 enum glyph_row_area area)
1130{
1131 struct frame *f = WINDOW_XFRAME (w);
1132 int window_x, window_y, window_width;
1133 int x, y, width, height;
1134
1135 window_box (w, area, &window_x, &window_y, &window_width, 0);
1136
1137 x = window_x;
1138 y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1139 y = max (y, window_y);
1140 width = window_width;
1141 height = row->visible_height;
1142
1143 BView_ClipToRect (FRAME_HAIKU_VIEW (f), x, y, width, height);
1144}
1145
1146static void
1147haiku_update_begin (struct frame *f)
1148{
1149}
1150
1151static void
1152haiku_update_end (struct frame *f)
1153{
1154 MOUSE_HL_INFO (f)->mouse_face_defer = false;
1155 flush_frame (f);
1156}
1157
1158static void
1159haiku_draw_composite_glyph_string_foreground (struct glyph_string *s)
1160{
1161 int i, j, x;
1162 struct font *font = s->font;
1163 void *view = FRAME_HAIKU_VIEW (s->f);
1164 struct face *face = s->face;
1165
1166 /* If first glyph of S has a left box line, start drawing the text
1167 of S to the right of that box line. */
1168 if (face && face->box != FACE_NO_BOX
1169 && s->first_glyph->left_box_line_p)
1170 x = s->x + max (face->box_vertical_line_width, 0);
1171 else
1172 x = s->x;
1173
1174 /* S is a glyph string for a composition. S->cmp_from is the index
1175 of the first character drawn for glyphs of this composition.
1176 S->cmp_from == 0 means we are drawing the very first character of
1177 this composition. */
1178
1179 /* Draw a rectangle for the composition if the font for the very
1180 first character of the composition could not be loaded. */
1181
1182 if (s->font_not_found_p && !s->cmp_from)
1183 {
1184 BView_StartClip (view);
1185 if (s->hl == DRAW_CURSOR)
1186 BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
1187 else
1188 BView_SetHighColor (view, s->face->foreground);
1189 BView_StrokeRectangle (view, s->x, s->y, s->width - 1, s->height - 1);
1190 BView_EndClip (view);
1191 }
1192 else if (!s->first_glyph->u.cmp.automatic)
1193 {
1194 int y = s->ybase;
1195
1196 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
1197 /* TAB in a composition means display glyphs with padding
1198 space on the left or right. */
1199 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1200 {
1201 int xx = x + s->cmp->offsets[j * 2];
1202 int yy = y - s->cmp->offsets[j * 2 + 1];
1203
1204 font->driver->draw (s, j, j + 1, xx, yy, false);
1205 if (face->overstrike)
1206 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
1207 }
1208 }
1209 else
1210 {
1211 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1212 Lisp_Object glyph;
1213 int y = s->ybase;
1214 int width = 0;
1215
1216 for (i = j = s->cmp_from; i < s->cmp_to; i++)
1217 {
1218 glyph = LGSTRING_GLYPH (gstring, i);
1219 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1220 width += LGLYPH_WIDTH (glyph);
1221 else
1222 {
1223 int xoff, yoff, wadjust;
1224
1225 if (j < i)
1226 {
1227 font->driver->draw (s, j, i, x, y, false);
1228 if (s->face->overstrike)
1229 font->driver->draw (s, j, i, x + 1, y, false);
1230 x += width;
1231 }
1232 xoff = LGLYPH_XOFF (glyph);
1233 yoff = LGLYPH_YOFF (glyph);
1234 wadjust = LGLYPH_WADJUST (glyph);
1235 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
1236 if (face->overstrike)
1237 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
1238 false);
1239 x += wadjust;
1240 j = i + 1;
1241 width = 0;
1242 }
1243 }
1244 if (j < i)
1245 {
1246 font->driver->draw (s, j, i, x, y, false);
1247 if (face->overstrike)
1248 font->driver->draw (s, j, i, x + 1, y, false);
1249 }
1250 }
1251}
1252
1253static void
1254haiku_draw_image_relief (struct glyph_string *s)
1255{
1256 int x1, y1, thick;
1257 bool raised_p, top_p, bot_p, left_p, right_p;
1258 int extra_x, extra_y;
1259 struct haiku_rect r;
1260 int x = s->x;
1261 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
1262
1263 struct face *face = s->face;
1264
1265 /* If first glyph of S has a left box line, start drawing it to the
1266 right of that line. */
1267 if (face->box != FACE_NO_BOX
1268 && s->first_glyph->left_box_line_p
1269 && s->slice.x == 0)
1270 x += max (face->box_vertical_line_width, 0);
1271
1272 /* If there is a margin around the image, adjust x- and y-position
1273 by that margin. */
1274 if (s->slice.x == 0)
1275 x += s->img->hmargin;
1276 if (s->slice.y == 0)
1277 y += s->img->vmargin;
1278
1279 if (s->hl == DRAW_IMAGE_SUNKEN
1280 || s->hl == DRAW_IMAGE_RAISED)
1281 {
1282 if (s->face->id == TAB_BAR_FACE_ID)
1283 thick = (tab_bar_button_relief < 0
1284 ? DEFAULT_TAB_BAR_BUTTON_RELIEF
1285 : min (tab_bar_button_relief, 1000000));
1286 else
1287 thick = (tool_bar_button_relief < 0
1288 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
1289 : min (tool_bar_button_relief, 1000000));
1290 raised_p = s->hl == DRAW_IMAGE_RAISED;
1291 }
1292 else
1293 {
1294 thick = eabs (s->img->relief);
1295 raised_p = s->img->relief > 0;
1296 }
1297
1298 x1 = x + s->slice.width - 1;
1299 y1 = y + s->slice.height - 1;
1300
1301 extra_x = extra_y = 0;
1302
1303 if (s->face->id == TAB_BAR_FACE_ID)
1304 {
1305 if (CONSP (Vtab_bar_button_margin)
1306 && FIXNUMP (XCAR (Vtab_bar_button_margin))
1307 && FIXNUMP (XCDR (Vtab_bar_button_margin)))
1308 {
1309 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
1310 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
1311 }
1312 else if (FIXNUMP (Vtab_bar_button_margin))
1313 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
1314 }
1315
1316 if (s->face->id == TOOL_BAR_FACE_ID)
1317 {
1318 if (CONSP (Vtool_bar_button_margin)
1319 && FIXNUMP (XCAR (Vtool_bar_button_margin))
1320 && FIXNUMP (XCDR (Vtool_bar_button_margin)))
1321 {
1322 extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin));
1323 extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin));
1324 }
1325 else if (FIXNUMP (Vtool_bar_button_margin))
1326 extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin);
1327 }
1328
1329 top_p = bot_p = left_p = right_p = 0;
1330
1331 if (s->slice.x == 0)
1332 x -= thick + extra_x, left_p = 1;
1333 if (s->slice.y == 0)
1334 y -= thick + extra_y, top_p = 1;
1335 if (s->slice.x + s->slice.width == s->img->width)
1336 x1 += thick + extra_x, right_p = 1;
1337 if (s->slice.y + s->slice.height == s->img->height)
1338 y1 += thick + extra_y, bot_p = 1;
1339
1340 get_glyph_string_clip_rect (s, &r);
1341 haiku_draw_relief_rect (s, x, y, x1, y1, thick, thick, raised_p,
1342 top_p, bot_p, left_p, right_p, &r, 0);
1343}
1344
1345static void
1346haiku_draw_image_glyph_string (struct glyph_string *s)
1347{
1348 struct face *face = s->face;
1349
1350 int box_line_hwidth = max (face->box_vertical_line_width, 0);
1351 int box_line_vwidth = max (face->box_horizontal_line_width, 0);
1352
1353 int x, y;
1354 int height, width;
1355
1356 height = s->height;
1357 if (s->slice.y == 0)
1358 height -= box_line_vwidth;
1359 if (s->slice.y + s->slice.height >= s->img->height)
1360 height -= box_line_vwidth;
1361
1362 width = s->background_width;
1363 x = s->x;
1364 if (s->first_glyph->left_box_line_p
1365 && s->slice.x == 0)
1366 {
1367 x += box_line_hwidth;
1368 width -= box_line_hwidth;
1369 }
1370
1371 y = s->y;
1372 if (s->slice.y == 0)
1373 y += box_line_vwidth;
1374
1375 void *view = FRAME_HAIKU_VIEW (s->f);
1376 void *bitmap = s->img->pixmap;
1377
1378 s->stippled_p = face->stipple != 0;
1379
1380 BView_draw_lock (view);
1381 BView_StartClip (view);
1382 BView_SetHighColor (view, face->background);
1383 BView_FillRectangle (view, x, y, width, height);
1384 BView_EndClip (view);
1385 BView_draw_unlock (view);
1386
1387 if (bitmap)
1388 {
1389 struct haiku_rect nr;
1390 Emacs_Rectangle cr, ir, r;
1391
1392 get_glyph_string_clip_rect (s, &nr);
1393 CONVERT_TO_EMACS_RECT (cr, nr);
1394 x = s->x;
1395 y = s->ybase - image_ascent (s->img, face, &s->slice);
1396
1397 if (s->slice.x == 0)
1398 x += s->img->hmargin;
1399 if (s->slice.y == 0)
1400 y += s->img->vmargin;
1401
1402 if (face->box != FACE_NO_BOX
1403 && s->first_glyph->left_box_line_p
1404 && s->slice.x == 0)
1405 x += max (face->box_vertical_line_width, 0);
1406
1407 ir.x = x;
1408 ir.y = y;
1409 ir.width = s->slice.width;
1410 ir.height = s->slice.height;
1411 r = ir;
1412
1413 void *mask = s->img->mask;
1414
1415 if (gui_intersect_rectangles (&cr, &ir, &r))
1416 {
1417 BView_draw_lock (view);
1418 BView_StartClip (view);
1419
1420 haiku_clip_to_string (s);
1421 if (s->img->have_be_transforms_p)
1422 {
1423 bitmap = BBitmap_transform_bitmap (bitmap,
1424 s->img->mask,
1425 face->background,
1426 s->img->be_rotate,
1427 s->img->width,
1428 s->img->height);
1429 mask = NULL;
1430 }
1431
1432 BView_DrawBitmap (view, bitmap,
1433 s->slice.x + r.x - x,
1434 s->slice.y + r.y - y,
1435 r.width, r.height,
1436 r.x, r.y, r.width, r.height);
1437 if (mask)
1438 {
1439 BView_DrawMask (mask, view,
1440 s->slice.x + r.x - x,
1441 s->slice.y + r.y - y,
1442 r.width, r.height,
1443 r.x, r.y, r.width, r.height,
1444 face->background);
1445 }
1446
1447 if (s->img->have_be_transforms_p)
1448 BBitmap_free (bitmap);
1449 BView_EndClip (view);
1450 BView_draw_unlock (view);
1451 }
1452
1453 if (s->hl == DRAW_CURSOR)
1454 {
1455 BView_draw_lock (view);
1456 BView_StartClip (view);
1457 BView_SetPenSize (view, 1);
1458 BView_SetHighColor (view, FRAME_CURSOR_COLOR (s->f).pixel);
1459 BView_StrokeRectangle (view, r.x, r.y, r.width, r.height);
1460 BView_EndClip (view);
1461 BView_draw_unlock (view);
1462 }
1463 }
1464
1465 if (s->img->relief
1466 || s->hl == DRAW_IMAGE_RAISED
1467 || s->hl == DRAW_IMAGE_SUNKEN)
1468 haiku_draw_image_relief (s);
1469}
1470
1471static void
1472haiku_draw_glyph_string (struct glyph_string *s)
1473{
1474 block_input ();
1475 prepare_face_for_display (s->f, s->face);
1476
1477 struct face *face = s->face;
1478 if (face != s->face)
1479 prepare_face_for_display (s->f, face);
1480
1481 if (s->next && s->right_overhang && !s->for_overlaps)
1482 {
1483 int width;
1484 struct glyph_string *next;
1485
1486 for (width = 0, next = s->next;
1487 next && width < s->right_overhang;
1488 width += next->width, next = next->next)
1489 if (next->first_glyph->type != IMAGE_GLYPH)
1490 {
1491 prepare_face_for_display (s->f, s->next->face);
1492 haiku_start_clip (s->next);
1493 haiku_clip_to_string (s->next);
1494 if (next->first_glyph->type != STRETCH_GLYPH)
1495 haiku_maybe_draw_background (s->next, 1);
1496 else
1497 haiku_draw_stretch_glyph_string (s->next);
1498 next->num_clips = 0;
1499 haiku_end_clip (s);
1500 }
1501 }
1502
1503 haiku_start_clip (s);
1504
1505 int box_filled_p = 0;
1506
1507 if (!s->for_overlaps && face->box != FACE_NO_BOX
1508 && (s->first_glyph->type == CHAR_GLYPH
1509 || s->first_glyph->type == COMPOSITE_GLYPH))
1510 {
1511 haiku_clip_to_string (s);
1512 haiku_maybe_draw_background (s, 1);
1513 box_filled_p = 1;
1514 haiku_draw_string_box (s, 0);
1515 }
1516 else if (!s->clip_head && !s->clip_tail &&
1517 ((s->prev && s->left_overhang && s->prev->hl != s->hl) ||
1518 (s->next && s->right_overhang && s->next->hl != s->hl)))
1519 haiku_clip_to_string_exactly (s, s);
1520 else
1521 haiku_clip_to_string (s);
1522
1523 if (s->for_overlaps)
1524 s->background_filled_p = 1;
1525
1526 switch (s->first_glyph->type)
1527 {
1528 case COMPOSITE_GLYPH:
1529 if (s->for_overlaps || (s->cmp_from > 0
1530 && ! s->first_glyph->u.cmp.automatic))
1531 s->background_filled_p = 1;
1532 else
1533 haiku_maybe_draw_background (s, 1);
1534 haiku_draw_composite_glyph_string_foreground (s);
1535 break;
1536 case CHAR_GLYPH:
1537 if (s->for_overlaps)
1538 s->background_filled_p = 1;
1539 else
1540 haiku_maybe_draw_background (s, 0);
1541 haiku_draw_glyph_string_foreground (s);
1542 break;
1543 case STRETCH_GLYPH:
1544 haiku_draw_stretch_glyph_string (s);
1545 break;
1546 case IMAGE_GLYPH:
1547 haiku_draw_image_glyph_string (s);
1548 break;
1549 case GLYPHLESS_GLYPH:
1550 if (s->for_overlaps)
1551 s->background_filled_p = 1;
1552 else
1553 haiku_maybe_draw_background (s, 1);
1554 haiku_draw_glyphless_glyph_string_foreground (s);
1555 break;
1556 }
1557
1558 if (!box_filled_p && face->box != FACE_NO_BOX)
1559 haiku_draw_string_box (s, 1);
1560
1561 if (!s->for_overlaps)
1562 {
1563 uint32_t dcol;
1564 dcol = face->foreground;
1565
1566 haiku_draw_text_decoration (s, face, dcol, s->width, s->x);
1567
1568 if (s->prev)
1569 {
1570 struct glyph_string *prev;
1571
1572 for (prev = s->prev; prev; prev = prev->prev)
1573 if (prev->hl != s->hl
1574 && prev->x + prev->width + prev->right_overhang > s->x)
1575 {
1576 /* As prev was drawn while clipped to its own area, we
1577 must draw the right_overhang part using s->hl now. */
1578 enum draw_glyphs_face save = prev->hl;
1579 struct face *save_face = prev->face;
1580
1581 prev->hl = s->hl;
1582 prev->face = s->face;
1583 haiku_start_clip (s);
1584 haiku_clip_to_string_exactly (s, prev);
1585 if (prev->first_glyph->type == CHAR_GLYPH)
1586 haiku_draw_glyph_string_foreground (prev);
1587 else
1588 haiku_draw_composite_glyph_string_foreground (prev);
1589 haiku_end_clip (s);
1590 prev->hl = save;
1591 prev->face = save_face;
1592 prev->num_clips = 0;
1593 }
1594 }
1595
1596 if (s->next)
1597 {
1598 struct glyph_string *next;
1599
1600 for (next = s->next; next; next = next->next)
1601 if (next->hl != s->hl
1602 && next->x - next->left_overhang < s->x + s->width)
1603 {
1604 /* As next will be drawn while clipped to its own area,
1605 we must draw the left_overhang part using s->hl now. */
1606 enum draw_glyphs_face save = next->hl;
1607 struct face *save_face = next->face;
1608
1609 next->hl = s->hl;
1610 next->face = s->face;
1611 haiku_start_clip (s);
1612 haiku_clip_to_string_exactly (s, next);
1613 if (next->first_glyph->type == CHAR_GLYPH)
1614 haiku_draw_glyph_string_foreground (next);
1615 else
1616 haiku_draw_composite_glyph_string_foreground (next);
1617 haiku_end_clip (s);
1618
1619 next->background_filled_p = 0;
1620 next->hl = save;
1621 next->face = save_face;
1622 next->clip_head = next;
1623 next->num_clips = 0;
1624 }
1625 }
1626 }
1627 s->num_clips = 0;
1628 haiku_end_clip (s);
1629 unblock_input ();
1630}
1631
1632static void
1633haiku_after_update_window_line (struct window *w,
1634 struct glyph_row *desired_row)
1635{
1636 eassert (w);
1637 struct frame *f;
1638 int width, height;
1639
1640 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1641 desired_row->redraw_fringe_bitmaps_p = true;
1642
1643 if (windows_or_buffers_changed
1644 && desired_row->full_width_p
1645 && (f = XFRAME (w->frame),
1646 width = FRAME_INTERNAL_BORDER_WIDTH (f),
1647 width != 0)
1648 && (height = desired_row->visible_height,
1649 height > 0))
1650 {
1651 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1652 int face_id =
1653 !NILP (Vface_remapping_alist)
1654 ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
1655 : INTERNAL_BORDER_FACE_ID;
1656 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
1657
1658 block_input ();
1659 if (face)
1660 {
1661 void *view = FRAME_HAIKU_VIEW (f);
1662 BView_draw_lock (view);
1663 BView_StartClip (view);
1664 BView_SetHighColor (view, face->background_defaulted_p ?
1665 FRAME_BACKGROUND_PIXEL (f) : face->background);
1666 BView_FillRectangle (view, 0, y, width, height);
1667 BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width,
1668 y, width, height);
1669 BView_EndClip (view);
1670 BView_draw_unlock (view);
1671 }
1672 else
1673 {
1674 haiku_clear_frame_area (f, 0, y, width, height);
1675 haiku_clear_frame_area (f, FRAME_PIXEL_WIDTH (f) - width,
1676 y, width, height);
1677 }
1678 unblock_input ();
1679 }
1680}
1681
1682static void
1683haiku_set_window_size (struct frame *f, bool change_gravity,
1684 int width, int height)
1685{
1686 haiku_update_size_hints (f);
1687
1688 if (FRAME_HAIKU_WINDOW (f))
1689 {
1690 block_input ();
1691 BWindow_resize (FRAME_HAIKU_WINDOW (f), width, height);
1692 unblock_input ();
1693 }
1694}
1695
1696static void
1697haiku_draw_window_cursor (struct window *w,
1698 struct glyph_row *glyph_row,
1699 int x, int y,
1700 enum text_cursor_kinds cursor_type,
1701 int cursor_width, bool on_p, bool active_p)
1702{
1703 struct frame *f = XFRAME (WINDOW_FRAME (w));
1704
1705 struct glyph *phys_cursor_glyph;
1706 struct glyph *cursor_glyph;
1707
1708 void *view = FRAME_HAIKU_VIEW (f);
1709
1710 int fx, fy, h, cursor_height;
1711
1712 if (!on_p)
1713 return;
1714
1715 if (cursor_type == NO_CURSOR)
1716 {
1717 w->phys_cursor_width = 0;
1718 return;
1719 }
1720
1721 w->phys_cursor_on_p = true;
1722 w->phys_cursor_type = cursor_type;
1723
1724 phys_cursor_glyph = get_phys_cursor_glyph (w);
1725
1726 if (!phys_cursor_glyph)
1727 {
1728 if (glyph_row->exact_window_width_line_p
1729 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
1730 {
1731 glyph_row->cursor_in_fringe_p = 1;
1732 draw_fringe_bitmap (w, glyph_row, 0);
1733 }
1734 return;
1735 }
1736
1737 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
1738
1739 if (cursor_type == BAR_CURSOR)
1740 {
1741 if (cursor_width < 1)
1742 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
1743 if (cursor_width < w->phys_cursor_width)
1744 w->phys_cursor_width = cursor_width;
1745 }
1746 else if (cursor_type == HBAR_CURSOR)
1747 {
1748 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
1749 if (cursor_height > glyph_row->height)
1750 cursor_height = glyph_row->height;
1751 if (h > cursor_height)
1752 fy += h - cursor_height;
1753 h = cursor_height;
1754 }
1755
1756 BView_draw_lock (view);
1757 BView_StartClip (view);
1758 BView_SetHighColor (view, FRAME_CURSOR_COLOR (f).pixel);
1759 haiku_clip_to_row (w, glyph_row, TEXT_AREA);
1760
1761 switch (cursor_type)
1762 {
1763 default:
1764 case DEFAULT_CURSOR:
1765 case NO_CURSOR:
1766 break;
1767 case HBAR_CURSOR:
1768 BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
1769 break;
1770 case BAR_CURSOR:
1771 cursor_glyph = get_phys_cursor_glyph (w);
1772 if (cursor_glyph->resolved_level & 1)
1773 BView_FillRectangle (view, fx + cursor_glyph->pixel_width - w->phys_cursor_width,
1774 fy, w->phys_cursor_width, h);
1775 else
1776 BView_FillRectangle (view, fx, fy, w->phys_cursor_width, h);
1777 break;
1778 case HOLLOW_BOX_CURSOR:
1779 if (phys_cursor_glyph->type != IMAGE_GLYPH)
1780 {
1781 BView_SetPenSize (view, 1);
1782 BView_StrokeRectangle (view, fx, fy, w->phys_cursor_width, h);
1783 }
1784 else
1785 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
1786 break;
1787 case FILLED_BOX_CURSOR:
1788 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
1789 }
1790 BView_EndClip (view);
1791 BView_draw_unlock (view);
1792}
1793
1794static void
1795haiku_show_hourglass (struct frame *f)
1796{
1797 if (FRAME_OUTPUT_DATA (f)->hourglass_p)
1798 return;
1799
1800 block_input ();
1801 FRAME_OUTPUT_DATA (f)->hourglass_p = 1;
1802
1803 if (FRAME_HAIKU_VIEW (f))
1804 BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
1805 FRAME_OUTPUT_DATA (f)->hourglass_cursor);
1806 unblock_input ();
1807}
1808
1809static void
1810haiku_hide_hourglass (struct frame *f)
1811{
1812 if (!FRAME_OUTPUT_DATA (f)->hourglass_p)
1813 return;
1814
1815 block_input ();
1816 FRAME_OUTPUT_DATA (f)->hourglass_p = 0;
1817
1818 if (FRAME_HAIKU_VIEW (f))
1819 BView_set_view_cursor (FRAME_HAIKU_VIEW (f),
1820 FRAME_OUTPUT_DATA (f)->current_cursor);
1821 unblock_input ();
1822}
1823
1824static void
1825haiku_compute_glyph_string_overhangs (struct glyph_string *s)
1826{
1827 if (s->cmp == NULL
1828 && (s->first_glyph->type == CHAR_GLYPH
1829 || s->first_glyph->type == COMPOSITE_GLYPH))
1830 {
1831 struct font_metrics metrics;
1832
1833 if (s->first_glyph->type == CHAR_GLYPH)
1834 {
1835 struct font *font = s->font;
1836 font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
1837 }
1838 else
1839 {
1840 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1841
1842 composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
1843 }
1844 s->right_overhang = (metrics.rbearing > metrics.width
1845 ? metrics.rbearing - metrics.width : 0);
1846 s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
1847 }
1848 else if (s->cmp)
1849 {
1850 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1851 s->left_overhang = - s->cmp->lbearing;
1852 }
1853}
1854
1855static void
1856haiku_draw_vertical_window_border (struct window *w,
1857 int x, int y_0, int y_1)
1858{
1859 struct frame *f = XFRAME (WINDOW_FRAME (w));
1860 struct face *face;
1861
1862 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
1863 void *view = FRAME_HAIKU_VIEW (f);
1864 BView_draw_lock (view);
1865 BView_StartClip (view);
1866 if (face)
1867 BView_SetHighColor (view, face->foreground);
1868 BView_StrokeLine (view, x, y_0, x, y_1);
1869 BView_EndClip (view);
1870 BView_draw_unlock (view);
1871}
1872
1873static void
1874haiku_set_scroll_bar_default_width (struct frame *f)
1875{
1876 int unit = FRAME_COLUMN_WIDTH (f);
1877 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = BScrollBar_default_size (0) + 1;
1878 FRAME_CONFIG_SCROLL_BAR_COLS (f) =
1879 (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
1880}
1881
1882static void
1883haiku_set_scroll_bar_default_height (struct frame *f)
1884{
1885 int height = FRAME_LINE_HEIGHT (f);
1886 FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = BScrollBar_default_size (1) + 1;
1887 FRAME_CONFIG_SCROLL_BAR_LINES (f) =
1888 (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
1889}
1890
1891static void
1892haiku_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
1893{
1894 struct frame *f = XFRAME (WINDOW_FRAME (w));
1895 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
1896 struct face *face_first
1897 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
1898 struct face *face_last
1899 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
1900 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
1901 unsigned long color_first = (face_first
1902 ? face_first->foreground
1903 : FRAME_FOREGROUND_PIXEL (f));
1904 unsigned long color_last = (face_last
1905 ? face_last->foreground
1906 : FRAME_FOREGROUND_PIXEL (f));
1907 void *view = FRAME_HAIKU_VIEW (f);
1908
1909 BView_draw_lock (view);
1910 BView_StartClip (view);
1911
1912 if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
1913 /* A vertical divider, at least three pixels wide: Draw first and
1914 last pixels differently. */
1915 {
1916 BView_SetHighColor (view, color_first);
1917 BView_StrokeLine (view, x0, y0, x0, y1 - 1);
1918 BView_SetHighColor (view, color);
1919 BView_FillRectangle (view, x0 + 1, y0, x1 - x0 - 2, y1 - y0);
1920 BView_SetHighColor (view, color_last);
1921 BView_StrokeLine (view, x1 - 1, y0, x1 - 1, y1 - 1);
1922 }
1923 else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
1924 /* A horizontal divider, at least three pixels high: Draw first and
1925 last pixels differently. */
1926 {
1927 BView_SetHighColor (view, color_first);
1928 BView_StrokeLine (f, x0, y0, x1 - 1, y0);
1929 BView_SetHighColor (view, color);
1930 BView_FillRectangle (view, x0, y0 + 1, x1 - x0, y1 - y0 - 2);
1931 BView_SetHighColor (view, color_last);
1932 BView_StrokeLine (view, x0, y1, x1 - 1, y1);
1933 }
1934 else
1935 {
1936 BView_SetHighColor (view, color);
1937 BView_FillRectangleAbs (view, x0, y0, x1, y1);
1938 }
1939 BView_EndClip (view);
1940 BView_draw_unlock (view);
1941}
1942
1943static void
1944haiku_condemn_scroll_bars (struct frame *frame)
1945{
1946 if (!NILP (FRAME_SCROLL_BARS (frame)))
1947 {
1948 if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
1949 {
1950 /* Prepend scrollbars to already condemned ones. */
1951 Lisp_Object last = FRAME_SCROLL_BARS (frame);
1952
1953 while (!NILP (XSCROLL_BAR (last)->next))
1954 last = XSCROLL_BAR (last)->next;
1955
1956 XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
1957 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
1958 }
1959
1960 fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
1961 fset_scroll_bars (frame, Qnil);
1962 }
1963}
1964
1965static void
1966haiku_redeem_scroll_bar (struct window *w)
1967{
1968 struct scroll_bar *bar;
1969 Lisp_Object barobj;
1970 struct frame *f;
1971
1972 if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
1973 {
1974 bar = XSCROLL_BAR (w->vertical_scroll_bar);
1975 /* Unlink it from the condemned list. */
1976 f = XFRAME (WINDOW_FRAME (w));
1977 if (NILP (bar->prev))
1978 {
1979 /* If the prev pointer is nil, it must be the first in one of
1980 the lists. */
1981 if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
1982 /* It's not condemned. Everything's fine. */
1983 goto horizontal;
1984 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
1985 w->vertical_scroll_bar))
1986 fset_condemned_scroll_bars (f, bar->next);
1987 else
1988 /* If its prev pointer is nil, it must be at the front of
1989 one or the other! */
1990 emacs_abort ();
1991 }
1992 else
1993 XSCROLL_BAR (bar->prev)->next = bar->next;
1994
1995 if (! NILP (bar->next))
1996 XSCROLL_BAR (bar->next)->prev = bar->prev;
1997
1998 bar->next = FRAME_SCROLL_BARS (f);
1999 bar->prev = Qnil;
2000 XSETVECTOR (barobj, bar);
2001 fset_scroll_bars (f, barobj);
2002 if (! NILP (bar->next))
2003 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2004 }
2005 horizontal:
2006 if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
2007 {
2008 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
2009 /* Unlink it from the condemned list. */
2010 f = XFRAME (WINDOW_FRAME (w));
2011 if (NILP (bar->prev))
2012 {
2013 /* If the prev pointer is nil, it must be the first in one of
2014 the lists. */
2015 if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
2016 /* It's not condemned. Everything's fine. */
2017 return;
2018 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2019 w->horizontal_scroll_bar))
2020 fset_condemned_scroll_bars (f, bar->next);
2021 else
2022 /* If its prev pointer is nil, it must be at the front of
2023 one or the other! */
2024 emacs_abort ();
2025 }
2026 else
2027 XSCROLL_BAR (bar->prev)->next = bar->next;
2028
2029 if (! NILP (bar->next))
2030 XSCROLL_BAR (bar->next)->prev = bar->prev;
2031
2032 bar->next = FRAME_SCROLL_BARS (f);
2033 bar->prev = Qnil;
2034 XSETVECTOR (barobj, bar);
2035 fset_scroll_bars (f, barobj);
2036 if (! NILP (bar->next))
2037 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2038 }
2039}
2040
2041static void
2042haiku_judge_scroll_bars (struct frame *f)
2043{
2044 Lisp_Object bar, next;
2045
2046 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
2047
2048 /* Clear out the condemned list now so we won't try to process any
2049 more events on the hapless scroll bars. */
2050 fset_condemned_scroll_bars (f, Qnil);
2051
2052 for (; ! NILP (bar); bar = next)
2053 {
2054 struct scroll_bar *b = XSCROLL_BAR (bar);
2055
2056 haiku_scroll_bar_remove (b);
2057
2058 next = b->next;
2059 b->next = b->prev = Qnil;
2060 }
2061
2062 /* Now there should be no references to the condemned scroll bars,
2063 and they should get garbage-collected. */
2064}
2065
2066static struct scroll_bar *
2067haiku_scroll_bar_create (struct window *w, int left, int top,
2068 int width, int height, bool horizontal_p)
2069{
2070 struct frame *f = XFRAME (WINDOW_FRAME (w));
2071 Lisp_Object barobj;
2072
2073 void *sb = NULL;
2074 void *vw = FRAME_HAIKU_VIEW (f);
2075
2076 block_input ();
2077 struct scroll_bar *bar
2078 = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
2079
2080 XSETWINDOW (bar->window, w);
2081 bar->top = top;
2082 bar->left = left;
2083 bar->width = width;
2084 bar->height = height;
2085 bar->position = 0;
2086 bar->total = 0;
2087 bar->dragging = 0;
2088 bar->update = -1;
2089 bar->horizontal = horizontal_p;
2090
2091 sb = BScrollBar_make_for_view (vw, horizontal_p,
2092 left, top, left + width - 1,
2093 top + height - 1, bar);
2094
2095 BView_publish_scroll_bar (vw, left, top, width, height);
2096
2097 bar->next = FRAME_SCROLL_BARS (f);
2098 bar->prev = Qnil;
2099 bar->scroll_bar = sb;
2100 XSETVECTOR (barobj, bar);
2101 fset_scroll_bars (f, barobj);
2102
2103 if (!NILP (bar->next))
2104 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2105
2106 unblock_input ();
2107 return bar;
2108}
2109
2110static void
2111haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
2112{
2113 eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
2114 Lisp_Object barobj;
2115 struct scroll_bar *bar;
2116 int top, height, left, width;
2117 int window_x, window_width;
2118
2119 /* Get window dimensions. */
2120 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
2121 left = window_x;
2122 width = window_width;
2123 top = WINDOW_SCROLL_BAR_AREA_Y (w);
2124 height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
2125
2126 block_input ();
2127
2128 if (NILP (w->horizontal_scroll_bar))
2129 {
2130 bar = haiku_scroll_bar_create (w, left, top, width, height, true);
2131 BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
2132 bar->update = position;
2133 bar->position = position;
2134 bar->total = whole;
2135 }
2136 else
2137 {
2138 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
2139
2140 if (bar->left != left || bar->top != top ||
2141 bar->width != width || bar->height != height)
2142 {
2143 void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
2144 BView_forget_scroll_bar (view, bar->left, bar->top,
2145 bar->width, bar->height);
2146 BView_move_frame (bar->scroll_bar, left, top,
2147 left + width - 1, top + height - 1);
2148 BView_publish_scroll_bar (view, left, top, width, height);
2149 bar->left = left;
2150 bar->top = top;
2151 bar->width = width;
2152 bar->height = height;
2153 }
2154
2155 if (!bar->dragging)
2156 {
2157 BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
2158 BView_invalidate (bar->scroll_bar);
2159 }
2160 }
2161 bar->position = position;
2162 bar->total = whole;
2163 XSETVECTOR (barobj, bar);
2164 wset_horizontal_scroll_bar (w, barobj);
2165 unblock_input ();
2166}
2167
2168static void
2169haiku_set_vertical_scroll_bar (struct window *w,
2170 int portion, int whole, int position)
2171{
2172 eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
2173 Lisp_Object barobj;
2174 struct scroll_bar *bar;
2175 int top, height, left, width;
2176 int window_y, window_height;
2177
2178 /* Get window dimensions. */
2179 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
2180 top = window_y;
2181 height = window_height;
2182
2183 /* Compute the left edge and the width of the scroll bar area. */
2184 left = WINDOW_SCROLL_BAR_AREA_X (w);
2185 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
2186 block_input ();
2187
2188 if (NILP (w->vertical_scroll_bar))
2189 {
2190 bar = haiku_scroll_bar_create (w, left, top, width, height, false);
2191 BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
2192 bar->position = position;
2193 bar->total = whole;
2194 }
2195 else
2196 {
2197 bar = XSCROLL_BAR (w->vertical_scroll_bar);
2198
2199 if (bar->left != left || bar->top != top ||
2200 bar->width != width || bar->height != height)
2201 {
2202 void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
2203 BView_forget_scroll_bar (view, bar->left, bar->top,
2204 bar->width, bar->height);
2205 BView_move_frame (bar->scroll_bar, left, top,
2206 left + width - 1, top + height - 1);
2207 flush_frame (WINDOW_XFRAME (w));
2208 BView_publish_scroll_bar (view, left, top, width, height);
2209 bar->left = left;
2210 bar->top = top;
2211 bar->width = width;
2212 bar->height = height;
2213 }
2214
2215 if (!bar->dragging)
2216 {
2217 BView_scroll_bar_update (bar->scroll_bar, portion, whole, position);
2218 bar->update = position;
2219 BView_invalidate (bar->scroll_bar);
2220 }
2221 }
2222
2223 bar->position = position;
2224 bar->total = whole;
2225
2226 XSETVECTOR (barobj, bar);
2227 wset_vertical_scroll_bar (w, barobj);
2228 unblock_input ();
2229}
2230
2231static void
2232haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2233 struct draw_fringe_bitmap_params *p)
2234{
2235 void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w)));
2236 struct face *face = p->face;
2237
2238 BView_draw_lock (view);
2239 BView_StartClip (view);
2240
2241 haiku_clip_to_row (w, row, ANY_AREA);
2242 if (p->bx >= 0 && !p->overlay_p)
2243 {
2244 BView_SetHighColor (view, face->background);
2245 BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
2246 }
2247
2248 if (p->which && p->which < fringe_bitmap_fillptr)
2249 {
2250 void *bitmap = fringe_bmps[p->which];
2251
2252 uint32_t col;
2253
2254 if (!p->cursor_p)
2255 col = face->foreground;
2256 else if (p->overlay_p)
2257 col = face->background;
2258 else
2259 col = FRAME_CURSOR_COLOR (XFRAME (WINDOW_FRAME (w))).pixel;
2260
2261 if (!p->overlay_p)
2262 {
2263 BView_SetHighColor (view, face->background);
2264 BView_FillRectangle (view, p->x, p->y, p->wd, p->h);
2265 }
2266
2267 BView_SetLowColor (view, col);
2268 BView_DrawBitmapWithEraseOp (view, bitmap, p->x, p->y, p->wd, p->h);
2269 }
2270 BView_EndClip (view);
2271 BView_draw_unlock (view);
2272}
2273
2274static void
2275haiku_define_fringe_bitmap (int which, unsigned short *bits,
2276 int h, int wd)
2277{
2278 if (which >= fringe_bitmap_fillptr)
2279 {
2280 int i = fringe_bitmap_fillptr;
2281 fringe_bitmap_fillptr = which + 20;
2282 fringe_bmps = !i ? xmalloc (fringe_bitmap_fillptr * sizeof (void *)) :
2283 xrealloc (fringe_bmps, fringe_bitmap_fillptr * sizeof (void *));
2284
2285 while (i < fringe_bitmap_fillptr)
2286 fringe_bmps[i++] = NULL;
2287 }
2288
2289 fringe_bmps[which] = BBitmap_new (wd, h, 1);
2290 BBitmap_import_mono_bits (fringe_bmps[which], bits, wd, h);
2291}
2292
2293static void
2294haiku_destroy_fringe_bitmap (int which)
2295{
2296 if (which >= fringe_bitmap_fillptr)
2297 return;
2298
2299 if (fringe_bmps[which])
2300 BBitmap_free (fringe_bmps[which]);
2301 fringe_bmps[which] = NULL;
2302}
2303
2304static void
2305haiku_scroll_run (struct window *w, struct run *run)
2306{
2307 struct frame *f = XFRAME (w->frame);
2308 void *view = FRAME_HAIKU_VIEW (f);
2309 int x, y, width, height, from_y, to_y, bottom_y;
2310 window_box (w, ANY_AREA, &x, &y, &width, &height);
2311
2312 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2313 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2314 bottom_y = y + height;
2315
2316 if (to_y < from_y)
2317 {
2318 /* Scrolling up. Make sure we don't copy part of the mode
2319 line at the bottom. */
2320 if (from_y + run->height > bottom_y)
2321 height = bottom_y - from_y;
2322 else
2323 height = run->height;
2324 }
2325 else
2326 {
2327 /* Scrolling down. Make sure we don't copy over the mode line.
2328 at the bottom. */
2329 if (to_y + run->height > bottom_y)
2330 height = bottom_y - to_y;
2331 else
2332 height = run->height;
2333 }
2334
2335 if (!height)
2336 return;
2337
2338 block_input ();
2339 gui_clear_cursor (w);
2340 BView_draw_lock (view);
2341#ifdef USE_BE_CAIRO
2342 if (EmacsView_double_buffered_p (view))
2343 {
2344#endif
2345 BView_StartClip (view);
2346 BView_CopyBits (view, x, from_y, width, height,
2347 x, to_y, width, height);
2348 BView_EndClip (view);
2349#ifdef USE_BE_CAIRO
2350 }
2351 else
2352 {
2353 EmacsWindow_begin_cr_critical_section (FRAME_HAIKU_WINDOW (f));
2354 cairo_surface_t *surface = FRAME_CR_SURFACE (f);
2355 cairo_surface_t *s
2356 = cairo_surface_create_similar (surface,
2357 cairo_surface_get_content (surface),
2358 width, height);
2359 cairo_t *cr = cairo_create (s);
2360 if (surface)
2361 {
2362 cairo_set_source_surface (cr, surface, -x, -from_y);
2363 cairo_paint (cr);
2364 cairo_destroy (cr);
2365
2366 cr = haiku_begin_cr_clip (f, NULL);
2367 cairo_save (cr);
2368 cairo_set_source_surface (cr, s, x, to_y);
2369 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2370 cairo_rectangle (cr, x, to_y, width, height);
2371 cairo_fill (cr);
2372 cairo_restore (cr);
2373 cairo_surface_destroy (s);
2374 haiku_end_cr_clip (cr);
2375 }
2376 EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
2377 }
2378#endif
2379 BView_draw_unlock (view);
2380
2381 unblock_input ();
2382}
2383
2384static void
2385haiku_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2386 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2387 Time *timestamp)
2388{
2389 block_input ();
2390 if (!fp)
2391 return;
2392 Lisp_Object frame, tail;
2393 struct frame *f1 = NULL;
2394 FOR_EACH_FRAME (tail, frame)
2395 XFRAME (frame)->mouse_moved = false;
2396
2397 if (gui_mouse_grabbed (x_display_list) && !EQ (track_mouse, Qdropping))
2398 f1 = x_display_list->last_mouse_frame;
2399
2400 if (!f1 || FRAME_TOOLTIP_P (f1))
2401 f1 = ((EQ (track_mouse, Qdropping) && gui_mouse_grabbed (x_display_list))
2402 ? x_display_list->last_mouse_frame
2403 : NULL);
2404
2405 if (!f1 && insist > 0)
2406 f1 = SELECTED_FRAME ();
2407
2408 if (!f1 || (!FRAME_HAIKU_P (f1) && (insist > 0)))
2409 FOR_EACH_FRAME (tail, frame)
2410 if (FRAME_HAIKU_P (XFRAME (frame)) &&
2411 !FRAME_TOOLTIP_P (XFRAME (frame)))
2412 f1 = XFRAME (frame);
2413
2414 if (FRAME_TOOLTIP_P (f1))
2415 f1 = NULL;
2416
2417 if (f1 && FRAME_HAIKU_P (f1))
2418 {
2419 int sx, sy;
2420 void *view = FRAME_HAIKU_VIEW (f1);
2421 if (view)
2422 {
2423 BView_get_mouse (view, &sx, &sy);
2424
2425 remember_mouse_glyph (f1, sx, sy, &x_display_list->last_mouse_glyph);
2426 x_display_list->last_mouse_glyph_frame = f1;
2427
2428 *bar_window = Qnil;
2429 *part = scroll_bar_above_handle;
2430 *fp = f1;
2431 XSETINT (*x, sx);
2432 XSETINT (*y, sy);
2433 }
2434 }
2435
2436 unblock_input ();
2437}
2438
2439static void
2440haiku_flush (struct frame *f)
2441{
2442 if (FRAME_VISIBLE_P (f))
2443 BWindow_Flush (FRAME_HAIKU_WINDOW (f));
2444}
2445
2446static void
2447haiku_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
2448{
2449 if (f->tooltip)
2450 return;
2451 block_input ();
2452 if (!f->pointer_invisible && FRAME_HAIKU_VIEW (f)
2453 && !FRAME_OUTPUT_DATA (f)->hourglass_p)
2454 BView_set_view_cursor (FRAME_HAIKU_VIEW (f), cursor);
2455 unblock_input ();
2456 FRAME_OUTPUT_DATA (f)->current_cursor = cursor;
2457}
2458
2459static void
2460haiku_update_window_end (struct window *w, bool cursor_on_p,
2461 bool mouse_face_overwritten_p)
2462{
2463
2464}
2465
2466static void
2467haiku_default_font_parameter (struct frame *f, Lisp_Object parms)
2468{
2469 struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2470 Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
2471 RES_TYPE_STRING);
2472 Lisp_Object font = Qnil;
2473 if (EQ (font_param, Qunbound))
2474 font_param = Qnil;
2475
2476 if (NILP (font_param))
2477 {
2478 /* System font should take precedence over X resources. We suggest this
2479 regardless of font-use-system-font because .emacs may not have been
2480 read yet. */
2481 struct haiku_font_pattern ptn;
2482 ptn.specified = 0;
2483
2484 if (f->tooltip)
2485 BFont_populate_plain_family (&ptn);
2486 else
2487 BFont_populate_fixed_family (&ptn);
2488
2489 if (ptn.specified & FSPEC_FAMILY)
2490 font = font_open_by_name (f, build_unibyte_string (ptn.family));
2491 }
2492
2493 if (NILP (font))
2494 font = !NILP (font_param) ? font_param
2495 : gui_display_get_arg (dpyinfo, parms, Qfont, "font", "Font",
2496 RES_TYPE_STRING);
2497
2498 if (! FONTP (font) && ! STRINGP (font))
2499 {
2500 const char **names = (const char *[]) { "monospace-12",
2501 "Noto Sans Mono-12",
2502 "Source Code Pro-12",
2503 NULL };
2504 int i;
2505
2506 for (i = 0; names[i]; i++)
2507 {
2508 font
2509 = font_open_by_name (f, build_unibyte_string (names[i]));
2510 if (!NILP (font))
2511 break;
2512 }
2513 if (NILP (font))
2514 error ("No suitable font was found");
2515 }
2516 else if (!NILP (font_param))
2517 {
2518 /* Remember the explicit font parameter, so we can re-apply it
2519 after we've applied the `default' face settings. */
2520 AUTO_FRAME_ARG (arg, Qfont_parameter, font_param);
2521 gui_set_frame_parameters (f, arg);
2522 }
2523
2524 gui_default_parameter (f, parms, Qfont, font, "font", "Font",
2525 RES_TYPE_STRING);
2526}
2527
2528static struct redisplay_interface haiku_redisplay_interface =
2529 {
2530 haiku_frame_parm_handlers,
2531 gui_produce_glyphs,
2532 gui_write_glyphs,
2533 gui_insert_glyphs,
2534 gui_clear_end_of_line,
2535 haiku_scroll_run,
2536 haiku_after_update_window_line,
2537 NULL,
2538 haiku_update_window_end,
2539 haiku_flush,
2540 gui_clear_window_mouse_face,
2541 gui_get_glyph_overhangs,
2542 gui_fix_overlapping_area,
2543 haiku_draw_fringe_bitmap,
2544 haiku_define_fringe_bitmap,
2545 haiku_destroy_fringe_bitmap,
2546 haiku_compute_glyph_string_overhangs,
2547 haiku_draw_glyph_string,
2548 haiku_define_frame_cursor,
2549 haiku_clear_frame_area,
2550 haiku_clear_under_internal_border,
2551 haiku_draw_window_cursor,
2552 haiku_draw_vertical_window_border,
2553 haiku_draw_window_divider,
2554 0, /* shift glyphs for insert */
2555 haiku_show_hourglass,
2556 haiku_hide_hourglass,
2557 haiku_default_font_parameter,
2558 };
2559
2560static void
2561haiku_make_fullscreen_consistent (struct frame *f)
2562{
2563 Lisp_Object lval = get_frame_param (f, Qfullscreen);
2564
2565 if (!EQ (lval, Qmaximized) && FRAME_OUTPUT_DATA (f)->zoomed_p)
2566 lval = Qmaximized;
2567 else if (EQ (lval, Qmaximized) && !FRAME_OUTPUT_DATA (f)->zoomed_p)
2568 lval = Qnil;
2569
2570 store_frame_param (f, Qfullscreen, lval);
2571}
2572
2573static int
2574haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
2575{
2576 block_input ();
2577 int message_count = 0;
2578 static void *buf = NULL;
2579 ssize_t b_size;
2580 struct unhandled_event *unhandled_events = NULL;
2581
2582 if (!buf)
2583 buf = xmalloc (200);
2584 haiku_read_size (&b_size);
2585 while (b_size >= 0)
2586 {
2587 enum haiku_event_type type;
2588 struct input_event inev, inev2;
2589
2590 if (b_size > 200)
2591 emacs_abort ();
2592
2593 EVENT_INIT (inev);
2594 EVENT_INIT (inev2);
2595 inev.kind = NO_EVENT;
2596 inev2.kind = NO_EVENT;
2597 inev.arg = Qnil;
2598 inev2.arg = Qnil;
2599
2600 haiku_read (&type, buf, b_size);
2601
2602 switch (type)
2603 {
2604 case QUIT_REQUESTED:
2605 {
2606 struct haiku_quit_requested_event *b = buf;
2607 struct frame *f = haiku_window_to_frame (b->window);
2608
2609 if (!f)
2610 continue;
2611
2612 inev.kind = DELETE_WINDOW_EVENT;
2613 XSETFRAME (inev.frame_or_window, f);
2614 break;
2615 }
2616 case FRAME_RESIZED:
2617 {
2618 struct haiku_resize_event *b = buf;
2619 struct frame *f = haiku_window_to_frame (b->window);
2620
2621 if (!f)
2622 continue;
2623
2624 int width = (int) b->px_widthf;
2625 int height = (int) b->px_heightf;
2626
2627 BView_draw_lock (FRAME_HAIKU_VIEW (f));
2628 BView_resize_to (FRAME_HAIKU_VIEW (f), width, height);
2629 BView_draw_unlock (FRAME_HAIKU_VIEW (f));
2630 if (width != FRAME_PIXEL_WIDTH (f)
2631 || height != FRAME_PIXEL_HEIGHT (f)
2632 || (f->new_size_p
2633 && ((f->new_width >= 0 && width != f->new_width)
2634 || (f->new_height >= 0 && height != f->new_height))))
2635 {
2636 change_frame_size (f, width, height, false, true, false);
2637 SET_FRAME_GARBAGED (f);
2638 cancel_mouse_face (f);
2639 haiku_clear_under_internal_border (f);
2640 }
2641
2642 if (FRAME_OUTPUT_DATA (f)->pending_zoom_width != width ||
2643 FRAME_OUTPUT_DATA (f)->pending_zoom_height != height)
2644 {
2645 FRAME_OUTPUT_DATA (f)->zoomed_p = 0;
2646 haiku_make_fullscreen_consistent (f);
2647 }
2648 else
2649 {
2650 FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
2651 FRAME_OUTPUT_DATA (f)->pending_zoom_width = INT_MIN;
2652 FRAME_OUTPUT_DATA (f)->pending_zoom_height = INT_MIN;
2653 }
2654 break;
2655 }
2656 case FRAME_EXPOSED:
2657 {
2658 struct haiku_expose_event *b = buf;
2659 struct frame *f = haiku_window_to_frame (b->window);
2660
2661 if (!f)
2662 continue;
2663
2664 expose_frame (f, b->x, b->y, b->width, b->height);
2665
2666 haiku_clear_under_internal_border (f);
2667 break;
2668 }
2669 case KEY_DOWN:
2670 {
2671 struct haiku_key_event *b = buf;
2672 struct frame *f = haiku_window_to_frame (b->window);
2673 int non_ascii_p;
2674 if (!f)
2675 continue;
2676
2677 inev.code = b->unraw_mb_char;
2678
2679 BMapKey (b->kc, &non_ascii_p, &inev.code);
2680
2681 if (non_ascii_p)
2682 inev.kind = NON_ASCII_KEYSTROKE_EVENT;
2683 else
2684 inev.kind = inev.code > 127 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT :
2685 ASCII_KEYSTROKE_EVENT;
2686
2687 inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
2688 XSETFRAME (inev.frame_or_window, f);
2689 break;
2690 }
2691 case ACTIVATION:
2692 {
2693 struct haiku_activation_event *b = buf;
2694 struct frame *f = haiku_window_to_frame (b->window);
2695
2696 if (!f)
2697 continue;
2698
2699 if ((x_display_list->focus_event_frame != f && b->activated_p) ||
2700 (x_display_list->focus_event_frame == f && !b->activated_p))
2701 {
2702 haiku_new_focus_frame (b->activated_p ? f : NULL);
2703 if (b->activated_p)
2704 x_display_list->focus_event_frame = f;
2705 else
2706 x_display_list->focus_event_frame = NULL;
2707 inev.kind = b->activated_p ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
2708 XSETFRAME (inev.frame_or_window, f);
2709 }
2710
2711 break;
2712 }
2713 case MOUSE_MOTION:
2714 {
2715 struct haiku_mouse_motion_event *b = buf;
2716 struct frame *f = haiku_window_to_frame (b->window);
2717
2718 if (!f)
2719 continue;
2720
2721 Lisp_Object frame;
2722 XSETFRAME (frame, f);
2723
2724 if (b->just_exited_p)
2725 {
2726 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2727 if (f == hlinfo->mouse_face_mouse_frame)
2728 {
2729 /* If we move outside the frame, then we're
2730 certainly no longer on any text in the frame. */
2731 clear_mouse_face (hlinfo);
2732 hlinfo->mouse_face_mouse_frame = 0;
2733 }
2734
2735 haiku_new_focus_frame (x_display_list->focused_frame);
2736 help_echo_string = Qnil;
2737 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
2738 }
2739 else
2740 {
2741 struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2742 struct haiku_rect r = dpyinfo->last_mouse_glyph;
2743
2744 dpyinfo->last_mouse_motion_x = b->x;
2745 dpyinfo->last_mouse_motion_y = b->y;
2746 dpyinfo->last_mouse_motion_frame = f;
2747
2748 previous_help_echo_string = help_echo_string;
2749 help_echo_string = Qnil;
2750
2751 if (f != dpyinfo->last_mouse_glyph_frame ||
2752 b->x < r.x || b->x >= r.x + r.width - 1 || b->y < r.y ||
2753 b->y >= r.y + r.height - 1)
2754 {
2755 f->mouse_moved = true;
2756 dpyinfo->last_mouse_scroll_bar = NULL;
2757 note_mouse_highlight (f, b->x, b->y);
2758 remember_mouse_glyph (f, b->x, b->y,
2759 &FRAME_DISPLAY_INFO (f)->last_mouse_glyph);
2760 dpyinfo->last_mouse_glyph_frame = f;
2761 gen_help_event (help_echo_string, frame, help_echo_window,
2762 help_echo_object, help_echo_pos);
2763 }
2764
2765 if (MOUSE_HL_INFO (f)->mouse_face_hidden)
2766 {
2767 MOUSE_HL_INFO (f)->mouse_face_hidden = 0;
2768 clear_mouse_face (MOUSE_HL_INFO (f));
2769 }
2770
2771 if (!NILP (Vmouse_autoselect_window))
2772 {
2773 static Lisp_Object last_mouse_window;
2774 Lisp_Object window = window_from_coordinates (f, b->x, b->y, 0, 0, 0);
2775
2776 if (WINDOWP (window)
2777 && !EQ (window, last_mouse_window)
2778 && !EQ (window, selected_window)
2779 && (!NILP (focus_follows_mouse)
2780 || (EQ (XWINDOW (window)->frame,
2781 XWINDOW (selected_window)->frame))))
2782 {
2783 inev.kind = SELECT_WINDOW_EVENT;
2784 inev.frame_or_window = window;
2785 }
2786
2787 last_mouse_window = window;
2788 }
2789 }
2790 break;
2791 }
2792 case BUTTON_UP:
2793 case BUTTON_DOWN:
2794 {
2795 struct haiku_button_event *b = buf;
2796 struct frame *f = haiku_window_to_frame (b->window);
2797 Lisp_Object tab_bar_arg = Qnil;
2798 int tab_bar_p = 0, tool_bar_p = 0;
2799
2800 if (!f)
2801 continue;
2802
2803 struct haiku_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2804
2805 inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
2806
2807 x_display_list->last_mouse_glyph_frame = 0;
2808
2809 /* Is this in the tab-bar? */
2810 if (WINDOWP (f->tab_bar_window)
2811 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
2812 {
2813 Lisp_Object window;
2814 int x = b->x;
2815 int y = b->y;
2816
2817 window = window_from_coordinates (f, x, y, 0, true, true);
2818 tab_bar_p = EQ (window, f->tab_bar_window);
2819
2820 if (tab_bar_p)
2821 tab_bar_arg = handle_tab_bar_click
2822 (f, x, y, type == BUTTON_DOWN, inev.modifiers);
2823 }
2824
2825 if (WINDOWP (f->tool_bar_window)
2826 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
2827 {
2828 Lisp_Object window;
2829 int x = b->x;
2830 int y = b->y;
2831
2832 window = window_from_coordinates (f, x, y, 0, true, true);
2833 tool_bar_p = EQ (window, f->tool_bar_window);
2834
2835 if (tool_bar_p)
2836 handle_tool_bar_click
2837 (f, x, y, type == BUTTON_DOWN, inev.modifiers);
2838 }
2839
2840 if (type == BUTTON_UP)
2841 {
2842 inev.modifiers |= up_modifier;
2843 dpyinfo->grabbed &= ~(1 << b->btn_no);
2844 }
2845 else
2846 {
2847 inev.modifiers |= down_modifier;
2848 dpyinfo->last_mouse_frame = f;
2849 dpyinfo->grabbed |= (1 << b->btn_no);
2850 if (f && !tab_bar_p)
2851 f->last_tab_bar_item = -1;
2852 if (f && !tool_bar_p)
2853 f->last_tool_bar_item = -1;
2854 }
2855
2856 if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
2857 inev.kind = MOUSE_CLICK_EVENT;
2858 inev.arg = tab_bar_arg;
2859 inev.code = b->btn_no;
2860
2861 inev.modifiers |= type == BUTTON_UP ?
2862 up_modifier : down_modifier;
2863
2864 XSETINT (inev.x, b->x);
2865 XSETINT (inev.y, b->y);
2866
2867 XSETFRAME (inev.frame_or_window, f);
2868 break;
2869 }
2870 case ICONIFICATION:
2871 {
2872 struct haiku_iconification_event *b = buf;
2873 struct frame *f = haiku_window_to_frame (b->window);
2874
2875 if (!f)
2876 continue;
2877
2878 if (!b->iconified_p)
2879 {
2880 SET_FRAME_VISIBLE (f, 1);
2881 SET_FRAME_ICONIFIED (f, 0);
2882 inev.kind = DEICONIFY_EVENT;
2883
2884
2885 /* Haiku doesn't expose frames on deiconification, but
2886 if we are double-buffered, the previous screen
2887 contents should have been preserved. */
2888 if (!EmacsView_double_buffered_p (FRAME_HAIKU_VIEW (f)))
2889 {
2890 SET_FRAME_GARBAGED (f);
2891 expose_frame (f, 0, 0, 0, 0);
2892 }
2893 }
2894 else
2895 {
2896 SET_FRAME_VISIBLE (f, 0);
2897 SET_FRAME_ICONIFIED (f, 1);
2898 inev.kind = ICONIFY_EVENT;
2899 }
2900
2901 XSETFRAME (inev.frame_or_window, f);
2902 break;
2903 }
2904 case MOVE_EVENT:
2905 {
2906 struct haiku_move_event *b = buf;
2907 struct frame *f = haiku_window_to_frame (b->window);
2908
2909 if (!f)
2910 continue;
2911
2912 if (FRAME_OUTPUT_DATA (f)->pending_zoom_x != b->x ||
2913 FRAME_OUTPUT_DATA (f)->pending_zoom_y != b->y)
2914 FRAME_OUTPUT_DATA (f)->zoomed_p = 0;
2915 else
2916 {
2917 FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
2918 FRAME_OUTPUT_DATA (f)->pending_zoom_x = INT_MIN;
2919 FRAME_OUTPUT_DATA (f)->pending_zoom_y = INT_MIN;
2920 }
2921
2922 if (FRAME_PARENT_FRAME (f))
2923 haiku_coords_from_parent (f, &b->x, &b->y);
2924
2925 if (b->x != f->left_pos || b->y != f->top_pos)
2926 {
2927 inev.kind = MOVE_FRAME_EVENT;
2928
2929 XSETINT (inev.x, b->x);
2930 XSETINT (inev.y, b->y);
2931
2932 f->left_pos = b->x;
2933 f->top_pos = b->y;
2934
2935 struct frame *p;
2936
2937 if ((p = FRAME_PARENT_FRAME (f)))
2938 {
2939 void *window = FRAME_HAIKU_WINDOW (p);
2940 EmacsWindow_move_weak_child (window, b->window, b->x, b->y);
2941 }
2942
2943 XSETFRAME (inev.frame_or_window, f);
2944 }
2945
2946 haiku_make_fullscreen_consistent (f);
2947 break;
2948 }
2949 case SCROLL_BAR_VALUE_EVENT:
2950 {
2951 struct haiku_scroll_bar_value_event *b = buf;
2952 struct scroll_bar *bar = b->scroll_bar;
2953
2954 struct window *w = XWINDOW (bar->window);
2955
2956 if (bar->update != -1)
2957 {
2958 bar->update = -1;
2959 break;
2960 }
2961
2962 if (bar->position != b->position)
2963 {
2964 inev.kind = bar->horizontal ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT :
2965 SCROLL_BAR_CLICK_EVENT;
2966 inev.part = bar->horizontal ?
2967 scroll_bar_horizontal_handle : scroll_bar_handle;
2968
2969 XSETINT (inev.x, b->position);
2970 XSETINT (inev.y, bar->total);
2971 XSETWINDOW (inev.frame_or_window, w);
2972 }
2973 break;
2974 }
2975 case SCROLL_BAR_DRAG_EVENT:
2976 {
2977 struct haiku_scroll_bar_drag_event *b = buf;
2978 struct scroll_bar *bar = b->scroll_bar;
2979
2980 bar->dragging = b->dragging_p;
2981 if (!b->dragging_p && bar->horizontal)
2982 set_horizontal_scroll_bar (XWINDOW (bar->window));
2983 else if (!b->dragging_p)
2984 set_vertical_scroll_bar (XWINDOW (bar->window));
2985 break;
2986 }
2987 case WHEEL_MOVE_EVENT:
2988 {
2989 struct haiku_wheel_move_event *b = buf;
2990 struct frame *f = haiku_window_to_frame (b->window);
2991 int x, y;
2992 static float px = 0.0f, py = 0.0f;
2993
2994 if (!f)
2995 continue;
2996 BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y);
2997
2998 inev.modifiers = haiku_modifiers_to_emacs (b->modifiers);
2999
3000 inev2.modifiers = inev.modifiers;
3001
3002 if (signbit (px) != signbit (b->delta_x))
3003 px = 0;
3004
3005 if (signbit (py) != signbit (b->delta_y))
3006 py = 0;
3007
3008 px += b->delta_x;
3009 py += b->delta_y;
3010
3011 if (fabsf (py) >= FRAME_LINE_HEIGHT (f))
3012 {
3013 inev.kind = WHEEL_EVENT;
3014 inev.code = 0;
3015
3016 XSETINT (inev.x, x);
3017 XSETINT (inev.y, y);
3018 XSETINT (inev.arg, lrint (fabsf (py) / FRAME_LINE_HEIGHT (f)));
3019 XSETFRAME (inev.frame_or_window, f);
3020
3021 inev.modifiers |= signbit (py) ? up_modifier : down_modifier;
3022 py = 0.0f;
3023 }
3024
3025 if (fabsf (px) >= FRAME_COLUMN_WIDTH (f))
3026 {
3027 inev2.kind = HORIZ_WHEEL_EVENT;
3028 inev2.code = 0;
3029
3030 XSETINT (inev2.x, x);
3031 XSETINT (inev2.y, y);
3032 XSETINT (inev2.arg, lrint (fabsf (px) / FRAME_COLUMN_WIDTH (f)));
3033 XSETFRAME (inev2.frame_or_window, f);
3034
3035 inev2.modifiers |= signbit (px) ? up_modifier : down_modifier;
3036 px = 0.0f;
3037 }
3038
3039 break;
3040 }
3041
3042 case MENU_BAR_RESIZE:
3043 {
3044 struct haiku_menu_bar_resize_event *b = buf;
3045 struct frame *f = haiku_window_to_frame (b->window);
3046
3047 if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
3048 continue;
3049
3050 int old_height = FRAME_MENU_BAR_HEIGHT (f);
3051
3052 FRAME_MENU_BAR_HEIGHT (f) = b->height + 1;
3053 FRAME_MENU_BAR_LINES (f) =
3054 (b->height + FRAME_LINE_HEIGHT (f)) / FRAME_LINE_HEIGHT (f);
3055
3056 if (old_height != b->height)
3057 {
3058 adjust_frame_size (f, -1, -1, 3, true, Qmenu_bar_lines);
3059 haiku_clear_under_internal_border (f);
3060 }
3061 break;
3062 }
3063 case MENU_BAR_OPEN:
3064 case MENU_BAR_CLOSE:
3065 {
3066 struct haiku_menu_bar_state_event *b = buf;
3067 struct frame *f = haiku_window_to_frame (b->window);
3068
3069 if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
3070 continue;
3071
3072 if (type == MENU_BAR_OPEN)
3073 {
3074 if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
3075 {
3076 BView_draw_lock (FRAME_HAIKU_VIEW (f));
3077 /* This shouldn't be here, but nsmenu does it, so
3078 it should probably be safe. */
3079 int was_waiting_for_input_p = waiting_for_input;
3080 if (waiting_for_input)
3081 waiting_for_input = 0;
3082 set_frame_menubar (f, 1);
3083 waiting_for_input = was_waiting_for_input_p;
3084 BView_draw_unlock (FRAME_HAIKU_VIEW (f));
3085 }
3086 FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
3087 popup_activated_p += 1;
3088 }
3089 else
3090 {
3091 if (!popup_activated_p)
3092 emacs_abort ();
3093 if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
3094 {
3095 FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0;
3096 popup_activated_p -= 1;
3097 }
3098 }
3099 break;
3100 }
3101 case MENU_BAR_SELECT_EVENT:
3102 {
3103 struct haiku_menu_bar_select_event *b = buf;
3104 struct frame *f = haiku_window_to_frame (b->window);
3105
3106 if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
3107 continue;
3108
3109 if (FRAME_OUTPUT_DATA (f)->menu_up_to_date_p)
3110 find_and_call_menu_selection (f, f->menu_bar_items_used,
3111 f->menu_bar_vector, b->ptr);
3112 break;
3113 }
3114 case FILE_PANEL_EVENT:
3115 {
3116 if (!popup_activated_p)
3117 continue;
3118
3119 struct unhandled_event *ev = xmalloc (sizeof *ev);
3120 ev->next = unhandled_events;
3121 ev->type = type;
3122 memcpy (&ev->buffer, buf, 200);
3123
3124 unhandled_events = ev;
3125 break;
3126 }
3127 case MENU_BAR_HELP_EVENT:
3128 {
3129 struct haiku_menu_bar_help_event *b = buf;
3130
3131 if (!popup_activated_p)
3132 continue;
3133
3134 struct frame *f = haiku_window_to_frame (b->window);
3135 if (!f || !FRAME_EXTERNAL_MENU_BAR (f) ||
3136 !FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
3137 continue;
3138
3139 run_menu_bar_help_event (f, b->mb_idx);
3140
3141 break;
3142 }
3143 case ZOOM_EVENT:
3144 {
3145 struct haiku_zoom_event *b = buf;
3146
3147 struct frame *f = haiku_window_to_frame (b->window);
3148
3149 if (!f)
3150 continue;
3151
3152 FRAME_OUTPUT_DATA (f)->pending_zoom_height = b->height;
3153 FRAME_OUTPUT_DATA (f)->pending_zoom_width = b->width;
3154 FRAME_OUTPUT_DATA (f)->pending_zoom_x = b->x;
3155 FRAME_OUTPUT_DATA (f)->pending_zoom_y = b->y;
3156
3157 FRAME_OUTPUT_DATA (f)->zoomed_p = 1;
3158 haiku_make_fullscreen_consistent (f);
3159 break;
3160 }
3161 case REFS_EVENT:
3162 {
3163 struct haiku_refs_event *b = buf;
3164 struct frame *f = haiku_window_to_frame (b->window);
3165
3166 if (!f)
3167 continue;
3168
3169 inev.kind = DRAG_N_DROP_EVENT;
3170 inev.arg = build_string_from_utf8 (b->ref);
3171
3172 XSETINT (inev.x, b->x);
3173 XSETINT (inev.y, b->y);
3174 XSETFRAME (inev.frame_or_window, f);
3175
3176 /* There should be no problem with calling free here.
3177 free on Haiku is thread-safe. */
3178 free (b->ref);
3179 break;
3180 }
3181 case APP_QUIT_REQUESTED_EVENT:
3182 case KEY_UP:
3183 default:
3184 break;
3185 }
3186
3187 haiku_read_size (&b_size);
3188
3189 if (inev.kind != NO_EVENT)
3190 {
3191 kbd_buffer_store_event_hold (&inev, hold_quit);
3192 ++message_count;
3193 }
3194
3195 if (inev2.kind != NO_EVENT)
3196 {
3197 kbd_buffer_store_event_hold (&inev2, hold_quit);
3198 ++message_count;
3199 }
3200 }
3201
3202 for (struct unhandled_event *ev = unhandled_events; ev;)
3203 {
3204 haiku_write_without_signal (ev->type, &ev->buffer);
3205 struct unhandled_event *old = ev;
3206 ev = old->next;
3207 xfree (old);
3208 }
3209
3210 unblock_input ();
3211 return message_count;
3212}
3213
3214static void
3215haiku_frame_rehighlight (struct frame *frame)
3216{
3217 haiku_rehighlight ();
3218}
3219
3220static void
3221haiku_delete_window (struct frame *f)
3222{
3223 check_window_system (f);
3224 haiku_free_frame_resources (f);
3225}
3226
3227static void
3228haiku_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
3229{
3230 BBitmap_free (pixmap);
3231}
3232
3233static void
3234haiku_beep (struct frame *f)
3235{
3236 if (visible_bell)
3237 {
3238 void *view = FRAME_HAIKU_VIEW (f);
3239 if (view)
3240 {
3241 block_input ();
3242 BView_draw_lock (view);
3243 if (!EmacsView_double_buffered_p (view))
3244 {
3245 BView_SetHighColorForVisibleBell (view, FRAME_FOREGROUND_PIXEL (f));
3246 BView_FillRectangleForVisibleBell (view, 0, 0, FRAME_PIXEL_WIDTH (f),
3247 FRAME_PIXEL_HEIGHT (f));
3248 SET_FRAME_GARBAGED (f);
3249 expose_frame (f, 0, 0, 0, 0);
3250 }
3251 else
3252 {
3253 EmacsView_do_visible_bell (view, FRAME_FOREGROUND_PIXEL (f));
3254 haiku_flip_buffers (f);
3255 }
3256 BView_draw_unlock (view);
3257 unblock_input ();
3258 }
3259 }
3260 else
3261 haiku_ring_bell ();
3262}
3263
3264static void
3265haiku_toggle_invisible_pointer (struct frame *f, bool invisible_p)
3266{
3267 void *view = FRAME_HAIKU_VIEW (f);
3268
3269 if (view)
3270 {
3271 block_input ();
3272 BView_set_view_cursor (view, invisible_p ?
3273 FRAME_OUTPUT_DATA (f)->no_cursor :
3274 FRAME_OUTPUT_DATA (f)->current_cursor);
3275 f->pointer_invisible = invisible_p;
3276 unblock_input ();
3277 }
3278}
3279
3280static void
3281haiku_fullscreen (struct frame *f)
3282{
3283 if (f->want_fullscreen == FULLSCREEN_MAXIMIZED)
3284 {
3285 EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
3286 BWindow_zoom (FRAME_HAIKU_WINDOW (f));
3287 }
3288 else if (f->want_fullscreen == FULLSCREEN_BOTH)
3289 EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 1);
3290 else if (f->want_fullscreen == FULLSCREEN_NONE)
3291 {
3292 EmacsWindow_make_fullscreen (FRAME_HAIKU_WINDOW (f), 0);
3293 EmacsWindow_unzoom (FRAME_HAIKU_WINDOW (f));
3294 }
3295
3296 f->want_fullscreen = FULLSCREEN_NONE;
3297
3298 haiku_update_size_hints (f);
3299}
3300
3301static struct terminal *
3302haiku_create_terminal (struct haiku_display_info *dpyinfo)
3303{
3304 struct terminal *terminal;
3305
3306 terminal = create_terminal (output_haiku, &haiku_redisplay_interface);
3307
3308 terminal->display_info.haiku = dpyinfo;
3309 dpyinfo->terminal = terminal;
3310 terminal->kboard = allocate_kboard (Qhaiku);
3311
3312 terminal->iconify_frame_hook = haiku_iconify_frame;
3313 terminal->focus_frame_hook = haiku_focus_frame;
3314 terminal->ring_bell_hook = haiku_beep;
3315 terminal->popup_dialog_hook = haiku_popup_dialog;
3316 terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible;
3317 terminal->set_frame_offset_hook = haiku_set_offset;
3318 terminal->delete_terminal_hook = haiku_delete_terminal;
3319 terminal->get_string_resource_hook = get_string_resource;
3320 terminal->set_new_font_hook = haiku_new_font;
3321 terminal->defined_color_hook = haiku_defined_color;
3322 terminal->set_window_size_hook = haiku_set_window_size;
3323 terminal->read_socket_hook = haiku_read_socket;
3324 terminal->implicit_set_name_hook = haiku_implicitly_set_name;
3325 terminal->mouse_position_hook = haiku_mouse_position;
3326 terminal->delete_frame_hook = haiku_delete_window;
3327 terminal->frame_up_to_date_hook = haiku_frame_up_to_date;
3328 terminal->buffer_flipping_unblocked_hook = haiku_buffer_flipping_unblocked_hook;
3329 terminal->clear_frame_hook = haiku_clear_frame;
3330 terminal->change_tab_bar_height_hook = haiku_change_tab_bar_height;
3331 terminal->change_tool_bar_height_hook = haiku_change_tool_bar_height;
3332 terminal->set_vertical_scroll_bar_hook = haiku_set_vertical_scroll_bar;
3333 terminal->set_horizontal_scroll_bar_hook = haiku_set_horizontal_scroll_bar;
3334 terminal->set_scroll_bar_default_height_hook = haiku_set_scroll_bar_default_height;
3335 terminal->set_scroll_bar_default_width_hook = haiku_set_scroll_bar_default_width;
3336 terminal->judge_scroll_bars_hook = haiku_judge_scroll_bars;
3337 terminal->condemn_scroll_bars_hook = haiku_condemn_scroll_bars;
3338 terminal->redeem_scroll_bar_hook = haiku_redeem_scroll_bar;
3339 terminal->update_begin_hook = haiku_update_begin;
3340 terminal->update_end_hook = haiku_update_end;
3341 terminal->frame_rehighlight_hook = haiku_frame_rehighlight;
3342 terminal->query_frame_background_color = haiku_query_frame_background_color;
3343 terminal->free_pixmap = haiku_free_pixmap;
3344 terminal->frame_raise_lower_hook = haiku_frame_raise_lower;
3345 terminal->menu_show_hook = haiku_menu_show;
3346 terminal->toggle_invisible_pointer_hook = haiku_toggle_invisible_pointer;
3347 terminal->fullscreen_hook = haiku_fullscreen;
3348
3349 return terminal;
3350}
3351
3352struct haiku_display_info *
3353haiku_term_init (void)
3354{
3355 struct haiku_display_info *dpyinfo;
3356 struct terminal *terminal;
3357
3358 Lisp_Object color_file, color_map;
3359
3360 block_input ();
3361 Fset_input_interrupt_mode (Qnil);
3362
3363 baud_rate = 19200;
3364
3365 dpyinfo = xzalloc (sizeof *dpyinfo);
3366
3367 haiku_io_init ();
3368
3369 if (port_application_to_emacs < B_OK)
3370 emacs_abort ();
3371
3372 color_file = Fexpand_file_name (build_string ("rgb.txt"),
3373 Fsymbol_value (intern ("data-directory")));
3374
3375 color_map = Fx_load_color_file (color_file);
3376 if (NILP (color_map))
3377 fatal ("Could not read %s.\n", SDATA (color_file));
3378
3379 dpyinfo->color_map = color_map;
3380
3381 dpyinfo->display = BApplication_setup ();
3382
3383 BScreen_res (&dpyinfo->resx, &dpyinfo->resy);
3384
3385 dpyinfo->next = x_display_list;
3386 dpyinfo->n_planes = be_get_display_planes ();
3387 x_display_list = dpyinfo;
3388
3389 terminal = haiku_create_terminal (dpyinfo);
3390 if (current_kboard == initial_kboard)
3391 current_kboard = terminal->kboard;
3392
3393 terminal->kboard->reference_count++;
3394 /* Never delete haiku displays -- there can only ever be one,
3395 anyhow. */
3396 terminal->reference_count++;
3397 terminal->name = xstrdup ("be");
3398
3399 dpyinfo->name_list_element = Fcons (build_string ("be"), Qnil);
3400 dpyinfo->smallest_font_height = 1;
3401 dpyinfo->smallest_char_width = 1;
3402
3403 gui_init_fringe (terminal->rif);
3404 unblock_input ();
3405
3406 return dpyinfo;
3407}
3408
3409void
3410put_xrm_resource (Lisp_Object name, Lisp_Object val)
3411{
3412 eassert (STRINGP (name));
3413 eassert (STRINGP (val) || NILP (val));
3414
3415 Lisp_Object lval = assoc_no_quit (name, rdb);
3416 if (!NILP (lval))
3417 Fsetcdr (lval, val);
3418 else
3419 rdb = Fcons (Fcons (name, val), rdb);
3420}
3421
3422void
3423haiku_clear_under_internal_border (struct frame *f)
3424{
3425 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
3426 {
3427 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
3428 int width = FRAME_PIXEL_WIDTH (f);
3429 int height = FRAME_PIXEL_HEIGHT (f);
3430 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
3431 int face_id =
3432 (FRAME_PARENT_FRAME (f)
3433 ? (!NILP (Vface_remapping_alist)
3434 ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID)
3435 : CHILD_FRAME_BORDER_FACE_ID)
3436 : (!NILP (Vface_remapping_alist)
3437 ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
3438 : INTERNAL_BORDER_FACE_ID));
3439 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
3440 void *view = FRAME_HAIKU_VIEW (f);
3441 block_input ();
3442 BView_draw_lock (view);
3443 BView_StartClip (view);
3444 BView_ClipToRect (view, 0, 0, FRAME_PIXEL_WIDTH (f),
3445 FRAME_PIXEL_HEIGHT (f));
3446
3447 if (face)
3448 BView_SetHighColor (view, face->background);
3449 else
3450 BView_SetHighColor (view, FRAME_BACKGROUND_PIXEL (f));
3451
3452 BView_FillRectangle (view, 0, margin, width, border);
3453 BView_FillRectangle (view, 0, 0, border, height);
3454 BView_FillRectangle (view, 0, margin, width, border);
3455 BView_FillRectangle (view, width - border, 0, border, height);
3456 BView_FillRectangle (view, 0, height - border, width, border);
3457 BView_EndClip (view);
3458 BView_draw_unlock (view);
3459 unblock_input ();
3460 }
3461}
3462
3463void
3464mark_haiku_display (void)
3465{
3466 if (x_display_list)
3467 mark_object (x_display_list->color_map);
3468}
3469
3470void
3471haiku_scroll_bar_remove (struct scroll_bar *bar)
3472{
3473 block_input ();
3474 void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (XWINDOW (bar->window)));
3475 BView_forget_scroll_bar (view, bar->left, bar->top, bar->width, bar->height);
3476 BScrollBar_delete (bar->scroll_bar);
3477 expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)),
3478 bar->left, bar->top, bar->width, bar->height);
3479
3480 if (bar->horizontal)
3481 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
3482 else
3483 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
3484
3485 unblock_input ();
3486};
3487
3488void
3489haiku_set_offset (struct frame *frame, int x, int y,
3490 int change_gravity)
3491{
3492 if (change_gravity > 0)
3493 {
3494 frame->top_pos = y;
3495 frame->left_pos = x;
3496 frame->size_hint_flags &= ~ (XNegative | YNegative);
3497 if (x < 0)
3498 frame->size_hint_flags |= XNegative;
3499 if (y < 0)
3500 frame->size_hint_flags |= YNegative;
3501 frame->win_gravity = NorthWestGravity;
3502 }
3503
3504 haiku_update_size_hints (frame);
3505
3506 block_input ();
3507 if (change_gravity)
3508 BWindow_set_offset (FRAME_HAIKU_WINDOW (frame), x, y);
3509 unblock_input ();
3510}
3511
3512#ifdef USE_BE_CAIRO
3513cairo_t *
3514haiku_begin_cr_clip (struct frame *f, struct glyph_string *s)
3515{
3516 cairo_surface_t *surface = FRAME_CR_SURFACE (f);
3517 if (!surface)
3518 return NULL;
3519
3520 cairo_t *context = cairo_create (surface);
3521 return context;
3522}
3523
3524void
3525haiku_end_cr_clip (cairo_t *cr)
3526{
3527 cairo_destroy (cr);
3528}
3529#endif
3530
3531void
3532syms_of_haikuterm (void)
3533{
3534 DEFVAR_BOOL ("haiku-initialized", haiku_initialized,
3535 doc: /* Non-nil if the Haiku terminal backend has been initialized. */);
3536
3537 DEFVAR_BOOL ("x-use-underline-position-properties",
3538 x_use_underline_position_properties,
3539 doc: /* SKIP: real doc in xterm.c. */);
3540 x_use_underline_position_properties = 1;
3541
3542 DEFVAR_BOOL ("x-underline-at-descent-line",
3543 x_underline_at_descent_line,
3544 doc: /* SKIP: real doc in xterm.c. */);
3545 x_underline_at_descent_line = 0;
3546
3547 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
3548 doc: /* SKIP: real doc in xterm.c. */);
3549 Vx_toolkit_scroll_bars = Qt;
3550
3551 DEFVAR_BOOL ("haiku-debug-on-fatal-error", haiku_debug_on_fatal_error,
3552 doc: /* If non-nil, Emacs will launch the system debugger upon a fatal error. */);
3553 haiku_debug_on_fatal_error = 1;
3554
3555 DEFSYM (Qshift, "shift");
3556 DEFSYM (Qcontrol, "control");
3557 DEFSYM (Qoption, "option");
3558 DEFSYM (Qcommand, "command");
3559
3560 DEFVAR_LISP ("haiku-meta-keysym", Vhaiku_meta_keysym,
3561 doc: /* Which key Emacs uses as the meta modifier.
3562This is either one of the symbols `shift', `control', `command', and
3563`option', or nil, in which case it is treated as `command'.
3564
3565Setting it to any other value is equivalent to `command'. */);
3566 Vhaiku_meta_keysym = Qnil;
3567
3568 DEFVAR_LISP ("haiku-control-keysym", Vhaiku_control_keysym,
3569 doc: /* Which key Emacs uses as the control modifier.
3570This is either one of the symbols `shift', `control', `command', and
3571`option', or nil, in which case it is treated as `control'.
3572
3573Setting it to any other value is equivalent to `control'. */);
3574 Vhaiku_control_keysym = Qnil;
3575
3576 DEFVAR_LISP ("haiku-super-keysym", Vhaiku_super_keysym,
3577 doc: /* Which key Emacs uses as the super modifier.
3578This is either one of the symbols `shift', `control', `command', and
3579`option', or nil, in which case it is treated as `option'.
3580
3581Setting it to any other value is equivalent to `option'. */);
3582 Vhaiku_super_keysym = Qnil;
3583
3584 DEFVAR_LISP ("haiku-shift-keysym", Vhaiku_shift_keysym,
3585 doc: /* Which key Emacs uses as the shift modifier.
3586This is either one of the symbols `shift', `control', `command', and
3587`option', or nil, in which case it is treated as `shift'.
3588
3589Setting it to any other value is equivalent to `shift'. */);
3590 Vhaiku_shift_keysym = Qnil;
3591
3592
3593 DEFSYM (Qx_use_underline_position_properties,
3594 "x-use-underline-position-properties");
3595
3596 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
3597
3598 rdb = Qnil;
3599 staticpro (&rdb);
3600
3601 Fprovide (Qhaiku, Qnil);
3602#ifdef HAVE_BE_FREETYPE
3603 Fprovide (Qfreetype, Qnil);
3604#endif
3605#ifdef USE_BE_CAIRO
3606 Fprovide (intern_c_string ("cairo"), Qnil);
3607#endif
3608}
diff --git a/src/haikuterm.h b/src/haikuterm.h
new file mode 100644
index 00000000000..af55f68c679
--- /dev/null
+++ b/src/haikuterm.h
@@ -0,0 +1,293 @@
1/* Haiku window system support
2 Copyright (C) 2021 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#ifndef _HAIKU_TERM_H_
20#define _HAIKU_TERM_H_
21
22#include <pthread.h>
23
24#ifdef USE_BE_CAIRO
25#include <cairo.h>
26#endif
27
28#include "haikugui.h"
29#include "frame.h"
30#include "character.h"
31#include "dispextern.h"
32#include "font.h"
33
34#define C_FRAME struct frame *
35#define C_FONT struct font *
36#define C_TERMINAL struct terminal *
37
38#define HAVE_CHAR_CACHE_MAX 65535
39
40extern int popup_activated_p;
41
42extern void be_app_quit (void);
43
44struct haikufont_info
45{
46 struct font font;
47 haiku be_font;
48 struct font_metrics **metrics;
49 short metrics_nrows;
50
51 unsigned short **glyphs;
52};
53
54struct haiku_bitmap_record
55{
56 haiku img;
57 char *file;
58 int refcount;
59 int height, width, depth;
60};
61
62struct haiku_display_info
63{
64 /* Chain of all haiku_display_info structures. */
65 struct haiku_display_info *next;
66 C_TERMINAL terminal;
67
68 Lisp_Object name_list_element;
69 Lisp_Object color_map;
70
71 int n_fonts;
72
73 int smallest_char_width;
74 int smallest_font_height;
75
76 struct frame *focused_frame;
77 struct frame *focus_event_frame;
78 struct frame *last_mouse_glyph_frame;
79
80 struct haiku_bitmap_record *bitmaps;
81 ptrdiff_t bitmaps_size;
82 ptrdiff_t bitmaps_last;
83
84 int grabbed;
85 int n_planes;
86 int color_p;
87
88 Window root_window;
89 Lisp_Object rdb;
90
91 Emacs_Cursor vertical_scroll_bar_cursor;
92 Emacs_Cursor horizontal_scroll_bar_cursor;
93
94 Mouse_HLInfo mouse_highlight;
95
96 C_FRAME highlight_frame;
97 C_FRAME last_mouse_frame;
98 C_FRAME last_mouse_motion_frame;
99
100 int last_mouse_motion_x;
101 int last_mouse_motion_y;
102
103 struct haiku_rect last_mouse_glyph;
104
105 void *last_mouse_scroll_bar;
106
107 haiku display;
108
109 double resx, resy;
110};
111
112struct haiku_output
113{
114 Emacs_Cursor text_cursor;
115 Emacs_Cursor nontext_cursor;
116 Emacs_Cursor modeline_cursor;
117 Emacs_Cursor hand_cursor;
118 Emacs_Cursor hourglass_cursor;
119 Emacs_Cursor horizontal_drag_cursor;
120 Emacs_Cursor vertical_drag_cursor;
121 Emacs_Cursor left_edge_cursor;
122 Emacs_Cursor top_left_corner_cursor;
123 Emacs_Cursor top_edge_cursor;
124 Emacs_Cursor top_right_corner_cursor;
125 Emacs_Cursor right_edge_cursor;
126 Emacs_Cursor bottom_right_corner_cursor;
127 Emacs_Cursor bottom_edge_cursor;
128 Emacs_Cursor bottom_left_corner_cursor;
129 Emacs_Cursor no_cursor;
130
131 Emacs_Cursor current_cursor;
132
133 struct haiku_display_info *display_info;
134
135 int baseline_offset;
136 int fontset;
137
138 Emacs_Color cursor_color;
139
140 Window window_desc, parent_desc;
141 char explicit_parent;
142
143 int titlebar_height;
144 int toolbar_height;
145
146 haiku window;
147 haiku view;
148 haiku menubar;
149
150 int menu_up_to_date_p;
151 int zoomed_p;
152
153 int pending_zoom_x;
154 int pending_zoom_y;
155 int pending_zoom_width;
156 int pending_zoom_height;
157
158 int menu_bar_open_p;
159
160 C_FONT font;
161
162 int hourglass_p;
163 uint32_t cursor_fg;
164 bool dirty_p;
165
166 /* The pending position we're waiting for. */
167 int pending_top, pending_left;
168};
169
170struct x_output
171{
172 /* Unused, makes term.c happy. */
173};
174
175extern struct haiku_display_info *x_display_list;
176extern struct font_driver const haikufont_driver;
177
178struct scroll_bar
179{
180 /* These fields are shared by all vectors. */
181 union vectorlike_header header;
182
183 /* The window we're a scroll bar for. */
184 Lisp_Object window;
185
186 /* The next and previous in the chain of scroll bars in this frame. */
187 Lisp_Object next, prev;
188
189 /* Fields after 'prev' are not traced by the GC. */
190
191 /* The position and size of the scroll bar in pixels, relative to the
192 frame. */
193 int top, left, width, height;
194
195 /* The actual scrollbar. */
196 void *scroll_bar;
197
198 /* Non-nil if the scroll bar handle is currently being dragged by
199 the user. */
200 int dragging;
201
202 /* The update position if we are waiting for a scrollbar update, or
203 -1. */
204 int update;
205
206 /* The last known position of this scrollbar. */
207 int position;
208
209 /* The total number of units inside this scrollbar. */
210 int total;
211
212 /* True if the scroll bar is horizontal. */
213 bool horizontal;
214};
215
216#define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
217
218#define FRAME_DIRTY_P(f) (FRAME_OUTPUT_DATA (f)->dirty_p)
219#define MAKE_FRAME_DIRTY(f) (FRAME_DIRTY_P (f) = 1)
220#define FRAME_OUTPUT_DATA(f) ((f)->output_data.haiku)
221#define FRAME_HAIKU_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window)
222#define FRAME_HAIKU_VIEW(f) ((MAKE_FRAME_DIRTY (f)), FRAME_OUTPUT_DATA (f)->view)
223#define FRAME_HAIKU_MENU_BAR(f) (FRAME_OUTPUT_DATA (f)->menubar)
224#define FRAME_DISPLAY_INFO(f) (FRAME_OUTPUT_DATA (f)->display_info)
225#define FRAME_FONT(f) (FRAME_OUTPUT_DATA (f)->font)
226#define FRAME_FONTSET(f) (FRAME_OUTPUT_DATA (f)->fontset)
227#define FRAME_NATIVE_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window)
228#define FRAME_BASELINE_OFFSET(f) (FRAME_OUTPUT_DATA (f)->baseline_offset)
229#define FRAME_CURSOR_COLOR(f) (FRAME_OUTPUT_DATA (f)->cursor_color)
230
231#ifdef USE_BE_CAIRO
232#define FRAME_CR_SURFACE(f) \
233 (FRAME_HAIKU_VIEW (f) ? EmacsView_cairo_surface (FRAME_HAIKU_VIEW (f)) : 0);
234#endif
235
236extern void syms_of_haikuterm (void);
237extern void syms_of_haikufns (void);
238extern void syms_of_haikumenu (void);
239extern void syms_of_haikufont (void);
240extern void syms_of_haikuselect (void);
241extern void init_haiku_select (void);
242
243extern void haiku_iconify_frame (struct frame *);
244extern void haiku_visualize_frame (struct frame *);
245extern void haiku_unvisualize_frame (struct frame *);
246extern void haiku_set_offset (struct frame *, int, int, int);
247extern void haiku_set_frame_visible_invisible (struct frame *, bool);
248extern void haiku_free_frame_resources (struct frame *f);
249extern void haiku_scroll_bar_remove (struct scroll_bar *bar);
250extern void haiku_clear_under_internal_border (struct frame *f);
251extern void haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p);
252
253extern struct haiku_display_info *haiku_term_init (void);
254
255extern void mark_haiku_display (void);
256
257extern int haiku_get_color (const char *name, Emacs_Color *color);
258extern void haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
259extern void haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
260extern void haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
261extern void haiku_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval);
262extern void haiku_change_tab_bar_height (struct frame *f, int height);
263extern void haiku_change_tool_bar_height (struct frame *f, int height);
264
265extern void haiku_query_color (uint32_t col, Emacs_Color *color);
266
267extern unsigned long haiku_get_pixel (haiku bitmap, int x, int y);
268extern void haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel);
269
270extern Lisp_Object haiku_menu_show (struct frame *f, int x, int y, int menu_flags,
271 Lisp_Object title, const char **error_name);
272extern Lisp_Object haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents);
273
274extern void initialize_frame_menubar (struct frame *f);
275
276extern void run_menu_bar_help_event (struct frame *f, int mb_idx);
277extern void put_xrm_resource (Lisp_Object name, Lisp_Object val);
278
279#ifdef HAVE_NATIVE_IMAGE_API
280extern bool haiku_can_use_native_image_api (Lisp_Object type);
281extern int haiku_load_image (struct frame *f, struct image *img,
282 Lisp_Object spec_file, Lisp_Object spec_data);
283extern void syms_of_haikuimage (void);
284#endif
285
286#ifdef USE_BE_CAIRO
287extern cairo_t *
288haiku_begin_cr_clip (struct frame *f, struct glyph_string *s);
289
290extern void
291haiku_end_cr_clip (cairo_t *cr);
292#endif
293#endif /* _HAIKU_TERM_H_ */
diff --git a/src/image.c b/src/image.c
index 6769e491202..734ccdac311 100644
--- a/src/image.c
+++ b/src/image.c
@@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20#include <config.h> 20#include <config.h>
21 21
22#include <fcntl.h> 22#include <fcntl.h>
23#include <math.h>
23#include <unistd.h> 24#include <unistd.h>
24 25
25/* Include this before including <setjmp.h> to work around bugs with 26/* Include this before including <setjmp.h> to work around bugs with
@@ -135,6 +136,27 @@ typedef struct ns_bitmap_record Bitmap_Record;
135# define COLOR_TABLE_SUPPORT 1 136# define COLOR_TABLE_SUPPORT 1
136#endif 137#endif
137 138
139#ifdef HAVE_HAIKU
140#include "haiku_support.h"
141typedef struct haiku_bitmap_record Bitmap_Record;
142
143#define GET_PIXEL(ximg, x, y) haiku_get_pixel (ximg, x, y)
144#define PUT_PIXEL haiku_put_pixel
145#define NO_PIXMAP 0
146
147#define PIX_MASK_RETAIN 0
148#define PIX_MASK_DRAW 1
149
150#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
151#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
152#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
153#define BLUE_FROM_ULONG(color) ((color) & 0xff)
154#define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101)
155#define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101)
156#define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101)
157
158#endif
159
138static void image_disable_image (struct frame *, struct image *); 160static void image_disable_image (struct frame *, struct image *);
139static void image_edge_detection (struct frame *, struct image *, Lisp_Object, 161static void image_edge_detection (struct frame *, struct image *, Lisp_Object,
140 Lisp_Object); 162 Lisp_Object);
@@ -430,6 +452,11 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
430 return -1; 452 return -1;
431#endif 453#endif
432 454
455#ifdef HAVE_HAIKU
456 void *bitmap = BBitmap_new (width, height, 1);
457 BBitmap_import_mono_bits (bitmap, bits, width, height);
458#endif
459
433 id = image_allocate_bitmap_record (f); 460 id = image_allocate_bitmap_record (f);
434 461
435#ifdef HAVE_NS 462#ifdef HAVE_NS
@@ -437,6 +464,11 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
437 dpyinfo->bitmaps[id - 1].depth = 1; 464 dpyinfo->bitmaps[id - 1].depth = 1;
438#endif 465#endif
439 466
467#ifdef HAVE_HAIKU
468 dpyinfo->bitmaps[id - 1].img = bitmap;
469 dpyinfo->bitmaps[id - 1].depth = 1;
470#endif
471
440 dpyinfo->bitmaps[id - 1].file = NULL; 472 dpyinfo->bitmaps[id - 1].file = NULL;
441 dpyinfo->bitmaps[id - 1].height = height; 473 dpyinfo->bitmaps[id - 1].height = height;
442 dpyinfo->bitmaps[id - 1].width = width; 474 dpyinfo->bitmaps[id - 1].width = width;
@@ -465,7 +497,7 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
465ptrdiff_t 497ptrdiff_t
466image_create_bitmap_from_file (struct frame *f, Lisp_Object file) 498image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
467{ 499{
468#ifdef HAVE_NTGUI 500#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
469 return -1; /* W32_TODO : bitmap support */ 501 return -1; /* W32_TODO : bitmap support */
470#else 502#else
471 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); 503 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
@@ -561,6 +593,10 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
561 ns_release_object (bm->img); 593 ns_release_object (bm->img);
562#endif 594#endif
563 595
596#ifdef HAVE_HAIKU
597 BBitmap_free (bm->img);
598#endif
599
564 if (bm->file) 600 if (bm->file)
565 { 601 {
566 xfree (bm->file); 602 xfree (bm->file);
@@ -1834,6 +1870,11 @@ image_size_in_bytes (struct image *img)
1834 if (img->mask) 1870 if (img->mask)
1835 size += w32_image_size (img->mask); 1871 size += w32_image_size (img->mask);
1836 1872
1873#elif defined HAVE_HAIKU
1874 if (img->pixmap)
1875 size += BBitmap_bytes_length (img->pixmap);
1876 if (img->mask)
1877 size += BBitmap_bytes_length (img->mask);
1837#endif 1878#endif
1838 1879
1839 return size; 1880 return size;
@@ -2173,6 +2214,7 @@ compute_image_size (size_t width, size_t height,
2173 single step, but the maths for each element is much more complex 2214 single step, but the maths for each element is much more complex
2174 and performing the steps separately makes for more readable code. */ 2215 and performing the steps separately makes for more readable code. */
2175 2216
2217#ifndef HAVE_HAIKU
2176typedef double matrix3x3[3][3]; 2218typedef double matrix3x3[3][3];
2177 2219
2178static void 2220static void
@@ -2187,6 +2229,7 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result)
2187 result[i][j] = sum; 2229 result[i][j] = sum;
2188 } 2230 }
2189} 2231}
2232#endif /* not HAVE_HAIKU */
2190 2233
2191static void 2234static void
2192compute_image_rotation (struct image *img, double *rotation) 2235compute_image_rotation (struct image *img, double *rotation)
@@ -2244,6 +2287,7 @@ image_set_transform (struct frame *f, struct image *img)
2244 double rotation = 0.0; 2287 double rotation = 0.0;
2245 compute_image_rotation (img, &rotation); 2288 compute_image_rotation (img, &rotation);
2246 2289
2290#ifndef HAVE_HAIKU
2247# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS 2291# if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS
2248 /* We want scale up operations to use a nearest neighbor filter to 2292 /* We want scale up operations to use a nearest neighbor filter to
2249 show real pixels instead of munging them, but scale down 2293 show real pixels instead of munging them, but scale down
@@ -2414,6 +2458,34 @@ image_set_transform (struct frame *f, struct image *img)
2414 img->xform.eDx = matrix[2][0]; 2458 img->xform.eDx = matrix[2][0];
2415 img->xform.eDy = matrix[2][1]; 2459 img->xform.eDy = matrix[2][1];
2416# endif 2460# endif
2461#else
2462 if (rotation != 0 &&
2463 rotation != 90 &&
2464 rotation != 180 &&
2465 rotation != 270 &&
2466 rotation != 360)
2467 {
2468 image_error ("No native support for rotation by %g degrees",
2469 make_float (rotation));
2470 return;
2471 }
2472
2473 rotation = fmod (rotation, 360.0);
2474
2475 if (rotation == 90 || rotation == 270)
2476 {
2477 int w = width;
2478 width = height;
2479 height = w;
2480 }
2481
2482 img->have_be_transforms_p = rotation != 0 || (img->width != width) || (img->height != height);
2483 img->be_rotate = rotation;
2484 img->be_scale_x = 1.0 / (img->width / (double) width);
2485 img->be_scale_y = 1.0 / (img->height / (double) height);
2486 img->width = width;
2487 img->height = height;
2488#endif /* not HAVE_HAIKU */
2417} 2489}
2418 2490
2419#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ 2491#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */
@@ -2820,6 +2892,30 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d
2820 return 1; 2892 return 1;
2821#endif /* HAVE_X_WINDOWS */ 2893#endif /* HAVE_X_WINDOWS */
2822 2894
2895#ifdef HAVE_HAIKU
2896 if (depth == 0)
2897 depth = 24;
2898
2899 if (depth != 24 && depth != 1)
2900 {
2901 *pimg = NULL;
2902 image_error ("Invalid image bit depth specified");
2903 return 0;
2904 }
2905
2906 *pixmap = BBitmap_new (width, height, depth == 1);
2907
2908 if (*pixmap == NO_PIXMAP)
2909 {
2910 *pimg = NULL;
2911 image_error ("Unable to create pixmap", Qnil, Qnil);
2912 return 0;
2913 }
2914
2915 *pimg = *pixmap;
2916 return 1;
2917#endif
2918
2823#ifdef HAVE_NTGUI 2919#ifdef HAVE_NTGUI
2824 2920
2825 BITMAPINFOHEADER *header; 2921 BITMAPINFOHEADER *header;
@@ -2960,7 +3056,7 @@ static void
2960gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg, 3056gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg,
2961 Emacs_Pixmap pixmap, int width, int height) 3057 Emacs_Pixmap pixmap, int width, int height)
2962{ 3058{
2963#ifdef USE_CAIRO 3059#if defined USE_CAIRO || defined HAVE_HAIKU
2964 eassert (pimg == pixmap); 3060 eassert (pimg == pixmap);
2965#elif defined HAVE_X_WINDOWS 3061#elif defined HAVE_X_WINDOWS
2966 GC gc; 3062 GC gc;
@@ -3087,7 +3183,7 @@ image_unget_x_image_or_dc (struct image *img, bool mask_p,
3087static Emacs_Pix_Container 3183static Emacs_Pix_Container
3088image_get_x_image (struct frame *f, struct image *img, bool mask_p) 3184image_get_x_image (struct frame *f, struct image *img, bool mask_p)
3089{ 3185{
3090#ifdef USE_CAIRO 3186#if defined USE_CAIRO || defined (HAVE_HAIKU)
3091 return !mask_p ? img->pixmap : img->mask; 3187 return !mask_p ? img->pixmap : img->mask;
3092#elif defined HAVE_X_WINDOWS 3188#elif defined HAVE_X_WINDOWS
3093 XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img; 3189 XImage *ximg_in_img = !mask_p ? img->ximg : img->mask_img;
@@ -4036,7 +4132,7 @@ xbm_load (struct frame *f, struct image *img)
4036#endif /* not HAVE_NTGUI */ 4132#endif /* not HAVE_NTGUI */
4037#endif /* HAVE_XPM */ 4133#endif /* HAVE_XPM */
4038 4134
4039#if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS 4135#if defined HAVE_XPM || defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU
4040 4136
4041/* Indices of image specification fields in xpm_format, below. */ 4137/* Indices of image specification fields in xpm_format, below. */
4042 4138
@@ -4056,7 +4152,7 @@ enum xpm_keyword_index
4056 XPM_LAST 4152 XPM_LAST
4057}; 4153};
4058 4154
4059#if defined HAVE_XPM || defined HAVE_NS 4155#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU
4060/* Vector of image_keyword structures describing the format 4156/* Vector of image_keyword structures describing the format
4061 of valid XPM image specifications. */ 4157 of valid XPM image specifications. */
4062 4158
@@ -4074,7 +4170,7 @@ static const struct image_keyword xpm_format[XPM_LAST] =
4074 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, 4170 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
4075 {":background", IMAGE_STRING_OR_NIL_VALUE, 0} 4171 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
4076}; 4172};
4077#endif /* HAVE_XPM || HAVE_NS */ 4173#endif /* HAVE_XPM || HAVE_NS || HAVE_HAIKU */
4078 4174
4079#if defined HAVE_X_WINDOWS && !defined USE_CAIRO 4175#if defined HAVE_X_WINDOWS && !defined USE_CAIRO
4080 4176
@@ -4298,7 +4394,7 @@ init_xpm_functions (void)
4298 4394
4299#endif /* WINDOWSNT */ 4395#endif /* WINDOWSNT */
4300 4396
4301#if defined HAVE_XPM || defined HAVE_NS 4397#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU
4302/* Value is true if COLOR_SYMBOLS is a valid color symbols list 4398/* Value is true if COLOR_SYMBOLS is a valid color symbols list
4303 for XPM images. Such a list must consist of conses whose car and 4399 for XPM images. Such a list must consist of conses whose car and
4304 cdr are strings. */ 4400 cdr are strings. */
@@ -4334,9 +4430,9 @@ xpm_image_p (Lisp_Object object)
4334 && (! fmt[XPM_COLOR_SYMBOLS].count 4430 && (! fmt[XPM_COLOR_SYMBOLS].count
4335 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))); 4431 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
4336} 4432}
4337#endif /* HAVE_XPM || HAVE_NS */ 4433#endif /* HAVE_XPM || HAVE_NS || HAVE_HAIKU */
4338 4434
4339#endif /* HAVE_XPM || USE_CAIRO || HAVE_NS */ 4435#endif /* HAVE_XPM || USE_CAIRO || HAVE_NS || HAVE_HAIKU */
4340 4436
4341#if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK 4437#if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK
4342ptrdiff_t 4438ptrdiff_t
@@ -4705,9 +4801,10 @@ xpm_load (struct frame *f, struct image *img)
4705#endif /* HAVE_XPM && !USE_CAIRO */ 4801#endif /* HAVE_XPM && !USE_CAIRO */
4706 4802
4707#if (defined USE_CAIRO && defined HAVE_XPM) \ 4803#if (defined USE_CAIRO && defined HAVE_XPM) \
4708 || (defined HAVE_NS && !defined HAVE_XPM) 4804 || (defined HAVE_NS && !defined HAVE_XPM) \
4805 || (defined HAVE_HAIKU && !defined HAVE_XPM)
4709 4806
4710/* XPM support functions for NS where libxpm is not available, and for 4807/* XPM support functions for NS and Haiku where libxpm is not available, and for
4711 Cairo. Only XPM version 3 (without any extensions) is supported. */ 4808 Cairo. Only XPM version 3 (without any extensions) is supported. */
4712 4809
4713static void xpm_put_color_table_v (Lisp_Object, const char *, 4810static void xpm_put_color_table_v (Lisp_Object, const char *,
@@ -5444,7 +5541,7 @@ lookup_rgb_color (struct frame *f, int r, int g, int b)
5444{ 5541{
5445#ifdef HAVE_NTGUI 5542#ifdef HAVE_NTGUI
5446 return PALETTERGB (r >> 8, g >> 8, b >> 8); 5543 return PALETTERGB (r >> 8, g >> 8, b >> 8);
5447#elif defined USE_CAIRO || defined HAVE_NS 5544#elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU
5448 return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); 5545 return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8);
5449#else 5546#else
5450 xsignal1 (Qfile_error, 5547 xsignal1 (Qfile_error,
@@ -5517,7 +5614,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
5517 p = colors; 5614 p = colors;
5518 for (y = 0; y < img->height; ++y) 5615 for (y = 0; y < img->height; ++y)
5519 { 5616 {
5520#if !defined USE_CAIRO && !defined HAVE_NS 5617#if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU
5521 Emacs_Color *row = p; 5618 Emacs_Color *row = p;
5522 for (x = 0; x < img->width; ++x, ++p) 5619 for (x = 0; x < img->width; ++x, ++p)
5523 p->pixel = GET_PIXEL (ximg, x, y); 5620 p->pixel = GET_PIXEL (ximg, x, y);
@@ -5525,7 +5622,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p)
5525 { 5622 {
5526 FRAME_TERMINAL (f)->query_colors (f, row, img->width); 5623 FRAME_TERMINAL (f)->query_colors (f, row, img->width);
5527 } 5624 }
5528#else /* USE_CAIRO || HAVE_NS */ 5625#else /* USE_CAIRO || HAVE_NS || HAVE_HAIKU */
5529 for (x = 0; x < img->width; ++x, ++p) 5626 for (x = 0; x < img->width; ++x, ++p)
5530 { 5627 {
5531 p->pixel = GET_PIXEL (ximg, x, y); 5628 p->pixel = GET_PIXEL (ximg, x, y);
@@ -5839,6 +5936,7 @@ image_disable_image (struct frame *f, struct image *img)
5839 { 5936 {
5840#ifndef HAVE_NTGUI 5937#ifndef HAVE_NTGUI
5841#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ 5938#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */
5939#ifndef HAVE_HAIKU
5842 5940
5843#ifndef USE_CAIRO 5941#ifndef USE_CAIRO
5844#define CrossForeground(f) BLACK_PIX_DEFAULT (f) 5942#define CrossForeground(f) BLACK_PIX_DEFAULT (f)
@@ -5856,6 +5954,7 @@ image_disable_image (struct frame *f, struct image *img)
5856 if (img->mask) 5954 if (img->mask)
5857 image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height, 5955 image_pixmap_draw_cross (f, img->mask, 0, 0, img->width, img->height,
5858 MaskForeground (f)); 5956 MaskForeground (f));
5957#endif /* !HAVE_HAIKU */
5859#endif /* !HAVE_NS */ 5958#endif /* !HAVE_NS */
5860#else 5959#else
5861 HDC hdc, bmpdc; 5960 HDC hdc, bmpdc;
@@ -6413,6 +6512,8 @@ image_can_use_native_api (Lisp_Object type)
6413 return w32_can_use_native_image_api (type); 6512 return w32_can_use_native_image_api (type);
6414# elif defined HAVE_NS 6513# elif defined HAVE_NS
6415 return ns_can_use_native_image_api (type); 6514 return ns_can_use_native_image_api (type);
6515# elif defined HAVE_HAIKU
6516 return haiku_can_use_native_image_api (type);
6416# else 6517# else
6417 return false; 6518 return false;
6418# endif 6519# endif
@@ -6486,6 +6587,9 @@ native_image_load (struct frame *f, struct image *img)
6486# elif defined HAVE_NS 6587# elif defined HAVE_NS
6487 return ns_load_image (f, img, image_file, 6588 return ns_load_image (f, img, image_file,
6488 image_spec_value (img->spec, QCdata, NULL)); 6589 image_spec_value (img->spec, QCdata, NULL));
6590# elif defined HAVE_HAIKU
6591 return haiku_load_image (f, img, image_file,
6592 image_spec_value (img->spec, QCdata, NULL));
6489# else 6593# else
6490 return 0; 6594 return 0;
6491# endif 6595# endif
@@ -9635,7 +9739,8 @@ imagemagick_load_image (struct frame *f, struct image *img,
9635 9739
9636 init_color_table (); 9740 init_color_table ();
9637 9741
9638#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && ! defined (HAVE_NS) 9742#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && \
9743 ! defined (HAVE_NS) && ! defined (HAVE_HAIKU)
9639 if (imagemagick_render_type != 0) 9744 if (imagemagick_render_type != 0)
9640 { 9745 {
9641 /* Magicexportimage is normally faster than pixelpushing. This 9746 /* Magicexportimage is normally faster than pixelpushing. This
@@ -10925,7 +11030,8 @@ The list of capabilities can include one or more of the following:
10925 if (FRAME_WINDOW_P (f)) 11030 if (FRAME_WINDOW_P (f))
10926 { 11031 {
10927#ifdef HAVE_NATIVE_TRANSFORMS 11032#ifdef HAVE_NATIVE_TRANSFORMS
10928# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) 11033# if defined HAVE_IMAGEMAGICK || defined (USE_CAIRO) || defined (HAVE_NS) \
11034 || defined (HAVE_HAIKU)
10929 return list2 (Qscale, Qrotate90); 11035 return list2 (Qscale, Qrotate90);
10930# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) 11036# elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
10931 int event_basep, error_basep; 11037 int event_basep, error_basep;
@@ -11015,7 +11121,7 @@ static struct image_type const image_types[] =
11015 { SYMBOL_INDEX (Qjpeg), jpeg_image_p, jpeg_load, image_clear_image, 11121 { SYMBOL_INDEX (Qjpeg), jpeg_image_p, jpeg_load, image_clear_image,
11016 IMAGE_TYPE_INIT (init_jpeg_functions) }, 11122 IMAGE_TYPE_INIT (init_jpeg_functions) },
11017#endif 11123#endif
11018#if defined HAVE_XPM || defined HAVE_NS 11124#if defined HAVE_XPM || defined HAVE_NS || defined HAVE_HAIKU
11019 { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image, 11125 { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image,
11020 IMAGE_TYPE_INIT (init_xpm_functions) }, 11126 IMAGE_TYPE_INIT (init_xpm_functions) },
11021#endif 11127#endif
@@ -11163,7 +11269,7 @@ non-numeric, there is no explicit limit on the size of images. */);
11163 DEFSYM (Qxbm, "xbm"); 11269 DEFSYM (Qxbm, "xbm");
11164 add_image_type (Qxbm); 11270 add_image_type (Qxbm);
11165 11271
11166#if defined (HAVE_XPM) || defined (HAVE_NS) 11272#if defined (HAVE_XPM) || defined (HAVE_NS) || defined (HAVE_HAIKU)
11167 DEFSYM (Qxpm, "xpm"); 11273 DEFSYM (Qxpm, "xpm");
11168 add_image_type (Qxpm); 11274 add_image_type (Qxpm);
11169#endif 11275#endif
diff --git a/src/keyboard.c b/src/keyboard.c
index 0c48790ce8d..3722ba14cc5 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3865,7 +3865,7 @@ kbd_buffer_get_event (KBOARD **kbp,
3865 /* One way or another, wait until input is available; then, if 3865 /* One way or another, wait until input is available; then, if
3866 interrupt handlers have not read it, read it now. */ 3866 interrupt handlers have not read it, read it now. */
3867 3867
3868#ifdef USABLE_SIGIO 3868#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
3869 gobble_input (); 3869 gobble_input ();
3870#endif 3870#endif
3871 if (kbd_fetch_ptr != kbd_store_ptr) 3871 if (kbd_fetch_ptr != kbd_store_ptr)
@@ -6156,7 +6156,6 @@ make_lispy_event (struct input_event *event)
6156 case CONFIG_CHANGED_EVENT: 6156 case CONFIG_CHANGED_EVENT:
6157 return list3 (Qconfig_changed_event, 6157 return list3 (Qconfig_changed_event,
6158 event->arg, event->frame_or_window); 6158 event->arg, event->frame_or_window);
6159
6160 /* The 'kind' field of the event is something we don't recognize. */ 6159 /* The 'kind' field of the event is something we don't recognize. */
6161 default: 6160 default:
6162 emacs_abort (); 6161 emacs_abort ();
@@ -7247,7 +7246,7 @@ totally_unblock_input (void)
7247 unblock_input_to (0); 7246 unblock_input_to (0);
7248} 7247}
7249 7248
7250#ifdef USABLE_SIGIO 7249#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
7251 7250
7252void 7251void
7253handle_input_available_signal (int sig) 7252handle_input_available_signal (int sig)
@@ -7263,7 +7262,7 @@ deliver_input_available_signal (int sig)
7263{ 7262{
7264 deliver_process_signal (sig, handle_input_available_signal); 7263 deliver_process_signal (sig, handle_input_available_signal);
7265} 7264}
7266#endif /* USABLE_SIGIO */ 7265#endif /* defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) */
7267 7266
7268 7267
7269/* User signal events. */ 7268/* User signal events. */
@@ -7333,7 +7332,7 @@ handle_user_signal (int sig)
7333 } 7332 }
7334 7333
7335 p->npending++; 7334 p->npending++;
7336#ifdef USABLE_SIGIO 7335#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
7337 if (interrupt_input) 7336 if (interrupt_input)
7338 handle_input_available_signal (sig); 7337 handle_input_available_signal (sig);
7339 else 7338 else
@@ -11103,7 +11102,7 @@ See also `current-input-mode'. */)
11103 (Lisp_Object interrupt) 11102 (Lisp_Object interrupt)
11104{ 11103{
11105 bool new_interrupt_input; 11104 bool new_interrupt_input;
11106#ifdef USABLE_SIGIO 11105#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
11107#ifdef HAVE_X_WINDOWS 11106#ifdef HAVE_X_WINDOWS
11108 if (x_display_list != NULL) 11107 if (x_display_list != NULL)
11109 { 11108 {
@@ -11114,9 +11113,9 @@ See also `current-input-mode'. */)
11114 else 11113 else
11115#endif /* HAVE_X_WINDOWS */ 11114#endif /* HAVE_X_WINDOWS */
11116 new_interrupt_input = !NILP (interrupt); 11115 new_interrupt_input = !NILP (interrupt);
11117#else /* not USABLE_SIGIO */ 11116#else /* not USABLE_SIGIO || USABLE_SIGPOLL */
11118 new_interrupt_input = false; 11117 new_interrupt_input = false;
11119#endif /* not USABLE_SIGIO */ 11118#endif /* not USABLE_SIGIO || USABLE_SIGPOLL */
11120 11119
11121 if (new_interrupt_input != interrupt_input) 11120 if (new_interrupt_input != interrupt_input)
11122 { 11121 {
@@ -11545,12 +11544,16 @@ init_keyboard (void)
11545 sigaction (SIGQUIT, &action, 0); 11544 sigaction (SIGQUIT, &action, 0);
11546#endif /* not DOS_NT */ 11545#endif /* not DOS_NT */
11547 } 11546 }
11548#ifdef USABLE_SIGIO 11547#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
11549 if (!noninteractive) 11548 if (!noninteractive)
11550 { 11549 {
11551 struct sigaction action; 11550 struct sigaction action;
11552 emacs_sigaction_init (&action, deliver_input_available_signal); 11551 emacs_sigaction_init (&action, deliver_input_available_signal);
11552#ifdef USABLE_SIGIO
11553 sigaction (SIGIO, &action, 0); 11553 sigaction (SIGIO, &action, 0);
11554#else
11555 sigaction (SIGPOLL, &action, 0);
11556#endif
11554 } 11557 }
11555#endif 11558#endif
11556 11559
diff --git a/src/lisp.h b/src/lisp.h
index 31656bb3b1c..19caba40014 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -138,7 +138,12 @@ verify (BITS_WORD_MAX >> (BITS_PER_BITS_WORD - 1) == 1);
138 buffers and strings. Emacs never allocates objects larger than 138 buffers and strings. Emacs never allocates objects larger than
139 PTRDIFF_MAX bytes, as they cause problems with pointer subtraction. 139 PTRDIFF_MAX bytes, as they cause problems with pointer subtraction.
140 In C99, pD can always be "t"; configure it here for the sake of 140 In C99, pD can always be "t"; configure it here for the sake of
141 pre-C99 libraries such as glibc 2.0 and Solaris 8. */ 141 pre-C99 libraries such as glibc 2.0 and Solaris 8.
142
143 On Haiku, the size of ptrdiff_t is inconsistent with the value of
144 PTRDIFF_MAX. In that case, "t" should be sufficient. */
145
146#ifndef HAIKU
142#if PTRDIFF_MAX == INT_MAX 147#if PTRDIFF_MAX == INT_MAX
143# define pD "" 148# define pD ""
144#elif PTRDIFF_MAX == LONG_MAX 149#elif PTRDIFF_MAX == LONG_MAX
@@ -148,6 +153,9 @@ verify (BITS_WORD_MAX >> (BITS_PER_BITS_WORD - 1) == 1);
148#else 153#else
149# define pD "t" 154# define pD "t"
150#endif 155#endif
156#else
157# define pD "t"
158#endif
151 159
152/* Convenience macro for rarely-used functions that do not return. */ 160/* Convenience macro for rarely-used functions that do not return. */
153#define AVOID _Noreturn ATTRIBUTE_COLD void 161#define AVOID _Noreturn ATTRIBUTE_COLD void
@@ -3330,7 +3338,7 @@ struct frame;
3330 3338
3331/* Define if the windowing system provides a menu bar. */ 3339/* Define if the windowing system provides a menu bar. */
3332#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \ 3340#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
3333 || defined (HAVE_NS) || defined (USE_GTK) 3341 || defined (HAVE_NS) || defined (USE_GTK) || defined (HAVE_HAIKU)
3334#define HAVE_EXT_MENU_BAR true 3342#define HAVE_EXT_MENU_BAR true
3335#endif 3343#endif
3336 3344
@@ -4429,7 +4437,7 @@ extern Lisp_Object menu_bar_items (Lisp_Object);
4429extern Lisp_Object tab_bar_items (Lisp_Object, int *); 4437extern Lisp_Object tab_bar_items (Lisp_Object, int *);
4430extern Lisp_Object tool_bar_items (Lisp_Object, int *); 4438extern Lisp_Object tool_bar_items (Lisp_Object, int *);
4431extern void discard_mouse_events (void); 4439extern void discard_mouse_events (void);
4432#ifdef USABLE_SIGIO 4440#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
4433void handle_input_available_signal (int); 4441void handle_input_available_signal (int);
4434#endif 4442#endif
4435extern Lisp_Object pending_funcalls; 4443extern Lisp_Object pending_funcalls;
diff --git a/src/menu.c b/src/menu.c
index 1aafa78c3ce..ab01e1bfad2 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -50,7 +50,8 @@ extern AppendMenuW_Proc unicode_append_menu;
50static bool 50static bool
51have_boxes (void) 51have_boxes (void)
52{ 52{
53#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined(HAVE_NS) 53#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined (HAVE_NS) \
54 || defined (HAVE_HAIKU)
54 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))) 55 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)))
55 return 1; 56 return 1;
56#endif 57#endif
@@ -422,7 +423,8 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
422 AREF (item_properties, ITEM_PROPERTY_SELECTED), 423 AREF (item_properties, ITEM_PROPERTY_SELECTED),
423 AREF (item_properties, ITEM_PROPERTY_HELP)); 424 AREF (item_properties, ITEM_PROPERTY_HELP));
424 425
425#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI) 426#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \
427 || defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
426 /* Display a submenu using the toolkit. */ 428 /* Display a submenu using the toolkit. */
427 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)) 429 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))
428 && ! (NILP (map) || NILP (enabled))) 430 && ! (NILP (map) || NILP (enabled)))
@@ -872,6 +874,10 @@ update_submenu_strings (widget_value *first_wv)
872 } 874 }
873} 875}
874 876
877#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
878#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \
879 || defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
880
875/* Find the menu selection and store it in the keyboard buffer. 881/* Find the menu selection and store it in the keyboard buffer.
876 F is the frame the menu is on. 882 F is the frame the menu is on.
877 MENU_BAR_ITEMS_USED is the length of VECTOR. 883 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,
959 SAFE_FREE (); 965 SAFE_FREE ();
960} 966}
961 967
962#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */ 968#endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI || HAVE_HAIKU */
963 969
964#ifdef HAVE_NS 970#ifdef HAVE_NS
965/* As above, but return the menu selection instead of storing in kb buffer. 971/* As above, but return the menu selection instead of storing in kb buffer.
diff --git a/src/process.c b/src/process.c
index a00426795b8..241ffe9a8dd 100644
--- a/src/process.c
+++ b/src/process.c
@@ -259,7 +259,7 @@ static bool process_output_skip;
259 259
260static void start_process_unwind (Lisp_Object); 260static void start_process_unwind (Lisp_Object);
261static void create_process (Lisp_Object, char **, Lisp_Object); 261static void create_process (Lisp_Object, char **, Lisp_Object);
262#ifdef USABLE_SIGIO 262#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
263static bool keyboard_bit_set (fd_set *); 263static bool keyboard_bit_set (fd_set *);
264#endif 264#endif
265static void deactivate_process (Lisp_Object); 265static void deactivate_process (Lisp_Object);
@@ -5730,7 +5730,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5730 if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell))) 5730 if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
5731 break; 5731 break;
5732 5732
5733#ifdef USABLE_SIGIO 5733#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
5734 /* If we think we have keyboard input waiting, but didn't get SIGIO, 5734 /* If we think we have keyboard input waiting, but didn't get SIGIO,
5735 go read it. This can happen with X on BSD after logging out. 5735 go read it. This can happen with X on BSD after logging out.
5736 In that case, there really is no input and no SIGIO, 5736 In that case, there really is no input and no SIGIO,
@@ -5738,7 +5738,11 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5738 5738
5739 if (read_kbd && interrupt_input 5739 if (read_kbd && interrupt_input
5740 && keyboard_bit_set (&Available) && ! noninteractive) 5740 && keyboard_bit_set (&Available) && ! noninteractive)
5741#ifdef USABLE_SIGIO
5741 handle_input_available_signal (SIGIO); 5742 handle_input_available_signal (SIGIO);
5743#else
5744 handle_input_available_signal (SIGPOLL);
5745#endif
5742#endif 5746#endif
5743 5747
5744 /* If checking input just got us a size-change event from X, 5748 /* If checking input just got us a size-change event from X,
@@ -7732,7 +7736,7 @@ delete_gpm_wait_descriptor (int desc)
7732 7736
7733# endif 7737# endif
7734 7738
7735# ifdef USABLE_SIGIO 7739#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
7736 7740
7737/* Return true if *MASK has a bit set 7741/* Return true if *MASK has a bit set
7738 that corresponds to one of the keyboard input descriptors. */ 7742 that corresponds to one of the keyboard input descriptors. */
diff --git a/src/sound.c b/src/sound.c
index 9041076bdc0..d42bc8550d3 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -299,11 +299,15 @@ sound_perror (const char *msg)
299 int saved_errno = errno; 299 int saved_errno = errno;
300 300
301 turn_on_atimers (1); 301 turn_on_atimers (1);
302#ifdef USABLE_SIGIO 302#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
303 { 303 {
304 sigset_t unblocked; 304 sigset_t unblocked;
305 sigemptyset (&unblocked); 305 sigemptyset (&unblocked);
306#ifdef USABLE_SIGIO
306 sigaddset (&unblocked, SIGIO); 307 sigaddset (&unblocked, SIGIO);
308#else
309 sigaddset (&unblocked, SIGPOLL);
310#endif
307 pthread_sigmask (SIG_UNBLOCK, &unblocked, 0); 311 pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
308 } 312 }
309#endif 313#endif
@@ -698,7 +702,7 @@ static void
698vox_configure (struct sound_device *sd) 702vox_configure (struct sound_device *sd)
699{ 703{
700 int val; 704 int val;
701#ifdef USABLE_SIGIO 705#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
702 sigset_t oldset, blocked; 706 sigset_t oldset, blocked;
703#endif 707#endif
704 708
@@ -708,9 +712,13 @@ vox_configure (struct sound_device *sd)
708 interrupted by a signal. Block the ones we know to cause 712 interrupted by a signal. Block the ones we know to cause
709 troubles. */ 713 troubles. */
710 turn_on_atimers (0); 714 turn_on_atimers (0);
711#ifdef USABLE_SIGIO 715#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
712 sigemptyset (&blocked); 716 sigemptyset (&blocked);
717#ifdef USABLE_SIGIO
713 sigaddset (&blocked, SIGIO); 718 sigaddset (&blocked, SIGIO);
719#else
720 sigaddset (&blocked, SIGPOLL);
721#endif
714 pthread_sigmask (SIG_BLOCK, &blocked, &oldset); 722 pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
715#endif 723#endif
716 724
@@ -744,7 +752,7 @@ vox_configure (struct sound_device *sd)
744 } 752 }
745 753
746 turn_on_atimers (1); 754 turn_on_atimers (1);
747#ifdef USABLE_SIGIO 755#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
748 pthread_sigmask (SIG_SETMASK, &oldset, 0); 756 pthread_sigmask (SIG_SETMASK, &oldset, 0);
749#endif 757#endif
750} 758}
@@ -760,10 +768,14 @@ vox_close (struct sound_device *sd)
760 /* On GNU/Linux, it seems that the device driver doesn't like to 768 /* On GNU/Linux, it seems that the device driver doesn't like to
761 be interrupted by a signal. Block the ones we know to cause 769 be interrupted by a signal. Block the ones we know to cause
762 troubles. */ 770 troubles. */
763#ifdef USABLE_SIGIO 771#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
764 sigset_t blocked, oldset; 772 sigset_t blocked, oldset;
765 sigemptyset (&blocked); 773 sigemptyset (&blocked);
774#ifdef USABLE_SIGIO
766 sigaddset (&blocked, SIGIO); 775 sigaddset (&blocked, SIGIO);
776#else
777 sigaddset (&blocked, SIGPOLL);
778#endif
767 pthread_sigmask (SIG_BLOCK, &blocked, &oldset); 779 pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
768#endif 780#endif
769 turn_on_atimers (0); 781 turn_on_atimers (0);
@@ -772,7 +784,7 @@ vox_close (struct sound_device *sd)
772 ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL); 784 ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL);
773 785
774 turn_on_atimers (1); 786 turn_on_atimers (1);
775#ifdef USABLE_SIGIO 787#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
776 pthread_sigmask (SIG_SETMASK, &oldset, 0); 788 pthread_sigmask (SIG_SETMASK, &oldset, 0);
777#endif 789#endif
778 790
diff --git a/src/sysdep.c b/src/sysdep.c
index 8eaee224987..5e13dd097ec 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -678,6 +678,9 @@ sys_subshell (void)
678#ifdef USABLE_SIGIO 678#ifdef USABLE_SIGIO
679 saved_handlers[3].code = SIGIO; 679 saved_handlers[3].code = SIGIO;
680 saved_handlers[4].code = 0; 680 saved_handlers[4].code = 0;
681#elif defined (USABLE_SIGPOLL)
682 saved_handlers[3].code = SIGPOLL;
683 saved_handlers[4].code = 0;
681#else 684#else
682 saved_handlers[3].code = 0; 685 saved_handlers[3].code = 0;
683#endif 686#endif
@@ -788,6 +791,7 @@ init_sigio (int fd)
788} 791}
789 792
790#ifndef DOS_NT 793#ifndef DOS_NT
794#ifdef F_SETOWN
791static void 795static void
792reset_sigio (int fd) 796reset_sigio (int fd)
793{ 797{
@@ -795,12 +799,13 @@ reset_sigio (int fd)
795 fcntl (fd, F_SETFL, old_fcntl_flags[fd]); 799 fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
796#endif 800#endif
797} 801}
802#endif /* F_SETOWN */
798#endif 803#endif
799 804
800void 805void
801request_sigio (void) 806request_sigio (void)
802{ 807{
803#ifdef USABLE_SIGIO 808#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
804 sigset_t unblocked; 809 sigset_t unblocked;
805 810
806 if (noninteractive) 811 if (noninteractive)
@@ -810,7 +815,11 @@ request_sigio (void)
810# ifdef SIGWINCH 815# ifdef SIGWINCH
811 sigaddset (&unblocked, SIGWINCH); 816 sigaddset (&unblocked, SIGWINCH);
812# endif 817# endif
818# ifdef USABLE_SIGIO
813 sigaddset (&unblocked, SIGIO); 819 sigaddset (&unblocked, SIGIO);
820# else
821 sigaddset (&unblocked, SIGPOLL);
822# endif
814 pthread_sigmask (SIG_UNBLOCK, &unblocked, 0); 823 pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
815 824
816 interrupts_deferred = 0; 825 interrupts_deferred = 0;
@@ -820,7 +829,7 @@ request_sigio (void)
820void 829void
821unrequest_sigio (void) 830unrequest_sigio (void)
822{ 831{
823#ifdef USABLE_SIGIO 832#if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL)
824 sigset_t blocked; 833 sigset_t blocked;
825 834
826 if (noninteractive) 835 if (noninteractive)
@@ -830,7 +839,11 @@ unrequest_sigio (void)
830# ifdef SIGWINCH 839# ifdef SIGWINCH
831 sigaddset (&blocked, SIGWINCH); 840 sigaddset (&blocked, SIGWINCH);
832# endif 841# endif
842# ifdef USABLE_SIGIO
833 sigaddset (&blocked, SIGIO); 843 sigaddset (&blocked, SIGIO);
844# else
845 sigaddset (&blocked, SIGPOLL);
846# endif
834 pthread_sigmask (SIG_BLOCK, &blocked, 0); 847 pthread_sigmask (SIG_BLOCK, &blocked, 0);
835 interrupts_deferred = 1; 848 interrupts_deferred = 1;
836#endif 849#endif
@@ -1256,9 +1269,12 @@ init_sys_modes (struct tty_display_info *tty_out)
1256 /* This code added to insure that, if flow-control is not to be used, 1269 /* This code added to insure that, if flow-control is not to be used,
1257 we have an unlocked terminal at the start. */ 1270 we have an unlocked terminal at the start. */
1258 1271
1272#ifndef HAIKU /* On Haiku, TCXONC is a no-op and causes spurious
1273 compiler warnings. */
1259#ifdef TCXONC 1274#ifdef TCXONC
1260 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TCXONC, 1); 1275 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TCXONC, 1);
1261#endif 1276#endif
1277#endif /* HAIKU */
1262#ifdef TIOCSTART 1278#ifdef TIOCSTART
1263 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TIOCSTART, 0); 1279 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TIOCSTART, 0);
1264#endif 1280#endif
@@ -1674,6 +1690,8 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
1674 sigaddset (&action->sa_mask, SIGQUIT); 1690 sigaddset (&action->sa_mask, SIGQUIT);
1675#ifdef USABLE_SIGIO 1691#ifdef USABLE_SIGIO
1676 sigaddset (&action->sa_mask, SIGIO); 1692 sigaddset (&action->sa_mask, SIGIO);
1693#elif defined (USABLE_SIGPOLL)
1694 sigaddset (&action->sa_mask, SIGPOLL);
1677#endif 1695#endif
1678 } 1696 }
1679 1697
@@ -2772,6 +2790,7 @@ static const struct speed_struct speeds[] =
2772#ifdef B150 2790#ifdef B150
2773 { 150, B150 }, 2791 { 150, B150 },
2774#endif 2792#endif
2793#ifndef HAVE_TINY_SPEED_T
2775#ifdef B200 2794#ifdef B200
2776 { 200, B200 }, 2795 { 200, B200 },
2777#endif 2796#endif
@@ -2859,6 +2878,7 @@ static const struct speed_struct speeds[] =
2859#ifdef B4000000 2878#ifdef B4000000
2860 { 4000000, B4000000 }, 2879 { 4000000, B4000000 },
2861#endif 2880#endif
2881#endif /* HAVE_TINY_SPEED_T */
2862 }; 2882 };
2863 2883
2864/* Convert a numerical speed (e.g., 9600) to a Bnnn constant (e.g., 2884/* Convert a numerical speed (e.g., 9600) to a Bnnn constant (e.g.,
@@ -3120,8 +3140,9 @@ list_system_processes (void)
3120} 3140}
3121 3141
3122/* The WINDOWSNT implementation is in w32.c. 3142/* The WINDOWSNT implementation is in w32.c.
3123 The MSDOS implementation is in dosfns.c. */ 3143 The MSDOS implementation is in dosfns.c.
3124#elif !defined (WINDOWSNT) && !defined (MSDOS) 3144 The Haiku implementation is in haiku.c. */
3145#elif !defined (WINDOWSNT) && !defined (MSDOS) && !defined (HAIKU)
3125 3146
3126Lisp_Object 3147Lisp_Object
3127list_system_processes (void) 3148list_system_processes (void)
@@ -4200,8 +4221,9 @@ system_process_attributes (Lisp_Object pid)
4200} 4221}
4201 4222
4202/* The WINDOWSNT implementation is in w32.c. 4223/* The WINDOWSNT implementation is in w32.c.
4203 The MSDOS implementation is in dosfns.c. */ 4224 The MSDOS implementation is in dosfns.c.
4204#elif !defined (WINDOWSNT) && !defined (MSDOS) 4225 The HAIKU implementation is in haiku.c. */
4226#elif !defined (WINDOWSNT) && !defined (MSDOS) && !defined (HAIKU)
4205 4227
4206Lisp_Object 4228Lisp_Object
4207system_process_attributes (Lisp_Object pid) 4229system_process_attributes (Lisp_Object pid)
diff --git a/src/termhooks.h b/src/termhooks.h
index b274be9e3cd..1cf9863f3a1 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -60,7 +60,8 @@ enum output_method
60 output_x_window, 60 output_x_window,
61 output_msdos_raw, 61 output_msdos_raw,
62 output_w32, 62 output_w32,
63 output_ns 63 output_ns,
64 output_haiku
64}; 65};
65 66
66/* Input queue declarations and hooks. */ 67/* Input queue declarations and hooks. */
@@ -266,7 +267,6 @@ enum event_kind
266 /* File or directory was changed. */ 267 /* File or directory was changed. */
267 , FILE_NOTIFY_EVENT 268 , FILE_NOTIFY_EVENT
268#endif 269#endif
269
270}; 270};
271 271
272/* Bit width of an enum event_kind tag at the start of structs and unions. */ 272/* Bit width of an enum event_kind tag at the start of structs and unions. */
@@ -447,6 +447,7 @@ struct terminal
447 struct x_display_info *x; /* xterm.h */ 447 struct x_display_info *x; /* xterm.h */
448 struct w32_display_info *w32; /* w32term.h */ 448 struct w32_display_info *w32; /* w32term.h */
449 struct ns_display_info *ns; /* nsterm.h */ 449 struct ns_display_info *ns; /* nsterm.h */
450 struct haiku_display_info *haiku; /* haikuterm.h */
450 } display_info; 451 } display_info;
451 452
452 453
@@ -835,6 +836,9 @@ extern struct terminal *terminal_list;
835#elif defined (HAVE_NS) 836#elif defined (HAVE_NS)
836#define TERMINAL_FONT_CACHE(t) \ 837#define TERMINAL_FONT_CACHE(t) \
837 (t->type == output_ns ? t->display_info.ns->name_list_element : Qnil) 838 (t->type == output_ns ? t->display_info.ns->name_list_element : Qnil)
839#elif defined (HAVE_HAIKU)
840#define TERMINAL_FONT_CACHE(t) \
841 (t->type == output_haiku ? t->display_info.haiku->name_list_element : Qnil)
838#endif 842#endif
839 843
840extern struct terminal *decode_live_terminal (Lisp_Object); 844extern struct terminal *decode_live_terminal (Lisp_Object);
diff --git a/src/terminal.c b/src/terminal.c
index b83adc596bb..b5f244ee318 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -445,6 +445,8 @@ possible return values. */)
445 return Qpc; 445 return Qpc;
446 case output_ns: 446 case output_ns:
447 return Qns; 447 return Qns;
448 case output_haiku:
449 return Qhaiku;
448 default: 450 default:
449 emacs_abort (); 451 emacs_abort ();
450 } 452 }
diff --git a/src/verbose.mk.in b/src/verbose.mk.in
index a5ff931ed09..9252971acc3 100644
--- a/src/verbose.mk.in
+++ b/src/verbose.mk.in
@@ -23,7 +23,9 @@ ifeq (${V},1)
23AM_V_AR = 23AM_V_AR =
24AM_V_at = 24AM_V_at =
25AM_V_CC = 25AM_V_CC =
26AM_V_CXX =
26AM_V_CCLD = 27AM_V_CCLD =
28AM_V_CXXLD =
27AM_V_ELC = 29AM_V_ELC =
28AM_V_ELN = 30AM_V_ELN =
29AM_V_GEN = 31AM_V_GEN =
@@ -34,7 +36,9 @@ else
34AM_V_AR = @echo " AR " $@; 36AM_V_AR = @echo " AR " $@;
35AM_V_at = @ 37AM_V_at = @
36AM_V_CC = @echo " CC " $@; 38AM_V_CC = @echo " CC " $@;
39AM_V_CXX = @echo " CXX " $@;
37AM_V_CCLD = @echo " CCLD " $@; 40AM_V_CCLD = @echo " CCLD " $@;
41AM_V_CXXLD = @echo " CXXLD " $@;
38ifeq ($(HAVE_NATIVE_COMP),yes) 42ifeq ($(HAVE_NATIVE_COMP),yes)
39ifeq ($(NATIVE_DISABLED),1) 43ifeq ($(NATIVE_DISABLED),1)
40AM_V_ELC = @echo " ELC " $@; 44AM_V_ELC = @echo " ELC " $@;
diff --git a/src/xdisp.c b/src/xdisp.c
index 6c70ce60bb5..8d34b7c4c30 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -15657,6 +15657,11 @@ redisplay_internal (void)
15657 } 15657 }
15658#endif 15658#endif
15659 15659
15660#if defined (HAVE_HAIKU)
15661 if (popup_activated_p)
15662 return;
15663#endif
15664
15660 /* I don't think this happens but let's be paranoid. */ 15665 /* I don't think this happens but let's be paranoid. */
15661 if (redisplaying_p) 15666 if (redisplaying_p)
15662 return; 15667 return;
@@ -25247,6 +25252,11 @@ display_menu_bar (struct window *w)
25247 return; 25252 return;
25248#endif /* HAVE_NS */ 25253#endif /* HAVE_NS */
25249 25254
25255#ifdef HAVE_HAIKU
25256 if (FRAME_HAIKU_P (f))
25257 return;
25258#endif /* HAVE_HAIKU */
25259
25250#if defined (USE_X_TOOLKIT) || defined (USE_GTK) 25260#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
25251 eassert (!FRAME_WINDOW_P (f)); 25261 eassert (!FRAME_WINDOW_P (f));
25252 init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID); 25262 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)
33698 return; 33708 return;
33699#endif 33709#endif
33700 33710
33711#if defined (HAVE_HAIKU)
33712 if (popup_activated_p)
33713 return;
33714#endif
33715
33701 if (!f->glyphs_initialized_p 33716 if (!f->glyphs_initialized_p
33702 || f->pointer_invisible) 33717 || f->pointer_invisible)
33703 return; 33718 return;
diff --git a/src/xfaces.c b/src/xfaces.c
index d0d73eb8286..fec6b2654b1 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -246,6 +246,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
246#ifdef HAVE_NS 246#ifdef HAVE_NS
247#define GCGraphicsExposures 0 247#define GCGraphicsExposures 0
248#endif /* HAVE_NS */ 248#endif /* HAVE_NS */
249
250#ifdef HAVE_HAIKU
251#define GCGraphicsExposures 0
252#endif /* HAVE_HAIKU */
249#endif /* HAVE_WINDOW_SYSTEM */ 253#endif /* HAVE_WINDOW_SYSTEM */
250 254
251#include "buffer.h" 255#include "buffer.h"
@@ -555,8 +559,8 @@ x_free_gc (struct frame *f, Emacs_GC *gc)
555 559
556#endif /* HAVE_NTGUI */ 560#endif /* HAVE_NTGUI */
557 561
558#ifdef HAVE_NS 562#if defined (HAVE_NS) || defined (HAVE_HAIKU)
559/* NS emulation of GCs */ 563/* NS and Haiku emulation of GCs */
560 564
561static Emacs_GC * 565static Emacs_GC *
562x_create_gc (struct frame *f, 566x_create_gc (struct frame *f,
diff --git a/src/xfns.c b/src/xfns.c
index 0ea43d13306..a142f5518cc 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4461,7 +4461,8 @@ For GNU and Unix system, the first 2 numbers are the version of the X
4461Protocol used on TERMINAL and the 3rd number is the distributor-specific 4461Protocol used on TERMINAL and the 3rd number is the distributor-specific
4462release number. For MS Windows, the 3 numbers report the OS major and 4462release number. For MS Windows, the 3 numbers report the OS major and
4463minor version and build number. For Nextstep, the first 2 numbers are 4463minor version and build number. For Nextstep, the first 2 numbers are
4464hard-coded and the 3rd represents the OS version. 4464hard-coded and the 3rd represents the OS version. For Haiku, all 3
4465numbers are hard-coded.
4465 4466
4466See also the function `x-server-vendor'. 4467See also the function `x-server-vendor'.
4467 4468
@@ -7419,7 +7420,7 @@ Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file
7419selection box, if specified. If MUSTMATCH is non-nil, the returned file 7420selection box, if specified. If MUSTMATCH is non-nil, the returned file
7420or directory must exist. 7421or directory must exist.
7421 7422
7422This function is defined only on NS, MS Windows, and X Windows with the 7423This function is defined only on NS, Haiku, MS Windows, and X Windows with the
7423Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored. 7424Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored.
7424Otherwise, if ONLY-DIR-P is non-nil, the user can select only directories. 7425Otherwise, if ONLY-DIR-P is non-nil, the user can select only directories.
7425On MS Windows 7 and later, the file selection dialog "remembers" the last 7426On MS Windows 7 and later, the file selection dialog "remembers" the last
diff --git a/src/xterm.c b/src/xterm.c
index 18f8a6062f8..9e5aed996ae 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -14959,7 +14959,7 @@ selected window or cursor position is preserved. */);
14959A value of nil means Emacs doesn't use toolkit scroll bars. 14959A value of nil means Emacs doesn't use toolkit scroll bars.
14960With the X Window system, the value is a symbol describing the 14960With the X Window system, the value is a symbol describing the
14961X toolkit. Possible values are: gtk, motif, xaw, or xaw3d. 14961X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
14962With MS Windows or Nextstep, the value is t. */); 14962With MS Windows, Haiku windowing or Nextstep, the value is t. */);
14963#ifdef USE_TOOLKIT_SCROLL_BARS 14963#ifdef USE_TOOLKIT_SCROLL_BARS
14964#ifdef USE_MOTIF 14964#ifdef USE_MOTIF
14965 Vx_toolkit_scroll_bars = intern_c_string ("motif"); 14965 Vx_toolkit_scroll_bars = intern_c_string ("motif");