Emacs/GDB: always display source in specific window with gdb-many-windows
Asked Answered
S

3

8

I use GDB in Emacs 24 with gdb-many-windows set to t, usually in its own frame. I like to have a separate editing frame. It looks like this (apologies for my crude ASCII diagram):

+-------------+-------------+
| gdb         | locals      |
+-------------+-------------+
| source      | I/O         |
|             |             |
+-------------+-------------+
| stack       | breakpoints |
+-------------+-------------+

This works pretty well except for one big problem. Whenever gdb needs to display a different source buffer, e.g., after up/down/step, it doesn't always show it in the "source" window. For example, if I have the same buffer open in a window in a different frame, it will raise that frame while keeping keyboard focus in the gdb frame. This is really annoying on a single-monitor setup when the frames cover each other.

I'd like gdb to always use the source window in the gdb-many-windows setup to display source, no matter if the same source buffer is displayed elsewhere. How can I do that?


EDIT: More detailed instructions to reproduce. I'm using Emacs 24.2.1 with GDB 7.5-ubuntu. I've seen this problem on Ubuntu 10.04 and Linux Mint Nadia with Cinnamon.

  • Evaluate this expression: (setq gdb-many-windows t)
  • Compile a C program with at least two files.

For example:

// foo.c
void bar(int);
void foo(int c) {
  if (c > 0)
    bar(c - 1);
}
int main(void) {
  foo(100);
  return 0;
}

// bar.c
void foo(int c);
void bar(int c) {
  if (c > 0)
    foo(c - 2);
}

// compile with gcc -g -O0 foo.c bar.c -o test
  • Let bar.c be displayed in the main frame. Open a new frame with M-x 5 2. In that frame, start gdb with M-x gdb. There should be six windows in that frame as shown above. Position the gdb frame on top of the source frame.
  • Set a breakpoint in main and step through calls to foo and bar. When bar is called, the main frame will be raised over the gdb frame since bar.c is already visible there, but keyboard focus will stay in the gdb frame.

I think the problem function is gdb-display-source-buffer in gud.el.gz. I'm planning to try overriding this with defadvice, but I'm not really familiar with advice. If I figure it out, I'll post an answer here.

Shonda answered 26/11, 2013 at 19:52 Comment(4)
Can't reproduce the problem.Hedonics
@Jay Conrod: Could you please tell us whether you still have this problem. If so, please give the full version numbers of your Emacs and gdb. Furthermore, please try also emacs -q to detect potential problems with your configuration. Also try to provide a minimal example. I.e., small source files and step-by-step instructions to reproduce the problem.Poverty
@Tobias, added detailed instructions to reproduce. Let me know if I can clarify anything else.Shonda
on debian with emacs 24.4.1, this still happens to me. FWIW, i found a bug report, but without (yet) any patch: lists.gnu.org/archive/html/bug-gnu-emacs/2014-06/msg00097.htmlZomba
P
1

I have 24.3. And I cannot reproduce the problem with this version. There gud-display-line looks as follows:

