changeset 111991:968255ee954a

Support for menu separators in the GTK tool-bar. * src/gtkutil.c (XG_BIN_CHILD): New macro. (xg_get_menu_item_label, xg_update_menubar) (xg_update_menu_item, xg_tool_bar_menu_proxy) (xg_show_toolbar_item, update_frame_tool_bar): Use it. (separator_names, xg_separator_p): Move to keyboard.c. (create_menus, xg_update_submenu, update_frame_tool_bar): Use menu_separator_name_p. * src/keyboard.c (parse_tool_bar_item): Allow menu separators in tool-bar maps. (menu_separator_name_p): New function, from gtkutil.c. (separator_names): Move from gtkutil.c. * src/keyboard.h (menu_separator_name_p): Add prototype. * src/nsmenu.m (name_is_separator): Function deleted. (addItemWithWidgetValue): Use menu_separator_name_p. * src/w32menu.c (name_is_separator): Function deleted. (add_menu_item): Use menu_separator_name_p.
author Chong Yidong <cyd@stupidchicken.com>
date Fri, 17 Dec 2010 12:04:06 +0800
parents fd7dd167d6e5
children 7e4ae0dd59c9
files etc/NEWS lisp/ChangeLog lisp/menu-bar.el lisp/tool-bar.el src/ChangeLog src/dispextern.h src/gtkutil.c src/keyboard.c src/keyboard.h src/nsmenu.m src/w32menu.c src/xdisp.c
diffstat 12 files changed, 162 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/etc/NEWS	Fri Dec 17 10:43:03 2010 +0900
+++ b/etc/NEWS	Fri Dec 17 12:04:06 2010 +0800
@@ -690,6 +690,11 @@
 triplet, instead of signalling an error if the user provides a invalid
 input.
 
