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