w32menu.c 44.6 KB
Newer Older
1
/* Menu support for GNU Emacs on the Microsoft Windows API.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2020 Free
3
   Software Foundation, Inc.
Geoff Voelker's avatar
Geoff Voelker committed
4 5 6

This file is part of GNU Emacs.

7
GNU Emacs is free software: you can redistribute it and/or modify
Geoff Voelker's avatar
Geoff Voelker committed
8
it under the terms of the GNU General Public License as published by
9 10
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
Geoff Voelker's avatar
Geoff Voelker committed
11 12 13 14 15 16 17

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
18
along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
Geoff Voelker's avatar
Geoff Voelker committed
19 20

#include <config.h>
21

22
#include <signal.h>
Geoff Voelker's avatar
Geoff Voelker committed
23
#include <stdio.h>
24
#include <setjmp.h>
25

Geoff Voelker's avatar
Geoff Voelker committed
26
#include "lisp.h"
27
#include "keyboard.h"
Geoff Voelker's avatar
Geoff Voelker committed
28 29
#include "frame.h"
#include "blockinput.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
30
#include "buffer.h"
31
#include "coding.h"	/* for ENCODE_SYSTEM */
32
#include "menu.h"
Daniel Colascione's avatar
Daniel Colascione committed
33
#include "pdumper.h"
Geoff Voelker's avatar
Geoff Voelker committed
34 35 36 37 38

/* This may include sys/types.h, and that somehow loses
   if this is not done before the other system files.  */
#include "w32term.h"

Daniel Colascione's avatar
Daniel Colascione committed
39 40 41 42 43 44 45 46
/* Cygwin does not support the multibyte string functions declared in
 * mbstring.h below --- but that's okay: because Cygwin is
 * UNICODE-only, we don't need to use these functions anyway.  */

#ifndef NTGUI_UNICODE
#include <mbstring.h>
#endif /* !NTGUI_UNICODE */

Geoff Voelker's avatar
Geoff Voelker committed
47 48 49 50 51 52
/* Load sys/types.h if not already loaded.
   In some systems loading it twice is suicidal.  */
#ifndef makedev
#include <sys/types.h>
#endif

Daniel Colascione's avatar
Daniel Colascione committed
53
#include "w32common.h"	/* for osinfo_cache */
54

55
#undef HAVE_DIALOGS /* TODO: Implement native dialogs.  */
56

57 58 59 60 61
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif /* no TRUE */

62
HMENU current_popup_menu;
63

64 65 66 67
typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) (
    IN HMENU,
    IN UINT,
    IN BOOL,
68
    IN OUT LPMENUITEMINFOA);
69 70 71 72
typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
    IN HMENU,
    IN UINT,
    IN BOOL,
73
    IN LPCMENUITEMINFOA);
74 75
typedef int (WINAPI * MessageBoxW_Proc) (
    IN HWND window,
76 77
    IN const WCHAR *text,
    IN const WCHAR *caption,
78
    IN UINT type);
79

Daniel Colascione's avatar
Daniel Colascione committed
80
#ifdef NTGUI_UNICODE
81 82 83 84
GetMenuItemInfoA_Proc get_menu_item_info = GetMenuItemInfoA;
SetMenuItemInfoA_Proc set_menu_item_info = SetMenuItemInfoA;
AppendMenuW_Proc unicode_append_menu = AppendMenuW;
MessageBoxW_Proc unicode_message_box = MessageBoxW;
Daniel Colascione's avatar
Daniel Colascione committed
85
#else /* !NTGUI_UNICODE */
86 87 88
GetMenuItemInfoA_Proc get_menu_item_info = NULL;
SetMenuItemInfoA_Proc set_menu_item_info = NULL;
AppendMenuW_Proc unicode_append_menu = NULL;
89
MessageBoxW_Proc unicode_message_box = NULL;
Daniel Colascione's avatar
Daniel Colascione committed
90
#endif /* NTGUI_UNICODE */
91

92
#ifdef HAVE_DIALOGS
93
static Lisp_Object w32_dialog_show (struct frame *, Lisp_Object, Lisp_Object, char **);
94
#else
95
static bool is_simple_dialog (Lisp_Object);
Dmitry Antipov's avatar
Dmitry Antipov committed
96
static Lisp_Object simple_dialog_show (struct frame *, Lisp_Object, Lisp_Object);
97
#endif
98

99
static void utf8to16 (unsigned char *, int, WCHAR *);
100
static int fill_in_menu (HMENU, widget_value *);
101

102
void w32_free_menu_strings (HWND);
Daniel Colascione's avatar
Daniel Colascione committed
103

