root/src/haikumenu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. digest_menu_items
  2. haiku_dialog_show
  3. haiku_popup_dialog
  4. haiku_menu_show_help
  5. haiku_process_pending_signals_for_menu_1
  6. haiku_process_pending_signals_for_menu_2
  7. haiku_process_pending_signals_for_menu
  8. haiku_menu_show
  9. free_frame_menubar
  10. initialize_frame_menubar
  11. set_frame_menubar
  12. run_menu_bar_help_event
  13. DEFUN
  14. DEFUN
  15. haiku_activate_menubar
  16. syms_of_haikumenu

     1 /* Haiku window system support
     2    Copyright (C) 2021-2023 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 static struct timespec menu_timer_timespec;
    33 
    34 int popup_activated_p = 0;
    35 
    36 static void
    37 digest_menu_items (void *first_menu, int start, int menu_items_used,
    38                    bool is_menu_bar)
    39 {
    40   void **menus, **panes;
    41   ssize_t menu_len;
    42   ssize_t pane_len;
    43   int i, menu_depth;
    44   void *menu, *window, *view;
    45   Lisp_Object pane_name, prefix;
    46   const char *pane_string;
    47   Lisp_Object item_name, enable, descrip, def, selected, help;
    48 
    49   USE_SAFE_ALLOCA;
    50 
    51   menu_len = (menu_items_used + 1 - start) * sizeof *menus;
    52   pane_len = (menu_items_used + 1 - start) * sizeof *panes;
    53   menu = first_menu;
    54 
    55   i = start;
    56   menu_depth = 0;
    57 
    58   menus = SAFE_ALLOCA (menu_len);
    59   panes = SAFE_ALLOCA (pane_len);
    60   memset (menus, 0, menu_len);
    61   memset (panes, 0, pane_len);
    62   menus[0] = first_menu;
    63 
    64   window = NULL;
    65   view = NULL;
    66 
    67   if (FRAMEP (Vmenu_updating_frame) &&
    68       FRAME_LIVE_P (XFRAME (Vmenu_updating_frame)) &&
    69       FRAME_HAIKU_P (XFRAME (Vmenu_updating_frame)))
    70     {
    71       window = FRAME_HAIKU_WINDOW (XFRAME (Vmenu_updating_frame));
    72       view = FRAME_HAIKU_VIEW (XFRAME (Vmenu_updating_frame));
    73     }
    74 
    75   if (view)
    76     BView_draw_lock (view, false, 0, 0, 0, 0);
    77 
    78   while (i < menu_items_used)
    79     {
    80       if (NILP (AREF (menu_items, i)))
    81         {
    82           menus[++menu_depth] = menu;
    83           i++;
    84         }
    85       else if (EQ (AREF (menu_items, i), Qlambda))
    86         {
    87           panes[menu_depth] = NULL;
    88           menu = panes[--menu_depth] ? panes[menu_depth] : menus[menu_depth];
    89           i++;
    90         }
    91       else if (EQ (AREF (menu_items, i), Qquote))
    92         i += 1;
    93       else if (EQ (AREF (menu_items, i), Qt))
    94         {
    95           if (menu_items_n_panes == 1)
    96             {
    97               i += MENU_ITEMS_PANE_LENGTH;
    98               continue;
    99             }
   100 
   101           pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
   102           prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
   103 
   104           if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
   105             {
   106               pane_name = ENCODE_UTF_8 (pane_name);
   107               ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
   108             }
   109 
   110           pane_string = (NILP (pane_name)
   111                          ? "" : SSDATA (pane_name));
   112           if (!NILP (prefix))
   113             pane_string++;
   114 
   115           if (strcmp (pane_string, ""))
   116             {
   117               panes[menu_depth] =
   118                 menu = BMenu_new_submenu (menus[menu_depth], pane_string, 1);
   119             }
   120 
   121           i += MENU_ITEMS_PANE_LENGTH;
   122         }
   123       else
   124         {
   125           item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
   126           enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
   127           descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
   128           def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
   129           selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
   130           help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
   131 
   132           if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
   133             {
   134               item_name = ENCODE_UTF_8 (item_name);
   135               ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
   136             }
   137 
   138           if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
   139             {
   140               descrip = ENCODE_UTF_8 (descrip);
   141               ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
   142             }
   143 
   144           if (STRINGP (help) && STRING_MULTIBYTE (help))
   145             help = ENCODE_UTF_8 (help);
   146 
   147           if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used &&
   148               NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH)))
   149             menu = BMenu_new_submenu (menu, SSDATA (item_name), !NILP (enable));
   150           else if (NILP (def) && menu_separator_name_p (SSDATA (item_name)))
   151             BMenu_add_separator (menu);
   152           else if (!is_menu_bar)
   153             {
   154               if (!use_system_tooltips || NILP (Fsymbol_value (Qtooltip_mode)))
   155                 BMenu_add_item (menu, SSDATA (item_name),
   156                                 !NILP (def) ? aref_addr (menu_items, i) : NULL,
   157                                 !NILP (enable), !NILP (selected), 0, window,
   158                                 !NILP (descrip) ? SSDATA (descrip) : NULL,
   159                                 NULL);
   160               else
   161                 BMenu_add_item (menu, SSDATA (item_name),
   162                                 !NILP (def) ? aref_addr (menu_items, i) : NULL,
   163                                 !NILP (enable), !NILP (selected), 0, window,
   164                                 !NILP (descrip) ? SSDATA (descrip) : NULL,
   165                                 STRINGP (help) ? SSDATA (help) : NULL);
   166             }
   167           else if (!use_system_tooltips || NILP (Fsymbol_value (Qtooltip_mode)))
   168             BMenu_add_item (menu, SSDATA (item_name),
   169                             !NILP (def) ? (void *) (intptr_t) i : NULL,
   170                             !NILP (enable), !NILP (selected), 1, window,
   171                             !NILP (descrip) ? SSDATA (descrip) : NULL,
   172                             NULL);
   173           else
   174             BMenu_add_item (menu, SSDATA (item_name),
   175                             !NILP (def) ? (void *) (intptr_t) i : NULL,
   176                             !NILP (enable), !NILP (selected), 1, window,
   177                             !NILP (descrip) ? SSDATA (descrip) : NULL,
   178                             STRINGP (help) ? SSDATA (help) : NULL);
   179 
   180           i += MENU_ITEMS_ITEM_LENGTH;
   181         }
   182     }
   183 
   184   if (view)
   185     BView_draw_unlock (view);
   186 
   187   SAFE_FREE ();
   188 }
   189 
   190 static Lisp_Object
   191 haiku_dialog_show (struct frame *f, Lisp_Object title,
   192                    Lisp_Object header, const char **error_name)
   193 {
   194   int i, nb_buttons = 0;
   195   bool boundary_seen = false;
   196   Lisp_Object pane_name, vals[10];
   197   void *alert, *button;
   198   bool enabled_item_seen_p = false;
   199   int32 val;
   200 
   201   *error_name = NULL;
   202 
   203   if (menu_items_n_panes > 1)
   204     {
   205       *error_name = "Multiple panes in dialog box";
   206       return Qnil;
   207     }
   208 
   209   pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
   210   i = MENU_ITEMS_PANE_LENGTH;
   211 
   212   if (STRING_MULTIBYTE (pane_name))
   213     pane_name = ENCODE_UTF_8 (pane_name);
   214 
   215   block_input ();
   216   alert = BAlert_new (SSDATA (pane_name), NILP (header) ? HAIKU_INFO_ALERT :
   217                       HAIKU_IDEA_ALERT);
   218 
   219   while (i < menu_items_used)
   220     {
   221       Lisp_Object item_name, enable, descrip, value;
   222       item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
   223       enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
   224       descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
   225       value = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
   226 
   227       if (NILP (item_name))
   228         {
   229           BAlert_delete (alert);
   230           *error_name = "Submenu in dialog items";
   231           unblock_input ();
   232           return Qnil;
   233         }
   234 
   235       if (EQ (item_name, Qquote))
   236         {
   237           if (nb_buttons)
   238             boundary_seen = true;
   239 
   240           i++;
   241           continue;
   242         }
   243 
   244       if (nb_buttons >= 9)
   245         {
   246           BAlert_delete (alert);
   247           *error_name = "Too many dialog items";
   248           unblock_input ();
   249           return Qnil;
   250         }
   251 
   252       if (STRING_MULTIBYTE (item_name))
   253         item_name = ENCODE_UTF_8 (item_name);
   254       if (!NILP (descrip) && STRING_MULTIBYTE (descrip))
   255         descrip = ENCODE_UTF_8 (descrip);
   256 
   257       button = BAlert_add_button (alert, SSDATA (item_name));
   258 
   259       BButton_set_enabled (button, !NILP (enable));
   260       enabled_item_seen_p |= !NILP (enable);
   261 
   262       if (!NILP (descrip))
   263         BView_set_tooltip (button, SSDATA (descrip));
   264 
   265       vals[nb_buttons] = value;
   266       ++nb_buttons;
   267       i += MENU_ITEMS_ITEM_LENGTH;
   268     }
   269 
   270   /* Haiku only lets us specify a single button to place on the
   271      left.  */
   272   if (boundary_seen)
   273     BAlert_set_offset_spacing (alert);
   274 
   275   /* If there isn't a single enabled item, add an "Ok" button so the
   276      popup can be dismissed.  */
   277   if (!enabled_item_seen_p)
   278     BAlert_add_button (alert, "Ok");
   279   unblock_input ();
   280 
   281   unrequest_sigio ();
   282   ++popup_activated_p;
   283   val = BAlert_go (alert, block_input, unblock_input,
   284                    process_pending_signals);
   285   --popup_activated_p;
   286   request_sigio ();
   287 
   288   if (val < 0)
   289     quit ();
   290   else if (val < nb_buttons)
   291     return vals[val];
   292 
   293   /* The dialog was dismissed via the button appended to dismiss popup
   294      dialogs without a single enabled item.  */
   295   if (nb_buttons)
   296     quit ();
   297   /* Otherwise, the Ok button was added because no buttons were seen
   298      at all.  */
   299   else
   300     return Qt;
   301 
   302   emacs_abort ();
   303 }
   304 
   305 Lisp_Object
   306 haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
   307 {
   308   Lisp_Object title;
   309   const char *error_name = NULL;
   310   Lisp_Object selection;
   311   specpdl_ref specpdl_count = SPECPDL_INDEX ();
   312 
   313   check_window_system (f);
   314 
   315   /* Decode the dialog items from what was specified.  */
   316   title = Fcar (contents);
   317   CHECK_STRING (title);
   318   record_unwind_protect_void (unuse_menu_items);
   319 
   320   if (NILP (Fcar (Fcdr (contents))))
   321     /* No buttons specified, add an "Ok" button so users can pop down
   322        the dialog.  Also, the lesstif/motif version crashes if there are
   323        no buttons.  */
   324     contents = list2 (title, Fcons (build_string ("Ok"), Qt));
   325 
   326   list_of_panes (list1 (contents));
   327 
   328   /* Display them in a dialog box.  */
   329   selection = haiku_dialog_show (f, title, header, &error_name);
   330 
   331   unbind_to (specpdl_count, Qnil);
   332   discard_menu_items ();
   333 
   334   if (error_name)
   335     error ("%s", error_name);
   336   return selection;
   337 }
   338 
   339 static void
   340 haiku_menu_show_help (void *help, void *data)
   341 {
   342   Lisp_Object *id = (Lisp_Object *) help;
   343 
   344   if (help)
   345     show_help_echo (id[MENU_ITEMS_ITEM_HELP],
   346                     Qnil, Qnil, Qnil);
   347   else
   348     show_help_echo (Qnil, Qnil, Qnil, Qnil);
   349 }
   350 
   351 static Lisp_Object
   352 haiku_process_pending_signals_for_menu_1 (void *ptr)
   353 {
   354   menu_timer_timespec = timer_check ();
   355 
   356   return Qnil;
   357 }
   358 
   359 static Lisp_Object
   360 haiku_process_pending_signals_for_menu_2 (enum nonlocal_exit exit, Lisp_Object error)
   361 {
   362   menu_timer_timespec.tv_sec = 0;
   363   menu_timer_timespec.tv_nsec = -1;
   364 
   365   return Qnil;
   366 }
   367 
   368 static struct timespec
   369 haiku_process_pending_signals_for_menu (void)
   370 {
   371   process_pending_signals ();
   372 
   373   /* The original idea was to let timers throw so that timeouts can
   374      work correctly, but there's no way to pop down a BPopupMenu
   375      that's currently popped up.  */
   376   internal_catch_all (haiku_process_pending_signals_for_menu_1, NULL,
   377                       haiku_process_pending_signals_for_menu_2);
   378 
   379   return menu_timer_timespec;
   380 }
   381 
   382 Lisp_Object
   383 haiku_menu_show (struct frame *f, int x, int y, int menuflags,
   384                  Lisp_Object title, const char **error_name)
   385 {
   386   int i, submenu_depth, j;
   387   void *view, *menu;
   388   Lisp_Object *subprefix_stack;
   389   Lisp_Object prefix, entry;
   390 
   391   USE_SAFE_ALLOCA;
   392 
   393   view = FRAME_HAIKU_VIEW (f);
   394   i = 0;
   395   submenu_depth = 0;
   396   subprefix_stack
   397     = SAFE_ALLOCA (menu_items_used * sizeof (Lisp_Object));
   398 
   399   eassert (FRAME_HAIKU_P (f));
   400 
   401   *error_name = NULL;
   402 
   403   if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
   404     {
   405       *error_name = "Empty menu";
   406 
   407       SAFE_FREE ();
   408       return Qnil;
   409     }
   410 
   411   block_input ();
   412   if (STRINGP (title) && STRING_MULTIBYTE (title))
   413     title = ENCODE_UTF_8 (title);
   414 
   415   menu = BPopUpMenu_new (STRINGP (title) ? SSDATA (title) : NULL);
   416   if (STRINGP (title))
   417     {
   418       BMenu_add_title (menu, SSDATA (title));
   419       BMenu_add_separator (menu);
   420     }
   421   digest_menu_items (menu, 0, menu_items_used, 0);
   422   BView_convert_to_screen (view, &x, &y);
   423   unblock_input ();
   424 
   425   unrequest_sigio ();
   426   popup_activated_p++;
   427   menu_item_selection = BMenu_run (menu, x, y,  haiku_menu_show_help,
   428                                    block_input, unblock_input,
   429                                    haiku_process_pending_signals_for_menu, NULL);
   430   popup_activated_p--;
   431   request_sigio ();
   432 
   433   FRAME_DISPLAY_INFO (f)->grabbed = 0;
   434 
   435   /* Clear the grab view manually.  There is a race condition here if
   436      the window thread receives a button press between here and the
   437      end of BMenu_run.  */
   438   be_clear_grab_view ();
   439 
   440   if (menu_item_selection)
   441     {
   442       prefix = entry = Qnil;
   443       i = 0;
   444       while (i < menu_items_used)
   445         {
   446           if (NILP (AREF (menu_items, i)))
   447             {
   448               subprefix_stack[submenu_depth++] = prefix;
   449               prefix = entry;
   450               i++;
   451             }
   452           else if (EQ (AREF (menu_items, i), Qlambda))
   453             {
   454               prefix = subprefix_stack[--submenu_depth];
   455               i++;
   456             }
   457           else if (EQ (AREF (menu_items, i), Qt))
   458             {
   459               prefix
   460                 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
   461               i += MENU_ITEMS_PANE_LENGTH;
   462             }
   463           /* Ignore a nil in the item list.
   464              It's meaningful only for dialog boxes.  */
   465           else if (EQ (AREF (menu_items, i), Qquote))
   466             i += 1;
   467           else
   468             {
   469               entry
   470                 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
   471               if (menu_item_selection == aref_addr (menu_items, i))
   472                 {
   473                   if (menuflags & MENU_KEYMAPS)
   474                     {
   475                       entry = list1 (entry);
   476                       if (!NILP (prefix))
   477                         entry = Fcons (prefix, entry);
   478                       for (j = submenu_depth - 1; j >= 0; j--)
   479                         if (!NILP (subprefix_stack[j]))
   480                           entry = Fcons (subprefix_stack[j], entry);
   481                     }
   482                   block_input ();
   483                   BPopUpMenu_delete (menu);
   484                   unblock_input ();
   485 
   486                   SAFE_FREE ();
   487                   return entry;
   488                 }
   489               i += MENU_ITEMS_ITEM_LENGTH;
   490             }
   491         }
   492     }
   493   else if (!(menuflags & MENU_FOR_CLICK))
   494     {
   495       block_input ();
   496       BPopUpMenu_delete (menu);
   497       unblock_input ();
   498       quit ();
   499     }
   500   block_input ();
   501   BPopUpMenu_delete (menu);
   502   unblock_input ();
   503 
   504   SAFE_FREE ();
   505   return Qnil;
   506 }
   507 
   508 void
   509 free_frame_menubar (struct frame *f)
   510 {
   511   void *mbar;
   512 
   513   FRAME_MENU_BAR_LINES (f) = 0;
   514   FRAME_MENU_BAR_HEIGHT (f) = 0;
   515   FRAME_EXTERNAL_MENU_BAR (f) = 0;
   516 
   517   block_input ();
   518   mbar = FRAME_HAIKU_MENU_BAR (f);
   519   FRAME_HAIKU_MENU_BAR (f) = NULL;
   520 
   521   if (mbar)
   522     BMenuBar_delete (mbar);
   523 
   524   if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p)
   525     --popup_activated_p;
   526   FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0;
   527   unblock_input ();
   528 
   529   adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
   530 }
   531 
   532 void
   533 initialize_frame_menubar (struct frame *f)
   534 {
   535   /* This function is called before the first chance to redisplay
   536      the frame.  It has to be, so the frame will have the right size.  */
   537   fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
   538   set_frame_menubar (f, true);
   539 }
   540 
   541 void
   542 set_frame_menubar (struct frame *f, bool deep_p)
   543 {
   544   void *mbar = FRAME_HAIKU_MENU_BAR (f);
   545   void *view = FRAME_HAIKU_VIEW (f);
   546   bool first_time_p = false;
   547 
   548   if (!mbar)
   549     {
   550       block_input ();
   551       mbar = FRAME_HAIKU_MENU_BAR (f) = BMenuBar_new (view);
   552       first_time_p = 1;
   553 
   554       /* Now wait for the MENU_BAR_RESIZE event informing us of the
   555          initial dimensions of that menu bar.  */
   556       if (FRAME_VISIBLE_P (f))
   557         haiku_wait_for_event (f, MENU_BAR_RESIZE);
   558 
   559       unblock_input ();
   560     }
   561 
   562   Lisp_Object items;
   563   struct buffer *prev = current_buffer;
   564   Lisp_Object buffer;
   565   specpdl_ref specpdl_count = SPECPDL_INDEX ();
   566   int previous_menu_items_used = f->menu_bar_items_used;
   567   Lisp_Object *previous_items
   568     = alloca (previous_menu_items_used * sizeof *previous_items);
   569   int count;
   570   ptrdiff_t subitems, i;
   571   int *submenu_start, *submenu_end, *submenu_n_panes;
   572   Lisp_Object *submenu_names;
   573 
   574   XSETFRAME (Vmenu_updating_frame, f);
   575 
   576   if (!deep_p)
   577     {
   578       items = FRAME_MENU_BAR_ITEMS (f);
   579       Lisp_Object string;
   580 
   581       block_input ();
   582       int count = BMenu_count_items (mbar);
   583 
   584       int i;
   585       for (i = 0; i < ASIZE (items); i += 4)
   586         {
   587           string = AREF (items, i + 1);
   588 
   589           if (!STRINGP (string))
   590             break;
   591 
   592           if (STRING_MULTIBYTE (string))
   593             string = ENCODE_UTF_8 (string);
   594 
   595           if (i / 4 < count)
   596             {
   597               void *it = BMenu_item_at (mbar, i / 4);
   598               BMenu_item_set_label (it, SSDATA (string));
   599             }
   600           else
   601             BMenu_new_menu_bar_submenu (mbar, SSDATA (string));
   602         }
   603 
   604       if (i / 4 < count)
   605         BMenu_delete_from (mbar, i / 4, count - i / 4 + 1);
   606       unblock_input ();
   607 
   608       f->menu_bar_items_used = 0;
   609     }
   610   else
   611     {
   612       /* If we are making a new widget, its contents are empty,
   613          do always reinitialize them.  */
   614       if (first_time_p)
   615         previous_menu_items_used = 0;
   616 
   617       buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
   618       specbind (Qinhibit_quit, Qt);
   619       /* Don't let the debugger step into this code
   620          because it is not reentrant.  */
   621       specbind (Qdebug_on_next_call, Qnil);
   622 
   623       record_unwind_save_match_data ();
   624       if (NILP (Voverriding_local_map_menu_flag))
   625         {
   626           specbind (Qoverriding_terminal_local_map, Qnil);
   627           specbind (Qoverriding_local_map, Qnil);
   628         }
   629 
   630       set_buffer_internal_1 (XBUFFER (buffer));
   631 
   632       /* Run the Lucid hook.  */
   633       safe_run_hooks (Qactivate_menubar_hook);
   634 
   635       /* If it has changed current-menubar from previous value,
   636          really recompute the menubar from the value.  */
   637       safe_run_hooks (Qmenu_bar_update_hook);
   638       fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
   639 
   640       items = FRAME_MENU_BAR_ITEMS (f);
   641 
   642       /* Save the frame's previous menu bar contents data.  */
   643       if (previous_menu_items_used)
   644         memcpy (previous_items, xvector_contents (f->menu_bar_vector),
   645                 previous_menu_items_used * word_size);
   646 
   647       /* Fill in menu_items with the current menu bar contents.
   648          This can evaluate Lisp code.  */
   649       save_menu_items ();
   650 
   651       menu_items = f->menu_bar_vector;
   652       menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
   653       subitems = ASIZE (items) / 4;
   654       submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
   655       submenu_end = alloca (subitems * sizeof *submenu_end);
   656       submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
   657       submenu_names = alloca (subitems * sizeof (Lisp_Object));
   658 
   659       init_menu_items ();
   660       for (i = 0; i < subitems; i++)
   661         {
   662           Lisp_Object key, string, maps;
   663 
   664           key = AREF (items, 4 * i);
   665           string = AREF (items, 4 * i + 1);
   666           maps = AREF (items, 4 * i + 2);
   667           if (NILP (string))
   668             break;
   669 
   670           if (STRINGP (string) && STRING_MULTIBYTE (string))
   671             string = ENCODE_UTF_8 (string);
   672 
   673           submenu_start[i] = menu_items_used;
   674 
   675           menu_items_n_panes = 0;
   676           parse_single_submenu (key, string, maps);
   677           submenu_n_panes[i] = menu_items_n_panes;
   678 
   679           submenu_end[i] = menu_items_used;
   680           submenu_names[i] = string;
   681         }
   682 
   683       submenu_start[i] = -1;
   684       finish_menu_items ();
   685 
   686       set_buffer_internal_1 (prev);
   687 
   688       /* If there has been no change in the Lisp-level contents
   689          of the menu bar, skip redisplaying it.  Just exit.  */
   690 
   691       /* Compare the new menu items with the ones computed last time.  */
   692       for (i = 0; i < previous_menu_items_used; i++)
   693         if (menu_items_used == i
   694             || (!EQ (previous_items[i], AREF (menu_items, i))))
   695           break;
   696       if (i == menu_items_used && i == previous_menu_items_used && i != 0)
   697         {
   698           /* The menu items have not changed.  Don't bother updating
   699              the menus in any form, since it would be a no-op.  */
   700           discard_menu_items ();
   701           unbind_to (specpdl_count, Qnil);
   702           return;
   703         }
   704 
   705       /* Convert menu_items into widget_value trees
   706          to display the menu.  This cannot evaluate Lisp code.  */
   707 
   708       block_input ();
   709       count = BMenu_count_items (mbar);
   710       for (i = 0; submenu_start[i] >= 0; ++i)
   711         {
   712           void *mn = NULL;
   713           if (i < count)
   714             mn = BMenu_item_get_menu (BMenu_item_at (mbar, i));
   715           if (mn)
   716             BMenu_delete_all (mn);
   717           else
   718             mn = BMenu_new_menu_bar_submenu (mbar, SSDATA (submenu_names[i]));
   719 
   720           menu_items_n_panes = submenu_n_panes[i];
   721           digest_menu_items (mn, submenu_start[i], submenu_end[i], 1);
   722         }
   723       unblock_input ();
   724 
   725       /* The menu items are different, so store them in the frame.  */
   726       fset_menu_bar_vector (f, menu_items);
   727       f->menu_bar_items_used = menu_items_used;
   728     }
   729 
   730   /* This undoes save_menu_items.  */
   731   unbind_to (specpdl_count, Qnil);
   732 }
   733 
   734 void
   735 run_menu_bar_help_event (struct frame *f, int mb_idx)
   736 {
   737   Lisp_Object frame, vec, help;
   738 
   739   XSETFRAME (frame, f);
   740 
   741   block_input ();
   742   if (mb_idx < 0)
   743     {
   744       kbd_buffer_store_help_event (frame, Qnil);
   745       unblock_input ();
   746       return;
   747     }
   748 
   749   vec = f->menu_bar_vector;
   750   if ((mb_idx + MENU_ITEMS_ITEM_HELP) >= ASIZE (vec))
   751     return;
   752 
   753   help = AREF (vec, mb_idx + MENU_ITEMS_ITEM_HELP);
   754   if (STRINGP (help) || NILP (help))
   755     kbd_buffer_store_help_event (frame, help);
   756   unblock_input ();
   757 }
   758 
   759 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p,
   760        0, 0, 0, doc: /* SKIP: real doc in xmenu.c. */)
   761   (void)
   762 {
   763   return popup_activated_p ? Qt : Qnil;
   764 }
   765 
   766 DEFUN ("haiku-menu-bar-open", Fhaiku_menu_bar_open, Shaiku_menu_bar_open, 0, 1, "i",
   767        doc: /* Show and start key navigation of the menu bar in FRAME.
   768 This initially opens the first menu bar item and you can then navigate
   769 with the arrow keys, select a menu entry with the return key, or
   770 cancel with the escape key.  If FRAME is nil or not given, use the
   771 selected frame.  If FRAME has no menu bar, a pop-up is displayed at
   772 the position of the last non-menu event instead.  */)
   773   (Lisp_Object frame)
   774 {
   775   struct frame *f = decode_window_system_frame (frame);
   776   int rc;
   777 
   778   if (FRAME_EXTERNAL_MENU_BAR (f))
   779     {
   780       block_input ();
   781       set_frame_menubar (f, 1);
   782       rc = BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f));
   783       unblock_input ();
   784 
   785       if (!rc)
   786         return Qnil;
   787 
   788       FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
   789       popup_activated_p += 1;
   790     }
   791   else
   792     return call2 (Qpopup_menu, call0 (Qmouse_menu_bar_map),
   793                   last_nonmenu_event);
   794 
   795   return Qnil;
   796 }
   797 
   798 void
   799 haiku_activate_menubar (struct frame *f)
   800 {
   801   int rc;
   802 
   803   if (!FRAME_HAIKU_MENU_BAR (f))
   804     return;
   805 
   806   set_frame_menubar (f, true);
   807 
   808   if (FRAME_OUTPUT_DATA (f)->saved_menu_event)
   809     {
   810       block_input ();
   811       rc = be_replay_menu_bar_event (FRAME_HAIKU_MENU_BAR (f),
   812                                      FRAME_OUTPUT_DATA (f)->saved_menu_event);
   813       xfree (FRAME_OUTPUT_DATA (f)->saved_menu_event);
   814       FRAME_OUTPUT_DATA (f)->saved_menu_event = NULL;
   815       unblock_input ();
   816 
   817       if (!rc)
   818         return;
   819 
   820       FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
   821       popup_activated_p += 1;
   822     }
   823   else
   824     {
   825       block_input ();
   826       rc = BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f));
   827       unblock_input ();
   828 
   829       if (!rc)
   830         return;
   831 
   832       FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
   833       popup_activated_p += 1;
   834     }
   835 }
   836 
   837 void
   838 syms_of_haikumenu (void)
   839 {
   840   DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
   841   DEFSYM (Qpopup_menu, "popup-menu");
   842   DEFSYM (Qmouse_menu_bar_map, "mouse-menu-bar-map");
   843   DEFSYM (Qtooltip_mode, "tooltip-mode");
   844 
   845   defsubr (&Smenu_or_popup_active_p);
   846   defsubr (&Shaiku_menu_bar_open);
   847   return;
   848 }

/* [<][>][^][v][top][bottom][index][help] */