| 1131 | | |
|---|
| 1132 | | ;;;; Keyboard layout/language change events |
|---|
| 1133 | | (defun mac-handle-language-change (event) |
|---|
| 1134 | | "Set keyboard coding system to what is specified in EVENT." |
|---|
| 1135 | | (interactive "e") |
|---|
| 1136 | | (let ((coding-system |
|---|
| 1137 | | (cdr (assq (car (cadr event)) mac-script-code-coding-systems)))) |
|---|
| 1138 | | (set-keyboard-coding-system (or coding-system 'mac-roman)) |
|---|
| 1139 | | ;; MacJapanese maps reverse solidus to ?\x80. |
|---|
| 1140 | | (if (eq coding-system 'japanese-shift-jis) |
|---|
| 1141 | | (define-key key-translation-map [?\x80] "\\")))) |
|---|
| 1142 | | |
|---|
| 1143 | | (define-key special-event-map [language-change] 'mac-handle-language-change) |
|---|
| 1144 | | |
|---|
| 1145 | | ;;;; Selections |
|---|
| 1146 | | |
|---|
| 1147 | | ;;; We keep track of the last text selected here, so we can check the |
|---|
| 1148 | | ;;; current selection against it, and avoid passing back our own text |
|---|
| 1149 | | ;;; from x-get-selection-value. |
|---|
| 1150 | | (defvar x-last-selected-text-clipboard nil |
|---|
| 1151 | | "The value of the CLIPBOARD selection last time we selected or |
|---|
| 1152 | | pasted text.") |
|---|
| 1153 | | (defvar x-last-selected-text-primary nil |
|---|
| 1154 | | "The value of the PRIMARY X selection last time we selected or |
|---|
| 1155 | | pasted text.") |
|---|
| 1156 | | |
|---|
| 1157 | | (defcustom x-select-enable-clipboard t |
|---|
| 1158 | | "*Non-nil means cutting and pasting uses the clipboard. |
|---|
| 1159 | | This is in addition to the primary selection." |
|---|
| 1160 | | :type 'boolean |
|---|
| 1161 | | :group 'killing) |
|---|
| 1162 | | |
|---|
| 1163 | | ;;; Make TEXT, a string, the primary X selection. |
|---|
| 1164 | | (defun x-select-text (text &optional push) |
|---|
| 1165 | | (x-set-selection 'PRIMARY text) |
|---|
| 1166 | | (setq x-last-selected-text-primary text) |
|---|
| 1167 | | (if (not x-select-enable-clipboard) |
|---|
| 1168 | | (setq x-last-selected-text-clipboard nil) |
|---|
| 1169 | | (x-set-selection 'CLIPBOARD text) |
|---|
| 1170 | | (setq x-last-selected-text-clipboard text)) |
|---|
| 1171 | | ) |
|---|
| 1172 | | |
|---|
| 1173 | | (defun x-get-selection (&optional type data-type) |
|---|
| 1174 | | "Return the value of a selection. |
|---|
| 1175 | | The argument TYPE (default `PRIMARY') says which selection, |
|---|
| 1176 | | and the argument DATA-TYPE (default `STRING') says |
|---|
| 1177 | | how to convert the data. |
|---|
| 1178 | | |
|---|
| 1179 | | TYPE may be any symbol \(but nil stands for `PRIMARY'). However, |
|---|
| 1180 | | only a few symbols are commonly used. They conventionally have |
|---|
| 1181 | | all upper-case names. The most often used ones, in addition to |
|---|
| 1182 | | `PRIMARY', are `SECONDARY' and `CLIPBOARD'. |
|---|
| 1183 | | |
|---|
| 1184 | | DATA-TYPE is usually `STRING', but can also be one of the symbols |
|---|
| 1185 | | in `selection-converter-alist', which see." |
|---|
| 1186 | | (let ((data (x-get-selection-internal (or type 'PRIMARY) |
|---|
| 1187 | | (or data-type 'STRING))) |
|---|
| 1188 | | (coding (or next-selection-coding-system |
|---|
| 1189 | | selection-coding-system))) |
|---|
| 1190 | | (when (and (stringp data) |
|---|
| 1191 | | (setq data-type (get-text-property 0 'foreign-selection data))) |
|---|
| 1192 | | (cond ((eq data-type 'public.utf16-plain-text) |
|---|
| 1193 | | (let ((encoded (and (fboundp 'mac-code-convert-string) |
|---|
| 1194 | | (mac-code-convert-string data nil coding)))) |
|---|
| 1195 | | (if encoded |
|---|
| 1196 | | (setq data (decode-coding-string encoded coding)) |
|---|
| 1197 | | (setq data |
|---|
| 1198 | | (decode-coding-string data |
|---|
| 1199 | | (if (eq (byteorder) ?B) |
|---|
| 1200 | | 'utf-16be 'utf-16le)))))) |
|---|
| 1201 | | ((eq data-type 'com.apple.traditional-mac-plain-text) |
|---|
| 1202 | | (setq data (decode-coding-string data coding))) |
|---|
| 1203 | | ((eq data-type 'public.file-url) |
|---|
| 1204 | | (setq data (decode-coding-string data 'utf-8)) |
|---|
| 1205 | | ;; Remove a trailing nul character. |
|---|
| 1206 | | (let ((len (length data))) |
|---|
| 1207 | | (if (and (> len 0) (= (aref data (1- len)) ?\0)) |
|---|
| 1208 | | (setq data (substring data 0 (1- len))))))) |
|---|
| 1209 | | (put-text-property 0 (length data) 'foreign-selection data-type data)) |
|---|
| 1210 | | data)) |
|---|
| 1211 | | |
|---|
| 1212 | | (defun x-selection-value (type) |
|---|
| 1213 | | (let ((data-types '(public.utf16-plain-text |
|---|
| 1214 | | com.apple.traditional-mac-plain-text |
|---|
| 1215 | | public.file-url)) |
|---|
| 1216 | | text tiff-image) |
|---|
| 1217 | | (while (and (null text) data-types) |
|---|
| 1218 | | (setq text (condition-case nil |
|---|
| 1219 | | (x-get-selection type (car data-types)) |
|---|
| 1220 | | (error nil))) |
|---|
| 1221 | | (setq data-types (cdr data-types))) |
|---|
| 1222 | | (if text |
|---|
| 1223 | | (remove-text-properties 0 (length text) '(foreign-selection nil) text)) |
|---|
| 1224 | | (setq tiff-image (condition-case nil |
|---|
| 1225 | | (x-get-selection type 'public.tiff) |
|---|
| 1226 | | (error nil))) |
|---|
| 1227 | | (when tiff-image |
|---|
| 1228 | | (remove-text-properties 0 (length tiff-image) |
|---|
| 1229 | | '(foreign-selection nil) tiff-image) |
|---|
| 1230 | | (setq tiff-image (create-image tiff-image 'tiff t)) |
|---|
| 1231 | | (or text (setq text " ")) |
|---|
| 1232 | | (put-text-property 0 (length text) 'display tiff-image text)) |
|---|
| 1233 | | text)) |
|---|
| 1234 | | |
|---|
| 1235 | | ;;; Return the value of the current selection. |
|---|
| 1236 | | ;;; Treat empty strings as if they were unset. |
|---|
| 1237 | | ;;; If this function is called twice and finds the same text, |
|---|
| 1238 | | ;;; it returns nil the second time. This is so that a single |
|---|
| 1239 | | ;;; selection won't be added to the kill ring over and over. |
|---|
| 1240 | | (defun x-get-selection-value () |
|---|
| 1241 | | (let (clip-text primary-text) |
|---|
| 1242 | | (if (not x-select-enable-clipboard) |
|---|
| 1243 | | (setq x-last-selected-text-clipboard nil) |
|---|
| 1244 | | (setq clip-text (x-selection-value 'CLIPBOARD)) |
|---|
| 1245 | | (if (string= clip-text "") (setq clip-text nil)) |
|---|
| 1246 | | |
|---|
| 1247 | | ;; Check the CLIPBOARD selection for 'newness', is it different |
|---|
| 1248 | | ;; from what we remebered them to be last time we did a |
|---|
| 1249 | | ;; cut/paste operation. |
|---|
| 1250 | | (setq clip-text |
|---|
| 1251 | | (cond;; check clipboard |
|---|
| 1252 | | ((or (not clip-text) (string= clip-text "")) |
|---|
| 1253 | | (setq x-last-selected-text-clipboard nil)) |
|---|
| 1254 | | ((eq clip-text x-last-selected-text-clipboard) nil) |
|---|
| 1255 | | ((string= clip-text x-last-selected-text-clipboard) |
|---|
| 1256 | | ;; Record the newer string, |
|---|
| 1257 | | ;; so subsequent calls can use the `eq' test. |
|---|
| 1258 | | (setq x-last-selected-text-clipboard clip-text) |
|---|
| 1259 | | nil) |
|---|
| 1260 | | (t |
|---|
| 1261 | | (setq x-last-selected-text-clipboard clip-text)))) |
|---|
| 1262 | | ) |
|---|
| 1263 | | |
|---|
| 1264 | | (setq primary-text (x-selection-value 'PRIMARY)) |
|---|
| 1265 | | ;; Check the PRIMARY selection for 'newness', is it different |
|---|
| 1266 | | ;; from what we remebered them to be last time we did a |
|---|
| 1267 | | ;; cut/paste operation. |
|---|
| 1268 | | (setq primary-text |
|---|
| 1269 | | (cond;; check primary selection |
|---|
| 1270 | | ((or (not primary-text) (string= primary-text "")) |
|---|
| 1271 | | (setq x-last-selected-text-primary nil)) |
|---|
| 1272 | | ((eq primary-text x-last-selected-text-primary) nil) |
|---|
| 1273 | | ((string= primary-text x-last-selected-text-primary) |
|---|
| 1274 | | ;; Record the newer string, |
|---|
| 1275 | | ;; so subsequent calls can use the `eq' test. |
|---|
| 1276 | | (setq x-last-selected-text-primary primary-text) |
|---|
| 1277 | | nil) |
|---|
| 1278 | | (t |
|---|
| 1279 | | (setq x-last-selected-text-primary primary-text)))) |
|---|
| 1280 | | |
|---|
| 1281 | | ;; As we have done one selection, clear this now. |
|---|
| 1282 | | (setq next-selection-coding-system nil) |
|---|
| 1283 | | |
|---|
| 1284 | | ;; At this point we have recorded the current values for the |
|---|
| 1285 | | ;; selection from clipboard (if we are supposed to) and primary, |
|---|
| 1286 | | ;; So return the first one that has changed (which is the first |
|---|
| 1287 | | ;; non-null one). |
|---|
| 1288 | | (or clip-text primary-text) |
|---|
| 1289 | | )) |
|---|
| 1290 | | |
|---|
| 1291 | | (put 'CLIPBOARD 'mac-scrap-name "com.apple.scrap.clipboard") |
|---|
| 1292 | | (when (eq system-type 'darwin) |
|---|
| 1293 | | (put 'FIND 'mac-scrap-name "com.apple.scrap.find") |
|---|
| 1294 | | (put 'PRIMARY 'mac-scrap-name |
|---|
| 1295 | | (format "org.gnu.Emacs.%d.selection.PRIMARY" (emacs-pid)))) |
|---|
| 1296 | | (put 'com.apple.traditional-mac-plain-text 'mac-ostype "TEXT") |
|---|
| 1297 | | (put 'public.utf16-plain-text 'mac-ostype "utxt") |
|---|
| 1298 | | (put 'public.tiff 'mac-ostype "TIFF") |
|---|
| 1299 | | (put 'public.file-url 'mac-ostype "furl") |
|---|
| 1300 | | |
|---|
| 1301 | | (defun mac-select-convert-to-string (selection type value) |
|---|
| 1302 | | (let ((str (cdr (xselect-convert-to-string selection nil value))) |
|---|
| 1303 | | coding) |
|---|
| 1304 | | (setq coding (or next-selection-coding-system selection-coding-system)) |
|---|
| 1305 | | (if coding |
|---|
| 1306 | | (setq coding (coding-system-base coding)) |
|---|
| 1307 | | (setq coding 'raw-text)) |
|---|
| 1308 | | (when str |
|---|
| 1309 | | ;; If TYPE is nil, this is a local request, thus return STR as |
|---|
| 1310 | | ;; is. Otherwise, encode STR. |
|---|
| 1311 | | (if (not type) |
|---|
| 1312 | | str |
|---|
| 1313 | | (let ((inhibit-read-only t)) |
|---|
| 1314 | | (remove-text-properties 0 (length str) '(composition nil) str) |
|---|
| 1315 | | (cond |
|---|
| 1316 | | ((eq type 'public.utf16-plain-text) |
|---|
| 1317 | | (let (s) |
|---|
| 1318 | | (when (and (fboundp 'mac-code-convert-string) |
|---|
| 1319 | | (memq coding (find-coding-systems-string str))) |
|---|
| 1320 | | (setq coding (coding-system-change-eol-conversion coding 'mac)) |
|---|
| 1321 | | (setq s (mac-code-convert-string |
|---|
| 1322 | | (encode-coding-string str coding) |
|---|
| 1323 | | coding nil))) |
|---|
| 1324 | | (setq str (or s |
|---|
| 1325 | | (encode-coding-string str |
|---|
| 1326 | | (if (eq (byteorder) ?B) |
|---|
| 1327 | | 'utf-16be-mac |
|---|
| 1328 | | 'utf-16le-mac)))))) |
|---|
| 1329 | | ((eq type 'com.apple.traditional-mac-plain-text) |
|---|
| 1330 | | (let ((encodables (find-coding-systems-string str)) |
|---|
| 1331 | | (rest mac-script-code-coding-systems)) |
|---|
| 1332 | | (unless (memq coding encodables) |
|---|
| 1333 | | (while (and rest (not (memq (cdar rest) encodables))) |
|---|
| 1334 | | (setq rest (cdr rest))) |
|---|
| 1335 | | (if rest |
|---|
| 1336 | | (setq coding (cdar rest))))) |
|---|
| 1337 | | (setq coding (coding-system-change-eol-conversion coding 'mac)) |
|---|
| 1338 | | (setq str (encode-coding-string str coding))) |
|---|
| 1339 | | (t |
|---|
| 1340 | | (error "Unknown selection type: %S" type)) |
|---|
| 1341 | | ))) |
|---|
| 1342 | | |
|---|
| 1343 | | (setq next-selection-coding-system nil) |
|---|
| 1344 | | (cons type str)))) |
|---|
| 1345 | | |
|---|
| 1346 | | (defun mac-select-convert-to-file-url (selection type value) |
|---|
| 1347 | | (let ((filename (xselect-convert-to-filename selection type value)) |
|---|
| 1348 | | (coding (or file-name-coding-system default-file-name-coding-system))) |
|---|
| 1349 | | (if (and filename coding) |
|---|
| 1350 | | (setq filename (encode-coding-string filename coding))) |
|---|
| 1351 | | (and filename |
|---|
| 1352 | | (concat "file://localhost" |
|---|
| 1353 | | (mapconcat 'url-hexify-string |
|---|
| 1354 | | (split-string filename "/") "/"))))) |
|---|
| 1355 | | |
|---|
| 1356 | | (setq selection-converter-alist |
|---|
| 1357 | | (nconc |
|---|
| 1358 | | '((public.utf16-plain-text . mac-select-convert-to-string) |
|---|
| 1359 | | (com.apple.traditional-mac-plain-text . mac-select-convert-to-string) |
|---|
| 1360 | | ;; This is not enabled by default because the `Import Image' |
|---|
| 1361 | | ;; menu makes Emacs crash or hang for unknown reasons. |
|---|
| 1362 | | ;; (public.tiff . nil) |
|---|
| 1363 | | (public.file-url . mac-select-convert-to-file-url) |
|---|
| 1364 | | ) |
|---|
| 1365 | | selection-converter-alist)) |
|---|
| 1366 | | |
|---|
| 1367 | | ;;;; Apple events, HICommand events, and Services menu |
|---|
| 1368 | | |
|---|
| 1369 | | ;;; Event classes |
|---|
| 1370 | | (put 'core-event 'mac-apple-event-class "aevt") ; kCoreEventClass |
|---|
| 1371 | | (put 'internet-event 'mac-apple-event-class "GURL") ; kAEInternetEventClass |
|---|
| 1372 | | |
|---|
| 1373 | | ;;; Event IDs |
|---|
| 1374 | | ;; kCoreEventClass |
|---|
| 1375 | | (put 'open-application 'mac-apple-event-id "oapp") ; kAEOpenApplication |
|---|
| 1376 | | (put 'reopen-application 'mac-apple-event-id "rapp") ; kAEReopenApplication |
|---|
| 1377 | | (put 'open-documents 'mac-apple-event-id "odoc") ; kAEOpenDocuments |
|---|
| 1378 | | (put 'print-documents 'mac-apple-event-id "pdoc") ; kAEPrintDocuments |
|---|
| 1379 | | (put 'open-contents 'mac-apple-event-id "ocon") ; kAEOpenContents |
|---|
| 1380 | | (put 'quit-application 'mac-apple-event-id "quit") ; kAEQuitApplication |
|---|
| 1381 | | (put 'application-died 'mac-apple-event-id "obit") ; kAEApplicationDied |
|---|
| 1382 | | (put 'show-preferences 'mac-apple-event-id "pref") ; kAEShowPreferences |
|---|
| 1383 | | (put 'autosave-now 'mac-apple-event-id "asav") ; kAEAutosaveNow |
|---|
| 1384 | | ;; kAEInternetEventClass |
|---|
| 1385 | | (put 'get-url 'mac-apple-event-id "GURL") ; kAEGetURL |
|---|
| 1386 | | ;; Converted HICommand events |
|---|
| 1387 | | (put 'about 'mac-apple-event-id "abou") ; kHICommandAbout |
|---|
| 1388 | | |
|---|
| 1389 | | (defmacro mac-event-spec (event) |
|---|
| 1390 | | `(nth 1 ,event)) |
|---|
| 1391 | | |
|---|
| 1392 | | (defmacro mac-event-ae (event) |
|---|
| 1393 | | `(nth 2 ,event)) |
|---|
| 1394 | | |
|---|
| 1395 | | (defun mac-ae-parameter (ae &optional keyword type) |
|---|
| 1396 | | (or keyword (setq keyword "----")) ;; Direct object. |
|---|
| 1397 | | (if (not (and (consp ae) (equal (car ae) "aevt"))) |
|---|
| 1398 | | (error "Not an Apple event: %S" ae) |
|---|
| 1399 | | (let ((type-data (cdr (assoc keyword (cdr ae)))) |
|---|
| 1400 | | data) |
|---|
| 1401 | | (when (and type type-data (not (equal type (car type-data)))) |
|---|
| 1402 | | (setq data (mac-coerce-ae-data (car type-data) (cdr type-data) type)) |
|---|
| 1403 | | (setq type-data (if data (cons type data) nil))) |
|---|
| 1404 | | type-data))) |
|---|
| 1405 | | |
|---|
| 1406 | | (defun mac-ae-list (ae &optional keyword type) |
|---|
| 1407 | | (or keyword (setq keyword "----")) ;; Direct object. |
|---|
| 1408 | | (let ((desc (mac-ae-parameter ae keyword "list"))) |
|---|
| 1409 | | (cond ((null desc) |
|---|
| 1410 | | nil) |
|---|
| 1411 | | ((not (equal (car desc) "list")) |
|---|
| 1412 | | (error "Parameter for \"%s\" is not a list" keyword)) |
|---|
| 1413 | | (t |
|---|
| 1414 | | (if (null type) |
|---|
| 1415 | | (cdr desc) |
|---|
| 1416 | | (mapcar |
|---|
| 1417 | | (lambda (type-data) |
|---|
| 1418 | | (mac-coerce-ae-data (car type-data) (cdr type-data) type)) |
|---|
| 1419 | | (cdr desc))))))) |
|---|
| 1420 | | |
|---|
| 1421 | | (defun mac-bytes-to-integer (bytes &optional from to) |
|---|
| 1422 | | (or from (setq from 0)) |
|---|
| 1423 | | (or to (setq to (length bytes))) |
|---|
| 1424 | | (let* ((len (- to from)) |
|---|
| 1425 | | (extended-sign-len (- (1+ (ceiling (log most-positive-fixnum 2))) |
|---|
| 1426 | | (* 8 len))) |
|---|
| 1427 | | (result 0)) |
|---|
| 1428 | | (dotimes (i len) |
|---|
| 1429 | | (setq result (logior (lsh result 8) |
|---|
| 1430 | | (aref bytes (+ from (if (eq (byteorder) ?B) i |
|---|
| 1431 | | (- len i 1))))))) |
|---|
| 1432 | | (if (> extended-sign-len 0) |
|---|
| 1433 | | (ash (lsh result extended-sign-len) (- extended-sign-len)) |
|---|
| 1434 | | result))) |
|---|
| 1435 | | |
|---|
| 1436 | | (defun mac-ae-selection-range (ae) |
|---|
| 1437 | | ;; #pragma options align=mac68k |
|---|
| 1438 | | ;; typedef struct SelectionRange { |
|---|
| 1439 | | ;; short unused1; // 0 (not used) |
|---|
| 1440 | | ;; short lineNum; // line to select (<0 to specify range) |
|---|
| 1441 | | ;; long startRange; // start of selection range (if line < 0) |
|---|
| 1442 | | ;; long endRange; // end of selection range (if line < 0) |
|---|
| 1443 | | ;; long unused2; // 0 (not used) |
|---|
| 1444 | | ;; long theDate; // modification date/time |
|---|
| 1445 | | ;; } SelectionRange; |
|---|
| 1446 | | ;; #pragma options align=reset |
|---|
| 1447 | | (let ((range-bytes (cdr (mac-ae-parameter ae "kpos" "TEXT")))) |
|---|
| 1448 | | (and range-bytes |
|---|
| 1449 | | (list (mac-bytes-to-integer range-bytes 2 4) |
|---|
| 1450 | | (mac-bytes-to-integer range-bytes 4 8) |
|---|
| 1451 | | (mac-bytes-to-integer range-bytes 8 12) |
|---|
| 1452 | | (mac-bytes-to-integer range-bytes 16 20))))) |
|---|
| 1453 | | |
|---|
| 1454 | | ;; On Mac OS X 10.4 and later, the `open-document' event contains an |
|---|
| 1455 | | ;; optional parameter keyAESearchText from the Spotlight search. |
|---|
| 1456 | | (defun mac-ae-text-for-search (ae) |
|---|
| 1457 | | (let ((utf8-text (cdr (mac-ae-parameter ae "stxt" "utf8")))) |
|---|
| 1458 | | (and utf8-text |
|---|
| 1459 | | (decode-coding-string utf8-text 'utf-8)))) |
|---|
| 1460 | | |
|---|
| 1461 | | (defun mac-ae-open-documents (event) |
|---|
| 1462 | | "Open the documents specified by the Apple event EVENT." |
|---|
| 1463 | | (interactive "e") |
|---|
| 1464 | | (let ((ae (mac-event-ae event))) |
|---|
| 1465 | | (dolist (file-name (mac-ae-list ae nil 'undecoded-file-name)) |
|---|
| 1466 | | (if file-name |
|---|
| 1467 | | (dnd-open-local-file (concat "file:" file-name) nil))) |
|---|
| 1468 | | (let ((selection-range (mac-ae-selection-range ae)) |
|---|
| 1469 | | (search-text (mac-ae-text-for-search ae))) |
|---|
| 1470 | | (cond (selection-range |
|---|
| 1471 | | (let ((line (car selection-range)) |
|---|
| 1472 | | (start (cadr selection-range)) |
|---|
| 1473 | | (end (nth 2 selection-range))) |
|---|
| 1474 | | (if (> line 0) |
|---|
| 1475 | | (goto-line line) |
|---|
| 1476 | | (if (and (> start 0) (> end 0)) |
|---|
| 1477 | | (progn (set-mark start) |
|---|
| 1478 | | (goto-char end)))))) |
|---|
| 1479 | | ((stringp search-text) |
|---|
| 1480 | | (re-search-forward |
|---|
| 1481 | | (mapconcat 'regexp-quote (split-string search-text) "\\|") |
|---|
| 1482 | | nil t))))) |
|---|
| 1483 | | (select-frame-set-input-focus (selected-frame))) |
|---|
| 1484 | | |
|---|
| 1485 | | (defun mac-ae-text (ae) |
|---|
| 1486 | | (or (cdr (mac-ae-parameter ae nil "TEXT")) |
|---|
| 1487 | | (error "No text in Apple event."))) |
|---|
| 1488 | | |
|---|
| 1489 | | (defun mac-ae-get-url (event) |
|---|
| 1490 | | "Open the URL specified by the Apple event EVENT. |
|---|
| 1491 | | Currently the `mailto' scheme is supported." |
|---|
| 1492 | | (interactive "e") |
|---|
| 1493 | | (let* ((ae (mac-event-ae event)) |
|---|
| 1494 | | (parsed-url (url-generic-parse-url (mac-ae-text ae)))) |
|---|
| 1495 | | (if (string= (url-type parsed-url) "mailto") |
|---|
| 1496 | | (url-mailto parsed-url) |
|---|
| 1497 | | (error "Unsupported URL scheme: %s" (url-type parsed-url))))) |
|---|
| 1498 | | |
|---|
| 1499 | | (setq mac-apple-event-map (make-sparse-keymap)) |
|---|
| 1500 | | |
|---|
| 1501 | | ;; Received when Emacs is launched without associated documents. |
|---|
| 1502 | | ;; Accept it as an Apple event, but no Emacs event is generated so as |
|---|
| 1503 | | ;; not to erase the splash screen. |
|---|
| 1504 | | (define-key mac-apple-event-map [core-event open-application] 0) |
|---|
| 1505 | | |
|---|
| 1506 | | ;; Received when a dock or application icon is clicked and Emacs is |
|---|
| 1507 | | ;; already running. Simply ignored. Another idea is to make a new |
|---|
| 1508 | | ;; frame if all frames are invisible. |
|---|
| 1509 | | (define-key mac-apple-event-map [core-event reopen-application] 'ignore) |
|---|
| 1510 | | |
|---|
| 1511 | | (define-key mac-apple-event-map [core-event open-documents] |
|---|
| 1512 | | 'mac-ae-open-documents) |
|---|
| 1513 | | (define-key mac-apple-event-map [core-event show-preferences] 'customize) |
|---|
| 1514 | | (define-key mac-apple-event-map [core-event quit-application] |
|---|
| 1515 | | 'save-buffers-kill-emacs) |
|---|
| 1516 | | |
|---|
| 1517 | | (define-key mac-apple-event-map [internet-event get-url] 'mac-ae-get-url) |
|---|
| 1518 | | |
|---|
| 1519 | | (define-key mac-apple-event-map [hicommand about] 'display-splash-screen) |
|---|
| 1520 | | |
|---|
| 1521 | | (defun mac-services-open-file () |
|---|
| 1522 | | "Open the file specified by the selection value for Services." |
|---|
| 1523 | | (interactive) |
|---|
| 1524 | | (find-file-existing (x-selection-value mac-services-selection))) |
|---|
| 1525 | | |
|---|
| 1526 | | (defun mac-services-open-selection () |
|---|
| 1527 | | "Create a new buffer containing the selection value for Services." |
|---|
| 1528 | | (interactive) |
|---|
| 1529 | | (switch-to-buffer (generate-new-buffer "*untitled*")) |
|---|
| 1530 | | (insert (x-selection-value mac-services-selection)) |
|---|
| 1531 | | (sit-for 0) |
|---|
| 1532 | | (save-buffer) ; It pops up the save dialog. |
|---|
| 1533 | | ) |
|---|
| 1534 | | |
|---|
| 1535 | | (defun mac-services-mail-selection () |
|---|
| 1536 | | "Prepare a mail buffer containing the selection value for Services." |
|---|
| 1537 | | (interactive) |
|---|
| 1538 | | (compose-mail) |
|---|
| 1539 | | (rfc822-goto-eoh) |
|---|
| 1540 | | (forward-line 1) |
|---|
| 1541 | | (insert (x-selection-value mac-services-selection) "\n")) |
|---|
| 1542 | | |
|---|
| 1543 | | (defun mac-services-mail-to () |
|---|
| 1544 | | "Prepare a mail buffer to be sent to the selection value for Services." |
|---|
| 1545 | | (interactive) |
|---|
| 1546 | | (compose-mail (x-selection-value mac-services-selection))) |
|---|
| 1547 | | |
|---|
| 1548 | | (defun mac-services-insert-text () |
|---|
| 1549 | | "Insert the selection value for Services." |
|---|
| 1550 | | (interactive) |
|---|
| 1551 | | (let ((text (x-selection-value mac-services-selection))) |
|---|
| 1552 | | (if (not buffer-read-only) |
|---|
| 1553 | | (insert text) |
|---|
| 1554 | | (kill-new text) |
|---|
| 1555 | | (message |
|---|
| 1556 | | (substitute-command-keys |
|---|
| 1557 | | "The text from the Services menu can be accessed with \\[yank]"))))) |
|---|
| 1558 | | |
|---|
| 1559 | | (define-key mac-apple-event-map [services paste] 'mac-services-insert-text) |
|---|
| 1560 | | (define-key mac-apple-event-map [services perform open-file] |
|---|
| 1561 | | 'mac-services-open-file) |
|---|
| 1562 | | (define-key mac-apple-event-map [services perform open-selection] |
|---|
| 1563 | | 'mac-services-open-selection) |
|---|
| 1564 | | (define-key mac-apple-event-map [services perform mail-selection] |
|---|
| 1565 | | 'mac-services-mail-selection) |
|---|
| 1566 | | (define-key mac-apple-event-map [services perform mail-to] |
|---|
| 1567 | | 'mac-services-mail-to) |
|---|
| 1568 | | |
|---|
| 1569 | | (defun mac-dispatch-apple-event (event) |
|---|
| 1570 | | "Dispatch EVENT according to the keymap `mac-apple-event-map'." |
|---|
| 1571 | | (interactive "e") |
|---|
| 1572 | | (let* ((binding (lookup-key mac-apple-event-map (mac-event-spec event))) |
|---|
| 1573 | | (service-message |
|---|
| 1574 | | (and (keymapp binding) |
|---|
| 1575 | | (cdr (mac-ae-parameter (mac-event-ae event) "svmg"))))) |
|---|
| 1576 | | (when service-message |
|---|
| 1577 | | (setq service-message |
|---|
| 1578 | | (intern (decode-coding-string service-message 'utf-8))) |
|---|
| 1579 | | (setq binding (lookup-key binding (vector service-message)))) |
|---|
| 1580 | | ;; Replace (cadr event) with a dummy position so that event-start |
|---|
| 1581 | | ;; returns it. |
|---|
| 1582 | | (setcar (cdr event) (list (selected-window) (point) '(0 . 0) 0)) |
|---|
| 1583 | | (call-interactively binding))) |
|---|
| 1584 | | |
|---|
| 1585 | | (global-set-key [mac-apple-event] 'mac-dispatch-apple-event) |
|---|
| 1586 | | |
|---|
| 1587 | | ;; Processing of Apple events are deferred at the startup time. For |
|---|
| 1588 | | ;; example, files dropped onto the Emacs application icon can only be |
|---|
| 1589 | | ;; processed when the initial frame has been created: this is where |
|---|
| 1590 | | ;; the files should be opened. |
|---|
| 1591 | | (add-hook 'after-init-hook 'mac-process-deferred-apple-events) |
|---|
| 1592 | | |
|---|
| 1593 | | ;;; Do the actual Windows setup here; the above code just defines |
|---|
| 1594 | | ;;; functions and variables that we use now. |
|---|
| 1595 | | |
|---|
| 1596 | | (setq command-line-args (x-handle-args command-line-args)) |
|---|
| 1597 | | |
|---|
| 1598 | | ;;; Make sure we have a valid resource name. |
|---|
| 1599 | | (or (stringp x-resource-name) |
|---|
| 1600 | | (let (i) |
|---|
| 1601 | | (setq x-resource-name (invocation-name)) |
|---|
| 1602 | | |
|---|
| 1603 | | ;; Change any . or * characters in x-resource-name to hyphens, |
|---|
| 1604 | | ;; so as not to choke when we use it in X resource queries. |
|---|
| 1605 | | (while (setq i (string-match "[.*]" x-resource-name)) |
|---|
| 1606 | | (aset x-resource-name i ?-)))) |
|---|
| 1607 | | |
|---|
| 1608 | | (if (x-display-list) |
|---|
| 1609 | | ;; On Mac OS 8/9, Most coding systems used in code conversion for |
|---|
| 1610 | | ;; font names are not ready at the time when the terminal frame is |
|---|
| 1611 | | ;; created. So we reconstruct font name table for the initial |
|---|
| 1612 | | ;; frame. |
|---|
| 1613 | | (mac-clear-font-name-table) |
|---|
| 1614 | | (x-open-connection "Mac" |
|---|
| 1615 | | x-command-line-resources |
|---|
| 1616 | | ;; Exit Emacs with fatal error if this fails. |
|---|
| 1617 | | t)) |
|---|
| 1618 | | |
|---|
| 1619 | | (setq frame-creation-function 'x-create-frame-with-faces) |
|---|
| 1620 | | |
|---|
| | 1223 | (defconst mac-system-coding-system |
|---|
| | 1224 | (let ((base (or (cdr (assq mac-system-script-code |
|---|
| | 1225 | mac-script-code-coding-systems)) |
|---|
| | 1226 | 'mac-roman))) |
|---|
| | 1227 | (if (eq system-type 'darwin) |
|---|
| | 1228 | base |
|---|
| | 1229 | (coding-system-change-eol-conversion base 'mac))) |
|---|
| | 1230 | "Coding system derived from the system script code.") |
|---|
| | 1231 | |
|---|
| | 1232 | (set-selection-coding-system mac-system-coding-system) |
|---|
| | 1233 | |
|---|
| | 1234 | |
|---|
| | 1235 | ;;;; Keyboard layout/language change events |
|---|
| | 1236 | (defun mac-handle-language-change (event) |
|---|
| | 1237 | "Set keyboard coding system to what is specified in EVENT." |
|---|
| | 1238 | (interactive "e") |
|---|
| | 1239 | (let ((coding-system |
|---|
| | 1240 | (cdr (assq (car (cadr event)) mac-script-code-coding-systems)))) |
|---|
| | 1241 | (set-keyboard-coding-system (or coding-system 'mac-roman)) |
|---|
| | 1242 | ;; MacJapanese maps reverse solidus to ?\x80. |
|---|
| | 1243 | (if (eq coding-system 'japanese-shift-jis) |
|---|
| | 1244 | (define-key key-translation-map [?\x80] "\\")))) |
|---|
| | 1245 | |
|---|
| | 1246 | (define-key special-event-map [language-change] 'mac-handle-language-change) |
|---|
| | 1247 | |
|---|
| | 1248 | |
|---|
| | 1249 | ;;;; Conversion between common flavors and Lisp string. |
|---|
| | 1250 | |
|---|
| | 1251 | (defconst mac-text-encoding-mac-japanese-basic-variant #x20001 |
|---|
| | 1252 | "MacJapanese text encoding without Apple double-byte extensions.") |
|---|
| | 1253 | |
|---|
| | 1254 | (defun mac-utxt-to-string (data &optional coding-system) |
|---|
| | 1255 | (or coding-system (setq coding-system mac-system-coding-system)) |
|---|
| | 1256 | (let* ((encoding |
|---|
| | 1257 | (and (eq system-type 'darwin) |
|---|
| | 1258 | (eq (coding-system-base coding-system) 'japanese-shift-jis) |
|---|
| | 1259 | mac-text-encoding-mac-japanese-basic-variant)) |
|---|
| | 1260 | (str (and (fboundp 'mac-code-convert-string) |
|---|
| | 1261 | (mac-code-convert-string data nil |
|---|
| | 1262 | (or encoding coding-system))))) |
|---|
| | 1263 | (when str |
|---|
| | 1264 | (setq str (decode-coding-string str coding-system)) |
|---|
| | 1265 | (if (eq encoding mac-text-encoding-mac-japanese-basic-variant) |
|---|
| | 1266 | ;; Does it contain Apple one-byte extensions other than |
|---|
| | 1267 | ;; reverse solidus? |
|---|
| | 1268 | (if (string-match "[\xa0\xfd-\xff]" str) |
|---|
| | 1269 | (setq str nil) |
|---|
| | 1270 | ;; ASCII-only? |
|---|
| | 1271 | (unless (string-match "\\`[[:ascii:]]*\\'" str) |
|---|
| | 1272 | (subst-char-in-string ?\x5c ?\¥ str t) |
|---|
| | 1273 | (subst-char-in-string ?\x80 ?\\ str t))))) |
|---|
| | 1274 | (or str |
|---|
| | 1275 | (decode-coding-string data |
|---|
| | 1276 | (if (eq (byteorder) ?B) 'utf-16be 'utf-16le))))) |
|---|
| | 1277 | |
|---|
| | 1278 | (defun mac-string-to-utxt (string &optional coding-system) |
|---|
| | 1279 | (or coding-system (setq coding-system mac-system-coding-system)) |
|---|
| | 1280 | (let (data encoding) |
|---|
| | 1281 | (when (and (fboundp 'mac-code-convert-string) |
|---|
| | 1282 | (memq (coding-system-base coding-system) |
|---|
| | 1283 | (find-coding-systems-string string))) |
|---|
| | 1284 | (setq coding-system |
|---|
| | 1285 | (coding-system-change-eol-conversion coding-system 'mac)) |
|---|
| | 1286 | (when (and (eq system-type 'darwin) |
|---|
| | 1287 | (eq coding-system 'japanese-shift-jis-mac)) |
|---|
| | 1288 | (setq encoding mac-text-encoding-mac-japanese-basic-variant) |
|---|
| | 1289 | (setq string (subst-char-in-string ?\\ ?\x80 string)) |
|---|
| | 1290 | (subst-char-in-string ?\¥ ?\x5c string t)) |
|---|
| | 1291 | (setq data (mac-code-convert-string |
|---|
| | 1292 | (encode-coding-string string coding-system) |
|---|
| | 1293 | (or encoding coding-system) nil))) |
|---|
| | 1294 | (or data (encode-coding-string string (if (eq (byteorder) ?B) |
|---|
| | 1295 | 'utf-16be-mac |
|---|
| | 1296 | 'utf-16le-mac))))) |
|---|
| | 1297 | |
|---|
| | 1298 | (defun mac-TEXT-to-string (data &optional coding-system) |
|---|
| | 1299 | (or coding-system (setq coding-system mac-system-coding-system)) |
|---|
| | 1300 | (prog1 (setq data (decode-coding-string data coding-system)) |
|---|
| | 1301 | (when (eq (coding-system-base coding-system) 'japanese-shift-jis) |
|---|
| | 1302 | ;; (subst-char-in-string ?\x5c ?\¥ data t) |
|---|
| | 1303 | (subst-char-in-string ?\x80 ?\\ data t)))) |
|---|
| | 1304 | |
|---|
| | 1305 | (defun mac-string-to-TEXT (string &optional coding-system) |
|---|
| | 1306 | (or coding-system (setq coding-system mac-system-coding-system)) |
|---|
| | 1307 | (let ((encodables (find-coding-systems-string string)) |
|---|
| | 1308 | (rest mac-script-code-coding-systems)) |
|---|
| | 1309 | (unless (memq (coding-system-base coding-system) encodables) |
|---|
| | 1310 | (while (and rest (not (memq (cdar rest) encodables))) |
|---|
| | 1311 | (setq rest (cdr rest))) |
|---|
| | 1312 | (if rest |
|---|
| | 1313 | (setq coding-system (cdar rest))))) |
|---|
| | 1314 | (setq coding-system |
|---|
| | 1315 | (coding-system-change-eol-conversion coding-system 'mac)) |
|---|
| | 1316 | (when (eq coding-system 'japanese-shift-jis-mac) |
|---|
| | 1317 | ;; (setq string (subst-char-in-string ?\\ ?\x80 string)) |
|---|
| | 1318 | (setq string (subst-char-in-string ?\¥ ?\x5c string))) |
|---|
| | 1319 | (encode-coding-string string coding-system)) |
|---|
| | 1320 | |
|---|
| | 1321 | (defun mac-furl-to-string (data) |
|---|
| | 1322 | ;; Remove a trailing nul character. |
|---|
| | 1323 | (let ((len (length data))) |
|---|
| | 1324 | (if (and (> len 0) (= (aref data (1- len)) ?\0)) |
|---|
| | 1325 | (substring data 0 (1- len)) |
|---|
| | 1326 | data))) |
|---|
| | 1327 | |
|---|
| | 1328 | (defun mac-TIFF-to-string (data &optional text) |
|---|
| | 1329 | (prog1 (or text (setq text (copy-sequence " "))) |
|---|
| | 1330 | (put-text-property 0 (length text) 'display (create-image data 'tiff t) |
|---|
| | 1331 | text))) |
|---|
| | 1332 | |
|---|
| | 1333 | ;;;; Selections |
|---|
| | 1334 | |
|---|
| | 1335 | ;;; We keep track of the last text selected here, so we can check the |
|---|
| | 1336 | ;;; current selection against it, and avoid passing back our own text |
|---|
| | 1337 | ;;; from x-get-selection-value. |
|---|
| | 1338 | (defvar x-last-selected-text-clipboard nil |
|---|
| | 1339 | "The value of the CLIPBOARD selection last time we selected or |
|---|
| | 1340 | pasted text.") |
|---|
| | 1341 | (defvar x-last-selected-text-primary nil |
|---|
| | 1342 | "The value of the PRIMARY X selection last time we selected or |
|---|
| | 1343 | pasted text.") |
|---|
| | 1344 | |
|---|
| | 1345 | (defcustom x-select-enable-clipboard t |
|---|
| | 1346 | "*Non-nil means cutting and pasting uses the clipboard. |
|---|
| | 1347 | This is in addition to the primary selection." |
|---|
| | 1348 | :type 'boolean |
|---|
| | 1349 | :group 'killing) |
|---|
| | 1350 | |
|---|
| | 1351 | ;;; Make TEXT, a string, the primary X selection. |
|---|
| | 1352 | (defun x-select-text (text &optional push) |
|---|
| | 1353 | (x-set-selection 'PRIMARY text) |
|---|
| | 1354 | (setq x-last-selected-text-primary text) |
|---|
| | 1355 | (if (not x-select-enable-clipboard) |
|---|
| | 1356 | (setq x-last-selected-text-clipboard nil) |
|---|
| | 1357 | (x-set-selection 'CLIPBOARD text) |
|---|
| | 1358 | (setq x-last-selected-text-clipboard text)) |
|---|
| | 1359 | ) |
|---|
| | 1360 | |
|---|
| | 1361 | (defun x-get-selection (&optional type data-type) |
|---|
| | 1362 | "Return the value of a selection. |
|---|
| | 1363 | The argument TYPE (default `PRIMARY') says which selection, |
|---|
| | 1364 | and the argument DATA-TYPE (default `STRING') says |
|---|
| | 1365 | how to convert the data. |
|---|
| | 1366 | |
|---|
| | 1367 | TYPE may be any symbol \(but nil stands for `PRIMARY'). However, |
|---|
| | 1368 | only a few symbols are commonly used. They conventionally have |
|---|
| | 1369 | all upper-case names. The most often used ones, in addition to |
|---|
| | 1370 | `PRIMARY', are `SECONDARY' and `CLIPBOARD'. |
|---|
| | 1371 | |
|---|
| | 1372 | DATA-TYPE is usually `STRING', but can also be one of the symbols |
|---|
| | 1373 | in `selection-converter-alist', which see." |
|---|
| | 1374 | (let ((data (x-get-selection-internal (or type 'PRIMARY) |
|---|
| | 1375 | (or data-type 'STRING))) |
|---|
| | 1376 | (coding (or next-selection-coding-system |
|---|
| | 1377 | selection-coding-system))) |
|---|
| | 1378 | (when (and (stringp data) |
|---|
| | 1379 | (setq data-type (get-text-property 0 'foreign-selection data))) |
|---|
| | 1380 | (cond ((eq data-type 'public.utf16-plain-text) |
|---|
| | 1381 | (setq data (mac-utxt-to-string data coding))) |
|---|
| | 1382 | ((eq data-type 'com.apple.traditional-mac-plain-text) |
|---|
| | 1383 | (setq data (mac-TEXT-to-string data coding))) |
|---|
| | 1384 | ((eq data-type 'public.file-url) |
|---|
| | 1385 | (setq data (mac-furl-to-string data)))) |
|---|
| | 1386 | (put-text-property 0 (length data) 'foreign-selection data-type data)) |
|---|
| | 1387 | data)) |
|---|
| | 1388 | |
|---|
| | 1389 | (defun x-selection-value (type) |
|---|
| | 1390 | (let ((data-types '(public.utf16-plain-text |
|---|
| | 1391 | com.apple.traditional-mac-plain-text |
|---|
| | 1392 | public.file-url)) |
|---|
| | 1393 | text tiff-image) |
|---|
| | 1394 | (while (and (null text) data-types) |
|---|
| | 1395 | (setq text (condition-case nil |
|---|
| | 1396 | (x-get-selection type (car data-types)) |
|---|
| | 1397 | (error nil))) |
|---|
| | 1398 | (setq data-types (cdr data-types))) |
|---|
| | 1399 | (if text |
|---|
| | 1400 | (remove-text-properties 0 (length text) '(foreign-selection nil) text)) |
|---|
| | 1401 | (setq tiff-image (condition-case nil |
|---|
| | 1402 | (x-get-selection type 'public.tiff) |
|---|
| | 1403 | (error nil))) |
|---|
| | 1404 | (when tiff-image |
|---|
| | 1405 | (remove-text-properties 0 (length tiff-image) |
|---|
| | 1406 | '(foreign-selection nil) tiff-image) |
|---|
| | 1407 | (setq text (mac-TIFF-to-string tiff-image text))) |
|---|
| | 1408 | text)) |
|---|
| | 1409 | |
|---|
| | 1410 | ;;; Return the value of the current selection. |
|---|
| | 1411 | ;;; Treat empty strings as if they were unset. |
|---|
| | 1412 | ;;; If this function is called twice and finds the same text, |
|---|
| | 1413 | ;;; it returns nil the second time. This is so that a single |
|---|
| | 1414 | ;;; selection won't be added to the kill ring over and over. |
|---|
| | 1415 | (defun x-get-selection-value () |
|---|
| | 1416 | (let (clip-text primary-text) |
|---|
| | 1417 | (if (not x-select-enable-clipboard) |
|---|
| | 1418 | (setq x-last-selected-text-clipboard nil) |
|---|
| | 1419 | (setq clip-text (x-selection-value 'CLIPBOARD)) |
|---|
| | 1420 | (if (string= clip-text "") (setq clip-text nil)) |
|---|
| | 1421 | |
|---|
| | 1422 | ;; Check the CLIPBOARD selection for 'newness', is it different |
|---|
| | 1423 | ;; from what we remebered them to be last time we did a |
|---|
| | 1424 | ;; cut/paste operation. |
|---|
| | 1425 | (setq clip-text |
|---|
| | 1426 | (cond;; check clipboard |
|---|
| | 1427 | ((or (not clip-text) (string= clip-text "")) |
|---|
| | 1428 | (setq x-last-selected-text-clipboard nil)) |
|---|
| | 1429 | ((eq clip-text x-last-selected-text-clipboard) nil) |
|---|
| | 1430 | ((string= clip-text x-last-selected-text-clipboard) |
|---|
| | 1431 | ;; Record the newer string, |
|---|
| | 1432 | ;; so subsequent calls can use the `eq' test. |
|---|
| | 1433 | (setq x-last-selected-text-clipboard clip-text) |
|---|
| | 1434 | nil) |
|---|
| | 1435 | (t |
|---|
| | 1436 | (setq x-last-selected-text-clipboard clip-text)))) |
|---|
| | 1437 | ) |
|---|
| | 1438 | |
|---|
| | 1439 | (setq primary-text (x-selection-value 'PRIMARY)) |
|---|
| | 1440 | ;; Check the PRIMARY selection for 'newness', is it different |
|---|
| | 1441 | ;; from what we remebered them to be last time we did a |
|---|
| | 1442 | ;; cut/paste operation. |
|---|
| | 1443 | (setq primary-text |
|---|
| | 1444 | (cond;; check primary selection |
|---|
| | 1445 | ((or (not primary-text) (string= primary-text "")) |
|---|
| | 1446 | (setq x-last-selected-text-primary nil)) |
|---|
| | 1447 | ((eq primary-text x-last-selected-text-primary) nil) |
|---|
| | 1448 | ((string= primary-text x-last-selected-text-primary) |
|---|
| | 1449 | ;; Record the newer string, |
|---|
| | 1450 | ;; so subsequent calls can use the `eq' test. |
|---|
| | 1451 | (setq x-last-selected-text-primary primary-text) |
|---|
| | 1452 | nil) |
|---|
| | 1453 | (t |
|---|
| | 1454 | (setq x-last-selected-text-primary primary-text)))) |
|---|
| | 1455 | |
|---|
| | 1456 | ;; As we have done one selection, clear this now. |
|---|
| | 1457 | (setq next-selection-coding-system nil) |
|---|
| | 1458 | |
|---|
| | 1459 | ;; At this point we have recorded the current values for the |
|---|
| | 1460 | ;; selection from clipboard (if we are supposed to) and primary, |
|---|
| | 1461 | ;; So return the first one that has changed (which is the first |
|---|
| | 1462 | ;; non-null one). |
|---|
| | 1463 | (or clip-text primary-text) |
|---|
| | 1464 | )) |
|---|
| | 1465 | |
|---|
| | 1466 | (put 'CLIPBOARD 'mac-scrap-name "com.apple.scrap.clipboard") |
|---|
| | 1467 | (when (eq system-type 'darwin) |
|---|
| | 1468 | (put 'FIND 'mac-scrap-name "com.apple.scrap.find") |
|---|
| | 1469 | (put 'PRIMARY 'mac-scrap-name |
|---|
| | 1470 | (format "org.gnu.Emacs.%d.selection.PRIMARY" (emacs-pid)))) |
|---|
| | 1471 | (put 'com.apple.traditional-mac-plain-text 'mac-ostype "TEXT") |
|---|
| | 1472 | (put 'public.utf16-plain-text 'mac-ostype "utxt") |
|---|
| | 1473 | (put 'public.tiff 'mac-ostype "TIFF") |
|---|
| | 1474 | (put 'public.file-url 'mac-ostype "furl") |
|---|
| | 1475 | |
|---|
| | 1476 | (defun mac-select-convert-to-string (selection type value) |
|---|
| | 1477 | (let ((str (cdr (xselect-convert-to-string selection nil value))) |
|---|
| | 1478 | (coding (or next-selection-coding-system selection-coding-system))) |
|---|
| | 1479 | (when str |
|---|
| | 1480 | ;; If TYPE is nil, this is a local request, thus return STR as |
|---|
| | 1481 | ;; is. Otherwise, encode STR. |
|---|
| | 1482 | (if (not type) |
|---|
| | 1483 | str |
|---|
| | 1484 | (let ((inhibit-read-only t)) |
|---|
| | 1485 | (remove-text-properties 0 (length str) '(composition nil) str) |
|---|
| | 1486 | (cond |
|---|
| | 1487 | ((eq type 'public.utf16-plain-text) |
|---|
| | 1488 | (setq str (mac-string-to-utxt str coding))) |
|---|
| | 1489 | ((eq type 'com.apple.traditional-mac-plain-text) |
|---|
| | 1490 | (setq str (mac-string-to-TEXT str coding))) |
|---|
| | 1491 | (t |
|---|
| | 1492 | (error "Unknown selection type: %S" type)) |
|---|
| | 1493 | ))) |
|---|
| | 1494 | |
|---|
| | 1495 | (setq next-selection-coding-system nil) |
|---|
| | 1496 | (cons type str)))) |
|---|
| | 1497 | |
|---|
| | 1498 | (defun mac-select-convert-to-file-url (selection type value) |
|---|
| | 1499 | (let ((filename (xselect-convert-to-filename selection type value)) |
|---|
| | 1500 | (coding (or file-name-coding-system default-file-name-coding-system))) |
|---|
| | 1501 | (if (and filename coding) |
|---|
| | 1502 | (setq filename (encode-coding-string filename coding))) |
|---|
| | 1503 | (and filename |
|---|
| | 1504 | (concat "file://localhost" |
|---|
| | 1505 | (mapconcat 'url-hexify-string |
|---|
| | 1506 | (split-string filename "/") "/"))))) |
|---|
| | 1507 | |
|---|
| | 1508 | (setq selection-converter-alist |
|---|
| | 1509 | (nconc |
|---|
| | 1510 | '((public.utf16-plain-text . mac-select-convert-to-string) |
|---|
| | 1511 | (com.apple.traditional-mac-plain-text . mac-select-convert-to-string) |
|---|
| | 1512 | ;; This is not enabled by default because the `Import Image' |
|---|
| | 1513 | ;; menu makes Emacs crash or hang for unknown reasons. |
|---|
| | 1514 | ;; (public.tiff . nil) |
|---|
| | 1515 | (public.file-url . mac-select-convert-to-file-url) |
|---|
| | 1516 | ) |
|---|
| | 1517 | selection-converter-alist)) |
|---|
| | 1518 | |
|---|
| | 1519 | ;;;; Apple events, HICommand events, and Services menu |
|---|
| | 1520 | |
|---|
| | 1521 | ;;; Event classes |
|---|
| | 1522 | (put 'core-event 'mac-apple-event-class "aevt") ; kCoreEventClass |
|---|
| | 1523 | (put 'internet-event 'mac-apple-event-class "GURL") ; kAEInternetEventClass |
|---|
| | 1524 | |
|---|
| | 1525 | ;;; Event IDs |
|---|
| | 1526 | ;; kCoreEventClass |
|---|
| | 1527 | (put 'open-application 'mac-apple-event-id "oapp") ; kAEOpenApplication |
|---|
| | 1528 | (put 'reopen-application 'mac-apple-event-id "rapp") ; kAEReopenApplication |
|---|
| | 1529 | (put 'open-documents 'mac-apple-event-id "odoc") ; kAEOpenDocuments |
|---|
| | 1530 | (put 'print-documents 'mac-apple-event-id "pdoc") ; kAEPrintDocuments |
|---|
| | 1531 | (put 'open-contents 'mac-apple-event-id "ocon") ; kAEOpenContents |
|---|
| | 1532 | (put 'quit-application 'mac-apple-event-id "quit") ; kAEQuitApplication |
|---|
| | 1533 | (put 'application-died 'mac-apple-event-id "obit") ; kAEApplicationDied |
|---|
| | 1534 | (put 'show-preferences 'mac-apple-event-id "pref") ; kAEShowPreferences |
|---|
| | 1535 | (put 'autosave-now 'mac-apple-event-id "asav") ; kAEAutosaveNow |
|---|
| | 1536 | ;; kAEInternetEventClass |
|---|
| | 1537 | (put 'get-url 'mac-apple-event-id "GURL") ; kAEGetURL |
|---|
| | 1538 | ;; Converted HICommand events |
|---|
| | 1539 | (put 'about 'mac-apple-event-id "abou") ; kHICommandAbout |
|---|
| | 1540 | |
|---|
| | 1541 | (defmacro mac-event-spec (event) |
|---|
| | 1542 | `(nth 1 ,event)) |
|---|
| | 1543 | |
|---|
| | 1544 | (defmacro mac-event-ae (event) |
|---|
| | 1545 | `(nth 2 ,event)) |
|---|
| | 1546 | |
|---|
| | 1547 | (defun mac-ae-parameter (ae &optional keyword type) |
|---|
| | 1548 | (or keyword (setq keyword "----")) ;; Direct object. |
|---|
| | 1549 | (if (not (and (consp ae) (equal (car ae) "aevt"))) |
|---|
| | 1550 | (error "Not an Apple event: %S" ae) |
|---|
| | 1551 | (let ((type-data (cdr (assoc keyword (cdr ae)))) |
|---|
| | 1552 | data) |
|---|
| | 1553 | (when (and type type-data (not (equal type (car type-data)))) |
|---|
| | 1554 | (setq data (mac-coerce-ae-data (car type-data) (cdr type-data) type)) |
|---|
| | 1555 | (setq type-data (if data (cons type data) nil))) |
|---|
| | 1556 | type-data))) |
|---|
| | 1557 | |
|---|
| | 1558 | (defun mac-ae-list (ae &optional keyword type) |
|---|
| | 1559 | (or keyword (setq keyword "----")) ;; Direct object. |
|---|
| | 1560 | (let ((desc (mac-ae-parameter ae keyword "list"))) |
|---|
| | 1561 | (cond ((null desc) |
|---|
| | 1562 | nil) |
|---|
| | 1563 | ((not (equal (car desc) "list")) |
|---|
| | 1564 | (error "Parameter for \"%s\" is not a list" keyword)) |
|---|
| | 1565 | (t |
|---|
| | 1566 | (if (null type) |
|---|
| | 1567 | (cdr desc) |
|---|
| | 1568 | (mapcar |
|---|
| | 1569 | (lambda (type-data) |
|---|
| | 1570 | (mac-coerce-ae-data (car type-data) (cdr type-data) type)) |
|---|
| | 1571 | (cdr desc))))))) |
|---|
| | 1572 | |
|---|
| | 1573 | (defun mac-bytes-to-integer (bytes &optional from to) |
|---|
| | 1574 | (or from (setq from 0)) |
|---|
| | 1575 | (or to (setq to (length bytes))) |
|---|
| | 1576 | (let* ((len (- to from)) |
|---|
| | 1577 | (extended-sign-len (- (1+ (ceiling (log most-positive-fixnum 2))) |
|---|
| | 1578 | (* 8 len))) |
|---|
| | 1579 | (result 0)) |
|---|
| | 1580 | (dotimes (i len) |
|---|
| | 1581 | (setq result (logior (lsh result 8) |
|---|
| | 1582 | (aref bytes (+ from (if (eq (byteorder) ?B) i |
|---|
| | 1583 | (- len i 1))))))) |
|---|
| | 1584 | (if (> extended-sign-len 0) |
|---|
| | 1585 | (ash (lsh result extended-sign-len) (- extended-sign-len)) |
|---|
| | 1586 | result))) |
|---|
| | 1587 | |
|---|
| | 1588 | (defun mac-bytes-to-digits (bytes &optional from to) |
|---|
| | 1589 | (or from (setq from 0)) |
|---|
| | 1590 | (or to (setq to (length bytes))) |
|---|
| | 1591 | (let ((len (- to from)) |
|---|
| | 1592 | (val 0.0)) |
|---|
| | 1593 | (dotimes (i len) |
|---|
| | 1594 | (setq val (+ (* val 256.0) |
|---|
| | 1595 | (aref bytes (+ from (if (eq (byteorder) ?B) i |
|---|
| | 1596 | (- len i 1))))))) |
|---|
| | 1597 | (format "%.0f" val))) |
|---|
| | 1598 | |
|---|
| | 1599 | (defun mac-ae-selection-range (ae) |
|---|
| | 1600 | ;; #pragma options align=mac68k |
|---|
| | 1601 | ;; typedef struct SelectionRange { |
|---|
| | 1602 | ;; short unused1; // 0 (not used) |
|---|
| | 1603 | ;; short lineNum; // line to select (<0 to specify range) |
|---|
| | 1604 | ;; long startRange; // start of selection range (if line < 0) |
|---|
| | 1605 | ;; long endRange; // end of selection range (if line < 0) |
|---|
| | 1606 | ;; long unused2; // 0 (not used) |
|---|
| | 1607 | ;; long theDate; // modification date/time |
|---|
| | 1608 | ;; } SelectionRange; |
|---|
| | 1609 | ;; #pragma options align=reset |
|---|
| | 1610 | (let ((range-bytes (cdr (mac-ae-parameter ae "kpos" "TEXT")))) |
|---|
| | 1611 | (and range-bytes |
|---|
| | 1612 | (list (mac-bytes-to-integer range-bytes 2 4) |
|---|
| | 1613 | (mac-bytes-to-integer range-bytes 4 8) |
|---|
| | 1614 | (mac-bytes-to-integer range-bytes 8 12) |
|---|
| | 1615 | (mac-bytes-to-integer range-bytes 16 20))))) |
|---|
| | 1616 | |
|---|
| | 1617 | ;; On Mac OS X 10.4 and later, the `open-document' event contains an |
|---|
| | 1618 | ;; optional parameter keyAESearchText from the Spotlight search. |
|---|
| | 1619 | (defun mac-ae-text-for-search (ae) |
|---|
| | 1620 | (let ((utf8-text (cdr (mac-ae-parameter ae "stxt" "utf8")))) |
|---|
| | 1621 | (and utf8-text |
|---|
| | 1622 | (decode-coding-string utf8-text 'utf-8)))) |
|---|
| | 1623 | |
|---|
| | 1624 | (defun mac-ae-open-documents (event) |
|---|
| | 1625 | "Open the documents specified by the Apple event EVENT." |
|---|
| | 1626 | (interactive "e") |
|---|
| | 1627 | (let ((ae (mac-event-ae event))) |
|---|
| | 1628 | (dolist (file-name (mac-ae-list ae nil 'undecoded-file-name)) |
|---|
| | 1629 | (if file-name |
|---|
| | 1630 | (dnd-open-local-file (concat "file:" file-name) nil))) |
|---|
| | 1631 | (let ((selection-range (mac-ae-selection-range ae)) |
|---|
| | 1632 | (search-text (mac-ae-text-for-search ae))) |
|---|
| | 1633 | (cond (selection-range |
|---|
| | 1634 | (let ((line (car selection-range)) |
|---|
| | 1635 | (start (cadr selection-range)) |
|---|
| | 1636 | (end (nth 2 selection-range))) |
|---|
| | 1637 | (if (> line 0) |
|---|
| | 1638 | (goto-line line) |
|---|
| | 1639 | (if (and (> start 0) (> end 0)) |
|---|
| | 1640 | (progn (set-mark start) |
|---|
| | 1641 | (goto-char end)))))) |
|---|
| | 1642 | ((stringp search-text) |
|---|
| | 1643 | (re-search-forward |
|---|
| | 1644 | (mapconcat 'regexp-quote (split-string search-text) "\\|") |
|---|
| | 1645 | nil t))))) |
|---|
| | 1646 | (select-frame-set-input-focus (selected-frame))) |
|---|
| | 1647 | |
|---|
| | 1648 | (defun mac-ae-text (ae) |
|---|
| | 1649 | (or (cdr (mac-ae-parameter ae nil "TEXT")) |
|---|
| | 1650 | (error "No text in Apple event."))) |
|---|
| | 1651 |
|---|