Separate read and write access to Lisp_Object slots of struct window.
[bpt/emacs.git] / src / w32menu.c
index c31a8c1..80f48bd 100644 (file)
@@ -1,5 +1,5 @@
-/* Menu support for GNU Emacs on the Microsoft W32 API.
-   Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2011
+/* Menu support for GNU Emacs on the Microsoft Windows API.
+   Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2012
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -31,6 +31,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "termhooks.h"
 #include "window.h"
 #include "blockinput.h"
+#include "character.h"
 #include "buffer.h"
 #include "charset.h"
 #include "coding.h"
@@ -48,6 +49,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "dispextern.h"
 
+#include "w32heap.h"   /* for osinfo_cache */
+
 #undef HAVE_DIALOGS /* TODO: Implement native dialogs.  */
 
 #ifndef TRUE
@@ -159,13 +162,12 @@ otherwise it is "Question". */)
     }
   else if (CONSP (position))
     {
-      Lisp_Object tem;
-      tem = Fcar (position);
+      Lisp_Object tem = XCAR (position);
       if (CONSP (tem))
-       window = Fcar (Fcdr (position));
+       window = Fcar (XCDR (position));
       else
        {
-         tem = Fcar (Fcdr (position));  /* EVENT_START (position) */
+         tem = Fcar (XCDR (position));  /* EVENT_START (position) */
          window = Fcar (tem);       /* POSN_WINDOW (tem) */
        }
     }
@@ -274,8 +276,8 @@ menubar_selection_callback (FRAME_PTR f, void * client_data)
   if (!f)
     return;
   entry = Qnil;
-  subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
-  vector = f->menu_bar_vector;
+  subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size);
+  vector = FGET (f, menu_bar_vector);
   prefix = Qnil;
   i = 0;
   while (i < f->menu_bar_items_used)
@@ -381,18 +383,18 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
 
       struct buffer *prev = current_buffer;
       Lisp_Object buffer;
-      int specpdl_count = SPECPDL_INDEX ();
+      ptrdiff_t specpdl_count = SPECPDL_INDEX ();
       int previous_menu_items_used = f->menu_bar_items_used;
       Lisp_Object *previous_items
        = (Lisp_Object *) alloca (previous_menu_items_used
-                                 * sizeof (Lisp_Object));
+                                 * word_size);
 
       /* If we are making a new widget, its contents are empty,
         do always reinitialize them.  */
       if (! menubar_widget)
        previous_menu_items_used = 0;
 
-      buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
+      buffer = WGET (XWINDOW (FRAME_SELECTED_WINDOW (f)), buffer);
       specbind (Qinhibit_quit, Qt);
       /* Don't let the debugger step into this code
         because it is not reentrant.  */
@@ -417,14 +419,14 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
 
       /* Save the frame's previous menu bar contents data.  */
       if (previous_menu_items_used)
-       memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
-               previous_menu_items_used * sizeof (Lisp_Object));
+       memcpy (previous_items, XVECTOR (FGET (f, menu_bar_vector))->contents,
+               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 = FGET (f, menu_bar_vector);
       menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
       submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
       submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
@@ -498,7 +500,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
          return;
        }
 
-      f->menu_bar_vector = menu_items;
+      FSET (f, menu_bar_vector, menu_items);
       f->menu_bar_items_used = menu_items_used;
 
       /* This undoes save_menu_items.  */
@@ -663,7 +665,7 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   widget_value **submenu_stack
     = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
   Lisp_Object *subprefix_stack
-    = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
+    = (Lisp_Object *) alloca (menu_items_used * word_size);
   int submenu_depth = 0;
   int first_pane;
 
