[xmonad] Working emacs minibuffer frame

Jonas Bernoulli jonas at bernoul.li
Sat Jun 6 13:24:25 EDT 2009


Hi

I have started using Xmonad and learning Haskell two days ago and the
first thing I did was to try to get the Emacs minibuffer frame to show
up at the bottom of each workspace. And I succeeded - but it's not
perfect yet.

I have read this [1] thread, which helped to get started.

After searching the Emacs C part for quite a while for the right place
to implement the minibuffer strut I came across
x-change-window-property which lets you do it from Emacs Lisp, like
so:

;; Create the minibuffer frame.
(setq default-minibuffer-frame (make-frame '((minibuffer . only))))

;; Make the minibuffer frame a strut at the bottom.
;; See http://standards.freedesktop.org/wm-spec/1.3/ar01s05.html#id2523368
;; Second argument has the form:
;; (left_width right_width top_height bottom_height
;;  left_start_y left_end_y right_start_y right_end_y
;;  top_start_x top_end_x bottom_start_x bottom_end_x)
(x-change-window-property "_NET_WM_STRUT_PARTIAL"
   			  '(0 0 0 34
			    0 0 0 0
			    0 0 0 2559)
   			  default-minibuffer-frame "CARDINAL" 32 t)

;; Make all other frames use the default minibuffer frame.
(modify-all-frames-parameters '((minibuffer . nil)))

That does not work however. Xmonad does correctly reserve space for
the strut but the minibuffer frame is still tilted.

The EWMH spec states [2] that window managers MUST watch for property
notify events if the Window Manager uses [the _NET_WM_STRUT_PARTIAL]
property to assign special semantics to the window.

Xmonad does that partially. The minibuffer window (frame) changes this
property after it was created and Xmonad correctly reserves space for
the window but fails to move the window to the correct location and
resize it accordingly. (It also does not remove the border but this is
not required by EWMH.)

Their are basically two ways to fix this:

1. Make Xmonad follow the EWMH spec more closely, or
2. Edit Emacs C code to set the property before the window is drawn.

I do not know enough about Xmonad and Haskell yet to do (1) just now.
And C isn't my strength either but I could probably do it by copying
code from dzen and adapting it to the needs of Emacs. But since it
would probably take a while for such a patch to get into Emacs, and
(1) is the better solution anyway I think that should be preferred.

Well I just started learning Haskell so this will take a while, so I
would welcome it if someone else did it. Until then here is a
workaround:

In ~/.xmonad/xmonad.hs

import XMonad.Hooks.ManageDocks
import XMonad.Actions.DeManage

myKeys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
    [ ((modMask,               xK_y     ), withFocused demanage)
    ...]

main = do
  xmonad $ defaultConfig
    { manageHook        = manageDocks
                          <+> manageHook defaultConfig
                          <+> composeAll [ title =? "EmacsMinibuffer"
--> doFloat ]
    ...}

In ~/.emacs.d/init.el

(setq default-minibuffer-frame
      (make-frame '((minibuffer . only) ; t might also be in nice
		    ;; If omitted title defaults to " *Minibuf-0*"
		    ;; but Xmonad does not seam to like that.
		    (title  . "EmacsMinibuffer")
		    ;; Position the window manually.
		    (left   . 0)      ; in pixels
		    (top    . 1566)   ; in pixels
		    (width  . 282)    ; in characters
		    (height . 2))))      ; in text lines

(x-change-window-property "_NET_WM_STRUT_PARTIAL"
   			  '(0 0 0 34
			    0 0 0 0
			    0 0 0 2559)
   			  default-minibuffer-frame "CARDINAL" 32 t)

(modify-all-frames-parameters '((minibuffer . nil)))

Then you have to select the minibuffer frame and press modKey-y.

And of course you would have to change the numbers above to
accommodate your setup. (The Emacs lisp code above could be extended
to figure it out on it's own, something I might do when I find time.)

Even though Xmonad does not everything required to support the strut
property being set after some window was created, it is still better
to use x-change-window-property to set strut because the alternative
of using something like:

import XMonad.Layout.Gaps

myLayout = gaps [ (D,32) ] $ Grid ||| Full

is not so good. When Emacs is closed the space reserved for the
minibuffer frame is not made available again. With the strut approach
it is.

I can live with the current state, but will investigate ways to
improve it once I have time. But again, people knowing more about
Haskell and Xmonad are very welcome to take it from here.


Best regards

Jonas



Ps. As much as Drew's libraries usually work out-of-the-box,
oneonone.el [3] just blew up in my face when used with Xmonad and a
dark background (these are unrelated, but oneonone sucks equally at
both).

Pps. I plan to write a xmonad.el to implement some of OneOnOne idea
and then some more optimized for Xmonad. Like automatically determine
size and location of the minibuffer frame and a dedicated
*Completions* frame and strut sidebar ... . Of course this will be
much easier once Xmonad fully supports changes to
_NET_WM_STRUT_PARTIAL.

Pps. Emacs could even be used wherever dzen, xmobar, dmenu and similar
apps are currently are used. Wouldn't that be great!

[1] http://www.haskell.org/pipermail/xmonad/2009-May/007854.html
[2] http://standards.freedesktop.org/wm-spec/1.3/ar01s05.html#id2523368
[3] http://www.emacswiki.org/emacs/OneOnOneEmacs


More information about the xmonad mailing list