diff options
| author | Po Lu | 2021-11-20 21:30:08 +0800 |
|---|---|---|
| committer | Po Lu | 2021-11-20 21:46:07 +0800 |
| commit | 85a078e7853d708e599f97a3de06aed3a1c090ea (patch) | |
| tree | 082931cb8ad6b276d8eaafeda685c368e0510f05 /src | |
| parent | bfcc59371ba74e53c5ce1ba93bcddf9a9aa64230 (diff) | |
| download | emacs-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')
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@ | |||
| 34 | abs_top_srcdir=@abs_top_srcdir@ | 34 | abs_top_srcdir=@abs_top_srcdir@ |
| 35 | VPATH = $(srcdir) | 35 | VPATH = $(srcdir) |
| 36 | CC = @CC@ | 36 | CC = @CC@ |
| 37 | CXX = @CXX@ | ||
| 37 | CFLAGS = @CFLAGS@ | 38 | CFLAGS = @CFLAGS@ |
| 38 | CPPFLAGS = @CPPFLAGS@ | 39 | CPPFLAGS = @CPPFLAGS@ |
| 39 | LDFLAGS = @LDFLAGS@ | 40 | LDFLAGS = @LDFLAGS@ |
| @@ -346,10 +347,17 @@ BUILD_DETAILS = @BUILD_DETAILS@ | |||
| 346 | 347 | ||
| 347 | UNEXEC_OBJ = @UNEXEC_OBJ@ | 348 | UNEXEC_OBJ = @UNEXEC_OBJ@ |
| 348 | 349 | ||
| 350 | HAIKU_OBJ = @HAIKU_OBJ@ | ||
| 351 | HAIKU_CXX_OBJ = @HAIKU_CXX_OBJ@ | ||
| 352 | HAIKU_LIBS = @HAIKU_LIBS@ | ||
| 353 | HAIKU_CFLAGS = @HAIKU_CFLAGS@ | ||
| 354 | |||
| 349 | DUMPING=@DUMPING@ | 355 | DUMPING=@DUMPING@ |
| 350 | CHECK_STRUCTS = @CHECK_STRUCTS@ | 356 | CHECK_STRUCTS = @CHECK_STRUCTS@ |
| 351 | HAVE_PDUMPER = @HAVE_PDUMPER@ | 357 | HAVE_PDUMPER = @HAVE_PDUMPER@ |
| 352 | 358 | ||
| 359 | HAVE_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. |
| 355 | DO_CODESIGN=$(patsubst aarch64-apple-darwin%,yes,@configuration@) | 363 | DO_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. |
| 369 | NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd | 377 | NON_OBJC_CFLAGS = -Wignored-attributes -Wignored-qualifiers -Wopenmp-simd |
| 378 | # Ditto, but for C++. | ||
| 379 | NON_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) |
| 386 | ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) | 397 | ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) |
| 387 | ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ | 398 | ALL_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) |
| 401 | ALL_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) \ |
| 418 | obj = $(base_obj) $(NS_OBJC_OBJ) | 433 | $(HAIKU_OBJ) |
| 434 | doc_obj = $(base_obj) $(NS_OBJC_OBJ) | ||
| 435 | obj = $(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. |
| 435 | GMALLOC_OBJ=@GMALLOC_OBJ@ | 453 | GMALLOC_OBJ=@GMALLOC_OBJ@ |
| @@ -455,7 +473,11 @@ FIRSTFILE_OBJ=@FIRSTFILE_OBJ@ | |||
| 455 | ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) | 473 | ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) |
| 456 | 474 | ||
| 457 | # Must be first, before dep inclusion! | 475 | # Must be first, before dep inclusion! |
| 476 | ifneq ($(HAVE_BE_APP),yes) | ||
| 458 | all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) | 477 | all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) |
| 478 | else | ||
| 479 | all: Emacs Emacs.pdmp $(OTHER_FILES) | ||
| 480 | endif | ||
| 459 | ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:) | 481 | ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:) |
| 460 | all: ../native-lisp | 482 | all: ../native-lisp |
| 461 | endif | 483 | endif |
| @@ -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) $@ |
| 585 | endif | 607 | endif |
| 586 | 608 | ||
| 609 | ## On Haiku, also produce a binary named Emacs with the appropriate | ||
| 610 | ## icon set. | ||
| 611 | |||
| 612 | ifeq ($(HAVE_BE_APP),yes) | ||
| 613 | Emacs: emacs$(EXEEXT) | ||
| 614 | cp -f emacs$(EXEEXT) $@ | ||
| 615 | $(AM_V_GEN) $(libsrc)/be-resources \ | ||
| 616 | $(etc)/images/icons/hicolor/32x32/apps/emacs.png $@ | ||
| 617 | Emacs.pdmp: $(pdmp) | ||
| 618 | $(AM_V_GEN) cp -f $(pdmp) $@ | ||
| 619 | endif | ||
| 620 | |||
| 587 | ifeq ($(DUMPING),pdumper) | 621 | ifeq ($(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 | |||
| 624 | GLOBAL_SOURCES = $(base_obj:.o=.c) $(NS_OBJC_OBJ:.o=.m) | 658 | GLOBAL_SOURCES = $(base_obj:.o=.c) $(NS_OBJC_OBJ:.o=.m) |
| 625 | 659 | ||
| 626 | gl-stamp: $(libsrc)/make-docfile$(EXEEXT) $(GLOBAL_SOURCES) | 660 | gl-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. |
| 650 | temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ | 684 | temacs$(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 \ | 686 | ifeq ($(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++ | ||
| 690 | else | ||
| 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) |
| 694 | endif | ||
| 655 | ifeq ($(HAVE_PDUMPER),yes) | 695 | ifeq ($(HAVE_PDUMPER),yes) |
| 656 | $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@.tmp | 696 | $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@.tmp |
| 657 | ifeq ($(DO_CODESIGN),yes) | 697 | ifeq ($(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. |
| 737 | ctagsfiles1 = $(filter-out ${srcdir}/macuvs.h, $(wildcard ${srcdir}/*.[hc])) | 777 | ctagsfiles1 = $(filter-out ${srcdir}/macuvs.h, $(wildcard ${srcdir}/*.[hc])) |
| 738 | ctagsfiles2 = $(wildcard ${srcdir}/*.m) | 778 | ctagsfiles2 = $(wildcard ${srcdir}/*.m) |
| 779 | ctagsfiles3 = $(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" | ||
| 139 | typedef struct haiku_display_info Display_Info; | ||
| 140 | typedef Emacs_Pixmap Emacs_Pix_Container; | ||
| 141 | typedef 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); | |||
| 3489 | void prepare_image_for_display (struct frame *, struct image *); | 3504 | void prepare_image_for_display (struct frame *, struct image *); |
| 3490 | ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); | 3505 | ptrdiff_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> |
| 114 | extern void moncontrol (int mode); | 118 | extern 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. | ||
| 3232 | Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, | 3260 | Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, |
| 3233 | hpux, usg-unix-v) indicates some sort of Unix system. */); | 3261 | hpux, 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 | |||
| 347 | double_integer_scale (double d) | 347 | double_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; | |||
| 965 | extern void syms_of_nsfont (void); | 965 | extern void syms_of_nsfont (void); |
| 966 | extern void syms_of_macfont (void); | 966 | extern 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) |
| 969 | extern struct font_driver const ftcrfont_driver; | 969 | extern struct font_driver const ftcrfont_driver; |
| 970 | #ifdef HAVE_HARFBUZZ | 970 | #ifdef HAVE_HARFBUZZ |
| 971 | extern struct font_driver ftcrhbfont_driver; | 971 | extern struct font_driver ftcrhbfont_driver; |
| @@ -999,7 +999,7 @@ extern void font_deferred_log (const char *, Lisp_Object, Lisp_Object); | |||
| 999 | INLINE bool | 999 | INLINE bool |
| 1000 | font_data_structures_may_be_ill_formed (void) | 1000 | font_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. | ||
| 229 | See also `frame-live-p'. */) | 230 | See 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 | ||
| 35 | enum metrics_status | 47 | enum 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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 30 | Lisp_Object | ||
| 31 | list_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 | |||
| 43 | Lisp_Object | ||
| 44 | system_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 | |||
| 125 | struct 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. */ | ||
| 134 | static struct load_sample samples[16*60]; | ||
| 135 | static int first_idx = -1, last_idx = -1; | ||
| 136 | static int max_idx = ARRAYELTS (samples); | ||
| 137 | static unsigned num_of_processors = 0; | ||
| 138 | |||
| 139 | static int | ||
| 140 | buf_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 | |||
| 150 | static int | ||
| 151 | buf_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 | |||
| 161 | static double | ||
| 162 | getavg (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 | |||
| 193 | static void | ||
| 194 | sample_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 | |||
| 216 | int | ||
| 217 | getloadavg (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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 38 | static void | ||
| 39 | rgb32_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 | |||
| 47 | static BView * | ||
| 48 | get_view (void *vw) | ||
| 49 | { | ||
| 50 | BView *view = (BView *) find_appropriate_view_for_draw (vw); | ||
| 51 | return view; | ||
| 52 | } | ||
| 53 | |||
| 54 | void | ||
| 55 | BView_StartClip (void *view) | ||
| 56 | { | ||
| 57 | BView *vw = get_view (view); | ||
| 58 | vw->PushState (); | ||
| 59 | } | ||
| 60 | |||
| 61 | void | ||
| 62 | BView_EndClip (void *view) | ||
| 63 | { | ||
| 64 | BView *vw = get_view (view); | ||
| 65 | vw->PopState (); | ||
| 66 | } | ||
| 67 | |||
| 68 | void | ||
| 69 | BView_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 | |||
| 78 | void | ||
| 79 | BView_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 | |||
| 88 | void | ||
| 89 | BView_SetPenSize (void *view, int u) | ||
| 90 | { | ||
| 91 | BView *vw = get_view (view); | ||
| 92 | vw->SetPenSize (u); | ||
| 93 | } | ||
| 94 | |||
| 95 | void | ||
| 96 | BView_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 | |||
| 104 | void | ||
| 105 | BView_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 | |||
| 113 | void | ||
| 114 | BView_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 | |||
| 122 | void | ||
| 123 | BView_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 | |||
| 136 | void | ||
| 137 | BView_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 | |||
| 145 | void | ||
| 146 | BView_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 | |||
| 154 | void | ||
| 155 | BView_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 | |||
| 164 | void | ||
| 165 | BView_SetFont (void *view, void *font) | ||
| 166 | { | ||
| 167 | BView *vw = get_view (view); | ||
| 168 | |||
| 169 | vw->SetFont ((BFont *) font); | ||
| 170 | } | ||
| 171 | |||
| 172 | void | ||
| 173 | BView_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 | |||
| 181 | void | ||
| 182 | BView_DrawString (void *view, const char *chr, ptrdiff_t len) | ||
| 183 | { | ||
| 184 | BView *vw = get_view (view); | ||
| 185 | |||
| 186 | vw->DrawString (chr, len); | ||
| 187 | } | ||
| 188 | |||
| 189 | void | ||
| 190 | BView_DrawChar (void *view, char chr) | ||
| 191 | { | ||
| 192 | BView *vw = get_view (view); | ||
| 193 | |||
| 194 | vw->DrawChar (chr); | ||
| 195 | } | ||
| 196 | |||
| 197 | void | ||
| 198 | BView_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. */ | ||
| 210 | void | ||
| 211 | rgb_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 | |||
| 247 | static double | ||
| 248 | hue_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 | |||
| 259 | void | ||
| 260 | hsl_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 | |||
| 280 | void | ||
| 281 | BView_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 | |||
| 295 | void | ||
| 296 | BView_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 | |||
| 331 | void | ||
| 332 | BView_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 | |||
| 359 | static BBitmap * | ||
| 360 | rotate_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 | |||
| 378 | static BBitmap * | ||
| 379 | rotate_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 | |||
| 397 | void * | ||
| 398 | BBitmap_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 | |||
| 462 | void | ||
| 463 | BView_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 | |||
| 471 | void | ||
| 472 | BView_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 | |||
| 481 | void | ||
| 482 | BView_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 35 | static 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 | |||
| 40 | static void | ||
| 41 | estimate_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 | |||
| 74 | void | ||
| 75 | BFont_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 | |||
| 83 | void | ||
| 84 | BFont_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. */ | ||
| 114 | int | ||
| 115 | BFont_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. */ | ||
| 122 | int | ||
| 123 | BFont_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. */ | ||
| 132 | void | ||
| 133 | BFont_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. */ | ||
| 149 | void | ||
| 150 | BFont_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 | |||
| 171 | static void | ||
| 172 | font_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 | |||
| 272 | static bool | ||
| 273 | font_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 | |||
| 289 | static bool | ||
| 290 | font_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 | |||
| 306 | static bool | ||
| 307 | font_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 | |||
| 326 | static bool | ||
| 327 | font_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 | |||
| 378 | static void | ||
| 379 | haiku_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. */ | ||
| 394 | void | ||
| 395 | haiku_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. */ | ||
| 407 | struct haiku_font_pattern * | ||
| 408 | BFont_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. */ | ||
| 502 | int | ||
| 503 | BFont_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 (©, 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. */ | ||
| 570 | void | ||
| 571 | BFont_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 | |||
| 581 | void | ||
| 582 | BFont_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 | |||
| 592 | int | ||
| 593 | BFont_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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. */ | ||
| 37 | port_id port_application_to_emacs; | ||
| 38 | |||
| 39 | void | ||
| 40 | haiku_io_init (void) | ||
| 41 | { | ||
| 42 | port_application_to_emacs = create_port (PORT_CAP, "application emacs port"); | ||
| 43 | } | ||
| 44 | |||
| 45 | static ssize_t | ||
| 46 | haiku_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. */ | ||
| 100 | void | ||
| 101 | haiku_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. */ | ||
| 117 | int | ||
| 118 | haiku_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. */ | ||
| 133 | int | ||
| 134 | haiku_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. */ | ||
| 154 | int | ||
| 155 | haiku_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 | |||
| 167 | int | ||
| 168 | haiku_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 | |||
| 178 | void | ||
| 179 | haiku_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. */ | ||
| 189 | void | ||
| 190 | record_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. */ | ||
| 196 | ptrdiff_t | ||
| 197 | c_specpdl_idx_from_cxx (void) | ||
| 198 | { | ||
| 199 | return SPECPDL_INDEX (); | ||
| 200 | } | ||
| 201 | |||
| 202 | /* unbind_to (IDX, Qnil), but safe from C++ code. */ | ||
| 203 | void | ||
| 204 | c_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 29 | static BClipboard *primary = NULL; | ||
| 30 | static BClipboard *secondary = NULL; | ||
| 31 | static BClipboard *system_clipboard = NULL; | ||
| 32 | |||
| 33 | int selection_state_flag; | ||
| 34 | |||
| 35 | static char * | ||
| 36 | BClipboard_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 | |||
| 66 | static void | ||
| 67 | BClipboard_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 | |||
| 86 | char * | ||
| 87 | BClipboard_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 | |||
| 95 | char * | ||
| 96 | BClipboard_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 | |||
| 104 | char * | ||
| 105 | BClipboard_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 | |||
| 113 | void | ||
| 114 | BClipboard_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 | |||
| 123 | void | ||
| 124 | BClipboard_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 | |||
| 133 | void | ||
| 134 | BClipboard_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 | |||
| 143 | void | ||
| 144 | BClipboard_free_data (void *ptr) | ||
| 145 | { | ||
| 146 | std::free (ptr); | ||
| 147 | } | ||
| 148 | |||
| 149 | void | ||
| 150 | init_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 83 | static color_space dpy_color_space = B_NO_COLOR_SPACE; | ||
| 84 | static key_map *key_map = NULL; | ||
| 85 | static char *key_chars = NULL; | ||
| 86 | static BLocker key_map_lock; | ||
| 87 | |||
| 88 | extern "C" | ||
| 89 | { | ||
| 90 | extern _Noreturn void emacs_abort (void); | ||
| 91 | /* Also defined in haikuterm.h. */ | ||
| 92 | extern void be_app_quit (void); | ||
| 93 | } | ||
| 94 | |||
| 95 | static thread_id app_thread; | ||
| 96 | |||
| 97 | _Noreturn void | ||
| 98 | gui_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 | ||
| 108 | static cairo_format_t | ||
| 109 | cairo_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 | |||
| 129 | static void | ||
| 130 | map_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 | |||
| 154 | static void | ||
| 155 | map_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 | |||
| 171 | static void | ||
| 172 | map_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 | |||
| 188 | class Emacs : public BApplication | ||
| 189 | { | ||
| 190 | public: | ||
| 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 | |||
| 245 | class EmacsWindow : public BDirectWindow | ||
| 246 | { | ||
| 247 | public: | ||
| 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 | |||
| 866 | class EmacsMenuBar : public BMenuBar | ||
| 867 | { | ||
| 868 | public: | ||
| 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 | |||
| 886 | class EmacsView : public BView | ||
| 887 | { | ||
| 888 | public: | ||
| 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 | |||
| 1260 | class EmacsScrollBar : public BScrollBar | ||
| 1261 | { | ||
| 1262 | public: | ||
| 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 | |||
| 1318 | class EmacsTitleMenuItem : public BMenuItem | ||
| 1319 | { | ||
| 1320 | public: | ||
| 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 | |||
| 1339 | class EmacsMenuItem : public BMenuItem | ||
| 1340 | { | ||
| 1341 | public: | ||
| 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 | |||
| 1421 | class EmacsPopUpMenu : public BPopUpMenu | ||
| 1422 | { | ||
| 1423 | public: | ||
| 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 | |||
| 1437 | static int32 | ||
| 1438 | start_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. */ | ||
| 1452 | void * | ||
| 1453 | BBitmap_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'. */ | ||
| 1461 | int | ||
| 1462 | BBitmap_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 | |||
| 1484 | void | ||
| 1485 | BBitmap_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. */ | ||
| 1492 | void * | ||
| 1493 | BBitmap_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 | |||
| 1501 | void | ||
| 1502 | BBitmap_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. */ | ||
| 1518 | void * | ||
| 1519 | BApplication_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. */ | ||
| 1539 | void * | ||
| 1540 | BWindow_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 | |||
| 1563 | void | ||
| 1564 | BWindow_quit (void *window) | ||
| 1565 | { | ||
| 1566 | ((BWindow *) window)->Lock (); | ||
| 1567 | ((BWindow *) window)->Quit (); | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | /* Set WINDOW's offset to X, Y. */ | ||
| 1571 | void | ||
| 1572 | BWindow_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. */ | ||
| 1588 | void | ||
| 1589 | BWindow_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. */ | ||
| 1597 | void | ||
| 1598 | BWindow_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. */ | ||
| 1617 | void | ||
| 1618 | BWindow_retitle (void *window, const char *title) | ||
| 1619 | { | ||
| 1620 | ((BWindow *) window)->SetTitle (title); | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | /* Resize WINDOW to WIDTH by HEIGHT. */ | ||
| 1624 | void | ||
| 1625 | BWindow_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. */ | ||
| 1632 | void | ||
| 1633 | BWindow_activate (void *window) | ||
| 1634 | { | ||
| 1635 | ((BWindow *) window)->Activate (); | ||
| 1636 | } | ||
| 1637 | |||
| 1638 | /* Return the pixel dimensions of the main screen in WIDTH and | ||
| 1639 | HEIGHT. */ | ||
| 1640 | void | ||
| 1641 | BScreen_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. */ | ||
| 1653 | void | ||
| 1654 | BView_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 | |||
| 1664 | void * | ||
| 1665 | BCursor_create_default (void) | ||
| 1666 | { | ||
| 1667 | return new BCursor (B_CURSOR_ID_SYSTEM_DEFAULT); | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | void * | ||
| 1671 | BCursor_create_modeline (void) | ||
| 1672 | { | ||
| 1673 | return new BCursor (B_CURSOR_ID_CONTEXT_MENU); | ||
| 1674 | } | ||
| 1675 | |||
| 1676 | void * | ||
| 1677 | BCursor_from_id (enum haiku_cursor cursor) | ||
| 1678 | { | ||
| 1679 | return new BCursor ((enum BCursorID) cursor); | ||
| 1680 | } | ||
| 1681 | |||
| 1682 | void * | ||
| 1683 | BCursor_create_i_beam (void) | ||
| 1684 | { | ||
| 1685 | return new BCursor (B_CURSOR_ID_I_BEAM); | ||
| 1686 | } | ||
| 1687 | |||
| 1688 | void * | ||
| 1689 | BCursor_create_progress_cursor (void) | ||
| 1690 | { | ||
| 1691 | return new BCursor (B_CURSOR_ID_PROGRESS); | ||
| 1692 | } | ||
| 1693 | |||
| 1694 | void * | ||
| 1695 | BCursor_create_grab (void) | ||
| 1696 | { | ||
| 1697 | return new BCursor (B_CURSOR_ID_GRAB); | ||
| 1698 | } | ||
| 1699 | |||
| 1700 | void | ||
| 1701 | BCursor_delete (void *cursor) | ||
| 1702 | { | ||
| 1703 | delete (BCursor *) cursor; | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | void | ||
| 1707 | BView_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 | |||
| 1715 | void | ||
| 1716 | BWindow_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. */ | ||
| 1723 | void | ||
| 1724 | BMapKey (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. */ | ||
| 1787 | void * | ||
| 1788 | BScrollBar_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 | |||
| 1805 | void | ||
| 1806 | BScrollBar_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 | |||
| 1819 | void | ||
| 1820 | BView_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 | |||
| 1833 | void | ||
| 1834 | BView_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. */ | ||
| 1846 | int | ||
| 1847 | BScrollBar_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. */ | ||
| 1853 | void | ||
| 1854 | BView_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. */ | ||
| 1866 | void | ||
| 1867 | BView_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 | |||
| 1889 | void | ||
| 1890 | BView_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 | |||
| 1906 | void | ||
| 1907 | BWindow_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. */ | ||
| 1914 | void | ||
| 1915 | BView_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. */ | ||
| 1926 | void | ||
| 1927 | BView_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. */ | ||
| 1938 | void | ||
| 1939 | BView_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. */ | ||
| 1950 | void | ||
| 1951 | BBitmap_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. */ | ||
| 1965 | void | ||
| 1966 | BView_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 | |||
| 1977 | void | ||
| 1978 | BView_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 | |||
| 1989 | void | ||
| 1990 | BView_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. */ | ||
| 2005 | void | ||
| 2006 | BView_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 | |||
| 2019 | void | ||
| 2020 | BView_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. */ | ||
| 2034 | void | ||
| 2035 | BWindow_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. */ | ||
| 2048 | void | ||
| 2049 | BWindow_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. */ | ||
| 2061 | void | ||
| 2062 | BWindow_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 | |||
| 2076 | void | ||
| 2077 | BView_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. */ | ||
| 2087 | uint32_t | ||
| 2088 | haiku_current_workspace (void) | ||
| 2089 | { | ||
| 2090 | return current_workspace (); | ||
| 2091 | } | ||
| 2092 | |||
| 2093 | /* Return a bitmask consisting of workspaces WINDOW is on. */ | ||
| 2094 | uint32_t | ||
| 2095 | BWindow_workspaces (void *window) | ||
| 2096 | { | ||
| 2097 | return ((BWindow *) window)->Workspaces (); | ||
| 2098 | } | ||
| 2099 | |||
| 2100 | /* Create a popup menu. */ | ||
| 2101 | void * | ||
| 2102 | BPopUpMenu_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. */ | ||
| 2111 | void | ||
| 2112 | BMenu_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. */ | ||
| 2120 | void | ||
| 2121 | BMenu_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. */ | ||
| 2144 | void | ||
| 2145 | BMenu_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. */ | ||
| 2153 | void * | ||
| 2154 | BMenu_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. */ | ||
| 2166 | void * | ||
| 2167 | BMenu_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. */ | ||
| 2181 | void * | ||
| 2182 | BMenu_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. */ | ||
| 2200 | void | ||
| 2201 | BPopUpMenu_delete (void *menu) | ||
| 2202 | { | ||
| 2203 | delete (BPopUpMenu *) menu; | ||
| 2204 | } | ||
| 2205 | |||
| 2206 | /* Create a menubar, attach it to VIEW, and return it. */ | ||
| 2207 | void * | ||
| 2208 | BMenuBar_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. */ | ||
| 2222 | void | ||
| 2223 | BMenuBar_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. */ | ||
| 2235 | void | ||
| 2236 | BMenu_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. */ | ||
| 2243 | void | ||
| 2244 | BMenu_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. */ | ||
| 2251 | int | ||
| 2252 | BMenu_count_items (void *menu) | ||
| 2253 | { | ||
| 2254 | return ((BMenu *) menu)->CountItems (); | ||
| 2255 | } | ||
| 2256 | |||
| 2257 | /* Find the item in MENU at IDX. */ | ||
| 2258 | void * | ||
| 2259 | BMenu_item_at (void *menu, int idx) | ||
| 2260 | { | ||
| 2261 | return ((BMenu *) menu)->ItemAt (idx); | ||
| 2262 | } | ||
| 2263 | |||
| 2264 | /* Set ITEM's label to LABEL. */ | ||
| 2265 | void | ||
| 2266 | BMenu_item_set_label (void *item, const char *label) | ||
| 2267 | { | ||
| 2268 | ((BMenuItem *) item)->SetLabel (label); | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | /* Get ITEM's menu. */ | ||
| 2272 | void * | ||
| 2273 | BMenu_item_get_menu (void *item) | ||
| 2274 | { | ||
| 2275 | return ((BMenuItem *) item)->Submenu (); | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | /* Emit a beep noise. */ | ||
| 2279 | void | ||
| 2280 | haiku_ring_bell (void) | ||
| 2281 | { | ||
| 2282 | beep (); | ||
| 2283 | } | ||
| 2284 | |||
| 2285 | /* Create a BAlert with TEXT. */ | ||
| 2286 | void * | ||
| 2287 | BAlert_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. */ | ||
| 2294 | void * | ||
| 2295 | BAlert_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. */ | ||
| 2304 | int32_t | ||
| 2305 | BAlert_go (void *alert) | ||
| 2306 | { | ||
| 2307 | return ((BAlert *) alert)->Go (); | ||
| 2308 | } | ||
| 2309 | |||
| 2310 | /* Enable or disable BUTTON depending on ENABLED_P. */ | ||
| 2311 | void | ||
| 2312 | BButton_set_enabled (void *button, int enabled_p) | ||
| 2313 | { | ||
| 2314 | ((BButton *) button)->SetEnabled (enabled_p); | ||
| 2315 | } | ||
| 2316 | |||
| 2317 | /* Set VIEW's tooltip to TOOLTIP. */ | ||
| 2318 | void | ||
| 2319 | BView_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. */ | ||
| 2325 | void | ||
| 2326 | BView_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. */ | ||
| 2354 | void | ||
| 2355 | BAlert_delete (void *alert) | ||
| 2356 | { | ||
| 2357 | delete (BAlert *) alert; | ||
| 2358 | } | ||
| 2359 | |||
| 2360 | /* Place the resolution of the monitor in DPI in RSSX and RSSY. */ | ||
| 2361 | void | ||
| 2362 | BScreen_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. */ | ||
| 2383 | void | ||
| 2384 | EmacsWindow_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 | |||
| 2393 | void | ||
| 2394 | EmacsWindow_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. */ | ||
| 2405 | void | ||
| 2406 | be_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. */ | ||
| 2427 | int | ||
| 2428 | be_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. */ | ||
| 2455 | int | ||
| 2456 | be_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. */ | ||
| 2481 | void | ||
| 2482 | be_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. */ | ||
| 2493 | void | ||
| 2494 | EmacsWindow_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. */ | ||
| 2508 | void * | ||
| 2509 | find_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. */ | ||
| 2520 | void | ||
| 2521 | EmacsView_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. */ | ||
| 2536 | void | ||
| 2537 | EmacsView_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. */ | ||
| 2549 | void | ||
| 2550 | EmacsView_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. */ | ||
| 2560 | int | ||
| 2561 | EmacsView_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 | |||
| 2571 | struct popup_file_dialog_data | ||
| 2572 | { | ||
| 2573 | BMessage *msg; | ||
| 2574 | BFilePanel *panel; | ||
| 2575 | BEntry *entry; | ||
| 2576 | }; | ||
| 2577 | |||
| 2578 | static void | ||
| 2579 | unwind_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 | |||
| 2589 | static void | ||
| 2590 | be_popup_file_dialog_safe_set_target (BFilePanel *dialog, BWindow *window) | ||
| 2591 | { | ||
| 2592 | dialog->SetTarget (BMessenger (window)); | ||
| 2593 | } | ||
| 2594 | |||
| 2595 | /* Popup a file dialog. */ | ||
| 2596 | char * | ||
| 2597 | be_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 | |||
| 2661 | void | ||
| 2662 | be_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. */ | ||
| 2674 | void | ||
| 2675 | EmacsView_do_visible_bell (void *view, uint32_t color) | ||
| 2676 | { | ||
| 2677 | EmacsView *vw = (EmacsView *) view; | ||
| 2678 | vw->DoVisibleBell (color); | ||
| 2679 | } | ||
| 2680 | |||
| 2681 | /* Zoom WINDOW. */ | ||
| 2682 | void | ||
| 2683 | BWindow_zoom (void *window) | ||
| 2684 | { | ||
| 2685 | BWindow *w = (BWindow *) window; | ||
| 2686 | w->Zoom (); | ||
| 2687 | } | ||
| 2688 | |||
| 2689 | /* Make WINDOW fullscreen if FULLSCREEN_P. */ | ||
| 2690 | void | ||
| 2691 | EmacsWindow_make_fullscreen (void *window, int fullscreen_p) | ||
| 2692 | { | ||
| 2693 | EmacsWindow *w = (EmacsWindow *) window; | ||
| 2694 | w->MakeFullscreen (fullscreen_p); | ||
| 2695 | } | ||
| 2696 | |||
| 2697 | /* Unzoom (maximize) WINDOW. */ | ||
| 2698 | void | ||
| 2699 | EmacsWindow_unzoom (void *window) | ||
| 2700 | { | ||
| 2701 | EmacsWindow *w = (EmacsWindow *) window; | ||
| 2702 | w->UnZoom (); | ||
| 2703 | } | ||
| 2704 | |||
| 2705 | /* Move the pointer into MBAR and start tracking. */ | ||
| 2706 | void | ||
| 2707 | BMenuBar_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 | ||
| 2722 | int | ||
| 2723 | be_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 | |||
| 2778 | void * | ||
| 2779 | be_translate_bitmap_from_file_name (const char *filename) | ||
| 2780 | { | ||
| 2781 | BBitmap *bm = BTranslationUtils::GetBitmap (filename); | ||
| 2782 | return bm; | ||
| 2783 | } | ||
| 2784 | |||
| 2785 | void * | ||
| 2786 | be_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. */ | ||
| 2795 | size_t | ||
| 2796 | BBitmap_bytes_length (void *bitmap) | ||
| 2797 | { | ||
| 2798 | BBitmap *bm = (BBitmap *) bitmap; | ||
| 2799 | return bm->BitsLength (); | ||
| 2800 | } | ||
| 2801 | |||
| 2802 | /* Show VIEW's tooltip. */ | ||
| 2803 | void | ||
| 2804 | BView_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. */ | ||
| 2817 | cairo_surface_t * | ||
| 2818 | EmacsView_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. */ | ||
| 2827 | void | ||
| 2828 | BView_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. */ | ||
| 2845 | void | ||
| 2846 | EmacsWindow_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. */ | ||
| 2859 | void | ||
| 2860 | EmacsWindow_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. */ | ||
| 2872 | int | ||
| 2873 | be_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. */ | ||
| 2879 | int | ||
| 2880 | be_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. */ | ||
| 2889 | int | ||
| 2890 | be_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. */ | ||
| 2904 | void | ||
| 2905 | BWindow_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. */ | ||
| 2916 | void | ||
| 2917 | BWindow_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 35 | enum 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 | |||
| 52 | enum 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 | |||
| 61 | enum 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 | |||
| 88 | struct haiku_quit_requested_event | ||
| 89 | { | ||
| 90 | void *window; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct haiku_resize_event | ||
| 94 | { | ||
| 95 | void *window; | ||
| 96 | float px_heightf; | ||
| 97 | float px_widthf; | ||
| 98 | }; | ||
| 99 | |||
| 100 | struct haiku_expose_event | ||
| 101 | { | ||
| 102 | void *window; | ||
| 103 | int x; | ||
| 104 | int y; | ||
| 105 | int width; | ||
| 106 | int height; | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct haiku_refs_event | ||
| 110 | { | ||
| 111 | void *window; | ||
| 112 | int x, y; | ||
| 113 | /* Free this with free! */ | ||
| 114 | char *ref; | ||
| 115 | }; | ||
| 116 | |||
| 117 | struct 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 | |||
| 127 | struct 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 | |||
| 136 | struct haiku_activation_event | ||
| 137 | { | ||
| 138 | void *window; | ||
| 139 | int activated_p; | ||
| 140 | }; | ||
| 141 | |||
| 142 | struct 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 | |||
| 151 | struct haiku_button_event | ||
| 152 | { | ||
| 153 | void *window; | ||
| 154 | int btn_no; | ||
| 155 | int modifiers; | ||
| 156 | int x; | ||
| 157 | int y; | ||
| 158 | }; | ||
| 159 | |||
| 160 | struct haiku_iconification_event | ||
| 161 | { | ||
| 162 | void *window; | ||
| 163 | int iconified_p; | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct haiku_move_event | ||
| 167 | { | ||
| 168 | void *window; | ||
| 169 | int x; | ||
| 170 | int y; | ||
| 171 | }; | ||
| 172 | |||
| 173 | struct haiku_wheel_move_event | ||
| 174 | { | ||
| 175 | void *window; | ||
| 176 | int modifiers; | ||
| 177 | float delta_x; | ||
| 178 | float delta_y; | ||
| 179 | }; | ||
| 180 | |||
| 181 | struct haiku_menu_bar_select_event | ||
| 182 | { | ||
| 183 | void *window; | ||
| 184 | void *ptr; | ||
| 185 | }; | ||
| 186 | |||
| 187 | struct haiku_file_panel_event | ||
| 188 | { | ||
| 189 | void *ptr; | ||
| 190 | }; | ||
| 191 | |||
| 192 | struct haiku_menu_bar_help_event | ||
| 193 | { | ||
| 194 | void *window; | ||
| 195 | int mb_idx; | ||
| 196 | }; | ||
| 197 | |||
| 198 | struct 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 | |||
| 217 | typedef char haiku_font_family_or_style[64]; | ||
| 218 | |||
| 219 | enum haiku_font_slant | ||
| 220 | { | ||
| 221 | NO_SLANT = -1, | ||
| 222 | SLANT_OBLIQUE, | ||
| 223 | SLANT_REGULAR, | ||
| 224 | SLANT_ITALIC | ||
| 225 | }; | ||
| 226 | |||
| 227 | enum 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 | |||
| 241 | enum haiku_font_language | ||
| 242 | { | ||
| 243 | LANGUAGE_CN, | ||
| 244 | LANGUAGE_KO, | ||
| 245 | LANGUAGE_JP, | ||
| 246 | MAX_LANGUAGE /* This isn't a language. */ | ||
| 247 | }; | ||
| 248 | |||
| 249 | struct 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 | |||
| 273 | struct haiku_scroll_bar_value_event | ||
| 274 | { | ||
| 275 | void *scroll_bar; | ||
| 276 | int position; | ||
| 277 | }; | ||
| 278 | |||
| 279 | struct haiku_scroll_bar_drag_event | ||
| 280 | { | ||
| 281 | void *scroll_bar; | ||
| 282 | int dragging_p; | ||
| 283 | }; | ||
| 284 | |||
| 285 | struct haiku_menu_bar_resize_event | ||
| 286 | { | ||
| 287 | void *window; | ||
| 288 | int width; | ||
| 289 | int height; | ||
| 290 | }; | ||
| 291 | |||
| 292 | struct 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 | ||
| 314 | extern "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 | |||
| 827 | extern _Noreturn void | ||
| 828 | gui_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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. */ | ||
| 48 | static Lisp_Object tip_frame; | ||
| 49 | |||
| 50 | /* The window-system window corresponding to the frame of the | ||
| 51 | currently visible tooltip. */ | ||
| 52 | static Window tip_window; | ||
| 53 | |||
| 54 | /* A timer that hides or deletes the currently visible tooltip when it | ||
| 55 | fires. */ | ||
| 56 | static Lisp_Object tip_timer; | ||
| 57 | |||
| 58 | /* STRING argument of last `x-show-tip' call. */ | ||
| 59 | static Lisp_Object tip_last_string; | ||
| 60 | |||
| 61 | /* Normalized FRAME argument of last `x-show-tip' call. */ | ||
| 62 | static Lisp_Object tip_last_frame; | ||
| 63 | |||
| 64 | /* PARMS argument of last `x-show-tip' call. */ | ||
| 65 | static Lisp_Object tip_last_parms; | ||
| 66 | |||
| 67 | static void | ||
| 68 | haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval); | ||
| 69 | static void | ||
| 70 | haiku_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name); | ||
| 71 | |||
| 72 | static ptrdiff_t image_cache_refcount; | ||
| 73 | |||
| 74 | static Lisp_Object | ||
| 75 | get_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 | |||
| 105 | void | ||
| 106 | haiku_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 | |||
| 154 | void | ||
| 155 | haiku_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 | |||
| 203 | static void | ||
| 204 | haiku_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 | |||
| 211 | static void | ||
| 212 | haiku_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 | |||
| 231 | static void | ||
| 232 | haiku_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 | |||
| 254 | int | ||
| 255 | haiku_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 | |||
| 294 | static struct haiku_display_info * | ||
| 295 | haiku_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 | |||
| 310 | static struct haiku_display_info * | ||
| 311 | check_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 | |||
| 346 | static void | ||
| 347 | haiku_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 | |||
| 357 | static void | ||
| 358 | haiku_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 | |||
| 374 | static void | ||
| 375 | haiku_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 | |||
| 398 | static void | ||
| 399 | haiku_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 | |||
| 433 | static void | ||
| 434 | haiku_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | ||
| 435 | { | ||
| 436 | haiku_set_name (f, arg, 1); | ||
| 437 | } | ||
| 438 | |||
| 439 | static void | ||
| 440 | haiku_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 | |||
| 454 | static void | ||
| 455 | unwind_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 | |||
| 494 | static void | ||
| 495 | unwind_create_tip_frame (Lisp_Object frame) | ||
| 496 | { | ||
| 497 | unwind_create_frame (frame); | ||
| 498 | tip_window = NULL; | ||
| 499 | tip_frame = Qnil; | ||
| 500 | } | ||
| 501 | |||
| 502 | static void | ||
| 503 | haiku_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 | |||
| 541 | static void | ||
| 542 | unwind_popup (void) | ||
| 543 | { | ||
| 544 | if (!popup_activated_p) | ||
| 545 | emacs_abort (); | ||
| 546 | --popup_activated_p; | ||
| 547 | } | ||
| 548 | |||
| 549 | static Lisp_Object | ||
| 550 | haiku_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 | |||
| 938 | static void | ||
| 939 | compute_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 | |||
| 1005 | static Lisp_Object | ||
| 1006 | haiku_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 | |||
| 1057 | static void | ||
| 1058 | haiku_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 | |||
| 1070 | static void | ||
| 1071 | haiku_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. */ | ||
| 1109 | static Lisp_Object | ||
| 1110 | frame_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 | |||
| 1155 | void | ||
| 1156 | haiku_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 | |||
| 1195 | void | ||
| 1196 | haiku_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 | |||
| 1220 | void | ||
| 1221 | haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | ||
| 1222 | { | ||
| 1223 | set_frame_cursor_types (f, arg); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | unsigned long | ||
| 1227 | haiku_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 | |||
| 1251 | void | ||
| 1252 | haiku_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 | |||
| 1285 | void | ||
| 1286 | haiku_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 | |||
| 1367 | void | ||
| 1368 | haiku_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 | |||
| 1383 | void | ||
| 1384 | haiku_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 | |||
| 1406 | void | ||
| 1407 | haiku_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 | |||
| 1418 | void | ||
| 1419 | haiku_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 | |||
| 1437 | void | ||
| 1438 | haiku_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 | |||
| 1446 | void | ||
| 1447 | frame_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 | |||
| 1457 | void | ||
| 1458 | haiku_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 | |||
| 1467 | Display_Info * | ||
| 1468 | check_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. */ | ||
| 1480 | void | ||
| 1481 | haiku_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 | |||
| 1507 | static void | ||
| 1508 | haiku_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 | |||
| 1532 | DEFUN ("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 | ||
| 1536 | coordinates X and Y are interpreted to start from the top-left | ||
| 1537 | corner 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 | |||
| 1552 | DEFUN ("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. | ||
| 1555 | The position is returned as a cons cell (X . Y) of the coordinates of | ||
| 1556 | the mouse cursor position in pixels relative to a position (0, 0) of the | ||
| 1557 | selected 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 | |||
| 1580 | DEFUN ("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 | |||
| 1587 | DEFUN ("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 | |||
| 1598 | DEFUN ("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 | |||
| 1616 | DEFUN ("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 | |||
| 1624 | DEFUN ("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 | |||
| 1643 | DEFUN ("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 | |||
| 1656 | DEFUN ("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 | |||
| 1669 | DEFUN ("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 | |||
| 1682 | DEFUN ("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 | |||
| 1694 | DEFUN ("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 | |||
| 1702 | DEFUN ("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 | |||
| 1719 | DEFUN ("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 | |||
| 2003 | DEFUN ("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 | |||
| 2010 | DEFUN ("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 | |||
| 2020 | DEFUN ("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 | |||
| 2030 | DEFUN ("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 | |||
| 2038 | DEFUN ("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 | |||
| 2046 | DEFUN ("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 | |||
| 2054 | DEFUN ("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 | |||
| 2065 | DEFUN ("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 | |||
| 2075 | DEFUN ("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 | |||
| 2085 | DEFUN ("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 | |||
| 2096 | DEFUN ("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 | |||
| 2119 | DEFUN ("haiku-frame-geometry", Fhaiku_frame_geometry, Shaiku_frame_geometry, 0, 1, 0, | ||
| 2120 | doc: /* Return geometric attributes of FRAME. | ||
| 2121 | FRAME must be a live frame and defaults to the selected one. The return | ||
| 2122 | value is an association list of the attributes listed below. All height | ||
| 2123 | and 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 | |||
| 2163 | DEFUN ("haiku-frame-edges", Fhaiku_frame_edges, Shaiku_frame_edges, 0, 2, 0, | ||
| 2164 | doc: /* Return edge coordinates of FRAME. | ||
| 2165 | FRAME must be a live frame and defaults to the selected one. The return | ||
| 2166 | value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are | ||
| 2167 | in pixels relative to the origin - the position (0, 0) - of FRAME's | ||
| 2168 | display. | ||
| 2169 | |||
| 2170 | If optional argument TYPE is the symbol `outer-edges', return the outer | ||
| 2171 | edges of FRAME. The outer edges comprise the decorations of the window | ||
| 2172 | manager (like the title bar or external borders) as well as any external | ||
| 2173 | menu 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 | ||
| 2175 | edges exclude the decorations of the window manager and any external | ||
| 2176 | menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return | ||
| 2177 | the inner edges of FRAME. These edges exclude title bar, any borders, | ||
| 2178 | menu 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 | |||
| 2187 | DEFUN ("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. | ||
| 2189 | Optional arg FRAME specifies a frame on which to display the file panel. | ||
| 2190 | If it is nil, the current frame is used instead. | ||
| 2191 | The frame being used will be brought to the front of | ||
| 2192 | the display after the file panel is closed. | ||
| 2193 | Optional arg DIR, if non-nil, supplies a default directory. | ||
| 2194 | Optional arg MUSTMATCH, if non-nil, means the returned file or | ||
| 2195 | directory must exist. | ||
| 2196 | Optional arg DIR_ONLY_P, if non-nil, means choose only directories. | ||
| 2197 | Optional 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 | |||
| 2250 | DEFUN ("haiku-put-resource", Fhaiku_put_resource, Shaiku_put_resource, | ||
| 2251 | 2, 2, 0, doc: /* Place STRING by the key RESOURCE in the resource database. | ||
| 2252 | It 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 | |||
| 2263 | DEFUN ("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. | ||
| 2266 | If TERMINAL is non-nil and specifies a live frame, return the child | ||
| 2267 | frames of that frame in Z (stacking) order. | ||
| 2268 | |||
| 2269 | As it is impossible to reliably determine the frame stacking order on | ||
| 2270 | Haiku, the selected frame is always the first element of the returned | ||
| 2271 | list, while the rest are not guaranteed to be in any particular order. | ||
| 2272 | |||
| 2273 | Frames 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 | |||
| 2300 | DEFUN ("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 | |||
| 2317 | frame_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 | |||
| 2369 | void | ||
| 2370 | syms_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. | ||
| 2429 | This can avoid a great deal of consing that does not play | ||
| 2430 | well with the Haiku memory allocator, but comes with the | ||
| 2431 | disadvantage of not being able to use special display properties | ||
| 2432 | within 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 | |||
| 3 | Copyright (C) 2021 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along 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 | |||
| 40 | static Lisp_Object font_cache; | ||
| 41 | |||
| 42 | #define METRICS_NCOLS_PER_ROW (128) | ||
| 43 | |||
| 44 | enum 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 | |||
| 53 | static 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 | |||
| 105 | static void | ||
| 106 | haikufont_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 | |||
| 177 | static Lisp_Object | ||
| 178 | haikufont_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 | |||
| 196 | static Lisp_Object | ||
| 197 | haikufont_get_cache (struct frame *frame) | ||
| 198 | { | ||
| 199 | return font_cache; | ||
| 200 | } | ||
| 201 | |||
| 202 | static Lisp_Object | ||
| 203 | haikufont_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 | |||
| 241 | static int | ||
| 242 | haikufont_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 | |||
| 278 | static Lisp_Object | ||
| 279 | haikufont_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 | |||
| 295 | static enum haiku_font_slant | ||
| 296 | haikufont_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 | |||
| 309 | static Lisp_Object | ||
| 310 | haikufont_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 | |||
| 339 | static enum haiku_font_width | ||
| 340 | haikufont_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 | |||
| 361 | static int | ||
| 362 | haikufont_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 | |||
| 381 | static Lisp_Object | ||
| 382 | haikufont_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 | |||
| 424 | static void | ||
| 425 | haikufont_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 | |||
| 559 | static void | ||
| 560 | haikufont_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 | |||
| 569 | static Lisp_Object | ||
| 570 | haikufont_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 | |||
| 588 | static Lisp_Object | ||
| 589 | haikufont_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 | |||
| 619 | static void | ||
| 620 | haiku_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 | |||
| 648 | static unsigned int | ||
| 649 | haikufont_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 | |||
| 664 | static Lisp_Object | ||
| 665 | haikufont_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 | |||
| 752 | static void | ||
| 753 | haikufont_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 | |||
| 775 | static void | ||
| 776 | haikufont_prepare_face (struct frame *f, struct face *face) | ||
| 777 | { | ||
| 778 | |||
| 779 | } | ||
| 780 | |||
| 781 | static void | ||
| 782 | haikufont_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 | |||
| 834 | static void | ||
| 835 | haikufont_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 | |||
| 866 | static Lisp_Object | ||
| 867 | haikufont_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 | |||
| 945 | static int | ||
| 946 | haikufont_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 | |||
| 1031 | struct 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 | |||
| 1047 | void | ||
| 1048 | syms_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | ||
| 23 | extern "C" | ||
| 24 | { | ||
| 25 | #endif | ||
| 26 | |||
| 27 | typedef struct haiku_char_struct | ||
| 28 | { | ||
| 29 | int rbearing; | ||
| 30 | int lbearing; | ||
| 31 | int width; | ||
| 32 | int ascent; | ||
| 33 | int descent; | ||
| 34 | } XCharStruct; | ||
| 35 | |||
| 36 | struct haiku_rect | ||
| 37 | { | ||
| 38 | int x, y; | ||
| 39 | int width, height; | ||
| 40 | }; | ||
| 41 | |||
| 42 | typedef void *haiku; | ||
| 43 | |||
| 44 | typedef haiku Emacs_Pixmap; | ||
| 45 | typedef haiku Emacs_Window; | ||
| 46 | typedef haiku Emacs_Cursor; | ||
| 47 | typedef 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 | |||
| 100 | typedef haiku Window; | ||
| 101 | typedef 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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 28 | bool | ||
| 29 | haiku_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 | |||
| 62 | extern int | ||
| 63 | haiku_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 | |||
| 105 | void | ||
| 106 | syms_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 31 | static Lisp_Object *volatile menu_item_selection; | ||
| 32 | |||
| 33 | int popup_activated_p = 0; | ||
| 34 | |||
| 35 | struct submenu_stack_cell | ||
| 36 | { | ||
| 37 | void *parent_menu; | ||
| 38 | void *pane; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static void | ||
| 42 | digest_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 | |||
| 166 | static Lisp_Object | ||
| 167 | haiku_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 | |||
| 248 | Lisp_Object | ||
| 249 | haiku_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 | |||
| 284 | Lisp_Object | ||
| 285 | haiku_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 | |||
| 385 | void | ||
| 386 | free_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 | |||
| 404 | void | ||
| 405 | initialize_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 | |||
| 413 | void | ||
| 414 | set_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 | |||
| 577 | void | ||
| 578 | run_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 | |||
| 610 | DEFUN ("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 | |||
| 617 | DEFUN ("haiku-menu-bar-open", Fhaiku_menu_bar_open, Shaiku_menu_bar_open, 0, 1, "i", | ||
| 618 | doc: /* Show the menu bar in FRAME. | ||
| 619 | |||
| 620 | Move the mouse pointer onto the first element of FRAME's menu bar, and | ||
| 621 | cause it to be opened. If FRAME is nil or not given, use the selected | ||
| 622 | frame. If FRAME has no menu bar, a pop-up is displayed at the position | ||
| 623 | of 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 | |||
| 646 | void | ||
| 647 | syms_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 27 | DEFUN ("haiku-selection-data", Fhaiku_selection_data, Shaiku_selection_data, | ||
| 28 | 2, 2, 0, | ||
| 29 | doc: /* Retrieve content typed as NAME from the clipboard | ||
| 30 | CLIPBOARD. CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or | ||
| 31 | `CLIPBOARD'. NAME is a MIME type denoting the type of the data to | ||
| 32 | fetch. */) | ||
| 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 | |||
| 80 | DEFUN ("haiku-selection-put", Fhaiku_selection_put, Shaiku_selection_put, | ||
| 81 | 3, 3, 0, | ||
| 82 | doc: /* Add or remove content from the clipboard CLIPBOARD. | ||
| 83 | CLIPBOARD is the symbol `PRIMARY', `SECONDARY' or `CLIPBOARD'. NAME | ||
| 84 | is a MIME type denoting the type of the data to add. DATA is the | ||
| 85 | string that will be placed in the clipboard, or nil if the content is | ||
| 86 | to 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 | ||
| 88 | clipboard. */) | ||
| 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 | |||
| 123 | void | ||
| 124 | syms_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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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> | ||
| 28 | extern "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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 43 | struct haiku_display_info *x_display_list = NULL; | ||
| 44 | extern frame_parm_handler haiku_frame_parm_handlers[]; | ||
| 45 | |||
| 46 | static void **fringe_bmps; | ||
| 47 | static int fringe_bitmap_fillptr = 0; | ||
| 48 | |||
| 49 | static Lisp_Object rdb; | ||
| 50 | |||
| 51 | struct unhandled_event | ||
| 52 | { | ||
| 53 | struct unhandled_event *next; | ||
| 54 | enum haiku_event_type type; | ||
| 55 | uint8_t buffer[200]; | ||
| 56 | }; | ||
| 57 | |||
| 58 | char * | ||
| 59 | get_keysym_name (int keysym) | ||
| 60 | { | ||
| 61 | static char value[16]; | ||
| 62 | sprintf (value, "%d", keysym); | ||
| 63 | return value; | ||
| 64 | } | ||
| 65 | |||
| 66 | static struct frame * | ||
| 67 | haiku_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 | |||
| 87 | static void | ||
| 88 | haiku_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 | |||
| 101 | static void | ||
| 102 | haiku_delete_terminal (struct terminal *terminal) | ||
| 103 | { | ||
| 104 | emacs_abort (); | ||
| 105 | } | ||
| 106 | |||
| 107 | static const char * | ||
| 108 | get_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 | |||
| 121 | static void | ||
| 122 | haiku_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 | |||
| 141 | static void | ||
| 142 | haiku_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 | |||
| 159 | static void | ||
| 160 | haiku_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 | |||
| 167 | static void | ||
| 168 | haiku_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 | |||
| 181 | static void | ||
| 182 | haiku_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 | |||
| 191 | static void | ||
| 192 | haiku_buffer_flipping_unblocked_hook (struct frame *f) | ||
| 193 | { | ||
| 194 | if (FRAME_DIRTY_P (f)) | ||
| 195 | haiku_flip_buffers (f); | ||
| 196 | } | ||
| 197 | |||
| 198 | static void | ||
| 199 | haiku_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 | |||
| 214 | static void | ||
| 215 | haiku_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 | |||
| 236 | static Lisp_Object | ||
| 237 | haiku_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 | |||
| 274 | static int | ||
| 275 | haiku_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 | |||
| 283 | static void | ||
| 284 | haiku_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 | |||
| 293 | static int | ||
| 294 | haiku_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 | |||
| 310 | static void | ||
| 311 | haiku_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 | |||
| 342 | static void | ||
| 343 | haiku_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. */ | ||
| 355 | static void | ||
| 356 | haiku_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 | |||
| 362 | static void | ||
| 363 | haiku_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 | |||
| 384 | static void | ||
| 385 | haiku_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | ||
| 386 | { | ||
| 387 | haiku_set_name (f, arg, 0); | ||
| 388 | } | ||
| 389 | |||
| 390 | static void | ||
| 391 | haiku_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) | ||
| 392 | { | ||
| 393 | haiku_query_color (FRAME_BACKGROUND_PIXEL (f), bgcolor); | ||
| 394 | } | ||
| 395 | |||
| 396 | static bool | ||
| 397 | haiku_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'. */ | ||
| 407 | static void | ||
| 408 | haiku_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 | |||
| 432 | static void | ||
| 433 | haiku_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 | |||
| 455 | static void | ||
| 456 | haiku_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 | |||
| 538 | static void | ||
| 539 | haiku_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 | |||
| 617 | static void | ||
| 618 | haiku_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 | |||
| 637 | static void | ||
| 638 | haiku_draw_stipple_background (struct glyph_string *s, struct face *face, | ||
| 639 | int box_line_hwidth, int box_line_vwidth) | ||
| 640 | { | ||
| 641 | } | ||
| 642 | |||
| 643 | static void | ||
| 644 | haiku_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 | |||
| 667 | static void | ||
| 668 | haiku_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 | |||
| 694 | static void | ||
| 695 | haiku_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 | |||
| 730 | static void | ||
| 731 | haiku_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 | |||
| 878 | static void | ||
| 879 | haiku_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 | |||
| 927 | static void | ||
| 928 | haiku_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 | |||
| 1008 | static void | ||
| 1009 | haiku_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 | |||
| 1111 | static void | ||
| 1112 | haiku_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 | |||
| 1119 | static void | ||
| 1120 | haiku_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 | |||
| 1127 | static void | ||
| 1128 | haiku_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 | |||
| 1146 | static void | ||
| 1147 | haiku_update_begin (struct frame *f) | ||
| 1148 | { | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static void | ||
| 1152 | haiku_update_end (struct frame *f) | ||
| 1153 | { | ||
| 1154 | MOUSE_HL_INFO (f)->mouse_face_defer = false; | ||
| 1155 | flush_frame (f); | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | static void | ||
| 1159 | haiku_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 | |||
| 1253 | static void | ||
| 1254 | haiku_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 | |||
| 1345 | static void | ||
| 1346 | haiku_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 | |||
| 1471 | static void | ||
| 1472 | haiku_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 | |||
| 1632 | static void | ||
| 1633 | haiku_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 | |||
| 1682 | static void | ||
| 1683 | haiku_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 | |||
| 1696 | static void | ||
| 1697 | haiku_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 | |||
| 1794 | static void | ||
| 1795 | haiku_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 | |||
| 1809 | static void | ||
| 1810 | haiku_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 | |||
| 1824 | static void | ||
| 1825 | haiku_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 | |||
| 1855 | static void | ||
| 1856 | haiku_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 | |||
| 1873 | static void | ||
| 1874 | haiku_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 | |||
| 1882 | static void | ||
| 1883 | haiku_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 | |||
| 1891 | static void | ||
| 1892 | haiku_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 | |||
| 1943 | static void | ||
| 1944 | haiku_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 | |||
| 1965 | static void | ||
| 1966 | haiku_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 | |||
| 2041 | static void | ||
| 2042 | haiku_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 | |||
| 2066 | static struct scroll_bar * | ||
| 2067 | haiku_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 | |||
| 2110 | static void | ||
| 2111 | haiku_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 | |||
| 2168 | static void | ||
| 2169 | haiku_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 | |||
| 2231 | static void | ||
| 2232 | haiku_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 | |||
| 2274 | static void | ||
| 2275 | haiku_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 | |||
| 2293 | static void | ||
| 2294 | haiku_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 | |||
| 2304 | static void | ||
| 2305 | haiku_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 | |||
| 2384 | static void | ||
| 2385 | haiku_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 | |||
| 2439 | static void | ||
| 2440 | haiku_flush (struct frame *f) | ||
| 2441 | { | ||
| 2442 | if (FRAME_VISIBLE_P (f)) | ||
| 2443 | BWindow_Flush (FRAME_HAIKU_WINDOW (f)); | ||
| 2444 | } | ||
| 2445 | |||
| 2446 | static void | ||
| 2447 | haiku_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 | |||
| 2459 | static void | ||
| 2460 | haiku_update_window_end (struct window *w, bool cursor_on_p, | ||
| 2461 | bool mouse_face_overwritten_p) | ||
| 2462 | { | ||
| 2463 | |||
| 2464 | } | ||
| 2465 | |||
| 2466 | static void | ||
| 2467 | haiku_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 | |||
| 2528 | static 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 | |||
| 2560 | static void | ||
| 2561 | haiku_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 | |||
| 2573 | static int | ||
| 2574 | haiku_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 | |||
| 3214 | static void | ||
| 3215 | haiku_frame_rehighlight (struct frame *frame) | ||
| 3216 | { | ||
| 3217 | haiku_rehighlight (); | ||
| 3218 | } | ||
| 3219 | |||
| 3220 | static void | ||
| 3221 | haiku_delete_window (struct frame *f) | ||
| 3222 | { | ||
| 3223 | check_window_system (f); | ||
| 3224 | haiku_free_frame_resources (f); | ||
| 3225 | } | ||
| 3226 | |||
| 3227 | static void | ||
| 3228 | haiku_free_pixmap (struct frame *f, Emacs_Pixmap pixmap) | ||
| 3229 | { | ||
| 3230 | BBitmap_free (pixmap); | ||
| 3231 | } | ||
| 3232 | |||
| 3233 | static void | ||
| 3234 | haiku_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 | |||
| 3264 | static void | ||
| 3265 | haiku_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 | |||
| 3280 | static void | ||
| 3281 | haiku_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 | |||
| 3301 | static struct terminal * | ||
| 3302 | haiku_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 | |||
| 3352 | struct haiku_display_info * | ||
| 3353 | haiku_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 | |||
| 3409 | void | ||
| 3410 | put_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 | |||
| 3422 | void | ||
| 3423 | haiku_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 | |||
| 3463 | void | ||
| 3464 | mark_haiku_display (void) | ||
| 3465 | { | ||
| 3466 | if (x_display_list) | ||
| 3467 | mark_object (x_display_list->color_map); | ||
| 3468 | } | ||
| 3469 | |||
| 3470 | void | ||
| 3471 | haiku_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 | |||
| 3488 | void | ||
| 3489 | haiku_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 | ||
| 3513 | cairo_t * | ||
| 3514 | haiku_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 | |||
| 3524 | void | ||
| 3525 | haiku_end_cr_clip (cairo_t *cr) | ||
| 3526 | { | ||
| 3527 | cairo_destroy (cr); | ||
| 3528 | } | ||
| 3529 | #endif | ||
| 3530 | |||
| 3531 | void | ||
| 3532 | syms_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. | ||
| 3562 | This is either one of the symbols `shift', `control', `command', and | ||
| 3563 | `option', or nil, in which case it is treated as `command'. | ||
| 3564 | |||
| 3565 | Setting 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. | ||
| 3570 | This is either one of the symbols `shift', `control', `command', and | ||
| 3571 | `option', or nil, in which case it is treated as `control'. | ||
| 3572 | |||
| 3573 | Setting 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. | ||
| 3578 | This is either one of the symbols `shift', `control', `command', and | ||
| 3579 | `option', or nil, in which case it is treated as `option'. | ||
| 3580 | |||
| 3581 | Setting 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. | ||
| 3586 | This is either one of the symbols `shift', `control', `command', and | ||
| 3587 | `option', or nil, in which case it is treated as `shift'. | ||
| 3588 | |||
| 3589 | Setting 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 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along 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 | |||
| 40 | extern int popup_activated_p; | ||
| 41 | |||
| 42 | extern void be_app_quit (void); | ||
| 43 | |||
| 44 | struct 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 | |||
| 54 | struct haiku_bitmap_record | ||
| 55 | { | ||
| 56 | haiku img; | ||
| 57 | char *file; | ||
| 58 | int refcount; | ||
| 59 | int height, width, depth; | ||
| 60 | }; | ||
| 61 | |||
| 62 | struct 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 | |||
| 112 | struct 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 | |||
| 170 | struct x_output | ||
| 171 | { | ||
| 172 | /* Unused, makes term.c happy. */ | ||
| 173 | }; | ||
| 174 | |||
| 175 | extern struct haiku_display_info *x_display_list; | ||
| 176 | extern struct font_driver const haikufont_driver; | ||
| 177 | |||
| 178 | struct 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 | |||
| 236 | extern void syms_of_haikuterm (void); | ||
| 237 | extern void syms_of_haikufns (void); | ||
| 238 | extern void syms_of_haikumenu (void); | ||
| 239 | extern void syms_of_haikufont (void); | ||
| 240 | extern void syms_of_haikuselect (void); | ||
| 241 | extern void init_haiku_select (void); | ||
| 242 | |||
| 243 | extern void haiku_iconify_frame (struct frame *); | ||
| 244 | extern void haiku_visualize_frame (struct frame *); | ||
| 245 | extern void haiku_unvisualize_frame (struct frame *); | ||
| 246 | extern void haiku_set_offset (struct frame *, int, int, int); | ||
| 247 | extern void haiku_set_frame_visible_invisible (struct frame *, bool); | ||
| 248 | extern void haiku_free_frame_resources (struct frame *f); | ||
| 249 | extern void haiku_scroll_bar_remove (struct scroll_bar *bar); | ||
| 250 | extern void haiku_clear_under_internal_border (struct frame *f); | ||
| 251 | extern void haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p); | ||
| 252 | |||
| 253 | extern struct haiku_display_info *haiku_term_init (void); | ||
| 254 | |||
| 255 | extern void mark_haiku_display (void); | ||
| 256 | |||
| 257 | extern int haiku_get_color (const char *name, Emacs_Color *color); | ||
| 258 | extern void haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval); | ||
| 259 | extern void haiku_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval); | ||
| 260 | extern void haiku_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval); | ||
| 261 | extern void haiku_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval); | ||
| 262 | extern void haiku_change_tab_bar_height (struct frame *f, int height); | ||
| 263 | extern void haiku_change_tool_bar_height (struct frame *f, int height); | ||
| 264 | |||
| 265 | extern void haiku_query_color (uint32_t col, Emacs_Color *color); | ||
| 266 | |||
| 267 | extern unsigned long haiku_get_pixel (haiku bitmap, int x, int y); | ||
| 268 | extern void haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel); | ||
| 269 | |||
| 270 | extern Lisp_Object haiku_menu_show (struct frame *f, int x, int y, int menu_flags, | ||
| 271 | Lisp_Object title, const char **error_name); | ||
| 272 | extern Lisp_Object haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents); | ||
| 273 | |||
| 274 | extern void initialize_frame_menubar (struct frame *f); | ||
| 275 | |||
| 276 | extern void run_menu_bar_help_event (struct frame *f, int mb_idx); | ||
| 277 | extern void put_xrm_resource (Lisp_Object name, Lisp_Object val); | ||
| 278 | |||
| 279 | #ifdef HAVE_NATIVE_IMAGE_API | ||
| 280 | extern bool haiku_can_use_native_image_api (Lisp_Object type); | ||
| 281 | extern int haiku_load_image (struct frame *f, struct image *img, | ||
| 282 | Lisp_Object spec_file, Lisp_Object spec_data); | ||
| 283 | extern void syms_of_haikuimage (void); | ||
| 284 | #endif | ||
| 285 | |||
| 286 | #ifdef USE_BE_CAIRO | ||
| 287 | extern cairo_t * | ||
| 288 | haiku_begin_cr_clip (struct frame *f, struct glyph_string *s); | ||
| 289 | |||
| 290 | extern void | ||
| 291 | haiku_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" | ||
| 141 | typedef 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 | |||
| 138 | static void image_disable_image (struct frame *, struct image *); | 160 | static void image_disable_image (struct frame *, struct image *); |
| 139 | static void image_edge_detection (struct frame *, struct image *, Lisp_Object, | 161 | static 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, | |||
| 465 | ptrdiff_t | 497 | ptrdiff_t |
| 466 | image_create_bitmap_from_file (struct frame *f, Lisp_Object file) | 498 | image_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 | ||
| 2176 | typedef double matrix3x3[3][3]; | 2218 | typedef double matrix3x3[3][3]; |
| 2177 | 2219 | ||
| 2178 | static void | 2220 | static 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 | ||
| 2191 | static void | 2234 | static void |
| 2192 | compute_image_rotation (struct image *img, double *rotation) | 2235 | compute_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 | |||
| 2960 | gui_put_x_image (struct frame *f, Emacs_Pix_Container pimg, | 3056 | gui_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, | |||
| 3087 | static Emacs_Pix_Container | 3183 | static Emacs_Pix_Container |
| 3088 | image_get_x_image (struct frame *f, struct image *img, bool mask_p) | 3184 | image_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 |
| 4342 | ptrdiff_t | 4438 | ptrdiff_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 | ||
| 4713 | static void xpm_put_color_table_v (Lisp_Object, const char *, | 4810 | static 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 | ||
| 7252 | void | 7251 | void |
| 7253 | handle_input_available_signal (int sig) | 7252 | handle_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); | |||
| 4429 | extern Lisp_Object tab_bar_items (Lisp_Object, int *); | 4437 | extern Lisp_Object tab_bar_items (Lisp_Object, int *); |
| 4430 | extern Lisp_Object tool_bar_items (Lisp_Object, int *); | 4438 | extern Lisp_Object tool_bar_items (Lisp_Object, int *); |
| 4431 | extern void discard_mouse_events (void); | 4439 | extern void discard_mouse_events (void); |
| 4432 | #ifdef USABLE_SIGIO | 4440 | #if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) |
| 4433 | void handle_input_available_signal (int); | 4441 | void handle_input_available_signal (int); |
| 4434 | #endif | 4442 | #endif |
| 4435 | extern Lisp_Object pending_funcalls; | 4443 | extern 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; | |||
| 50 | static bool | 50 | static bool |
| 51 | have_boxes (void) | 51 | have_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 | ||
| 260 | static void start_process_unwind (Lisp_Object); | 260 | static void start_process_unwind (Lisp_Object); |
| 261 | static void create_process (Lisp_Object, char **, Lisp_Object); | 261 | static void create_process (Lisp_Object, char **, Lisp_Object); |
| 262 | #ifdef USABLE_SIGIO | 262 | #if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) |
| 263 | static bool keyboard_bit_set (fd_set *); | 263 | static bool keyboard_bit_set (fd_set *); |
| 264 | #endif | 264 | #endif |
| 265 | static void deactivate_process (Lisp_Object); | 265 | static 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 | |||
| 698 | vox_configure (struct sound_device *sd) | 702 | vox_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 | ||
| 791 | static void | 795 | static void |
| 792 | reset_sigio (int fd) | 796 | reset_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 | ||
| 800 | void | 805 | void |
| 801 | request_sigio (void) | 806 | request_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) | |||
| 820 | void | 829 | void |
| 821 | unrequest_sigio (void) | 830 | unrequest_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 | ||
| 3126 | Lisp_Object | 3147 | Lisp_Object |
| 3127 | list_system_processes (void) | 3148 | list_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 | ||
| 4206 | Lisp_Object | 4228 | Lisp_Object |
| 4207 | system_process_attributes (Lisp_Object pid) | 4229 | system_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 | ||
| 840 | extern struct terminal *decode_live_terminal (Lisp_Object); | 844 | extern 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) | |||
| 23 | AM_V_AR = | 23 | AM_V_AR = |
| 24 | AM_V_at = | 24 | AM_V_at = |
| 25 | AM_V_CC = | 25 | AM_V_CC = |
| 26 | AM_V_CXX = | ||
| 26 | AM_V_CCLD = | 27 | AM_V_CCLD = |
| 28 | AM_V_CXXLD = | ||
| 27 | AM_V_ELC = | 29 | AM_V_ELC = |
| 28 | AM_V_ELN = | 30 | AM_V_ELN = |
| 29 | AM_V_GEN = | 31 | AM_V_GEN = |
| @@ -34,7 +36,9 @@ else | |||
| 34 | AM_V_AR = @echo " AR " $@; | 36 | AM_V_AR = @echo " AR " $@; |
| 35 | AM_V_at = @ | 37 | AM_V_at = @ |
| 36 | AM_V_CC = @echo " CC " $@; | 38 | AM_V_CC = @echo " CC " $@; |
| 39 | AM_V_CXX = @echo " CXX " $@; | ||
| 37 | AM_V_CCLD = @echo " CCLD " $@; | 40 | AM_V_CCLD = @echo " CCLD " $@; |
| 41 | AM_V_CXXLD = @echo " CXXLD " $@; | ||
| 38 | ifeq ($(HAVE_NATIVE_COMP),yes) | 42 | ifeq ($(HAVE_NATIVE_COMP),yes) |
| 39 | ifeq ($(NATIVE_DISABLED),1) | 43 | ifeq ($(NATIVE_DISABLED),1) |
| 40 | AM_V_ELC = @echo " ELC " $@; | 44 | AM_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 | ||
| 561 | static Emacs_GC * | 565 | static Emacs_GC * |
| 562 | x_create_gc (struct frame *f, | 566 | x_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 | |||
| 4461 | Protocol used on TERMINAL and the 3rd number is the distributor-specific | 4461 | Protocol used on TERMINAL and the 3rd number is the distributor-specific |
| 4462 | release number. For MS Windows, the 3 numbers report the OS major and | 4462 | release number. For MS Windows, the 3 numbers report the OS major and |
| 4463 | minor version and build number. For Nextstep, the first 2 numbers are | 4463 | minor version and build number. For Nextstep, the first 2 numbers are |
| 4464 | hard-coded and the 3rd represents the OS version. | 4464 | hard-coded and the 3rd represents the OS version. For Haiku, all 3 |
| 4465 | numbers are hard-coded. | ||
| 4465 | 4466 | ||
| 4466 | See also the function `x-server-vendor'. | 4467 | See 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 | |||
| 7419 | selection box, if specified. If MUSTMATCH is non-nil, the returned file | 7420 | selection box, if specified. If MUSTMATCH is non-nil, the returned file |
| 7420 | or directory must exist. | 7421 | or directory must exist. |
| 7421 | 7422 | ||
| 7422 | This function is defined only on NS, MS Windows, and X Windows with the | 7423 | This function is defined only on NS, Haiku, MS Windows, and X Windows with the |
| 7423 | Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored. | 7424 | Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored. |
| 7424 | Otherwise, if ONLY-DIR-P is non-nil, the user can select only directories. | 7425 | Otherwise, if ONLY-DIR-P is non-nil, the user can select only directories. |
| 7425 | On MS Windows 7 and later, the file selection dialog "remembers" the last | 7426 | On 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. */); | |||
| 14959 | A value of nil means Emacs doesn't use toolkit scroll bars. | 14959 | A value of nil means Emacs doesn't use toolkit scroll bars. |
| 14960 | With the X Window system, the value is a symbol describing the | 14960 | With the X Window system, the value is a symbol describing the |
| 14961 | X toolkit. Possible values are: gtk, motif, xaw, or xaw3d. | 14961 | X toolkit. Possible values are: gtk, motif, xaw, or xaw3d. |
| 14962 | With MS Windows or Nextstep, the value is t. */); | 14962 | With 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"); |