* .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.
657 lines
17 KiB
C
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;
|
|
}
|