104 105
Lisp_Object
w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
Geoff Voelker's avatar
Geoff Voelker committed
106
{
107

108 109
  check_window_system (f);

110
#ifndef HAVE_DIALOGS
Geoff Voelker's avatar
Geoff Voelker committed
111

112 113 114 115 116 117 118 119 120 121
  /* Handle simple Yes/No choices as MessageBox popups.  */
  if (is_simple_dialog (contents))
    return simple_dialog_show (f, contents, header);
  else
    return Qunsupported__w32_dialog;
#else  /* HAVE_DIALOGS */
    {
      Lisp_Object title;
      char *error_name;
      Lisp_Object selection;
Geoff Voelker's avatar
Geoff Voelker committed
122

123 124 125
      /* Decode the dialog items from what was specified.  */
      title = Fcar (contents);
      CHECK_STRING (title);
Geoff Voelker's avatar
Geoff Voelker committed
126

127
      list_of_panes (Fcons (contents, Qnil));
Geoff Voelker's avatar
Geoff Voelker committed
128

129 130
      /* Display them in a dialog box.  */
      block_input ();
131
      selection = w32_dialog_show (f, title, header, &error_name);
132 133 134 135 136 137 138 139
      unblock_input ();

      discard_menu_items ();
      FRAME_DISPLAY_INFO (f)->grabbed = 0;

      if (error_name) error (error_name);
      return selection;
    }
140
#endif /* HAVE_DIALOGS */
141
}
Geoff Voelker's avatar
Geoff Voelker committed
142

143 144
/* Activate the menu bar of frame F.
   This is called from keyboard.c when it gets the
Pavel Janík's avatar
Pavel Janík committed
145
   MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
146 147 148 149 150 151 152 153

   To activate the menu bar, we signal to the input thread that it can
   return from the WM_INITMENU message, allowing the normal Windows
   processing of the menus.

   But first we recompute the menu bar contents (the whole tree).

   This way we can safely execute Lisp code.  */
154

155
void
156
w32_activate_menubar (struct frame *f)
157
{
158
  set_frame_menubar (f, false, true);
159 160 161 162 163 164 165 166

  /* Lock out further menubar changes while active.  */
  f->output_data.w32->menubar_active = 1;

  /* Signal input thread to return from WM_INITMENU.  */
  complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
}

167 168 169 170
/* This callback is called from the menu bar pulldown menu
   when the user makes a selection.
   Figure out what the user chose
   and put the appropriate events into the keyboard buffer.  */
171
void menubar_selection_callback (struct frame *, void *);
172 173

void
Dmitry Antipov's avatar
Dmitry Antipov committed
174
menubar_selection_callback (struct frame *f, void * client_data)
Geoff Voelker's avatar
Geoff Voelker committed
175
{
176 177 178 179
  Lisp_Object prefix, entry;
  Lisp_Object vector;
  Lisp_Object *subprefix_stack;
  int submenu_depth = 0;
Geoff Voelker's avatar
Geoff Voelker committed
180
  int i;
Richard M. Stallman's avatar
Richard M. Stallman committed
181

182
  if (!f)
183
    return;
184
  entry = Qnil;
185
  subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size);
186
  vector = f->menu_bar_vector;
187 188 189 190
  prefix = Qnil;
  i = 0;
  while (i < f->menu_bar_items_used)
    {
191
      if (EQ (AREF (vector, i), Qnil))
192 193 194 195 196
	{
	  subprefix_stack[submenu_depth++] = prefix;
	  prefix = entry;
	  i++;
	}
197
      else if (EQ (AREF (vector, i), Qlambda))
198 199 200 201
	{
	  prefix = subprefix_stack[--submenu_depth];
	  i++;
	}
202
      else if (EQ (AREF (vector, i), Qt))
203
	{
204
	  prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
205 206 207 208
	  i += MENU_ITEMS_PANE_LENGTH;
	}
      else
	{
209
	  entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
210
	  /* The UINT_PTR cast avoids a warning.  There's no problem
211
	     as long as pointers have enough bits to hold small integers.  */
212
	  if ((int) (UINT_PTR) client_data == i)
213 214 215 216
	    {
	      int j;
	      struct input_event buf;
	      Lisp_Object frame;
217
	      EVENT_INIT (buf);
218

219
	      XSETFRAME (frame, f);
220 221 222
	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = frame;
223
	      kbd_buffer_store_event (&buf);
224

225 226 227
	      for (j = 0; j < submenu_depth; j++)
		if (!NILP (subprefix_stack[j]))
		  {
228 229 230
		    buf.kind = MENU_BAR_EVENT;
		    buf.frame_or_window = frame;
		    buf.arg = subprefix_stack[j];
231 232
		    kbd_buffer_store_event (&buf);
		  }
Richard M. Stallman's avatar
Richard M. Stallman committed
233

234 235
	      if (!NILP (prefix))
		{
236 237 238
		  buf.kind = MENU_BAR_EVENT;
		  buf.frame_or_window = frame;
		  buf.arg = prefix;
239 240
		  kbd_buffer_store_event (&buf);
		}
Richard M. Stallman's avatar
Richard M. Stallman committed
241

242 243 244
	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = entry;
245 246
	      /* Free memory used by owner-drawn and help-echo strings.  */
	      w32_free_menu_strings (FRAME_W32_WINDOW (f));
247 248
	      kbd_buffer_store_event (&buf);

249
	      f->output_data.w32->menubar_active = 0;
250 251 252 253
	      return;
	    }
	  i += MENU_ITEMS_ITEM_LENGTH;
	}
254
    }
