Add bindings for vc-log-incoming and vc-log-outgoing.
[bpt/emacs.git] / lisp / vc-dir.el
index 87c0ce3..3d6bd32 100644 (file)
@@ -1,6 +1,6 @@
 ;;; vc-dir.el --- Directory status display under VC
 
-;; Copyright (C) 2007, 2008
+;; Copyright (C) 2007, 2008, 2009, 2010
 ;;   Free Software Foundation, Inc.
 
 ;; Author:   Dan Nicolaescu <dann@ics.uci.edu>
@@ -83,25 +83,27 @@ See `run-hooks'."
   ;; Used to keep the cursor on the file name column.
   (beginning-of-line)
   (unless (eolp)
-    ;; Must be in sync with vc-default-status-printer.
+    ;; Must be in sync with vc-default-dir-printer.
     (forward-char 25)))
 
 (defun vc-dir-prepare-status-buffer (bname dir backend &optional create-new)
   "Find a buffer named BNAME showing DIR, or create a new one."
   (setq dir (file-name-as-directory (expand-file-name dir)))
-  (let*
-        ;; Look for another buffer name BNAME visiting the same directory.
-        ((buf (save-excursion
-               (unless create-new
-                 (dolist (buffer (buffer-list))
-                   (set-buffer buffer)
-                   (when (and (derived-mode-p 'vc-dir-mode)
-                              (eq vc-dir-backend backend)
-                              (string= (expand-file-name default-directory) dir))
-                     (return buffer)))))))
+  (let* ;; Look for another buffer name BNAME visiting the same directory.
+      ((buf (save-excursion
+              (unless create-new
+                (dolist (buffer vc-dir-buffers)
+                  (when (buffer-live-p buffer)
+                    (set-buffer buffer)
+                    (when (and (derived-mode-p 'vc-dir-mode)
+                               (eq vc-dir-backend backend)
+                               (string= default-directory dir))
+                      (return buffer))))))))
     (or buf
         ;; Create a new buffer named BNAME.
-        (with-current-buffer (create-file-buffer bname)
+       ;; We pass a filename to create-file-buffer because it is what
+       ;; the function expects, and also what uniquify needs (if active)
+        (with-current-buffer (create-file-buffer (expand-file-name bname dir))
           (cd dir)
           (vc-setup-buffer (current-buffer))
           ;; Reset the vc-parent-buffer-name so that it does not appear
@@ -186,9 +188,18 @@ See `run-hooks'."
     (define-key map [diff]
       '(menu-item "Compare with Base Version" vc-diff
                  :help "Compare file set with the base version"))