+** Tool-bars can display separators.
+Tool-bar separators are handled like menu separators in menu-bar maps,
+i.e. with entries of the form `(menu-item "--")'.
+
+Currently, tool-bar separators are only displayed on GTK.
 
 ** Image API
 
--- a/lisp/ChangeLog	Fri Dec 17 10:43:03 2010 +0900
+++ b/lisp/ChangeLog	Fri Dec 17 12:04:06 2010 +0800
@@ -1,3 +1,9 @@
+2010-12-16  Chong Yidong  <cyd@stupidchicken.com>
+
+	* tool-bar.el (tool-bar-setup): Add separators.
+
+	* menu-bar.el (featurep): Use menu-bar-separator.
+
 2010-12-16  Daiki Ueno  <ueno@unixuser.org>
 
 	* epa-file.el (epa-file-select-keys): Accept 'silent to inhibit
--- a/lisp/menu-bar.el	Fri Dec 17 10:43:03 2010 +0900
+++ b/lisp/menu-bar.el	Fri Dec 17 12:04:06 2010 +0800
@@ -523,7 +523,8 @@
 	      ,(purecopy "Cut (kill) text in region between mark and current position")))
 ;; ns-win.el said: Separate undo from cut/paste section.
 (if (featurep 'ns)
-    (define-key menu-bar-edit-menu [separator-undo] `(,(purecopy "--"))))
+    (define-key menu-bar-edit-menu [separator-undo] menu-bar-separator))
+
 (define-key menu-bar-edit-menu [undo]
   `(menu-item ,(purecopy "Undo") undo
 	      :enable (and (not buffer-read-only)
--- a/lisp/tool-bar.el	Fri Dec 17 10:43:03 2010 +0900
+++ b/lisp/tool-bar.el	Fri Dec 17 12:04:06 2010 +0800
@@ -257,23 +257,23 @@
 ;;; Set up some global items.  Additions/deletions up for grabs.
 
 (defun tool-bar-setup ()
-  ;; People say it's bad to have EXIT on the tool bar, since users
-  ;; might inadvertently click that button.
-  ;;(tool-bar-add-item-from-menu 'save-buffers-kill-emacs "exit")
   (tool-bar-add-item-from-menu 'find-file "new" nil :label "New File"
 			       :vert-only t)
   (tool-bar-add-item-from-menu 'menu-find-file-existing "open" nil
-			       :vert-only t)
+			       :label "Open" :vert-only t)
   (tool-bar-add-item-from-menu 'dired "diropen" nil :vert-only t)
   (tool-bar-add-item-from-menu 'kill-this-buffer "close" nil :vert-only t)
   (tool-bar-add-item-from-menu 'save-buffer "save" nil :vert-only t
+			       :label "Save"
 			       :visible '(or buffer-file-name
 					     (not (eq 'special
 						      (get major-mode
 							   'mode-class)))))
+  (define-key-after (default-value 'tool-bar-map) [separator-1] menu-bar-separator)
   (tool-bar-add-item-from-menu 'undo "undo" nil :vert-only t
 			       :visible '(not (eq 'special (get major-mode
 								'mode-class))))
+  (define-key-after (default-value 'tool-bar-map) [separator-2] menu-bar-separator)
   (tool-bar-add-item-from-menu (lookup-key menu-bar-edit-menu [cut])
 			       "cut" nil :vert-only t
 			       :visible '(not (eq 'special (get major-mode
@@ -284,6 +284,7 @@
 			       "paste" nil :vert-only t
 			       :visible '(not (eq 'special (get major-mode
 								'mode-class))))
+  (define-key-after (default-value 'tool-bar-map) [separator-3] menu-bar-separator)
   (tool-bar-add-item-from-menu 'nonincremental-search-forward "search"
 			       nil :label "Search")
   ;;(tool-bar-add-item-from-menu 'ispell-buffer "spell")
--- a/src/ChangeLog	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/ChangeLog	Fri Dec 17 12:04:06 2010 +0800
@@ -1,3 +1,26 @@
+2010-12-17  Chong Yidong  <cyd@stupidchicken.com>
+
+	* keyboard.c (parse_tool_bar_item): Allow menu separators in
+	tool-bar maps.
+	(menu_separator_name_p): New function, from gtkutil.c.
+	(separator_names): Move from gtkutil.c.
+
+	* keyboard.h (menu_separator_name_p): Add prototype.
+
+	* gtkutil.c (XG_BIN_CHILD): New macro.
+	(xg_get_menu_item_label, xg_update_menubar)
+	(xg_update_menu_item, xg_tool_bar_menu_proxy)
+	(xg_show_toolbar_item, update_frame_tool_bar): Use it.
+	(separator_names, xg_separator_p): Move to keyboard.c.
+	(create_menus, xg_update_submenu, update_frame_tool_bar): Use
+	menu_separator_name_p.
+
+	* nsmenu.m (name_is_separator): Function deleted.
+	(addItemWithWidgetValue): Use menu_separator_name_p.
+
+	* w32menu.c (name_is_separator): Function deleted.
+	(add_menu_item): Use menu_separator_name_p.
+
 2010-12-16  Jan Djärv  <jan.h.d@swipnet.se>
 
 	* nsterm.m (ns_draw_window_cursor): If the cursor color is the
--- a/src/dispextern.h	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/dispextern.h	Fri Dec 17 12:04:06 2010 +0800
@@ -2881,7 +2881,8 @@
   /* The binding.  */
   TOOL_BAR_ITEM_BINDING,
 
-  /* Button type.  One of nil, `:radio' or `:toggle'.  */
+  /* Button type.  One of nil (default button), t (a separator),
+     `:radio', or `:toggle'.  The latter two currently do nothing.  */
   TOOL_BAR_ITEM_TYPE,
 
   /* Help string.  */
--- a/src/gtkutil.c	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/gtkutil.c	Fri Dec 17 12:04:06 2010 +0800
@@ -72,6 +72,8 @@
 #define remove_submenu(w) gtk_menu_item_remove_submenu ((w))
 #endif
 
+#define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x))
+
 
 /***********************************************************************
                       Display handling functions
@@ -2128,54 +2130,6 @@
   return w;
 }
 
-/* Return non-zero if LABEL specifies a separator (GTK only has one
-   separator type)  */
-
-static const char* separator_names[] = {
-  "space",
-  "no-line",
-  "single-line",
-  "double-line",
-  "single-dashed-line",
-  "double-dashed-line",
-  "shadow-etched-in",
-  "shadow-etched-out",
-  "shadow-etched-in-dash",
-  "shadow-etched-out-dash",
-  "shadow-double-etched-in",
-  "shadow-double-etched-out",
-  "shadow-double-etched-in-dash",
-  "shadow-double-etched-out-dash",
-  0,
-};
-
-static int
-xg_separator_p (const char *label)
-{
-  if (! label) return 0;
-  else if (strlen (label) > 3
-	   && strncmp (label, "--", 2) == 0
-	   && label[2] != '-')
-    {
-      int i;
-
-      label += 2;
-      for (i = 0; separator_names[i]; ++i)
-	if (strcmp (label, separator_names[i]) == 0)
-          return 1;
-    }
-  else
-    {
-      /* Old-style separator, maybe.  It's a separator if it contains
-	 only dashes.  */
-      while (*label == '-')
-	++label;
-      if (*label == 0) return 1;
-    }
-
-  return 0;
-}
-
 static int xg_detached_menus;
 
 /* Returns non-zero if there are detached menus.  */
@@ -2374,7 +2328,7 @@
       GtkWidget *w;
 
       if (pop_up_p && !item->contents && !item->call_data
-          && !xg_separator_p (item->name))
+          && !menu_separator_name_p (item->name))
         {
           char *utf8_label;
           /* A title for a popup.  We do the same as GTK does when
@@ -2387,7 +2341,7 @@
           gtk_widget_set_sensitive (w, FALSE);
           if (utf8_label) g_free (utf8_label);
         }
-      else if (xg_separator_p (item->name))
+      else if (menu_separator_name_p (item->name))
         {
           group = NULL;
           /* GTK only have one separator type.  */
@@ -2499,7 +2453,7 @@
 static const char *
 xg_get_menu_item_label (GtkMenuItem *witem)
 {
-  GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
+  GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
   return gtk_label_get_label (wlabel);
 }
 
@@ -2652,7 +2606,7 @@
                 Rename X to B (minibuf to C-mode menu).
               If the X menu hasn't been invoked, the menu under B
               is up to date when leaving the minibuffer.  */
-          GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem)));
+          GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
           char *utf8_label = get_utf8_string (val->name);
           GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
 