255 256 257
  /* Free memory used by owner-drawn and help-echo strings.  */
  w32_free_menu_strings (FRAME_W32_WINDOW (f));
  f->output_data.w32->menubar_active = 0;
258
}
259

260 261 262 263 264 265

/* Set the contents of the menubar widgets of frame F.
   The argument FIRST_TIME is currently ignored;
   it is set the first time this is called, from initialize_frame_menubar.  */

void
Dmitry Antipov's avatar
Dmitry Antipov committed
266
set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
267 268
{
  HMENU menubar_widget = f->output_data.w32->menubar_widget;
269
  Lisp_Object items;
270
  widget_value *wv, *first_wv, *prev_wv = 0;
Eli Zaretskii's avatar
Eli Zaretskii committed
271
  int i, last_i = 0;
272
  int *submenu_start, *submenu_end;
273
  int *submenu_top_level_items, *submenu_n_panes;
274 275 276 277 278 279 280 281

  /* We must not change the menubar when actually in use.  */
  if (f->output_data.w32->menubar_active)
    return;

  XSETFRAME (Vmenu_updating_frame, f);

  if (! menubar_widget)
282
    deep_p = true;
283 284 285 286 287 288 289

  if (deep_p)
    {
      /* Make a widget-value tree representing the entire menu trees.  */

      struct buffer *prev = current_buffer;
      Lisp_Object buffer;
290
      ptrdiff_t specpdl_count = SPECPDL_INDEX ();
291 292 293
      int previous_menu_items_used = f->menu_bar_items_used;
      Lisp_Object *previous_items
	= (Lisp_Object *) alloca (previous_menu_items_used
294
				  * word_size);
295 296 297 298 299 300

      /* If we are making a new widget, its contents are empty,
	 do always reinitialize them.  */
      if (! menubar_widget)
	previous_menu_items_used = 0;

301
      buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
302 303 304 305 306
      specbind (Qinhibit_quit, Qt);
      /* Don't let the debugger step into this code
	 because it is not reentrant.  */
      specbind (Qdebug_on_next_call, Qnil);

307 308
      record_unwind_save_match_data ();

309 310 311 312 313 314 315 316
      if (NILP (Voverriding_local_map_menu_flag))
	{
	  specbind (Qoverriding_terminal_local_map, Qnil);
	  specbind (Qoverriding_local_map, Qnil);
	}

      set_buffer_internal_1 (XBUFFER (buffer));

317
      /* Run the hooks.  */
318
      safe_run_hooks (Qactivate_menubar_hook);
319
      safe_run_hooks (Qmenu_bar_update_hook);
320
      fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
321 322 323 324

      items = FRAME_MENU_BAR_ITEMS (f);

      /* Save the frame's previous menu bar contents data.  */
325
      if (previous_menu_items_used)
326
	memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
327
		previous_menu_items_used * word_size);
328

329 330
      /* Fill in menu_items with the current menu bar contents.
	 This can evaluate Lisp code.  */
331 332
      save_menu_items ();

333
      menu_items = f->menu_bar_vector;
334
      menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
335 336
      submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
      submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
337
      submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
338
      submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int));
339
      init_menu_items ();
340
      for (i = 0; i < ASIZE (items); i += 4)
341 342 343
	{
	  Lisp_Object key, string, maps;

344 345 346 347 348
	  last_i = i;

	  key = AREF (items, i);
	  string = AREF (items, i + 1);
	  maps = AREF (items, i + 2);
349 350 351
	  if (NILP (string))
	    break;

352 353 354 355 356
	  submenu_start[i] = menu_items_used;

	  menu_items_n_panes = 0;
	  submenu_top_level_items[i]
	    = parse_single_submenu (key, string, maps);
357
	  submenu_n_panes[i] = menu_items_n_panes;
358 359 360 361 362 363 364 365 366

	  submenu_end[i] = menu_items_used;
	}

      finish_menu_items ();

      /* Convert menu_items into widget_value trees
	 to display the menu.  This cannot evaluate Lisp code.  */

367
      wv = make_widget_value ("menubar", NULL, true, Qnil);
368 369 370 371 372
      wv->button_type = BUTTON_TYPE_NONE;
      first_wv = wv;

      for (i = 0; i < last_i; i += 4)
	{
373
	  menu_items_n_panes = submenu_n_panes[i];
374 375
	  wv = digest_single_submenu (submenu_start[i], submenu_end[i],
				      submenu_top_level_items[i]);
376
	  if (prev_wv)
377 378 379 380
	    prev_wv->next = wv;
	  else
	    first_wv->contents = wv;
	  /* Don't set wv->name here; GC during the loop might relocate it.  */
381
	  wv->enabled = true;
382
	  wv->button_type = BUTTON_TYPE_NONE;
383 384 385 386 387 388 389 390 391 392
	  prev_wv = wv;
	}

      set_buffer_internal_1 (prev);

      /* If there has been no change in the Lisp-level contents
	 of the menu bar, skip redisplaying it.  Just exit.  */

      for (i = 0; i < previous_menu_items_used; i++)
	if (menu_items_used == i
393
	    || (!EQ (previous_items[i], AREF (menu_items, i))))