+    (define-key map [logo]
+      '(menu-item "Show Outgoing Log" vc-log-outgoing
+                 :help "Show a log of changes that will be sent with a push operation"))
+    (define-key map [logi]
+      '(menu-item "Show Incoming Log" vc-log-incoming
+                 :help "Show a log of changes that will be received with a pull operation"))
     (define-key map [log]
-     '(menu-item "Show history" vc-print-log
-     :help "List the change log of the current file set in a window"))
+      '(menu-item "Show history" vc-print-log
+                 :help "List the change log of the current file set in a window"))
+    (define-key map [rlog]
+      '(menu-item "Show Top of the Tree History " vc-print-root-log
+                 :help "List the change log for the current tree in a window"))
     ;; VC commands.
     (define-key map [sepvccmd] '("--"))
     (define-key map [update]
@@ -206,7 +217,7 @@ See `run-hooks'."
       '(menu-item "Register" vc-register
                  :help "Register file set into the version control system"))
     map)
-  "Menu for VC dir")
+  "Menu for VC dir.")
 
 ;; VC backends can use this to add mode-specific menu items to
 ;; vc-dir-menu-map.
@@ -259,7 +270,9 @@ See `run-hooks'."
     (define-key map "\C-c\C-c" 'vc-dir-kill-dir-status-process)
     (define-key map [down-mouse-3] 'vc-dir-menu)
     (define-key map [mouse-2] 'vc-dir-toggle-mark)
+    (define-key map [follow-link] 'mouse-face)
     (define-key map "x" 'vc-dir-hide-up-to-date)
+    (define-key map [?\C-k] 'vc-dir-kill-line)
     (define-key map "S" 'vc-dir-search) ;; FIXME: Maybe use A like dired?
     (define-key map "Q" 'vc-dir-query-replace-regexp)
     (define-key map (kbd "M-s a C-s")   'vc-dir-isearch)
@@ -274,21 +287,22 @@ See `run-hooks'."
     map)
   "Keymap for directory buffer.")
 
-(defmacro vc-at-event (event &rest body)
-  "Evaluate `body' with point located at event-start of `event'.
-If `body' uses `event', it should be a variable,
+(defmacro vc-dir-at-event (event &rest body)
+  "Evaluate BODY with point located at event-start of EVENT.
+If BODY uses EVENT, it should be a variable,
  otherwise it will be evaluated twice."
-  (let ((posn (make-symbol "vc-at-event-posn")))
-    `(let ((,posn (event-start ,event)))
-       (save-excursion
-         (set-buffer (window-buffer (posn-window ,posn)))
-         (goto-char (posn-point ,posn))
-         ,@body))))
+  (let ((posn (make-symbol "vc-dir-at-event-posn")))
+    `(save-excursion
+       (unless (equal ,event '(tool-bar))
+         (let ((,posn (event-start ,event)))
+           (set-buffer (window-buffer (posn-window ,posn)))
+           (goto-char (posn-point ,posn))))
+       ,@body)))
 
 (defun vc-dir-menu (e)
   "Popup the VC dir menu."
   (interactive "e")
-  (vc-at-event e (popup-menu vc-dir-menu-map e)))
+  (vc-dir-at-event e (popup-menu vc-dir-menu-map e)))
 
 (defvar vc-dir-tool-bar-map
   (let ((map (make-sparse-keymap)))
@@ -296,7 +310,8 @@ If `body' uses `event', it should be a variable,
                                   map vc-dir-mode-map)
     (tool-bar-local-item "bookmark_add"
                         'vc-dir-toggle-mark 'vc-dir-toggle-mark map
-                        :help "Toggle mark on current item")
+                        :help "Toggle mark on current item"
+                        :label "Toggle Mark")
     (tool-bar-local-item-from-menu 'vc-dir-previous-line "left-arrow"
                                   map vc-dir-mode-map
                                   :rtl "right-arrow")
@@ -308,24 +323,28 @@ If `body' uses `event', it should be a variable,
     (tool-bar-local-item-from-menu 'revert-buffer "refresh"
                                   map vc-dir-mode-map)
     (tool-bar-local-item-from-menu 'nonincremental-search-forward
-                                  "search" map)
+                                  "search" map nil
+                                  :label "Search")
     (tool-bar-local-item-from-menu 'vc-dir-query-replace-regexp
-                                  "search-replace" map vc-dir-mode-map)
+                                  "search-replace" map vc-dir-mode-map
+                                  :label "Replace")
     (tool-bar-local-item-from-menu 'vc-dir-kill-dir-status-process "cancel"
-                                  map vc-dir-mode-map)
+                                  map vc-dir-mode-map
+                                  :label "Cancel")
     (tool-bar-local-item-from-menu 'quit-window "exit"
                                   map vc-dir-mode-map)
     map))
 
 (defun vc-dir-node-directory (node)
   ;; Compute the directory for NODE.
-  ;; If it's a directory node, get it from the the node.
+  ;; If it's a directory node, get it from the node.
   (let ((data (ewoc-data node)))
     (or (vc-dir-fileinfo->directory data)
        ;; Otherwise compute it from the file name.
        (file-name-directory
-        (expand-file-name
-         (vc-dir-fileinfo->name data))))))
+        (directory-file-name
+         (expand-file-name
+          (vc-dir-fileinfo->name data)))))))
 
 (defun vc-dir-update (entries buffer &optional noinsert)
   "Update BUFFER's ewoc from the list of ENTRIES.
@@ -341,26 +360,30 @@ If NOINSERT, ignore elements on ENTRIES which are not in the ewoc."
          ;; names too many times
          (sort entries
                (lambda (entry1 entry2)
-                 (let ((dir1 (file-name-directory (expand-file-name (car entry1))))
-                       (dir2 (file-name-directory (expand-file-name (car entry2)))))
+                 (let ((dir1 (file-name-directory
+                               (directory-file-name (expand-file-name (car entry1)))))
+                       (dir2 (file-name-directory
+                              (directory-file-name (expand-file-name (car entry2))))))
                    (cond
                     ((string< dir1 dir2) t)
                     ((not (string= dir1 dir2)) nil)
                     ((string< (car entry1) (car entry2))))))))
     ;; Insert directory entries in the right places.
     (let ((entry (car entries))
-         (node (ewoc-nth vc-ewoc 0)))
+         (node (ewoc-nth vc-ewoc 0))
+         (to-remove nil)
+         (dotname (file-relative-name default-directory)))
       ;; Insert . if it is not present.
       (unless node
-       (let ((rd (file-relative-name default-directory)))
-         (ewoc-enter-last
-          vc-ewoc (vc-dir-create-fileinfo
-                   rd nil nil nil (expand-file-name default-directory))))
+       (ewoc-enter-last
+        vc-ewoc (vc-dir-create-fileinfo
+                 dotname nil nil nil default-directory))
        (setq node (ewoc-nth vc-ewoc 0)))
 
       (while (and entry node)
        (let* ((entryfile (car entry))
-              (entrydir (file-name-directory (expand-file-name entryfile)))
+              (entrydir (file-name-directory (directory-file-name
+                                              (expand-file-name entryfile))))
               (nodedir (vc-dir-node-directory node)))
          (cond
           ;; First try to find the directory.
@@ -370,13 +393,21 @@ If NOINSERT, ignore elements on ENTRIES which are not in the ewoc."
            ;; Found the directory, find the place for the file name.
            (let ((nodefile (vc-dir-fileinfo->name (ewoc-data node))))
              (cond
+              ((string= nodefile dotname)
+               (setq node (ewoc-next vc-ewoc node)))
               ((string-lessp nodefile entryfile)
                (setq node (ewoc-next vc-ewoc node)))
               ((string-equal nodefile entryfile)
-               (setf (vc-dir-fileinfo->state (ewoc-data node)) (nth 1 entry))
-               (setf (vc-dir-fileinfo->extra (ewoc-data node)) (nth 2 entry))
-               (setf (vc-dir-fileinfo->needs-update (ewoc-data node)) nil)
-               (ewoc-invalidate vc-ewoc node)
+               (if (nth 1 entry)
+                   (progn
+                     (setf (vc-dir-fileinfo->state (ewoc-data node)) (nth 1 entry))
+                     (setf (vc-dir-fileinfo->extra (ewoc-data node)) (nth 2 entry))
+                     (setf (vc-dir-fileinfo->needs-update (ewoc-data node)) nil)
+                     (ewoc-invalidate vc-ewoc node))
+                 ;; If the state is nil, the file does not exist
+                 ;; anymore, so remember the entry so we can remove
+                 ;; it after we are done inserting all ENTRIES.
+                 (push node to-remove))
                (setq entries (cdr entries))
                (setq entry (car entries))
                (setq node (ewoc-next vc-ewoc node)))
@@ -402,7 +433,8 @@ If NOINSERT, ignore elements on ENTRIES which are not in the ewoc."
       (unless (or node noinsert)
        (let ((lastdir (vc-dir-node-directory (ewoc-nth vc-ewoc -1))))
          (dolist (entry entries)
-           (let ((entrydir (file-name-directory (expand-file-name (car entry)))))
+           (let ((entrydir (file-name-directory
+                            (directory-file-name (expand-file-name (car entry))))))
              ;; Insert a directory node if needed.
              (unless (string-equal lastdir entrydir)
                (setq lastdir entrydir)
@@ -411,7 +443,10 @@ If NOINSERT, ignore elements on ENTRIES which are not in the ewoc."
                   vc-ewoc (vc-dir-create-fileinfo rd nil nil nil entrydir))))
              ;; Now insert the node itself.
              (ewoc-enter-last vc-ewoc
-                              (apply 'vc-dir-create-fileinfo entry)))))))))
+                              (apply 'vc-dir-create-fileinfo entry))))))
+      (when to-remove
+       (let ((inhibit-read-only t))
+         (apply 'ewoc-delete vc-ewoc (nreverse to-remove)))))))
 
 (defun vc-dir-busy ()
   (and (buffer-live-p vc-dir-process-buffer)
@@ -674,7 +709,7 @@ that share the same state."
 
 (defun vc-dir-toggle-mark (e)
   (interactive "e")
-  (vc-at-event e (vc-dir-mark-unmark 'vc-dir-toggle-mark-file)))
+  (vc-dir-at-event e (vc-dir-mark-unmark 'vc-dir-toggle-mark-file)))
 
 (defun vc-dir-delete-file ()
   "Delete the marked files, or the current file if no marks."
@@ -687,9 +722,10 @@ that share the same state."
   (interactive)
   (find-file (vc-dir-current-file)))
 
-(defun vc-dir-find-file-other-window ()
+(defun vc-dir-find-file-other-window (&optional event)
   "Find the file on the current line, in another window."
-  (interactive)
+  (interactive (list last-nonmenu-event))
+  (if event (posn-set-point (event-end event)))
   (find-file-other-window (vc-dir-current-file)))
 
 (defun vc-dir-isearch ()
@@ -839,7 +875,7 @@ If it is a file, return the corresponding cons for the file itself."
   ;; Update the entries for all the child files of DIRNAME shown in
   ;; the current *vc-dir* buffer.
   (let ((files (vc-dir-find-child-files dirname))
-       (ddir (expand-file-name default-directory))
+       (ddir default-directory)
        fileentries)
     (when files
       (dolist (crt files)
@@ -848,39 +884,43 @@ If it is a file, return the corresponding cons for the file itself."
       (vc-dir-update fileentries (current-buffer)))))
 
 (defun vc-dir-resynch-file (&optional fname)
-  "Update the entries for FILE in any directory buffers that list it."
+  "Update the entries for FNAME in any directory buffers that list it."
   (let ((file (or fname (expand-file-name buffer-file-name)))
-       (found-vc-dir-buf nil))
-    (save-excursion
-      (dolist (status-buf (buffer-list))
-       (set-buffer status-buf)
-       ;; look for a vc-dir buffer that might show this file.
-       (when (derived-mode-p 'vc-dir-mode)
-         (setq found-vc-dir-buf t)
-         (let ((ddir (expand-file-name default-directory)))
-           (when (vc-string-prefix-p ddir file)
-             (if (file-directory-p file)
-                 (vc-dir-resync-directory-files file)
-               (vc-dir-update
-                (list (vc-dir-recompute-file-state file ddir))
-                status-buf)))))))
-    ;; We didn't find any vc-dir buffers, remove the hook, it is
-    ;; not needed.
-    (unless found-vc-dir-buf
-      (remove-hook 'after-save-hook 'vc-dir-resynch-file))))
+        (drop '()))
+    (save-current-buffer
+      ;; look for a vc-dir buffer that might show this file.
+      (dolist (status-buf vc-dir-buffers)
+        (if (not (buffer-live-p status-buf))
+            (push status-buf drop)
+          (set-buffer status-buf)
+          (if (not (derived-mode-p 'vc-dir-mode))
+              (push status-buf drop)
+            (let ((ddir default-directory))
+              (when (vc-string-prefix-p ddir file)
+                (if (file-directory-p file)
+                   (progn
+                     (vc-dir-resync-directory-files file)
+                     (ewoc-set-hf vc-ewoc
+                                  (vc-dir-headers vc-dir-backend default-directory) ""))
+                  (let ((state (vc-dir-recompute-file-state file ddir)))
+                    (vc-dir-update
+                     (list state)
+                     status-buf (eq (cadr state) 'up-to-date))))))))))
+    ;; Remove out-of-date entries from vc-dir-buffers.
+    (dolist (b drop) (setq vc-dir-buffers (delq b vc-dir-buffers)))))
 
 (defvar use-vc-backend)  ;; dynamically bound
 
 (define-derived-mode vc-dir-mode special-mode "VC dir"
   "Major mode for VC directory buffers.
 Marking/Unmarking key bindings and actions:
-m - marks a file/directory or if the region is active, mark all the files
-     in region.
+m - mark a file/directory
+  - if the region is active, mark all the files in region.
     Restrictions: - a file cannot be marked if any parent directory is marked
                   - a directory cannot be marked if any child file or
                     directory is marked
-u - marks a file/directory or if the region is active, unmark all the files
-     in region.
+u - unmark a file/directory
+  - if the region is active, unmark all the files in region.
 M - if the cursor is on a file: mark all the files with the same state as
       the current file
   - if the cursor is on a directory: mark all child files
@@ -889,10 +929,12 @@ U - if the cursor is on a file: unmark all the files with the same state
       as the current file
   - if the cursor is on a directory: unmark all child files
   - with a prefix argument: unmark all files
+mouse-2  - toggles the mark state
 
 VC commands
-VC commands in the `C-x v' can be used, they act on the marked
-entries, or on the current entry if nothing is marked.
+VC commands in the `C-x v' prefix can be used.
+VC commands act on the marked entries.  If nothing is marked, VC
+commands act on the current entry.
 
 Search & Replace
 S - searches the marked files
@@ -901,8 +943,8 @@ M-s a C-s - does an isearch on the marked files
 M-s a C-M-s - does a regexp isearch on the marked files
 If nothing is marked, these commands act on the current entry.
 When a directory is current or marked, the Search & Replace
-commands act on the files in those directories displayed in the
-*vc-dir* buffer.
+commands act on the child files of that directory that are displayed in
+the *vc-dir* buffer.
 
 \\{vc-dir-mode-map}"
   (set (make-local-variable 'vc-dir-backend) use-vc-backend)
@@ -912,29 +954,30 @@ commands act on the files in those directories displayed in the
   (let ((buffer-read-only nil))
     (erase-buffer)
     (set (make-local-variable 'vc-dir-process-buffer) nil)
-    (set (make-local-variable 'vc-ewoc)
-        (ewoc-create #'vc-dir-status-printer
-                     (vc-dir-headers vc-dir-backend default-directory)))
+    (set (make-local-variable 'vc-ewoc) (ewoc-create #'vc-dir-printer))
     (set (make-local-variable 'revert-buffer-function)
         'vc-dir-revert-buffer-function)
-    (set (make-local-variable 'list-buffers-directory)
-         (expand-file-name default-directory))
-    (add-hook 'after-save-hook 'vc-dir-resynch-file)
+    (setq list-buffers-directory (expand-file-name "*vc-dir*" default-directory))
+    (add-to-list 'vc-dir-buffers (current-buffer))
     ;; Make sure that if the directory buffer is killed, the update
     ;; process running in the background is also killed.
     (add-hook 'kill-buffer-query-functions 'vc-dir-kill-query nil t)
+    (hack-dir-local-variables-non-file-buffer)
     (vc-dir-refresh)))
 
 (defun vc-dir-headers (backend dir)
   "Display the headers in the *VC dir* buffer.
-It calls the `status-extra-headers' backend method to display backend
+It calls the `dir-extra-headers' backend method to display backend
 specific headers."
   (concat
+   ;; First layout the common headers.
    (propertize "VC backend : " 'face 'font-lock-type-face)
    (propertize (format "%s\n" backend) 'face 'font-lock-variable-name-face)
    (propertize "Working dir: " 'face 'font-lock-type-face)
-   (propertize (format "%s\n" dir) 'face 'font-lock-variable-name-face)
-   (vc-call-backend backend 'status-extra-headers dir)
+   (propertize (format "%s\n" (abbreviate-file-name dir))
+               'face 'font-lock-variable-name-face)
+   ;; Then the backend specific ones.
+   (vc-call-backend backend 'dir-extra-headers dir)
    "\n"))
 
 (defun vc-dir-refresh-files (files default-state)
@@ -1032,7 +1075,8 @@ Throw an error if another update process is in progress."
                        (vc-dir-refresh-files
                         (mapcar 'vc-dir-fileinfo->name remaining)
                         'up-to-date)
-                     (setq mode-line-process nil))))))))))))
+                     (setq mode-line-process nil)))))))))
+      (ewoc-set-hf vc-ewoc (vc-dir-headers backend def-dir) ""))))
 
 (defun vc-dir-show-fileentry (file)
   "Insert an entry for a specific file into the current *VC-dir* listing.
@@ -1068,8 +1112,15 @@ outside of VC) and one wants to do some operation on it."
            (ewoc-delete vc-ewoc crt))
          (setq crt prev)))))
 
-(defun vc-dir-status-printer (fileentry)
-  (vc-call-backend vc-dir-backend 'status-printer fileentry))
+(defun vc-dir-kill-line ()
+  "Remove the current line from display."
+  (interactive)
+  (let ((crt (ewoc-locate vc-ewoc))
+        (inhibit-read-only t))
+    (ewoc-delete vc-ewoc crt)))
+
+(defun vc-dir-printer (fileentry)
+  (vc-call-backend vc-dir-backend 'dir-printer fileentry))
 
 (defun vc-dir-deduce-fileset (&optional state-model-only-files)
   (let ((marked (vc-dir-marked-files))
@@ -1093,7 +1144,7 @@ outside of VC) and one wants to do some operation on it."
       ;; state to decide which operation to perform.
       (dolist (crt (cdr only-files-list))
        (unless (vc-compatible-state (cdr crt) state)
-         (error "%s:%s clashes with %s:%s"
+         (error "When applying VC operations to multiple files, the files are required\nto  be in similar VC states.\n%s in state %s clashes with %s in state %s"
                 (car crt) (cdr crt) (caar only-files-list) state)))
       (setq only-files-list (mapcar 'car only-files-list))
       (when (and state (not (eq state 'unregistered)))
@@ -1102,9 +1153,22 @@ outside of VC) and one wants to do some operation on it."
 
 ;;;###autoload
 (defun vc-dir (dir &optional backend)
-  "Show the VC status for DIR.
+  "Show the VC status for \"interesting\" files in and below DIR.
+This allows you to mark files and perform VC operations on them.
+The list omits files which are up to date, with no changes in your copy
+or the repository, if there is nothing in particular to say about them.
+
+Preparing the list of file status takes time; when the buffer
+first appears, it has only the first few lines of summary information.
+The file lines appear later.
+
 Optional second argument BACKEND specifies the VC backend to use.
-Interactively, a prefix argument means to ask for the backend."
+Interactively, a prefix argument means to ask for the backend.
+
+These are the commands available for use in the file status buffer:
+
+\\{vc-dir-mode-map}"
+
   (interactive
    (list
     ;; When you hit C-x v d in a visited VC file,
@@ -1124,14 +1188,15 @@ Interactively, a prefix argument means to ask for the backend."
          nil t nil nil)))))
   (unless backend
     (setq backend (vc-responsible-backend dir)))
-  (pop-to-buffer (vc-dir-prepare-status-buffer "*vc-dir*" dir backend))
+  (let (pop-up-windows)                      ; based on cvs-examine; bug#6204
+    (pop-to-buffer (vc-dir-prepare-status-buffer "*vc-dir*" dir backend)))
   (if (derived-mode-p 'vc-dir-mode)
       (vc-dir-refresh)
     ;; FIXME: find a better way to pass the backend to `vc-dir-mode'.
     (let ((use-vc-backend backend))
       (vc-dir-mode))))
 
-(defun vc-default-status-extra-headers (backend dir)
+(defun vc-default-dir-extra-headers (backend dir)
   ;; Be loud by default to remind people to add code to display
   ;; backend specific headers.
   ;; XXX: change this to return nil before the release.
@@ -1140,9 +1205,18 @@ Interactively, a prefix argument means to ask for the backend."
    (propertize "Please add backend specific headers here.  It's easy!"
               'face 'font-lock-warning-face)))
 
-(defun vc-default-status-printer (backend fileentry)
+(defvar vc-dir-filename-mouse-map
+   (let ((map (make-sparse-keymap)))
+     (define-key map [mouse-2] 'vc-dir-find-file-other-window)
+    map)
+  "Local keymap for visiting a file.")
+
+(defun vc-default-dir-printer (backend fileentry)
   "Pretty print FILEENTRY."
   ;; If you change the layout here, change vc-dir-move-to-goal-column.
+  ;; VC backends can implement backend specific versions of this
+  ;; function.  Changes here might need to be reflected in the
+  ;; vc-BACKEND-dir-printer functions.
   (let* ((isdir (vc-dir-fileinfo->directory fileentry))
        (state (if isdir "" (vc-dir-fileinfo->state fileentry)))
        (filename (vc-dir-fileinfo->name fileentry)))
@@ -1166,7 +1240,8 @@ Interactively, a prefix argument means to ask for the backend."
       (if isdir
          "Directory\nVC operations can be applied to it\nmouse-3: Pop-up menu"
        "File\nmouse-3: Pop-up menu")
-      'mouse-face 'highlight))))
+      'mouse-face 'highlight
+      'keymap vc-dir-filename-mouse-map))))
 
 (defun vc-default-extra-status-menu (backend)
   nil)