@@ -2751,7 +2705,7 @@
   const char *old_key = 0;
   xg_menu_item_cb_data *cb_data;
 
-  wchild = gtk_bin_get_child (GTK_BIN (w));
+  wchild = XG_BIN_CHILD (w);
   utf8_label = get_utf8_string (val->name);
   utf8_key = get_utf8_string (val->key);
 
@@ -2910,7 +2864,7 @@
 
     if (GTK_IS_SEPARATOR_MENU_ITEM (w))
       {
-        if (! xg_separator_p (cur->name))
+        if (! menu_separator_name_p (cur->name))
           break;
       }
     else if (GTK_IS_CHECK_MENU_ITEM (w))
@@ -2933,7 +2887,7 @@
         GtkWidget *sub;
 
         if (cur->button_type != BUTTON_TYPE_NONE ||
-            xg_separator_p (cur->name))
+            menu_separator_name_p (cur->name))
           break;
 
         xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
@@ -3725,9 +3679,8 @@
 static gboolean
 xg_tool_bar_menu_proxy (GtkToolItem *toolitem, gpointer user_data)
 {
-  GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (toolitem));
-  GtkButton *wbutton = GTK_BUTTON (gtk_bin_get_child (GTK_BIN (weventbox)));
-  GtkWidget *vb = gtk_bin_get_child (GTK_BIN (wbutton));
+  GtkButton *wbutton = GTK_BUTTON (XG_BIN_CHILD (XG_BIN_CHILD (toolitem)));
+  GtkWidget *vb = XG_BIN_CHILD (wbutton);
   GtkWidget *c1;
   GtkLabel *wlbl = GTK_LABEL (xg_get_tool_bar_widgets (vb, &c1));
   GtkImage *wimage = GTK_IMAGE (c1);
@@ -4180,9 +4133,9 @@
   int show_label = ! EQ (style, Qimage) && ! (vert_only && horiz);
   int show_image = ! EQ (style, Qtext);
 
-  GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (ti));
-  GtkWidget *wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
-  GtkWidget *vb = gtk_bin_get_child (GTK_BIN (wbutton));
+  GtkWidget *weventbox = XG_BIN_CHILD (ti);
+  GtkWidget *wbutton = XG_BIN_CHILD (weventbox);
+  GtkWidget *vb = XG_BIN_CHILD (wbutton);
   GtkWidget *wimage;
   GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
   GtkWidget *new_box = NULL;
@@ -4330,7 +4283,6 @@
       char *icon_name = NULL;
       Lisp_Object rtl;
       GtkWidget *wbutton = NULL;
-      GtkWidget *weventbox;
       Lisp_Object specified_file;
       const char *label = (STRINGP (PROP (TOOL_BAR_ITEM_LABEL))
                            ? SSDATA (PROP (TOOL_BAR_ITEM_LABEL)) : "");
@@ -4338,16 +4290,34 @@
 
       ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), i);
 