394 395 396 397
	  break;
      if (i == menu_items_used && i == previous_menu_items_used && i != 0)
	{
	  free_menubar_widget_value_tree (first_wv);
398 399
	  discard_menu_items ();
          unbind_to (specpdl_count, Qnil);
400 401 402
	  return;
	}

403
      fset_menu_bar_vector (f, menu_items);
404 405 406 407 408
      f->menu_bar_items_used = menu_items_used;

      /* This undoes save_menu_items.  */
      unbind_to (specpdl_count, Qnil);

409
      /* Now GC cannot happen during the lifetime of the widget_value,
410 411 412 413
	 so it's safe to store data from a Lisp_String, as long as
	 local copies are made when the actual menu is created.
	 Windows takes care of this for normal string items, but
	 not for owner-drawn items or additional item-info.  */
414
      wv = first_wv->contents;
415
      for (i = 0; i < ASIZE (items); i += 4)
416 417
	{
	  Lisp_Object string;
418
	  string = AREF (items, i + 1);
419 420
	  if (NILP (string))
	    break;
421
	  wv->name = SSDATA (string);
422
	  update_submenu_strings (wv->contents);
423 424 425 426 427 428
	  wv = wv->next;
	}
    }
  else
    {
      /* Make a widget-value tree containing
429
	 just the top level menu bar strings.  */
430

431
      wv = make_widget_value ("menubar", NULL, true, Qnil);
432 433 434
      wv->button_type = BUTTON_TYPE_NONE;
      first_wv = wv;

435
      items = FRAME_MENU_BAR_ITEMS (f);
436
      for (i = 0; i < ASIZE (items); i += 4)
437 438 439
	{
	  Lisp_Object string;

440
	  string = AREF (items, i + 1);
441 442 443
	  if (NILP (string))
	    break;

444
	  wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
445
	  wv->button_type = BUTTON_TYPE_NONE;
446 447 448 449 450 451
	  /* This prevents lwlib from assuming this
	     menu item is really supposed to be empty.  */
	  /* The EMACS_INT cast avoids a warning.
	     This value just has to be different from small integers.  */
	  wv->call_data = (void *) (EMACS_INT) (-1);

452
	  if (prev_wv)
453 454 455 456 457 458
	    prev_wv->next = wv;
	  else
	    first_wv->contents = wv;
	  prev_wv = wv;
	}

459 460 461 462
      /* Forget what we thought we knew about what is in the
	 detailed contents of the menu bar menus.
	 Changing the top level always destroys the contents.  */
      f->menu_bar_items_used = 0;
463 464 465
    }

  /* Create or update the menu bar widget.  */
Geoff Voelker's avatar
Geoff Voelker committed
466

467
  block_input ();
Geoff Voelker's avatar
Geoff Voelker committed
468

469 470 471 472 473 474 475 476 477 478 479
  if (menubar_widget)
    {
      /* Empty current menubar, rather than creating a fresh one.  */
      while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
	;
    }
  else
    {
      menubar_widget = CreateMenu ();
    }
  fill_in_menu (menubar_widget, first_wv->contents);
Geoff Voelker's avatar
Geoff Voelker committed
480

481
  free_menubar_widget_value_tree (first_wv);
Geoff Voelker's avatar
Geoff Voelker committed
482

483 484
  {
    HMENU old_widget = f->output_data.w32->menubar_widget;
Geoff Voelker's avatar
Geoff Voelker committed
485

486 487
    f->output_data.w32->menubar_widget = menubar_widget;
    SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
488
    /* Causes flicker when menu bar is updated
489
    DrawMenuBar (FRAME_W32_WINDOW (f)); */
Geoff Voelker's avatar
Geoff Voelker committed
490

491 492 493
    /* Force the window size to be recomputed so that the frame's text
       area remains the same, if menubar has just been created.  */
    if (old_widget == NULL)
494 495 496 497
      {
	windows_or_buffers_changed = 23;
	adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
      }
Geoff Voelker's avatar
Geoff Voelker committed
498
  }
499

500
  unblock_input ();
Geoff Voelker's avatar
Geoff Voelker committed
501 502
}

503 504 505 506 507 508
/* Called from Fx_create_frame to create the initial menubar of a frame
   before it is mapped, so that the window is mapped with the menubar already
   there instead of us tacking it on later and thrashing the window after it
   is visible.  */

void
Dmitry Antipov's avatar
Dmitry Antipov committed
509
initialize_frame_menubar (struct frame *f)
510 511 512
{
  /* This function is called before the first chance to redisplay
     the frame.  It has to be, so the frame will have the right size.  */
513
  fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
514
  set_frame_menubar (f, true, true);
Geoff Voelker's avatar
Geoff Voelker committed
515 516
}

