Files
emacs/src/haikumenu.c
Po Lu 85a078e785 Add support for the Haiku operating system and its window system
* .gitignore: Add binaries specific to Haiku.

* Makefie.in (HAVE_BE_APP): New variable.
(install-arch-dep): Install Emacs and Emacs.pdmp when
using Haiku.

* configure.ac: Detect and configure for Haiku and
various related configurations.
(be-app, be-freetype, be-cairo): New options.
(HAVE_BE_APP, HAIKU_OBJ, HAIKU_CXX_OBJ)
(HAIKU_LIBS, HAIKU_CFLAGS): New variables.
(HAIKU, HAVE_TINY_SPEED_T): New define.
(emacs_config_features): Add BE_APP.

* doc/emacs/Makefile.in (EMACSSOURCES): Add Haiku
appendix.

* doc/emacs/emacs.texi: Add Haiku appendix to menus and
include it.

* doc/emacs/haiku.texi: New Haiku appendix.

* doc/lispref/display.texi (Defining Faces, Window Systems):
Explain meaning of `haiku' as a window system identifier.
(haiku-use-system-tooltips): Explain meaning of system
tooltips on
Haiku.

* doc/lispref/frames.texi (Multiple Terminals): Explain
meaning of haiku as a display type.
(Frame Layout): Clarify section for Haiku frames.
(Size Parameters): Explain limitations of fullwidth and
fullheight on Haiku.
(Management Parameters): Explain limitations of
inhibiting double buffering on builds with Cairo,
and the inability of frames with no-accept-focus to
receive keyboard input on Haiku.
(Font and Color Parameters): Explain the different font
backends available on Haiku.
(Raising and Lowering): Explain that lowering and
restacking frames doesn't work on Haiku.
(Child Frames): Explain oddities of child frame
visibility on Haiku.

* doc/lispref/os.texi (System Environment): Explain
meaning of haiku.
* etc/MACHINES: Add appropriate notices for Haiku.
* etc/NEWS: Document changes.
* etc/PROBLEMS: Document font spacing bug on Haiku.

* lib-src/Makefile.in: Build be-resources binary on
Haiku.
(CXX, CXXFLAGS, NON_CXX_FLAGS, ALL_CXXFLAGS)
(HAVE_BE_APP, HAIKU_LIBS, HAIKU_CFLAGS): New variables.
(DONT_INSTALL): Add be-resources binary if on Haiku.
(be-resources): New target.

* lib-src/be_resources: Add helper binary for setting
resources on the Emacs application.

* lib-src/emacsclient.c (decode_options): Set
alt_display to "be" on Haiku.

* lisp/cus-edit.el (custom-button, custom-button-mouse)
(custom-button-unraised, custom-button-pressed): Update
face definitions for Haiku.

* lisp/cus-start.el: Add haiku-debug-on-fatal-error and
haiku-use-system-tooltips.

* lisp/faces.el (face-valid-attribute-values): Clarify
attribute comment for Haiku.
(tool-bar): Add appropriate toolbar color for Haiku.

* lisp/frame.el (haiku-frame-geometry)
(haiku-mouse-absolute-pixel-position)
(haiku-set-mouse-absolute-pixel-position)
(haiku-frame-edges)
(haiku-frame-list-z-order): New function declarations.

(frame-geometry, frame-edges)
(mouse-absolute-pixel-position)
(set-mouse-absolute-pixel-position)
(frame-list-z-order): Call appropriate window system
functions on Haiku.

(display-mouse-p, display-graphic-p)
(display-images-p, display-pixel-height)
(display-pixel-width, display-mm-height)
(display-mm-width, display-backing-store)
(display-save-under, display-planes)
(display-color-cells, display-visual-class): Update type
tests for Haiku.

* lisp/international/mule-cmds.el
(set-coding-system-map): Also
prevent set-terminal-coding-system from appearing in the menu
bar on Haiku.

* lisp/loadup.el: Load Haiku-specific files when built
with Haiku, and don't rename newly built Emacs on Haiku as BFS
doesn't support hard links.

* lisp/menu-bar.el (menu-bar-open): Add for Haiku.

* lisp/mwheel.el (mouse-wheel-down-event): Expect
wheel-up on Haiku.
(mouse-wheel-up-event): Expect wheel-down on Haiku.
(mouse-wheel-left-event): Expect wheel-left on Haiku.
(mouse-wheel-right-event): Expect wheel-right on Haiku.

* lisp/net/browse-url.el
(browse-url--browser-defcustom-type):
Add option for WebPositive.
(browse-url-webpositive-program): New variable.
(browse-url-default-program): Search for WebPositive.
(browse-url-webpositive): New function.

* lisp/net/eww.el (eww-form-submit, eww-form-file)
(eww-form-checkbox, eww-form-select): Define faces
appropriately for Haiku.

* lisp/term/haiku-win.el: New file.

* lisp/tooltip.el (menu-or-popup-active-p): New function
declaration.
(tooltip-show-help): Don't use tooltips on Haiku when a
menu is active.

* lisp/version.el (haiku-get-version-string): New
function declaration.
(emacs-version): Add Haiku version string if
appropriate.

* src/Makefile.in: Also produce binary named "Emacs"
with Haiku resources set.

(CXX, HAIKU_OBJ, HAIKU_CXX_OBJ, HAIKU_LIBS)
(HAIKU_CFLAGS, HAVE_BE_APP, NON_CXX_FLAGS)
(ALL_CXX_FLAGS): New variables.

(.SUFFIXES): Add .cc.
(.cc.o): New target.
(base_obj): Add Haiku C objects.
(doc_obj, obj): Split objects that should scanned for
documentation into doc_obj.
(SOME_MACHINE_OBJECTS): Add appropriate Haiku C objects.
(all): Depend on Emacs and Emacs.pdmp on Haiku.
(LIBES): Add Haiku libraries.
(gl-stamp)
($(etc)/DOC): Scan doc_obj instead of obj
(temacs$(EXEEXT): Use C++ linker on Haiku.
(ctagsfiles3): New variable.
(TAGS): Scan C++ files.

* src/alloc.c (garbage_collect): Mark Haiku display.

* src/dispextern.h (HAVE_NATIVE_TRANSFORMS): Also enable
on Haiku.
(struct image): Add fields for Haiku transforms.
(RGB_PIXEL_COLOR): Define to unsigned long on Haiku as
well.
(sit_for): Also check USABLE_SIGPOLL.
(init_display_interactive): Set initial window system to
Haiku on Haiku builds.

* src/emacs.c (main): Define Haiku syms and init haiku
clipboard.
(shut_down_emacs): Quit BApplication on Haiku and
trigger debug
on aborts if haiku_debug_on_fatal_error.
(Vsystem_type): Update docstring.

* src/fileio.c (next-read-file-uses-dialog-p): Enable on
Haiku.

* src/filelock.c (WTMP_FILE): Only define if BOOT_TIME
is also defined.

* src/floatfns.c (double_integer_scale): Work around
Haiku libroot brain damage.

* src/font.c (syms_of_font): Define appropriate font
driver symbols for Haiku builds with various options.

* src/font.h: Also enable ftcrfont on Haiku builds with
Cairo.
(font_data_structures_may_be_ill_formed): Also enable on
Haiku builds that have Cairo.

* src/frame.c (Fframep): Update doc-string for Haiku
builds and return haiku if appropriate.
(syms_of_frame): New symbol `haiku'.