+      /* If this is a separator, use a gtk separator item.  */
+      if (EQ (PROP (TOOL_BAR_ITEM_TYPE), Qt))
+	{
+	  if (ti == NULL || !GTK_IS_SEPARATOR_TOOL_ITEM (ti))
+	    {
+	      if (ti)
+		gtk_container_remove (GTK_CONTAINER (wtoolbar),
+				      GTK_WIDGET (ti));
+	      ti = gtk_separator_tool_item_new ();
+	      gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, i);
+	    }
+	  gtk_widget_show (GTK_WIDGET (ti));
+	  continue;
+	}
+
+      /* Otherwise, the tool-bar item is an ordinary button.  */
+
+      if (ti && GTK_IS_SEPARATOR_TOOL_ITEM (ti))
+	{
+	  gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti));
+	  ti = NULL;
+	}
+
       if (ti)
-        {
-          weventbox = gtk_bin_get_child (GTK_BIN (ti));
-          wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
-        }
-
-
-      image = PROP (TOOL_BAR_ITEM_IMAGES);
+	wbutton = XG_BIN_CHILD (XG_BIN_CHILD (ti));
 
       /* Ignore invalid image specifications.  */
+      image = PROP (TOOL_BAR_ITEM_IMAGES);
       if (!valid_image_p (image))
         {
           if (wbutton) gtk_widget_hide (wbutton);
@@ -4426,7 +4396,7 @@
                 {
                   /* Insert an empty (non-image) button */
                   ti = xg_make_tool_item (f, NULL, NULL, "", i, 0);
-                  gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, -1);
+                  gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, i);
                 }
               continue;
             }
@@ -4460,17 +4430,17 @@
 
           gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
           ti = xg_make_tool_item (f, w, &wbutton, label, i, vert_only);
-          gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, -1);
+          gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, i);
           gtk_widget_set_sensitive (wbutton, enabled_p);
         }
       else
         {
-          GtkWidget *vb = gtk_bin_get_child (GTK_BIN (wbutton));
+          GtkWidget *vb = XG_BIN_CHILD (wbutton);
           GtkWidget *wimage;
           GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
 
-          Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage),
-                                                      XG_TOOL_BAR_IMAGE_DATA);
+          Pixmap old_img = (Pixmap) g_object_get_data (G_OBJECT (wimage),
+						       XG_TOOL_BAR_IMAGE_DATA);
           gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage),
                                                        XG_TOOL_BAR_STOCK_NAME);
           gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage),
--- a/src/keyboard.c	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/keyboard.c	Fri Dec 17 12:04:06 2010 +0800
@@ -7464,6 +7464,54 @@
 static Lisp_Object menu_bar_items_vector;
 static int menu_bar_items_index;
 
+
+static const char* separator_names[] = {
+  "space",
+  "no-line",
+  "single-line",
+  "double-line",
+  "single-dashed-line",
+  "double-dashed-line",
+  "shadow-etched-in",
+  "shadow-etched-out",
+  "shadow-etched-in-dash",
+  "shadow-etched-out-dash",
+  "shadow-double-etched-in",
+  "shadow-double-etched-out",
+  "shadow-double-etched-in-dash",
+  "shadow-double-etched-out-dash",
+  0,
+};
+
+/* Return non-zero if LABEL specifies a separator.  */
+
+int
+menu_separator_name_p (const char *label)
+{
+  if (!label)
+    return 0;
+  else if (strlen (label) > 3
+	   && strncmp (label, "--", 2) == 0
+	   && label[2] != '-')
+    {
+      int i;
+      label += 2;
+      for (i = 0; separator_names[i]; ++i)
+	if (strcmp (label, separator_names[i]) == 0)
+          return 1;
+    }
+  else
+    {
+      /* It's a separator if it contains only dashes.  */
+      while (*label == '-')
+	++label;
+      return (*label == 0);
+    }
+
+  return 0;
+}
+
+
 /* Return a vector of menu items for a menu bar, appropriate
    to the current buffer.  Each item has three elements in the vector:
    KEY STRING MAPLIST.
@@ -8201,10 +8249,14 @@
      Rule out items that aren't lists, don't start with
      `menu-item' or whose rest following `tool-bar-item' is not a
      list.  */