517 518 519 520
/* Get rid of the menu bar of frame F, and free its storage.
   This is used when deleting a frame, and when turning off the menu bar.  */

void
Dmitry Antipov's avatar
Dmitry Antipov committed
521
free_frame_menubar (struct frame *f)
522
{
523
  block_input ();
524 525 526 527 528 529 530

  {
    HMENU old = GetMenu (FRAME_W32_WINDOW (f));
    SetMenu (FRAME_W32_WINDOW (f), NULL);
    f->output_data.w32->menubar_widget = NULL;
    DestroyMenu (old);
  }
531

532
  unblock_input ();
533
}
Geoff Voelker's avatar
Geoff Voelker committed
534

535 536 537 538

/* w32_menu_show actually displays a menu using the panes and items in
   menu_items and returns the value selected from it; we assume input
   is blocked by the caller.  */
Geoff Voelker's avatar
Geoff Voelker committed
539 540 541 542

/* F is the frame the menu is for.
   X and Y are the frame-relative specified position,
   relative to the inside upper left corner of the frame F.
543 544 545
   Bitfield MENUFLAGS bits are:
   MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
   MENU_KEYMAPS is set if this menu was specified with keymaps;
546 547
    in that case, we return a list containing the chosen item's value
    and perhaps also the pane's prefix.
Geoff Voelker's avatar
Geoff Voelker committed
548 549 550 551
   TITLE is the specified menu title.
   ERROR is a place to store an error message string in case of failure.
   (We return nil on failure, but the value doesn't actually matter.)  */

552
Lisp_Object
553
w32_menu_show (struct frame *f, int x, int y, int menuflags,
554
	       Lisp_Object title, const char **error)
Geoff Voelker's avatar
Geoff Voelker committed
555
{
556 557 558
  int i;
  int menu_item_selection;
  HMENU menu;
Geoff Voelker's avatar
Geoff Voelker committed
559
  POINT pos;
560 561 562 563
  widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
  widget_value **submenu_stack
    = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
  Lisp_Object *subprefix_stack
564
    = (Lisp_Object *) alloca (menu_items_used * word_size);
565
  int submenu_depth = 0;
566
  bool first_pane;
567

Geoff Voelker's avatar
Geoff Voelker committed
568
  *error = NULL;
569

570 571 572
  if (menu_items_n_panes == 0)
    return Qnil;

573
  if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
Geoff Voelker's avatar
Geoff Voelker committed
574 575 576 577
    {
      *error = "Empty menu";
      return Qnil;
    }
578

579 580
  block_input ();

581 582
  /* Create a tree of widget_value objects
     representing the panes and their items.  */
583
  wv = make_widget_value ("menu", NULL, true, Qnil);
584
  wv->button_type = BUTTON_TYPE_NONE;
585
  first_wv = wv;
586
  first_pane = true;
587

588 589 590 591
  /* Loop over all panes and items, filling in the tree.  */
  i = 0;
  while (i < menu_items_used)
    {
592
      if (EQ (AREF (menu_items, i), Qnil))
593 594 595 596
	{
	  submenu_stack[submenu_depth++] = save_wv;
	  save_wv = prev_wv;
	  prev_wv = 0;
597
	  first_pane = false;
598 599
	  i++;
	}
600
      else if (EQ (AREF (menu_items, i), Qlambda))
601 602 603
	{
	  prev_wv = save_wv;
	  save_wv = submenu_stack[--submenu_depth];
604
	  first_pane = false;
605 606
	  i++;
	}
607
      else if (EQ (AREF (menu_items, i), Qt)
608 609 610 611
	       && submenu_depth != 0)
	i += MENU_ITEMS_PANE_LENGTH;
      /* Ignore a nil in the item list.
	 It's meaningful only for dialog boxes.  */
612
      else if (EQ (AREF (menu_items, i), Qquote))
613
	i += 1;
614
      else if (EQ (AREF (menu_items, i), Qt))
615 616 617
	{
	  /* Create a new pane.  */
	  Lisp_Object pane_name, prefix;
618
	  const char *pane_string;
619 620
	  pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
	  prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
621 622

	  if (STRINGP (pane_name))
623
	    {
624 625 626 627 628
	      if (unicode_append_menu)
		pane_name = ENCODE_UTF_8 (pane_name);
	      else if (STRING_MULTIBYTE (pane_name))
		pane_name = ENCODE_SYSTEM (pane_name);

629
	      ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
630
	    }
631

632
	  pane_string = (NILP (pane_name)
633
			 ? "" : SSDATA (pane_name));
634 635 636 637 638 639 640 641
	  /* If there is just one top-level pane, put all its items directly
	     under the top-level menu.  */
	  if (menu_items_n_panes == 1)
	    pane_string = "";

	  /* If the pane has a meaningful name,
	     make the pane a top-level menu item
	     with its items as a submenu beneath it.  */
642
	  if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
643
	    {
644
	      wv = make_widget_value (pane_string, NULL, true, Qnil);
645 646 647 648
	      if (save_wv)
		save_wv->next = wv;
	      else
		first_wv->contents = wv;
649
	      if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
650
		wv->name++;
651
	      wv->button_type = BUTTON_TYPE_NONE;
652 653 654 655 656 657 658 659
	      save_wv = wv;
	      prev_wv = 0;
	    }
	  else if (first_pane)
	    {
	      save_wv = wv;
	      prev_wv = 0;
	    }
660
	  first_pane = false;
661 662 663 664 665
	  i += MENU_ITEMS_PANE_LENGTH;
	}
      else
	{
	  /* Create a new item within current pane.  */
666 667
	  Lisp_Object item_name, enable, descrip, def, type, selected, help;

668 669 670 671 672 673 674
	  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);
	  type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
	  selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
          help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
675

676
          if (STRINGP (item_name))
677
	    {
678 679 680 681 682
	      if (unicode_append_menu)
		item_name = ENCODE_UTF_8 (item_name);
	      else if (STRING_MULTIBYTE (item_name))
		item_name = ENCODE_SYSTEM (item_name);

683
	      ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
684
	    }
685 686

	  if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
687 688
            {
	      descrip = ENCODE_SYSTEM (descrip);
689
	      ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
690
	    }
691

692
	  wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
693
				  STRINGP (help) ? help : Qnil);
694
	  if (prev_wv)
695
	    prev_wv->next = wv;
696
	  else
697 698
	    save_wv->contents = wv;
	  if (!NILP (descrip))
699
	    wv->key = SSDATA (descrip);
700
	  /* Use the contents index as call_data, since we are
701
             restricted to 16-bits.  */
702
	  wv->call_data = !NILP (def) ? (void *) (UINT_PTR) i : 0;
703 704 705 706 707 708 709 710

	  if (NILP (type))
	    wv->button_type = BUTTON_TYPE_NONE;
	  else if (EQ (type, QCtoggle))
	    wv->button_type = BUTTON_TYPE_TOGGLE;
	  else if (EQ (type, QCradio))
	    wv->button_type = BUTTON_TYPE_RADIO;
	  else
711
	    emacs_abort ();
712 713

	  wv->selected = !NILP (selected);
714

715 716 717 718 719 720 721 722 723
	  prev_wv = wv;

	  i += MENU_ITEMS_ITEM_LENGTH;
	}
    }

  /* Deal with the title, if it is non-nil.  */
  if (!NILP (title))
    {
724 725
      widget_value *wv_title;
      widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil);
