This repository has been archived by the owner on Aug 17, 2020. It is now read-only.
forked from DarwinAwardWinner/mac-pseudo-daemon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
osx-pseudo-daemon.el
152 lines (130 loc) · 5.67 KB
/
osx-pseudo-daemon.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
;;; osx-pseudo-daemon.el --- Daemon mode that plays nice with OSX.
;; Author: Ryan C. Thompson
;; URL: https://github.com/DarwinAwardWinner/osx-pseudo-daemon
;; Version: 1.0
;; Created: 2013-09-20
;; Keywords: convenience osx
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;; On OSX, if you use Cocoa Emacs' daemon mode and then close all GUI
;; frames, the Emacs app on your dock becomes nonfunctional until you
;; open a new GUI frame using emacsclient on the command line. This is
;; obviously suboptimal. This package makes it so that whenever you
;; close the last GUI frame, a new frame is created and the Emacs app
;; is hidden, thus approximating the behvaior of daemon mode while
;; keeping the Emacs dock icon functional. To actually quit instead of
;; hiding Emacs, use CMD+Q (or Alt+Q if you swapped Alt & Command
;; keys).
;;; License:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
;; Try to require ns to ensure that (featurep 'mac) is t if ns is
;; available.
(require 'mac nil 'noerror)
;;;###autoload
(defgroup osx-pseudo-daemon nil
"Emulate daemon mode in OSX by hiding Emacs when you kill the last GUI frame.")
;;;###autoload
(define-minor-mode osx-pseudo-daemon-mode
"Emulate daemon mode in OSX by hiding Emacs when you kill the last GUI frame.
On OSX, if you use Cocoa Emacs' daemon mode and then close all
GUI frames, the Emacs app on your dock becomes nonfunctional
until you open a new GUI frame using emacsclient on the command
line. This is obviously suboptimal. This package makes it so that
whenever you close the last GUI frame, a new frame is created and
the Emacs app is hidden, thus approximating the behvaior of
daemon mode while keeping the Emacs dock icon functional. To
actually quit instead of hiding Emacs, use CMD+Q (or Alt+Q if you
swapped Alt & Command keys).
This mode has no effect unless Emacs is running on OSX with the
Cocoa GUI, so it is safe to enable it unconditionally on all
platforms.
"
:group 'osx-pseudo-daemon
:global t
;; Enable by default on OSX
:init-value (featurep 'mac))
(defun mac-hide-emacs ()
"On a Mac, hide all applications other than Emacs and the frontmost
application."
(interactive)
(do-applescript (concat "tell application \"System Events\" to "
" tell process \"Emacs\" to set visible to false")))
(defun osxpd-frame-is-last-ns-frame (frame)
"Returns t if FRAME is the only NS frame."
(and
(featurep 'mac)
;; Frame is ns frame
(eq (framep frame) 'mac)
;; No other frames on same terminal
(>= 1 (length (filtered-frame-list
(lambda (frm) (eq (frame-terminal frm)
(frame-terminal frame))))))))
(defun osxpd-keep-at-least-one-ns-frame (frame)
"If FRAME is the last NS frame, open a new hidden NS frame.
This is called immediately prior to FRAME being closed."
(when (featurep 'mac)
(let ((frame (or frame (selected-frame))))
(when (osxpd-frame-is-last-ns-frame frame)
(progn
;; If FRAME is fullscreen, un-fullscreen it.
(when (eq (frame-parameter frame 'fullscreen)
'fullboth)
(set-frame-parameter frame 'fullscreen nil)
;; Wait for fullscreen animation
(sit-for 1.5))
;; Create a new frame on same terminal as FRAME, then restore
;; selected frame.
(let ((sf (selected-frame)))
(select-frame frame)
(make-frame)
(switch-to-buffer "*scratch*")
(select-frame sf))
;; Making a frame might unhide emacs, so hide again
(sit-for 0.1)
;; (ns-hide-emacs t)
(mac-hide-emacs)
)))))
;; TODO: Is `delete-frame-hook' an appropriate place for this?
(defadvice delete-frame (before osxpd-keep-at-least-one-ns-frame activate)
"When the last NS frame is deleted, create a new hidden one first."
(when osx-pseudo-daemon-mode
(osxpd-keep-at-least-one-ns-frame frame)))
;; This is the function that gets called when you click the X button
;; on the window's title bar.
(defadvice handle-delete-frame (around osxpd-never-quit-ns-emacs activate)
"Never invoke `save-buffers-kill-emacs' when deleting NS frame.
Instead, just delete the frame as normal."
(let ((frame (posn-window (event-start event))))
(if (and osx-pseudo-daemon-mode
(eq 'mac (framep frame)))
(delete-frame frame t)
ad-do-it)))
(defadvice save-buffers-kill-terminal (around osx-pseudo-daemon activate)
"When killing an NS terminal, instead just delete all NS frames."
(let ((frame (selected-frame)))
(if (and osx-pseudo-daemon-mode
(eq 'mac (framep frame)))
;; For NS GUI, just delete all NS frames. A new hidden one
;; will automatically be spawned by the advice to
;; `delete-frame'.
(mapc 'delete-frame
(filtered-frame-list
(lambda (frm) (eq (frame-terminal frm)
(frame-terminal frame)))))
ad-do-it)))
(provide 'osx-pseudo-daemon)
;;; osx-pseudo-daemon.el ends here