@@ -1060,7 +1062,7 @@ w32_dialog_show (FRAME_PTR f, int keymaps,
        if (!NILP (descrip))
          wv->key = SSDATA (descrip);
        wv->value = SSDATA (item_name);
-       wv->call_data = (void *) &AREF (menu_items, i);
+       wv->call_data = aref_addr (menu_items, i);
        wv->enabled = !NILP (enable);
        wv->help = Qnil;
        prev_wv = wv;
@@ -1173,18 +1175,23 @@ w32_dialog_show (FRAME_PTR f, int keymaps,
 static int
 is_simple_dialog (Lisp_Object contents)
 {
-  Lisp_Object options = XCDR (contents);
+  Lisp_Object options;
   Lisp_Object name, yes, no, other;
 
+  if (!CONSP (contents))
+    return 0;
+  options = XCDR (contents);
+
   yes = build_string ("Yes");
   no = build_string ("No");
 
   if (!CONSP (options))
     return 0;
 
-  name = XCAR (XCAR (options));
-  if (!CONSP (options))
+  name = XCAR (options);
+  if (!CONSP (name))
     return 0;
+  name = XCAR (name);
 
   if (!NILP (Fstring_equal (name, yes)))
     other = no;
@@ -1197,7 +1204,10 @@ is_simple_dialog (Lisp_Object contents)
   if (!CONSP (options))
     return 0;
 
-  name = XCAR (XCAR (options));
+  name = XCAR (options);
+  if (!CONSP (name))
+    return 0;
+  name = XCAR (name);
   if (NILP (Fstring_equal (name, other)))
     return 0;
 
@@ -1219,10 +1229,11 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
      is_simple_dialog, we don't need to worry about checking contents
      to see what type of dialog to use.  */
 
-  /* Use unicode if possible, so any language can be displayed.  */
+  /* Use Unicode if possible, so any language can be displayed.  */
   if (unicode_message_box)
     {
       WCHAR *text, *title;
+      USE_SAFE_ALLOCA;
 
       if (STRINGP (temp))
        {
@@ -1232,7 +1243,7 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
             one utf16 word, so we cannot simply use the character
             length of temp.  */
          int utf8_len = strlen (utf8_text);
-         text = alloca ((utf8_len + 1) * sizeof (WCHAR));
+         text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
          utf8to16 (utf8_text, utf8_len, text);
        }
       else
@@ -1252,6 +1263,7 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
        }
 
       answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
+      SAFE_FREE ();
     }
   else
     {
@@ -1358,6 +1370,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
   char *out_string, *p, *q;
   int return_value;
   size_t nlen, orig_len;
+  USE_SAFE_ALLOCA;
 
   if (menu_separator_name_p (wv->name))
     {
@@ -1373,7 +1386,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
 
       if (wv->key != NULL)
        {
-         out_string = alloca (strlen (wv->name) + strlen (wv->key) + 2);
+         out_string = SAFE_ALLOCA (strlen (wv->name) + strlen (wv->key) + 2);
          strcpy (out_string, wv->name);
          strcat (out_string, "\t");
          strcat (out_string, wv->key);
@@ -1407,7 +1420,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
       if (nlen > orig_len)
         {
           p = out_string;
-          out_string = alloca (nlen + 1);
+          out_string = SAFE_ALLOCA (nlen + 1);
           q = out_string;
           while (*p)
             {
@@ -1443,7 +1456,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
               out_string = (char *) local_alloc (strlen (wv->name) + 1);
               strcpy (out_string, wv->name);
 #ifdef MENU_DEBUG
-             DebPrint ("Menu: allocing %ld for owner-draw", out_string);
+             DebPrint ("Menu: allocating %ld for owner-draw", out_string);
 #endif
              fuFlags = MF_OWNERDRAW | MF_DISABLED;
            }
@@ -1467,7 +1480,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
       if (fuFlags & MF_OWNERDRAW)
        utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
       else
-       utf16_string = alloca ((utf8_len + 1) * sizeof (WCHAR));
+       utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
 
       utf8to16 (out_string, utf8_len, utf16_string);
       return_value = unicode_append_menu (menu, fuFlags,
@@ -1476,7 +1489,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
                                          utf16_string);
       if (!return_value)
        {
-         /* On W9x/ME, unicode menus are not supported, though AppendMenuW
+         /* On W9x/ME, Unicode menus are not supported, though AppendMenuW
             apparently does exist at least in some cases and appears to be
             stubbed out to do nothing.  out_string is UTF-8, but since
             our standard menus are in English and this is only going to
@@ -1486,8 +1499,11 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
            AppendMenu (menu, fuFlags,
                        item != NULL ? (UINT) item: (UINT) wv->call_data,
                        out_string);
-         /* Don't use unicode menus in future.  */
-         unicode_append_menu = NULL;
+         /* Don't use Unicode menus in future, unless this is Windows
+            NT or later, where a failure of AppendMenuW does NOT mean
+            Unicode menus are unsupported.  */
+         if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT)
+           unicode_append_menu = NULL;
        }
 
       if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
@@ -1516,11 +1532,14 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
             until it is ready to be displayed, since GC can happen while
             menus are active.  */
          if (!NILP (wv->help))
-#ifdef USE_LISP_UNION_TYPE
-           info.dwItemData = (DWORD) (wv->help).i;
-#else
-           info.dwItemData = (DWORD) (wv->help);
-#endif
+           {
+             /* As of Jul-2012, w32api headers say that dwItemData
+                has DWORD type, but that's a bug: it should actually
+                be ULONG_PTR, which is correct for 32-bit and 64-bit
+                Windows alike.  MSVC headers get it right; hopefully,
+                MinGW headers will, too.  */
+             info.dwItemData = (ULONG_PTR) XLI (wv->help);
+           }
          if (wv->button_type == BUTTON_TYPE_RADIO)
            {
              /* CheckMenuRadioItem allows us to differentiate TOGGLE and
@@ -1536,6 +1555,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item)
                              FALSE, &info);
        }
     }
+  SAFE_FREE ();
   return return_value;
 }
 
@@ -1594,12 +1614,7 @@ w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
          info.fMask = MIIM_DATA;
          get_menu_item_info (menu, item, FALSE, &info);
 
-#ifdef USE_LISP_UNION_TYPE
-         help = info.dwItemData ? (Lisp_Object) ((EMACS_INT) info.dwItemData)
-                                : Qnil;
-#else
-         help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
-#endif
+         help = info.dwItemData ? XIL (info.dwItemData) : Qnil;
        }
 
       /* Store the help echo in the keyboard buffer as the X toolkit