13

Q: how can I control which window org-deadline uses to display the calendar?

org-deadline temporarily pops up the calendar buffer in a window when setting a deadline, and then closes it again after completing. When there is only one window, it pops a new window at the bottom of the existing frame. When there are multiple windows, it selects one -- I presume with something like get-lru-window -- of the available windows.

The latter is problematic if it takes over one of the other windows that has the information I need in order to set the deadline (date, time, etc.) This is commonly a problem in a window setup such as:

+--------------------+--------------------+
|                    |                    |
|                    |  (B: mu4e header)  |
|                    |                    |
|                    +--------------------+
|  (A: agenda file)  |                    |
|                    |                    |
|                    |                    |
|                    |  (C: mu4e view)    |
|                    |                    |
|                    |                    |
|                    |                    |
+--------------------+--------------------+

When adding a deadline to the agenda file in (A), org-deadline will take over (B) or (C), which contain emails that have the date/time information I need. I'd much prefer that, if I'm calling org-deadline from (A), it would pop a temporary window (D) to contain the calendar buffer as below:

+--------------------+--------------------+
|                    |                    |
|                    |  (B: mu4e header)  |
|                    |                    |
|                    +--------------------+
|  (A: agenda file)  |                    |
|                    |                    |
|                    |                    |
+--------------------+  (C: mu4e view)    |
|                    |                    |
|   (D: calendar)    |                    |
|                    |                    |
+--------------------+--------------------+

So: how would one force org-deadline (and analogous functions) to pop a new, temporary window at the bottom of the active window rather than take over one of the other ones?

PS: I'm aware of dedicated windows, but they don't strike me as the best approach since it's not so much that I want to dedicate buffers to windows as I want to avoid having a function take over one of the "short" ones.

Malabarba
  • 22,878
  • 6
  • 78
  • 163
Dan
  • 32,584
  • 6
  • 98
  • 168
  • I really hope somebody comes back with an answer that gives fine control over new, temporary windows. ([popwin.el](http://www.emacswiki.org/PopWin)? `display-buffer-alist`?) But I think there's an additional wrinkle here because `org-deadline` uses `calendar` which itself goes way out of its way to control what window to use. c.f. the comments in `calendar-basic-setup`. – purple_arrows Oct 06 '14 at 14:34

1 Answers1

10

Following should do what you want.

(defun my-window-displaying-agenda-p (window)
    (equal (with-current-buffer (window-buffer window) major-mode)
        'org-agenda-mode)) 

(defun my-position-calendar-buffer (buffer alist)
  (let ((agenda-window (car (remove-if-not #'my-window-displaying-agenda-p (window-list)))))
    (when agenda-window
      (let ((desired-window (split-window agenda-window nil 'below)))
        (set-window-buffer desired-window  buffer)
        desired-window))))

(add-to-list 'display-buffer-alist (cons "\\*Calendar\\*" (cons #'my-position-calendar-buffer nil)))

Calendar uses the function calendar-basic-setup to display the calendar buffer, calendar-basic-setup in turn uses pop-to-buffer which in turn uses display-buffer to display the calendar buffer. Now display-buffer is highly customizable and allows us to provide functions to display a buffer using certain variables we use one such variable display-buffer-alist here.

Basically we are saying emacs to use the function my-position-calendar-buffer to display a buffer matching the regexp \*Calendar\*. The function my-position-calendar-buffer searches for a window displaying org agenda, if it does not find any such window, it does nothing in which case display-buffer will try some other functions to display the buffer. In case a window displaying org-agenda is found the function splits that window vertically and displays the calendar buffer.

I have not tested this throughly (just tried starting calendar with agenda view and without agenda view), it seems to be working but there might be some bugs.

Iqbal Ansari
  • 7,468
  • 1
  • 28
  • 31
  • 1
    It would be preferable to use something like `add-to-list` on display-buffer-alist. Using `setq` overrides other customizations. – Malabarba Oct 06 '14 at 21:37
  • @Malabarba thanks for the suggestion, fixed! – Iqbal Ansari Oct 07 '14 at 00:48
  • Just an update for those running into this answer with emas version > 24.X: to use the code above you need to replace `remove-if-not` with `cl-remove-if-not`. – apc Jun 24 '20 at 14:38
  • Not sure about earlier ones, but at least in emacs 27 and 28, `remove-if-not` still exists as an alias to `cl-remove-if-not`. That might elicit a warning, but it is not going to break. But @apc is correct that you should fix the code: the alias might go away eventually. At least for now, though, you don't *need* to. – NickD Jul 12 '21 at 14:28