726 727 728 729 730

      /* Maybe replace this separator with a bitmap or owner-draw item
	 so that it looks better.  Having two separators looks odd.  */
      wv_sep->next = first_wv->contents;

731 732 733
      if (unicode_append_menu)
	title = ENCODE_UTF_8 (title);
      else if (STRING_MULTIBYTE (title))
734
	title = ENCODE_SYSTEM (title);
735

736
      wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
737
      wv_title->title = TRUE;
738
      wv_title->button_type = BUTTON_TYPE_NONE;
739 740 741 742
      wv_title->next = wv_sep;
      first_wv->contents = wv_title;
    }

743 744 745
  /* No selection has been chosen yet.  */
  menu_item_selection = 0;

746
  /* Actually create the menu.  */
747
  current_popup_menu = menu = CreatePopupMenu ();
748
  fill_in_menu (menu, first_wv->contents);
749

750
  /* Adjust coordinates to be root-window-relative.  */
Geoff Voelker's avatar
Geoff Voelker committed
751 752
  pos.x = x;
  pos.y = y;
753
  ClientToScreen (FRAME_W32_WINDOW (f), &pos);
754

Geoff Voelker's avatar
Geoff Voelker committed
755
  /* Display the menu.  */
756
  menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
757 758
				     WM_EMACS_TRACKPOPUPMENU,
				     (WPARAM)menu, (LPARAM)&pos);
759 760 761 762

  /* Clean up extraneous mouse events which might have been generated
     during the call. */
  discard_mouse_events ();
763
  FRAME_DISPLAY_INFO (f)->grabbed = 0;
764

765 766 767
  /* Free the widget_value objects we used to specify the contents.  */
  free_menubar_widget_value_tree (first_wv);

768 769
  DestroyMenu (menu);

770 771
  /* Free the owner-drawn and help-echo menu strings.  */
  w32_free_menu_strings (FRAME_W32_WINDOW (f));
772
  f->output_data.w32->menubar_active = 0;
773

Geoff Voelker's avatar
Geoff Voelker committed
774 775
  /* Find the selected item, and its pane, to return
     the proper value.  */
776
  if (menu_item_selection != 0)
