From 4039c78625bb20cf57b434a7d395bf2473e45133 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 17 Dec 2010 12:04:06 +0800 Subject: [PATCH] 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. --- etc/NEWS | 5 ++ lisp/ChangeLog | 6 +++ lisp/menu-bar.el | 3 +- lisp/tool-bar.el | 9 ++-- src/ChangeLog | 23 +++++++++ src/dispextern.h | 3 +- src/gtkutil.c | 118 ++++++++++++++++++----------------------------- src/keyboard.c | 76 ++++++++++++++++++++++++++---- src/keyboard.h | 1 + src/nsmenu.m | 17 +------ src/w32menu.c | 16 +------ src/xdisp.c | 4 ++ 12 files changed, 162 insertions(+), 119 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 87df565f23..1ec8325c2a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -690,6 +690,11 @@ The command `read-color' now requires a match for a color name or RGB 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 diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 892acdc752..6a4c0a0f73 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,9 @@ +2010-12-16 Chong Yidong + + * tool-bar.el (tool-bar-setup): Add separators. + + * menu-bar.el (featurep): Use menu-bar-separator. + 2010-12-16 Daiki Ueno * epa-file.el (epa-file-select-keys): Accept 'silent to inhibit diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 4708c52e12..989bdcff82 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -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) diff --git a/lisp/tool-bar.el b/lisp/tool-bar.el index a3292c4204..7c7216ed7d 100644 --- a/lisp/tool-bar.el +++ b/lisp/tool-bar.el @@ -257,23 +257,23 @@ holds a keymap." ;;; 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 @@ holds a keymap." "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") diff --git a/src/ChangeLog b/src/ChangeLog index c6e0d92f1f..f9287ea9c8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,26 @@ +2010-12-17 Chong Yidong + + * 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 * nsterm.m (ns_draw_window_cursor): If the cursor color is the diff --git a/src/dispextern.h b/src/dispextern.h index 27d3c1583c..175dbe1975 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2881,7 +2881,8 @@ enum tool_bar_item_idx /* 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. */ diff --git a/src/gtkutil.c b/src/gtkutil.c index 6fd4b96981..a6cfbf002b 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -72,6 +72,8 @@ along with GNU Emacs. If not, see . */ #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 @@ make_menu_item (const char *utf8_label, 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 @@ create_menus (widget_value *data, 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 @@ create_menus (widget_value *data, 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 @@ xg_create_widget (const char *type, const char *name, FRAME_PTR f, widget_value 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 @@ xg_update_menubar (GtkWidget *menubar, 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 @@ xg_update_menu_item (widget_value *val, 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 @@ xg_update_submenu (GtkWidget *submenu, 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 @@ xg_update_submenu (GtkWidget *submenu, 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 @@ xg_get_tool_bar_widgets (GtkWidget *vb, GtkWidget **wimage) 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 @@ xg_show_toolbar_item (GtkToolItem *ti) 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 @@ update_frame_tool_bar (FRAME_PTR f) 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 @@ update_frame_tool_bar (FRAME_PTR f) ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), i); - if (ti) - { - weventbox = gtk_bin_get_child (GTK_BIN (ti)); - wbutton = gtk_bin_get_child (GTK_BIN (weventbox)); - } - + /* 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; + } - image = PROP (TOOL_BAR_ITEM_IMAGES); + if (ti) + 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 @@ update_frame_tool_bar (FRAME_PTR f) { /* 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 @@ update_frame_tool_bar (FRAME_PTR f) 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), diff --git a/src/keyboard.c b/src/keyboard.c index 1023d34ca7..959c57a81e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7464,6 +7464,54 @@ static Lisp_Object menu_bar_one_keymap_changed_items; 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 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item) 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 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item) } 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 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item) 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)) diff --git a/src/keyboard.h b/src/keyboard.h index 7f36691a5a..d103950fb2 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -492,6 +492,7 @@ extern int quit_char; 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); diff --git a/src/nsmenu.m b/src/nsmenu.m index 973f2c15e2..95f651f669 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -507,21 +507,6 @@ set_frame_menubar (struct frame *f, int first_time, int deep_p) } -/* 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 @@ name_is_separator ( const char *name) 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]; diff --git a/src/w32menu.c b/src/w32menu.c index ff6bd977be..1e700201bf 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -1326,20 +1326,6 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header) #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 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) 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; diff --git a/src/xdisp.c b/src/xdisp.c index 1c220647ba..41204e0a5b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10317,6 +10317,10 @@ build_desired_tool_bar_string (struct frame *f) 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); -- 2.39.2