Subject: bug#76789: 31.0.50; [PATCH] speedbar: New speedbar-window-mode

From: Vincenzo Pupillo <[email-masked]>
Date: Fri, 14 Mar 2025 20:52:33 +0100

Thank you Eli for the review,

In data giovedì 13 marzo 2025 10:57:41 Ora standard dell’Europa centrale, Eli 
Zaretskii ha scritto:
> > From: Vincenzo Pupillo <[email-masked]>
> > Cc: [email-masked]
> > Date: Tue, 11 Mar 2025 16:41:22 +0100
> > 
> > Thank you Eli.
> > In this updated version of the patch I corrected what you indicated and
> > added something in the manual, rather short :-(.
> 
> Thanks.  I meant to install it, but building Emacs after applying the
> changes yields warnings:
> 
>   In speedbar-frame-or-window:
>   speedbar.el:1009:2: Warning: docstring has wrong usage of unescaped single
> quotes (use \=' or different quoting such as `...')
> 
>   In speedbar-window-mode:
>   speedbar.el:1045:13: Warning: assignment to free variable
> `speedbar-select-frame-method'
> 
>   In speedbar-window--buffer-live-p:
>   speedbar.el:1079:11: Warning: defsubst `speedbar-window--buffer-live-p'
> was used before it was defined
> 
>   In speedbar-window--width:
>   speedbar.el:1113:11: Warning: defsubst `speedbar-window--width' was used
> before it was defined
> 
>   In speedbar-current-frame:
>   speedbar.el:1135:11: Warning: defsubst `speedbar-current-frame' was used
> before it was defined
> 
> Please fix those.

Done

> 
> Also, here:
> > +@cindex @code{speedbar-window}
> > +Optionally, the speedbar can be displayed as a window, splitting the
> > +windows of the selected frame, in both terminal and graphics modes.
> > +Only one speedbar window can be open at a time.
> > +
> > +It is possible to switch from displaying the speedbar in a separate
> > +frame to displaying it in a window and vice versa simply by using the
> > +@kbd{M-x speedbar-window @key{RET}} or
> > +@kbd{M-x speedbar-frame@key{RET}} command.
> 
> please mention and index the user option you added.
> 
> > +** Speedbar
> > +
> > +---
> > +*** The new command 'speedbar-window-mode' opens Speedbar in a window
> > instead +of a frame.
> > +
> > +*** New command 'speedbar-window' is an alias for 'speedbar-window-mode'.
> > +'
> > +*** The new user option 'speedbar-prefer-window', tells 'speedbar' to
> > open
> > +a side window instead of a frame.
> > +
> > +*** 'speedbar-easymenu-definition-trailer' is now a function.
> > +
> 
> These NEWS entries should be marked with "+++", since this is now
> documented in the relevant manuals.

Done. 

The new version of the patch is attached.

Vincenzo

From 21e5405fe279794f3b6479595fc2def53cf10bc8 Mon Sep 17 00:00:00 2001
From: Vincenzo Pupillo <[email-masked]>
Date: Thu, 6 Mar 2025 13:39:01 +0100
Subject: [PATCH] Add a new command `speedbar-window'.

Speedbar now can be opened in a window instead of a separate frame. The
frame remains the default.

* doc/emacs/frames.texi: Mention Speedbar window mode.
* doc/misc/speedbar.texi: Document 'speedbar-window'.
* lisp/speedbar.el
(speedbar-prefer-window): New user option. If t, the command `speedbar'
open the speedbar in a window.
(speedbar-window-dedicated-window): New user option. If t the window is
dedicated.
(speedbar-window-side):  New user option. The side of 'speedbar-window',
defaults to left.
(speedbar-window-default-width): New user option. The default size of
the 'speedbar-window'.
(speedbar-window-max-width): New user option. Limits the width of the
'speedbar-window'. The user can resize the window as desired, but this
option will be the width of the window when restored.
(speedbar--buffer-name): New variable, the buffer name used for both
'speedbar-frame-mode' and 'speedbar-window-mode'.
(speedbar--window): New variable, the window displaying 'speedbar-window'.
(speedbar--window-width): New variable, store the current width of
'speedbar-window'.
(speedbar-easymenu-definition-trailer): Now it is a function that
returns a different trailer for 'speedbar-frame' and 'speedbar-window'.
(speedbar): Now it is a function that calls 'speedbar-frame-mode', the
default or 'speedbar-window-mode' based on the value of
'speedbar-prefer-window'.
(speedbar-frame-mode): Before opening a frame, close 'speedbar-window'
if it is open.
(speedbar-frame-or-window): New function, returns 'frame', 'window'
or nil if speedbar is not open.
(speedbar-window): New alias for 'speedbar-window-mode'.
(speedbar-window-mode): Enable of disable 'speedbar-window'.
(speedbar-window--window-live-p): New function, return non-nil if the
'speedbar-window' is live.
(speedbar-window--buffer-live-p): New function, return non-nil if the
'speedbar-buffer' is live.
(speedbar-window--live-p): New function, return t if 'speedbar-window'
is open.
(speedbar-window-current-window): New function, return t if the selected
window is speedbar-window.
(speedbar-window--close): New function, close the 'speedbar-window'.
(speedbar-window--width): New function, return the current width of
'speedbar-window'.
(speedbar-width): New function, return the 'speedbar' of
'speedbar-frame-mode' of 'speedbar-frame-mode'.
(speedbar-set-mode-line-format): Use the new 'speedbar-width' function.
(speedbar-directory-buttons): Use the new 'speedbar-width' function.
(speedbar--speedbar-live-p): New function, returns t if
'speedbar-frame-mode' or 'speedbar-window-mode' are open.
(speedbar-timer-fn): Now handle 'speedbar-frame-mode' and
'speedbar-window-mode'.
---
 doc/emacs/frames.texi  |   3 +
 doc/misc/speedbar.texi |  59 ++++++--
 etc/NEWS               |  28 ++++
 lisp/speedbar.el       | 326 +++++++++++++++++++++++++++++++++--------
 4 files changed, 341 insertions(+), 75 deletions(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 9992c39dcc9..1fa6e0b5b33 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -964,6 +964,9 @@ Speedbar
 files, and lets you move the current message to another Rmail file by
 clicking on its @samp{<M>} box.
 
+The speedbar can optionally be displayed as a window rather than a
+separate frame, in both terminal and graphics mode.
+
   For more details on using and programming the speedbar, @xref{Top,
 Speedbar,,speedbar, Speedbar Manual}.
 
diff --git a/doc/misc/speedbar.texi b/doc/misc/speedbar.texi
index 69c54f5b552..716135dfc4a 100644
--- a/doc/misc/speedbar.texi
+++ b/doc/misc/speedbar.texi
@@ -46,11 +46,11 @@ Top
 is the ``explorer'' often used in modern development environments, office
 packages, and web browsers.
 
-Speedbar displays a narrow frame in which a tree view is shown.  This
-tree view defaults to containing a list of files and directories.  Files
-can be ``expanded'' to list tags inside.  Directories can be expanded to
-list the files within them.  Each file or tag can be jumped to
-immediately.
+Speedbar displays a narrow frame or a narrow window in which a tree view
+is shown.  This tree view defaults to containing a list of files and
+directories.  Files can be ``expanded'' to list tags inside.
+Directories can be expanded to list the files within them.  Each file or
+tag can be jumped to immediately.
 
 Speedbar expands upon ``explorer'' windows by maintaining context with the
 user.  For example, when using the file view, the current buffer's file
@@ -114,6 +114,21 @@ Introduction
 @code{speedbar-get-focus}.  This function will toggle between frames, and
 it's useful to bind it to a key in terminal mode.  @xref{Customizing}.
 
+@cindex @code{speedbar-window}
+Optionally, the speedbar can be displayed as a window, splitting the
+windows of the selected frame, in both terminal and graphics modes.
+Only one speedbar window can be open at a time.
+
+It is possible to switch from displaying the speedbar in a separate
+frame to displaying it in a window and vice versa simply by using the
+@kbd{M-x speedbar-window @key{RET}} or
+@kbd{M-x speedbar-frame@key{RET}} command.
+
+@cindex @code{speedbar-prefer-window}
+The user option @code{speedbar-prefer-window} changes the behavior of
+the @code{speedbar} command, if set to t the @code{speedbar} command
+will display the speedbar in a window instead of in a frame.
+
 @node Basic Navigation
 @chapter Basic Navigation
 
@@ -138,10 +153,11 @@ Basic Key Bindings
 @table @kbd
 @item Q
 @cindex quitting speedbar
-Quit speedbar, and kill the frame.
+Quit speedbar, and kill the frame.  This is only available for
+@code{speed-frame}.
 @item q
-Quit speedbar, and hide the frame.  This makes it faster to restore the
-speedbar frame, than if you press @kbd{Q}.
+Quit speedbar, and hide the frame or close the window.  This makes it
+faster to restore the speedbar frame, than if you press @kbd{Q}.
 @item g
 @cindex refresh speedbar display
 Refresh whatever contents are in speedbar.
@@ -658,10 +674,10 @@ Customizing
 @end table
 
 @menu
-* Frames and Faces::        Visible behaviors.
-* Tag Hierarchy Methods::   Customizing how tags are displayed.
-* Version Control::         Adding new VC detection modes.
-* Hooks::                   The many hooks you can use.
+* Frames, Windows and Faces::   Visible behaviors.
+* Tag Hierarchy Methods::       Customizing how tags are displayed.
+* Version Control::             Adding new VC detection modes.
+* Hooks::                       The many hooks you can use.
 @end menu
 
 @node Frames and Faces
@@ -701,6 +717,25 @@ Frames and Faces
 set up initial details.  Height is also automatically added when
 speedbar is created, though you can override it.
 
+@cindex @code{speedbar-window-side}
+If the speedbar is displayed in a window, you can also customize the
+side on which the @code{speedbar-window} is displayed by changing the
+@code{speedbar-window-side} option.
+
+@cindex @code{speedbar-window-default-width}
+@cindex @code{speedbar-window-max-width}
+The size of the @code{speedbar-window}, when opened on the left or right
+side, can be defined by changing the
+@code{speedbar-window-default-width} option, which defines the default
+window size. The width of the speedbar window can be greater than
+@code{speedbar-window-max-width}, but if it is closed and later
+reopened, the width will be equal to @code{speedbar-window-max-width}.
+
+@cindex @code{speedbar-window-dedicated-window}
+By default, @code{speedbar-window} is displayed in a dedicated window,
+so @code{display-buffer} will never use this window. Setting
+@code{speedbar-window-dedicated-window} to nil can change this behavior.
+
 @node Tag Hierarchy Methods
 @section Tag Hierarchy Methods
 @cindex tag hierarchy
diff --git a/etc/NEWS b/etc/NEWS
index ef4cacb20f9..7bfc9286cf7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1375,6 +1375,34 @@ Major-mode authors can customize the variables
 'yank-media-autoselect-function' and/or 'yank-media-preferred-types' to
 change the selection rules.
 
+** Speedbar
+
++++
+*** The new command 'speedbar-window-mode' opens Speedbar in a window
+instead of a frame.
+
++++
+*** New command 'speedbar-window' is an alias for 'speedbar-window-mode'.
+
++++
+*** The new user option 'speedbar-prefer-window', tells 'speedbar' to
+open a side window instead of a frame.
+
++++
+*** The new user option ‘speedbar-dedicated-window’ defines whether the
+‘speedbar’ is displayed in a dedicated window.
+
++++
+*** The new user option 'speedbar-window-default-width' defines the
+initial width of the 'speedbar-window'
+
++++
+*** The new user option 'speedbar-window-max-width' defines the maximum
+width of the 'speedbar-window' when it is closed and then restored.
+
+---
+*** 'speedbar-easymenu-definition-trailer' is now a function.
+
 ** Miscellaneous
 
 ---
diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index 104e23b9bc9..d5e21acdbb2 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -22,9 +22,9 @@
 
 ;;; Commentary:
 ;;
-;;   The speedbar provides a frame in which files, and locations in
-;; files are displayed.  These items can be clicked on with mouse-2 in
-;; to display that file location.
+;;   The speedbar provides a frame or a window in which files, and
+;; locations in files are displayed.  These items can be clicked on with
+;; mouse-2 in to display that file location.
 ;;
 ;;; Customizing and Developing for speedbar
 ;;
@@ -139,8 +139,66 @@ speedbar-use-images
   :version "21.1"
   :type 'boolean)
 
+(defcustom speedbar-select-frame-method 'attached
+  "Specify how to select a frame for displaying a file.
+A number such as 1 or -1 means to pass that number to `other-frame'
+while selecting a frame from speedbar.  Any other value means to use
+the attached frame (the frame that speedbar was started from)."
+  :group 'speedbar
+  :type '(choice integer (other :tag "attached" attached)))
+
+(defcustom speedbar-prefer-window nil
+  "If t, the command `speedbar' opens the speedbar in a window."
+  :type 'boolean
+  :group 'speedbar
+  :version "31.1")
+
+(defcustom speedbar-window-dedicated-window t
+  "Whether to make the `speedbar-window' dedicated."
+  :group 'speedbar
+  :type 'boolean
+  :version "31.1")
+
+(defcustom speedbar-window-side 'left
+  "Control the side of the frame on which to show the speedbar window.
+The value can be `left', `right', `top' or `bottom'.
+See `display-buffer-in-side-window' for more details."
+  :type '(radio (const :tag "Left" left)
+		(const :tag "Right" right)
+		(const :tag "Top" top)
+		(const :tag "Bottom" bottom))
+  :group 'speedbar
+  :version "31.1")
+
+(defcustom speedbar-window-default-width 20
+  "Initial width in characters of `speedbar-window'.
+Specified the desired width when `speedbar-window' is opened on the left or
+right side.  The default value is the same width of `speedbar-frame-mode'."
+  :type 'integer
+  :group 'speedbar
+  :version "31.1")
+
+(defcustom speedbar-window-max-width 40
+  "The maximum allowed width in characters of the `speedbar-window'.
+The `speedbar-window' width can exceed the value defined here, however
+if the window is closed and then reopened, this will be the width of the
+`speedbar-window'."
+  :type 'integer
+  :group 'speedbar
+  :version "31.1")
+
 ;;; Code:
 
+(defconst speedbar--buffer-name " SPEEDBAR"
+  "Speedbar buffer name.")
+
+(defvar speedbar--window nil
+  "The window displaying `speedbar-window'.")
+
+(defvar speedbar--window-width speedbar-window-default-width
+"Stores the current width of `speedbar-window'.
+Subsequent calls to `speedbar-window' will open a window of this width.")
+
 (defvar speedbar-initial-expansion-mode-alist
   '(("buffers" speedbar-buffer-easymenu-definition speedbar-buffers-key-map
      speedbar-buffer-buttons)
@@ -844,11 +902,18 @@ speedbar-easymenu-definition-special
     )
   "Additional menu items while in file-mode.")
 
-(defvar speedbar-easymenu-definition-trailer
-  '(["Customize..." speedbar-customize t]
-    ["Close" dframe-close-frame t]
-    ["Quit" delete-frame t])
-  "Menu items appearing at the end of the speedbar menu.")
+(defun speedbar-easymenu-definition-trailer ()
+  "Return menu items appearing at the end of the speedbar menu."
+  (let ((type (speedbar-frame-or-window)))
+    (cond ((eq type 'frame)
+	   '(["Customize..." speedbar-customize t]
+	     ["Close" dframe-close-frame t]
+	     ["Quit" delete-frame t]))
+	  ((eq type 'window)
+	   '(["Customize..." speedbar-customize t]
+	     ["Close"
+	      (lambda () (interactive) (speedbar-window--close))
+	      :keys "q" :active t])))))
 
 (defvar speedbar-desired-buffer nil
   "Non-nil when speedbar is showing buttons specific to a special mode.
@@ -891,7 +956,19 @@ 'speedbar-mode-line-update
 ;;
 
 ;;;###autoload
-(defalias 'speedbar 'speedbar-frame-mode)
+(defun speedbar (&optional arg)
+  "Open or close the `speedbar'.
+Positive ARG means turn on, negative turn off.
+A nil ARG means toggle.  If `speedbar-prefer-window' is t, open the
+speedbar in a window instead of in a separate frame."
+  (interactive "P")
+  (if speedbar-prefer-window
+      (speedbar-window-mode arg)
+    (speedbar-frame-mode arg)))
+
+;;;###autoload
+(defalias 'speedbar-frame 'speedbar-frame-mode)
+
 ;;;###autoload
 (defun speedbar-frame-mode (&optional arg)
   "Enable or disable speedbar.  Positive ARG means turn on, negative turn off.
@@ -901,10 +978,12 @@ speedbar-frame-mode
 `speedbar-before-popup-hook' is called before popping up the speedbar frame.
 `speedbar-before-delete-hook' is called before the frame is deleted."
   (interactive "P")
+  (when (eq (speedbar-frame-or-window) 'window)
+    (speedbar-window--close))
   ;; Get the buffer to play with
   (if (not (buffer-live-p speedbar-buffer))
       (with-current-buffer
-          (setq speedbar-buffer (get-buffer-create " SPEEDBAR"))
+          (setq speedbar-buffer (get-buffer-create speedbar--buffer-name))
 	(speedbar-mode)))
   ;; Do the frame thing
   (dframe-frame-mode arg
@@ -934,6 +1013,119 @@ speedbar-frame-mode
     (message (substitute-command-keys
               "Use \\[speedbar-get-focus] to see the speedbar window"))))
 
+(defsubst speedbar-current-frame ()
+  "Return the frame to use for speedbar based on current context."
+  (dframe-current-frame 'speedbar-frame 'speedbar-mode))
+
+(defsubst speedbar-window--window-live-p ()
+    "Return non-nil if `speedbar--window' is defined and live."
+  (when (and speedbar--window (window-live-p speedbar--window))
+    speedbar--window))
+
+(defsubst speedbar-window--buffer-live-p ()
+    "Return non-nil if `speedbar-buffer' is live."
+  (when (and speedbar-buffer (buffer-live-p speedbar-buffer))
+    speedbar-buffer))
+
+(defun speedbar-window--live-p ()
+  "Return t if `speedbar-window' is live."
+  (and (speedbar-window--buffer-live-p) (speedbar-window--window-live-p)))
+
+(defsubst speedbar-window-current-window ()
+  "Return t if the selected windows is the `speedbar--window'."
+  (eq (selected-window) speedbar--window))
+
+(defsubst speedbar-window--width ()
+  "Return the width of `speedbar-window'."
+  (let ((edges (window-edges speedbar--window)))
+    (- (nth 2 edges) (nth 0 edges))))
+
+(defun speedbar-frame-or-window ()
+  "Return `frame' or `window' if one of each are open.
+Return nil if both are closed."
+  (cond
+   ((speedbar-window--live-p)
+    'window)
+   ((and (frame-live-p (speedbar-current-frame))
+	 speedbar-buffer
+	 (not (speedbar-window--live-p)))
+    'frame)
+   (t nil)))
+
+;;;###autoload
+(defalias 'speedbar-window 'speedbar-window-mode)
+;;;###autoload
+(defun speedbar-window-mode (&optional arg)
+  "Enable or disable speedbar window mode.
+Positive ARG means turn on, negative turn off.
+A nil ARG means toggle.  Once the speedbar window is activated, a buffer in
+`speedbar-mode' will be displayed.  Currently, only one speedbar is
+supported at a time.
+`speedbar-before-popup-hook' is called before popping up the speedbar frame.
+`speedbar-before-delete-hook' is called before the frame is deleted."
+  (interactive "P")
+  (when (eq (speedbar-frame-or-window) 'frame)
+    (delete-frame (speedbar-current-frame)))
+
+  (if (or (and (not arg) (speedbar-window--live-p))
+	  (and (numberp arg) (< arg 0)))
+      (speedbar-window--close)
+    (let ((current-window (selected-window)))
+      (unless (speedbar-window--buffer-live-p)
+	(setq speedbar-buffer (get-buffer-create speedbar--buffer-name)))
+
+      (setq speedbar-frame (selected-frame)
+	    dframe-attached-frame (selected-frame)
+	    speedbar-select-frame-method 'attached
+	    speedbar-last-selected-file nil)
+
+      (set-buffer speedbar-buffer)
+      (speedbar-mode)
+
+      ;; let's create the window
+      (setq speedbar--window
+	    (display-buffer-in-side-window speedbar-buffer
+					   `((side ,@speedbar-window-side)
+					     (slot . 0)
+					     (dedicated ,@speedbar-window-dedicated-window)
+					     (window-width ,@speedbar--window-width))))
+      ;; additional window parameters
+      (set-window-parameter speedbar--window 'no-other-window t)
+      (set-window-parameter speedbar--window 'no-delete-other-windows t)
+
+      ;; `speedbar-reconfigure-keymaps' checks if the `speedbar-window' is open, so
+      ;; should stay after the buffer and window definition.
+      (speedbar-reconfigure-keymaps)
+      (speedbar-update-contents)
+      (speedbar-set-timer dframe-update-speed)
+
+      ;; hscroll
+      (setq-local auto-hscroll-mode nil)
+      ;; reset the selection variable
+      (setq speedbar-last-selected-file nil)
+      (select-window current-window))))
+
+(defun speedbar-window--close ()
+  "Close `speedbar-window'."
+  (when (speedbar-window--live-p)
+    (let ((current-window (selected-window)))
+      ;; store the current window width
+      (setq speedbar--window-width
+	    (let ((current-width (speedbar-window--width)))
+	      (if (> current-width speedbar-window-max-width)
+		  speedbar-window-max-width
+		current-width)))
+
+      (delete-window speedbar--window)
+      (setq speedbar--window nil
+	    speedbar-frame nil
+	    dframe-attached-frame nil)
+      (speedbar-set-timer nil)
+      (kill-buffer speedbar-buffer)
+      (setq speedbar-buffer nil)
+      (when (and current-window (window-live-p current-window))
+	(select-window current-window)))))
+
 (defun speedbar-frame-reposition-smartly ()
   "Reposition the speedbar frame to be next to the attached frame."
   (cond ((or (assoc 'left speedbar-frame-parameters)
@@ -951,10 +1143,6 @@ speedbar-frame-reposition-smartly
 				  (dframe-attached-frame speedbar-frame)
 				  speedbar-default-position))))
 
-(defsubst speedbar-current-frame ()
-  "Return the frame to use for speedbar based on current context."
-  (dframe-current-frame 'speedbar-frame 'speedbar-mode))
-
 (defun speedbar-handle-delete-frame (e)
   "Handle a delete frame event E.
 If the deleted frame is the frame speedbar is attached to,
@@ -980,6 +1168,14 @@ speedbar-frame-width
 Return nil if it doesn't exist."
   (frame-width speedbar-frame))
 
+(defun speedbar-width ()
+  "Return the width of the `speedbar'.
+if `speedbar-window-mode' is open, the width is `speedbar-window--width'
+otherwise the width is `speedbar-frame-width'."
+  (if (speedbar-window--live-p)
+      (speedbar-window--width)
+    (speedbar-frame-width)))
+
 (define-derived-mode speedbar-mode fundamental-mode "Speedbar"
   "Major mode for managing a display of directories and tags.
 \\<speedbar-mode-map>
@@ -1066,7 +1262,7 @@ speedbar-set-mode-line-format
   (if (and (frame-live-p (speedbar-current-frame))
 	   speedbar-buffer)
       (with-current-buffer speedbar-buffer
-	(let* ((w (or (speedbar-frame-width) 20))
+	(let* ((w (or (speedbar-width) 20))
 	       (p1 "<<")
 	       (p5 ">>")
 	       (p3 (if speedbar-update-flag "#" "!"))
@@ -1128,7 +1324,7 @@ speedbar-reconfigure-keymaps
 			    (setq alist (cdr alist)))
 			  displays)))
 	    ;; The trailer
-	    speedbar-easymenu-definition-trailer))
+	    (speedbar-easymenu-definition-trailer)))
 	(localmap (save-excursion
 		    (let ((cf (selected-frame)))
 		      (prog2
@@ -1838,7 +2034,7 @@ speedbar-directory-buttons
       ;; Nuke the beginning of the directory if it's too long...
       (cond ((eq speedbar-directory-button-trim-method 'span)
 	     (beginning-of-line)
-	     (let ((ww (or (speedbar-frame-width) 20)))
+	     (let ((ww (or (speedbar-width) 20)))
 	       (move-to-column ww nil)
 	       (while (>= (current-column) ww)
 		 (re-search-backward "[/\\]" nil t)
@@ -1854,7 +2050,7 @@ speedbar-directory-buttons
 		   (move-to-column ww nil)))))
 	    ((eq speedbar-directory-button-trim-method 'trim)
 	     (end-of-line)
-	     (let ((ww (or (speedbar-frame-width) 20))
+	     (let ((ww (or (speedbar-width) 20))
 		   (tl (current-column)))
 	       (if (< ww tl)
 		   (progn
@@ -2525,56 +2721,67 @@ speedbar-set-timer
   ;; change this if it changed for some reason
   (speedbar-set-mode-line-format))
 
+(defun speedbar--speedbar-live-p ()
+  "Return non-nil if `speedbar-window-mode' or `speedbar-frame-mode' are active."
+  (cond
+   ((and (speedbar-current-frame)
+	 (frame-live-p (speedbar-current-frame)))
+    t)
+   ((speedbar-window--window-live-p) t)
+   (t nil)))
+
 (defun speedbar-timer-fn ()
   "Run whenever Emacs is idle to update the speedbar item."
-  (if (or (not (speedbar-current-frame))
-	  (not (frame-live-p (speedbar-current-frame))))
+  (if (not (speedbar--speedbar-live-p))
       (speedbar-set-timer nil)
     ;; Save all the match data so that we don't mess up executing fns
     (save-match-data
       ;; Only do stuff if the frame is visible, not an icon, and if
       ;; it is currently flagged to do something.
       (if (and speedbar-update-flag
-	       (speedbar-current-frame)
+	       (or (speedbar-window-current-window)
+		   (speedbar-current-frame))
 	       (frame-visible-p (speedbar-current-frame))
 	       (not (eq (frame-visible-p (speedbar-current-frame)) 'icon)))
 	  (let ((af (selected-frame)))
-	      (dframe-select-attached-frame speedbar-frame)
-	      ;; make sure we at least choose a window to
-	      ;; get a good directory from
-	      (if (window-minibuffer-p)
-		  nil
-		;; Check for special modes
-		(speedbar-maybe-add-localized-support (current-buffer))
-		;; Update for special mode all the time!
-		(if (and speedbar-mode-specific-contents-flag
-			 (consp speedbar-special-mode-expansion-list)
-			 (local-variable-p
-			  'speedbar-special-mode-expansion-list
-			  (current-buffer)))
-		    ;;(eq (get major-mode 'mode-class 'special)))
-		    (progn
-		      (if (<= 2 speedbar-verbosity-level)
+	    (dframe-select-attached-frame speedbar-frame)
+	    ;; make sure we at least choose a window to
+	    ;; get a good directory from
+	    (if (window-minibuffer-p)
+		nil
+	      ;; Check for special modes
+	      (speedbar-maybe-add-localized-support (current-buffer))
+	      ;; Update for special mode all the time!
+	      (if (and speedbar-mode-specific-contents-flag
+		       (consp speedbar-special-mode-expansion-list)
+		       (local-variable-p
+			'speedbar-special-mode-expansion-list
+			(current-buffer)))
+		  ;;(eq (get major-mode 'mode-class 'special)))
+		  (progn
+		    (if (<= 2 speedbar-verbosity-level)
+			(dframe-message
+			 "Updating speedbar to special mode: %s..."
+			 major-mode))
+		    (speedbar-update-special-contents)
+		    (if (<= 2 speedbar-verbosity-level)
+			(progn
 			  (dframe-message
-			   "Updating speedbar to special mode: %s..."
-			   major-mode))
-		      (speedbar-update-special-contents)
-		      (if (<= 2 speedbar-verbosity-level)
-			  (progn
-			    (dframe-message
-			     "Updating speedbar to special mode: %s...done"
-			     major-mode)
-			    (dframe-message nil))))
-
- 		  ;; Update all the contents if directories change!
- 		  (unless (and (or (member major-mode speedbar-ignored-modes)
-				   (eq af (speedbar-current-frame))
-				   (not (buffer-file-name)))
-			       ;; Always update for GUD.
-			       (not (string-equal "GUD"
-				     speedbar-initial-expansion-list-name)))
-		    (speedbar-update-localized-contents)))
-		(select-frame af))
+			   "Updating speedbar to special mode: %s...done"
+			   major-mode)
+			  (dframe-message nil))))
+
+		;; Update all the contents if directories change!
+		(unless (and (or (member major-mode speedbar-ignored-modes)
+				 (and
+				  (eq af (speedbar-current-frame))
+				  (speedbar-window-current-window))
+				 (not (buffer-file-name)))
+			     ;; Always update for GUD.
+			     (not (string-equal "GUD"
+						speedbar-initial-expansion-list-name)))
+		  (speedbar-update-localized-contents)))
+	      (select-frame af))
 	    ;; Now run stealthy updates of time-consuming items
 	    (speedbar-stealthy-updates)))))
   (run-hooks 'speedbar-timer-hook))
@@ -3363,13 +3570,6 @@ speedbar-tag-expand
 
 ;;; Loading files into the attached frame.
 ;;
-(defcustom speedbar-select-frame-method 'attached
-  "Specify how to select a frame for displaying a file.
-A number such as 1 or -1 means to pass that number to `other-frame'
-while selecting a frame from speedbar.  Any other value means to use
-the attached frame (the frame that speedbar was started from)."
-  :group 'speedbar
-  :type '(choice integer (other :tag "attached" attached)))
 
 (defun speedbar-find-file-in-frame (file)
   "This will load FILE into the speedbar attached frame.
-- 
2.48.1