More CL cleanups and reduction of use of cl.el.
[bpt/emacs.git] / lisp / term / ns-win.el
CommitLineData
e95a67dc 1;;; ns-win.el --- lisp side of interface with NeXT/Open/GNUstep/MacOS X window system -*- lexical-binding: t -*-
c0642f6d 2
acaf905b 3;; Copyright (C) 1993-1994, 2005-2012 Free Software Foundation, Inc.
c0642f6d 4
c5220417
GM
5;; Authors: Carl Edman
6;; Christian Limpach
7;; Scott Bender
8;; Christophe de Dinechin
9;; Adrian Robert
c0642f6d
GM
10;; Keywords: terminals
11
12;; This file is part of GNU Emacs.
13
14;; GNU Emacs is free software: you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation, either version 3 of the License, or
17;; (at your option) any later version.
18
19;; GNU Emacs is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
25;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
edfda783
AR
26
27;;; Commentary:
28
a5a1b464
CY
29;; ns-win.el: this file is loaded from ../lisp/startup.el when it
30;; recognizes that Nextstep windows are to be used. Command line
31;; switches are parsed and those pertaining to Nextstep are processed
32;; and removed from the command line. The Nextstep display is opened
33;; and hooks are set for popping up the initial window.
edfda783
AR
34
35;; startup.el will then examine startup files, and eventually call the hooks
36;; which create the first window (s).
37
a5a1b464
CY
38;; A number of other Nextstep convenience functions are defined in
39;; this file, which works in close coordination with src/nsfns.m.
edfda783
AR
40
41;;; Code:
42
725513b7 43(or (featurep 'ns)
3dcdb6ea 44 (error "%s: Loading ns-win.el but not compiled for GNUstep/MacOS"
725513b7 45 (invocation-name)))
ebe68042 46
1bcc4637 47;; Documentation-purposes only: actually loaded in loadup.el.
edfda783
AR
48(require 'frame)
49(require 'mouse)
50(require 'faces)
edfda783
AR
51(require 'menu-bar)
52(require 'fontset)
53
20bc68dd
GM
54(defgroup ns nil
55 "GNUstep/Mac OS X specific features."
56 :group 'environment)
57
edfda783
AR
58;;;; Command line argument handling.
59
d7d8c62a
GM
60(defvar x-invocation-args)
61(defvar ns-command-line-resources nil) ; FIXME unused?
d377ef4a 62
c0642f6d
GM
63;; nsterm.m.
64(defvar ns-input-file)
65
e95a67dc 66(defun ns-handle-nxopen (_switch &optional temp)
1bcc4637
GM
67 (setq unread-command-events (append unread-command-events
68 (if temp '(ns-open-temp-file)
69 '(ns-open-file)))
d7d8c62a 70 ns-input-file (append ns-input-file (list (pop x-invocation-args)))))
edfda783
AR
71
72(defun ns-handle-nxopentemp (switch)
1bcc4637 73 (ns-handle-nxopen switch t))
edfda783 74
e95a67dc 75(defun ns-ignore-1-arg (_switch)
d7d8c62a 76 (setq x-invocation-args (cdr x-invocation-args)))
edfda783 77
489382c5 78(defun ns-parse-geometry (geom)
ba0c843d 79 "Parse a Nextstep-style geometry string GEOM.
edfda783
AR
80Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
81The properties returned may include `top', `left', `height', and `width'."
a5a1b464
CY
82 (when (string-match "\\([0-9]+\\)\\( \\([0-9]+\\)\\( \\([0-9]+\\)\
83\\( \\([0-9]+\\) ?\\)?\\)?\\)?"
84 geom)
85 (apply
86 'append
87 (list
88 (list (cons 'top (string-to-number (match-string 1 geom))))
89 (if (match-string 3 geom)
90 (list (cons 'left (string-to-number (match-string 3 geom)))))
91 (if (match-string 5 geom)
92 (list (cons 'height (string-to-number (match-string 5 geom)))))
93 (if (match-string 7 geom)
94 (list (cons 'width (string-to-number (match-string 7 geom)))))))))
edfda783
AR
95
96;;;; Keyboard mapping.
97
725513b7 98(define-obsolete-variable-alias 'ns-alternatives-map 'x-alternatives-map "24.1")
edfda783 99
a5a1b464 100;; Here are some Nextstep-like bindings for command key sequences.
4c785fa7 101(define-key global-map [?\s-,] 'customize)
edfda783
AR
102(define-key global-map [?\s-'] 'next-multiframe-window)
103(define-key global-map [?\s-`] 'other-frame)
79cb9c05 104(define-key global-map [?\s-~] 'ns-prev-frame)
edfda783
AR
105(define-key global-map [?\s--] 'center-line)
106(define-key global-map [?\s-:] 'ispell)
107(define-key global-map [?\s-\;] 'ispell-next)
108(define-key global-map [?\s-?] 'info)
109(define-key global-map [?\s-^] 'kill-some-buffers)
110(define-key global-map [?\s-&] 'kill-this-buffer)
111(define-key global-map [?\s-C] 'ns-popup-color-panel)
112(define-key global-map [?\s-D] 'dired)
113(define-key global-map [?\s-E] 'edit-abbrevs)
114(define-key global-map [?\s-L] 'shell-command)
115(define-key global-map [?\s-M] 'manual-entry)
116(define-key global-map [?\s-S] 'ns-write-file-using-panel)
117(define-key global-map [?\s-a] 'mark-whole-buffer)
118(define-key global-map [?\s-c] 'ns-copy-including-secondary)
119(define-key global-map [?\s-d] 'isearch-repeat-backward)
120(define-key global-map [?\s-e] 'isearch-yank-kill)
121(define-key global-map [?\s-f] 'isearch-forward)
122(define-key global-map [?\s-g] 'isearch-repeat-forward)
123(define-key global-map [?\s-h] 'ns-do-hide-emacs)
124(define-key global-map [?\s-H] 'ns-do-hide-others)
125(define-key global-map [?\s-j] 'exchange-point-and-mark)
126(define-key global-map [?\s-k] 'kill-this-buffer)
127(define-key global-map [?\s-l] 'goto-line)
128(define-key global-map [?\s-m] 'iconify-frame)
129(define-key global-map [?\s-n] 'make-frame)
130(define-key global-map [?\s-o] 'ns-open-file-using-panel)
131(define-key global-map [?\s-p] 'ns-print-buffer)
132(define-key global-map [?\s-q] 'save-buffers-kill-emacs)
133(define-key global-map [?\s-s] 'save-buffer)
134(define-key global-map [?\s-t] 'ns-popup-font-panel)
135(define-key global-map [?\s-u] 'revert-buffer)
136(define-key global-map [?\s-v] 'yank)
137(define-key global-map [?\s-w] 'delete-frame)
138(define-key global-map [?\s-x] 'kill-region)
139(define-key global-map [?\s-y] 'ns-paste-secondary)
140(define-key global-map [?\s-z] 'undo)
141(define-key global-map [?\s-|] 'shell-command-on-region)
142(define-key global-map [s-kp-bar] 'shell-command-on-region)
ebe68042 143;; (as in Terminal.app)
edfda783
AR
144(define-key global-map [s-right] 'ns-next-frame)
145(define-key global-map [s-left] 'ns-prev-frame)
146
147(define-key global-map [home] 'beginning-of-buffer)
148(define-key global-map [end] 'end-of-buffer)
149(define-key global-map [kp-home] 'beginning-of-buffer)
150(define-key global-map [kp-end] 'end-of-buffer)
ce3cefcc
CY
151(define-key global-map [kp-prior] 'scroll-down-command)
152(define-key global-map [kp-next] 'scroll-up-command)
edfda783 153
1bcc4637 154;; Allow shift-clicks to work similarly to under Nextstep.
55e8d9a5
AR
155(define-key global-map [S-mouse-1] 'mouse-save-then-kill)
156(global-unset-key [S-down-mouse-1])
157
a5a1b464 158;; Special Nextstep-generated events are converted to function keys. Here
fc3eda04
AR
159;; are the bindings for them. Note, these keys are actually declared in
160;; x-setup-function-keys in common-win.
c6c62e78 161(define-key global-map [ns-power-off] 'save-buffers-kill-emacs)
edfda783
AR
162(define-key global-map [ns-open-file] 'ns-find-file)
163(define-key global-map [ns-open-temp-file] [ns-open-file])
525795c1 164(define-key global-map [ns-drag-file] 'ns-find-file)
edfda783
AR
165(define-key global-map [ns-drag-color] 'ns-set-foreground-at-mouse)
166(define-key global-map [S-ns-drag-color] 'ns-set-background-at-mouse)
167(define-key global-map [ns-drag-text] 'ns-insert-text)
168(define-key global-map [ns-change-font] 'ns-respond-to-change-font)
169(define-key global-map [ns-open-file-line] 'ns-open-file-select-line)
edfda783 170(define-key global-map [ns-spi-service-call] 'ns-spi-service-call)
3e972d98 171(define-key global-map [ns-new-frame] 'make-frame)
33b35792 172(define-key global-map [ns-toggle-toolbar] 'ns-toggle-toolbar)
3e972d98 173(define-key global-map [ns-show-prefs] 'customize)
edfda783
AR
174
175
2f93961f
CY
176;; Set up a number of aliases and other layers to pretend we're using
177;; the Choi/Mitsuharu Carbon port.
178
179(defvaralias 'mac-allow-anti-aliasing 'ns-antialias-text)
180(defvaralias 'mac-command-modifier 'ns-command-modifier)
b7d1e144 181(defvaralias 'mac-right-command-modifier 'ns-right-command-modifier)
2f93961f 182(defvaralias 'mac-control-modifier 'ns-control-modifier)
b7d1e144 183(defvaralias 'mac-right-control-modifier 'ns-right-control-modifier)
2f93961f 184(defvaralias 'mac-option-modifier 'ns-option-modifier)
a2e35ef5 185(defvaralias 'mac-right-option-modifier 'ns-right-option-modifier)
2f93961f 186(defvaralias 'mac-function-modifier 'ns-function-modifier)
406aaa6f 187(declare-function ns-do-applescript "nsfns.m" (script))
583ff3c3
AR
188(defalias 'do-applescript 'ns-do-applescript)
189
edfda783 190;;;; Services
d377ef4a
GM
191(declare-function ns-perform-service "nsfns.m" (service send))
192
edfda783
AR
193(defun ns-define-service (path)
194 (let ((mapping [menu-bar services])
195 (service (mapconcat 'identity path "/"))
196 (name (intern
ebe68042
SM
197 (subst-char-in-string
198 ?\s ?-
199 (mapconcat 'identity (cons "ns-service" path) "-")))))
200 ;; This defines the function.
201 (defalias name
e95a67dc
SM
202 (lambda (arg)
203 (interactive "p")
204 (let* ((in-string
205 (cond ((stringp arg) arg)
206 (mark-active
207 (buffer-substring (region-beginning) (region-end)))))
208 (out-string (ns-perform-service service in-string)))
209 (cond
210 ((stringp arg) out-string)
211 ((and out-string (or (not in-string)
212 (not (string= in-string out-string))))
213 (if mark-active (delete-region (region-beginning) (region-end)))
214 (insert out-string)
215 (setq deactivate-mark nil))))))
edfda783
AR
216 (cond
217 ((lookup-key global-map mapping)
218 (while (cdr path)
219 (setq mapping (vconcat mapping (list (intern (car path)))))
220 (if (not (keymapp (lookup-key global-map mapping)))
221 (define-key global-map mapping
222 (cons (car path) (make-sparse-keymap (car path)))))
223 (setq path (cdr path)))
224 (setq mapping (vconcat mapping (list (intern (car path)))))
225 (define-key global-map mapping (cons (car path) name))))
226 name))
227
c0642f6d
GM
228;; nsterm.m
229(defvar ns-input-spi-name)
230(defvar ns-input-spi-arg)
231
f2d9c15f
GM
232(declare-function dnd-open-file "dnd" (uri action))
233
edfda783 234(defun ns-spi-service-call ()
82a330df 235 "Respond to a service request."
edfda783
AR
236 (interactive)
237 (cond ((string-equal ns-input-spi-name "open-selection")
238 (switch-to-buffer (generate-new-buffer "*untitled*"))
239 (insert ns-input-spi-arg))
240 ((string-equal ns-input-spi-name "open-file")
241 (dnd-open-file ns-input-spi-arg nil))
242 ((string-equal ns-input-spi-name "mail-selection")
243 (compose-mail)
244 (rfc822-goto-eoh)
245 (forward-line 1)
246 (insert ns-input-spi-arg))
247 ((string-equal ns-input-spi-name "mail-to")
248 (compose-mail ns-input-spi-arg))
249 (t (error (concat "Service " ns-input-spi-name " not recognized")))))
250
251
43c660bc
SM
252;; Composed key sequence handling for Nextstep system input methods.
253;; (On Nextstep systems, input methods are provided for CJK
254;; characters, etc. which require multiple keystrokes, and during
255;; entry a partial ("working") result is typically shown in the
256;; editing window.)
edfda783
AR
257
258(defface ns-working-text-face
259 '((t :underline t))
260 "Face used to highlight working text during compose sequence insert."
261 :group 'ns)
262
263(defvar ns-working-overlay nil
43c660bc
SM
264 "Overlay used to highlight working text during compose sequence insert.
265When text is in th echo area, this just stores the length of the working text.")
edfda783 266
33b35792
AR
267(defvar ns-working-text) ; nsterm.m
268
269;; Test if in echo area, based on mac-win.el 2007/08/26 unicode-2.
270;; This will fail if called from a NONASCII_KEYSTROKE event on the global map.
edfda783
AR
271(defun ns-in-echo-area ()
272 "Whether, for purposes of inserting working composition text, the minibuffer
273is currently being used."
274 (or isearch-mode
275 (and cursor-in-echo-area (current-message))
276 ;; Overlay strings are not shown in some cases.
277 (get-char-property (point) 'invisible)
278 (and (not (bobp))
279 (or (and (get-char-property (point) 'display)
280 (eq (get-char-property (1- (point)) 'display)
281 (get-char-property (point) 'display)))
282 (and (get-char-property (point) 'composition)
283 (eq (get-char-property (1- (point)) 'composition)
284 (get-char-property (point) 'composition)))))))
285
9d8f6d31
AR
286;; The 'interactive' here stays for subinvocations, so the ns-in-echo-area
287;; always returns nil for some reason. If this WASN'T the case, we could
288;; map this to [ns-insert-working-text] and eliminate Fevals in nsterm.m.
33b35792 289;; These functions test whether in echo area and delegate accordingly.
9d8f6d31 290(defun ns-put-working-text ()
edfda783 291 (interactive)
9d8f6d31 292 (if (ns-in-echo-area) (ns-echo-working-text) (ns-insert-working-text)))
33b35792
AR
293(defun ns-unput-working-text ()
294 (interactive)
43c660bc 295 (ns-delete-working-text))
c0642f6d 296
9d8f6d31 297(defun ns-insert-working-text ()
2b4e72e1 298 "Insert contents of `ns-working-text' as UTF-8 string and mark with
43c660bc
SM
299`ns-working-overlay'. Any previously existing working text is cleared first.
300The overlay is assigned the face `ns-working-text-face'."
301 ;; FIXME: if buffer is read-only, don't try to insert anything
302 ;; and if text is bound to a command, execute that instead (Bug#1453)
edfda783 303 (interactive)
43c660bc 304 (ns-delete-working-text)
edfda783
AR
305 (let ((start (point)))
306 (insert ns-working-text)
307 (overlay-put (setq ns-working-overlay (make-overlay start (point)
308 (current-buffer) nil t))
43c660bc 309 'face 'ns-working-text-face)))
edfda783
AR
310
311(defun ns-echo-working-text ()
2b4e72e1 312 "Echo contents of `ns-working-text' in message display area.
43c660bc
SM
313See `ns-insert-working-text'."
314 (ns-delete-working-text)
edfda783
AR
315 (let* ((msg (current-message))
316 (msglen (length msg))
317 message-log-max)
43c660bc 318 (setq ns-working-overlay (length ns-working-text))
edfda783 319 (setq msg (concat msg ns-working-text))
43c660bc 320 (put-text-property msglen (+ msglen ns-working-overlay)
08324aaa 321 'face 'ns-working-text-face msg)
43c660bc 322 (message "%s" msg)))
edfda783
AR
323
324(defun ns-delete-working-text()
43c660bc 325 "Delete working text and clear `ns-working-overlay'."
edfda783 326 (interactive)
43c660bc
SM
327 (cond
328 ((and (overlayp ns-working-overlay)
329 ;; Still alive?
330 (overlay-buffer ns-working-overlay))
331 (with-current-buffer (overlay-buffer ns-working-overlay)
332 (delete-region (overlay-start ns-working-overlay)
333 (overlay-end ns-working-overlay))
334 (delete-overlay ns-working-overlay)))
335 ((integerp ns-working-overlay)
336 (let ((msg (current-message))
337 message-log-max)
338 (setq msg (substring msg 0 (- (length msg) ns-working-overlay)))
339 (message "%s" msg))))
340 (setq ns-working-overlay nil))
edfda783
AR
341
342
c0642f6d
GM
343(declare-function ns-convert-utf8-nfd-to-nfc "nsfns.m" (str))
344
edfda783
AR
345;;;; OS X file system Unicode UTF-8 NFD (decomposed form) support
346;; Lisp code based on utf-8m.el, by Seiji Zenitani, Eiji Honjoh, and
347;; Carsten Bormann.
e925113b
GM
348(when (eq system-type 'darwin)
349 (defun ns-utf8-nfd-post-read-conversion (length)
350 "Calls `ns-convert-utf8-nfd-to-nfc' to compose char sequences."
351 (save-excursion
352 (save-restriction
353 (narrow-to-region (point) (+ (point) length))
354 (let ((str (buffer-string)))
355 (delete-region (point-min) (point-max))
356 (insert (ns-convert-utf8-nfd-to-nfc str))
1bcc4637 357 (- (point-max) (point-min))))))
e925113b
GM
358
359 (define-coding-system 'utf-8-nfd
360 "UTF-8 NFD (decomposed) encoding."
361 :coding-type 'utf-8
362 :mnemonic ?U
363 :charset-list '(unicode)
364 :post-read-conversion 'ns-utf8-nfd-post-read-conversion)
365 (set-file-name-coding-system 'utf-8-nfd))
edfda783
AR
366
367;;;; Inter-app communications support.
368
c0642f6d
GM
369(defvar ns-input-text) ; nsterm.m
370
edfda783 371(defun ns-insert-text ()
2b4e72e1 372 "Insert contents of `ns-input-text' at point."
edfda783
AR
373 (interactive)
374 (insert ns-input-text)
375 (setq ns-input-text nil))
c0642f6d 376
edfda783 377(defun ns-insert-file ()
2b4e72e1
JB
378 "Insert contents of file `ns-input-file' like insert-file but with less
379prompting. If file is a directory perform a `find-file' on it."
edfda783 380 (interactive)
c6efd3dd 381 (let ((f (pop ns-input-file)))
edfda783
AR
382 (if (file-directory-p f)
383 (find-file f)
1bcc4637 384 (push-mark (+ (point) (cadr (insert-file-contents f)))))))
edfda783
AR
385
386(defvar ns-select-overlay nil
a5a1b464 387 "Overlay used to highlight areas in files requested by Nextstep apps.")
edfda783
AR
388(make-variable-buffer-local 'ns-select-overlay)
389
c0642f6d
GM
390(defvar ns-input-line) ; nsterm.m
391
edfda783 392(defun ns-open-file-select-line ()
b90cc058
CY
393 "Open a buffer containing the file `ns-input-file'.
394Lines are highlighted according to `ns-input-line'."
edfda783
AR
395 (interactive)
396 (ns-find-file)
397 (cond
398 ((and ns-input-line (buffer-modified-p))
399 (if ns-select-overlay
400 (setq ns-select-overlay (delete-overlay ns-select-overlay)))
401 (deactivate-mark)
5f68c1b7
GM
402 (goto-char (point-min))
403 (forward-line (1- (if (consp ns-input-line)
404 (min (car ns-input-line) (cdr ns-input-line))
405 ns-input-line))))
edfda783
AR
406 (ns-input-line
407 (if (not ns-select-overlay)
d93e053b
GM
408 (overlay-put (setq ns-select-overlay (make-overlay (point-min)
409 (point-min)))
edfda783
AR
410 'face 'highlight))
411 (let ((beg (save-excursion
d93e053b
GM
412 (goto-char (point-min))
413 (line-beginning-position
414 (if (consp ns-input-line)
415 (min (car ns-input-line) (cdr ns-input-line))
416 ns-input-line))))
edfda783 417 (end (save-excursion
d93e053b
GM
418 (goto-char (point-min))
419 (line-beginning-position
420 (1+ (if (consp ns-input-line)
421 (max (car ns-input-line) (cdr ns-input-line))
422 ns-input-line))))))
edfda783
AR
423 (move-overlay ns-select-overlay beg end)
424 (deactivate-mark)
425 (goto-char beg)))
426 (t
427 (if ns-select-overlay
428 (setq ns-select-overlay (delete-overlay ns-select-overlay))))))
429
430(defun ns-unselect-line ()
a5a1b464 431 "Removes any Nextstep highlight a buffer may contain."
edfda783
AR
432 (if ns-select-overlay
433 (setq ns-select-overlay (delete-overlay ns-select-overlay))))
434
435(add-hook 'first-change-hook 'ns-unselect-line)
436
edfda783 437;;;; Preferences handling.
c0642f6d 438(declare-function ns-get-resource "nsfns.m" (owner name))
edfda783
AR
439
440(defun get-lisp-resource (arg1 arg2)
441 (let ((res (ns-get-resource arg1 arg2)))
442 (cond
443 ((not res) 'unbound)
444 ((string-equal (upcase res) "YES") t)
445 ((string-equal (upcase res) "NO") nil)
446 (t (read res)))))
447
c0642f6d 448;; nsterm.m
c6c62e78 449
c0642f6d
GM
450(declare-function ns-read-file-name "nsfns.m"
451 (prompt &optional dir isLoad init))
452
edfda783
AR
453;;;; File handling.
454
455(defun ns-open-file-using-panel ()
456 "Pop up open-file panel, and load the result in a buffer."
457 (interactive)
ebe68042 458 ;; Prompt dir defaultName isLoad initial.
edfda783
AR
459 (setq ns-input-file (ns-read-file-name "Select File to Load" nil t nil))
460 (if ns-input-file
461 (and (setq ns-input-file (list ns-input-file)) (ns-find-file))))
462
463(defun ns-write-file-using-panel ()
464 "Pop up save-file panel, and save buffer in resulting name."
465 (interactive)
466 (let (ns-output-file)
ebe68042 467 ;; Prompt dir defaultName isLoad initial.
edfda783
AR
468 (setq ns-output-file (ns-read-file-name "Save As" nil nil nil))
469 (message ns-output-file)
470 (if ns-output-file (write-file ns-output-file))))
471
73f6360c
GM
472(defcustom ns-pop-up-frames 'fresh
473 "Non-nil means open files upon request from the Workspace in a new frame.
c0642f6d 474If t, always do so. Any other non-nil value means open a new frame
73f6360c
GM
475unless the current buffer is a scratch buffer."
476 :type '(choice (const :tag "Never" nil)
477 (const :tag "Always" t)
478 (other :tag "Except for scratch buffer" fresh))
479 :version "23.1"
480 :group 'ns)
c0642f6d
GM
481
482(declare-function ns-hide-emacs "nsfns.m" (on))
483
edfda783 484(defun ns-find-file ()
2b4e72e1 485 "Do a `find-file' with the `ns-input-file' as argument."
edfda783 486 (interactive)
14beddf4
CY
487 (let* ((f (file-truename
488 (expand-file-name (pop ns-input-file)
489 command-line-default-directory)))
c6efd3dd
GM
490 (file (find-file-noselect f))
491 (bufwin1 (get-buffer-window file 'visible))
ee7683eb 492 (bufwin2 (get-buffer-window "*scratch*" 'visible)))
edfda783
AR
493 (cond
494 (bufwin1
495 (select-frame (window-frame bufwin1))
496 (raise-frame (window-frame bufwin1))
497 (select-window bufwin1))
498 ((and (eq ns-pop-up-frames 'fresh) bufwin2)
499 (ns-hide-emacs 'activate)
500 (select-frame (window-frame bufwin2))
501 (raise-frame (window-frame bufwin2))
502 (select-window bufwin2)
503 (find-file f))
504 (ns-pop-up-frames
505 (ns-hide-emacs 'activate)
506 (let ((pop-up-frames t)) (pop-to-buffer file nil)))
507 (t
508 (ns-hide-emacs 'activate)
509 (find-file f)))))
510
edfda783
AR
511;;;; Frame-related functions.
512
e925113b
GM
513;; nsterm.m
514(defvar ns-alternate-modifier)
515(defvar ns-right-alternate-modifier)
b7d1e144
JD
516(defvar ns-right-command-modifier)
517(defvar ns-right-control-modifier)
e925113b 518
edfda783
AR
519;; You say tomAYto, I say tomAHto..
520(defvaralias 'ns-option-modifier 'ns-alternate-modifier)
a2e35ef5 521(defvaralias 'ns-right-option-modifier 'ns-right-alternate-modifier)
edfda783
AR
522
523(defun ns-do-hide-emacs ()
524 (interactive)
525 (ns-hide-emacs t))
526
c0642f6d
GM
527(declare-function ns-hide-others "nsfns.m" ())
528
edfda783
AR
529(defun ns-do-hide-others ()
530 (interactive)
531 (ns-hide-others))
532
c0642f6d
GM
533(declare-function ns-emacs-info-panel "nsfns.m" ())
534
edfda783
AR
535(defun ns-do-emacs-info-panel ()
536 (interactive)
537 (ns-emacs-info-panel))
538
539(defun ns-next-frame ()
540 "Switch to next visible frame."
541 (interactive)
542 (other-frame 1))
2b4e72e1 543
edfda783
AR
544(defun ns-prev-frame ()
545 "Switch to previous visible frame."
546 (interactive)
547 (other-frame -1))
548
ebe68042 549;; If no position specified, make new frame offset by 25 from current.
e5744c66 550(defvar parameters) ; dynamically bound in make-frame
edfda783 551(add-hook 'before-make-frame-hook
ebe68042
SM
552 (lambda ()
553 (let ((left (cdr (assq 'left (frame-parameters))))
554 (top (cdr (assq 'top (frame-parameters)))))
555 (if (consp left) (setq left (cadr left)))
556 (if (consp top) (setq top (cadr top)))
557 (cond
558 ((or (assq 'top parameters) (assq 'left parameters)))
559 ((or (not left) (not top)))
560 (t
561 (setq parameters (cons (cons 'left (+ left 25))
562 (cons (cons 'top (+ top 25))
563 parameters))))))))
564
565;; frame will be focused anyway, so select it
37269466 566;; (if this is not done, mode line is dimmed until first interaction)
edfda783
AR
567(add-hook 'after-make-frame-functions 'select-frame)
568
f2d9c15f
GM
569(defvar tool-bar-mode)
570(declare-function tool-bar-mode "tool-bar" (&optional arg))
571
edfda783
AR
572;; Based on a function by David Reitter <dreitter@inf.ed.ac.uk> ;
573;; see http://lists.gnu.org/archive/html/emacs-devel/2005-09/msg00681.html .
574(defun ns-toggle-toolbar (&optional frame)
575 "Switches the tool bar on and off in frame FRAME.
576 If FRAME is nil, the change applies to the selected frame."
577 (interactive)
ebe68042
SM
578 (modify-frame-parameters
579 frame (list (cons 'tool-bar-lines
edfda783
AR
580 (if (> (or (frame-parameter frame 'tool-bar-lines) 0) 0)
581 0 1)) ))
582 (if (not tool-bar-mode) (tool-bar-mode t)))
583
edfda783 584
edfda783
AR
585;;;; Dialog-related functions.
586
587;; Ask user for confirm before printing. Due to Kevin Rodgers.
588(defun ns-print-buffer ()
589 "Interactive front-end to `print-buffer': asks for user confirmation first."
590 (interactive)
32226619 591 (if (and (called-interactively-p 'interactive)
ebe68042
SM
592 (or (listp last-nonmenu-event)
593 (and (char-or-string-p (event-basic-type last-command-event))
594 (memq 'super (event-modifiers last-command-event)))))
595 (let ((last-nonmenu-event (if (listp last-nonmenu-event)
596 last-nonmenu-event
597 ;; Fake it:
598 `(mouse-1 POSITION 1))))
599 (if (y-or-n-p (format "Print buffer %s? " (buffer-name)))
600 (print-buffer)
edfda783
AR
601 (error "Cancelled")))
602 (print-buffer)))
603
edfda783
AR
604;;;; Font support.
605
edfda783
AR
606;; Needed for font listing functions under both backend and normal
607(setq scalable-fonts-allowed t)
608
609;; Set to use font panel instead
406aaa6f 610(declare-function ns-popup-font-panel "nsfns.m" (&optional frame))
28571246 611(defalias 'x-select-font 'ns-popup-font-panel "Pop up the font panel.
2b4e72e1 612This function has been overloaded in Nextstep.")
4c785fa7 613(defalias 'mouse-set-font 'ns-popup-font-panel "Pop up the font panel.
2b4e72e1 614This function has been overloaded in Nextstep.")
edfda783 615
c0642f6d
GM
616;; nsterm.m
617(defvar ns-input-font)
618(defvar ns-input-fontsize)
619
edfda783 620(defun ns-respond-to-change-font ()
2b4e72e1
JB
621 "Respond to changeFont: event, expecting `ns-input-font' and\n\
622`ns-input-fontsize' of new font."
edfda783
AR
623 (interactive)
624 (modify-frame-parameters (selected-frame)
625 (list (cons 'font ns-input-font)
626 (cons 'fontsize ns-input-fontsize)))
627 (set-frame-font ns-input-font))
628
629
630;; Default fontset for Mac OS X. This is mainly here to show how a fontset
631;; can be set up manually. Ordinarily, fontsets are auto-created whenever
2b4e72e1 632;; a font is chosen by
edfda783 633(defvar ns-standard-fontset-spec
ebe68042
SM
634 ;; Only some code supports this so far, so use uglier XLFD version
635 ;; "-ns-*-*-*-*-*-10-*-*-*-*-*-fontset-standard,latin:Courier,han:Kai"
636 (mapconcat 'identity
637 '("-ns-*-*-*-*-*-10-*-*-*-*-*-fontset-standard"
638 "latin:-*-Courier-*-*-*-*-10-*-*-*-*-*-iso10646-1"
639 "han:-*-Kai-*-*-*-*-10-*-*-*-*-*-iso10646-1"
640 "cyrillic:-*-Trebuchet$MS-*-*-*-*-10-*-*-*-*-*-iso10646-1")
641 ",")
642 "String of fontset spec of the standard fontset.
edfda783 643This defines a fontset consisting of the Courier and other fonts that
2b4e72e1
JB
644come with OS X.
645See the documentation of `create-fontset-from-fontset-spec' for the format.")
edfda783 646
ebe68042 647;; Conditional on new-fontset so bootstrapping works on non-GUI compiles.
725513b7
GM
648(when (fboundp 'new-fontset)
649 ;; Setup the default fontset.
650 (create-default-fontset)
651 ;; Create the standard fontset.
652 (condition-case err
653 (create-fontset-from-fontset-spec ns-standard-fontset-spec t)
654 (error (display-warning
655 'initialization
656 (format "Creation of the standard fontset failed: %s" err)
657 :error))))
edfda783 658
6125167c
GM
659(defvar ns-reg-to-script) ; nsfont.m
660
a3b4b363 661;; This maps font registries (not exposed by NS APIs for font selection) to
fe7a3057 662;; Unicode scripts (which can be mapped to Unicode character ranges which are).
a3b4b363
AR
663;; See ../international/fontset.el
664(setq ns-reg-to-script
665 '(("iso8859-1" . latin)
666 ("iso8859-2" . latin)
667 ("iso8859-3" . latin)
668 ("iso8859-4" . latin)
669 ("iso8859-5" . cyrillic)
670 ("microsoft-cp1251" . cyrillic)
671 ("koi8-r" . cyrillic)
672 ("iso8859-6" . arabic)
673 ("iso8859-7" . greek)
674 ("iso8859-8" . hebrew)
675 ("iso8859-9" . latin)
676 ("iso8859-10" . latin)
677 ("iso8859-11" . thai)
678 ("tis620" . thai)
679 ("iso8859-13" . latin)
680 ("iso8859-14" . latin)
681 ("iso8859-15" . latin)
682 ("iso8859-16" . latin)
683 ("viscii1.1-1" . latin)
684 ("jisx0201" . kana)
685 ("jisx0208" . han)
686 ("jisx0212" . han)
687 ("jisx0213" . han)
688 ("gb2312.1980" . han)
689 ("gb18030" . han)
690 ("gbk-0" . han)
691 ("big5" . han)
692 ("cns11643" . han)
693 ("sisheng_cwnn" . bopomofo)
694 ("ksc5601.1987" . hangul)
695 ("ethiopic-unicode" . ethiopic)
696 ("is13194-devanagari" . indian-is13194)
697 ("iso10646.indian-1" . devanagari)))
698
edfda783
AR
699
700;;;; Pasteboard support.
701
c803b2b7
JD
702(declare-function ns-get-selection-internal "nsselect.m" (buffer))
703(declare-function ns-store-selection-internal "nsselect.m" (buffer string))
704
705(define-obsolete-function-alias 'ns-get-cut-buffer-internal
706 'ns-get-selection-internal "24.1")
707(define-obsolete-function-alias 'ns-store-cut-buffer-internal
708 'ns-store-selection-internal "24.1")
709
c0642f6d 710
edfda783
AR
711(defun ns-get-pasteboard ()
712 "Returns the value of the pasteboard."
c803b2b7 713 (ns-get-selection-internal 'CLIPBOARD))
c0642f6d 714
edfda783 715(defun ns-set-pasteboard (string)
a5a1b464 716 "Store STRING into the pasteboard of the Nextstep display server."
edfda783
AR
717 ;; Check the data type of STRING.
718 (if (not (stringp string)) (error "Nonstring given to pasteboard"))
c803b2b7 719 (ns-store-selection-internal 'CLIPBOARD string))
edfda783 720
ebe68042
SM
721;; We keep track of the last text selected here, so we can check the
722;; current selection against it, and avoid passing back our own text
6d7cc563 723;; from x-selection-value.
edfda783
AR
724(defvar ns-last-selected-text nil)
725
a5a1b464
CY
726;; Return the value of the current Nextstep selection. For
727;; compatibility with older Nextstep applications, this checks cut
728;; buffer 0 before retrieving the value of the primary selection.
6d7cc563 729(defun x-selection-value ()
edfda783 730 (let (text)
45240125 731 ;; Consult the selection. Treat empty strings as if they were unset.
edfda783
AR
732 (or text (setq text (ns-get-pasteboard)))
733 (if (string= text "") (setq text nil))
edfda783
AR
734 (cond
735 ((not text) nil)
736 ((eq text ns-last-selected-text) nil)
737 ((string= text ns-last-selected-text)
738 ;; Record the newer string, so subsequent calls can use the `eq' test.
739 (setq ns-last-selected-text text)
740 nil)
741 (t
742 (setq ns-last-selected-text text)))))
743
744(defun ns-copy-including-secondary ()
745 (interactive)
746 (call-interactively 'kill-ring-save)
c803b2b7
JD
747 (ns-store-selection-internal 'SECONDARY
748 (buffer-substring (point) (mark t))))
edfda783
AR
749(defun ns-paste-secondary ()
750 (interactive)
c803b2b7 751 (insert (ns-get-selection-internal 'SECONDARY)))
edfda783 752
edfda783 753
edfda783
AR
754;;;; Scrollbar handling.
755
756(global-set-key [vertical-scroll-bar down-mouse-1] 'ns-handle-scroll-bar-event)
757(global-unset-key [vertical-scroll-bar mouse-1])
758(global-unset-key [vertical-scroll-bar drag-mouse-1])
759
f2d9c15f
GM
760(declare-function scroll-bar-scale "scroll-bar" (num-denom whole))
761
edfda783 762(defun ns-scroll-bar-move (event)
55e8d9a5 763 "Scroll the frame according to a Nextstep scroller event."
edfda783
AR
764 (interactive "e")
765 (let* ((pos (event-end event))
766 (window (nth 0 pos))
767 (scale (nth 2 pos)))
937e6a56 768 (with-current-buffer (window-buffer window)
edfda783
AR
769 (cond
770 ((eq (car scale) (cdr scale))
771 (goto-char (point-max)))
772 ((= (car scale) 0)
773 (goto-char (point-min)))
774 (t
775 (goto-char (+ (point-min) 1
776 (scroll-bar-scale scale (- (point-max) (point-min)))))))
777 (beginning-of-line)
778 (set-window-start window (point))
779 (vertical-motion (/ (window-height window) 2) window))))
780
781(defun ns-handle-scroll-bar-event (event)
55e8d9a5 782 "Handle scroll bar EVENT to emulate Nextstep style scrolling."
edfda783
AR
783 (interactive "e")
784 (let* ((position (event-start event))
785 (bar-part (nth 4 position))
786 (window (nth 0 position))
787 (old-window (selected-window)))
788 (cond
789 ((eq bar-part 'ratio)
790 (ns-scroll-bar-move event))
791 ((eq bar-part 'handle)
792 (if (eq window (selected-window))
793 (track-mouse (ns-scroll-bar-move event))
ebe68042 794 ;; track-mouse faster for selected window, slower for unselected.
edfda783
AR
795 (ns-scroll-bar-move event)))
796 (t
797 (select-window window)
798 (cond
799 ((eq bar-part 'up)
800 (goto-char (window-start window))
801 (scroll-down 1))
802 ((eq bar-part 'above-handle)
803 (scroll-down))
804 ((eq bar-part 'below-handle)
805 (scroll-up))
806 ((eq bar-part 'down)
807 (goto-char (window-start window))
808 (scroll-up 1)))
809 (select-window old-window)))))
810
811
812;;;; Color support.
813
edfda783
AR
814;; Functions for color panel + drag
815(defun ns-face-at-pos (pos)
816 (let* ((frame (car pos))
817 (frame-pos (cons (cadr pos) (cddr pos)))
818 (window (window-at (car frame-pos) (cdr frame-pos) frame))
819 (window-pos (coordinates-in-window-p frame-pos window))
820 (buffer (window-buffer window))
821 (edges (window-edges window)))
822 (cond
823 ((not window-pos)
824 nil)
825 ((eq window-pos 'mode-line)
37269466 826 'mode-line)
edfda783
AR
827 ((eq window-pos 'vertical-line)
828 'default)
829 ((consp window-pos)
937e6a56 830 (with-current-buffer buffer
edfda783
AR
831 (let ((p (car (compute-motion (window-start window)
832 (cons (nth 0 edges) (nth 1 edges))
833 (window-end window)
834 frame-pos
835 (- (window-width window) 1)
836 nil
837 window))))
838 (cond
839 ((eq p (window-point window))
840 'cursor)
841 ((and mark-active (< (region-beginning) p) (< p (region-end)))
842 'region)
843 (t
844 (let ((faces (get-char-property p 'face window)))
845 (if (consp faces) (car faces) faces)))))))
846 (t
847 nil))))
848
c0642f6d
GM
849(defvar ns-input-color) ; nsterm.m
850
edfda783 851(defun ns-set-foreground-at-mouse ()
2b4e72e1 852 "Set the foreground color at the mouse location to `ns-input-color'."
edfda783
AR
853 (interactive)
854 (let* ((pos (mouse-position))
855 (frame (car pos))
856 (face (ns-face-at-pos pos)))
857 (cond
858 ((eq face 'cursor)
c0642f6d 859 (modify-frame-parameters frame (list (cons 'cursor-color
edfda783
AR
860 ns-input-color))))
861 ((not face)
862 (modify-frame-parameters frame (list (cons 'foreground-color
863 ns-input-color))))
864 (t
865 (set-face-foreground face ns-input-color frame)))))
866
867(defun ns-set-background-at-mouse ()
2b4e72e1 868 "Set the background color at the mouse location to `ns-input-color'."
edfda783
AR
869 (interactive)
870 (let* ((pos (mouse-position))
871 (frame (car pos))
872 (face (ns-face-at-pos pos)))
873 (cond
874 ((eq face 'cursor)
875 (modify-frame-parameters frame (list (cons 'cursor-color
876 ns-input-color))))
877 ((not face)
878 (modify-frame-parameters frame (list (cons 'background-color
879 ns-input-color))))
880 (t
881 (set-face-background face ns-input-color frame)))))
882
a5a1b464 883;; Set some options to be as Nextstep-like as possible.
edfda783
AR
884(setq frame-title-format t
885 icon-title-format t)
886
edfda783
AR
887
888(defvar ns-initialized nil
a5a1b464 889 "Non-nil if Nextstep windowing has been initialized.")
edfda783 890
c0642f6d 891(declare-function ns-list-services "nsfns.m" ())
b51a3365 892(declare-function x-open-connection "nsfns.m"
f2d9c15f 893 (display &optional xrm-string must-succeed))
cc232200 894(declare-function ns-set-resource "nsfns.m" (owner name value))
c0642f6d 895
a5a1b464
CY
896;; Do the actual Nextstep Windows setup here; the above code just
897;; defines functions and variables that we use now.
edfda783 898(defun ns-initialize-window-system ()
a5a1b464 899 "Initialize Emacs for Nextstep (Cocoa / GNUstep) windowing."
edfda783 900
ebe68042 901 ;; PENDING: not needed?
d7d8c62a 902 (setq command-line-args (x-handle-args command-line-args))
edfda783 903
9e50ff0c 904 (x-open-connection (system-name) nil t)
edfda783 905
ebe68042
SM
906 (dolist (service (ns-list-services))
907 (if (eq (car service) 'undefined)
908 (ns-define-service (cdr service))
909 (define-key global-map (vector (car service))
910 (ns-define-service (cdr service)))))
edfda783
AR
911
912 (if (and (eq (get-lisp-resource nil "NXAutoLaunch") t)
913 (eq (get-lisp-resource nil "HideOnAutoLaunch") t))
914 (add-hook 'after-init-hook 'ns-do-hide-emacs))
915
ebe68042 916 ;; FIXME: This will surely lead to "MODIFIED OUTSIDE CUSTOM" warnings.
edfda783 917 (menu-bar-mode (if (get-lisp-resource nil "Menus") 1 -1))
edfda783 918
cc232200 919 ;; OS X Lion introduces PressAndHold, which is unsupported by this port.
cd93b359
DR
920 ;; See this thread for more details:
921 ;; http://lists.gnu.org/archive/html/emacs-devel/2011-06/msg00505.html
922 (ns-set-resource nil "ApplePressAndHoldEnabled" "NO")
923
15cd8efd 924 (x-apply-session-resources)
edfda783
AR
925 (setq ns-initialized t))
926
d7d8c62a 927(add-to-list 'handle-args-function-alist '(ns . x-handle-args))
edfda783
AR
928(add-to-list 'frame-creation-function-alist '(ns . x-create-frame-with-faces))
929(add-to-list 'window-system-initialization-alist '(ns . ns-initialize-window-system))
930
931
932(provide 'ns-win)
933
934;;; ns-win.el ends here