Geoff Voelker's avatar
Geoff Voelker committed
777
    {
778 779
      Lisp_Object prefix, entry;

780
      prefix = entry = Qnil;
781 782 783
      i = 0;
      while (i < menu_items_used)
	{
784
	  if (EQ (AREF (menu_items, i), Qnil))
785 786 787 788 789
	    {
	      subprefix_stack[submenu_depth++] = prefix;
	      prefix = entry;
	      i++;
	    }
790
	  else if (EQ (AREF (menu_items, i), Qlambda))
791 792 793 794
	    {
	      prefix = subprefix_stack[--submenu_depth];
	      i++;
	    }
795
	  else if (EQ (AREF (menu_items, i), Qt))
796
	    {
797
	      prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
798 799 800 801
	      i += MENU_ITEMS_PANE_LENGTH;
	    }
	  /* Ignore a nil in the item list.
	     It's meaningful only for dialog boxes.  */
802
	  else if (EQ (AREF (menu_items, i), Qquote))
803 804 805
	    i += 1;
	  else
	    {
806
	      entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
807 808
	      if (menu_item_selection == i)
		{
809
		  if (menuflags & MENU_KEYMAPS)
810 811 812 813 814 815 816 817 818 819
		    {
		      int j;

		      entry = Fcons (entry, Qnil);
		      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);
		    }
820
		  unblock_input ();
821 822 823 824 825
		  return entry;
		}
	      i += MENU_ITEMS_ITEM_LENGTH;
	    }
	}
Geoff Voelker's avatar
Geoff Voelker committed
826
    }
827
  else if (!(menuflags & MENU_FOR_CLICK))
828 829 830
    {
      unblock_input ();
      /* Make "Cancel" equivalent to C-g.  */
Paul Eggert's avatar
Paul Eggert committed
831
      quit ();
832
    }
833

834
  unblock_input ();
Geoff Voelker's avatar
Geoff Voelker committed
835 836
  return Qnil;
}
837

Geoff Voelker's avatar
Geoff Voelker committed
838

839
#ifdef HAVE_DIALOGS
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
/* TODO: On Windows, there are two ways of defining a dialog.

   1. Create a predefined dialog resource and include it in nt/emacs.rc.
      Using this method, we could then set the titles and make unneeded
      buttons invisible before displaying the dialog.  Everything would
      be a fixed size though, so there is a risk that text does not
      fit on a button.
   2. Create the dialog template in memory on the fly.  This allows us
      to size the dialog and buttons dynamically, probably giving more
      natural looking results for dialogs with few buttons, and eliminating
      the problem of text overflowing the buttons.  But the API for this is
      quite complex - structures have to be allocated in particular ways,
      text content is tacked onto the end of structures in variable length
      arrays with further structures tacked on after these, there are
      certain alignment requirements for all this, and we have to
      measure all the text and convert to "dialog coordinates" to figure
      out how big to make everything.

      For now, we'll just stick with menus for dialogs that are more
      complicated than simple yes/no type questions for which we can use
      the MessageBox function.
*/
862

863
static char * button_names [] = {
Geoff Voelker's avatar
Geoff Voelker committed
864
  "button1", "button2", "button3", "button4", "button5",
865
  "button6", "button7", "button8", "button9", "button10" };
Geoff Voelker's avatar
Geoff Voelker committed
866 867

static Lisp_Object
868 869
w32_dialog_show (struct frame *f, Lisp_Object title,
		 Lisp_Object header, char **error)
