Move fix for cygw32 icon issue from emacs-24 branch to trunk as Stefan Monnier requests
[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:
efc3dd3c 42(eval-when-compile (require 'cl-lib))
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 450(declare-function ns-read-file-name "nsfns.m"
fcacb558 451 (prompt &optional dir mustmatch init dir_only_p))
c0642f6d 452
edfda783
AR
453;;;; File handling.
454
d7e642cc
JD
455(defun x-file-dialog (prompt dir default_filename mustmatch only_dir_p)
456"Read file name, prompting with PROMPT in directory DIR.
457Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file
458selection box, if specified. If MUSTMATCH is non-nil, the returned file
459or directory must exist.
460
461This function is only defined on NS, MS Windows, and X Windows with the
462Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored.
463Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories."
464 (ns-read-file-name prompt dir mustmatch default_filename only_dir_p))
465
edfda783
AR
466(defun ns-open-file-using-panel ()
467 "Pop up open-file panel, and load the result in a buffer."
468 (interactive)
ebe68042 469 ;; Prompt dir defaultName isLoad initial.
edfda783
AR
470 (setq ns-input-file (ns-read-file-name "Select File to Load" nil t nil))
471 (if ns-input-file
472 (and (setq ns-input-file (list ns-input-file)) (ns-find-file))))
473
474(defun ns-write-file-using-panel ()
475 "Pop up save-file panel, and save buffer in resulting name."
476 (interactive)
477 (let (ns-output-file)
ebe68042 478 ;; Prompt dir defaultName isLoad initial.
edfda783
AR
479 (setq ns-output-file (ns-read-file-name "Save As" nil nil nil))
480 (message ns-output-file)
481 (if ns-output-file (write-file ns-output-file))))
482
73f6360c
GM
483(defcustom ns-pop-up-frames 'fresh
484 "Non-nil means open files upon request from the Workspace in a new frame.
c0642f6d 485If t, always do so. Any other non-nil value means open a new frame
73f6360c
GM
486unless the current buffer is a scratch buffer."
487 :type '(choice (const :tag "Never" nil)
488 (const :tag "Always" t)
489 (other :tag "Except for scratch buffer" fresh))
490 :version "23.1"
491 :group 'ns)
c0642f6d
GM
492
493(declare-function ns-hide-emacs "nsfns.m" (on))
494
edfda783 495(defun ns-find-file ()
2b4e72e1 496 "Do a `find-file' with the `ns-input-file' as argument."
edfda783 497 (interactive)
14beddf4
CY
498 (let* ((f (file-truename
499 (expand-file-name (pop ns-input-file)
500 command-line-default-directory)))
c6efd3dd
GM
501 (file (find-file-noselect f))
502 (bufwin1 (get-buffer-window file 'visible))
ee7683eb 503 (bufwin2 (get-buffer-window "*scratch*" 'visible)))
edfda783
AR
504 (cond
505 (bufwin1
506 (select-frame (window-frame bufwin1))
507 (raise-frame (window-frame bufwin1))
508 (select-window bufwin1))
509 ((and (eq ns-pop-up-frames 'fresh) bufwin2)
510 (ns-hide-emacs 'activate)
511 (select-frame (window-frame bufwin2))
512 (raise-frame (window-frame bufwin2))
513 (select-window bufwin2)
514 (find-file f))
515 (ns-pop-up-frames
516 (ns-hide-emacs 'activate)
517 (let ((pop-up-frames t)) (pop-to-buffer file nil)))
518 (t
519 (ns-hide-emacs 'activate)
520 (find-file f)))))
521
edfda783
AR
522;;;; Frame-related functions.
523
e925113b
GM
524;; nsterm.m
525(defvar ns-alternate-modifier)
526(defvar ns-right-alternate-modifier)
b7d1e144
JD
527(defvar ns-right-command-modifier)
528(defvar ns-right-control-modifier)
e925113b 529
edfda783
AR
530;; You say tomAYto, I say tomAHto..
531(defvaralias 'ns-option-modifier 'ns-alternate-modifier)
a2e35ef5 532(defvaralias 'ns-right-option-modifier 'ns-right-alternate-modifier)
edfda783
AR
533
534(defun ns-do-hide-emacs ()
535 (interactive)
536 (ns-hide-emacs t))
537
c0642f6d
GM
538(declare-function ns-hide-others "nsfns.m" ())
539
edfda783
AR
540(defun ns-do-hide-others ()
541 (interactive)
542 (ns-hide-others))
543
c0642f6d
GM
544(declare-function ns-emacs-info-panel "nsfns.m" ())
545
edfda783
AR
546(defun ns-do-emacs-info-panel ()
547 (interactive)
548 (ns-emacs-info-panel))
549
550(defun ns-next-frame ()
551 "Switch to next visible frame."
552 (interactive)
553 (other-frame 1))
2b4e72e1 554
edfda783
AR
555(defun ns-prev-frame ()
556 "Switch to previous visible frame."
557 (interactive)
558 (other-frame -1))
559
ebe68042 560;; If no position specified, make new frame offset by 25 from current.
e5744c66 561(defvar parameters) ; dynamically bound in make-frame
edfda783 562(add-hook 'before-make-frame-hook
ebe68042
SM
563 (lambda ()
564 (let ((left (cdr (assq 'left (frame-parameters))))
565 (top (cdr (assq 'top (frame-parameters)))))
566 (if (consp left) (setq left (cadr left)))
567 (if (consp top) (setq top (cadr top)))
568 (cond
569 ((or (assq 'top parameters) (assq 'left parameters)))
570 ((or (not left) (not top)))
571 (t
572 (setq parameters (cons (cons 'left (+ left 25))
573 (cons (cons 'top (+ top 25))
574 parameters))))))))
575
576;; frame will be focused anyway, so select it
37269466 577;; (if this is not done, mode line is dimmed until first interaction)
edfda783
AR
578(add-hook 'after-make-frame-functions 'select-frame)
579
f2d9c15f
GM
580(defvar tool-bar-mode)
581(declare-function tool-bar-mode "tool-bar" (&optional arg))
582
edfda783
AR
583;; Based on a function by David Reitter <dreitter@inf.ed.ac.uk> ;
584;; see http://lists.gnu.org/archive/html/emacs-devel/2005-09/msg00681.html .
585(defun ns-toggle-toolbar (&optional frame)
586 "Switches the tool bar on and off in frame FRAME.
587 If FRAME is nil, the change applies to the selected frame."
588 (interactive)
ebe68042
SM
589 (modify-frame-parameters
590 frame (list (cons 'tool-bar-lines
edfda783
AR
591 (if (> (or (frame-parameter frame 'tool-bar-lines) 0) 0)
592 0 1)) ))
593 (if (not tool-bar-mode) (tool-bar-mode t)))
594
edfda783 595
edfda783
AR
596;;;; Dialog-related functions.
597
598;; Ask user for confirm before printing. Due to Kevin Rodgers.
599(defun ns-print-buffer ()
600 "Interactive front-end to `print-buffer': asks for user confirmation first."
601 (interactive)
32226619 602 (if (and (called-interactively-p 'interactive)
ebe68042
SM
603 (or (listp last-nonmenu-event)
604 (and (char-or-string-p (event-basic-type last-command-event))
605 (memq 'super (event-modifiers last-command-event)))))
606 (let ((last-nonmenu-event (if (listp last-nonmenu-event)
607 last-nonmenu-event
608 ;; Fake it:
609 `(mouse-1 POSITION 1))))
610 (if (y-or-n-p (format "Print buffer %s? " (buffer-name)))
611 (print-buffer)
edfda783
AR
612 (error "Cancelled")))
613 (print-buffer)))
614
edfda783
AR
615;;;; Font support.
616
edfda783
AR
617;; Needed for font listing functions under both backend and normal
618(setq scalable-fonts-allowed t)
619
620;; Set to use font panel instead
406aaa6f 621(declare-function ns-popup-font-panel "nsfns.m" (&optional frame))
28571246 622(defalias 'x-select-font 'ns-popup-font-panel "Pop up the font panel.
2b4e72e1 623This function has been overloaded in Nextstep.")
4c785fa7 624(defalias 'mouse-set-font 'ns-popup-font-panel "Pop up the font panel.
2b4e72e1 625This function has been overloaded in Nextstep.")
edfda783 626
c0642f6d
GM
627;; nsterm.m
628(defvar ns-input-font)
629(defvar ns-input-fontsize)
630
edfda783 631(defun ns-respond-to-change-font ()
2b4e72e1
JB
632 "Respond to changeFont: event, expecting `ns-input-font' and\n\
633`ns-input-fontsize' of new font."
edfda783
AR
634 (interactive)
635 (modify-frame-parameters (selected-frame)
fcacb558
JD
636 (list (cons 'fontsize ns-input-fontsize)))
637 (modify-frame-parameters (selected-frame)
638 (list (cons 'font ns-input-font)))
edfda783
AR
639 (set-frame-font ns-input-font))
640
641
642;; Default fontset for Mac OS X. This is mainly here to show how a fontset
643;; can be set up manually. Ordinarily, fontsets are auto-created whenever
2b4e72e1 644;; a font is chosen by
edfda783 645(defvar ns-standard-fontset-spec
ebe68042
SM
646 ;; Only some code supports this so far, so use uglier XLFD version
647 ;; "-ns-*-*-*-*-*-10-*-*-*-*-*-fontset-standard,latin:Courier,han:Kai"
648 (mapconcat 'identity
649 '("-ns-*-*-*-*-*-10-*-*-*-*-*-fontset-standard"
650 "latin:-*-Courier-*-*-*-*-10-*-*-*-*-*-iso10646-1"
651 "han:-*-Kai-*-*-*-*-10-*-*-*-*-*-iso10646-1"
652 "cyrillic:-*-Trebuchet$MS-*-*-*-*-10-*-*-*-*-*-iso10646-1")
653 ",")
654 "String of fontset spec of the standard fontset.
edfda783 655This defines a fontset consisting of the Courier and other fonts that
2b4e72e1
JB
656come with OS X.
657See the documentation of `create-fontset-from-fontset-spec' for the format.")
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."
efc3dd3c 900 (cl-assert (not ns-initialized))
edfda783 901
ebe68042 902 ;; PENDING: not needed?
d7d8c62a 903 (setq command-line-args (x-handle-args command-line-args))
edfda783 904
c2350548
JD
905 ;; Setup the default fontset.
906 (create-default-fontset)
907 ;; Create the standard fontset.
908 (condition-case err
909 (create-fontset-from-fontset-spec ns-standard-fontset-spec t)
910 (error (display-warning
911 'initialization
912 (format "Creation of the standard fontset failed: %s" err)
913 :error)))
914
9e50ff0c 915 (x-open-connection (system-name) nil t)
edfda783 916
ebe68042
SM
917 (dolist (service (ns-list-services))
918 (if (eq (car service) 'undefined)
919 (ns-define-service (cdr service))
920 (define-key global-map (vector (car service))
921 (ns-define-service (cdr service)))))
edfda783
AR
922
923 (if (and (eq (get-lisp-resource nil "NXAutoLaunch") t)
924 (eq (get-lisp-resource nil "HideOnAutoLaunch") t))
925 (add-hook 'after-init-hook 'ns-do-hide-emacs))
926
ebe68042 927 ;; FIXME: This will surely lead to "MODIFIED OUTSIDE CUSTOM" warnings.
edfda783 928 (menu-bar-mode (if (get-lisp-resource nil "Menus") 1 -1))
edfda783 929
cc232200 930 ;; OS X Lion introduces PressAndHold, which is unsupported by this port.
cd93b359
DR
931 ;; See this thread for more details:
932 ;; http://lists.gnu.org/archive/html/emacs-devel/2011-06/msg00505.html
933 (ns-set-resource nil "ApplePressAndHoldEnabled" "NO")
934
15cd8efd 935 (x-apply-session-resources)
edfda783
AR
936 (setq ns-initialized t))
937
efc3dd3c 938(add-to-list 'display-format-alist '("\\`ns\\'" . ns))
d7d8c62a 939(add-to-list 'handle-args-function-alist '(ns . x-handle-args))
edfda783
AR
940(add-to-list 'frame-creation-function-alist '(ns . x-create-frame-with-faces))
941(add-to-list 'window-system-initialization-alist '(ns . ns-initialize-window-system))
942
943
944(provide 'ns-win)
945
946;;; ns-win.el ends here