Emacs as daemon on OS X with window-system
I'm running gnu emacs 23.3.1 cocoa build on OS X 10.6.
I added the following to ~/Library/LaunchAgents/gnu.emacs.daemon.plist so that it will start a daemon and automatically restart emacs if I inadvertently kill it.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>gnu.emacs.daemon</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Emacs.app/Contents/MacOS/Emacs</string>
<string>--daemon</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>ServiceDescription</key>
<string>Gnu Emacs Daemon</string>
</dict>
</plist>
This sorta works but I noticed that my color theme wasn't working properly. Then I remembered I had added the following to my init file:
(when window-system
(require 'alpha)
(require 'color-theme-ir-black)
(modify-frame-parameters (selected-frame) '((alpha . 85)))
(color-theme-ir-black))
When started as a daemon window-system is false apparently and that makes sense, however the reason I added this is because I occasionally like to start the normal emacs build in a terminal from ssh etc and this color scheme is completely unreadable in iTerm thus the (when window-system ...). Is there a way to force emacs to start window mode when start with --daemon?
Another issue I have noticed is that when I run press s-w (delete-frame) in dameon mode I don't get the error attempt to delete sole visible or iconified frame and emacs continues to run in the background. I like this for the most part however I have noticed that once the last frame is killed I can no longer reopen emacs from the doc and although emacs will activate and menus are displayed they don't work and I can't create a new frame except by using emacsclient from the commandline. Anyone else have this issue and or recommendation on workaround? perhaps I can bind s-w to detect if last frame and iconify-frame instead, but not sure why it thinks its not the last window and allowed me to kill it in the first place.
UPDATE:
I found a comment on the following blog by Steve Purcell with a fix for a very similar problem: http://emacs-fu.blogspot.com/2009/03/color-theming.html
The secret it seems is to use 'after-make-frame-functions hook to setup the newly created frame and also to (setq color-theme-is-global nil) so that each frame can have its own color theme. So the relevant sections of my init now looks like this:
(defvar after-make-console-frame-hooks '()
"Hooks to run after creating a new TTY frame")
(defvar after-make-window-system-frame-hooks '()
"Hooks to run after creating a new window-system frame")
(defun run-after-make-frame-hooks (frame)
"Selectively run either `after-make-console-frame-hooks' or
`after-make-window-system-frame-hooks'"
(select-frame frame)
(run-hooks (if window-system
'after-make-window-system-frame-hooks
'after-make-console-frame-hooks)))
(add-hook 'after-make-frame-functions 'run-after-make-frame-hooks)
(add-hook 'after-init-hook (lambda ()
(run-after-make-frame-hooks (selected-frame))))
(setq color-theme-is-global nil)
(add-hook 'after-make-window-system-frame-hooks
'(lambda ()
(require 'alpha)
(require 'color-theme-ir-black)
(modify-frame-parameters (selected-frame) '((alpha . 85)))
(color-theme-ir-black)
(global-set-key (kbd "s-w") 'delete-frame)))
However, I am still having the issue where delete-frame closes the last frame when emacs was started as daemon and not allowing me to create a new frame other then by using emacsclient.
UPDATE:
If I eval (frame-list)
I see there are 2 frames listed even though only one is visible. I noticed that this does not occur if I start Emacs with open /Applications/Emacs.app
instead of emacsclient. I normally start emacs from the commandline with an alias e='emacsclient -c -n '
which is what creates the second frame. I can only seem to attach to the other frame by starting emacs with the open command. If I try emacsclient -n somefile without -c
I get nothing, and if I run emacsclient -n -e '(frame-list)'
I see there is a frame its just not visible until I use -c
to create new frame or open emacs from the applications folder.
Solution 1:
Running a process or application as a launchd daemon gives it a very different environment from running it normally or on the command line. I wonder if it might not work better to instead use a shell script as a login item.
For example:
#!/bin/bash
while true
do
open -W /Applications/Emacs.app
done
This script would need to be saved to a file with a .command
extension and 755 permissions (chmod 0755 myemacsscript.command
) and then added to the System Preferences : Login : Login Items pane.
When you login, Terminal will launch and run this script. You will probably want to setup a default terminal profile that excludes terminal from prompting on quit for this particular script, so that it doesn't hold you up when you log out.
I have no idea if this will fix the particular problems with Emacs.app, but it may at least provide an environment closer to what Emacs.app expects.