changeset 93979:b8d983c8a6d0

(is_simple_dialog, simple_dialog_show): New functions. (Fx_popup_dialog): Handle simple yes/no questions as dialogs.
author Jason Rumney <jasonr@gnu.org>
date Thu, 10 Apr 2008 15:19:43 +0000
parents 09cd83051653
children bbbb3f6811ea
files src/w32menu.c
diffstat 1 files changed, 160 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/w32menu.c	Thu Apr 10 15:05:46 2008 +0000
+++ b/src/w32menu.c	Thu Apr 10 15:19:43 2008 +0000
@@ -168,22 +168,28 @@
 
 extern Lisp_Object Qmenu_bar_update_hook;
 
-void set_frame_menubar ();
+void set_frame_menubar P_ ((FRAME_PTR, int, int));
 
 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
 				Lisp_Object, Lisp_Object, Lisp_Object,
 				Lisp_Object, Lisp_Object));
 #ifdef HAVE_DIALOGS
-static Lisp_Object w32_dialog_show ();
+static Lisp_Object w32_dialog_show P_ ((FRAME_PTR, int, Lisp_Object, char**));
+#else
+static int is_simple_dialog P_ ((Lisp_Object));
+static Lisp_Object simple_dialog_show P_ ((FRAME_PTR, Lisp_Object, Lisp_Object));
 #endif
-static Lisp_Object w32_menu_show ();
-
-static void keymap_panes ();
-static void single_keymap_panes ();
-static void single_menu_item ();
-static void list_of_panes ();
-static void list_of_items ();
-void w32_free_menu_strings (HWND);
+static Lisp_Object w32_menu_show P_ ((FRAME_PTR, int, int, int, int,
+				      Lisp_Object, char **));
+
+static void keymap_panes P_ ((Lisp_Object *, int, int));
+static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+				     int, int));
+static void single_menu_item P_ ((Lisp_Object, Lisp_Object,
+				  Lisp_Object *, int, int));
+static void list_of_panes P_ ((Lisp_Object));
+static void list_of_items P_ ((Lisp_Object));
+void w32_free_menu_strings P_((HWND));
 
 /* This holds a Lisp vector that holds the results of decoding
    the keymaps or alist-of-alists that specify a menu.
@@ -928,17 +934,23 @@
     CHECK_WINDOW (window);
 
 #ifndef HAVE_DIALOGS
-  /* Display a menu with these alternatives
-     in the middle of frame F.  */
+
   {
-    Lisp_Object x, y, frame, newpos;
-    XSETFRAME (frame, f);
-    XSETINT (x, x_pixel_width (f) / 2);
-    XSETINT (y, x_pixel_height (f) / 2);
-    newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
-
-    return Fx_popup_menu (newpos,
-			  Fcons (Fcar (contents), Fcons (contents, Qnil)));
+    /* Handle simple Yes/No choices as MessageBox popups.  */
+    if (is_simple_dialog (contents))
+      return simple_dialog_show (f, contents, header);
+    else
+      {
+	/* Display a menu with these alternatives
+	   in the middle of frame F.  */
+	Lisp_Object x, y, frame, newpos;
+	XSETFRAME (frame, f);
+	XSETINT (x, x_pixel_width (f) / 2);
+	XSETINT (y, x_pixel_height (f) / 2);
+	newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
+	return Fx_popup_menu (newpos,
+			      Fcons (Fcar (contents), Fcons (contents, Qnil)));
+      }
   }
 #else /* HAVE_DIALOGS */
   {
@@ -2001,6 +2013,29 @@
 
 
 #ifdef HAVE_DIALOGS
+/* 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.
+*/
+      
 static char * button_names [] = {
   "button1", "button2", "button3", "button4", "button5",
   "button6", "button7", "button8", "button9", "button10" };
@@ -2192,7 +2227,111 @@
 
   return Qnil;
 }
-#endif  /* HAVE_DIALOGS  */
+#else /* !HAVE_DIALOGS  */
+
+/* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
+   simple dialogs.  We could handle a few more, but I'm not aware of
+   anywhere in Emacs that uses the other specific dialog choices that
+   MessageBox provides.  */
+
+static int is_simple_dialog (contents)
+  Lisp_Object contents;
+{
+  Lisp_Object options = XCDR (contents);
+  Lisp_Object name, yes, no, other;
+
+  yes = build_string ("Yes");
+  no = build_string ("No");
+
+  if (!CONSP (options))
+    return 0;
+
+  name = XCAR (XCAR (options));
+  if (!CONSP (options))
+    return 0;
+
+  if (!NILP (Fstring_equal (name, yes)))
+    other = no;
+  else if (!NILP (Fstring_equal (name, no)))
+    other = yes;
+  else
+    return 0;
+
+  options = XCDR (options);
+  if (!CONSP (options))
+    return 0;
+
+  name = XCAR (XCAR (options));
+  if (NILP (Fstring_equal (name, other)))
+    return 0;
+
+  /* Check there are no more options.  */
+  options = XCDR (options);
+  return !(CONSP (options));
+}
+
+static Lisp_Object simple_dialog_show (f, contents, header)
+     FRAME_PTR f;
+     Lisp_Object contents, header;
+{
+  int answer;
+  UINT type;
+  char *text, *title;
+  Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
+
+  if (STRINGP (temp))
+    text = SDATA (temp);
+  else
+    text = "";
+
+  if (NILP (header))
+    {
+      title = "Question";
+      type = MB_ICONQUESTION;
+    }
+  else
+    {
+      title = "Information";
+      type = MB_ICONINFORMATION;
+    }
+  type |= MB_YESNO;
+
+  /* Since we only handle Yes/No dialogs, and we already checked
+     is_simple_dialog, we don't need to worry about checking contents
+     to see what type of dialog to use.  */
+  answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
+
+  if (answer == IDYES)
+    lispy_answer = build_string ("Yes");
+  else if (answer == IDNO)
+    lispy_answer = build_string ("No");
+  else
+    Fsignal (Qquit, Qnil);
+
+  for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
+    {
+      Lisp_Object item, name, value;
+      item = XCAR (temp);
+      if (CONSP (item))
+	{
+	  name = XCAR (item);
+	  value = XCDR (item);
+	}
+      else
+	{
+	  name = item;
+	  value = Qnil;
+	}
+
+      if (!NILP (Fstring_equal (name, lispy_answer)))
+	{
+	  return value;
+	}
+    }
+  Fsignal (Qquit, Qnil);
+  return Qnil;
+}
+#endif  /* !HAVE_DIALOGS  */
 
 
 /* Is this item a separator? */