diff options
author | Po Lu <luangruo@yahoo.com> | 2021-11-20 21:30:08 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2021-11-20 21:46:07 +0800 |
commit | 85a078e7853d708e599f97a3de06aed3a1c090ea (patch) | |
tree | 082931cb8ad6b276d8eaafeda685c368e0510f05 /src/haikumenu.c | |
parent | bfcc59371ba74e53c5ce1ba93bcddf9a9aa64230 (diff) | |
download | emacs-85a078e7853d708e599f97a3de06aed3a1c090ea.tar.gz |
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/haikumenu.c')
-rw-r--r-- | src/haikumenu.c | 656 |
1 files changed, 656 insertions, 0 deletions
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 @@ +/* Haiku window system support + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "lisp.h" +#include "frame.h" +#include "keyboard.h" +#include "menu.h" +#include "buffer.h" +#include "blockinput.h" + +#include "haikuterm.h" +#include "haiku_support.h" + +static Lisp_Object *volatile menu_item_selection; + +int popup_activated_p = 0; + +struct submenu_stack_cell +{ + void *parent_menu; + void *pane; +}; + +static void +digest_menu_items (void *first_menu, int start, int menu_items_used, + int mbar_p) +{ + void **menus, **panes; + ssize_t menu_len = (menu_items_used + 1 - start) * sizeof *menus; + ssize_t pane_len = (menu_items_used + 1 - start) * sizeof *panes; + + menus = alloca (menu_len); + panes = alloca (pane_len); + + int i = start, menu_depth = 0; + + memset (menus, 0, menu_len); + memset (panes, 0, pane_len); + + void *menu = first_menu; + + menus[0] = first_menu; + + void *window = NULL; + if (FRAMEP (Vmenu_updating_frame) && + FRAME_LIVE_P (XFRAME (Vmenu_updating_frame)) && + FRAME_HAIKU_P (XFRAME (Vmenu_updating_frame))) + window = FRAME_HAIKU_WINDOW (XFRAME (Vmenu_updating_frame)); + + while (i < menu_items_used) + { + if (NILP (AREF (menu_items, i))) + { + menus[++menu_depth] = menu; + i++; + } + else if (EQ (AREF (menu_items, i), Qlambda)) + { + panes[menu_depth] = NULL; + menu = panes[--menu_depth] ? panes[menu_depth] : menus[menu_depth]; + i++; + } + else if (EQ (AREF (menu_items, i), Qquote)) + i += 1; + else if (EQ (AREF (menu_items, i), Qt)) + { + Lisp_Object pane_name, prefix; + const char *pane_string; + + if (menu_items_n_panes == 1) + { + i += MENU_ITEMS_PANE_LENGTH; + continue; + } + + pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); + prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); + + if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) + { + pane_name = ENCODE_UTF_8 (pane_name); + ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); + } + + pane_string = (NILP (pane_name) + ? "" : SSDATA (pane_name)); + if (!NILP (prefix)) + pane_string++; + + if (strcmp (pane_string, "")) + { + panes[menu_depth] = + menu = BMenu_new_submenu (menus[menu_depth], pane_string, 1); + } + + i += MENU_ITEMS_PANE_LENGTH; + } + else + { + Lisp_Object item_name, enable, descrip, def, selected, help; + item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); + enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); + descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); + def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); + selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); + help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); + + if (STRINGP (item_name) && STRING_MULTIBYTE (item_name)) + { + item_name = ENCODE_UTF_8 (item_name); + ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); + } + + if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) + { + descrip = ENCODE_UTF_8 (descrip); + ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); + } + + if (STRINGP (help) && STRING_MULTIBYTE (help)) + { + help = ENCODE_UTF_8 (help); + ASET (menu_items, i + MENU_ITEMS_ITEM_HELP, help); + } + + if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used && + NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH))) + menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable)); + else if (NILP (def) && menu_separator_name_p (SSDATA (item_name))) + BMenu_add_separator (menu); + else if (!mbar_p) + BMenu_add_item (menu, SSDATA (item_name), + !NILP (def) ? aref_addr (menu_items, i) : NULL, + !NILP (enable), !NILP (selected), 0, window, + !NILP (descrip) ? SSDATA (descrip) : NULL, + STRINGP (help) ? SSDATA (help) : NULL); + else + BMenu_add_item (menu, SSDATA (item_name), + !NILP (def) ? (void *) (intptr_t) i : NULL, + !NILP (enable), !NILP (selected), 1, window, + !NILP (descrip) ? SSDATA (descrip) : NULL, + STRINGP (help) ? SSDATA (help) : NULL); + + i += MENU_ITEMS_ITEM_LENGTH; + } + } +} + +static Lisp_Object +haiku_dialog_show (struct frame *f, Lisp_Object title, + Lisp_Object header, const char **error_name) +{ + int i, nb_buttons = 0; + + *error_name = NULL; + + if (menu_items_n_panes > 1) + { + *error_name = "Multiple panes in dialog box"; + return Qnil; + } + + Lisp_Object pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME); + i = MENU_ITEMS_PANE_LENGTH; + + if (STRING_MULTIBYTE (pane_name)) + pane_name = ENCODE_UTF_8 (pane_name); + + block_input (); + void *alert = BAlert_new (SSDATA (pane_name), NILP (header) ? HAIKU_INFO_ALERT : + HAIKU_IDEA_ALERT); + + Lisp_Object vals[10]; + + while (i < menu_items_used) + { + Lisp_Object item_name, enable, descrip, value; + item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); + enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); + descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); + value = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + + if (NILP (item_name)) + { + BAlert_delete (alert); + *error_name = "Submenu in dialog items"; + unblock_input (); + return Qnil; + } + + if (EQ (item_name, Qquote)) + { + i++; + } + + if (nb_buttons >= 9) + { + BAlert_delete (alert); + *error_name = "Too many dialog items"; + unblock_input (); + return Qnil; + } + + if (STRING_MULTIBYTE (item_name)) + item_name = ENCODE_UTF_8 (item_name); + if (!NILP (descrip) && STRING_MULTIBYTE (descrip)) + descrip = ENCODE_UTF_8 (descrip); + + void *button = BAlert_add_button (alert, SSDATA (item_name)); + + BButton_set_enabled (button, !NILP (enable)); + if (!NILP (descrip)) + BView_set_tooltip (button, SSDATA (descrip)); + + vals[nb_buttons] = value; + ++nb_buttons; + i += MENU_ITEMS_ITEM_LENGTH; + } + + int32_t val = BAlert_go (alert); + unblock_input (); + + if (val < 0) + quit (); + else + return vals[val]; + + return Qnil; +} + +Lisp_Object +haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) +{ + Lisp_Object title; + const char *error_name = NULL; + Lisp_Object selection; + ptrdiff_t specpdl_count = SPECPDL_INDEX (); + + check_window_system (f); + + /* Decode the dialog items from what was specified. */ + title = Fcar (contents); + CHECK_STRING (title); + record_unwind_protect_void (unuse_menu_items); + + if (NILP (Fcar (Fcdr (contents)))) + /* No buttons specified, add an "Ok" button so users can pop down + the dialog. Also, the lesstif/motif version crashes if there are + no buttons. */ + contents = list2 (title, Fcons (build_string ("Ok"), Qt)); + + list_of_panes (list1 (contents)); + + /* Display them in a dialog box. */ + block_input (); + selection = haiku_dialog_show (f, title, header, &error_name); + unblock_input (); + + unbind_to (specpdl_count, Qnil); + discard_menu_items (); + + if (error_name) + error ("%s", error_name); + return selection; +} + +Lisp_Object +haiku_menu_show (struct frame *f, int x, int y, int menuflags, + Lisp_Object title, const char **error_name) +{ + int i = 0, submenu_depth = 0; + void *view = FRAME_HAIKU_VIEW (f); + void *menu; + + Lisp_Object *subprefix_stack = + alloca (menu_items_used * sizeof (Lisp_Object)); + + eassert (FRAME_HAIKU_P (f)); + + *error_name = NULL; + + if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) + { + *error_name = "Empty menu"; + return Qnil; + } + + block_input (); + if (STRINGP (title) && STRING_MULTIBYTE (title)) + title = ENCODE_UTF_8 (title); + + menu = BPopUpMenu_new (STRINGP (title) ? SSDATA (title) : NULL); + if (STRINGP (title)) + { + BMenu_add_title (menu, SSDATA (title)); + BMenu_add_separator (menu); + } + digest_menu_items (menu, 0, menu_items_used, 0); + BView_convert_to_screen (view, &x, &y); + unblock_input (); + + menu_item_selection = BMenu_run (menu, x, y); + + FRAME_DISPLAY_INFO (f)->grabbed = 0; + + if (menu_item_selection) + { + Lisp_Object prefix, entry; + + prefix = entry = Qnil; + i = 0; + while (i < menu_items_used) + { + if (NILP (AREF (menu_items, i))) + { + subprefix_stack[submenu_depth++] = prefix; + prefix = entry; + i++; + } + else if (EQ (AREF (menu_items, i), Qlambda)) + { + prefix = subprefix_stack[--submenu_depth]; + i++; + } + else if (EQ (AREF (menu_items, i), Qt)) + { + prefix + = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); + i += MENU_ITEMS_PANE_LENGTH; + } + /* Ignore a nil in the item list. + It's meaningful only for dialog boxes. */ + else if (EQ (AREF (menu_items, i), Qquote)) + i += 1; + else + { + entry + = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + if (menu_item_selection == aref_addr (menu_items, i)) + { + if (menuflags & MENU_KEYMAPS) + { + int j; + + entry = list1 (entry); + if (!NILP (prefix)) + entry = Fcons (prefix, entry); + for (j = submenu_depth - 1; j >= 0; j--) + if (!NILP (subprefix_stack[j])) + entry = Fcons (subprefix_stack[j], entry); + } + BPopUpMenu_delete (menu); + return entry; + } + i += MENU_ITEMS_ITEM_LENGTH; + } + } + } + else if (!(menuflags & MENU_FOR_CLICK)) + { + BPopUpMenu_delete (menu); + quit (); + } + BPopUpMenu_delete (menu); + return Qnil; +} + +void +free_frame_menubar (struct frame *f) +{ + FRAME_MENU_BAR_LINES (f) = 0; + FRAME_MENU_BAR_HEIGHT (f) = 0; + FRAME_EXTERNAL_MENU_BAR (f) = 0; + + block_input (); + void *mbar = FRAME_HAIKU_MENU_BAR (f); + if (mbar) + BMenuBar_delete (mbar); + if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p) + --popup_activated_p; + FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0; + unblock_input (); + + adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines); +} + +void +initialize_frame_menubar (struct frame *f) +{ + /* This function is called before the first chance to redisplay + the frame. It has to be, so the frame will have the right size. */ + fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); + set_frame_menubar (f, true); +} + +void +set_frame_menubar (struct frame *f, bool deep_p) +{ + void *mbar = FRAME_HAIKU_MENU_BAR (f); + void *view = FRAME_HAIKU_VIEW (f); + + int first_time_p = 0; + + if (!mbar) + { + mbar = FRAME_HAIKU_MENU_BAR (f) = BMenuBar_new (view); + first_time_p = 1; + } + + Lisp_Object items; + struct buffer *prev = current_buffer; + Lisp_Object buffer; + ptrdiff_t specpdl_count = SPECPDL_INDEX (); + int previous_menu_items_used = f->menu_bar_items_used; + Lisp_Object *previous_items + = alloca (previous_menu_items_used * sizeof *previous_items); + + XSETFRAME (Vmenu_updating_frame, f); + + if (!deep_p) + { + FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 0; + items = FRAME_MENU_BAR_ITEMS (f); + Lisp_Object string; + + block_input (); + int count = BMenu_count_items (mbar); + + int i; + for (i = 0; i < ASIZE (items); i += 4) + { + string = AREF (items, i + 1); + + if (!STRINGP (string)) + break; + + if (STRING_MULTIBYTE (string)) + string = ENCODE_UTF_8 (string); + + if (i / 4 < count) + { + void *it = BMenu_item_at (mbar, i / 4); + BMenu_item_set_label (it, SSDATA (string)); + } + else + BMenu_new_menu_bar_submenu (mbar, SSDATA (string)); + } + + if (i / 4 < count) + BMenu_delete_from (mbar, i / 4, count - i / 4 + 1); + unblock_input (); + + f->menu_bar_items_used = 0; + } + else + { + /* If we are making a new widget, its contents are empty, + do always reinitialize them. */ + if (first_time_p) + previous_menu_items_used = 0; + buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents; + specbind (Qinhibit_quit, Qt); + /* Don't let the debugger step into this code + because it is not reentrant. */ + specbind (Qdebug_on_next_call, Qnil); + + record_unwind_save_match_data (); + if (NILP (Voverriding_local_map_menu_flag)) + { + specbind (Qoverriding_terminal_local_map, Qnil); + specbind (Qoverriding_local_map, Qnil); + } + + set_buffer_internal_1 (XBUFFER (buffer)); + + /* Run the Lucid hook. */ + safe_run_hooks (Qactivate_menubar_hook); + + /* If it has changed current-menubar from previous value, + really recompute the menubar from the value. */ + if (! NILP (Vlucid_menu_bar_dirty_flag)) + call0 (Qrecompute_lucid_menubar); + safe_run_hooks (Qmenu_bar_update_hook); + fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); + + items = FRAME_MENU_BAR_ITEMS (f); + + /* Save the frame's previous menu bar contents data. */ + if (previous_menu_items_used) + memcpy (previous_items, xvector_contents (f->menu_bar_vector), + previous_menu_items_used * word_size); + + /* Fill in menu_items with the current menu bar contents. + This can evaluate Lisp code. */ + save_menu_items (); + menu_items = f->menu_bar_vector; + menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; + init_menu_items (); + int i; + int count = BMenu_count_items (mbar); + int subitems = ASIZE (items) / 4; + + int *submenu_start, *submenu_end, *submenu_n_panes; + Lisp_Object *submenu_names; + + submenu_start = alloca ((subitems + 1) * sizeof *submenu_start); + submenu_end = alloca (subitems * sizeof *submenu_end); + submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes); + submenu_names = alloca (subitems * sizeof (Lisp_Object)); + + for (i = 0; i < subitems; ++i) + { + Lisp_Object key, string, maps; + + key = AREF (items, i * 4); + string = AREF (items, i * 4 + 1); + maps = AREF (items, i * 4 + 2); + + if (NILP (string)) + break; + + if (STRINGP (string) && STRING_MULTIBYTE (string)) + string = ENCODE_UTF_8 (string); + + submenu_start[i] = menu_items_used; + menu_items_n_panes = 0; + parse_single_submenu (key, string, maps); + submenu_n_panes[i] = menu_items_n_panes; + submenu_end[i] = menu_items_used; + submenu_names[i] = string; + } + finish_menu_items (); + submenu_start[i] = -1; + + block_input (); + for (i = 0; submenu_start[i] >= 0; ++i) + { + void *mn = NULL; + if (i < count) + mn = BMenu_item_get_menu (BMenu_item_at (mbar, i)); + if (mn) + BMenu_delete_all (mn); + else + mn = BMenu_new_menu_bar_submenu (mbar, SSDATA (submenu_names[i])); + + menu_items_n_panes = submenu_n_panes[i]; + digest_menu_items (mn, submenu_start[i], submenu_end[i], 1); + } + unblock_input (); + + set_buffer_internal_1 (prev); + + FRAME_OUTPUT_DATA (f)->menu_up_to_date_p = 1; + fset_menu_bar_vector (f, menu_items); + f->menu_bar_items_used = menu_items_used; + } + unbind_to (specpdl_count, Qnil); +} + +void +run_menu_bar_help_event (struct frame *f, int mb_idx) +{ + Lisp_Object frame; + Lisp_Object vec; + Lisp_Object help; + + block_input (); + if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p) + { + unblock_input (); + return; + } + + XSETFRAME (frame, f); + + if (mb_idx < 0) + { + kbd_buffer_store_help_event (frame, Qnil); + unblock_input (); + return; + } + + vec = f->menu_bar_vector; + if (mb_idx >= ASIZE (vec)) + emacs_abort (); + + help = AREF (vec, mb_idx + MENU_ITEMS_ITEM_HELP); + if (STRINGP (help) || NILP (help)) + kbd_buffer_store_help_event (frame, help); + unblock_input (); +} + +DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, + 0, 0, 0, doc: /* SKIP: real doc in xmenu.c. */) + (void) +{ + return popup_activated_p ? Qt : Qnil; +} + +DEFUN ("haiku-menu-bar-open", Fhaiku_menu_bar_open, Shaiku_menu_bar_open, 0, 1, "i", + doc: /* Show the menu bar in FRAME. + +Move the mouse pointer onto the first element of FRAME's menu bar, and +cause it to be opened. If FRAME is nil or not given, use the selected +frame. If FRAME has no menu bar, a pop-up is displayed at the position +of the last non-menu event instead. */) + (Lisp_Object frame) +{ + struct frame *f = decode_window_system_frame (frame); + + if (FRAME_EXTERNAL_MENU_BAR (f)) + { + if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p) + set_frame_menubar (f, 1); + } + else + { + return call2 (Qpopup_menu, call0 (Qmouse_menu_bar_map), + last_nonmenu_event); + } + + block_input (); + BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f)); + unblock_input (); + + return Qnil; +} + +void +syms_of_haikumenu (void) +{ + DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); + DEFSYM (Qpopup_menu, "popup-menu"); + DEFSYM (Qmouse_menu_bar_map, "mouse-menu-bar-map"); + + defsubr (&Smenu_or_popup_active_p); + defsubr (&Shaiku_menu_bar_open); + return; +} |