Geoff Voelker's avatar
Geoff Voelker committed
870
{
871
  int i, nb_buttons = 0;
Geoff Voelker's avatar
Geoff Voelker committed
872
  char dialog_name[6];
873 874
  int menu_item_selection;

875
  widget_value *wv, *first_wv = 0, *prev_wv = 0;
876

Geoff Voelker's avatar
Geoff Voelker committed
877 878
  /* Number of elements seen so far, before boundary.  */
  int left_count = 0;
879 880 881
  /* true means we've seen the boundary between left-hand elts and
     right-hand.  */
  bool boundary_seen = false;
882

Geoff Voelker's avatar
Geoff Voelker committed
883
  *error = NULL;
884

Geoff Voelker's avatar
Geoff Voelker committed
885 886 887 888 889
  if (menu_items_n_panes > 1)
    {
      *error = "Multiple panes in dialog box";
      return Qnil;
    }
890

Geoff Voelker's avatar
Geoff Voelker committed
891 892 893
  /* Create a tree of widget_value objects
     representing the text label and buttons.  */
  {
894
    Lisp_Object pane_name;
Geoff Voelker's avatar
Geoff Voelker committed
895
    char *pane_string;
896
    pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
Geoff Voelker's avatar
Geoff Voelker committed
897
    pane_string = (NILP (pane_name)
898
		   ? "" : SSDATA (pane_name));
899
    prev_wv = make_widget_value ("message", pane_string, true, Qnil);
Geoff Voelker's avatar
Geoff Voelker committed
900
    first_wv = prev_wv;
901

Geoff Voelker's avatar
Geoff Voelker committed
902 903 904 905
    /* Loop over all panes and items, filling in the tree.  */
    i = MENU_ITEMS_PANE_LENGTH;
    while (i < menu_items_used)
      {
906

Geoff Voelker's avatar
Geoff Voelker committed
907
	/* Create a new item within current pane.  */
908 909
	Lisp_Object item_name, enable, descrip, help;

910 911 912 913
	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);
        help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
914

Geoff Voelker's avatar
Geoff Voelker committed
915 916 917 918 919 920 921 922 923 924
	if (NILP (item_name))
	  {
	    free_menubar_widget_value_tree (first_wv);
	    *error = "Submenu in dialog items";
	    return Qnil;
	  }
	if (EQ (item_name, Qquote))
	  {
	    /* This is the boundary between left-side elts
	       and right-side elts.  Stop incrementing right_count.  */
925
	    boundary_seen = true;
Geoff Voelker's avatar
Geoff Voelker committed
926 927 928
	    i++;
	    continue;
	  }
929
	if (nb_buttons >= 9)
Geoff Voelker's avatar
Geoff Voelker committed
930 931 932 933 934
	  {
	    free_menubar_widget_value_tree (first_wv);
	    *error = "Too many dialog items";
	    return Qnil;
	  }
935

936 937 938
	wv = make_widget_value (button_names[nb_buttons],
				SSDATA (item_name),
				!NILP (enable), Qnil);
Geoff Voelker's avatar
Geoff Voelker committed
939 940
	prev_wv->next = wv;
	if (!NILP (descrip))
941
	  wv->key = SSDATA (descrip);
942
	wv->call_data = aref_addr (menu_items, i);
Geoff Voelker's avatar
Geoff Voelker committed
943
	prev_wv = wv;
944

Geoff Voelker's avatar
Geoff Voelker committed
945 946
	if (! boundary_seen)
	  left_count++;
947

Geoff Voelker's avatar
Geoff Voelker committed
948 949 950
	nb_buttons++;
	i += MENU_ITEMS_ITEM_LENGTH;
      }
951

Geoff Voelker's avatar
Geoff Voelker committed
952 953 954 955
    /* If the boundary was not specified,
       by default put half on the left and half on the right.  */
    if (! boundary_seen)
      left_count = nb_buttons - nb_buttons / 2;
956

957
    wv = make_widget_value (dialog_name, NULL, false, Qnil);
958

959 960 961
    /*  Frame title: 'Q' = Question, 'I' = Information.
        Can also have 'E' = Error if, one day, we want
        a popup for errors. */
962
    if (NILP (header))
963 964 965 966
      dialog_name[0] = 'Q';
    else
      dialog_name[0] = 'I';

Geoff Voelker's avatar
Geoff Voelker committed
967 968
    /* Dialog boxes use a really stupid name encoding
       which specifies how many buttons to use
969
       and how many buttons are on the right. */
Geoff Voelker's avatar
Geoff Voelker committed
970 971 972 973 974 975 976 977 978
    dialog_name[1] = '0' + nb_buttons;
    dialog_name[2] = 'B';
    dialog_name[3] = 'R';
    /* Number of buttons to put on the right.  */
    dialog_name[4] = '0' + nb_buttons - left_count;
    dialog_name[5] = 0;
    wv->contents = first_wv;
    first_wv = wv;
  }
979

Geoff Voelker's avatar
Geoff Voelker committed
980
  /* Actually create the dialog.  */
981
  dialog_id = widget_id_tick++;
Geoff Voelker's avatar
Geoff Voelker committed
982
  menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
983
			   f->output_data.w32->widget, true, 0,
Geoff Voelker's avatar
Geoff Voelker committed
984
			   dialog_selection_callback, 0);
985
  lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
986

Geoff Voelker's avatar
Geoff Voelker committed
987 988
  /* Free the widget_value objects we used to specify the contents.  */
  free_menubar_widget_value_tree (first_wv);
989

Geoff Voelker's avatar
Geoff Voelker committed
990 991
  /* No selection has been chosen yet.  */
  menu_item_selection = 0;
992

Geoff Voelker's avatar
Geoff Voelker committed
993 994
  /* Display the menu.  */
  lw_pop_up_all_widgets (dialog_id);
995

Geoff Voelker's avatar
Geoff Voelker committed
996
  /* Process events that apply to the menu.  */
997
  popup_get_selection ((XEvent *) 0, FRAME_DISPLAY_INFO (f), dialog_id);
Geoff Voelker's avatar
Geoff Voelker committed
998

999
  lw_destroy_all_widgets (dialog_id);
Geoff Voelker's avatar
Geoff Voelker committed
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009

  /* Find the selected item, and its pane, to return
     the proper value.  */
  if (menu_item_selection != 0)
    {
      i = 0;
      while (i < menu_items_used)
	{
	  Lisp_Object entry;

1010
	  if (EQ (AREF (menu_items, i), Qt))
1011
	    i += MENU_ITEMS_PANE_LENGTH;
Geoff Voelker's avatar
Geoff Voelker committed
1012 1013
	  else
	    {