(defun gud-display-line (true-file line)
  (let* ((last-nonmenu-event t)  ; Prevent use of dialog box for questions.
     (buffer
      (with-current-buffer gud-comint-buffer
        (gud-find-file true-file)))
     (window (and buffer
              (or (get-buffer-window buffer)
              (display-buffer buffer))))
     (pos))
    (when buffer
      (with-current-buffer buffer
    (unless (or (verify-visited-file-modtime buffer) gud-keep-buffer)
      (if (yes-or-no-p
           (format "File %s changed on disk.  Reread from disk? "
               (buffer-name)))
          (revert-buffer t t)
        (setq gud-keep-buffer t)))
    (save-restriction
      (widen)
      (goto-char (point-min))
      (forward-line (1- line))
      (setq pos (point))
      (or gud-overlay-arrow-position
          (setq gud-overlay-arrow-position (make-marker)))
      (set-marker gud-overlay-arrow-position (point) (current-buffer))
      ;; If they turned on hl-line, move the hl-line highlight to
      ;; the arrow's line.
      (when (featurep 'hl-line)
        (cond
         (global-hl-line-mode
          (global-hl-line-highlight))
         ((and hl-line-mode hl-line-sticky-flag)
          (hl-line-highlight)))))
    (cond ((or (< pos (point-min)) (> pos (point-max)))
           (widen)
           (goto-char pos))))
      (when window
    (set-window-point window gud-overlay-arrow-position)
    (if (eq gud-minor-mode 'gdbmi)
        (setq gdb-source-window window))))))

The window setting is completely different from yours. Maybe, the above code is helpful or maybe you should upgrade to the new gud/gdb stuff.

Poverty answered 4/12, 2013 at 22:31 Comment(3)
Thanks, I'll try upgrading soon in the next day or two. I'm a little skeptical though, since get-buffer-window is still in there, and I think that may be what caused the problem earlier.Shonda
I've tried multiple scenarios such as: start with emacs -q, open many c-files, open three frames, maximize frames. The problem could not be re-produced with emacs 24.3 in any of these cases. Did you try with emacs -q?Poverty
I upgraded my emacs at home to 24.3, and I don't see the problem anymore. up/down/frame also work as expected. Not sure why it works exactly, but it does! Thanks for your help.Shonda
S
2

The function causing this problem is actually gud-display-line in gud.el.gz. This function is responsible for positioning the overlay arrow in the source window on the current line and making sure it is visible. Here's the logic:

(let* ...
 (window (and buffer
          (or (get-buffer-window buffer)
          (if (eq gud-minor-mode 'gdbmi)
              (or (if (get-buffer-window buffer 'visible)
                  (display-buffer buffer nil 'visible))
              (unless (gdb-display-source-buffer buffer)
                (gdb-display-buffer buffer nil 'visible))))
          (display-buffer buffer))))

I used defadvice to override the whole function; basically, I copied the source and changed the window selection logic.

(defadvice gud-display-line (around do-it-better activate)
  (let* ...
     (window (and buffer
                  (or (if (eq gud-minor-mode 'gdbmi)
                          (unless (gdb-display-source-buffer buffer)
                            (gdb-display-buffer buffer nil 'visible)))
                      (get-buffer-window buffer)
                      (display-buffer buffer))))
  ...)

Obviously not the most elegant solution. It also doesn't help when switching frames (with up/down/frame), so I'll edit this when I figure that out.

Shonda answered 4/12, 2013 at 22:15 Comment(1)
Using defadvice this way worked for me on Debian Jessie with emacs24-common 24.4+1-5. Has anyone simply submitted this as a bug report and patch? Even if it's imperfect in some way, it seems worth re-reporting with a fix. Presumably a maintainer could polish it enough to apply if they knew the issue?Torhert
P
1

I have 24.3. And I cannot reproduce the problem with this version. There gud-display-line looks as follows:

(defun gud-display-line (true-file line)
  (let* ((last-nonmenu-event t)  ; Prevent use of dialog box for questions.
     (buffer
      (with-current-buffer gud-comint-buffer
        (gud-find-file true-file)))
     (window (and buffer
              (or (get-buffer-window buffer)
              (display-buffer buffer))))
     (pos))
    (when buffer
      (with-current-buffer buffer
    (unless (or (verify-visited-file-modtime buffer) gud-keep-buffer)
      (if (yes-or-no-p
           (format "File %s changed on disk.  Reread from disk? "
               (buffer-name)))
          (revert-buffer t t)
        (setq gud-keep-buffer t)))
    (save-restriction
      (widen)
      (goto-char (point-min))
      (forward-line (1- line))
      (setq pos (point))
      (or gud-overlay-arrow-position
          (setq gud-overlay-arrow-position (make-marker)))
      (set-marker gud-overlay-arrow-position (point) (current-buffer))
      ;; If they turned on hl-line, move the hl-line highlight to
      ;; the arrow's line.
      (when (featurep 'hl-line)
        (cond
         (global-hl-line-mode
          (global-hl-line-highlight))
         ((and hl-line-mode hl-line-sticky-flag)
          (hl-line-highlight)))))
    (cond ((or (< pos (point-min)) (> pos (point-max)))
           (widen)
           (goto-char pos))))
      (when window
    (set-window-point window gud-overlay-arrow-position)
    (if (eq gud-minor-mode 'gdbmi)
        (setq gdb-source-window window))))))

The window setting is completely different from yours. Maybe, the above code is helpful or maybe you should upgrade to the new gud/gdb stuff.

Poverty answered 4/12, 2013 at 22:31 Comment(3)
Thanks, I'll try upgrading soon in the next day or two. I'm a little skeptical though, since get-buffer-window is still in there, and I think that may be what caused the problem earlier.Shonda
I've tried multiple scenarios such as: start with emacs -q, open many c-files, open three frames, maximize frames. The problem could not be re-produced with emacs 24.3 in any of these cases. Did you try with emacs -q?Poverty
I upgraded my emacs at home to 24.3, and I don't see the problem anymore. up/down/frame also work as expected. Not sure why it works exactly, but it does! Thanks for your help.Shonda
I
-1

I run Emacs 24.5 and for me this is still an issue. I manage my windows manually with dedicated windows now, mainly with the following function:

(defun gdb-restore-windows-gud-io-and-source ()
  "Restore GUD buffer, IO buffer and source buffer next to each other."
  (interactive)
  ;; Select dedicated GUD buffer.
  (switch-to-buffer gud-comint-buffer)
  (delete-other-windows)
  (set-window-dedicated-p (get-buffer-window) t)
  (when (or gud-last-last-frame gdb-show-main)
    (let ((side-win (split-window nil nil t))
          (bottom-win (split-window)))
      ;; Put source to the right.
      (set-window-buffer
       side-win
       (if gud-last-last-frame
           (gud-find-file (car gud-last-last-frame))
         (gud-find-file gdb-main-file)))
      (setq gdb-source-window side-win)
      ;; Show dedicated IO buffer at the bottom.
      (set-window-buffer
       bottom-win
       (gdb-get-buffer-create 'gdb-inferior-io))
      (set-window-dedicated-p bottom-win t))))

This shows the GUD window at the top left, the IO buffer at the bottom left and sets the source buffer to the right side. The GUD and the IO buffer are set to dedicated.

Innutrition answered 1/6, 2015 at 11:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.