* src/frame.h (struct frame): Add output data for Haiku.
(FRAME_HAIKU_P): New macro.
(FRAME_WINDOW_P): Test for Haiku frames as well.

* src/ftcrfont.c (RED_FROM_ULONG, GREEN_FROM_ULONG)
(BLUE_FROM_ULONG): New macros.
(ftcrfont_draw): Add haiku specific code for Haiku
builds with Cairo.

* src/ftfont.c (ftfont_open): Set face.
(ftfont_has_char, ftfont_text_extents): Work around
crash.
(syms_of_ftfont): New symbol `mono'.

* src/ftfont.h (struct font_info): Enable Cairo-specific
fields for Cairo builds on Haiku.

* src/haiku_draw_support.cc:
* src/haiku_font_support.cc:
* src/haiku_io.c:
* src/haiku_select.cc:
* src/haiku_support.cc:
* src/haiku_support.h:
* src/haikufns.c:
* src/haikufont.c:
* src/haikugui.h:
* src/haikuimage.c:
* src/haikumenu.c:
* src/haikuselect.c:
* src/haikuselect.h:
* src/haikuterm.c:
* src/haikuterm.h: Add new files for Haiku windowing
support.

* src/haiku.c: Add new files for Haiku operating system
support.

* src/image.c: Implement image transforms and native XPM
support
on Haiku.

(GET_PIXEL, PUT_PIXEL, NO_PIXMAP)
(PIX_MASK_RETAIN, PIX_MASK_DRAW)
(RGB_TO_ULONG, RED_FROM_ULONG, GREEN_FROM_ULONG)
(BLUE_FROM_ULONG, RED16_FROM_ULONG, GREEN16_FROM_ULONG)
(BLUE16_FROM_ULONG): Define to appropriate values on
Haiku.

(image_create_bitmap_from_data): Add Haiku support.
(image_create_bitmap_from_file): Add TODO on Haiku.
(free_bitmap_record): Free bitmap on Haiku.
(image_size_in_bytes): Implement for Haiku bitmaps.
(image_set_transform): Implement on Haiku.
(image_create_x_image_and_pixmap_1): Implement on Haiku,
24-bit or 1-bit only.
(image_destroy_x_image, image_get_x_image): Use correct
img and pixmap values on Haiku.
(lookup_rgb_color): Use correct macro on Haiku.
(image_to_emacs_colors): Implement on Haiku.
(image_disable_image): Disable on Haiku.
(image_can_use_native_api): Test for translator presence
on Haiku.
(native_image_load): Use translator on Haiku.
(imagemagick_load_image): Add Haiku-specific quirks.
(Fimage_transforms_p): Allow rotate90 on Haiku.
(image_types): Enable native XPM support on Haiku.
(syms_of_image): Enable XPM images on Haiku.

* src/keyboard.c (kbd_buffer_get_event)
(handle_async_input, handle_input_available_signal)
(handle_user_signal, Fset_input_interrupt_mode)
(init_keyboard): Check for USABLE_SIGPOLL along with
USABLE_SIGIO.

* src/lisp.h (pD): Work around broken Haiku headers.
(HAVE_EXT_MENU_BAR): Define on Haiku.
(handle_input_available_signal): Enable if we just have
SIGPOLL as well.

* src/menu.c (have_boxes): Return true on Haiku.
(single_menu_item): Enable toolkit menus on Haiku.
(find_and_call_menu_selection): Also enable on Haiku.

* src/process.c (keyboard_bit_set): Enable with only
usable SIGPOLL.
(wait_reading_process_output): Test for SIGPOLL as well
as SIGIO availability.

* src/sound.c (sound_perror, vox_open)
(vox_configure, vox_close): Enable for usable SIGPOLL as
well.

* src/sysdep.c (sys_subshell): Enable for usable SIGPOLL.
(reset_sigio): Make conditional on F_SETOWN.
(request_sigio, unrequest_sigio)
(emacs_sigaction_init): Also handle SIGPOLLs.
(init_sys_modes): Disable TCXONC usage on Haiku, as it
doesn't have any ttys other than pseudo ttys, which don't
support C-s/C-q flow control, and causes compiler warnings.
(speeds): Disable high speeds if HAVE_TINY_SPEED_T.

* src/termhooks.h (enum output_method): Add output_haiku.
(struct terminal): Add Haiku display info.
(TERMINAL_FONT_CACHE): Enable for Haiku.

* src/terminal.c (Fterminal_live_p): Return `haiku' if
appropriate.
* src/verbose.mk.in (AM_V_CXX, AM_V_CXXLD): New logging
variables.

* src/xdisp.c (redisplay_internal)
(note_mouse_highlight): Return on Haiku if a popup is activated.
(display_menu_bar): Return on Haiku if frame is a Haiku
frame.

* src/xfaces.c (GCGraphicsExposures): Enable correctly on Haiku.
(x_create_gc): Enable dummy GC code on Haiku.

* src/xfns.c (x-server-version, x-file-dialog): Add
Haiku specifics to doc strings.

* src/xterm.c (syms_of_xterm): Add Haiku information to
doc string.
2021-11-20 21:46:07 +08:00

657 lines
17 KiB
C

/* 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;
}