-  if (!CONSP (item)
-      || !EQ (XCAR (item), Qmenu_item)
-      || (item = XCDR (item),
-	  !CONSP (item)))
+  if (!CONSP (item))
+    return 0;
+
+  /* As an exception, allow old-style menu separators.  */
+  if (STRINGP (XCAR (item)))
+    item = Fcons (XCAR (item), Qnil);
+  else if (!EQ (XCAR (item), Qmenu_item)
+	   || (item = XCDR (item), !CONSP (item)))
     return 0;
 
   /* Create tool_bar_item_properties vector if necessary.  Reset it to
@@ -8234,10 +8286,18 @@
     }
   PROP (TOOL_BAR_ITEM_CAPTION) = caption;
 
-  /* Give up if rest following the caption is not a list.  */
+  /* If the rest following the caption is not a list, the menu item is
+     either a separator, or invalid.  */
   item = XCDR (item);
   if (!CONSP (item))
-    return 0;
+    {
+      if (menu_separator_name_p (SDATA (caption)))
+	{
+	  PROP (TOOL_BAR_ITEM_TYPE) = Qt;
+	  return 1;
+	}
+      return 0;
+    }
 
   /* Store the binding.  */
   PROP (TOOL_BAR_ITEM_BINDING) = XCAR (item);
@@ -8270,10 +8330,10 @@
 	  if (NILP (menu_item_eval_property (value)))
 	    return 0;
 	}
-      else if (EQ (key, QChelp)) 
+      else if (EQ (key, QChelp))
         /* `:help HELP-STRING'.  */
         PROP (TOOL_BAR_ITEM_HELP) = value;
-      else if (EQ (key, QCvert_only)) 
+      else if (EQ (key, QCvert_only))
         /* `:vert-only t/nil'.  */
         PROP (TOOL_BAR_ITEM_VERT_ONLY) = value;
       else if (EQ (key, QClabel))
--- a/src/keyboard.h	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/keyboard.h	Fri Dec 17 12:04:06 2010 +0800
@@ -492,6 +492,7 @@
 
 extern int timers_run;
 
+extern int menu_separator_name_p (const char *);
 extern int parse_menu_item (Lisp_Object, int);
 
 extern void echo_now (void);
--- a/src/nsmenu.m	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/nsmenu.m	Fri Dec 17 12:04:06 2010 +0800
@@ -507,21 +507,6 @@
 }
 
 
-/* Utility (from macmenu.c): is this item a separator? */
-static int
-name_is_separator ( const char *name)
-{
-  const char *start = name;
-
-  /* Check if name string consists of only dashes ('-').  */
-  while (*name == '-') name++;
-  /* Separators can also be of the form "--:TripleSuperMegaEtched"
-     or "--deep-shadow".  We don't implement them yet, se we just treat
-     them like normal separators.  */
-  return (*name == '\0' || start + 2 == name);
-}
-
-
 /* ==========================================================================
 
     Menu: class implementation
@@ -624,7 +609,7 @@
   NSMenuItem *item;
   widget_value *wv = (widget_value *)wvptr;
 
-  if (name_is_separator (wv->name))
+  if (menu_separator_name_p (wv->name))
     {
       item = [NSMenuItem separatorItem];
       [self addItem: item];
--- a/src/w32menu.c	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/w32menu.c	Fri Dec 17 12:04:06 2010 +0800
@@ -1326,20 +1326,6 @@
 #endif  /* !HAVE_DIALOGS  */
 
 
-/* Is this item a separator? */
-static int
-name_is_separator (const char *name)
-{
-  const char *start = name;
-
-  /* Check if name string consists of only dashes ('-').  */
-  while (*name == '-') name++;
-  /* Separators can also be of the form "--:TripleSuperMegaEtched"
-     or "--deep-shadow".  We don't implement them yet, se we just treat
-     them like normal separators.  */
-  return (*name == '\0' || start + 2 == name);
-}
-
 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
 static void
 utf8to16 (unsigned char * src, int len, WCHAR * dest)
@@ -1388,7 +1374,7 @@
   int return_value;
   size_t nlen, orig_len;
 
-  if (name_is_separator (wv->name))
+  if (menu_separator_name_p (wv->name))
     {
       fuFlags = MF_SEPARATOR;
       out_string = NULL;
--- a/src/xdisp.c	Fri Dec 17 10:43:03 2010 +0900
+++ b/src/xdisp.c	Fri Dec 17 12:04:06 2010 +0800
@@ -10317,6 +10317,10 @@
       int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
       int hmargin, vmargin, relief, idx, end;
 
+      /* Ignore separator items.  */
+      if (EQ (PROP (TOOL_BAR_ITEM_TYPE), Qt))
+	continue;
+
       /* If image is a vector, choose the image according to the
 	 button state.  */
       image = PROP (TOOL_BAR_ITEM_IMAGES);