From: Andrew Choi Date: Sun, 22 Oct 2000 16:50:16 +0000 (+0000) Subject: Initial check-in: changes for building Emacs under Mac OS. X-Git-Tag: emacs-pretest-21.0.90~678 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=1a578e9be2034298bb8ac29b7b84086a4ab290f4;p=emacs.git Initial check-in: changes for building Emacs under Mac OS. 2000-10-23 Andrew Choi * dispextern.h [macintosh]: Include macgui.h instead of macterm.h. * dispnew.c [macintosh]: Include macterm.h. (init_display) [macintosh]: initialization for window system. * emacs.c (main) [macintosh]: Call syms_of_textprop, syms_of_macfns, syms_of_ccl, syms_of_fontset, syms_of_xterm, syms_of_search, x_term_init, and init_keyboard before calling init_window_once. Also, call syms_of_xmenu. * fontset.c (syms_of_fontset) [macintosh]: Set ASCII font of default fontset to Monaco. * frame.c [macintosh]: Include macterm.h. Remove declarations of NewMacWindow and DisposeMacWindow. (make_terminal_frame) [macintosh]: Call make_mac_terminal_frame instead of calling NewMacWindow and setting fields of f->output_data.mac directly. Call init_frame_faces. (Fdelete_frame) [macintosh]: Remove unused code. (Fmodify_frame_parameters) [macintosh]: Call x_set_frame_parameters instead of mac_set_frame_parameters. * frame.h [macintosh]: Define menu_bar_lines field in struct frame. Define FRAME_EXTERNAL_MENU_BAR macro. * keyboard.c [macintosh]: Include macterm.h. (kbd_buffer_get_event) [macintosh]: Generate delete_window_event and menu_bar_activate_event type events as for X and NT. (make_lispy_event) [macintosh]: Construct lisp events of type MENU_BAR_EVENT as for X and NT. * sysdep.c [macintosh]: Remove declaration for sys_signal. Include stdlib.h. Remove definition of Vx_bitmap_file_path. (sys_subshell) [macintosh]: Remove definition entirely. (init_sys_modes) [macintosh]: Do not initialize Vwindow_system and Vwindow_system_version here. Remove initialization of Vx_bitmap_file_path. (read_input_waiting): Correct the number of parameters passed to read_socket_hook. Move all Macintosh functions to mac/mac.c. * term.c [macintosh]: Include macterm.h. * window.c [macintosh]: Include macterm.h. * xdisp.c [macintosh]: Include macterm.h. Declare set_frame_menubar and pending_menu_activation. (echo_area_display) [macintosh]: Do not return if terminal frame is the selected frame. (update_menu_bar) [macintosh]: Check FRAME_EXTERNAL_MENU_BAR (f). Allow only the selected frame to set menu bar. (redisplay_window) [macintosh]: Obtain menu bar to redisplay by calling FRAME_EXTERNAL_MENU_BAR (f). (display_menu_bar) [macintosh]: Check FRAME_MAC_P (f). * xfaces.c [macintosh]: Include macterm.h. Define x_display_info and check_x. Declare XCreateGC. Define x_create_gc and x_free_gc. Initialize font_sort_order. (x_face_list_fonts) [macintosh]: Use the same code as WINDOWSNT, but call x_list_fonts instead of w32_list_fonts. (Finternal_face_x_get_resource) [macintosh]: Do not call display_x_get_resource. (prepare_face_for_display) [macintosh]: Set xgcv.font. (realize_x_face) [macintosh]: Load the font if it is specified in ATTRS. (syms_of_xfaces) [macintosh]: Initialize Vscalable_fonts_allowed to Qt. * cus-edit.el (custom-button-face): Use 3D look for mac. (custom-button-pressed-face): Likewise. * faces.el (set-face-attributes-from-resources): Handle mac frames in the same way as x and w32 frames. (face-valid-attribute-values): Likewise. (read-face-attribute): Likewise. (defined-colors): Likewise. (color-defined-p): Likewise. (color-values): Likewise. (display-grayscale-p): Likewise. (face-set-after-frame-default): Likewise. (mode-line): Same default face as for x and w32. (tool-bar): Likewise. * frame.el: Remove call to frame-notice-user-settings at end of the file. * info.el (Info-fontify-node): make underlines invisible for mac as for x, pc, and w32 frame types. * term/mac-win.el: New file. --- diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 0e2b2b2a62a..2531ef0de1b 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,28 @@ +2000-10-23 Andrew Choi + + * cus-edit.el (custom-button-face): Use 3D look for mac. + (custom-button-pressed-face): Likewise. + + * faces.el (set-face-attributes-from-resources): Handle mac frames + in the same way as x and w32 frames. + (face-valid-attribute-values): Likewise. + (read-face-attribute): Likewise. + (defined-colors): Likewise. + (color-defined-p): Likewise. + (color-values): Likewise. + (display-grayscale-p): Likewise. + (face-set-after-frame-default): Likewise. + (mode-line): Same default face as for x and w32. + (tool-bar): Likewise. + + * frame.el: Remove call to frame-notice-user-settings at end of + the file. + + * info.el (Info-fontify-node): make underlines invisible for mac + as for x, pc, and w32 frame types. + + * term/mac-win.el: New file. + 2000-10-22 Dave Love * textmodes/refill.el: New file. diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index a88fe81ba58..9dc8ef02a13 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -1711,6 +1711,9 @@ and `face'." (((type w32) (class color)) ; Like default modeline (:box (:line-width 2 :style released-button) :background "lightgrey" :foreground "black")) + (((type mac) (class color)) ; Like default modeline + (:box (:line-width 2 :style released-button) + :background "lightgrey" :foreground "black")) (t nil)) "Face used for buttons in customization buffers." @@ -1724,6 +1727,9 @@ and `face'." (((type w32) (class color)) (:box (:line-width 2 :style pressed-button) :background "lightgrey" :foreground "black")) + (((type mac) (class color)) + (:box (:line-width 2 :style pressed-button) + :background "lightgrey" :foreground "black")) (t (:inverse-video t))) "Face used for buttons in customization buffers." diff --git a/lisp/faces.el b/lisp/faces.el index 0d49650a509..1a246af0a5a 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -300,7 +300,7 @@ specifies an invalid attribute." (defun set-face-attributes-from-resources (face frame) "Set attributes of FACE from X resources for FRAME." - (when (memq (framep frame) '(x w32)) + (when (memq (framep frame) '(x w32 mac)) (dolist (definition face-x-resources) (let ((attribute (car definition))) (dolist (entry (cdr definition)) @@ -777,7 +777,7 @@ an integer value." ((:height) 'integerp) (:stipple - (and (memq window-system '(x w32)) + (and (memq window-system '(x w32 mac)) (mapcar #'list (apply #'nconc (mapcar (lambda (dir) @@ -1231,7 +1231,7 @@ is used. If nil or omitted, use the selected frame." The argument FRAME specifies which frame to try. The value may be different for frames on different display types. If FRAME doesn't support colors, the value is nil." - (if (memq (framep (or frame (selected-frame))) '(x w32)) + (if (memq (framep (or frame (selected-frame))) '(x w32 mac)) (xw-defined-colors frame) (mapcar 'car (tty-color-alist frame)))) (defalias 'x-defined-colors 'defined-colors) @@ -1243,7 +1243,7 @@ If COLOR is the symbol `unspecified' or one of the strings \"unspecified-fg\" or \"unspecified-bg\", the value is nil." (if (member color '(unspecified "unspecified-bg" "unspecified-fg")) nil - (if (member (framep (or frame (selected-frame))) '(x w32)) + (if (member (framep (or frame (selected-frame))) '(x w32 mac)) (xw-color-defined-p color frame) (numberp (tty-color-translate color frame))))) (defalias 'x-color-defined-p 'color-defined-p) @@ -1258,7 +1258,7 @@ If COLOR is the symbol `unspecified' or one of the strings \"unspecified-fg\" or \"unspecified-bg\", the value is nil." (if (member color '(unspecified "unspecified-fg" "unspecified-bg")) nil - (if (memq (framep (or frame (selected-frame))) '(x w32)) + (if (memq (framep (or frame (selected-frame))) '(x w32 mac)) (xw-color-values color frame) (tty-color-values color frame)))) (defalias 'x-color-values 'color-values) @@ -1268,7 +1268,7 @@ If COLOR is the symbol `unspecified' or one of the strings The optional argument DISPLAY specifies which display to ask about. DISPLAY should be either a frame or a display name (a string). If omitted or nil, that stands for the selected frame's display." - (if (memq (framep-on-display display) '(x w32)) + (if (memq (framep-on-display display) '(x w32 mac)) (xw-display-color-p display) (tty-display-color-p display))) (defalias 'x-display-color-p 'display-color-p) @@ -1445,7 +1445,7 @@ Initialize colors of certain faces from frame parameters." (when spec (face-spec-set face spec frame)) (internal-merge-in-global-face face frame) - (when (memq window-system '(x w32)) + (when (memq window-system '(x w32 mac)) (make-face-x-resource-internal face frame)))) ;; Initialize attributes from frame parameters. @@ -1527,7 +1527,7 @@ created." (defface mode-line - '((((type x w32) (class color)) + '((((type x w32 mac) (class color)) (:box (:line-width 2 :style released-button) :background "grey75" :foreground "black")) (t @@ -1572,7 +1572,7 @@ created." (defface tool-bar - '((((type x w32) (class color)) + '((((type x w32 mac) (class color)) (:box (:line-width 1 :style released-button) :background "grey75" :foreground "black")) (((type x) (class mono)) diff --git a/lisp/frame.el b/lisp/frame.el index 88d18acf04d..65392e61b63 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1164,4 +1164,3 @@ If nil, don't show a cursor except in the selected window." (provide 'frame) ;;; frame.el ends here -(frame-notice-user-settings): diff --git a/lisp/info.el b/lisp/info.el index 29d3124efe1..2e6dbc09291 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -2427,7 +2427,7 @@ the variable `Info-file-list-for-emacs'." ;; This is a serious problem for trying to handle multiple ;; frame types at once. We want this text to be invisible ;; on frames that can display the font above. - (if (memq (framep (selected-frame)) '(x pc w32)) + (if (memq (framep (selected-frame)) '(x pc w32 mac)) (add-text-properties (match-end 1) (match-end 2) '(invisible t intangible t)))) (goto-char (point-min)) diff --git a/lisp/term/mac-win.el b/lisp/term/mac-win.el new file mode 100644 index 00000000000..f44e0d77b3c --- /dev/null +++ b/lisp/term/mac-win.el @@ -0,0 +1,1075 @@ +;;; mac-win.el --- support for "Macintosh windows". + +;; Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +;; Author: Andrew Choi + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Code: + +;; --------------------------------------------------------------------------- +;; We want to delay setting frame parameters until the faces are setup + +;; Mac can't handle ~ prefix in file names +;(setq auto-save-list-file-prefix ".saves-") + +(setq frame-creation-function 'x-create-frame-with-faces) + +;; for debugging +;; (defun mac-handle-scroll-bar-event (event) (interactive "e") (princ event)) + +;;(global-set-key [vertical-scroll-bar mouse-1] 'mac-handle-scroll-bar-event) + +(global-set-key + [vertical-scroll-bar down-mouse-1] + 'mac-handle-scroll-bar-event) + +(global-unset-key [vertical-scroll-bar drag-mouse-1]) +(global-unset-key [vertical-scroll-bar mouse-1]) + +(defun mac-handle-scroll-bar-event (event) + "Handle scroll bar EVENT to emulate Mac Toolbox style scrolling." + (interactive "e") + (let* ((position (event-start event)) + (window (nth 0 position)) + (bar-part (nth 4 position))) + (select-window window) + (cond + ((eq bar-part 'up) + (goto-char (window-start window)) + (mac-scroll-down-line)) + ((eq bar-part 'above-handle) + (mac-scroll-down)) + ((eq bar-part 'handle) + (scroll-bar-drag event)) + ((eq bar-part 'below-handle) + (mac-scroll-up)) + ((eq bar-part 'down) + (goto-char (window-start window)) + (mac-scroll-up-line))))) + +(defun mac-scroll-down () + (track-mouse + (while (not (eq (car-safe (read-event)) 'mouse-1)) nil) + (scroll-down))) + +(defun mac-scroll-down-line () + (track-mouse + (while (not (eq (car-safe (read-event)) 'mouse-1)) nil) + (scroll-down 1))) + +(defun mac-scroll-up () + (track-mouse + (while (not (eq (car-safe (read-event)) 'mouse-1)) nil) + (scroll-up))) + +(defun mac-scroll-up-line () + (track-mouse + (while (not (eq (car-safe (read-event)) 'mouse-1)) nil) + (scroll-up 1))) + +(defun xw-defined-colors (&optional frame) + "Internal function called by `defined-colors', which see." + (or frame (setq frame (selected-frame))) + (let ((all-colors x-colors) + (this-color nil) + (defined-colors nil)) + (while all-colors + (setq this-color (car all-colors) + all-colors (cdr all-colors)) + (and (color-supported-p this-color frame t) + (setq defined-colors (cons this-color defined-colors)))) + defined-colors)) + +;; Don't have this yet. +(fset 'x-get-resource 'ignore) + +;; Use Lisp verison of ls instead of calling subprocess on ls (faster, +;; don't need to write ls). +(load "ls-lisp") +;; This variable specifies the Unix program to call (as a process) to +;; deteremine the amount of free space on a file system (defaults to +;; df). If it is not set to nil, ls-lisp will not work correctly +;; unless an external application df is implemented on the Mac. +(setq dired-free-space-program nil) + +;; Set this so that Emacs calls subprocesses with "sh" as shell to +;; expand filenames Note no subprocess for the shell is actually +;; started (see run_mac_command in sysdep.c). +(setq shell-file-name "sh") + +;; X Window emulation in macterm.c is not complete enough to start a +;; frame without a minibuffer properly. Call this to tell ediff +;; library to use a single frame. +(ediff-toggle-multiframe) + +;; Emacs must be told we're using an 8-bit code for file names. +;; Otherwise file names won't be displayed properly in dired mode, +;; etc. +(setq file-name-coding-system 'latin-1) + +;; Setup to use the Mac clipboard. The functions mac-cut-function and +;; mac-paste-function are defined in mac.c. +(set-selection-coding-system 'compound-text-mac) + +(setq interprogram-cut-function + '(lambda (str push) + (mac-cut-function + (encode-coding-string str selection-coding-system t) push))) + +(setq interprogram-paste-function + '(lambda () + (decode-coding-string + (mac-paste-function) selection-coding-system t))) + +(defun mac-drag-n-drop (event) + "Edit the files listed in the drag-n-drop event.\n\ +Switch to a buffer editing the last file dropped." + (interactive "e") + (save-excursion + ;; Make sure the drop target has positive co-ords + ;; before setting the selected frame - otherwise it + ;; won't work. + (let* ((window (posn-window (event-start event))) + (coords (posn-x-y (event-start event))) + (x (car coords)) + (y (cdr coords))) + (if (and (> x 0) (> y 0)) + (set-frame-selected-window nil window)) + (mapcar 'find-file (car (cdr (cdr event))))) + (raise-frame) + (recenter))) + +(global-set-key [drag-n-drop] 'mac-drag-n-drop) + +; Tell event loop in macterm.c we are ready. +(setq mac-ready-for-drag-n-drop t) + +; Define constant values to be set to mac-keyboard-text-encoding +(defconst kTextEncodingMacRoman 0) +(defconst kTextEncodingISOLatin1 513 "0x201") +(defconst kTextEncodingISOLatin2 514 "0x202") + +;; Definitions for the Mac Roman character sets and coding system. +;; The Mac Roman encoding uses all 128 code points in the range 128 to +;; 255 for actual characters. Since Emacs cannot handle this many +;; code points as one character set, we divide it into two: +;; mac-roman-lower for code points 128 to 159 and mac-roman-upper for +;; code points 160 to 255. + +(defvar mac-roman-lower-final-char + (get-unused-iso-final-char 1 96)) + +(defvar mac-roman-upper-final-char + (1+ mac-roman-lower-final-char)) + +(define-charset nil 'mac-roman-lower + (vector 1 96 1 0 mac-roman-lower-final-char 1 + "Mac Roman lower" "Mac Roman lower" "Mac Roman lower")) + +(define-charset nil 'mac-roman-upper + (vector 1 96 1 0 mac-roman-upper-final-char 1 + "Mac Roman upper" "Mac Roman upper" "Mac Roman upper")) + +;; Since Mac Roman does not follow the ISO 2022 standard and uses code +;; points in the range 128-159, it is necessary to define it as a +;; type-4 charset, with CCL programs and all. + +(define-ccl-program decode-mac-roman + `(2 + ((loop + (read r0) + (if (r0 < 128) ;; ASCII + (if (r0 == ?\r) ;; assume such a file uses Mac EOL's + (write-repeat ?\n) + (write-repeat r0)) + (if (r0 < 160) ;; lower + ((r0 += 32) + (r1 = ,(charset-id 'mac-roman-lower)) + (write-multibyte-character r1 r0) + (repeat)) + ((r1 = ,(charset-id 'mac-roman-upper)) ;; upper + (write-multibyte-character r1 r0) + (repeat))))))) + "CCL program to decode Mac Roman") + +(define-ccl-program encode-mac-roman + `(1 + ((loop + (read-multibyte-character r0 r1) + (if (r0 == ,(charset-id 'ascii)) + (if (r1 == ?\n) + (write-repeat ?\r) + (write-repeat r1)) + (if (r0 == ,(charset-id 'mac-roman-lower)) + ((r1 += 96) + (write-repeat r1)) + (if (r0 == ,(charset-id 'mac-roman-upper)) + ((r1 += 128) + (write-repeat r1)))))))) + "CCL program to encode Mac Roman") + +(make-coding-system + 'mac-roman 4 ?M "Mac Roman Encoding" + '(decode-mac-roman . encode-mac-roman) + '((safe-charsets ascii mac-roman-lower mac-roman-upper) + (valid codes (0 . 255)))) + +;; This doesn't seem to do anything for type-4 charsets: +;; (put 'mac-roman 'eol-type (make-subsidiary-coding-system 'mac-roman)) + +(define-ccl-program ccl-encode-mac-roman-font + `(0 + (if (r0 == ,(charset-id 'mac-roman-lower)) + (r1 += 96) + (r1 += 128)))) + +(setq font-ccl-encoder-alist + (cons '("mac-roman" . ccl-encode-mac-roman-font) + font-ccl-encoder-alist)) + +(if (fboundp 'new-fontset) + (progn + (create-fontset-from-fontset-spec + "-etl-fixed-medium-r-normal-*-16-*-*-*-*-*-fontset-mac, + mac-roman-lower:-*-Monaco-*-*-*-*-12-*-*-*-*-*-mac-roman, + mac-roman-upper:-*-Monaco-*-*-*-*-12-*-*-*-*-*-mac-roman" + t))) + +;; To display filenames in Chinese or Japanese, replace mac-roman with +;; big5 or sjis +(setq file-name-coding-system 'mac-roman) + +;; (prefer-coding-system 'mac-roman) + +(defun mac-roman-kbd-insert () + "Insert a character in Mac Roman encoding at point.\n\ +Called by keymap of Mac-kbd minor mode." + (interactive "*") + (let ((ch last-command-char)) + (if (< ch 160) + (insert + (make-char 'mac-roman-lower + (- last-command-char 96))) + (insert + (make-char 'mac-roman-upper + (- last-command-char 128)))))) + +(defvar mac-roman-kbd-mode nil + "Non-nil if in Mac-kbd minor mode.") + +(put 'mac-roman-kbd-mode 'permanent-local t) + +(or (assq 'mac-roman-kbd-mode minor-mode-alist) + (setq minor-mode-alist + (cons '(mac-roman-kbd-mode " Mac-kbd") minor-mode-alist))) + +(defvar mac-roman-kbd-mode-map + (let ((map (make-keymap)) + (i 128)) + (while (< i 256) + (define-key map (vector i) 'mac-roman-kbd-insert) + (setq i (1+ i))) + map) + "Keymap for Mac-kbd minor mode.") + +(or (assq 'mac-roman-kbd-mode minor-mode-map-alist) + (setq minor-mode-map-alist + (cons (cons 'mac-roman-kbd-mode mac-roman-kbd-mode-map) + minor-mode-map-alist))) + +(defun mac-roman-kbd-mode (&optional arg) + "Toggle Mac Roman Keyboard (Mac-kbd) minor mode.\n\ +In this minor mode, characters in the range 128 to 255 generated by\n\ +the Mac keyboard are inserted as mac-roman-lower or mac-roman-upper\n\ +characters, in the mac-roman encoding.\n\ +\n\ +With an argument, a positive argument enables Mac Roman Keyboard mode,\n\ +and a negative argument disables it." + (interactive "P") + (if (if arg + ;; Negative arg means switch it off. + (<= (prefix-numeric-value arg) 0) + ;; No arg means toggle. + mac-roman-kbd-mode) + (setq mac-roman-kbd-mode nil) + ;; Enable mode. + (setq mac-roman-kbd-mode t))) + +;; +;; Available colors +;; + +(defvar x-colors '("LightGreen" + "light green" + "DarkRed" + "dark red" + "DarkMagenta" + "dark magenta" + "DarkCyan" + "dark cyan" + "DarkBlue" + "dark blue" + "DarkGray" + "dark gray" + "DarkGrey" + "dark grey" + "grey100" + "gray100" + "grey99" + "gray99" + "grey98" + "gray98" + "grey97" + "gray97" + "grey96" + "gray96" + "grey95" + "gray95" + "grey94" + "gray94" + "grey93" + "gray93" + "grey92" + "gray92" + "grey91" + "gray91" + "grey90" + "gray90" + "grey89" + "gray89" + "grey88" + "gray88" + "grey87" + "gray87" + "grey86" + "gray86" + "grey85" + "gray85" + "grey84" + "gray84" + "grey83" + "gray83" + "grey82" + "gray82" + "grey81" + "gray81" + "grey80" + "gray80" + "grey79" + "gray79" + "grey78" + "gray78" + "grey77" + "gray77" + "grey76" + "gray76" + "grey75" + "gray75" + "grey74" + "gray74" + "grey73" + "gray73" + "grey72" + "gray72" + "grey71" + "gray71" + "grey70" + "gray70" + "grey69" + "gray69" + "grey68" + "gray68" + "grey67" + "gray67" + "grey66" + "gray66" + "grey65" + "gray65" + "grey64" + "gray64" + "grey63" + "gray63" + "grey62" + "gray62" + "grey61" + "gray61" + "grey60" + "gray60" + "grey59" + "gray59" + "grey58" + "gray58" + "grey57" + "gray57" + "grey56" + "gray56" + "grey55" + "gray55" + "grey54" + "gray54" + "grey53" + "gray53" + "grey52" + "gray52" + "grey51" + "gray51" + "grey50" + "gray50" + "grey49" + "gray49" + "grey48" + "gray48" + "grey47" + "gray47" + "grey46" + "gray46" + "grey45" + "gray45" + "grey44" + "gray44" + "grey43" + "gray43" + "grey42" + "gray42" + "grey41" + "gray41" + "grey40" + "gray40" + "grey39" + "gray39" + "grey38" + "gray38" + "grey37" + "gray37" + "grey36" + "gray36" + "grey35" + "gray35" + "grey34" + "gray34" + "grey33" + "gray33" + "grey32" + "gray32" + "grey31" + "gray31" + "grey30" + "gray30" + "grey29" + "gray29" + "grey28" + "gray28" + "grey27" + "gray27" + "grey26" + "gray26" + "grey25" + "gray25" + "grey24" + "gray24" + "grey23" + "gray23" + "grey22" + "gray22" + "grey21" + "gray21" + "grey20" + "gray20" + "grey19" + "gray19" + "grey18" + "gray18" + "grey17" + "gray17" + "grey16" + "gray16" + "grey15" + "gray15" + "grey14" + "gray14" + "grey13" + "gray13" + "grey12" + "gray12" + "grey11" + "gray11" + "grey10" + "gray10" + "grey9" + "gray9" + "grey8" + "gray8" + "grey7" + "gray7" + "grey6" + "gray6" + "grey5" + "gray5" + "grey4" + "gray4" + "grey3" + "gray3" + "grey2" + "gray2" + "grey1" + "gray1" + "grey0" + "gray0" + "thistle4" + "thistle3" + "thistle2" + "thistle1" + "MediumPurple4" + "MediumPurple3" + "MediumPurple2" + "MediumPurple1" + "purple4" + "purple3" + "purple2" + "purple1" + "DarkOrchid4" + "DarkOrchid3" + "DarkOrchid2" + "DarkOrchid1" + "MediumOrchid4" + "MediumOrchid3" + "MediumOrchid2" + "MediumOrchid1" + "plum4" + "plum3" + "plum2" + "plum1" + "orchid4" + "orchid3" + "orchid2" + "orchid1" + "magenta4" + "magenta3" + "magenta2" + "magenta1" + "VioletRed4" + "VioletRed3" + "VioletRed2" + "VioletRed1" + "maroon4" + "maroon3" + "maroon2" + "maroon1" + "PaleVioletRed4" + "PaleVioletRed3" + "PaleVioletRed2" + "PaleVioletRed1" + "LightPink4" + "LightPink3" + "LightPink2" + "LightPink1" + "pink4" + "pink3" + "pink2" + "pink1" + "HotPink4" + "HotPink3" + "HotPink2" + "HotPink1" + "DeepPink4" + "DeepPink3" + "DeepPink2" + "DeepPink1" + "red4" + "red3" + "red2" + "red1" + "OrangeRed4" + "OrangeRed3" + "OrangeRed2" + "OrangeRed1" + "tomato4" + "tomato3" + "tomato2" + "tomato1" + "coral4" + "coral3" + "coral2" + "coral1" + "DarkOrange4" + "DarkOrange3" + "DarkOrange2" + "DarkOrange1" + "orange4" + "orange3" + "orange2" + "orange1" + "LightSalmon4" + "LightSalmon3" + "LightSalmon2" + "LightSalmon1" + "salmon4" + "salmon3" + "salmon2" + "salmon1" + "brown4" + "brown3" + "brown2" + "brown1" + "firebrick4" + "firebrick3" + "firebrick2" + "firebrick1" + "chocolate4" + "chocolate3" + "chocolate2" + "chocolate1" + "tan4" + "tan3" + "tan2" + "tan1" + "wheat4" + "wheat3" + "wheat2" + "wheat1" + "burlywood4" + "burlywood3" + "burlywood2" + "burlywood1" + "sienna4" + "sienna3" + "sienna2" + "sienna1" + "IndianRed4" + "IndianRed3" + "IndianRed2" + "IndianRed1" + "RosyBrown4" + "RosyBrown3" + "RosyBrown2" + "RosyBrown1" + "DarkGoldenrod4" + "DarkGoldenrod3" + "DarkGoldenrod2" + "DarkGoldenrod1" + "goldenrod4" + "goldenrod3" + "goldenrod2" + "goldenrod1" + "gold4" + "gold3" + "gold2" + "gold1" + "yellow4" + "yellow3" + "yellow2" + "yellow1" + "LightYellow4" + "LightYellow3" + "LightYellow2" + "LightYellow1" + "LightGoldenrod4" + "LightGoldenrod3" + "LightGoldenrod2" + "LightGoldenrod1" + "khaki4" + "khaki3" + "khaki2" + "khaki1" + "DarkOliveGreen4" + "DarkOliveGreen3" + "DarkOliveGreen2" + "DarkOliveGreen1" + "OliveDrab4" + "OliveDrab3" + "OliveDrab2" + "OliveDrab1" + "chartreuse4" + "chartreuse3" + "chartreuse2" + "chartreuse1" + "green4" + "green3" + "green2" + "green1" + "SpringGreen4" + "SpringGreen3" + "SpringGreen2" + "SpringGreen1" + "PaleGreen4" + "PaleGreen3" + "PaleGreen2" + "PaleGreen1" + "SeaGreen4" + "SeaGreen3" + "SeaGreen2" + "SeaGreen1" + "DarkSeaGreen4" + "DarkSeaGreen3" + "DarkSeaGreen2" + "DarkSeaGreen1" + "aquamarine4" + "aquamarine3" + "aquamarine2" + "aquamarine1" + "DarkSlateGray4" + "DarkSlateGray3" + "DarkSlateGray2" + "DarkSlateGray1" + "cyan4" + "cyan3" + "cyan2" + "cyan1" + "turquoise4" + "turquoise3" + "turquoise2" + "turquoise1" + "CadetBlue4" + "CadetBlue3" + "CadetBlue2" + "CadetBlue1" + "PaleTurquoise4" + "PaleTurquoise3" + "PaleTurquoise2" + "PaleTurquoise1" + "LightCyan4" + "LightCyan3" + "LightCyan2" + "LightCyan1" + "LightBlue4" + "LightBlue3" + "LightBlue2" + "LightBlue1" + "LightSteelBlue4" + "LightSteelBlue3" + "LightSteelBlue2" + "LightSteelBlue1" + "SlateGray4" + "SlateGray3" + "SlateGray2" + "SlateGray1" + "LightSkyBlue4" + "LightSkyBlue3" + "LightSkyBlue2" + "LightSkyBlue1" + "SkyBlue4" + "SkyBlue3" + "SkyBlue2" + "SkyBlue1" + "DeepSkyBlue4" + "DeepSkyBlue3" + "DeepSkyBlue2" + "DeepSkyBlue1" + "SteelBlue4" + "SteelBlue3" + "SteelBlue2" + "SteelBlue1" + "DodgerBlue4" + "DodgerBlue3" + "DodgerBlue2" + "DodgerBlue1" + "blue4" + "blue3" + "blue2" + "blue1" + "RoyalBlue4" + "RoyalBlue3" + "RoyalBlue2" + "RoyalBlue1" + "SlateBlue4" + "SlateBlue3" + "SlateBlue2" + "SlateBlue1" + "azure4" + "azure3" + "azure2" + "azure1" + "MistyRose4" + "MistyRose3" + "MistyRose2" + "MistyRose1" + "LavenderBlush4" + "LavenderBlush3" + "LavenderBlush2" + "LavenderBlush1" + "honeydew4" + "honeydew3" + "honeydew2" + "honeydew1" + "ivory4" + "ivory3" + "ivory2" + "ivory1" + "cornsilk4" + "cornsilk3" + "cornsilk2" + "cornsilk1" + "LemonChiffon4" + "LemonChiffon3" + "LemonChiffon2" + "LemonChiffon1" + "NavajoWhite4" + "NavajoWhite3" + "NavajoWhite2" + "NavajoWhite1" + "PeachPuff4" + "PeachPuff3" + "PeachPuff2" + "PeachPuff1" + "bisque4" + "bisque3" + "bisque2" + "bisque1" + "AntiqueWhite4" + "AntiqueWhite3" + "AntiqueWhite2" + "AntiqueWhite1" + "seashell4" + "seashell3" + "seashell2" + "seashell1" + "snow4" + "snow3" + "snow2" + "snow1" + "thistle" + "MediumPurple" + "medium purple" + "purple" + "BlueViolet" + "blue violet" + "DarkViolet" + "dark violet" + "DarkOrchid" + "dark orchid" + "MediumOrchid" + "medium orchid" + "orchid" + "plum" + "violet" + "magenta" + "VioletRed" + "violet red" + "MediumVioletRed" + "medium violet red" + "maroon" + "PaleVioletRed" + "pale violet red" + "LightPink" + "light pink" + "pink" + "DeepPink" + "deep pink" + "HotPink" + "hot pink" + "red" + "OrangeRed" + "orange red" + "tomato" + "LightCoral" + "light coral" + "coral" + "DarkOrange" + "dark orange" + "orange" + "LightSalmon" + "light salmon" + "salmon" + "DarkSalmon" + "dark salmon" + "brown" + "firebrick" + "chocolate" + "tan" + "SandyBrown" + "sandy brown" + "wheat" + "beige" + "burlywood" + "peru" + "sienna" + "SaddleBrown" + "saddle brown" + "IndianRed" + "indian red" + "RosyBrown" + "rosy brown" + "DarkGoldenrod" + "dark goldenrod" + "goldenrod" + "LightGoldenrod" + "light goldenrod" + "gold" + "yellow" + "LightYellow" + "light yellow" + "LightGoldenrodYellow" + "light goldenrod yellow" + "PaleGoldenrod" + "pale goldenrod" + "khaki" + "DarkKhaki" + "dark khaki" + "OliveDrab" + "olive drab" + "ForestGreen" + "forest green" + "YellowGreen" + "yellow green" + "LimeGreen" + "lime green" + "GreenYellow" + "green yellow" + "MediumSpringGreen" + "medium spring green" + "chartreuse" + "green" + "LawnGreen" + "lawn green" + "SpringGreen" + "spring green" + "PaleGreen" + "pale green" + "LightSeaGreen" + "light sea green" + "MediumSeaGreen" + "medium sea green" + "SeaGreen" + "sea green" + "DarkSeaGreen" + "dark sea green" + "DarkOliveGreen" + "dark olive green" + "DarkGreen" + "dark green" + "aquamarine" + "MediumAquamarine" + "medium aquamarine" + "CadetBlue" + "cadet blue" + "LightCyan" + "light cyan" + "cyan" + "turquoise" + "MediumTurquoise" + "medium turquoise" + "DarkTurquoise" + "dark turquoise" + "PaleTurquoise" + "pale turquoise" + "PowderBlue" + "powder blue" + "LightBlue" + "light blue" + "LightSteelBlue" + "light steel blue" + "SteelBlue" + "steel blue" + "LightSkyBlue" + "light sky blue" + "SkyBlue" + "sky blue" + "DeepSkyBlue" + "deep sky blue" + "DodgerBlue" + "dodger blue" + "blue" + "RoyalBlue" + "royal blue" + "MediumBlue" + "medium blue" + "LightSlateBlue" + "light slate blue" + "MediumSlateBlue" + "medium slate blue" + "SlateBlue" + "slate blue" + "DarkSlateBlue" + "dark slate blue" + "CornflowerBlue" + "cornflower blue" + "NavyBlue" + "navy blue" + "navy" + "MidnightBlue" + "midnight blue" + "LightGray" + "light gray" + "LightGrey" + "light grey" + "grey" + "gray" + "LightSlateGrey" + "light slate grey" + "LightSlateGray" + "light slate gray" + "SlateGrey" + "slate grey" + "SlateGray" + "slate gray" + "DimGrey" + "dim grey" + "DimGray" + "dim gray" + "DarkSlateGrey" + "dark slate grey" + "DarkSlateGray" + "dark slate gray" + "black" + "white" + "MistyRose" + "misty rose" + "LavenderBlush" + "lavender blush" + "lavender" + "AliceBlue" + "alice blue" + "azure" + "MintCream" + "mint cream" + "honeydew" + "seashell" + "LemonChiffon" + "lemon chiffon" + "ivory" + "cornsilk" + "moccasin" + "NavajoWhite" + "navajo white" + "PeachPuff" + "peach puff" + "bisque" + "BlanchedAlmond" + "blanched almond" + "PapayaWhip" + "papaya whip" + "AntiqueWhite" + "antique white" + "linen" + "OldLace" + "old lace" + "FloralWhite" + "floral white" + "gainsboro" + "WhiteSmoke" + "white smoke" + "GhostWhite" + "ghost white" + "snow") + "The list of X colors from the `rgb.txt' file. +XConsortium: rgb.txt,v 10.41 94/02/20 18:39:36 rws Exp") + +;;; mac-win.el ends here + diff --git a/mac/.emacs b/mac/.emacs new file mode 100644 index 00000000000..46405165803 --- /dev/null +++ b/mac/.emacs @@ -0,0 +1,10 @@ +; MPW does not allow saving a file with name beginning with a period. +; Use Emacs or SimpleText to edit and save this file instead. + +(cond ((fboundp 'global-font-lock-mode) + ;; Turn on font-lock in all modes that support it + (global-font-lock-mode t) + ;; Maximum colors + (setq font-lock-maximum-decoration t))) + +(setq default-frame-alist '((font . "fontset-mac"))) diff --git a/mac/ChangeLog b/mac/ChangeLog new file mode 100644 index 00000000000..9ccf9efb5d3 --- /dev/null +++ b/mac/ChangeLog @@ -0,0 +1,67 @@ +2000-10-20 Andrew Choi + + * INSTALL: New file. + + * README: New file. + + * TODO: New file. + + * emacs-cw5.mcp.xml: New file. + + * emacs-cw6.mcp.xml: New file. + + * makefile.MPW: New file. + + * inc/alloca.h: New file. + + * inc/cmdline-defs-cw5.h: New file. + + * inc/cmdline-defs-cw6.h: New file. + + * inc/config.h: New file. + + * inc/dirent.h: New file. + + * inc/epaths.h: New file. + + * inc/m-mac.h: New file. + + * inc/macgui.h: New file. + + * inc/macterm.h: New file. + + * inc/pwd.h: New file. + + * inc/s-mac.h: New file. + + * inc/termio.h: New file. + + * inc/utime.h: New file. + + * inc/utsname.h: New file. + + * inc/sys/file.h: New file. + + * inc/sys/ioctl.h: New file. + + * inc/sys/param.h: New file. + + * inc/sys/stat.h: New file. + + * inc/sys/time.h: New file. + + * inc/sys/types.h: New file. + + * src/Emacs.r: New file. + + * src/EmacsMPW.r: New file. + + * src/chdir.c: New file. + + * src/mac.c: New file. + + * src/macfns.c: New file. + + * src/macmenu.c: New file. + + * src/macterm.c: New file. diff --git a/mac/INSTALL b/mac/INSTALL new file mode 100644 index 00000000000..18ab3b4d201 --- /dev/null +++ b/mac/INSTALL @@ -0,0 +1,105 @@ +* BUILDING EMACS ON THE MAC OS -*- outline -*- + +You can use either Metrowerks CodeWarrior Pro 5 or 6 or MPW-GM +(Aug. 2000) to build Emacs. MPW-GM can be downloaded free of charge +from Apple at + + http://developer.apple.com/tools/mpw-tools/ + +You will need MPW-GM to build the make-docfile utility and to generate +the doc string file DOC. + +To decompress files, you can use MacGzip from + + http://persephone.cps.unizar.es/~spd/gzip + +and to untar them, you can use tar 4.0 from + + http://hyperarchive.lcs.mit.edu/HyperArchive/Archive/cmp/tar-40b.hqx + +(Optional) If you wish to fetch files from the Emacs CVS repository +directly to your Mac, you can use the CVS client MacCVS, which can be +downloaded from + + http://www.wincvs.org/ + +(Optional) A subset of the fonts from the GNU intlfonts-1.2 +distribution converted to NFNT format can be obtained from + + ftp://mac-emacs.sourceforge.net/pub/mac-emacs/GNU-fonts.smi.bin + +* BUILDING EMACS + +To build Emacs in the MPW Shell, simply set the directory to +...:emacs:mac: and build the target Emacs of the make file +makefile.mpw. I.e., execute the commands + + make Emacs -f makefile.MPW > Emacs.MakeScript + Emacs.MakeScript + +To build Emacs using CodeWarrior, start up the CodeWarrior IDE, choose +File->Import Project... and select the file emacs-cw5.mcp.xml or +emacs-cw6.mcp.xml, depending on which verison of CodeWarrior used. +When prompted to save the project, navigate to same directory as the +file emacs-cw[56].mcp.xml, name it emacs-cw5.mcp or emacs-cw6.mcp, and +save it there. Then choose Project->Make. Note that this does not +build the DOC file. To do so, use MPW and build the target "Doc" in +makefile.MPW. + +Once built, the Emacs application (Emacs CW or Emacs MPW) can be +launched where it is created. + +To build an optimized version of Emacs in CodeWarrior, change the +value in the Emacs Settings->Code Generation->Global Optimization +dialog. To build a version for profiling, check the Profiler +Information box in the Emacs Settings->Code Generation->PPC Processor +dialog and include the Profiler PPC.Lib library. + +To build optimized or debugging version of Emacs in MPW, follow the +comment in makefile.MPW to enable the -opt speed or -sym on option +(see note below). + +The Mac version requires compiled Lisp files to be present in the lisp +directory to run properly. It is cumbersome to bootstrap from only +the Lisp source files. One way of getting the compiled Lisp files is +to build Emacs once on, say, a Unix system and transfer that directory +to the Mac. Note that linefeed conversion must be disabled when +transferring compiled Lisp files. + +An alternative is to unzip and untar the archive lisp-elc.tgz. An +older version of frame.elc in the archive may cause a problem when the +Mac version starts up. If this is the case, simply remove or rename +that file. Then once Emacs runs, you can invoke +byte-recompile-directory on the lisp directory to byte-compile all +out-of-date Lisp files. + +You may also need to run update-autoloads-from-directories on the lisp +directory to bring loaddefs.el up-to-date. + +* NOTES + +Emacs should build and run on a PowerMac running Mac OS 8.1 - 9.0. + +You will need around 100 MB of disk space for the source files and +intermediate files. + +It will not run on machines with more than 256 MB of physical or +virtual memory. + +Currently there is no support for building the LEIM directory on the +Mac. However, it can be built on another platform and transferred to +the Mac. + +When Emacs is built with "-opt speed" enabled in makefile.MPW, +optimization causes the functions reset_buffer_local_variables in +buffer.c and syms_of_lread in lread.c to crash. Avoid this by +enclosing them in the following pragmas. + + #pragma options opt off + + + + #pragma options opt reset + +To use the same icon as when Emacs is built on Windows NT, define +GNU_ICON in mac/src/Emacs.r. diff --git a/mac/README b/mac/README new file mode 100644 index 00000000000..7d6938220a7 --- /dev/null +++ b/mac/README @@ -0,0 +1,33 @@ +GNU Emacs for Mac OS + +This directory contains the files needed to build GNU Emacs on the Mac +OS (8.1-9.0). Many of the major features of the Unix version are +supported: multiple frames, colors, scroll bars, menu bars, use of the +mouse, fontsets, international characters, input methods, and coding +systems. + +Mac OS specific support includes document drag-and-drop in the Finder, +transfer of text to and from other applications via the clipboard, and +sending AppleScript commands to other applications from Emacs. + +The following are not yet supported: unexec (dump-emacs), asynchronous +subprocesses (start-process), and networking +(open-network-connection). + +There is basic support for synchronous subprocesses (call-process) +although Unix commands that are used will need to be ported to the +Mac. + +Metrowerks CodeWarrior Pro 5 or Pro 6 or MPW-GM (August 2000) can be +used to build Emacs on the Mac OS. See the INSTALL file in this +directory for instructions on building Emacs. + +Binary distributions are available at + + http://mac-emacs.sourceforge.net/index.html + +At this site you can also find an FAQ, mailing lists, and dicussion +forums for discussing issues related to running GNU Emacs on Mac OS. + +Andrew. + diff --git a/mac/emacs-cw5.mcp.xml b/mac/emacs-cw5.mcp.xml new file mode 100644 index 00000000000..c9967473042 --- /dev/null +++ b/mac/emacs-cw5.mcp.xml @@ -0,0 +1,2053 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + Emacs + + + + UserSourceTrees + + + CustomColor1 + Red6168 + Green24672 + Blue23130 + + CustomColor2 + Red0 + Green32767 + Blue0 + + CustomColor3 + Red0 + Green32767 + Blue0 + + CustomColor4 + Red0 + Green32767 + Blue0 + + CustomKeywordList1DEFUN + + + AlwaysSearchUserPathstrue + InterpretDOSAndUnixPathstrue + UserSearchPaths + + SearchPath + Path:inc: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SearchPath + Path:src: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SearchPath + Path::src: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SystemSearchPaths + + SearchPath + Path:inc: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SearchPath + Path: + PathFormatMacOS + PathRootCodeWarrior + + Recursivetrue + HostFlagsAll + + + + + LinkerMacOS PPC Linker + PreLinker + PostLinker + TargetnameEmacs + OutputDirectory + Path: + PathFormatMacOS + PathRootProject + + SaveEntriesUsingRelativePathsfalse + + + FileMappings + + FileTypeAPPL + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeAppl + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeMMLB + FileExtension + CompilerLib Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeMPLF + FileExtension + CompilerLib Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeMWCD + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeRSRC + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.bh + CompilerBalloon Help + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.c + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.c++ + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cc + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cp + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cpp + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.exp + Compiler + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.gc + CompilerGameCode Converter + Precompilefalse + Launchabletrue + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.h + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMaketrue + + + FileTypeTEXT + FileExtension.l + CompilerFlex Preprocessor + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.p + CompilerMW Pascal PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pas + CompilerMW Pascal PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pch + CompilerMW C/C++ PPC + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pch++ + CompilerMW C/C++ PPC + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.ppu + CompilerMW Pascal PPC + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.r + CompilerRez + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.s + CompilerPPCAsm + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.y + CompilerBison Preprocessor + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeXCOF + FileExtension + CompilerXCOFF Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypedocu + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypersrc + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeshlb + FileExtension + CompilerPEF Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypestub + FileExtension + CompilerPEF Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileExtension.doc + Compiler + Precompilefalse + Launchabletrue + ResourceFilefalse + IgnoredByMaketrue + + + + + CacheModDatestrue + ActivateBrowsertrue + DumpBrowserInfofalse + CacheSubprojectstrue + UseThirdPartyDebuggerfalse + DebuggerCommandLine + Debugger Runtime + 0002000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000006315C40000000000000010006316550 + 000200000000000000000000063153E000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000 + + + + LogSystemMessagesfalse + AutoTargetDLLsfalse + StopAtWatchpointstrue + PauseWhileRunningfalse + PauseInterval5 + PauseUIFlags0 + AltExePath + Path + PathFormatGeneric + PathRootAbsolute + + StopAtTempBPOnLaunchtrue + CacheSymbolicstrue + TempBPFunctionNamemain + TempBPTypefalse + + + MWCodeGen_68K_codesizeSmart + MWCodeGen_68K_structalignmentMC68K + MWCodeGen_68K_fp_modeSANE + MWCodeGen_68K_code680200 + MWCodeGen_68K_profiler0 + MWCodeGen_68K_mpwc0 + MWCodeGen_68K_fourbyteints1 + MWCodeGen_68K_IEEEdoubles1 + MWCodeGen_68K_fardata1 + MWCodeGen_68K_farvtables1 + MWCodeGen_68K_farstrings1 + MWCodeGen_68K_pcrelstrings0 + MWCodeGen_68K_macsbugNew + MWCodeGen_68K_a6frames1 + + + MWDisassembler_68K_showcode1 + MWDisassembler_68K_mix0 + MWDisassembler_68K_nohex0 + MWDisassembler_68K_showdata1 + MWDisassembler_68K_showexceptions1 + MWDisassembler_68K_showsym0 + MWDisassembler_68K_shownames1 + + + GlobalOptimizer_68K_optimizationlevelLevel0 + GlobalOptimizer_68K_optforSpeed + + + MWLinker_68K_linksym1 + MWLinker_68K_symfullpath1 + MWLinker_68K_linksingle0 + MWLinker_68K_fastlink1 + MWLinker_68K_generateMap0 + MWLinker_68K_nolinkwarnings0 + MWLinker_68K_glueintosegone1 + MWLinker_68K_dontdeadstripinitcode0 + + + MWProject_68K_typeApplication + MWProject_68K_outfileMacOS Toolbox DEBUG 68K + MWProject_68K_symfilename + MWProject_68K_filecreator1061109567 + MWProject_68K_filetype1095782476 + MWProject_68K_size384 + MWProject_68K_flags22720 + MWProject_68K_rsrcheaderStandard + MWProject_68K_rsrcname + MWProject_68K_rsrctype1061109567 + MWProject_68K_rsrcid0 + MWProject_68K_rsrcmulti0 + MWProject_68K_rsrcstore0 + MWProject_68K_rsrcmerge0 + MWProject_68K_rsrcflags0 + MWProject_68K_a40 + MWProject_68K_minsize384 + MWProject_68K_rsrcsegtype0 + MWProject_68K_cfm68kcodegen0 + MWProject_68K_stacksize0 + MWProject_68K_thedebugger0 + MWProject_68K_rsrc_custom0 + MWProject_68K_is_rseg_app0 + MWProject_68K_is_pilot_lib0 + MWProject_68K_pilot_main_entry + + + MWFrontEnd_C_cplusplus0 + MWFrontEnd_C_checkprotos0 + MWFrontEnd_C_arm0 + MWFrontEnd_C_trigraphs0 + MWFrontEnd_C_onlystdkeywords0 + MWFrontEnd_C_enumsalwaysint0 + MWFrontEnd_C_mpwpointerstyle1 + MWFrontEnd_C_prefixnamecmdline-defs-cw5.h + MWFrontEnd_C_ansistrict0 + MWFrontEnd_C_mpwcnewline0 + MWFrontEnd_C_wchar_type0 + MWFrontEnd_C_enableexceptions0 + MWFrontEnd_C_dontreusestrings0 + MWFrontEnd_C_poolstrings0 + MWFrontEnd_C_dontinline0 + MWFrontEnd_C_useRTTI0 + MWFrontEnd_C_multibyteaware0 + MWFrontEnd_C_unsignedchars0 + MWFrontEnd_C_autoinline0 + MWFrontEnd_C_booltruefalse0 + MWFrontEnd_C_direct_to_som0 + MWFrontEnd_C_som_env_check0 + MWFrontEnd_C_alwaysinline0 + MWFrontEnd_C_inlinelevel0 + MWFrontEnd_C_ecplusplus0 + MWFrontEnd_C_objective_c0 + MWFrontEnd_C_defer_codegen0 + + + MWWarning_C_warn_illpragma1 + MWWarning_C_warn_emptydecl1 + MWWarning_C_warn_possunwant1 + MWWarning_C_warn_unusedvar0 + MWWarning_C_warn_unusedarg0 + MWWarning_C_warn_extracomma1 + MWWarning_C_pedantic1 + MWWarning_C_warningerrors0 + MWWarning_C_warn_hidevirtual1 + MWWarning_C_warn_implicitconv0 + MWWarning_C_warn_notinlined0 + MWWarning_C_warn_structclass0 + + + MWCFM68K_exportsNone + MWCFM68K_olddefversion0 + MWCFM68K_oldimpversion0 + MWCFM68K_currentversion0 + MWCFM68K_farthreshold256 + PCFM68K_sharedata0 + MWCFM68K_fragmentname + MWCFM68K_initname + MWCFM68K_mainname__start + MWCFM68K_termname + MWCFM68K_libfolder0 + MWCFM68K_alignmentAlign_2 + + + MWMerge_MacOS_projectTypeApplication + MWMerge_MacOS_outputNameMerge Out + MWMerge_MacOS_outputCreator1061109567 + MWMerge_MacOS_outputType1095782476 + MWMerge_MacOS_suppressWarning0 + MWMerge_MacOS_copyFragments1 + MWMerge_MacOS_copyResources1 + MWMerge_MacOS_skipResources + + ª^ + à8 + ¢ê + + + + MWCodeGen_PPC_structalignmentPPC + MWCodeGen_PPC_tracebacktablesInline + MWCodeGen_PPC_processorGeneric + MWCodeGen_PPC_readonlystrings0 + MWCodeGen_PPC_tocdata1 + MWCodeGen_PPC_profiler0 + MWCodeGen_PPC_fpcontract1 + MWCodeGen_PPC_schedule0 + MWCodeGen_PPC_peephole0 + MWCodeGen_PPC_processorspecific0 + MWCodeGen_PPC_altivec0 + MWCodeGen_PPC_vectortocdata0 + MWCodeGen_PPC_vrsave0 + + + MWDisassembler_PPC_showcode1 + MWDisassembler_PPC_extended1 + MWDisassembler_PPC_mix0 + MWDisassembler_PPC_nohex0 + MWDisassembler_PPC_showdata1 + MWDisassembler_PPC_showexceptions1 + MWDisassembler_PPC_showsym0 + MWDisassembler_PPC_shownames1 + + + GlobalOptimizer_PPC_optimizationlevelLevel0 + GlobalOptimizer_PPC_optforSpeed + + + MWLinker_PPC_linksym1 + MWLinker_PPC_symfullpath1 + MWLinker_PPC_linkmap1 + MWLinker_PPC_nolinkwarnings0 + MWLinker_PPC_dontdeadstripinitcode0 + MWLinker_PPC_permitmultdefs0 + MWLinker_PPC_linkmodeFast + MWLinker_PPC_initname + MWLinker_PPC_mainname__start + MWLinker_PPC_termname + + + MWPEF_exportsNone + MWPEF_libfolder0 + MWPEF_sortcodeNone + MWPEF_expandbss0 + MWPEF_sharedata0 + MWPEF_olddefversion0 + MWPEF_oldimpversion0 + MWPEF_currentversion0 + MWPEF_fragmentname + MWPEF_collapsereloads0 + + + MWProject_PPC_typeApplication + MWProject_PPC_outfileEmacs CW + MWProject_PPC_filecreator1162690936 + MWProject_PPC_filetype1095782476 + MWProject_PPC_size16384 + MWProject_PPC_minsize16384 + MWProject_PPC_stacksize512 + MWProject_PPC_flags22752 + MWProject_PPC_symfilename + MWProject_PPC_rsrcname + MWProject_PPC_rsrcheaderNative + MWProject_PPC_rsrctype1061109567 + MWProject_PPC_rsrcid0 + MWProject_PPC_rsrcflags0 + MWProject_PPC_rsrcstore0 + MWProject_PPC_rsrcmerge0 + + + MWAssembler_PPC_auxheader0 + MWAssembler_PPC_symmodeMac + MWAssembler_PPC_dialectPPC + MWAssembler_PPC_prefixfile + MWAssembler_PPC_typecheck0 + MWAssembler_PPC_warnings0 + MWAssembler_PPC_casesensitive0 + + + MWRez_Language_maxwidth80 + MWRez_Language_scriptRoman + MWRez_Language_alignmentAlign1 + MWRez_Language_filtermodeFilterSkip + MWRez_Language_suppresswarnings0 + MWRez_Language_escapecontrolchars1 + MWRez_Language_prefixname + MWRez_Language_filteredtypes'CODE' 'DATA' 'PICT' + + + + Name + InterfaceLib + MacOS + Library + + + + Name + MathLib + MacOS + Library + + + + Name + MSL RuntimePPC.Lib + MacOS + Library + + + + Name + emacs.c + MacOS + Text + Debug + + + Name + process.c + MacOS + Text + Debug + + + Name + floatfns.c + MacOS + Text + Debug + + + Name + editfns.c + MacOS + Text + Debug + + + Name + macros.c + MacOS + Text + Debug + + + Name + xdisp.c + MacOS + Text + Debug + + + Name + window.c + MacOS + Text + Debug + + + Name + minibuf.c + MacOS + Text + Debug + + + Name + keymap.c + MacOS + Text + Debug + + + Name + buffer.c + MacOS + Text + Debug + + + Name + cmds.c + MacOS + Text + Debug + + + Name + casefiddle.c + MacOS + Text + Debug + + + Name + textprop.c + MacOS + Text + Debug + + + Name + undo.c + MacOS + Text + Debug + + + Name + syntax.c + MacOS + Text + Debug + + + Name + search.c + MacOS + Text + Debug + + + Name + mocklisp.c + MacOS + Text + Debug + + + Name + marker.c + MacOS + Text + Debug + + + Name + insdel.c + MacOS + Text + Debug + + + Name + indent.c + MacOS + Text + Debug + + + Name + coding.c + MacOS + Text + Debug + + + Name + fileio.c + MacOS + Text + Debug + + + Name + alloc.c + MacOS + Text + Debug + + + Name + fns.c + MacOS + Text + Debug + + + Name + eval.c + MacOS + Text + Debug + + + Name + doc.c + MacOS + Text + Debug + + + Name + dired.c + MacOS + Text + Debug + + + Name + charset.c + MacOS + Text + Debug + + + Name + ccl.c + MacOS + Text + Debug + + + Name + category.c + MacOS + Text + Debug + + + Name + callproc.c + MacOS + Text + Debug + + + Name + casetab.c + MacOS + Text + Debug + + + Name + callint.c + MacOS + Text + Debug + + + Name + bytecode.c + MacOS + Text + Debug + + + Name + abbrev.c + MacOS + Text + Debug + + + Name + print.c + MacOS + Text + Debug + + + Name + data.c + MacOS + Text + Debug + + + Name + intervals.c + MacOS + Text + Debug + + + Name + regex.c + MacOS + Text + Debug + + + Name + mktime.c + MacOS + Text + Debug + + + Name + filemode.c + MacOS + Text + Debug + + + Name + getloadavg.c + MacOS + Text + Debug + + + Name + scroll.c + MacOS + Text + Debug + + + Name + region-cache.c + MacOS + Text + Debug + + + Name + doprnt.c + MacOS + Text + Debug + + + Name + cm.c + MacOS + Text + Debug + + + Name + termcap.c + MacOS + Text + Debug + + + Name + tparam.c + MacOS + Text + Debug + + + Name + sysdep.c + MacOS + Text + Debug + + + Name + lread.c + MacOS + Text + Debug + + + Name + frame.c + MacOS + Text + Debug + + + Name + term.c + MacOS + Text + Debug + + + Name + keyboard.c + MacOS + Text + Debug + + + Name + fontset.c + MacOS + Text + Debug + + + Name + dispnew.c + MacOS + Text + Debug + + + Name + Emacs.r + MacOS + Text + Debug + + + Name + AppleScriptLib + MacOS + Library + Debug + + + Name + strftime.c + MacOS + Text + Debug + + + Name + TextEncodingConverter + MacOS + Library + Debug + + + Name + xfaces.c + MacOS + Text + Debug + + + Name + macfns.c + MacOS + Text + Debug + + + Name + macterm.c + MacOS + Text + Debug + + + Name + composite.c + MacOS + Text + Debug + + + Name + atimer.c + MacOS + Text + Debug + + + Name + mac.c + MacOS + Text + Debug + + + Name + alloca.c + MacOS + Text + Debug + + + Name + MSL C.PPC.Lib + MacOS + Library + Debug + + + Name + MSL SIOUX.PPC.Lib + MacOS + Library + Debug + + + Name + macmenu.c + MacOS + Text + Debug + + + Name + AppearanceLib + MacOS + Library + Debug + + + + + Name + abbrev.c + MacOS + + + Name + alloc.c + MacOS + + + Name + alloca.c + MacOS + + + Name + atimer.c + MacOS + + + Name + buffer.c + MacOS + + + Name + bytecode.c + MacOS + + + Name + callint.c + MacOS + + + Name + callproc.c + MacOS + + + Name + casefiddle.c + MacOS + + + Name + casetab.c + MacOS + + + Name + category.c + MacOS + + + Name + ccl.c + MacOS + + + Name + charset.c + MacOS + + + Name + cm.c + MacOS + + + Name + cmds.c + MacOS + + + Name + coding.c + MacOS + + + Name + composite.c + MacOS + + + Name + data.c + MacOS + + + Name + dired.c + MacOS + + + Name + dispnew.c + MacOS + + + Name + doc.c + MacOS + + + Name + doprnt.c + MacOS + + + Name + editfns.c + MacOS + + + Name + emacs.c + MacOS + + + Name + eval.c + MacOS + + + Name + fileio.c + MacOS + + + Name + filemode.c + MacOS + + + Name + floatfns.c + MacOS + + + Name + fns.c + MacOS + + + Name + fontset.c + MacOS + + + Name + frame.c + MacOS + + + Name + getloadavg.c + MacOS + + + Name + indent.c + MacOS + + + Name + insdel.c + MacOS + + + Name + intervals.c + MacOS + + + Name + keyboard.c + MacOS + + + Name + keymap.c + MacOS + + + Name + lread.c + MacOS + + + Name + macros.c + MacOS + + + Name + marker.c + MacOS + + + Name + minibuf.c + MacOS + + + Name + mktime.c + MacOS + + + Name + mocklisp.c + MacOS + + + Name + print.c + MacOS + + + Name + process.c + MacOS + + + Name + regex.c + MacOS + + + Name + region-cache.c + MacOS + + + Name + scroll.c + MacOS + + + Name + search.c + MacOS + + + Name + strftime.c + MacOS + + + Name + syntax.c + MacOS + + + Name + term.c + MacOS + + + Name + termcap.c + MacOS + + + Name + textprop.c + MacOS + + + Name + tparam.c + MacOS + + + Name + undo.c + MacOS + + + Name + window.c + MacOS + + + Name + xdisp.c + MacOS + + + Name + sysdep.c + MacOS + + + Name + xfaces.c + MacOS + + + Name + mac.c + MacOS + + + Name + macfns.c + MacOS + + + Name + macmenu.c + MacOS + + + Name + macterm.c + MacOS + + + Name + MSL RuntimePPC.Lib + MacOS + + + Name + InterfaceLib + MacOS + + + Name + MathLib + MacOS + + + Name + AppleScriptLib + MacOS + + + Name + TextEncodingConverter + MacOS + + + Name + MSL C.PPC.Lib + MacOS + + + Name + MSL SIOUX.PPC.Lib + MacOS + + + Name + AppearanceLib + MacOS + + + Name + Emacs.r + MacOS + + + + + + + Emacs + + + + Emacs Source + + Emacs + Name + abbrev.c + MacOS + + + Emacs + Name + alloc.c + MacOS + + + Emacs + Name + alloca.c + MacOS + + + Emacs + Name + atimer.c + MacOS + + + Emacs + Name + buffer.c + MacOS + + + Emacs + Name + bytecode.c + MacOS + + + Emacs + Name + callint.c + MacOS + + + Emacs + Name + callproc.c + MacOS + + + Emacs + Name + casefiddle.c + MacOS + + + Emacs + Name + casetab.c + MacOS + + + Emacs + Name + category.c + MacOS + + + Emacs + Name + ccl.c + MacOS + + + Emacs + Name + charset.c + MacOS + + + Emacs + Name + cm.c + MacOS + + + Emacs + Name + cmds.c + MacOS + + + Emacs + Name + coding.c + MacOS + + + Emacs + Name + composite.c + MacOS + + + Emacs + Name + data.c + MacOS + + + Emacs + Name + dired.c + MacOS + + + Emacs + Name + dispnew.c + MacOS + + + Emacs + Name + doc.c + MacOS + + + Emacs + Name + doprnt.c + MacOS + + + Emacs + Name + editfns.c + MacOS + + + Emacs + Name + emacs.c + MacOS + + + Emacs + Name + eval.c + MacOS + + + Emacs + Name + fileio.c + MacOS + + + Emacs + Name + filemode.c + MacOS + + + Emacs + Name + floatfns.c + MacOS + + + Emacs + Name + fns.c + MacOS + + + Emacs + Name + fontset.c + MacOS + + + Emacs + Name + frame.c + MacOS + + + Emacs + Name + getloadavg.c + MacOS + + + Emacs + Name + indent.c + MacOS + + + Emacs + Name + insdel.c + MacOS + + + Emacs + Name + intervals.c + MacOS + + + Emacs + Name + keyboard.c + MacOS + + + Emacs + Name + keymap.c + MacOS + + + Emacs + Name + lread.c + MacOS + + + Emacs + Name + macros.c + MacOS + + + Emacs + Name + marker.c + MacOS + + + Emacs + Name + minibuf.c + MacOS + + + Emacs + Name + mktime.c + MacOS + + + Emacs + Name + mocklisp.c + MacOS + + + Emacs + Name + print.c + MacOS + + + Emacs + Name + process.c + MacOS + + + Emacs + Name + regex.c + MacOS + + + Emacs + Name + region-cache.c + MacOS + + + Emacs + Name + scroll.c + MacOS + + + Emacs + Name + search.c + MacOS + + + Emacs + Name + strftime.c + MacOS + + + Emacs + Name + syntax.c + MacOS + + + Emacs + Name + sysdep.c + MacOS + + + Emacs + Name + term.c + MacOS + + + Emacs + Name + termcap.c + MacOS + + + Emacs + Name + textprop.c + MacOS + + + Emacs + Name + tparam.c + MacOS + + + Emacs + Name + undo.c + MacOS + + + Emacs + Name + window.c + MacOS + + + Emacs + Name + xdisp.c + MacOS + + + Emacs + Name + xfaces.c + MacOS + + + Mac Source + + Emacs + Name + mac.c + MacOS + + + Emacs + Name + macfns.c + MacOS + + + Emacs + Name + macmenu.c + MacOS + + + Emacs + Name + macterm.c + MacOS + + + Resources + + Emacs + Name + Emacs.r + MacOS + + + Mac Libraries + + Emacs + Name + MSL RuntimePPC.Lib + MacOS + + + Emacs + Name + InterfaceLib + MacOS + + + Emacs + Name + MathLib + MacOS + + + Emacs + Name + AppleScriptLib + MacOS + + + Emacs + Name + TextEncodingConverter + MacOS + + + Emacs + Name + AppearanceLib + MacOS + + + ANSI Libraries + + Emacs + Name + MSL C.PPC.Lib + MacOS + + + Emacs + Name + MSL SIOUX.PPC.Lib + MacOS + + + + + diff --git a/mac/emacs-cw6.mcp.xml b/mac/emacs-cw6.mcp.xml new file mode 100644 index 00000000000..ff54af2bbc1 --- /dev/null +++ b/mac/emacs-cw6.mcp.xml @@ -0,0 +1,2309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + + Emacs + + + + UserSourceTrees + + + AlwaysSearchUserPathstrue + InterpretDOSAndUnixPathstrue + UserSearchPaths + + SearchPath + Path:inc: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SearchPath + Path:src: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SearchPath + Path::src: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SystemSearchPaths + + SearchPath + Path:inc: + PathFormatMacOS + PathRootProject + + Recursivetrue + HostFlagsAll + + + SearchPath + Path: + PathFormatMacOS + PathRootCodeWarrior + + Recursivetrue + HostFlagsAll + + + + + MWRuntimeSettings_WorkingDirectory + MWRuntimeSettings_CommandLine + MWRuntimeSettings_HostApplication + Path + PathFormatMacOS + PathRootAbsolute + + MWRuntimeSettings_EnvVars + + + LinkerMacOS PPC Linker + PreLinker + PostLinker + TargetnameEmacs + OutputDirectory + Path: + PathFormatMacOS + PathRootProject + + SaveEntriesUsingRelativePathsfalse + + + FileMappings + + FileTypeAPPL + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeAppl + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeMMLB + FileExtension + CompilerLib Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeMPLF + FileExtension + CompilerLib Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeMWCD + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeRSRC + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.bh + CompilerBalloon Help + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.c + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.c++ + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cc + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cp + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.cpp + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.exp + Compiler + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.gc + CompilerGameCode Converter + Precompilefalse + Launchabletrue + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.h + CompilerMW C/C++ PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMaketrue + + + FileTypeTEXT + FileExtension.l + CompilerFlex Preprocessor + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.p + CompilerMW Pascal PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pas + CompilerMW Pascal PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pch + CompilerMW C/C++ PPC + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.pch++ + CompilerMW C/C++ PPC + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.ppu + CompilerMW Pascal PPC + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.r + CompilerRez + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.s + CompilerPPCAsm + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeTEXT + FileExtension.y + CompilerBison Preprocessor + Precompiletrue + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypeXCOF + FileExtension + CompilerXCOFF Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypedocu + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypersrc + FileExtension + Compiler + Precompilefalse + Launchabletrue + ResourceFiletrue + IgnoredByMakefalse + + + FileTypeshlb + FileExtension + CompilerPEF Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileTypestub + FileExtension + CompilerPEF Import PPC + Precompilefalse + Launchablefalse + ResourceFilefalse + IgnoredByMakefalse + + + FileExtension.doc + Compiler + Precompilefalse + Launchabletrue + ResourceFilefalse + IgnoredByMaketrue + + + + + CacheModDatestrue + ActivateBrowsertrue + DumpBrowserInfofalse + CacheSubprojectstrue + UseThirdPartyDebuggerfalse + DebuggerCommandLine + + + LogSystemMessagesfalse + AutoTargetDLLsfalse + StopAtWatchpointstrue + PauseWhileRunningfalse + PauseInterval5 + PauseUIFlags0 + AltExePath + Path + PathFormatGeneric + PathRootAbsolute + + StopAtTempBPOnLaunchtrue + CacheSymbolicstrue + TempBPFunctionNamemain + TempBPTypefalse + Remote Debug + 00030000000000000000000006B1783006B29470000000000000030007609AE0 + 00000000000000000000000006B17830000000002E646F630000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000050000000000000002E6C6962 + 000000000000000000000000000000000000000000000000000000004C696220 + 496D706F72742078383600000000000000000000000000000000000000000000 + 000000002E6F0000000000000000000000000000000000000000000000000000 + 000000004F626A20496D706F7274207838360000000000000000000000000000 + 0000000000000000000000002E6F626A00000000000000000000000000000000 + 0000000000000000000000004F626A20496D706F727420783836000000000000 + 00000000000000000000000000000000000000002E7265730000000000000000 + 000000000000000000000000000000000000000057696E52657320496D706F72 + 7400000000000000000000000000000000000000000000000000000000000000 + 06B290200000000000ACF2E007609AE000000000000000000000000006B17830 + 000000000000544558542E637000000000000000000000000000000000000000 + 000000000000000000004D5720432F432B2B2050504300000000000000000000 + 0000000000000000000000000000544558542E63707000000000000000000000 + 0000000000000000000000000000000000004D5720432F432B2B205050430000 + 00000000000000000000000000000000000000000000544558542E6578700000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000005445 + 58542E6763000000000000000000000000000000000000000000000000000000 + 000047616D65436F646520436F6E766572746572000000000000000000000000 + 000040000000544558542E680000000000000000000000000000000000000000 + 000000000000 + + Auto-target + 00010000 + + + + CustomColor1 + Red6168 + Green24672 + Blue23130 + + CustomColor2 + Red0 + Green32767 + Blue0 + + CustomColor3 + Red0 + Green32767 + Blue0 + + CustomColor4 + Red0 + Green32767 + Blue0 + + + + MWCodeGen_68K_codesizeSmart + MWCodeGen_68K_structalignmentMC68K + MWCodeGen_68K_fp_modeSANE + MWCodeGen_68K_code680200 + MWCodeGen_68K_profiler0 + MWCodeGen_68K_mpwc0 + MWCodeGen_68K_fourbyteints1 + MWCodeGen_68K_IEEEdoubles1 + MWCodeGen_68K_fardata1 + MWCodeGen_68K_farvtables1 + MWCodeGen_68K_farstrings1 + MWCodeGen_68K_pcrelstrings0 + MWCodeGen_68K_macsbugNew + MWCodeGen_68K_a6frames1 + + + MWDisassembler_68K_showcode1 + MWDisassembler_68K_mix0 + MWDisassembler_68K_nohex0 + MWDisassembler_68K_showdata1 + MWDisassembler_68K_showexceptions1 + MWDisassembler_68K_showsym0 + MWDisassembler_68K_shownames1 + + + GlobalOptimizer_68K_optimizationlevelLevel0 + GlobalOptimizer_68K_optforSpeed + + + MWLinker_68K_linksym1 + MWLinker_68K_symfullpath1 + MWLinker_68K_linksingle0 + MWLinker_68K_fastlink1 + MWLinker_68K_generateMap0 + MWLinker_68K_nolinkwarnings0 + MWLinker_68K_glueintosegone1 + MWLinker_68K_dontdeadstripinitcode0 + + + MWProject_68K_typeApplication + MWProject_68K_outfileMacOS Toolbox DEBUG 68K + MWProject_68K_symfilename + MWProject_68K_filecreator1061109567 + MWProject_68K_filetype1095782476 + MWProject_68K_size384 + MWProject_68K_flags22720 + MWProject_68K_rsrcheaderStandard + MWProject_68K_rsrcname + MWProject_68K_rsrctype1061109567 + MWProject_68K_rsrcid0 + MWProject_68K_rsrcmulti0 + MWProject_68K_rsrcstore0 + MWProject_68K_rsrcmerge0 + MWProject_68K_rsrcflags0 + MWProject_68K_a40 + MWProject_68K_minsize384 + MWProject_68K_rsrcsegtype0 + MWProject_68K_cfm68kcodegen0 + MWProject_68K_stacksize0 + MWProject_68K_thedebugger0 + MWProject_68K_rsrc_custom0 + MWProject_68K_is_rseg_app0 + MWProject_68K_is_pilot_lib0 + MWProject_68K_pilot_main_entry + + + MWFrontEnd_C_cplusplus0 + MWFrontEnd_C_checkprotos0 + MWFrontEnd_C_arm0 + MWFrontEnd_C_trigraphs0 + MWFrontEnd_C_onlystdkeywords0 + MWFrontEnd_C_enumsalwaysint0 + MWFrontEnd_C_mpwpointerstyle1 + MWFrontEnd_C_prefixnamecmdline-defs-cw6.h + MWFrontEnd_C_ansistrict0 + MWFrontEnd_C_mpwcnewline0 + MWFrontEnd_C_wchar_type0 + MWFrontEnd_C_enableexceptions0 + MWFrontEnd_C_dontreusestrings0 + MWFrontEnd_C_poolstrings0 + MWFrontEnd_C_dontinline0 + MWFrontEnd_C_useRTTI0 + MWFrontEnd_C_multibyteaware0 + MWFrontEnd_C_unsignedchars0 + MWFrontEnd_C_autoinline0 + MWFrontEnd_C_booltruefalse0 + MWFrontEnd_C_direct_to_som0 + MWFrontEnd_C_som_env_check0 + MWFrontEnd_C_alwaysinline0 + MWFrontEnd_C_inlinelevel0 + MWFrontEnd_C_ecplusplus0 + MWFrontEnd_C_objective_c0 + MWFrontEnd_C_defer_codegen0 + + + MWWarning_C_warn_illpragma1 + MWWarning_C_warn_emptydecl1 + MWWarning_C_warn_possunwant1 + MWWarning_C_warn_unusedvar0 + MWWarning_C_warn_unusedarg0 + MWWarning_C_warn_extracomma1 + MWWarning_C_pedantic1 + MWWarning_C_warningerrors0 + MWWarning_C_warn_hidevirtual1 + MWWarning_C_warn_implicitconv0 + MWWarning_C_warn_notinlined0 + MWWarning_C_warn_structclass0 + + + MWCFM68K_exportsNone + MWCFM68K_olddefversion0 + MWCFM68K_oldimpversion0 + MWCFM68K_currentversion0 + MWCFM68K_farthreshold256 + PCFM68K_sharedata0 + MWCFM68K_fragmentname + MWCFM68K_initname + MWCFM68K_mainname__start + MWCFM68K_termname + MWCFM68K_libfolder0 + MWCFM68K_alignmentAlign_2 + + + MWFTP_Post_hostName + MWFTP_Post_username + MWFTP_Post_password854um6254wjei54ctb6054ctb6054cjfi55gdei + MWFTP_Post_remoteDir + MWFTP_Post_ftp_PathVersion0 + MWFTP_Post_ftp_PathType0 + MWFTP_Post_ftp_PathFormat0 + MWFTP_Post_ftp_tree + MWFTP_Post_uploadDir + MWFTP_Post_ftp_port21 + MWFTP_Post_SendBin1 + MWFTP_Post_ShouldLog1 + + + MWCommandLine_Java_clsName + MWCommandLine_Java_args + + + MWJava_Language_optimizefalse + MWJava_Language_warnDeprecatedfalse + MWJava_Language_emitMapfalse + MWJava_Language_strictFileNamesfalse + MWJava_Language_strictFileHierarchyfalse + MWJava_Language_1_1_Compatiblefalse + MWJava_Language_emitHeaders0 + MWJava_Language_headerTypeJNINativeHeaders + MWJava_Language_packageFilter + MWJava_Language_genCommentstrue + MWJava_Language_genHeadersfalse + + + MWJava_MRJAppBuilder_outFileMRJApplication + MWJava_MRJAppBuilder_mergefalse + MWJava_MRJAppBuilder_quitMenutrue + MWJava_MRJAppBuilder_growfalse + MWJava_MRJAppBuilder_stdoutTypeConsole + MWJava_MRJAppBuilder_stderrTypeConsole + MWJava_MRJAppBuilder_stdinTypeConsole + MWJava_MRJAppBuilder_appIconPVersion0 + MWJava_MRJAppBuilder_appIconPType0 + MWJava_MRJAppBuilder_appIconPFormat0 + MWJava_MRJAppBuilder_appIconPTree + MWJava_MRJAppBuilder_appIconFile + MWJava_MRJAppBuilder_splashScreenPVersion0 + MWJava_MRJAppBuilder_splashScreenPType0 + MWJava_MRJAppBuilder_splashScreenPFormat0 + MWJava_MRJAppBuilder_splashScreenPTree + MWJava_MRJAppBuilder_splashScreenPICTFile + MWJava_MRJAppBuilder_aboutName + MWJava_MRJAppBuilder_stdoutPVersion0 + MWJava_MRJAppBuilder_stdoutPType0 + MWJava_MRJAppBuilder_stdoutPFormat0 + MWJava_MRJAppBuilder_stdoutPTree + MWJava_MRJAppBuilder_stdoutFile + MWJava_MRJAppBuilder_stdoutAppendfalse + MWJava_MRJAppBuilder_stderrPType0 + MWJava_MRJAppBuilder_stderrPFormat0 + MWJava_MRJAppBuilder_stderrPTree + MWJava_MRJAppBuilder_stderrFile + MWJava_MRJAppBuilder_stderrAppendfalse + MWJava_MRJAppBuilder_stdinPType0 + MWJava_MRJAppBuilder_stdinPFormat0 + MWJava_MRJAppBuilder_stdinPTree + MWJava_MRJAppBuilder_stdinFile + + + MWJava_Output_outputtypeJarFile + MWJava_Output_outfileJavaClasses.jar + MWJava_Output_ftype1514754080 + MWJava_Output_fcreator1297570384 + MWJava_Output_compress0 + MWJava_Output_genManifest0 + MWJava_Output_trunctypeFront + MWJava_Output_deleteClasses0 + MWJava_Output_consoleApp1 + + + MWJava_Proj_projtypeApplet + MWJava_Proj_mainClassName + MWJava_Proj_HTMLAppCreator1463898714 + MWJava_Proj_HTMLAppName + MWJava_Proj_PathVersion0 + MWJava_Proj_PathType0 + MWJava_Proj_PathFormat0 + MWJava_Proj_tree + MWJava_Proj_HTMLAppWin32Name + MWJava_Proj_compress0 + MWJava_Proj_useVM1 + MWJava_Proj_vmarguments + MWJava_Proj_vmName + + + MWJavaDoc_Proj_Version1 + MWJavaDoc_Proj_Depricated1 + MWJavaDoc_Proj_Author1 + MWJavaDoc_Proj_Index1 + MWJavaDoc_Proj_Tree1 + MWJavaDoc_Proj_SunResolveToSame0 + MWJavaDoc_Proj_Shortnames1 + MWJavaDoc_Proj_Folder0 + MWJavaDoc_Proj_GenerateAPILinks0 + MWJavaDoc_Proj_scopePublic + MWJavaDoc_Proj_fcreator1297303877 + MWJavaDoc_Proj_encodingName + MWJavaDoc_Proj_decodingName + MWJavaDoc_Proj_javaPackagePathhttp://java.sun.com/products/jdk/1.1/docs/api/ + + + MWMerge_MacOS_projectTypeApplication + MWMerge_MacOS_outputNameMerge Out + MWMerge_MacOS_outputCreator1061109567 + MWMerge_MacOS_outputType1095782476 + MWMerge_MacOS_suppressWarning0 + MWMerge_MacOS_copyFragments1 + MWMerge_MacOS_copyResources1 + MWMerge_MacOS_skipResources + + ¼_À + ˆx + ¡À + + + + FileLockedfalse + ResourcesMapIsReadOnlyfalse + PrinterDriverIsMultiFinderCompatiblefalse + Invisiblefalse + HasBundlefalse + NameLockedfalse + Stationeryfalse + HasCustomIconfalse + Sharedfalse + HasBeenInitedfalse + Label0 + Comments + Packager Panel + 000100003F3F3F3F4150504C06B2000100B2D900000000000000061007609AE0 + 2020202020202020203C504106B2D310524D41543E4D61634F533C2F50415448 + 464F524D41543E0D202020202020202020202020202020203C2F46494C455245 + 463E0D202020202020202020202020202020203C46494C455245463E0D202020 + 20202020202020202020202020202020203C50415448545950453E4E616D653C + 2F50415448545950453E0D20202020202020202020202020202020202020203C + 504154483E666E732E633C2F504154483E0D2020202020202020202020202020 + 2020202020203C50415448464F524D41543E4D61634F533C2F50415448464F52 + 4D41543E0D202020202020202020202000202020203C2F46494C455245463E0D + 202020202020202020202020202020203C46494C455245463E0D202020202020 + 20202020202020202020202020203C50415448545950453E4E616D653C2F5041 + 5448545950453E0D20202020202020202020202020202020202020203C504154 + 483E666F6E747365742E633C2F504154483E0D20202020202020202020202020 + 202020202020203C50415448464F524D41543E4D61634F533C2F50415448464F + 524D41543E0D202020202020202020202020202020203C2F46494C455245463E + 0D202020202020202020202020202020203C46494C455245463E0D2020202020 + 2020202020202020202020202020203C50415448545950453E4E616D653C2F50 + 415448545950453E0D20202020202020202020202020202020202020203C5041 + 54483E6672616D652E633C2F504154483E0D2020202020202020202020202020 + 2020202020203C50415448464F524D41543E4D61634F533C2F50415448464F52 + 4D41543E0D202020202020202020202020202020203C2F46494C455245463E0D + 202020202020202020202020202020203C46494C455245463E0D202020202020 + 20202020202020202020202020203C50415448545950453E4E616D653C2F5041 + 5448545950453E0D20202020202020202020202020202020202020203C504154 + 483E6765746C6F61646176672E633C2F50410001000D20202020202020202020 + 202020202020202020203C50415448464F524D41543E4D61634F533C2F504154 + 48464F524D41543E0D202020202020202020202020202020203C2F46494C4552 + 45463E0D202020202020202020202020202020203C46494C455245463E0D2020 + 2020202020202020202020202020202020203C50415448545950453E4E616D65 + 3C2F50415448545950453E0D2020202020202020202020202020202020202020 + 3C504154483E696E64656E742E633C2F504154483E0D20202020202020202020 + 202020202020202020203C50415448464F524D41543E4D61634F533C2F504154 + 48464F524D41543E0D202020202020202020202000202020203C2F46494C4552 + 45463E0D202020202020202020202020202020203C46494C455245463E0D2020 + 2020202020202020202020202020202020203C50415448545950453E4E616D65 + 3C2F50415448545950453E0D2020202020202020202020202020202020202020 + 3C504154483E696E7364656C2E633C2F504154483E0D20202020202020202020 + 202020202020202020203C50415448464F524D41543E4D61634F533C2F504154 + 48464F524D41543E0D202020202020202020202020202020203C2F46494C4552 + 45463E0D202020202020202020202020202020203C46494C455245463E0D2020 + 2020202020202020202020202020202020203C50415448545950453E4E616D65 + 3C2F50415448545950453E0D2020202020202020202020202020202020202020 + 3C504154483E696E74657276616C732E633C2F504154483E0D20202020202020 + 202020202020202020202020203C50415448464F524D41543E4D61634F533C2F + 50415448464F524D41543E0D202020202020202020202020202020203C2F4649 + 4C455245463E0D202020202020202020202020202020203C46494C455245463E + 0D20202020202020202020202020202020202020203C50415448545950453E4E + 616D653C2F50415448545950453E0D2020202020202020202020202020202020 + 2020203C504154483E6B6579626F6172642E633C + + + + MWCodeGen_PPC_structalignmentPPC + MWCodeGen_PPC_tracebacktablesInline + MWCodeGen_PPC_processorGeneric + MWCodeGen_PPC_readonlystrings0 + MWCodeGen_PPC_tocdata1 + MWCodeGen_PPC_profiler0 + MWCodeGen_PPC_fpcontract1 + MWCodeGen_PPC_schedule0 + MWCodeGen_PPC_peephole0 + MWCodeGen_PPC_processorspecific0 + MWCodeGen_PPC_altivec0 + MWCodeGen_PPC_vectortocdata0 + MWCodeGen_PPC_vrsave0 + + + MWDisassembler_PPC_showcode1 + MWDisassembler_PPC_extended1 + MWDisassembler_PPC_mix0 + MWDisassembler_PPC_nohex0 + MWDisassembler_PPC_showdata1 + MWDisassembler_PPC_showexceptions1 + MWDisassembler_PPC_showsym0 + MWDisassembler_PPC_shownames1 + + + GlobalOptimizer_PPC_optimizationlevelLevel0 + GlobalOptimizer_PPC_optforSpeed + + + MWLinker_PPC_linksym1 + MWLinker_PPC_symfullpath1 + MWLinker_PPC_linkmap1 + MWLinker_PPC_nolinkwarnings0 + MWLinker_PPC_dontdeadstripinitcode0 + MWLinker_PPC_permitmultdefs0 + MWLinker_PPC_linkmodeFast + MWLinker_PPC_initname + MWLinker_PPC_mainname__start + MWLinker_PPC_termname + + + MWPEF_exportsNone + MWPEF_libfolder0 + MWPEF_sortcodeNone + MWPEF_expandbss0 + MWPEF_sharedata0 + MWPEF_olddefversion0 + MWPEF_oldimpversion0 + MWPEF_currentversion0 + MWPEF_fragmentname + MWPEF_collapsereloads0 + + + MWProject_PPC_typeApplication + MWProject_PPC_outfileEmacs CW + MWProject_PPC_filecreator1162690936 + MWProject_PPC_filetype1095782476 + MWProject_PPC_size16384 + MWProject_PPC_minsize16384 + MWProject_PPC_stacksize512 + MWProject_PPC_flags22752 + MWProject_PPC_symfilename + MWProject_PPC_rsrcname + MWProject_PPC_rsrcheaderNative + MWProject_PPC_rsrctype1061109567 + MWProject_PPC_rsrcid0 + MWProject_PPC_rsrcflags0 + MWProject_PPC_rsrcstore0 + MWProject_PPC_rsrcmerge0 + + + MWAssembler_PPC_auxheader0 + MWAssembler_PPC_symmodeMac + MWAssembler_PPC_dialectPPC + MWAssembler_PPC_prefixfile + MWAssembler_PPC_typecheck0 + MWAssembler_PPC_warnings0 + MWAssembler_PPC_casesensitive0 + + + MWRez_Language_maxwidth80 + MWRez_Language_scriptRoman + MWRez_Language_alignmentAlign1 + MWRez_Language_filtermodeFilterSkip + MWRez_Language_suppresswarnings0 + MWRez_Language_escapecontrolchars1 + MWRez_Language_prefixname + MWRez_Language_filteredtypes'CODE' 'DATA' 'PICT' + + + MWWinRC_prefixname + + + MWCodeGen_X86_processorGeneric + MWCodeGen_X86_alignmentbytes8 + MWCodeGen_X86_exceptionsZeroOverhead + MWCodeGen_X86_extinst_mmx0 + MWCodeGen_X86_extinst_3dnow0 + MWCodeGen_X86_use_mmx_3dnow_convention0 + MWCodeGen_X86_machinecodelisting0 + MWCodeGen_X86_intrinsics0 + MWCodeGen_X86_syminfo0 + MWCodeGen_X86_codeviewinfo1 + MWCodeGen_X86_extinst_cmov_fcomi0 + MWCodeGen_X86_extinst_sse0 + + + PDisasmX86_showHeaderstrue + PDisasmX86_showSymTabtrue + PDisasmX86_showCodetrue + PDisasmX86_showSourcefalse + PDisasmX86_showHextrue + PDisasmX86_showRelocationtrue + PDisasmX86_showCommentsfalse + PDisasmX86_showDebugfalse + PDisasmX86_showExceptionsfalse + PDisasmX86_showDatatrue + PDisasmX86_showRawfalse + PDisasmX86_verbosetrue + + + MWDebugger_X86_Exceptions + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + GlobalOptimizer_X86_optimizationlevelLevel0 + GlobalOptimizer_X86_optforSpeed + + + MWLinker_X86_entrypointusageDefault + MWLinker_X86_entrypoint + MWLinker_X86_subsystemWinGUI + MWLinker_X86_subsysmajorid4 + MWLinker_X86_subsysminorid0 + MWLinker_X86_usrmajorid0 + MWLinker_X86_usrminorid0 + MWLinker_X86_commandfile + MWLinker_X86_generatemap0 + MWLinker_X86_linksym0 + MWLinker_X86_linkCV1 + + + MWProject_X86_typeApplication + MWProject_X86_outfilenoname.exe + MWProject_X86_baseaddress4194304 + MWProject_X86_maxstacksize1024 + MWProject_X86_minstacksize4 + MWProject_X86_size1024 + MWProject_X86_minsize4 + MWProject_X86_importlib + + + + Name + InterfaceLib + MacOS + Library + + + + Name + MathLib + MacOS + Library + + + + Name + emacs.c + MacOS + Text + Debug + + + Name + process.c + MacOS + Text + Debug + + + Name + floatfns.c + MacOS + Text + Debug + + + Name + editfns.c + MacOS + Text + Debug + + + Name + macros.c + MacOS + Text + Debug + + + Name + xdisp.c + MacOS + Text + Debug + + + Name + window.c + MacOS + Text + Debug + + + Name + minibuf.c + MacOS + Text + Debug + + + Name + keymap.c + MacOS + Text + Debug + + + Name + buffer.c + MacOS + Text + Debug + + + Name + cmds.c + MacOS + Text + Debug + + + Name + casefiddle.c + MacOS + Text + Debug + + + Name + textprop.c + MacOS + Text + Debug + + + Name + undo.c + MacOS + Text + Debug + + + Name + syntax.c + MacOS + Text + Debug + + + Name + search.c + MacOS + Text + Debug + + + Name + mocklisp.c + MacOS + Text + Debug + + + Name + marker.c + MacOS + Text + Debug + + + Name + insdel.c + MacOS + Text + Debug + + + Name + indent.c + MacOS + Text + Debug + + + Name + coding.c + MacOS + Text + Debug + + + Name + fileio.c + MacOS + Text + Debug + + + Name + alloc.c + MacOS + Text + Debug + + + Name + fns.c + MacOS + Text + Debug + + + Name + eval.c + MacOS + Text + Debug + + + Name + doc.c + MacOS + Text + Debug + + + Name + dired.c + MacOS + Text + Debug + + + Name + charset.c + MacOS + Text + Debug + + + Name + ccl.c + MacOS + Text + Debug + + + Name + category.c + MacOS + Text + Debug + + + Name + callproc.c + MacOS + Text + Debug + + + Name + casetab.c + MacOS + Text + Debug + + + Name + callint.c + MacOS + Text + Debug + + + Name + bytecode.c + MacOS + Text + Debug + + + Name + abbrev.c + MacOS + Text + Debug + + + Name + print.c + MacOS + Text + Debug + + + Name + data.c + MacOS + Text + Debug + + + Name + intervals.c + MacOS + Text + Debug + + + Name + regex.c + MacOS + Text + Debug + + + Name + mktime.c + MacOS + Text + Debug + + + Name + filemode.c + MacOS + Text + Debug + + + Name + getloadavg.c + MacOS + Text + Debug + + + Name + scroll.c + MacOS + Text + Debug + + + Name + region-cache.c + MacOS + Text + Debug + + + Name + doprnt.c + MacOS + Text + Debug + + + Name + cm.c + MacOS + Text + Debug + + + Name + termcap.c + MacOS + Text + Debug + + + Name + tparam.c + MacOS + Text + Debug + + + Name + sysdep.c + MacOS + Text + Debug + + + Name + lread.c + MacOS + Text + Debug + + + Name + frame.c + MacOS + Text + Debug + + + Name + term.c + MacOS + Text + Debug + + + Name + keyboard.c + MacOS + Text + Debug + + + Name + fontset.c + MacOS + Text + Debug + + + Name + dispnew.c + MacOS + Text + Debug + + + Name + Emacs.r + MacOS + Text + Debug + + + Name + AppleScriptLib + MacOS + Library + Debug + + + Name + strftime.c + MacOS + Text + Debug + + + Name + TextEncodingConverter + MacOS + Library + Debug + + + Name + xfaces.c + MacOS + Text + Debug + + + Name + macfns.c + MacOS + Text + Debug + + + Name + macterm.c + MacOS + Text + Debug + + + Name + composite.c + MacOS + Text + Debug + + + Name + atimer.c + MacOS + Text + Debug + + + Name + mac.c + MacOS + Text + Debug + + + Name + alloca.c + MacOS + Text + Debug + + + Name + macmenu.c + MacOS + Text + Debug + + + Name + AppearanceLib + MacOS + Library + Debug + + + Name + MSL C.PPC.Lib + MacOS + Library + Debug + + + Name + MSL SIOUX.PPC.Lib + MacOS + Library + Debug + + + Name + MSL RuntimePPC.Lib + MacOS + Library + Debug + + + + + Name + abbrev.c + MacOS + + + Name + alloc.c + MacOS + + + Name + alloca.c + MacOS + + + Name + atimer.c + MacOS + + + Name + buffer.c + MacOS + + + Name + bytecode.c + MacOS + + + Name + callint.c + MacOS + + + Name + callproc.c + MacOS + + + Name + casefiddle.c + MacOS + + + Name + casetab.c + MacOS + + + Name + category.c + MacOS + + + Name + ccl.c + MacOS + + + Name + charset.c + MacOS + + + Name + cm.c + MacOS + + + Name + cmds.c + MacOS + + + Name + coding.c + MacOS + + + Name + composite.c + MacOS + + + Name + data.c + MacOS + + + Name + dired.c + MacOS + + + Name + dispnew.c + MacOS + + + Name + doc.c + MacOS + + + Name + doprnt.c + MacOS + + + Name + editfns.c + MacOS + + + Name + emacs.c + MacOS + + + Name + eval.c + MacOS + + + Name + fileio.c + MacOS + + + Name + filemode.c + MacOS + + + Name + floatfns.c + MacOS + + + Name + fns.c + MacOS + + + Name + fontset.c + MacOS + + + Name + frame.c + MacOS + + + Name + getloadavg.c + MacOS + + + Name + indent.c + MacOS + + + Name + insdel.c + MacOS + + + Name + intervals.c + MacOS + + + Name + keyboard.c + MacOS + + + Name + keymap.c + MacOS + + + Name + lread.c + MacOS + + + Name + macros.c + MacOS + + + Name + marker.c + MacOS + + + Name + minibuf.c + MacOS + + + Name + mktime.c + MacOS + + + Name + mocklisp.c + MacOS + + + Name + print.c + MacOS + + + Name + process.c + MacOS + + + Name + regex.c + MacOS + + + Name + region-cache.c + MacOS + + + Name + scroll.c + MacOS + + + Name + search.c + MacOS + + + Name + strftime.c + MacOS + + + Name + syntax.c + MacOS + + + Name + term.c + MacOS + + + Name + termcap.c + MacOS + + + Name + textprop.c + MacOS + + + Name + tparam.c + MacOS + + + Name + undo.c + MacOS + + + Name + window.c + MacOS + + + Name + xdisp.c + MacOS + + + Name + sysdep.c + MacOS + + + Name + xfaces.c + MacOS + + + Name + mac.c + MacOS + + + Name + macfns.c + MacOS + + + Name + macmenu.c + MacOS + + + Name + macterm.c + MacOS + + + Name + InterfaceLib + MacOS + + + Name + MathLib + MacOS + + + Name + AppleScriptLib + MacOS + + + Name + TextEncodingConverter + MacOS + + + Name + AppearanceLib + MacOS + + + Name + Emacs.r + MacOS + + + Name + MSL C.PPC.Lib + MacOS + + + Name + MSL SIOUX.PPC.Lib + MacOS + + + Name + MSL RuntimePPC.Lib + MacOS + + + + + + + Emacs + + + + Emacs Source + + Emacs + Name + abbrev.c + MacOS + + + Emacs + Name + alloc.c + MacOS + + + Emacs + Name + alloca.c + MacOS + + + Emacs + Name + atimer.c + MacOS + + + Emacs + Name + buffer.c + MacOS + + + Emacs + Name + bytecode.c + MacOS + + + Emacs + Name + callint.c + MacOS + + + Emacs + Name + callproc.c + MacOS + + + Emacs + Name + casefiddle.c + MacOS + + + Emacs + Name + casetab.c + MacOS + + + Emacs + Name + category.c + MacOS + + + Emacs + Name + ccl.c + MacOS + + + Emacs + Name + charset.c + MacOS + + + Emacs + Name + cm.c + MacOS + + + Emacs + Name + cmds.c + MacOS + + + Emacs + Name + coding.c + MacOS + + + Emacs + Name + composite.c + MacOS + + + Emacs + Name + data.c + MacOS + + + Emacs + Name + dired.c + MacOS + + + Emacs + Name + dispnew.c + MacOS + + + Emacs + Name + doc.c + MacOS + + + Emacs + Name + doprnt.c + MacOS + + + Emacs + Name + editfns.c + MacOS + + + Emacs + Name + emacs.c + MacOS + + + Emacs + Name + eval.c + MacOS + + + Emacs + Name + fileio.c + MacOS + + + Emacs + Name + filemode.c + MacOS + + + Emacs + Name + floatfns.c + MacOS + + + Emacs + Name + fns.c + MacOS + + + Emacs + Name + fontset.c + MacOS + + + Emacs + Name + frame.c + MacOS + + + Emacs + Name + getloadavg.c + MacOS + + + Emacs + Name + indent.c + MacOS + + + Emacs + Name + insdel.c + MacOS + + + Emacs + Name + intervals.c + MacOS + + + Emacs + Name + keyboard.c + MacOS + + + Emacs + Name + keymap.c + MacOS + + + Emacs + Name + lread.c + MacOS + + + Emacs + Name + macros.c + MacOS + + + Emacs + Name + marker.c + MacOS + + + Emacs + Name + minibuf.c + MacOS + + + Emacs + Name + mktime.c + MacOS + + + Emacs + Name + mocklisp.c + MacOS + + + Emacs + Name + print.c + MacOS + + + Emacs + Name + process.c + MacOS + + + Emacs + Name + regex.c + MacOS + + + Emacs + Name + region-cache.c + MacOS + + + Emacs + Name + scroll.c + MacOS + + + Emacs + Name + search.c + MacOS + + + Emacs + Name + strftime.c + MacOS + + + Emacs + Name + syntax.c + MacOS + + + Emacs + Name + sysdep.c + MacOS + + + Emacs + Name + term.c + MacOS + + + Emacs + Name + termcap.c + MacOS + + + Emacs + Name + textprop.c + MacOS + + + Emacs + Name + tparam.c + MacOS + + + Emacs + Name + undo.c + MacOS + + + Emacs + Name + window.c + MacOS + + + Emacs + Name + xdisp.c + MacOS + + + Emacs + Name + xfaces.c + MacOS + + + Mac Source + + Emacs + Name + mac.c + MacOS + + + Emacs + Name + macfns.c + MacOS + + + Emacs + Name + macmenu.c + MacOS + + + Emacs + Name + macterm.c + MacOS + + + Resources + + Emacs + Name + Emacs.r + MacOS + + + Mac Libraries + + Emacs + Name + InterfaceLib + MacOS + + + Emacs + Name + MathLib + MacOS + + + Emacs + Name + AppleScriptLib + MacOS + + + Emacs + Name + TextEncodingConverter + MacOS + + + Emacs + Name + AppearanceLib + MacOS + + + ANSI Libraries + + Emacs + Name + MSL C.PPC.Lib + MacOS + + + Emacs + Name + MSL SIOUX.PPC.Lib + MacOS + + + Emacs + Name + MSL RuntimePPC.Lib + MacOS + + + + + diff --git a/mac/inc/alloca.h b/mac/inc/alloca.h new file mode 100644 index 00000000000..a84eee04c6e --- /dev/null +++ b/mac/inc/alloca.h @@ -0,0 +1,8 @@ +#ifndef _ALLOCA_H_ +#define _ALLOCA_H_ + +#if __MRC__ +void *__alloca(size_t size); +#endif + +#endif \ No newline at end of file diff --git a/mac/inc/cmdline-defs-cw5.h b/mac/inc/cmdline-defs-cw5.h new file mode 100644 index 00000000000..78577837761 --- /dev/null +++ b/mac/inc/cmdline-defs-cw5.h @@ -0,0 +1,2 @@ +#define emacs 1 +#define HAVE_CONFIG_H \ No newline at end of file diff --git a/mac/inc/cmdline-defs-cw6.h b/mac/inc/cmdline-defs-cw6.h new file mode 100644 index 00000000000..c24befb02f7 --- /dev/null +++ b/mac/inc/cmdline-defs-cw6.h @@ -0,0 +1,4 @@ +#define emacs 1 +#define HAVE_CONFIG_H + +#define CODEWARRIOR_VERSION_6 diff --git a/mac/inc/config.h b/mac/inc/config.h new file mode 100644 index 00000000000..aeb4a8aaad7 --- /dev/null +++ b/mac/inc/config.h @@ -0,0 +1,570 @@ +/* Handcrafted Emacs site configuration file for Mac OS. -*- C -*- */ + +/* GNU Emacs site configuration template file. -*- C -*- + Copyright (C) 1988, 1993, 1994, 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* No code in Emacs #includes config.h twice, but some of the code + intended to work with other packages as well (like gmalloc.c) + think they can include it as many times as they like. */ +#ifndef EMACS_CONFIG_H +#define EMACS_CONFIG_H + +/* These are all defined in the top-level Makefile by configure. + They're here only for reference. */ + +/* Define GNU_MALLOC if you want to use the GNU memory allocator. */ +/* #undef GNU_MALLOC */ + +/* Define if you are using the GNU C Library. */ +/* #undef DOUG_LEA_MALLOC */ + +/* Define REL_ALLOC if you want to use the relocating allocator for + buffer space. */ +/* #undef REL_ALLOC */ + +/* Define HAVE_X_WINDOWS if you want to use the X window system. */ +/* #undef HAVE_X_WINDOWS */ + +/* Define HAVE_X11 if you want to use version 11 of X windows. + Otherwise, Emacs expects to use version 10. */ +/* #undef HAVE_X11 */ + +/* Define if using an X toolkit. */ +/* #undef USE_X_TOOLKIT */ + +/* Define this if you're using XFree386. */ +/* #undef HAVE_XFREE386 */ + +/* Define this if you have Motif 2.1 or newer. */ +/* #undef HAVE_MOTIF_2_1 */ + +/* Define HAVE_MENUS if you have mouse menus. + (This is automatic if you use X, but the option to specify it remains.) + It is also defined with other window systems that support xmenu.c. */ +#define HAVE_MENUS 1 + +/* Define if we have the X11R6 or newer version of Xt. */ +/* #undef HAVE_X11XTR6 */ + +/* Define if we have the X11R6 or newer version of Xlib. */ +/* #undef HAVE_X11R6 */ + +/* Define if we have the X11R5 or newer version of Xlib. */ +/* #undef HAVE_X11R5 */ + +/* Define if we have the XPM libary. */ +/* #undef HAVE_XPM */ + +/* Define if we have the PNG library. */ +/* #undef HAVE_PNG */ + +/* Define if we have the JPEG library. */ +/* #undef HAVE_JPEG */ + +/* Define if we have the TIFF library. */ +/* #undef HAVE_TIFF */ + +/* Define if we have the GIF library. */ +/* #undef HAVE_GIF */ + +/* Define if libXaw3d is available. */ +/* #undef HAVE_XAW3D */ + +/* Define if we should use toolkit scroll bars. */ +/* #undef USE_TOOLKIT_SCROLL_BARS */ + +/* Define if we should use XIM, if it is available. */ +/* #undef USE_XIM */ + +/* Define if netdb.h declares h_errno. */ +/* #undef HAVE_H_ERRNO */ + +/* If we're using any sort of window system, define some consequences. */ +#ifdef HAVE_X_WINDOWS +#define HAVE_WINDOW_SYSTEM +#define MULTI_KBOARD +#define HAVE_MOUSE +#endif + +/* Define for MacOS */ +#define HAVE_WINDOW_SYSTEM 1 +#define HAVE_MOUSE 1 + +/* Define USER_FULL_NAME to return a string + that is the user's full name. + It can assume that the variable `pw' + points to the password file entry for this user. + + At some sites, the pw_gecos field contains + the user's full name. If neither this nor any other + field contains the right thing, use pw_name, + giving the user's login name, since that is better than nothing. */ +#define USER_FULL_NAME pw->pw_name + +/* Define AMPERSAND_FULL_NAME if you use the convention + that & in the full name stands for the login id. */ +/* Turned on June 1996 supposing nobody will mind it. */ +/* #undef AMPERSAND_FULL_NAME */ + +/* Things set by --with options in the configure script. */ + +/* Define to support POP mail retrieval. */ +/* #undef MAIL_USE_POP 1 */ + +/* Define to support Kerberos-authenticated POP mail retrieval. */ +/* #undef KERBEROS */ +/* Define to use Kerberos 5 instead of Kerberos 4 */ +/* #undef KERBEROS5 */ +/* Define to support GSS-API in addition to (or instead of) Kerberos */ +/* #undef GSSAPI */ + +/* Define to support using a Hesiod database to find the POP server. */ +/* #undef HESIOD */ + +/* Header for Voxware or PCM sound card driver. */ +/* #undef HAVE_MACHINE_SOUNDCARD_H */ +/* #undef HAVE_SYS_SOUNDCARD_H */ +/* #undef HAVE_SOUNDCARD_H */ + +/* Define HAVE_SOUND if we have sound support. We know it works + and compiles only on the specified platforms. For others, + it probably doesn't make sense to try. */ + +#if defined __FreeBSD__ || defined __NetBSD__ || defined __linux__ +#ifdef HAVE_MACHINE_SOUNDCARD_H +#define HAVE_SOUND 1 +#endif +#ifdef HAVE_SYS_SOUNDCARD_H +#define HAVE_SOUND 1 +#endif +#ifdef HAVE_SOUNDCARD_H +#define HAVE_SOUND 1 +#endif +#endif /* __FreeBSD__ || __NetBSD__ || __linux__ */ + +/* Some things figured out by the configure script, grouped as they are in + configure.in. */ +#ifndef _ALL_SOURCE /* suppress warning if this is pre-defined */ +/* #undef _ALL_SOURCE */ +#endif + +/* #undef HAVE_SYS_SELECT_H */ +/* #undef HAVE_SYS_TIMEB_H */ +#define HAVE_SYS_TIME_H 1 + +#ifdef __MRC__ +#undef HAVE_UNISTD_H +#else /* CodeWarrior */ +#define HAVE_UNISTD_H 1 +#endif + +#define HAVE_UTIME_H 1 +/* #undef HAVE_LINUX_VERSION_H */ +/* #undef HAVE_SYS_SYSTEMINFO_H */ +/* #undef HAVE_TERMIOS_H */ +#define HAVE_LIMITS_H 1 +#define HAVE_STRING_H 1 +/* #undef HAVE_STDLIB_H */ +/* #undef HAVE_TERMCAP_H */ +/* #undef HAVE_TERM_H */ +/* #undef HAVE_STDIO_EXT_H */ +/* #undef STDC_HEADERS */ +/* #undef TIME_WITH_SYS_TIME */ +/* #undef HAVE_VFORK_H */ +#define HAVE_FCNTL_H 1 +/* #undef HAVE_SETITIMER */ +/* #undef HAVE_UALARM */ +/* #undef HAVE_SYS_WAIT_H */ + +/* #undef HAVE_LIBDNET */ +/* #undef HAVE_LIBPTHREADS */ +/* #undef HAVE_LIBRESOLV */ +/* #undef HAVE_LIBXMU */ +/* #undef HAVE_LIBNCURSES */ +/* #undef HAVE_LIBINTL */ +/* #undef HAVE_LIBXP */ + +/* movemail Kerberos support */ +/* libraries */ +/* #undef HAVE_LIBKRB */ +/* #undef HAVE_LIBKRB4 */ +/* #undef HAVE_LIBDES */ +/* #undef HAVE_LIBDES425 */ +/* #undef HAVE_LIBKRB5 */ +/* #undef HAVE_LIBCRYPTO */ +/* #undef HAVE_LIBCOM_ERR */ +/* header files */ +/* #undef HAVE_KRB5_H */ +/* #undef HAVE_DES_H */ +/* #undef HAVE_KRB_H */ +/* #undef HAVE_KERBEROSIV_DES_H */ +/* #undef HAVE_KERBEROSIV_KRB_H */ +/* #undef HAVE_KERBEROS_DES_H */ +/* #undef HAVE_KERBEROS_KRB_H */ +/* #undef HAVE_COM_ERR_H */ + +/* GSS-API libraries and headers */ +/* #undef HAVE_LIBGSSAPI_KRB5 */ +/* #undef HAVE_LIBGSSAPI */ +/* #undef HAVE_GSSAPI_H */ + +/* Mail-file locking */ +/* #undef HAVE_LIBMAIL */ +/* #undef HAVE_MAILLOCK_H */ +/* #undef HAVE_TOUCHLOCK */ + +/* #undef HAVE_ALLOCA_H */ + +/* #undef HAVE_DEV_PTMX */ + +#define HAVE_GETTIMEOFDAY 1 +/* If we don't have gettimeofday, + the test for GETTIMEOFDAY_ONE_ARGUMENT may succeed, + but we should ignore it. */ +#ifdef HAVE_GETTIMEOFDAY +#define GETTIMEOFDAY_ONE_ARGUMENT 1 +#endif +/* #undef HAVE_GETHOSTNAME */ +/* #undef HAVE_GETDOMAINNAME */ +/* #undef HAVE_DUP2 */ +#define HAVE_RENAME 1 +#define HAVE_CLOSEDIR 1 + +/* #undef TM_IN_SYS_TIME */ +/* #undef HAVE_TM_ZONE */ +/* #undef HAVE_TZNAME */ +/* #undef HAVE_TM_GMTOFF */ + +/* #undef const */ + +/* #undef HAVE_LONG_FILE_NAMES */ + +/* #undef CRAY_STACKSEG_END */ + +/* #undef UNEXEC_SRC unexelf.c + +/* #undef HAVE_LIBXBSD */ +/* #undef HAVE_XRMSETDATABASE */ +/* #undef HAVE_XSCREENRESOURCESTRING */ +/* #undef HAVE_XSCREENNUMBEROFSCREEN */ +/* #undef HAVE_XSETWMPROTOCOLS */ + +#define HAVE_MKDIR 1 +#define HAVE_RMDIR 1 +/* #undef HAVE_SYSINFO */ +/* #undef HAVE_RANDOM */ +/* #undef HAVE_LRAND48 */ +/* #undef HAVE_BCOPY */ +/* #undef HAVE_BCMP */ +#define HAVE_LOGB 1 +#define HAVE_FREXP 1 +#define HAVE_FMOD 1 + +#ifdef __MRC__ +#undef HAVE_RINT +#else /* CodeWarrior */ +#define HAVE_RINT +#endif + +/* #undef HAVE_CBRT */ +/* #undef HAVE_FTIME */ +/* #undef HAVE_RES_INIT */ /* For -lresolv on Suns. */ +/* #undef HAVE_SETSID */ +/* #undef HAVE_FPATHCONF */ +#define HAVE_SELECT 1 +/* #undef HAVE_MKTIME */ +/* #undef BROKEN_MKTIME */ /* have mktime but it's broken */ +/* #undef HAVE_EUIDACCESS */ +/* #undef HAVE_GETPAGESIZE */ +/* #undef HAVE_TZSET */ +#define HAVE_SETLOCALE 1 +/* #undef HAVE_UTIMES */ +/* #undef HAVE_SETRLIMIT */ +/* #undef HAVE_SETPGID */ +/* #undef HAVE_GETCWD */ +#define HAVE_GETWD 1 +/* #undef HAVE_SHUTDOWN */ +#define HAVE_STRFTIME 1 +/* #undef HAVE_GETADDRINFO */ +/* #undef HAVE___FPENDING */ +/* #undef HAVE_FTELLO */ +/* #undef HAVE_GETLOADAVG */ +/* #undef NLIST_STRUCT */ +/* #undef NLIST_NAME_UNION */ +/* #undef HAVE_MBLEN */ +/* #undef HAVE_MBRLEN */ +/* #undef HAVE_STRSIGNAL */ +/* #undef HAVE_GRANTPT */ +/* #undef HAVE_GETPT */ +/* #undef HAVE_SPEED_T */ /* speed_t typedef in termios.h */ +/* #undef HAVE_STRUCT_TIMEZONE */ + +/* #undef LOCALTIME_CACHE */ +/* #undef HAVE_INET_SOCKETS */ + +/* #undef HAVE_AIX_SMT_EXP */ + +/* #undef vfork */ + +/* Define if you have the ANSI `strerror' function. + Otherwise you must have the variable `char *sys_errlist[]'. */ +#define HAVE_STRERROR 1 + +/* Define if `sys_siglist' is declared by . */ +/* #undef SYS_SIGLIST_DECLARED */ + +/* Define if `struct utimbuf' is declared by . */ +#define HAVE_STRUCT_UTIMBUF 1 + +/* Define if `struct timeval' is declared by . */ +#define HAVE_TIMEVAL 1 + +/* If using GNU, then support inline function declarations. */ +/* Don't try to switch on inline handling as detected by AC_C_INLINE + generally, because even if non-gcc compilers accept `inline', they + may reject `extern inline'. */ +#ifdef __GNUC__ +#define INLINE __inline__ +#else +#define INLINE +#endif + +/* Define this if you don't have struct exception in math.h. */ +/* #undef NO_MATHERR */ + +/* Define as `void' if your compiler accepts `void *'; otherwise + define as `char'. */ +#define POINTER_TYPE void +#define PTR POINTER_TYPE * /* For strftime.c. */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ +/* Define to make ftello visible on some hosts (e.g. HP-UX 10.20). */ +/* #undef _LARGEFILE_SOURCE */ +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ +/* Define to make ftello visible on some hosts (e.g. glibc 2.1.3). */ +/* #undef _XOPEN_SOURCE */ + +#ifdef __MRC__ +#define EMACS_CONFIGURATION "macos-mpw" +#else /* Assume CodeWarrior */ +#define EMACS_CONFIGURATION "macos-cw" +#endif + +#define EMACS_CONFIG_OPTIONS "" + +/* The configuration script defines opsysfile to be the name of the + s/SYSTEM.h file that describes the system type you are using. The file + is chosen based on the configuration name you give. + + See the file ../etc/MACHINES for a list of systems and the + configuration names to use for them. + + See s/template.h for documentation on writing s/SYSTEM.h files. */ +#undef config_opsysfile +#include "s-mac.h" + +/* The configuration script defines machfile to be the name of the + m/MACHINE.h file that describes the machine you are using. The file is + chosen based on the configuration name you give. + + See the file ../etc/MACHINES for a list of machines and the + configuration names to use for them. + + See m/template.h for documentation on writing m/MACHINE.h files. */ +#undef config_machfile +#include "m-mac.h" + +/* Load in the conversion definitions if this system + needs them and the source file being compiled has not + said to inhibit this. There should be no need for you + to alter these lines. */ + +#ifdef SHORTNAMES +#ifndef NO_SHORTNAMES +#include "../shortnames/remap.h" +#endif /* not NO_SHORTNAMES */ +#endif /* SHORTNAMES */ + +/* If no remapping takes place, static variables cannot be dumped as + pure, so don't worry about the `static' keyword. */ +#ifdef NO_REMAP +/* #undef static */ +#endif + +/* Define `subprocesses' should be defined if you want to + have code for asynchronous subprocesses + (as used in M-x compile and M-x shell). + These do not work for some USG systems yet; + for the ones where they work, the s/SYSTEM.h file defines this flag. */ + +#ifndef VMS +#ifndef USG +/* #define subprocesses */ +#endif +#endif + +/* Define LD_SWITCH_SITE to contain any special flags your loader may need. */ +/* #undef LD_SWITCH_SITE */ + +/* Define C_SWITCH_SITE to contain any special flags your compiler needs. */ +/* #undef C_SWITCH_SITE */ + +/* Define LD_SWITCH_X_SITE to contain any special flags your loader + may need to deal with X Windows. For instance, if you've defined + HAVE_X_WINDOWS above and your X libraries aren't in a place that + your loader can find on its own, you might want to add "-L/..." or + something similar. */ +/* #undef LD_SWITCH_X_SITE */ + +/* Define LD_SWITCH_X_SITE_AUX with an -R option + in case it's needed (for Solaris, for example). */ +/* #undef LD_SWITCH_X_SITE_AUX */ + +/* Define C_SWITCH_X_SITE to contain any special flags your compiler + may need to deal with X Windows. For instance, if you've defined + HAVE_X_WINDOWS above and your X include files aren't in a place + that your compiler can find on its own, you might want to add + "-I/..." or something similar. */ +/* #undef C_SWITCH_X_SITE */ + +/* Define STACK_DIRECTION here, but not if m/foo.h did. */ +#ifndef STACK_DIRECTION +/* #undef STACK_DIRECTION */ +#endif + +/* Define the return type of signal handlers if the s-xxx file + did not already do so. */ +#define RETSIGTYPE void + +/* SIGTYPE is the macro we actually use. */ +#ifndef SIGTYPE +#define SIGTYPE RETSIGTYPE +#endif + +#ifdef emacs /* Don't do this for lib-src. */ +/* Tell regex.c to use a type compatible with Emacs. */ +#define RE_TRANSLATE_TYPE Lisp_Object +#define RE_TRANSLATE(TBL, C) CHAR_TABLE_TRANSLATE (TBL, C) +#define RE_TRANSLATE_P(TBL) (XFASTINT (TBL) != 0) +#endif + +/* Avoid link-time collision with system mktime if we will use our own. */ +#if ! HAVE_MKTIME || BROKEN_MKTIME +#define mktime emacs_mktime +#endif + +/* The rest of the code currently tests the CPP symbol BSTRING. + Override any claims made by the system-description files. + Note that on some SCO version it is possible to have bcopy and not bcmp. */ +/* #undef BSTRING */ +#if defined (HAVE_BCOPY) && defined (HAVE_BCMP) +#define BSTRING +#endif + +/* Define to empty if the keyword `volatile' does not work. Warning: + valid code using `volatile' can become incorrect without. Disable + with care. */ +/* #undef volatile */ + +/* Some of the files of Emacs which are intended for use with other + programs assume that if you have a config.h file, you must declare + the type of getenv. + + This declaration shouldn't appear when alloca.s or Makefile.in + includes config.h. */ +#ifndef NOT_C_CODE +extern char *getenv (); +#endif + +#endif /* EMACS_CONFIG_H */ + +/* These default definitions are good for almost all machines. + The exceptions override them in m/MACHINE.h. */ + +#ifndef BITS_PER_CHAR +#define BITS_PER_CHAR 8 +#endif + +#ifndef BITS_PER_SHORT +#define BITS_PER_SHORT 16 +#endif + +/* Note that lisp.h uses this in a preprocessor conditional, so it + would not work to use sizeof. That being so, we do all of them + without sizeof, for uniformity's sake. */ +#ifndef BITS_PER_INT +#define BITS_PER_INT 32 +#endif + +#ifndef BITS_PER_LONG +#ifdef _LP64 +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif +#endif + +/* Define if the compiler supports function prototypes. It may do so + but not define __STDC__ (e.g. DEC C by default) or may define it as + zero. */ +/* #undef PROTOTYPES */ +/* For mktime.c: */ +#ifndef __P +# if defined PROTOTYPES +# define __P(args) args +# else +# define __P(args) () +# endif /* GCC. */ +#endif /* __P */ + + +/* Don't include "string.h" or in non-C code. */ +#ifndef NOT_C_CODE +#ifdef HAVE_STRING_H +#include "string.h" +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#endif + +/* Define HAVE_X_I18N if we have usable i18n support. */ + +#ifdef HAVE_X11R6 +#define HAVE_X_I18N +#elif defined HAVE_X11R5 && !defined X11R5_INHIBIT_I18N +#define HAVE_X_I18N +#endif + +/* Define HAVE_X11R6_XIM if we have usable X11R6-style XIM support. */ + +#if defined HAVE_X11R6 && !defined INHIBIT_X11R6_XIM +#define HAVE_X11R6_XIM +#endif + +/* Should we enable expensive run-time checking of data types? */ +/* #undef ENABLE_CHECKING */ + +/* #define GLYPH_DEBUG 1 */ + +#define NO_RETURN /* nothing */ \ No newline at end of file diff --git a/mac/inc/dirent.h b/mac/inc/dirent.h new file mode 100644 index 00000000000..8513acb2bee --- /dev/null +++ b/mac/inc/dirent.h @@ -0,0 +1,48 @@ +/* Replacement dirent.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _DIRENT_H +#define _DIRENT_H + +/* for definition of FSSpec */ +#include + +/* for definition of ino_t */ +#include + +struct dirent { + ino_t d_ino; + char *d_name; +}; + +typedef struct DIR { + long dir_id; + short vol_ref_num; + long current_index; + int getting_volumes; /* true if this DIR struct refers to the root directory */ +} DIR; + +extern DIR *opendir(const char *); +extern int closedir(DIR *); +extern struct dirent *readdir(DIR *); + +#endif /* _DIRENT_H */ diff --git a/mac/inc/epaths.h b/mac/inc/epaths.h new file mode 100644 index 00000000000..706a8aa42d9 --- /dev/null +++ b/mac/inc/epaths.h @@ -0,0 +1,61 @@ +/* Hey Emacs, this is -*- C -*- code! */ + +/* Handcrafted epaths.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +/* The default search path for Lisp function "load". + This sets load-path. */ +#define PATH_LOADSEARCH "~emacs/lisp:~emacs/leim:~emacs/lisp/calendar:~emacs/lisp/emacs-lisp:~emacs/lisp/emulation:~emacs/lisp/progmodes:~emacs/lisp/textmodes:~emacs/lisp/international:~emacs/lisp/language:~emacs/lisp/play" + +/* Like PATH_LOADSEARCH, but used only when Emacs is dumping. This + path is usually identical to PATH_LOADSEARCH except that the entry + for the directory containing the installed lisp files has been + replaced with ../lisp. */ +#define PATH_DUMPLOADSEARCH "~emacs/lisp" + +/* The extra search path for programs to invoke. This is appended to + whatever the PATH environment variable says to set the Lisp + variable exec-path and the first file name in it sets the Lisp + variable exec-directory. exec-directory is used for finding + executables and other architecture-dependent files. */ +#define PATH_EXEC "~emacs/mac/bin" + +/* Where Emacs should look for its architecture-independent data + files, like the NEWS file. The lisp variable data-directory + is set to this value. */ +#define PATH_DATA "~emacs/data" + +/* Where Emacs should look for X bitmap files. + The lisp variable x-bitmap-file-path is set based on this value. */ +/* #define PATH_BITMAPS "/usr/include/X11/bitmaps" */ + +/* Where Emacs should look for its docstring file. The lisp variable + doc-directory is set to this value. */ +#define PATH_DOC "../etc" + +/* Where the configuration process believes the info tree lives. The + lisp variable configure-info-directory gets its value from this + macro, and is then used to set the Info-default-directory-list. */ +#define PATH_INFO "~emacs/info" + +/* Where Emacs should look for the application default file. */ +/* #define PATH_X_DEFAULTS "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S" */ diff --git a/mac/inc/m-mac.h b/mac/inc/m-mac.h new file mode 100644 index 00000000000..6378c614e93 --- /dev/null +++ b/mac/inc/m-mac.h @@ -0,0 +1,140 @@ +/* Handcrafted m-mac.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +/* The following line tells the configuration script what sort of + operating system this machine is likely to run. + USUAL-OPSYS="" */ + +/* Define WORDS_BIG_ENDIAN iff lowest-numbered byte in a word + is the most significant byte. */ + +#define WORDS_BIG_ENDIAN + +/* Define NO_ARG_ARRAY if you cannot take the address of the first of a + * group of arguments and treat it as an array of the arguments. */ + +#define NO_ARG_ARRAY + +/* Define WORD_MACHINE if addresses and such have + * to be corrected before they can be used as byte counts. */ + +/* #define WORD_MACHINE */ + +/* Now define a symbol for the cpu type, if your compiler + does not define it automatically: + Ones defined so far include vax, m68000, ns16000, pyramid, + orion, tahoe, APOLLO and many others */ + +/* Use type int rather than a union, to represent Lisp_Object */ +/* This is desirable for most machines. */ + +#define NO_UNION_TYPE + +/* Define EXPLICIT_SIGN_EXTEND if XINT must explicitly sign-extend + the 24-bit bit field into an int. In other words, if bit fields + are always unsigned. + + If you use NO_UNION_TYPE, this flag does not matter. */ + +#define EXPLICIT_SIGN_EXTEND + +/* Data type of load average, as read out of kmem. */ + +/* #define LOAD_AVE_TYPE long */ + +/* Convert that into an integer that is 100 for a load average of 1.0 */ + +/* #define LOAD_AVE_CVT(x) (int) (((double) (x)) * 100.0 / FSCALE) */ + +/* Define CANNOT_DUMP on machines where unexec does not work. + Then the function dump-emacs will not be defined + and temacs will do (load "loadup") automatically unless told otherwise. */ + +#define CANNOT_DUMP + +/* Define VIRT_ADDR_VARIES if the virtual addresses of + pure and impure space as loaded can vary, and even their + relative order cannot be relied on. + + Otherwise Emacs assumes that text space precedes data space, + numerically. */ + +#define VIRT_ADDR_VARIES + +/* Define C_ALLOCA if this machine does not support a true alloca + and the one written in C should be used instead. + Define HAVE_ALLOCA to say that the system provides a properly + working alloca function and it should be used. + Define neither one if an assembler-language alloca + in the file alloca.s should be used. */ + +#define C_ALLOCA +/* #define HAVE_ALLOCA */ + +/* Define NO_REMAP if memory segmentation makes it not work well + to change the boundary between the text section and data section + when Emacs is dumped. If you define this, the preloaded Lisp + code will not be sharable; but that's better than failing completely. */ + +/* #define NO_REMAP */ + +/* Some really obscure 4.2-based systems (like Sequent DYNIX) + * do not support asynchronous I/O (using SIGIO) on sockets, + * even though it works fine on tty's. If you have one of + * these systems, define the following, and then use it in + * config.h (or elsewhere) to decide when (not) to use SIGIO. + * + * You'd think this would go in an operating-system description file, + * but since it only occurs on some, but not all, BSD systems, the + * reasonable place to select for it is in the machine description + * file. + */ + +#define NO_SOCK_SIGIO + + +/* After adding support for a new system, modify the large case + statement in the `configure' script to recognize reasonable + configuration names, and add a description of the system to + `etc/MACHINES'. + + If you've just fixed a problem in an existing configuration file, + you should also check `etc/MACHINES' to make sure its descriptions + of known problems in that configuration should be updated. */ + +/* MPW build crashes if this is not defined. */ +#ifdef __MRC__ +#define IEEE_FLOATING_POINT 1 +#endif + +#if 0 +/* The usual definition of XINT, which involves shifting, does not + sign-extend properly on this machine. */ + +#define XINT(i) (((sign_extend_temp=(i)) & 0x00800000) \ + ? (sign_extend_temp | 0xFF000000) \ + : (sign_extend_temp & 0x00FFFFFF)) + +#ifdef emacs /* Don't do this when making xmakefile! */ +extern int sign_extend_temp; +#endif +#endif diff --git a/mac/inc/macgui.h b/mac/inc/macgui.h new file mode 100644 index 00000000000..1072bcec533 --- /dev/null +++ b/mac/inc/macgui.h @@ -0,0 +1,155 @@ +/* Definitions and headers for communication on the Mac OS. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef EMACS_MACGUI_H +#define EMACS_MACGUI_H + +#include +#include + +typedef int Pixmap; +typedef int Bitmap; + +typedef int Display; /* fix later */ + +typedef unsigned long Time; +typedef RGBColor Color; +typedef WindowPtr Window; + +#define FACE_DEFAULT (~0) + + +/* Emulate XCharStruct. */ +typedef struct _XCharStruct +{ + int rbearing; + int lbearing; + int width; + int ascent; + int descent; +} XCharStruct; + +struct MacFontStruct { + char *fontname; + + SInt16 mac_fontnum; /* font number of font used in this window */ + int mac_fontsize; /* size of font */ + Style mac_fontface; /* plain, bold, italics, etc. */ + short mac_scriptcode; /* Mac OS script code for font used */ + +#if 0 + SInt16 mFontNum; /* font number of font used in this window */ + short mScriptCode; /* Mac OS script code for font used */ + int mFontSize; /* size of font */ + Style mFontFace; /* plain, bold, italics, etc. */ + int mHeight; /* height of one line of text in pixels */ + int mWidth; /* width of one character in pixels */ + int mAscent; + int mDescent; + int mLeading; + char mTwoByte; /* true for two-byte font */ +#endif + +/* from Xlib.h */ +#if 0 + XExtData *ext_data; /* hook for extension to hang data */ + Font fid; /* Font id for this font */ + unsigned direction; /* hint about the direction font is painted */ +#endif + unsigned min_char_or_byte2;/* first character */ + unsigned max_char_or_byte2;/* last character */ + unsigned min_byte1; /* first row that exists */ + unsigned max_byte1; /* last row that exists */ +#if 0 + Bool all_chars_exist; /* flag if all characters have nonzero size */ + unsigned default_char; /* char to print for undefined character */ + int n_properties; /* how many properties there are */ + XFontProp *properties; /* pointer to array of additional properties */ +#endif + XCharStruct min_bounds; /* minimum bounds over all existing char */ + XCharStruct max_bounds; /* maximum bounds over all existing char */ + XCharStruct *per_char; /* first_char to last_char information */ + int ascent; /* logical extent above baseline for spacing */ + int descent; /* logical decent below baseline for spacing */ +}; + +typedef struct MacFontStruct MacFontStruct; +typedef struct MacFontStruct XFontStruct; + + +/* Emulate X GC's by keeping color and font info in a structure. */ +typedef struct _XGCValues +{ + unsigned long foreground; + unsigned long background; + XFontStruct *font; +} XGCValues; + +typedef XGCValues *GC; + +extern XGCValues * +XCreateGC (void *, Window, unsigned long, XGCValues *); + +#define GCForeground 0x01 +#define GCBackground 0x02 +#define GCFont 0x03 +#define GCGraphicsExposures 0 + +/* Bit Gravity */ + +#define ForgetGravity 0 +#define NorthWestGravity 1 +#define NorthGravity 2 +#define NorthEastGravity 3 +#define WestGravity 4 +#define CenterGravity 5 +#define EastGravity 6 +#define SouthWestGravity 7 +#define SouthGravity 8 +#define SouthEastGravity 9 +#define StaticGravity 10 + +#define NoValue 0x0000 +#define XValue 0x0001 +#define YValue 0x0002 +#define WidthValue 0x0004 +#define HeightValue 0x0008 +#define AllValues 0x000F +#define XNegative 0x0010 +#define YNegative 0x0020 + +#define USPosition (1L << 0) /* user specified x, y */ +#define USSize (1L << 1) /* user specified width, height */ + +#define PPosition (1L << 2) /* program specified position */ +#define PSize (1L << 3) /* program specified size */ +#define PMinSize (1L << 4) /* program specified minimum size */ +#define PMaxSize (1L << 5) /* program specified maximum size */ +#define PResizeInc (1L << 6) /* program specified resize increments */ +#define PAspect (1L << 7) /* program specified min and max aspect ratios */ +#define PBaseSize (1L << 8) /* program specified base for incrementing */ +#define PWinGravity (1L << 9) /* program specified window gravity */ + +extern int XParseGeometry (); + +#endif /* EMACS_MACGUI_H */ + diff --git a/mac/inc/macterm.h b/mac/inc/macterm.h new file mode 100644 index 00000000000..7df8a932653 --- /dev/null +++ b/mac/inc/macterm.h @@ -0,0 +1,665 @@ +/* Display module for Mac OS. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include "macgui.h" +#include "frame.h" + +/* The class of this X application. */ +#define EMACS_CLASS "Emacs" + +#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) + +#define RED_FROM_ULONG(color) ((color) >> 16) +#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) +#define BLUE_FROM_ULONG(color) ((color) & 0xff) + +#define BLACK_PIX_DEFAULT(f) RGB_TO_ULONG(0,0,0) +#define WHITE_PIX_DEFAULT(f) RGB_TO_ULONG(255,255,255) + +#define FONT_WIDTH(f) ((f)->max_bounds.width) +#define FONT_HEIGHT(f) ((f)->ascent + (f)->descent) +#define FONT_BASE(f) ((f)->ascent) +#define FONT_DESCENT(f) ((f)->descent) + +#define FONT_MAX_WIDTH(f) FONT_WIDTH(f) /* fix later */ + +enum text_cursor_kinds { + NO_CURSOR = -1, + FILLED_BOX_CURSOR, + HOLLOW_BOX_CURSOR, + BAR_CURSOR +}; + +/* Structure recording bitmaps and reference count. + If REFCOUNT is 0 then this record is free to be reused. */ + +struct mac_bitmap_record +{ + char *bitmap_data; + int refcount; + int height, width; +}; + + +/* For each display (currently only one on mac), we have a structure that + records information about it. */ + +struct mac_display_info +{ + /* Chain of all mac_display_info structures. */ + struct mac_display_info *next; + + /* This is a cons cell of the form (NAME . FONT-LIST-CACHE). + The same cons cell also appears in x_display_name_list. */ + Lisp_Object name_list_element; + + /* Number of frames that are on this display. */ + int reference_count; + + /* Dots per inch of the screen. */ + double resx, resy; + + /* Number of planes on this screen. */ + int n_planes; + + /* Number of bits per pixel on this screen. */ + int n_cbits; + + /* Dimensions of this screen. */ + int height, width; +#if 0 + int height_in,width_in; +#endif + + /* Mask of things that cause the mouse to be grabbed. */ + int grabbed; + +#if 0 + /* Emacs bitmap-id of the default icon bitmap for this frame. + Or -1 if none has been allocated yet. */ + int icon_bitmap_id; + +#endif + /* The root window of this screen. */ + Window root_window; + + /* The cursor to use for vertical scroll bars. */ + Cursor vertical_scroll_bar_cursor; + +#if 0 + /* color palette information. */ + int has_palette; + struct w32_palette_entry * color_list; + unsigned num_colors; + HPALETTE palette; + + /* deferred action flags checked when starting frame update. */ + int regen_palette; + + /* Keystroke that has been faked by Emacs and will be ignored when + received; value is reset after key is received. */ + int faked_key; + +#endif + + /* A table of all the fonts we have already loaded. */ + struct font_info *font_table; + + /* The current capacity of font_table. */ + int font_table_size; + + /* The number of fonts actually stored in the font table. + font_table[n] is used and valid iff 0 <= n < n_fonts. 0 <= + n_fonts <= font_table_size. and font_table[i].name != 0. */ + int n_fonts; + + /* Minimum width over all characters in all fonts in font_table. */ + int smallest_char_width; + + /* Minimum font height over all fonts in font_table. */ + int smallest_font_height; + + /* Reusable Graphics Context for drawing a cursor in a non-default face. */ + XGCValues *scratch_cursor_gc; + + /* These variables describe the range of text currently shown in its + mouse-face, together with the window they apply to. As long as + the mouse stays within this range, we need not redraw anything on + its account. Rows and columns are glyph matrix positions in + MOUSE_FACE_WINDOW. */ + int mouse_face_beg_row, mouse_face_beg_col; + int mouse_face_beg_x, mouse_face_beg_y; + int mouse_face_end_row, mouse_face_end_col; + int mouse_face_end_x, mouse_face_end_y; + int mouse_face_past_end; + + Lisp_Object mouse_face_window; + + int mouse_face_face_id; + + /* 1 if a mouse motion event came and we didn't handle it right away because + gc was in progress. */ + int mouse_face_deferred_gc; + + /* FRAME and X, Y position of mouse when last checked for + highlighting. X and Y can be negative or out of range for the frame. */ + struct frame *mouse_face_mouse_frame; + + int mouse_face_mouse_x, mouse_face_mouse_y; + + /* Nonzero means defer mouse-motion highlighting. */ + int mouse_face_defer; + + int mouse_face_image_state; + + char *mac_id_name; + + /* Pointer to bitmap records. */ + struct mac_bitmap_record *bitmaps; + + /* Allocated size of bitmaps field. */ + int bitmaps_size; + + /* Last used bitmap index. */ + int bitmaps_last; + + /* The frame (if any) which has the window that has keyboard focus. + Zero if none. This is examined by Ffocus_frame in w32fns.c. Note + that a mere EnterNotify event can set this; if you need to know the + last frame specified in a FocusIn or FocusOut event, use + w32_focus_event_frame. */ + struct frame *x_focus_frame; + + /* The last frame mentioned in a FocusIn or FocusOut event. This is + separate from w32_focus_frame, because whether or not LeaveNotify + events cause us to lose focus depends on whether or not we have + received a FocusIn event for it. */ + struct frame *x_focus_event_frame; + + /* The frame which currently has the visual highlight, and should get + keyboard input (other sorts of input have the frame encoded in the + event). It points to the focus frame's selected window's + frame. It differs from w32_focus_frame when we're using a global + minibuffer. */ + struct frame *x_highlight_frame; + + /* Cache of images. */ + struct image_cache *image_cache; +}; + +#define x_display_info mac_display_info + +/* This is a chain of structures for all the displays currently in use. */ +extern struct mac_display_info one_mac_display_info; + +/* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE), + one for each element of w32_display_list and in the same order. + NAME is the name of the frame. + FONT-LIST-CACHE records previous values returned by x-list-fonts. */ +extern Lisp_Object x_display_name_list; + +/* A flag to control how to display unibyte 8-bit character. */ +extern int unibyte_display_via_language_environment; + +extern struct x_display_info *x_display_info_for_display P_ ((Display *)); +extern struct x_display_info *x_display_info_for_name P_ ((Lisp_Object)); + +extern struct mac_display_info *mac_term_init (); + +/* The collection of data describing a window on the Mac. Functions + defined in macterm.c */ +struct mac_output { + WindowPtr mWP; /* pointer to QuickDraw window */ + FRAME_PTR mFP; /* points back to the frame struct */ + +#if 0 + int mNumCols; /* number of characters per column */ + int mNumRows; /* number of characters per row */ + int mLineHeight; /* height of one line of text in pixels */ + int mCharWidth; /* width of one character in pixels */ + int mHomeX; /* X pixel coordinate of lower left corner of character at (0, 0) */ + int mHomeY; /* Y pixel coordinate of lower left corner of character at (0, 0) */ + int mHighlight; /* current highlight state (0 = off). */ + int mTermWinSize; /* num of lines from top of window affected by ins_del_lines; set by set_terminal_window. */ +#endif + +#if 0 + /* stuffs used by xfaces.c */ + struct face **param_faces; + int n_param_faces; + struct face **computed_faces; + int n_computed_faces; + int size_computed_faces; +#endif + + unsigned long background_pixel; + unsigned long foreground_pixel; + + /* Position of the Mac window (x and y offsets in global coordinates). */ + int left_pos; + int top_pos; + + /* Border width of the W32 window as known by the window system. */ + int border_width; + + /* Size of the W32 window in pixels. */ + int pixel_height, pixel_width; + + /* Height of a line, in pixels. */ + int line_height; + + /* Here are the Graphics Contexts for the default font. */ + GC normal_gc; /* Normal video */ + GC reverse_gc; /* Reverse video */ + GC cursor_gc; /* cursor drawing */ + + /* Width of the internal border. This is a line of background color + just inside the window's border. When the frame is selected, + a highlighting is displayed inside the internal border. */ + int internal_border_width; + + /* The window used for this frame. + May be zero while the frame object is being created + and the window has not yet been created. */ + Window window_desc; + + /* The window that is the parent of this window. + Usually this is a window that was made by the window manager, + but it can be the root window, and it can be explicitly specified + (see the explicit_parent field, below). */ + Window parent_desc; + + /* Default ASCII font of this frame. */ + XFontStruct *font; + + /* The baseline offset of the default ASCII font. */ + int baseline_offset; + + /* If a fontset is specified for this frame instead of font, this + value contains an ID of the fontset, else -1. */ + int fontset; + + /* Pixel values used for various purposes. + border_pixel may be -1 meaning use a gray tile. */ + unsigned long cursor_pixel; + unsigned long border_pixel; + unsigned long mouse_pixel; + unsigned long cursor_foreground_pixel; + + /* Foreground color for scroll bars. A value of -1 means use the + default (black for non-toolkit scroll bars). */ + unsigned long scroll_bar_foreground_pixel; + + /* Background color for scroll bars. A value of -1 means use the + default (background color of the frame for non-toolkit scroll + bars). */ + unsigned long scroll_bar_background_pixel; + + /* Descriptor for the cursor in use for this window. */ + Cursor text_cursor; + Cursor nontext_cursor; + Cursor modeline_cursor; + Cursor cross_cursor; + Cursor busy_cursor; +#if 0 + /* Window whose cursor is busy_cursor. This window is temporarily + mapped to display a busy-cursor. */ + Window busy_window; + + /* Non-zero means busy cursor is currently displayed. */ + unsigned busy_p : 1; + + /* Flag to set when the window needs to be completely repainted. */ + int needs_exposure; + +#endif + + /* What kind of text cursor is drawn in this window right now? + (If there is no cursor (phys_cursor_x < 0), then this means nothing.) */ + enum text_cursor_kinds current_cursor; + + /* What kind of text cursor should we draw in the future? + This should always be filled_box_cursor or bar_cursor. */ + enum text_cursor_kinds desired_cursor; + + /* Width of bar cursor (if we are using that). */ + int cursor_width; + +#if 0 + DWORD dwStyle; +#endif + + /* The size of the extra width currently allotted for vertical + scroll bars, in pixels. */ + int vertical_scroll_bar_extra; + + /* The extra width currently allotted for the areas in which + truncation marks, continuation marks, and overlay arrows are + displayed. */ + int flags_areas_extra; + + /* This is the gravity value for the specified window position. */ + int win_gravity; + + /* The geometry flags for this window. */ + int size_hint_flags; + + /* This is the Emacs structure for the display this frame is on. */ + /* struct w32_display_info *display_info; */ + + /* Nonzero means our parent is another application's window + and was explicitly specified. */ + char explicit_parent; + + /* Nonzero means tried already to make this frame visible. */ + char asked_for_visible; + + /* Nonzero means menubar is currently active. */ + char menubar_active; + + /* Always contains NULL on the Mac OS because the menu bar is shared. */ + int menubar_widget; + +#if 0 + /* Nonzero means menubar is about to become active, but should be + brought up to date first. */ + volatile char pending_menu_activation; + +#endif + /* Relief GCs, colors etc. */ + struct relief + { + XGCValues *gc; + unsigned long pixel; + int allocated_p; + } + black_relief, white_relief; + + /* The background for which the above relief GCs were set up. + They are changed only when a different background is involved. */ + unsigned long relief_background; +}; + +typedef struct mac_output mac_output; + +/* Return the Mac window used for displaying data in frame F. */ +#define FRAME_MAC_WINDOW(f) ((f)->output_data.mac->mWP) + +#define FRAME_FOREGROUND_PIXEL(f) ((f)->output_data.mac->foreground_pixel) +#define FRAME_BACKGROUND_PIXEL(f) ((f)->output_data.mac->background_pixel) + +#define FRAME_FONT(f) ((f)->output_data.mac->font) +#define FRAME_FONTSET(f) ((f)->output_data.mac->fontset) + +#define FRAME_INTERNAL_BORDER_WIDTH(f) ((f)->output_data.mac->internal_border_width) +#define FRAME_LINE_HEIGHT(f) ((f)->output_data.mac->line_height) +/* Width of the default font of frame F. Must be defined by each + terminal specific header. */ +#define FRAME_DEFAULT_FONT_WIDTH(F) FONT_WIDTH (FRAME_FONT (F)) +#define FRAME_BASELINE_OFFSET(f) ((f)->output_data.mac->baseline_offset) + +/* This gives the w32_display_info structure for the display F is on. */ +#define FRAME_MAC_DISPLAY_INFO(f) (&one_mac_display_info) +#define FRAME_X_DISPLAY_INFO(f) (&one_mac_display_info) + +/* This is the `Display *' which frame F is on. */ +#define FRAME_MAC_DISPLAY(f) (0) + +/* This is the 'font_info *' which frame F has. */ +#define FRAME_MAC_FONT_TABLE(f) (FRAME_MAC_DISPLAY_INFO (f)->font_table) + +/* These two really ought to be called FRAME_PIXEL_{WIDTH,HEIGHT}. */ +#define PIXEL_WIDTH(f) ((f)->output_data.mac->pixel_width) +#define PIXEL_HEIGHT(f) ((f)->output_data.mac->pixel_height) + +#define FRAME_DESIRED_CURSOR(f) ((f)->output_data.mac->desired_cursor) + +/* Value is the smallest width of any character in any font on frame F. */ + +#define FRAME_SMALLEST_CHAR_WIDTH(F) \ + FRAME_MAC_DISPLAY_INFO(F)->smallest_char_width + +/* Value is the smallest height of any font on frame F. */ + +#define FRAME_SMALLEST_FONT_HEIGHT(F) \ + FRAME_MAC_DISPLAY_INFO(F)->smallest_font_height + +/* Return a pointer to the image cache of frame F. */ + +#define FRAME_X_IMAGE_CACHE(F) FRAME_MAC_DISPLAY_INFO ((F))->image_cache + + +/* Pixel width of the bitmaps drawn to indicate truncation, + continuation etc. */ + +#define FRAME_FLAGS_BITMAP_WIDTH(f) 8 +#define FRAME_FLAGS_BITMAP_HEIGHT(f) 8 + +/* Total width of areas reserved for drawing truncation bitmaps, + continuation bitmaps and alike. The width is in canonical char + units of the frame. This must currently be the case because window + sizes aren't pixel values. If it weren't the case, we wouldn't be + able to split windows horizontally nicely. */ + +#define FRAME_X_FLAGS_AREA_COLS(F) \ + ((2 * FRAME_FLAGS_BITMAP_WIDTH ((F)) + CANON_X_UNIT ((F)) - 1) \ + / CANON_X_UNIT ((F))) + +/* Total width of flags areas in pixels. */ + +#define FRAME_X_FLAGS_AREA_WIDTH(F) \ + (FRAME_X_FLAGS_AREA_COLS ((F)) * CANON_X_UNIT ((F))) + +/* Pixel-width of the left flags area. */ + +#define FRAME_X_LEFT_FLAGS_AREA_WIDTH(F) \ + (FRAME_X_FLAGS_AREA_WIDTH (F) / 2) + +/* Pixel-width of the right flags area. Note that we are doing + integer arithmetic here, so don't loose a pixel if the total + width is an odd number. */ + +#define FRAME_X_RIGHT_FLAGS_AREA_WIDTH(F) \ + (FRAME_X_FLAGS_AREA_WIDTH (F) - FRAME_X_FLAGS_AREA_WIDTH (F) / 2) + + + +/* Mac-specific scroll bar stuff. */ + +/* We represent scroll bars as lisp vectors. This allows us to place + references to them in windows without worrying about whether we'll + end up with windows referring to dead scroll bars; the garbage + collector will free it when its time comes. + + We use struct scroll_bar as a template for accessing fields of the + vector. */ + +struct scroll_bar { + + /* These fields are shared by all vectors. */ + EMACS_INT size_from_Lisp_Vector_struct; + struct Lisp_Vector *next_from_Lisp_Vector_struct; + + /* The window we're a scroll bar for. */ + Lisp_Object window; + + /* The next and previous in the chain of scroll bars in this frame. */ + Lisp_Object next, prev; + + /* The Mac control handle of this scroll bar. Since this is a full + 32-bit quantity, we store it split into two 32-bit values. */ + Lisp_Object control_handle_low, control_handle_high; + + /* The position and size of the scroll bar in pixels, relative to the + frame. */ + Lisp_Object top, left, width, height; + + /* The starting and ending positions of the handle, relative to the + handle area (i.e. zero is the top position, not + SCROLL_BAR_TOP_BORDER). If they're equal, that means the handle + hasn't been drawn yet. + + These are not actually the locations where the beginning and end + are drawn; in order to keep handles from becoming invisible when + editing large files, we establish a minimum height by always + drawing handle bottoms VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below + where they would be normally; the bottom and top are in a + different co-ordinate system. */ + Lisp_Object start, end; + + /* If the scroll bar handle is currently being dragged by the user, + this is the number of pixels from the top of the handle to the + place where the user grabbed it. If the handle isn't currently + being dragged, this is Qnil. */ + Lisp_Object dragging; +}; + +/* The number of elements a vector holding a struct scroll_bar needs. */ +#define SCROLL_BAR_VEC_SIZE \ + ((sizeof (struct scroll_bar) \ + - sizeof (EMACS_INT) - sizeof (struct Lisp_Vector *)) \ + / sizeof (Lisp_Object)) + +/* Turning a lisp vector value into a pointer to a struct scroll_bar. */ +#define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec)) + + +/* Building a 32-bit C integer from two 16-bit lisp integers. */ +#define SCROLL_BAR_PACK(low, high) (XINT (high) << 16 | XINT (low)) + +/* Setting two lisp integers to the low and high words of a 32-bit C int. */ +#define SCROLL_BAR_UNPACK(low, high, int32) \ + (XSETINT ((low), (int32) & 0xffff), \ + XSETINT ((high), ((int32) >> 16) & 0xffff)) + + +/* Extract the Mac control handle of the scroll bar from a struct scroll_bar. */ +#define SCROLL_BAR_CONTROL_HANDLE(ptr) \ + ((ControlHandle) SCROLL_BAR_PACK ((ptr)->control_handle_low, (ptr)->control_handle_high)) + +/* Store a Mac control handle in a struct scroll_bar. */ +#define SET_SCROLL_BAR_CONTROL_HANDLE(ptr, id) \ + (SCROLL_BAR_UNPACK ((ptr)->control_handle_low, (ptr)->control_handle_high, (int) id)) + +/* Return the inside width of a vertical scroll bar, given the outside + width. */ +#define VERTICAL_SCROLL_BAR_INSIDE_WIDTH(f,width) \ + ((width) \ + - VERTICAL_SCROLL_BAR_LEFT_BORDER \ + - VERTICAL_SCROLL_BAR_RIGHT_BORDER \ + - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2) + +/* Return the length of the rectangle within which the top of the + handle must stay. This isn't equivalent to the inside height, + because the scroll bar handle has a minimum height. + + This is the real range of motion for the scroll bar, so when we're + scaling buffer positions to scroll bar positions, we use this, not + VERTICAL_SCROLL_BAR_INSIDE_HEIGHT. */ +#define VERTICAL_SCROLL_BAR_TOP_RANGE(f,height) \ + (VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, height) - VERTICAL_SCROLL_BAR_MIN_HANDLE - UP_AND_DOWN_ARROWS) + +/* Return the inside height of vertical scroll bar, given the outside + height. See VERTICAL_SCROLL_BAR_TOP_RANGE too. */ +#define VERTICAL_SCROLL_BAR_INSIDE_HEIGHT(f,height) \ + ((height) - VERTICAL_SCROLL_BAR_TOP_BORDER - VERTICAL_SCROLL_BAR_BOTTOM_BORDER) + + +/* Border widths for scroll bars. + + Scroll bar windows don't have any borders; their border width is + set to zero, and we redraw borders ourselves. This makes the code + a bit cleaner, since we don't have to convert between outside width + (used when relating to the rest of the screen) and inside width + (used when sizing and drawing the scroll bar window itself). + + The handle moves up and down/back and forth in a rectangle inset + from the edges of the scroll bar. These are widths by which we + inset the handle boundaries from the scroll bar edges. */ +#define VERTICAL_SCROLL_BAR_LEFT_BORDER (0) +#define VERTICAL_SCROLL_BAR_RIGHT_BORDER (0) +#define VERTICAL_SCROLL_BAR_TOP_BORDER (0) +#define VERTICAL_SCROLL_BAR_BOTTOM_BORDER (0) + +/* Minimum lengths for scroll bar handles, in pixels. */ +#define VERTICAL_SCROLL_BAR_MIN_HANDLE (16) + +/* Combined length of up and down arrow boxes in scroll bars, in pixels. */ +#define UP_AND_DOWN_ARROWS (32) + +/* Trimming off a few pixels from each side prevents + text from glomming up against the scroll bar */ +#define VERTICAL_SCROLL_BAR_WIDTH_TRIM (0) + + +/* Manipulating pixel sizes and character sizes. + Knowledge of which factors affect the overall size of the window should + be hidden in these macros, if that's possible. + + Return the upper/left pixel position of the character cell on frame F + at ROW/COL. */ +#define CHAR_TO_PIXEL_ROW(f, row) \ + ((f)->output_data.mac->internal_border_width \ + + (row) * (f)->output_data.mac->line_height) +#define CHAR_TO_PIXEL_COL(f, col) \ + ((f)->output_data.mac->internal_border_width \ + + (col) * FONT_WIDTH ((f)->output_data.mac->font)) + +/* Return the pixel width/height of frame F if it has + WIDTH columns/HEIGHT rows. */ +#define CHAR_TO_PIXEL_WIDTH(f, width) \ + (CHAR_TO_PIXEL_COL (f, width) \ + + (f)->output_data.mac->vertical_scroll_bar_extra \ + + (f)->output_data.mac->flags_areas_extra \ + + (f)->output_data.mac->internal_border_width) +#define CHAR_TO_PIXEL_HEIGHT(f, height) \ + (CHAR_TO_PIXEL_ROW (f, height) \ + + (f)->output_data.mac->internal_border_width) + + +/* Return the row/column (zero-based) of the character cell containing + the pixel on FRAME at ROW/COL. */ +#define PIXEL_TO_CHAR_ROW(f, row) \ + (((row) - (f)->output_data.mac->internal_border_width) \ + / (f)->output_data.mac->line_height) +#define PIXEL_TO_CHAR_COL(f, col) \ + (((col) - (f)->output_data.mac->internal_border_width) \ + / FONT_WIDTH ((f)->output_data.mac->font)) + +/* How many columns/rows of text can we fit in WIDTH/HEIGHT pixels on + frame F? */ +#define PIXEL_TO_CHAR_WIDTH(f, width) \ + (PIXEL_TO_CHAR_COL (f, ((width) \ + - (f)->output_data.mac->internal_border_width \ + - (f)->output_data.mac->flags_areas_extra \ + - (f)->output_data.mac->vertical_scroll_bar_extra))) +#define PIXEL_TO_CHAR_HEIGHT(f, height) \ + (PIXEL_TO_CHAR_ROW (f, ((height) \ + - (f)->output_data.mac->internal_border_width))) + +struct frame * check_x_frame (Lisp_Object); + +/* Dummy entry for defining tty_display in frame.c. */ +struct x_output +{ + char _dummy; +}; diff --git a/mac/inc/pwd.h b/mac/inc/pwd.h new file mode 100644 index 00000000000..8e6a5dece34 --- /dev/null +++ b/mac/inc/pwd.h @@ -0,0 +1,37 @@ +/* Replacement pwd.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _PWD_H +#define _PWD_H + +#include + +/* Emacs uses only pw_name and pw_dir: let's just simulate these */ +struct passwd { + char *pw_name; /* user name */ + char *pw_dir; /* home directory */ +}; + +struct passwd *getpwuid(uid_t); +struct passwd *getpwnam(const char *); + +#endif /* _PWD_H */ diff --git a/mac/inc/s-mac.h b/mac/inc/s-mac.h new file mode 100644 index 00000000000..3780664f74e --- /dev/null +++ b/mac/inc/s-mac.h @@ -0,0 +1,320 @@ +/* Handcrafted s-mac.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +/* + * Define symbols to identify the version of Unix this is. + * Define all the symbols that apply correctly. + */ + +/* #define UNIPLUS */ +/* #define USG5 */ +/* #define USG */ +/* #define HPUX */ +/* #define UMAX */ +/* #define BSD4_1 */ +/* #define BSD4_2 */ +/* #define BSD4_3 */ +/* #define BSD_SYSTEM */ +/* #define VMS */ + +/* SYSTEM_TYPE should indicate the kind of system you are using. + It sets the Lisp variable system-type. */ + +#define SYSTEM_TYPE "macos" + +/* NOMULTIPLEJOBS should be defined if your system's shell + does not have "job control" (the ability to stop a program, + run some other program, then continue the first one). */ + +#define NOMULTIPLEJOBS + +/* Emacs can read input using SIGIO and buffering characters itself, + or using CBREAK mode and making C-g cause SIGINT. + The choice is controlled by the variable interrupt_input. + + Define INTERRUPT_INPUT to make interrupt_input = 1 the default (use SIGIO) + + Emacs uses the presence or absence of the SIGIO macro to indicate + whether or not signal-driven I/O is possible. It uses + INTERRUPT_INPUT to decide whether to use it by default. + + SIGIO can be used only on systems that implement it (4.2 and 4.3). + CBREAK mode has two disadvantages + 1) At least in 4.2, it is impossible to handle the Meta key properly. + I hear that in system V this problem does not exist. + 2) Control-G causes output to be discarded. + I do not know whether this can be fixed in system V. + + Another method of doing input is planned but not implemented. + It would have Emacs fork off a separate process + to read the input and send it to the true Emacs process + through a pipe. */ + +/* #define INTERRUPT_INPUT */ + +/* Letter to use in finding device name of first pty, + if system supports pty's. 'a' means it is /dev/ptya0 */ + +/* #define FIRST_PTY_LETTER 'a' */ + +/* + * Define HAVE_TERMIOS if the system provides POSIX-style + * functions and macros for terminal control. + * + * Define HAVE_TERMIO if the system provides sysV-style ioctls + * for terminal control. + * + * Do not define both. HAVE_TERMIOS is preferred, if it is + * supported on your system. + */ + +/* #define HAVE_TERMIOS */ +#define HAVE_TERMIO + +/* + * Define HAVE_PTYS if the system supports pty devices. + */ + +/* #define HAVE_PTYS */ + +/* + * Define NONSYSTEM_DIR_LIBRARY to make Emacs emulate + * The 4.2 opendir, etc., library functions. + */ + +/* #define NONSYSTEM_DIR_LIBRARY */ + +/* Define this symbol if your system has the functions bcopy, etc. */ + +/* #define BSTRING */ + +/* subprocesses should be defined if you want to + have code for asynchronous subprocesses + (as used in M-x compile and M-x shell). + This is generally OS dependent, and not supported + under most USG systems. */ + +/* #define subprocesses */ + +/* If your system uses COFF (Common Object File Format) then define the + preprocessor symbol "COFF". */ + +/* #define COFF */ + +/* define MAIL_USE_FLOCK if the mailer uses flock + to interlock access to /usr/spool/mail/$USER. + The alternative is that a lock file named + /usr/spool/mail/$USER.lock. */ + +/* #define MAIL_USE_FLOCK */ + +/* Define CLASH_DETECTION if you want lock files to be written + so that Emacs can tell instantly when you try to modify + a file that someone else has modified in his Emacs. */ + +/* #define CLASH_DETECTION */ + +/* Define this if your operating system declares signal handlers to + have a type other than the usual. `The usual' is `void' for ANSI C + systems (i.e. when the __STDC__ macro is defined), and `int' for + pre-ANSI systems. If you're using GCC on an older system, __STDC__ + will be defined, but the system's include files will still say that + signal returns int or whatever; in situations like that, define + this to be what the system's include files want. */ +/* #define SIGTYPE int */ + +/* If the character used to separate elements of the executable path + is not ':', #define this to be the appropriate character constant. */ +/* #define SEPCHAR ':' */ + +/* ============================================================ */ + +/* Here, add any special hacks needed + to make Emacs work on this system. For example, + you might define certain system call names that don't + exist on your system, or that do different things on + your system and must be used only through an encapsulation + (Which you should place, by convention, in sysdep.c). */ + +/* Some compilers tend to put everything declared static + into the initialized data area, which becomes pure after dumping Emacs. + On these systems, you must #define static as nothing to foil this. + Note that emacs carefully avoids static vars inside functions. */ + +/* #define static */ + +/* ============================================================ */ + +/* After adding support for a new system, modify the large case + statement in the `configure' script to recognize reasonable + configuration names, and add a description of the system to + `etc/MACHINES'. + + If you've just fixed a problem in an existing configuration file, + you should also check `etc/MACHINES' to make sure its descriptions + of known problems in that configuration should be updated. */ + +#ifdef __MRC__ +#define __signal_max SIGTERM /* largest one in signal.h */ +#endif + +#define SIGHUP (__signal_max+1) +#define SIGQUIT (__signal_max+2) +#define SIGTRAP (__signal_max+3) +#define SIGKILL (__signal_max+4) +#define SIGALRM (__signal_max+5) +#define SIGPIPE (__signal_max+6) +#define NSIG (__signal_max+6) + +#ifdef __MRC__ +#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base) +#elif __MWERKS__ +#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->buffer_ptr - (FILE)->buffer) +#endif + +#ifdef __MWERKS__ +#include +#ifndef ENOENT +#define ENOENT 100 +#endif +#ifndef EXDEV +#define EXDEV 101 +#endif +#ifndef EEXIST +#define EEXIST 102 +#endif +#ifndef EINTR +#define EINTR 102 +#endif +#ifndef EACCES +#define EACCES 103 +#endif +#ifndef ENOTDIR +#define ENOTDIR 104 +#endif +#ifndef EIO +#define EIO 105 +#endif +#ifndef EBADF +#define EBADF 106 +#endif +#endif + +#define SYSTEM_PURESIZE_EXTRA (200*1024) + +/* don't know what this will do, but sysdep.c needs it */ +#define DATA_START 0 + +/* Limited by CW's 32K limit on local data! */ +#define READ_BUF_SIZE (8 << 10) + +#include +void read_input_waiting (); + +/* #define GETTIMEOFDAY_ONE_ARGUMENT */ + +#define SYSV_SYSTEM_DIR + +#define SYSTEM_MALLOC + +/* Constants such as O_RDONLY are defined in fcntl.h. Best solution is + really to patch individual files to include it: callproc.c, doc.c, + fileio.c, getloadavg.c, lread.c, and termcap.c. */ +#include + +#define _setjmp setjmp +#define _longjmp longjmp + +#define _exit exit + +#define main emacs_main + +/* Include this here so it won't be include again when #include in emacs + sources. Then undefine the macro definitions in it for unlink, read, + write, access, and rmdir. */ +#ifdef __MWERKS__ +#include +#endif + +#undef unlink +#define unlink sys_unlink +#undef read +#define read sys_read +#undef write +#define write sys_write +#undef access +#define access sys_access +#undef rmdir +#define rmdir sys_rmdir + +#define open sys_open +#define creat sys_creat + +#define rename sys_rename +#define fopen sys_fopen +#define signal sys_signal + +#define gmtime sys_gmtime +#define localtime sys_localtime +#define ctime sys_ctime +#define time sys_time + +#ifndef bcmp +#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) +#endif +#ifndef bcopy +#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#endif +#ifndef bzero +#define bzero(s, n) memset ((s), 0, (n)) +#endif + +extern char *index (const char *, int); + +/* MPW strftime broken for "%p" format */ +#ifdef __MRC__ +#define strftime sys_strftime +#endif + +#include +/* Editfns.c includes types.h which indirectly includes time.h before config.h. + So gmtime (localtime) is defined and not sys_gmtime (sys_localtime). Define + here explicitly. */ +extern struct tm *sys_gmtime (const time_t *); +extern struct tm *sys_localtime (const time_t *); +extern char *sys_ctime (const time_t *); +extern time_t sys_time (time_t *); + +/* Emacs.c includes signal.h before config.h. Define this to make it happy. */ +#ifdef __MRC__ +#include +extern __sigfun sys_signal (int signal_num, __sigfun signal_func); +#elif __MWERKS__ +#include +extern __signal_func_ptr sys_signal (int signal_num, __signal_func_ptr signal_func); +#endif + +extern double atof (const char *); + +#define volatile + +#define SYMS_SYSTEM syms_of_mac() diff --git a/mac/inc/sys/file.h b/mac/inc/sys/file.h new file mode 100644 index 00000000000..c37d7006d48 --- /dev/null +++ b/mac/inc/sys/file.h @@ -0,0 +1,59 @@ +/* Replacement sys/file.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _SYS_FILE_H +#define _SYS_FILE_H + +#include +#include +#include + +#ifdef __MRC__ +#undef open +#undef creat + +#define open mpw_open +#define creat mpw_creat + +#include + +#undef open +#undef creat + +#define open sys_open +#define creat sys_creat +#endif + +#ifdef __MWERKS__ +#include +#endif + +mode_t umask(mode_t); + +void abort(void); +void _exit(int); +int kill(int,int); +int alarm(int); +int pause(void); +char *getwd(char *); + +#endif /* _SYS_FILE_H */ diff --git a/mac/inc/sys/ioctl.h b/mac/inc/sys/ioctl.h new file mode 100644 index 00000000000..116e7bf5b06 --- /dev/null +++ b/mac/inc/sys/ioctl.h @@ -0,0 +1,31 @@ +/* Replacement sys/ioctl.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +int ioctl(int, int, void *); + +#define FIONREAD 1 +#define TCGETA 2 + +#endif /* _SYS_IOCTL_H */ diff --git a/mac/inc/sys/param.h b/mac/inc/sys/param.h new file mode 100644 index 00000000000..7a39b149366 --- /dev/null +++ b/mac/inc/sys/param.h @@ -0,0 +1,28 @@ +/* Replacement sys/param.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#define MAXPATHLEN 255 + +#endif /* _SYS_PARAM_H */ diff --git a/mac/inc/sys/stat.h b/mac/inc/sys/stat.h new file mode 100644 index 00000000000..fe3dc5df669 --- /dev/null +++ b/mac/inc/sys/stat.h @@ -0,0 +1,86 @@ +/* Replacement sys/stat.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#ifdef __MWERKS__ +#include + +#ifdef CODEWARRIOR_VERSION_6 +#define fstat _fstat +#endif + +#undef S_IFMT +#undef S_IFBLK +#undef S_IFCHR +#undef S_IFIFO +#undef S_IFREG +#undef S_IFDIR +#undef S_IFLNK + +#undef S_IRUSR +#undef S_IWUSR +#undef S_IXUSR + +#endif /* __MWERKS__ */ + +/* Need to redefine these for CW, filemode.c assumes Unix definitions which are + inconsistent with CW definitions because CW uses bits 8-12 for S_IFMT info. + Bit 8 is used by S_IRUSR on Unix! */ +#define S_IFMT 0170000 /* type of file */ +#define S_IFBLK 0060000 /* block special */ +#define S_IFCHR 0020000 /* character special */ +#define S_IFIFO 0010000 /* FIFO special */ +#define S_IFREG 0100000 /* regular */ +#define S_IFDIR 0040000 /* directory */ +#define S_IFLNK 0030000 /* symbolic link */ + +#define S_IREAD 00400 +#define S_IWRITE 00200 +#define S_IEXEC 00100 + +/* Need to redefine these for because mode_string in filemode.c assumes Unix + values in the lower 9 bits which are different from CW values. */ +#define S_IRUSR S_IREAD +#define S_IWUSR S_IWRITE +#define S_IXUSR S_IEXEC + +#ifdef __MRC__ +typedef unsigned long dev_t; + +struct stat { + dev_t st_dev; /* ID of device containing file */ + int st_ino; /* file serial number */ + unsigned short st_mode; /* mode of file */ + int st_nlink; /* number of links to the file */ + int st_uid; /* user ID of file */ + int st_gid; /* group ID of file */ + int st_rdev; /* device ID (if file is character or block special) */ + int st_size; /* file size in bytes (if file is a regular file) */ + int st_atime; /* time of last access */ + int st_mtime; /* time of last data modification */ + int st_ctime; /* time of last status change */ +}; +#endif /* __MRC__ */ + +#endif /* _SYS_STAT_H */ diff --git a/mac/inc/sys/time.h b/mac/inc/sys/time.h new file mode 100644 index 00000000000..5c55c09b5cd --- /dev/null +++ b/mac/inc/sys/time.h @@ -0,0 +1,31 @@ +/* Replacement sys/time.h file for building GNU Emacs on the Macintosh. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _SYS_TIME_H +#define _SYS_TIME_H + +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + +#endif /* _SYS_TYPES_H */ diff --git a/mac/inc/sys/types.h b/mac/inc/sys/types.h new file mode 100644 index 00000000000..71eb976f3b2 --- /dev/null +++ b/mac/inc/sys/types.h @@ -0,0 +1,40 @@ +/* Replacement sys/types.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#ifdef __MWERKS__ +/* Need definitions of uid_t from stat.h */ +#include +#endif /* __MWERKS__ */ + +#ifdef __MRC__ +typedef long uid_t; +typedef long gid_t; +typedef long off_t; +typedef long ino_t; + +typedef unsigned long mode_t; +#endif /* __MRC__ */ + +#endif /* _SYS_TYPES_H */ diff --git a/mac/inc/termio.h b/mac/inc/termio.h new file mode 100644 index 00000000000..3f194e59af4 --- /dev/null +++ b/mac/inc/termio.h @@ -0,0 +1,68 @@ +/* Replacement termio.h file for building GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _SYS_TERMIO_H +#define _SYS_TERMIO_H + +typedef unsigned char cc_t; +typedef unsigned short tcflag_t; + +#define NCCS 32 + +struct termio { + tcflag_t c_iflag; /* input modes */ + tcflag_t c_oflag; /* output modes */ + tcflag_t c_cflag; /* control modes */ + tcflag_t c_lflag; /* local modes */ + cc_t c_cc[NCCS]; /* control chars */ +}; + +/* c_cc subscript names */ +#define VINTR 1 +#define VQUIT 2 +#define VERASE 3 +#define VTIME 4 +#define VMIN 5 + +/* c_iflag fields */ +#define IGNBRK 0x1 /* ignore break condition */ +#define ICRNL 0x2 /* map CR to NL on input */ +#define IXON 0x4 /* enable start/stop output control */ + +/* c_oflag fields */ +#define ONLCR 0x1 /* map CR to NL on output */ +#define TABDLY 0x2 /* horizontal tab delays */ +#define TAB3 0x4 /* expand tab to spaces */ + +/* c_cflag fields */ +#define CBAUD 0x1 +#define B9600 0x2 + +/* c_lflag fields */ +#define ISIG 0x1 /* enable signals */ +#define ICANON 0x2 /* canonical input (erase and kill processing) */ +#define ECHO 0x3 /* enable echo */ + +#define TCSETAW 4 +#define TCSETAF 5 + +#endif /* _SYS_TERMIO_H */ diff --git a/mac/inc/utime.h b/mac/inc/utime.h new file mode 100644 index 00000000000..8cb65ec5f80 --- /dev/null +++ b/mac/inc/utime.h @@ -0,0 +1,37 @@ +/* Replacement utime.h file for building GNU Emacs on the Macintosh. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _UTIME_H_ +#define _UTIME_H_ + +#include + +#define _mac_unix_epoch_offset_ (365L * 4L) * 24L * 60L * 60L + +struct utimbuf { + time_t actime; /* access time (ignored on the Mac) */ + time_t modtime; /* modification time */ +}; + +int utime(const char *path, const struct utimbuf *buf); + +#endif diff --git a/mac/inc/utsname.h b/mac/inc/utsname.h new file mode 100644 index 00000000000..fec32be7421 --- /dev/null +++ b/mac/inc/utsname.h @@ -0,0 +1,32 @@ +/* Replacement utsname.h file for building GNU Emacs on the Macintosh. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#ifndef _UTSNAME_H +#define _UTSNAME_H + +struct utsname { + char nodename[255]; +}; + +int uname(struct utsname *name); + +#endif diff --git a/mac/makefile.MPW b/mac/makefile.MPW new file mode 100644 index 00000000000..f460f5a1735 --- /dev/null +++ b/mac/makefile.MPW @@ -0,0 +1,1127 @@ +# Make file for building GNU Emacs on the Macintosh. +# Copyright (C) 1999, 2000 Free Software Foundation, Inc. +# +# Author: Andrew Choi +# +# This file is part of GNU Emacs. +# +# GNU Emacs is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Emacs; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. */ +# +# Defines the following targets: +# Emacs (default) - normal Emacs build. +# Clean - remove all object and executable files to prepare for a fresh build. +# Doc - generate the "DOC" file in ~emacs/etc/. +# Make-DocFile - build the make-docfile tool, utility for generating "DOC". +# PrepSource - prepare the source files after unstuffing the distribution. +# PrepDist - prepare for distribution: generate diff files; move mac-win.el to {Patches}. + +Src = ::src: # emacs's src directory +Includes = :inc: # mac includes directory (common for MPW and CW) +Source = :src: # mac source directory +Lib-Src = ::lib-src: # ~emacs/lib-src directory, containing make-docfile.c +EmacsTarget = :Emacs MPW # pathname of target executable file +DocTarget = ::etc: # where the generated DOC file should be placed +Lisp = ::lisp: # emacs's lisp directory +Make-DocFileDir = {Lib-Src} # directory containing make-docfile tool + +Makefile = makefile.MPW # self reference + +SymOption = # -sym on # remove hash mark before "-sym on" to enable source debugging +OptOption = # -opt speed # alternatively set to -opt off or -opt size + +# The -noMapCR options and the two -d's must not be removed. + +PPCCOptions = {SymOption} {OptOption} -noMapCR -enum int ¶ + -typecheck relaxed -w off ¶ + -includes unix -i {Includes},{Src} ¶ + -d emacs=1 -d HAVE_CONFIG_H + +LinkOptions = {SymOption} -d + +CONFIG_H_GROUP = "{Includes}config.h" "{Includes}s-mac.h" "{Includes}utsname.h" "{Includes}m-mac.h" +DISPEXTERN_H_GROUP = "{Src}dispextern.h" "{Includes}macgui.h" +INTERVALS_H_GROUP = "{Src}intervals.h" "{Src}dispextern.h" "{Includes}macgui.h" +WINDOW_H_GROUP = "{Src}window.h" {DISPEXTERN_H_GROUP} +BLOCKINPUT_H_GROUP = "{Src}blockinput.h" "{Src}atimer.h" "{Src}systime.h" ¶ + "{Includes}sys:time.h" "{Includes}sys:time.h" + +# The list all object files from the GNU Emacs 21.0 distribution. + +EmacsObjects = ¶ + "{Src}abbrev.c.x" ¶ + "{Src}alloc.c.x" ¶ + "{Src}alloca.c.x" ¶ + "{Src}atimer.c.x" ¶ + "{Src}buffer.c.x" ¶ + "{Src}bytecode.c.x" ¶ + "{Src}callint.c.x" ¶ + "{Src}callproc.c.x" ¶ + "{Src}casefiddle.c.x" ¶ + "{Src}casetab.c.x" ¶ + "{Src}category.c.x" ¶ + "{Src}ccl.c.x" ¶ + "{Src}charset.c.x" ¶ + "{Src}cm.c.x" ¶ + "{Src}cmds.c.x" ¶ + "{Src}coding.c.x" ¶ + "{Src}composite.c.x" ¶ + "{Src}data.c.x" ¶ + "{Src}dired.c.x" ¶ + "{Src}dispnew.c.x" ¶ + "{Src}doc.c.x" ¶ + "{Src}doprnt.c.x" ¶ + "{Src}editfns.c.x" ¶ + "{Src}emacs.c.x" ¶ + "{Src}eval.c.x" ¶ + "{Src}fileio.c.x" ¶ + "{Src}filemode.c.x" ¶ + "{Src}floatfns.c.x" ¶ + "{Src}fns.c.x" ¶ + "{Src}fontset.c.x" ¶ + "{Src}frame.c.x" ¶ + "{Src}getloadavg.c.x" ¶ + "{Src}indent.c.x" ¶ + "{Src}insdel.c.x" ¶ + "{Src}intervals.c.x" ¶ + "{Src}keyboard.c.x" ¶ + "{Src}keymap.c.x" ¶ + "{Src}lread.c.x" ¶ + "{Src}macros.c.x" ¶ + "{Src}marker.c.x" ¶ + "{Src}minibuf.c.x" ¶ + "{Src}mktime.c.x" ¶ + "{Src}mocklisp.c.x" ¶ + "{Src}print.c.x" ¶ + "{Src}process.c.x" ¶ + "{Src}regex.c.x" ¶ + "{Src}region-cache.c.x" ¶ + "{Src}scroll.c.x" ¶ + "{Src}search.c.x" ¶ + "{Src}strftime.c.x" ¶ + "{Src}syntax.c.x" ¶ + "{Src}sysdep.c.x" ¶ + "{Src}term.c.x" ¶ + "{Src}termcap.c.x" ¶ + "{Src}textprop.c.x" ¶ + "{Src}tparam.c.x" ¶ + "{Src}undo.c.x" ¶ + "{Src}window.c.x" ¶ + "{Src}xdisp.c.x" ¶ + "{Src}xfaces.c.x" + +# The list of object files generated from new source files of the Macintosh port. + +MacObjects = ¶ + "{Source}mac.c.x" ¶ + "{Source}macfns.c.x" ¶ + "{Source}macmenu.c.x" ¶ + "{Source}macterm.c.x" + +# The next two are the dependency rules for building Emacs. + +Emacs ÄÄ {Makefile} {DocTarget}DOC {EmacsObjects} {MacObjects} + PPCLink ¶ + {LinkOptions} ¶ + {EmacsObjects} {MacObjects} ¶ + "{SharedLibraries}InterfaceLib" ¶ + "{SharedLibraries}StdCLib" ¶ + "{SharedLibraries}MathLib" ¶ + "{SharedLibraries}AppleScriptLib" ¶ + "{SharedLibraries}TextEncodingConverter" ¶ + "{SharedLibraries}AppearanceLib" ¶ + "{PPCLibraries}StdCRuntime.o" ¶ + "{PPCLibraries}PPCCRuntime.o" ¶ + "{PPCLibraries}PPCToolLibs.o" ¶ + -o "{EmacsTarget}" + +Emacs ÄÄ {Makefile} "{Source}"Emacs.maclf.r "{Source}"EmacsMPW.maclf.r + Rez -a "{Source}"Emacs.maclf.r -o "{EmacsTarget}" + Rez -a "{Source}"EmacsMPW.maclf.r -o "{EmacsTarget}" + SetFile "{EmacsTarget}" -t APPL -c 'EMAx' -a B + +# Rez cannot handle files with Unix style end lines at all. So generate +# them. It does not hurt if Emacs.r and EmacsMPW.r already have Mac end +# lines. + +"{Source}"Emacs.maclf.r Ä "{Source}"Emacs.r + translate ¶0x0a ¶n < "{Source}"Emacs.r > "{Source}"Emacs.maclf.r + +"{Source}"EmacsMPW.maclf.r Ä "{Source}"EmacsMPW.r + translate ¶0x0a ¶n < "{Source}"EmacsMPW.r > "{Source}"EmacsMPW.maclf.r + +# Here comes a long boring list of rules saying which files depend on which +# other ones. I generated them by hand using the "-p" option of the MrC compiler. +# Know about MakeMake, but this is probably more accurate. + +{Src}abbrev.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}charset.h" ¶ + "{Src}syntax.h" + +{Src}alloc.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}puresize.h" ¶ + "{Src}buffer.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}frame.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}keyboard.h" ¶ + "{Src}charset.h" ¶ + "{Src}syssignal.h" + +{Src}alloca.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {BLOCKINPUT_H_GROUP} + +{Src}atimer.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}syssignal.h" ¶ + "{Src}systime.h" ¶ + "{Includes}sys:time.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}atimer.h" ¶ + "{Includes}sys:time.h" + +{Src}buffer.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Includes}sys:param.h" ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}window.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}region-cache.h" ¶ + "{Src}indent.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}frame.h" + +{Src}bytecode.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}syntax.h" + +{Src}callint.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}commands.h" ¶ + "{Src}keyboard.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}mocklisp.h" + +{Src}callproc.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:file.h" ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}ccl.h" ¶ + "{Src}coding.h" ¶ + "{Src}composite.h" ¶ + "{Includes}epaths.h" ¶ + "{Src}process.h" ¶ + "{Src}syssignal.h" ¶ + "{Src}systty.h" ¶ + "{Includes}termio.h" + +{Src}casefiddle Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}commands.h" ¶ + "{Src}syntax.h" ¶ + "{Src}composite.h" + +{Src}casetab.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" + +{Src}category.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}category.h" + +{Src}ccl.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}charset.h" ¶ + "{Src}ccl.h" ¶ + "{Src}coding.h" + +{Src}charset.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + "{Src}disptab.h" + +{Src}cm.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}cm.h" ¶ + "{Src}termhooks.h" + +{Src}cmds.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}syntax.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}keyboard.h" ¶ + {DISPEXTERN_H_GROUP} + +{Src}coding.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}composite.h" ¶ + "{Src}ccl.h" ¶ + "{Src}coding.h" ¶ + {WINDOW_H_GROUP} + +{Src}composite.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + {INTERVALS_H_GROUP} + +{Src}data.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}puresize.h" ¶ + "{Src}charset.h" ¶ + "{Src}buffer.h" ¶ + "{Src}keyboard.h" ¶ + "{Src}frame.h" ¶ + "{Src}syssignal.h" + +{Src}dired.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Src}systime.h" ¶ + "{Includes}sys:time.h" ¶ + "{Includes}dirent.h" ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}commands.h" ¶ + "{Src}charset.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + "{Src}regex.h" + +{Src}dispnew.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}termchar.h" ¶ + "{Src}termopts.h" ¶ + "{Src}termhooks.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}cm.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}commands.h" ¶ + "{Src}disptab.h" ¶ + "{Src}indent.h" ¶ + {INTERVALS_H_GROUP} ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}process.h" ¶ + "{Src}keyboard.h" ¶ + "{Src}syssignal.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" ¶ + "{Src}systime.h" + +{Src}doc.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:file.h" ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}keyboard.h" ¶ + "{Src}charset.h" + +{Src}doprnt.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}charset.h" + +{Src}editfns.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}pwd.h" ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}systime.h" ¶ + "{Includes}sys:time.h" + +{Src}emacs.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:file.h" ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}systty.h" ¶ + "{Includes}termio.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}syssignal.h" ¶ + "{Src}process.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}keyboard.h" ¶ + "{Src}frame.h" + +{Src}eval.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}commands.h" ¶ + "{Src}keyboard.h" ¶ + {DISPEXTERN_H_GROUP} + +{Src}fileio.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Includes}pwd.h" ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}systime.h" ¶ + "{Includes}sys:time.h" ¶ + "{Src}commands.h" + +{Src}filemode.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" + +{Src}floatfns.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}syssignal.h" + +{Src}fns.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + "{Src}charset.h" ¶ + "{Src}buffer.h" ¶ + "{Src}keyboard.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} + +{Src}fontset.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}ccl.h" ¶ + "{Src}frame.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}fontset.h" ¶ + {WINDOW_H_GROUP} + +{Src}frame.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}charset.h" ¶ + "{Src}fontset.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" ¶ + "{Src}frame.h" ¶ + "{Src}fontset.h" ¶ + "{Src}termhooks.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + {WINDOW_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}commands.h" ¶ + "{Src}keyboard.h" + +{Src}getloadavg.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" + +{Src}indent.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}category.h" ¶ + "{Src}indent.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}termchar.h" ¶ + "{Src}termopts.h" ¶ + "{Src}disptab.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}region-cache.h" + +{Src}insdel.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + {WINDOW_H_GROUP} ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}region-cache.h" + +{Src}intervals.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}puresize.h" ¶ + "{Src}keyboard.h" + +{Src}keyboard.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}termchar.h" ¶ + "{Src}termopts.h" ¶ + "{Src}lisp.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}macros.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}keyboard.h" ¶ + "{Src}syntax.h" ¶ + {INTERVALS_H_GROUP} ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}puresize.h" ¶ + "{Src}systime.h" ¶ + "{Src}atimer.h" ¶ + "{Includes}sys:ioctl.h" ¶ + "{Src}syssignal.h" ¶ + "{Src}systty.h" ¶ + "{Includes}termio.h" ¶ + "{Includes}sys:types.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" ¶ + "{Src}systime.h" + +{Src}keymap.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}keyboard.h" ¶ + "{Src}termhooks.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}puresize.h" ¶ + {INTERVALS_H_GROUP} + +{Src}lread.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Includes}sys:file.h" ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Includes}epaths.h" ¶ + "{Src}commands.h" ¶ + "{Src}keyboard.h" ¶ + "{Src}termhooks.h" + +{Src}macros.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}macros.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}keyboard.h" + +{Src}marker.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" + +{Src}minibuf.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}syntax.h" ¶ + "{Src}keyboard.h" + +{Src}mktime.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" + +{Src}mocklisp.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" + +{Src}print.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}process.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}termchar.h" ¶ + "{Src}keyboard.h" ¶ + {INTERVALS_H_GROUP} + +{Src}process.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Src}lisp.h" ¶ + "{Src}systime.h" ¶ + "{Includes}sys:time.h" ¶ + "{Src}charset.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + "{Src}termopts.h" ¶ + "{Src}sysselect.h" + +{Src}regex.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}syntax.h" ¶ + "{Src}charset.h" ¶ + "{Src}category.h" ¶ + "{Src}regex.h" + +{Src}region-cache.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}region-cache.h" + +{Src}scroll.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}termchar.h" ¶ + "{Src}lisp.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} + +{Src}search.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}syntax.h" ¶ + "{Src}category.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}region-cache.h" ¶ + "{Src}commands.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + {INTERVALS_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Src}regex.h" + +{Src}strftime.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:time.h" + +{Src}syntax.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}commands.h" ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}syntax.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}category.h" + +{Src}sysdep.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Includes}sys:ioctl.h" ¶ + "{Src}syswait.h" ¶ + "{Includes}sys:types.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}termhooks.h" ¶ + "{Src}termchar.h" ¶ + "{Src}termopts.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}process.h" ¶ + "{Src}syssignal.h" ¶ + "{Src}systime.h" ¶ + "{Includes}utime.h" ¶ + "{Src}sysselect.h" ¶ + "{Includes}dirent.h" ¶ + "{Includes}sys:types.h" + +{Src}term.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}termchar.h" ¶ + "{Src}termopts.h" ¶ + "{Src}lisp.h" ¶ + "{Src}charset.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + "{Src}frame.h" ¶ + "{Src}disptab.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}keyboard.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + {WINDOW_H_GROUP} ¶ + "{Src}cm.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" + +{Src}termcap.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Includes}sys:file.h" + +{Src}textproc.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}buffer.h" ¶ + {WINDOW_H_GROUP} + +{Src}tparam.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" + +{Src}undo.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}commands.h" + +{Src}window.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}buffer.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}commands.h" ¶ + "{Src}indent.h" ¶ + "{Src}termchar.h" ¶ + "{Src}disptab.h" ¶ + "{Src}keyboard.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + {BLOCKINPUT_H_GROUP} ¶ + {INTERVALS_H_GROUP} ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" + +{Src}xdisp.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}termchar.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Src}charset.h" ¶ + "{Src}indent.h" ¶ + "{Src}commands.h" ¶ + "{Src}macros.h" ¶ + "{Src}disptab.h" ¶ + "{Src}termhooks.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}keyboard.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + "{Src}process.h" ¶ + "{Src}region-cache.h" ¶ + "{Src}fontset.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" + +{Src}xfaces.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Src}lisp.h" ¶ + "{Src}charset.h" ¶ + "{Src}frame.h" ¶ + "{Src}fontset.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" ¶ + "{Src}buffer.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + {BLOCKINPUT_H_GROUP} ¶ + {WINDOW_H_GROUP} ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}keyboard.h" + +{Src}macmenu.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}keyboard.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}buffer.h" ¶ + "{Includes}sys:types.h" ¶ + {DISPEXTERN_H_GROUP} + +{Source}mac.c Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Includes}utime.h" ¶ + "{Includes}dirent.h" ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Includes}pwd.h" ¶ + "{Includes}sys:types.h" ¶ + "{Includes}sys:param.h" ¶ + "{Src}lisp.h" ¶ + "{Src}process.h" ¶ + "{Src}sysselect.h" ¶ + "{Src}systime.h" ¶ + "{Includes}sys:time.h" ¶ + "{Includes}utsname.h" + +{Source}macfns.c Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}charset.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" ¶ + "{Src}frame.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}buffer.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}fontset.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}keyboard.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Includes}epaths.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + "{Src}systime.h" ¶ + "{Src}bitmaps:gray.xbm" + +{Source}macterm.c Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + {BLOCKINPUT_H_GROUP} ¶ + "{Src}syssignal.h" ¶ + "{Includes}macterm.h" ¶ + "{Includes}macgui.h" ¶ + "{Src}frame.h" ¶ + "{Includes}alloca.h" ¶ + "{Includes}sys:types.h" ¶ + "{Src}systty.h" ¶ + "{Includes}termio.h" ¶ + "{Src}systime.h" ¶ + "{Includes}sys:stat.h" ¶ + "{Src}charset.h" ¶ + "{Src}ccl.h" ¶ + "{Src}frame.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}fontset.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}termopts.h" ¶ + "{Src}termchar.h" ¶ + "{Src}gnu.h" ¶ + "{Src}disptab.h" ¶ + "{Src}buffer.h" ¶ + {WINDOW_H_GROUP} ¶ + "{Src}keyboard.h" ¶ + {INTERVALS_H_GROUP} ¶ + "{Src}process.h" ¶ + "{Src}atimer.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + "{Includes}epaths.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" + + +#----------------------------------------# +# Variables and rules for target "Clean" # +#----------------------------------------# + +Clean Ä + Delete -i {EmacsObjects} {MacObjects} + Delete -i "{EmacsTarget}" + Delete -i stdout stderr + Delete -i {Make-DocFile-Objects} {Make-DocFileDir}make-docfile + Delete -i "{Source}"Emacs.maclf.r "{Source}"EmacsMPW.maclf.r + +DistClean Ä Clean + Delete -i "Emacs CW"Ã… + Delete -y "emacs Data" + Delete -i emacs.mcp + +#--------------------------------------# +# Variables and rules for target "Doc" # +#--------------------------------------# + +EmacsSource = ¶ + "{Src}abbrev.c" ¶ + "{Src}alloc.c" ¶ + "{Src}alloca.c" ¶ + "{Src}atimer.c" ¶ + "{Src}buffer.c" ¶ + "{Src}bytecode.c" ¶ + "{Src}callint.c" ¶ + "{Src}callproc.c" ¶ + "{Src}casefiddle.c" ¶ + "{Src}casetab.c" ¶ + "{Src}category.c" ¶ + "{Src}ccl.c" ¶ + "{Src}charset.c" ¶ + "{Src}cm.c" ¶ + "{Src}cmds.c" ¶ + "{Src}coding.c" ¶ + "{Src}composite.c" ¶ + "{Src}data.c" ¶ + "{Src}dired.c" ¶ + "{Src}dispnew.c" ¶ + "{Src}doc.c" ¶ + "{Src}doprnt.c" ¶ + "{Src}editfns.c" ¶ + "{Src}emacs.c" ¶ + "{Src}eval.c" ¶ + "{Src}fileio.c" ¶ + "{Src}filemode.c" ¶ + "{Src}floatfns.c" ¶ + "{Src}fns.c" ¶ + "{Src}fontset.c" ¶ + "{Src}frame.c" ¶ + "{Src}getloadavg.c" ¶ + "{Src}indent.c" ¶ + "{Src}insdel.c" ¶ + "{Src}intervals.c" ¶ + "{Src}keyboard.c" ¶ + "{Src}keymap.c" ¶ + "{Src}lread.c" ¶ + "{Src}macros.c" ¶ + "{Src}marker.c" ¶ + "{Src}minibuf.c" ¶ + "{Src}mktime.c" ¶ + "{Src}mocklisp.c" ¶ + "{Src}print.c" ¶ + "{Src}process.c" ¶ + "{Src}regex.c" ¶ + "{Src}region-cache.c" ¶ + "{Src}scroll.c" ¶ + "{Src}search.c" ¶ + "{Src}strftime.c" ¶ + "{Src}syntax.c" ¶ + "{Src}sysdep.c" ¶ + "{Src}term.c" ¶ + "{Src}termcap.c" ¶ + "{Src}textprop.c" ¶ + "{Src}tparam.c" ¶ + "{Src}undo.c" ¶ + "{Src}window.c" ¶ + "{Src}xdisp.c" ¶ + "{Src}xfaces.c" ¶ + "{Src}xmenu.c" + +MacSource = ¶ + "{Source}mac.c" ¶ + "{Source}macfns.c" ¶ + "{Source}macterm.c" + + +LispSource = ¶ + {Lisp}menu-bar.el ¶ + {Lisp}mouse.el ¶ + {Lisp}select.el ¶ + {Lisp}scroll-bar.el ¶ + {Lisp}vmsproc.el ¶ + {Lisp}vms-patch.el ¶ + {Lisp}ls-lisp.el ¶ + {Lisp}dos-fns.el ¶ + {Lisp}w32-fns.el ¶ + {Lisp}dos-w32.el ¶ + {Lisp}disp-table.el ¶ + {Lisp}dos-vars.el ¶ + {Lisp}international:ccl.el ¶ + {Lisp}international:codepage.el ¶ + {Lisp}abbrev.el ¶ + {Lisp}buff-menu.el ¶ + {Lisp}byte-run.el ¶ + {Lisp}cus-start.el ¶ + {Lisp}custom.el ¶ + {Lisp}emacs-lisp:lisp-mode.el ¶ + {Lisp}emacs-lisp:lisp.el ¶ + {Lisp}facemenu.el ¶ + {Lisp}faces.el ¶ + {Lisp}files.el ¶ + {Lisp}float-sup.el ¶ + {Lisp}format.el ¶ + {Lisp}frame.el ¶ + {Lisp}help.el ¶ + {Lisp}indent.el ¶ + {Lisp}isearch.el ¶ + {Lisp}loadup.el ¶ + {Lisp}loaddefs.el ¶ + {Lisp}bindings.el ¶ + {Lisp}map-ynp.el ¶ + {Lisp}international:mule.el ¶ + {Lisp}international:mule-conf.el ¶ + {Lisp}international:mule-cmds.el ¶ + {Lisp}international:characters.el ¶ + {Lisp}case-table.el ¶ + {Lisp}language:chinese.el ¶ + {Lisp}language:cyrillic.el ¶ + {Lisp}language:indian.el ¶ + {Lisp}language:devanagari.el ¶ + {Lisp}language:english.el ¶ + {Lisp}language:ethiopic.el ¶ + {Lisp}language:european.el ¶ + {Lisp}language:czech.el ¶ + {Lisp}language:slovak.el ¶ + {Lisp}language:romanian.el ¶ + {Lisp}language:greek.el ¶ + {Lisp}language:hebrew.el ¶ + {Lisp}language:japanese.el ¶ + {Lisp}language:korean.el ¶ + {Lisp}language:lao.el ¶ + {Lisp}language:thai.el ¶ + {Lisp}language:tibetan.el ¶ + {Lisp}language:vietnamese.el ¶ + {Lisp}language:misc-lang.el ¶ + {Lisp}paths.el ¶ + {Lisp}register.el ¶ + {Lisp}replace.el ¶ + {Lisp}simple.el ¶ + {Lisp}startup.el ¶ + {Lisp}subr.el ¶ + {Lisp}term:tty-colors.el ¶ + {Lisp}textmodes:fill.el ¶ + {Lisp}textmodes:page.el ¶ + {Lisp}textmodes:paragraphs.el ¶ + {Lisp}textmodes:text-mode.el ¶ + {Lisp}vc-hooks.el ¶ + {Lisp}ediff-hook.el ¶ + {Lisp}widget.el ¶ + {Lisp}window.el ¶ + {Lisp}version.el + + +Doc Ä {DocTarget}DOC + +{DocTarget}DOC Ä {Makefile} {EmacsSource} {MacSource} {LispSource} {Make-DocFileDir}Make-DocFile + {Make-DocFileDir}make-docfile {EmacsSource} > {DocTarget}DOC + {Make-DocFileDir}make-docfile {MacSource} >> {DocTarget}DOC + {Make-DocFileDir}make-docfile {LispSource} >> {DocTarget}DOC + + +#-----------------------------------------------# +# Variables and rules for target "Make-DocFile" # +#-----------------------------------------------# + +Make-DocFile-Includes = -i :inc: +Make-DocFile-Sym = + +Make-DocFile-PPCCOptions = -typecheck relaxed -w off -noMapCR ¶ + {Make-DocFile-Includes} {Make-DocFile-Sym} + +Make-DocFile-Objects = ¶ + "{Lib-Src}make-docfile.c.x" ¶ + "{Source}chdir.c.x" + +Make-DocFile Ä {Make-DocFileDir}Make-DocFile + +{Make-DocFileDir}Make-DocFile Ä {Makefile} {Make-DocFile-Objects} + PPCLink ¶ + -o {Make-DocFileDir}Make-DocFile ¶ + {Make-DocFile-Sym} ¶ + {Make-DocFile-Objects} ¶ + -t 'MPST' ¶ + -c 'MPS ' ¶ + "{SharedLibraries}InterfaceLib" ¶ + "{SharedLibraries}StdCLib" ¶ + "{SharedLibraries}MathLib" ¶ + "{PPCLibraries}StdCRuntime.o" ¶ + "{PPCLibraries}PPCCRuntime.o" ¶ + "{PPCLibraries}PPCToolLibs.o" + +"{Lib-Src}make-docfile.c.x" Ä {Makefile} "{Lib-Src}make-docfile.c" + {PPCC} "{Lib-Src}make-docfile.c" -o "{Lib-Src}make-docfile.c.x" {Make-DocFile-PPCCOptions} + +"{Source}chdir.c.x" Ä {Makefile} "{Source}chdir.c" + {PPCC} "{Source}chdir.c" -o "{Source}chdir.c.x" {Make-DocFile-PPCCOptions} + diff --git a/mac/src/Emacs.r b/mac/src/Emacs.r new file mode 100644 index 00000000000..4a66d7cf49c --- /dev/null +++ b/mac/src/Emacs.r @@ -0,0 +1,700 @@ +/* Resource definitions for GNU Emacs on the Macintosh. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include "Types.r" +/* added for finder icon balloon help --ben */ +#include "Balloons.r" + +/* Define to use gnu icon */ +/* #define GNU_ICON 1 */ + +resource 'STR#' (128) { + { + "TERM=macterm", + "TERMCAP=macterm:co#80:li#40:up=up:do=do:le=le:nd=nd:cm=cm:cs=cs:ce=ce:cd=cd:cl=cl:al=al:dl=dl:", + /* "HOME=/Ix/Data Files/Emacs Mac Port/emacs-20.4/mac/", */ + /* "MAIL=/Ix/System Folder/Eudora Folder/In" */ + } +}; + +resource 'STR#' (129) { + { + "emacs", + "-l", + "loadup" + } +}; + +/* added for finder icon balloon help --ben */ +resource 'hfdr' (-5696) { /*help for emacs icon*/ + /*header component*/ + HelpMgrVersion, hmDefaultOptions, 0, 0, + { /*icon component*/ + HMSTRResItem { /*use 'STR ' resource 128*/ + 128 + } + } +}; + +/* added for finder icon balloon help --ben */ +resource 'STR ' (128) { /*help message for emacs icon*/ + "GNU Emacs\0xd1the extensible, customizable, self-documenting real-time display editor." +}; + +resource 'MENU' (128, preload) { + 128, + textMenuProc, + 0x7FFFFFFD, + enabled, + apple, + { /* array: 2 elements */ + /* [1] */ + "About Emacs\0xc9", noIcon, noKey, noMark, plain, + /* [2] */ + "-", noIcon, noKey, noMark, plain + } +}; + +resource 'MBAR' (128, "MBAR for Menus1", preload) { + { /* array MenuArray: 1 element */ + /* [1] */ + 128 + } +}; + +resource 'WIND' (128, "Window", purgeable) { + {68, 33, 554, 754}, + kWindowFullZoomGrowDocumentProc, + invisible, + goAway, + 0x0, + "Terminal", + kWindowStaggerMainScreen +}; + +resource 'WIND' (129, "Terminal window", purgeable) { + {32, 8, 76, 620}, + kWindowModalDialogProc, + invisible, + goAway, + 0x0, + "Terminal", + kWindowDefaultPosition +}; + +resource 'WIND' (130, "Dialog window", purgeable) { + {32, 8, 42, 18}, + kWindowModalDialogProc, + invisible, + goAway, + 0x0, + "Terminal", + kWindowDefaultPosition +}; + +resource 'ALRT' (128, "About Box", purgeable) { + {40, 20, 160, 297}, + 128, + { /* array: 4 elements */ + /* [1] */ + OK, visible, silent, + /* [2] */ + OK, visible, silent, + /* [3] */ + OK, visible, silent, + /* [4] */ + OK, visible, silent + }, + centerMainScreen +}; + +resource 'DITL' (128, purgeable) { + { /* array DITLarray: 2 elements */ + /* [1] */ + {88, 185, 108, 265}, + Button { + enabled, + "OK" + }, + /* [2] */ + {10, 60, 72, 278}, + StaticText { + disabled, + "GNU Emacs 21.0.90 for Mac OS\n" + "(11 October 2000 release)\n" + "Report bugs to akochoi@users.sourceforge.net" + } + } +}; + +resource 'BNDL' (128) { + 'EMAx', + 0, + { /* array TypeArray: 2 elements */ + /* [1] */ + 'FREF', + { /* array IDArray: 2 elements */ + /* [1] */ + 0, 128, + /* [2] */ + 1, 129 + }, + /* [2] */ + 'ICN#', + { /* array IDArray: 2 elements */ + /* [1] */ + 0, 128, + /* [2] */ + 1, 129 + } + } +}; + +resource 'FREF' (128) { + 'APPL', + 0, + "" +}; + +resource 'FREF' (129) { + 'TEXT', + 1, + "" +}; + +resource 'vers' (1) { + 0x1, + 0x0, + development, + 0x0, + 0, + "d6", + "GNU Emacs 21.1 for Mac OS\n\0xa9 2" + "000 Free Software Foundation" +}; + +data 'EMAx' (0, "Owner resource") { + $"00" /* . */ +}; + +#ifdef GNU_ICON +resource 'ICN#' (128) { + { /* array: 2 elements */ + /* [1] */ + $"0000 0000 0000 0000 0000 0080 0000 0040" + $"0100 0030 0203 5808 0408 8400 0418 0220" + $"0420 0008 0464 9C80 04C1 0018 0000 0004" + $"118B 0120 000A 0000 0614 8180 0204 2080" + $"0468 0080 0480 4480 0000 0080 0148 08C0" + $"0120 00C0 0182 4020 0388 0120 0181 2040" + $"01E8 B040 00E0 70C0 0078 9880 003A 9880" + $"001E 4000 000F C0", + /* [2] */ + $"0000 0000 0000 0100 0000 0180 0000 00E0" + $"0100 3030 0203 F818 063F FC18 0E3F FE38" + $"1C7F FF78 1CFF FFF8 1CFF FFF8 1E7F FFFC" + $"1FFF FF38 1FFF FF80 0FFF FF80 07FF FF80" + $"0FFF FF80 0FFF FFC0 01FF FFC0 03FF FFC0" + $"03FF FFC0 03FF FFE0 03FF FFE0 03FF FFE0" + $"01FF FFC0 01FF FFC0 00FF FFC0 007F FF80" + $"001F E700 000F C000 0004 80" + } +}; +#else +resource 'ICN#' (128) { + { /* array: 2 elements */ + /* [1] */ + $"0000 0000 0000 0000 0001 F000 07DE 0F60" + $"0860 0090 1200 0028 1200 0008 0800 0008" + $"0800 0008 1000 0004 1000 0004 2000 0004" + $"2000 0044 4018 12C2 4018 0002 4018 0082" + $"4002 0C42 2000 1E02 2004 1E42 2004 0C02" + $"2004 0042 2002 0082 5001 8F05 8800 7004" + $"0800 0008 0400 0010 0200 0060 01C0 0380" + $"003F FC00 2000 0000 4000 0000 80", + /* [2] */ + $"0000 0000 0000 0000 0001 F000 07DF FF60" + $"0FFF FFF0 1FFF FFF8 1FFF FFF8 0FFF FFF8" + $"0FFF FFF8 1FFF FFFC 1FFF FFFC 3FFF FFFC" + $"3FFF FFFC 7FFF FFFE 7FFF FFFE 7FFF FFFE" + $"7FFF FFFE 3FFF FFFE 3FFF FFFE 3FFF FFFE" + $"3FFF FFFE 3FFF FFFE 7FFF FFFF FFFF FFFF" + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" + } +}; +#endif + +#ifdef GNU_ICON +resource 'icl4' (128) { + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 000C 0000 0000" + $"0000 0000 0000 0000 0000 000C F000 0000" + $"0000 0000 0000 0000 0000 0000 CFD0 0000" + $"0000 000F 0000 0000 00CC 0000 00FF 0000" + $"0000 00F0 0000 00FF CFCF F000 000C F000" + $"0000 0FD0 00CD FD0C F000 CF00 000C D000" + $"0000 CFC0 00DF F000 C000 00F0 00FC C000" + $"000C DF00 0DFD 0CD0 0000 DCDD 0DC0 F000" + $"000D 0F00 DFFC 0F00 FDDF FFDD FC0D D000" + $"000C 0F00 FFC0 DCDF 0000 DC00 00CF F000" + $"000C 0CD0 0C0C CDC0 000C 0CCD CCCC CF00" + $"000F 00CF F0DC FCFF DDC0 CDDF 00FD C000" + $"000D D000 CDC0 FCFC 0CDC CCCD C000 0000" + $"0000 CFF0 D00F 0F0C F0CD CCCF F000 0000" + $"0000 0CFC 00CD 0F0D D0FD CCCD F000 0000" + $"0000 CFCC DFF0 FC0C DCCC CCCC F000 0000" + $"0000 DFC0 FDDC 0C0C DFC0 CEDC FC00 0000" + $"0000 000C DDCC CDC0 C00C CCCC FC00 0000" + $"0000 00CF CF0C FC0C 0000 F00D FF00 0000" + $"0000 00CF D0FC 0CCC C000 0CCC FF00 0000" + $"0000 00CF F0DC 0CFC CFCD DDDC DCF0 0000" + $"0000 00FF FCD0 FDCC DDC0 00DF 0DF0 0000" + $"0000 00CF FDCD 0DCF CDFC CC0D 0FC0 0000" + $"0000 000F FFFC FCD0 F0FF C000 DF00 0000" + $"0000 000C FFF0 CDCD DFFF DCCC FF00 0000" + $"0000 0000 CFFF FC0D F0CF F000 FC00 0000" + $"0000 0000 0CFF FDF0 F0DF FDDD F000 0000" + $"0000 0000 000F FFFC CFC0 0DDD 0000 0000" + $"0000 0000 0000 FFFF FF00 0000 0000 0000" + $"0000 0000 0000 0C00 C0" +}; +#else +resource 'icl4' (128) { + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 000F FFFF 0000 0000 0000" + $"0000 0FFF FF0F FFF0 0000 FFFF 0FF0 0000" + $"0000 FCCC CFF0 0000 0000 0000 FCCF 0000" + $"000F 0DED CC00 0000 0000 0000 0DEC F000" + $"000F 0DED C000 0000 0000 0000 00DD F000" + $"0000 F0D0 0000 0000 0000 0000 0000 F000" + $"0000 FC00 0000 0000 0000 0000 0000 F000" + $"000F 0000 0000 0000 0000 0000 0000 0F00" + $"000F 0000 0000 0000 0000 0000 0000 0F00" + $"00F0 0000 0000 0000 0000 0000 0000 0F00" + $"00F0 0000 0000 0000 0000 0000 DEC0 0F00" + $"0F00 0000 00CE EC00 0CCC CCCC FFC0 00F0" + $"0F00 0000 0CDF FD0C C000 000D CDC0 00F0" + $"0F00 0000 00CE ECD0 0000 CC00 D000 00F0" + $"0F00 0000 0000 00D0 000C EEC0 0D00 00F0" + $"00F0 0000 0000 0D00 00CE AAEC 0D00 00F0" + $"00F0 0000 0000 0D00 00CE AAEC 0D00 00F0" + $"00F0 0000 0000 0D00 000C EEC0 0D00 00F0" + $"00F0 0000 0000 0D00 0000 CC00 0D00 00F0" + $"00F0 0000 0000 0CD0 0000 0000 E000 00F0" + $"0F0F 0000 0000 00CD D000 EEEE 0000 0F0F" + $"F000 F000 0000 0000 0EEE 0000 0000 0F00" + $"0000 F000 0000 0000 0000 0D00 0000 FC00" + $"0000 0F00 0000 0000 0000 0D00 000F C000" + $"0000 00F0 0000 0000 0000 0C00 0FFC C000" + $"0000 C00F FF00 0000 0000 00EE ECCC 0000" + $"000D 0000 0CFF FFFF FEEE EECC CCC0 0000" + $"0CF0 0000 0000 CCCC CCCC CC0C 0C00 0C00" + $"CEC0 0000 0000 0000 0000 0000 0000 0DC0" + $"FD00 0000 0000 0000 0000 0000 0000 00D0" +}; +#endif + +#ifdef GNU_ICON +resource 'icl8' (128) { + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 002B 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 002B FF00 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 2BFF F900 0000 0000" + $"0000 0000 0000 00FF 0000 0000 0000 0000" + $"0000 2B2B 0000 0000 0000 FFFF 0000 0000" + $"0000 0000 0000 FF00 0000 0000 0000 FFFF" + $"2BFF 2BFF FF00 0000 0000 002B FF00 0000" + $"0000 0000 00FF F900 0000 2BF9 FFF9 002B" + $"FF00 0000 2BFF 0000 0000 002B F900 0000" + $"0000 0000 2BFF 2B00 0000 F9FF FF00 0000" + $"2B00 0000 0000 FF00 0000 FF2B 2B00 0000" + $"0000 002B F9FF 0000 00F9 FFF9 002B F900" + $"0000 0000 F92B F9F9 00F9 2B00 FF00 0000" + $"0000 00F9 00FF 0000 F9FF FF2B 00FF 0000" + $"FFF9 F9FF FFFF F9F9 FF2B 00F9 F900 0000" + $"0000 002B 00FF 0000 FFFF 2B00 F92B F9FF" + $"0000 0000 F92B 0000 0000 2BFF FF00 0000" + $"0000 002B 002B F900 002B 002B 2BF9 2B00" + $"0000 002B 002B 2BF9 2B2B 2B2B 2BFF 0000" + $"0000 00FF 0000 2BFF FF00 F92B FF2B FFFF" + $"F9F9 2B00 2BF9 F9FF 0000 FFF9 2B00 0000" + $"0000 00F9 F900 0000 2BF9 2B00 FF2B FF2B" + $"002B F92B 2B2B 2BF9 2B00 0000 0000 0000" + $"0000 0000 2BFF FF00 F900 00FF 00FF 002B" + $"FF00 2BF9 2B2B 2BFF FF00 0000 0000 0000" + $"0000 0000 002B FF2B 0000 2BF9 00FF 00F9" + $"F900 FFF9 2B2B 2BF9 FF00 0000 0000 0000" + $"0000 0000 2BFF 2B2B F9FF FF00 FF2B 002B" + $"F92B 2B2B 2B2B 2B2B FF00 0000 0000 0000" + $"0000 0000 F9FF 2B00 FFF9 F92B 002B 002B" + $"F9FF 2B00 2BFC F92B FF2B 0000 0000 0000" + $"0000 0000 0000 002B F9F9 2B2B 2BF9 2B00" + $"2B00 002B 2B2B 2B2B FF2B 0000 0000 0000" + $"0000 0000 0000 2BFF 2BFF 002B FF2B 002B" + $"0000 0000 FF00 00F9 FFFF 0000 0000 0000" + $"0000 0000 0000 2BFF F900 FF2B 002B 2B2B" + $"2B00 0000 002B 2B2B FFFF 0000 0000 0000" + $"0000 0000 0000 2BFF FF00 F92B 002B FF2B" + $"2BFF 2BF9 F9F9 F92B F92B FF00 0000 0000" + $"0000 0000 0000 FFFF FF2B F900 FFF9 2B2B" + $"F9F9 2B00 0000 F9FF 00F9 FF00 0000 0000" + $"0000 0000 0000 2BFF FFF9 2BF9 00F9 2BFF" + $"2BF9 FF2B 2B2B 00F9 00FF 2B00 0000 0000" + $"0000 0000 0000 00FF FFFF FF2B FF2B F900" + $"FF00 FFFF 2B00 0000 F9FF 0000 0000 0000" + $"0000 0000 0000 002B FFFF FF00 2BF9 2BF9" + $"F9FF FFFF F92B 2B2B FFFF 0000 0000 0000" + $"0000 0000 0000 0000 2BFF FFFF FF2B 00F9" + $"FF00 2BFF FF00 0000 FF2B 0000 0000 0000" + $"0000 0000 0000 0000 002B FFFF FFF9 FF00" + $"FF00 F9FF FFF9 F9F9 FF00 0000 0000 0000" + $"0000 0000 0000 0000 0000 00FF FFFF FF2B" + $"2BFF 2B00 00F9 F9F9 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 FFFF FFFF" + $"FFFF 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 002B 0000" + $"2B" +}; +#else +resource 'icl8' (128) { + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 00FF" + $"FFFF FFFF 0000 0000 0000 0000 0000 0000" + $"0000 0000 00FF FFFF FFFF F5FF FFFF FFF5" + $"F5F5 F5F5 FFFF FFFF 00FF FF00 0000 0000" + $"0000 0000 FFF6 F6F6 F6FF FFF5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 FFF7 F6FF 0000 0000" + $"0000 00FF F5F9 FBF9 F7F7 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F9 FCF6 FF00 0000" + $"0000 00FF F5F9 FBF9 F7F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F9F9 FF00 0000" + $"0000 0000 FFF5 F9F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FF00 0000" + $"0000 0000 FFF7 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 FF00 0000" + $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5FF 0000" + $"0000 00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5FF 0000" + $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5FF 0000" + $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F9FC F6F5 F5FF 0000" + $"00FF F5F5 F5F5 F5F5 F5F5 F7FB FBF7 F5F5" + $"F5F6 F6F7 F7F7 F7F8 FFFF F7F5 F5F5 FF00" + $"00FF F5F5 F5F5 F5F5 F5F6 F9FF FFF9 F5F7" + $"F7F5 F5F5 F5F5 F5F9 F7F9 F6F5 F5F5 FF00" + $"00FF F5F5 F5F5 F5F5 F5F5 F7FB FCF7 F9F5" + $"F5F5 F5F5 F6F6 F5F5 F9F5 F5F5 F5F5 FF00" + $"00FF F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F9F5" + $"F5F5 F5F7 FBFB F7F5 F5F9 F5F5 F5F5 FF00" + $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5" + $"F5F5 F7FB FDFD ACF7 F5F9 F5F5 F5F5 FF00" + $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5" + $"F5F5 F7FB FDFD ACF7 F5F9 F5F5 F5F5 FE00" + $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5" + $"F5F5 F5F7 FBFB F7F5 F5F9 F5F5 F5F5 FE00" + $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5" + $"F5F5 F5F5 F7F7 F5F5 F5FA F5F5 F5F5 FE00" + $"0000 FFF5 F5F5 F5F5 F5F5 F5F5 F5F7 F9F5" + $"F5F5 F5F5 F5F5 F5F5 FBF5 F5F5 F5F5 FF00" + $"00FF F5FF F5F5 F5F5 F5F5 F5F5 F5F5 F7F9" + $"F9F5 F5F5 FBFB FBFB F5F5 F5F5 F5FE F5FF" + $"FFF5 F5F5 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5FB FBFB F5F5 F5F5 F5F5 F5F5 F5FF F5F5" + $"F5F5 F5F5 FFF5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F9 F5F5 F5F5 F5F5 FFF6 F5F5" + $"F5F5 F5F5 F5FF F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F9 F5F5 F5F5 F5FF F6F5 F5F5" + $"F5F5 F5F5 F5F5 FFF5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F6 F5F5 F5FF FFF7 F6F5 F5F5" + $"F5F5 F5F5 F7F5 F5FF FFFF F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 ACAC ACF7 F6F6 F5F5 F5F5" + $"F5F5 F5F9 F5F5 F5F5 F5F7 FFFF FFFF FFFF" + $"FFFC FCAC ACAC F6F6 F7F6 F6F5 F5F5 F5F5" + $"F5F6 FFF5 F5F5 F5F5 F5F5 F5F5 F6F7 F6F7" + $"F6F7 F6F6 F6F6 F5F6 F5F6 F5F5 F5F7 F5F5" + $"F6FC F7F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F9 F7F5" + $"FFF9 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F9F5" +}; +#endif + +#ifdef GNU_ICON +resource 'ics#' (128) { + { /* array: 2 elements */ + /* [1] */ + $"0000 0008 11E6 26B4 2EEA 2906 5B14 36D8" + $"2EA8 1A28 1D8C 1B5C 1EC8 0FE8 0780", + /* [2] */ + $"0010 001C 11FE 37FE 7FFE 7FFE 7FFE 3FF8" + $"3FF8 1FF8 1FFC 1FFC 1FF8 0FF8 07F0 0280" + } +}; +#else +resource 'ics#' (128) { + { /* array: 2 elements */ + /* [1] */ + $"0000 0000 0001 604B 6000 6002 0831 0078" + $"1079 1030 1001 0802 063C 01C0", + /* [2] */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" + } +}; +#endif + +#ifdef GNU_ICON +resource 'ics4' (128) { + $"0000 0000 000C 0000 0000 0000 000C FD00" + $"000F 000F FFF0 0FF0 00FD 0FFC F0FF 0FD0" + $"0DF0 FFFD FFFD FDF0 0CFD FCDF 0CDD CFF0" + $"0FDF FDFF DDDF CFC0 00FF DFFD FFCF F000" + $"00FC FFFC FCED F000 000F FCFC CCFD F000" + $"000F FFCF FDDD FF00 000F FDFF DFCF FF00" + $"000F FFFD FFDC F000 0000 FFFF FFFD F000" + $"0000 0FFF FCDD 0000 0000 00C0 C0" +}; +#else +resource 'ics4' (128) { + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 00DE CEEC 000C CCCC CCFF" + $"DFFD 0CC0 0000 0DCD CEEC D000 00CC 00D0" + $"0000 D000 0CEE C00D 000D 0000 CEAA EC0D" + $"000D 0000 CEAA EC0D 000D 0000 0CEE C00D" + $"000D 0000 00CC 000D 000C D000 0000 00E0" + $"0000 CDD0 00EE EE00 0000 000E EE00 0000" + $"0000 0000 000D 0000 0000 0000 000D" +}; +#endif + +#ifdef GNU_ICON +resource 'ics8' (128) { + $"0000 0000 0000 0000 0000 002B 0000 0000" + $"0000 0000 0000 0000 0000 002B FFF9 0000" + $"0000 00FF 0000 00FF FFFF FF00 00FF FF00" + $"0000 FFF9 00FF FF2B FF00 FFFF 00FF F900" + $"00F9 FF00 FFFF FFF9 FFFF FFF9 FFF9 FF00" + $"002B FFF9 FF2B F9FF 002B F9F9 2BFF FF00" + $"00FF F9FF FFF9 FFFF F9F9 F9FF 2BFF 2B00" + $"0000 FFFF F9FF FFF9 FFFF 2BFF FF00 0000" + $"0000 FF2B FFFF FF2B FF2B FCF9 FF00 0000" + $"0000 00FF FF2B FF2B 2B2B FFF9 FF00 0000" + $"0000 00FF FFFF 2BFF FFF9 F9F9 FFFF 0000" + $"0000 00FF FFF9 FFFF F9FF 2BFF FFFF 0000" + $"0000 00FF FFFF FFF9 FFFF F92B FF00 0000" + $"0000 0000 FFFF FFFF FFFF FFF9 FF00 0000" + $"0000 0000 00FF FFFF FF2B F9F9 0000 0000" + $"0000 0000 0000 2B00 2B" +}; +#else +resource 'ics8' (128) { + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F5F5 F9FC" + $"F7FB FBF7 F5F5 F5F6 F6F7 F7F7 F7F8 FFFF" + $"F9FF FFF9 F5F7 F7F5 F5F5 F5F5 F5F9 F7F9" + $"F7FB FCF7 F9F5 F5F5 F5F5 F6F6 F5F5 F9F5" + $"F5F5 F5F5 F9F5 F5F5 F5F7 FBFB F7F5 F5F9" + $"F5F5 F5F9 F5F5 F5F5 F7FB FDFD ACF7 F5F9" + $"F5F5 F5F9 F5F5 F5F5 F7FB FDFD ACF7 F5F9" + $"F5F5 F5F9 F5F5 F5F5 F5F7 FBFB F7F5 F5F9" + $"F5F5 F5F9 F5F5 F5F5 F5F5 F7F7 F5F5 F5FA" + $"F5F5 F5F7 F9F5 F5F5 F5F5 F5F5 F5F5 FBF5" + $"F5F5 F5F5 F7F9 F9F5 F5F5 FBFB FBFB F5F5" + $"F5F5 F5F5 F5F5 F5FB FBFB F5F5 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5 F5F5" + $"F5F5 F5F5 F5F5 F5F5 F5F5 F5F9 F5F5 F5F5" +}; +#endif + +resource 'ICN#' (129) { + { /* array: 2 elements */ + /* [1] */ + $"0000 0300 0000 1C80 0000 E0B0 0007 00F0" + $"0038 0070 01C0 0038 0E00 8038 7008 4038" + $"8008 2038 8004 0038 8080 041C C086 301C" + $"C087 311C 4007 BB8C 6167 378C 6170 070E" + $"2130 6006 3031 FC06 3047 FE06 10E7 FF02" + $"1867 FF82 1847 FF03 080F FE07 0C1F E03C" + $"0C0F C1F0 0406 0F80 0400 7C00 0203 E000" + $"031F 0000 01F8 0000 00C0", + /* [2] */ + $"0000 0300 0000 1F80 0000 FFB0 0007 FFF0" + $"003F FFF0 01FF FFF8 0FFF FFF8 7FFF FFF8" + $"FFFF FFF8 FFFF FFF8 FFFF FFFC FFFF FFFC" + $"FFFF FFFC 7FFF FFFC 7FFF FFFC 7FFF FFFE" + $"3FFF FFFE 3FFF FFFE 3FFF FFFE 1FFF FFFE" + $"1FFF FFFE 1FFF FFFF 0FFF FFFF 0FFF FFFC" + $"0FFF FFF0 07FF FF80 07FF FC00 03FF E000" + $"03FF 0000 01F8 0000 00C0" + } +}; + +resource 'icl4' (129) { + $"0000 0000 0000 0000 0000 00FF 0000 0000" + $"0000 0000 0000 0000 000F FF0C F000 0000" + $"0000 0000 0000 0000 FFF0 0000 F0FF 0000" + $"0000 0000 0000 0FFF 0000 0000 FFDF 0000" + $"0000 0000 00FF F000 0000 0000 CFEF 0000" + $"0000 000F FF00 0000 0000 0000 00ED F000" + $"0000 FFF0 0000 0000 DC00 0000 00AD F000" + $"0FFF 0000 0000 E000 0DC0 0000 00FE F000" + $"F000 0000 0000 DC00 0CD0 0000 00FE F000" + $"F000 0000 CC00 CC00 00C0 0C00 00FA F000" + $"F000 0000 D000 00C0 00C0 0DCC 00CF EF00" + $"EF00 0000 E000 0EED C0ED C0DD 000F EF00" + $"EFC0 0000 DC00 CEEF CCEF D0DD 000F AF00" + $"DFC0 000C 00C0 CEFE D0EF D0ED E00C FF00" + $"0EFC 00CD 0EDC 0DDE 00DF CDEE EC00 FF00" + $"0EFC 000E 0DEE 00CC 00CC CDFE D000 FFF0" + $"0DFC 000D CCFE C00C DEDD 0CDC 0000 CFF0" + $"00EF C00C 0CDE 00CE FFFF AE00 0000 0FF0" + $"00EF C000 DD0C 0DEE FFFF FEED C000 0FF0" + $"00DF C000 DFE0 CDFF FFFF FFAF C000 0CF0" + $"000E FC00 DEE0 CAFF FFFF FFFE D000 0CFD" + $"000E FC00 CED0 DEFF FFFF FFFE C000 0CFF" + $"000D FC00 0C0C EFFF FFFF AEDD 00CC CFFF" + $"0000 EF00 000D EFFF FADD C00C CCFF FED0" + $"0000 EF00 000C FAFF AED0 CCCF FFEE D000" + $"0000 DF00 000C DEED CCCC FFFE ED00 0000" + $"0000 0E00 0000 0CCC CFFF EED0 0000 0000" + $"0000 0DFD 0000 CCFF FEED 0000 0000 0000" + $"0000 00EF DDDF FFEE D000 0000 0000 0000" + $"0000 000E FFFE ED00 0000 0000 0000 0000" + $"0000 0000 DDD0" +}; + +resource 'icl8' (129) { + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 FFFF 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 00FF FFFF 00F7 FF00 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"FFFF FF00 0000 0000 FF00 FFFF 0000 0000" + $"0000 0000 0000 0000 0000 0000 00FF FFFF" + $"0000 0000 0000 0000 FFFF FAFF 0000 0000" + $"0000 0000 0000 0000 0000 FFFF FF00 0000" + $"0000 0000 0000 0000 F7FF FCFF 0000 0000" + $"0000 0000 0000 00FF FFFF 0000 0000 0000" + $"F500 0000 0000 0000 0000 FCFA FF00 0000" + $"0000 0000 FFFF FF00 0000 0000 0000 0000" + $"812B 0000 0000 0000 0000 FDFA FF00 0000" + $"00FF FFFF 0000 0000 0000 0000 FBF5 0000" + $"0081 2B00 0000 0000 0000 FFFC FF00 0000" + $"FF00 0000 0000 0000 00F5 0000 F9F8 0000" + $"00F8 FA00 0000 0000 0000 FFFC FF00 0000" + $"FF00 0000 0000 0000 F8F8 0000 F7F8 0000" + $"00F5 2B00 002B 0000 0000 FFFD FF00 0000" + $"FF00 0000 0000 00F5 FA00 0000 00F5 F800" + $"0000 2B00 00FA F8F6 0000 F7FF FCFF 0000" + $"FCFF 0000 0000 0000 FB00 0000 00FB FCF9" + $"F600 FBFA F700 5656 0000 00FF FCFF 0000" + $"FCFF F700 0000 0000 81F6 0000 F8FC ACFE" + $"F72B ACFE 5600 F9FA 0000 00FF FDFF 0000" + $"F9FF F700 0000 F5F7 F500 F600 2BAC FEFC" + $"FA00 FCFF 81F5 FB81 FBF5 00F7 FFFF 0000" + $"00FC FFF6 0000 2B81 00FC 81F8 0081 81FC" + $"F500 FAFF 2B81 ACFC FCF6 0000 FFFF 0000" + $"00FC FFF6 0000 00FB 0081 FCAC F500 F82B" + $"0000 F8F8 2B81 FFAC F900 0000 FFFF FF00" + $"00F9 FFF6 0000 0081 F6F8 FFAC F700 00F8" + $"F9FC FA56 00F6 562B 0000 0000 F7FF FF00" + $"0000 FCFF F700 00F7 002B FAFB F500 F7FC" + $"FEFF FFFF FDFB F500 0000 0000 00FF FF00" + $"0000 FCFF F700 0000 F9FA F5F8 0081 FCAC" + $"FFFF FFFF FFFC AC56 2B00 0000 00FF FF00" + $"0000 F9FF F700 0000 81FF AC00 F781 FFFF" + $"FFFF FFFF FFFF FDFE F800 0000 00F7 FF00" + $"0000 00FC FFF7 0000 56FC FBF5 F7FD FFFF" + $"FFFF FFFF FFFF FFAC 8100 0000 00F6 FFF9" + $"0000 00FC FFF7 0000 2BAC 5600 F9FC FFFF" + $"FFFF FFFF FFFF FFFB F700 0000 00F7 FFFF" + $"0000 00F9 FFF7 0000 F5F6 002B FBFE FFFF" + $"FFFF FFFE FDFC FA56 0000 F7F7 F7FF FFFF" + $"0000 0000 FCFF 0000 0000 00FA ACFF FFFF" + $"FFFD 8156 2BF5 00F7 F7F7 FFFF FFFC F900" + $"0000 0000 FCFF 0000 0000 00F7 FEFD FFFE" + $"FDFC F900 F7F7 F7FF FFFF FCFC F900 0000" + $"0000 0000 F9FF 0000 0000 00F6 56AC FBF9" + $"F7F6 F7F7 FFFF FFFC FCF9 0000 0000 0000" + $"0000 0000 00FC 0000 0000 0000 002B F7F7" + $"F7FF FFFF FCFC F900 0000 0000 0000 0000" + $"0000 0000 00F9 FFF9 0000 0000 F7F7 FFFF" + $"FFFC FCF9 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 FCFF F9F9 F9FF FFFF FCFC" + $"F900 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 00FC FFFF FFFC FCF9 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 FAFA F9" +}; + +resource 'ics#' (129) { + { /* array: 2 elements */ + /* [1] */ + $"0030 01CC 0E04 7006 8006 8006 8352 4412" + $"44C3 49F1 2BF1 23C7 23B8 01C0 1E", + /* [2] */ + $"0030 01FC 0FFC 7FFE FFFE FFFE FFFE 7FFE" + $"7FFF 7FFF 3FFF 3FFF 3FF8 3FC0 1E" + } +}; + +resource 'ics4' (129) { + $"0000 0000 0CFF C000 0000 0CCF FFC0 EE00" + $"00CC FFFC 0000 CEC0 CFFF C0C0 C000 0ED0" + $"F000 C0C0 CC00 0FD0 F000 C0CD 0CCC 0DA0" + $"FC0C C0DF CACD CCF0 DF0C DFCD 0DDA C0FC" + $"CF0C CD0C EEDC 00EF 0FC0 FCCF FFFE C0DF" + $"0DF0 DCDF FFFA C0CF 0CF0 0CAF FEDC CFFD" + $"00F0 0CEE DCFF FDC0 00CD 00CF FFDC 0000" + $"000D FFFD C000 0000 0000 CC" +}; + +resource 'ics8' (129) { + $"0000 0000 0000 0000 F5F7 FFFF 2BF5 0000" + $"0000 0000 00F6 F7FF FFFF F600 ACAC 0000" + $"0000 F6F7 FFFF FFF6 0000 0000 F8AC F700" + $"2BFF FFFF F600 F600 F8F5 0000 00AC FA00" + $"FFF5 0000 F6F5 F700 F6F6 F500 F5FE FA00" + $"FFF5 00F5 F700 F756 F5F8 2BF7 0081 FDF5" + $"FF2B 00F6 F700 FAFE F7FD F8FA 2BF7 FF00" + $"56FF 00F7 56FF 2B56 F556 56FD F800 FEF7" + $"2BFF F5F6 F7FA F5F8 ACFC F92B 0000 FBFF" + $"00FF F700 FFF8 F8FE FFFF FFFC F600 56FF" + $"0056 FF00 FAF7 81FF FFFF FFFD 2B00 F6FF" + $"002B FFF5 002B FDFF FFFC 56F7 F7FF FF81" + $"0000 FFF5 00F6 FCFB FAF7 FFFF FFF9 F600" + $"0000 F8F9 0000 F7FF FFFF F9F6 0000 0000" + $"0000 0081 FFFF FFF9 F600 0000 0000 0000" + $"0000 0000 F8F6" +}; diff --git a/mac/src/EmacsMPW.r b/mac/src/EmacsMPW.r new file mode 100644 index 00000000000..c4ff17f9914 --- /dev/null +++ b/mac/src/EmacsMPW.r @@ -0,0 +1,47 @@ +/* Resource definitions for GNU Emacs on the Macintosh when building + under MPW. + + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include "Types.r" +#include "CodeFragmentTypes.r" + +resource 'SIZE' (-1) { + reserved, + acceptSuspendResumeEvents, + reserved, + canBackground, + doesActivateOnFGSwitch, + backgroundAndForeground, + dontGetFrontClicks, + ignoreAppDiedEvents, + is32BitCompatible, + isHighLevelEventAware, + onlyLocalHLEvents, + notStationeryAware, + dontUseTextEditServices, + reserved, + reserved, + reserved, + 16777216, + 16777216 +}; diff --git a/mac/src/chdir.c b/mac/src/chdir.c new file mode 100644 index 00000000000..5bf9354b4f5 --- /dev/null +++ b/mac/src/chdir.c @@ -0,0 +1,43 @@ +/* Implementation of chdir on the Mac for use with make-docfile. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include +#include +#include + +int chdir(const char *path) +{ + WDPBRec wdpb; + + Str255 mypath; + OSErr error; + + strcpy(mypath, path); + c2pstr(mypath); + + wdpb.ioNamePtr = mypath; + wdpb.ioVRefNum = 0; + wdpb.ioWDDirID = 0; + error = PBHSetVolSync(&wdpb); + + return error == noErr ? 0 : -1; +} diff --git a/mac/src/mac.c b/mac/src/mac.c new file mode 100644 index 00000000000..08d2aa2d8bb --- /dev/null +++ b/mac/src/mac.c @@ -0,0 +1,2637 @@ +/* Unix emulation routines for GNU Emacs on the Mac OS. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#if __MWERKS__ +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lisp.h" +#include "process.h" +#include "sysselect.h" +#include "systime.h" + +Lisp_Object QCLIPBOARD; + +/* An instance of the AppleScript component. */ +static ComponentInstance as_scripting_component; +/* The single script context used for all script executions. */ +static OSAID as_script_context; + + +/* When converting from Mac to Unix pathnames, /'s in folder names are + converted to :'s. This function, used in copying folder names, + performs a strncat and converts all character a to b in the copy of + the string s2 appended to the end of s1. */ + +void +string_cat_and_replace (char *s1, const char *s2, int n, char a, char b) +{ + int l1 = strlen (s1); + int l2 = strlen (s2); + char *p = s1 + l1; + int i; + + strncat (s1, s2, n); + for (i = 0; i < l2; i++) + { + if (*p == a) + *p = b; + p++; + } +} + + +/* Convert a Mac pathname to Unix form. A Mac full pathname is one + that does not begin with a ':' and contains at least one ':'. A Mac + full pathname causes an '/' to be prepended to the Unix pathname. + The algorithm for the rest of the pathname is as follows: + For each segment between two ':', + if it is non-null, copy as is and then add a '/' at the end, + otherwise, insert a "../" into the Unix pathname. + Returns 1 if successful; 0 if fails. */ + +int +mac_to_unix_pathname (const char *mfn, char *ufn, int ufnbuflen) +{ + const char *p, *q, *pe; + + strcpy (ufn, ""); + + if (*mfn == '\0') + return 1; + + p = strchr (mfn, ':'); + if (p != 0 && p != mfn) /* full pathname */ + strcat (ufn, "/"); + + p = mfn; + if (*p == ':') + p++; + + pe = mfn + strlen (mfn); + while (p < pe) + { + q = strchr (p, ':'); + if (q) + { + if (q == p) + { /* two consecutive ':' */ + if (strlen (ufn) + 3 >= ufnbuflen) + return 0; + strcat (ufn, "../"); + } + else + { + if (strlen (ufn) + (q - p) + 1 >= ufnbuflen) + return 0; + string_cat_and_replace (ufn, p, q - p, '/', ':'); + strcat (ufn, "/"); + } + p = q + 1; + } + else + { + if (strlen (ufn) + (pe - p) >= ufnbuflen) + return 0; + string_cat_and_replace (ufn, p, pe - p, '/', ':'); + /* no separator for last one */ + p = pe; + } + } + + return 1; +} + + +extern char *get_temp_dir_name (); + + +/* Convert a Unix pathname to Mac form. Approximately reverse of the + above in algorithm. */ + +int +unix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen) +{ + const char *p, *q, *pe; + char expanded_pathname[MAXPATHLEN+1]; + + strcpy (mfn, ""); + + if (*ufn == '\0') + return 1; + + p = ufn; + + /* Check for and handle volume names. Last comparison: strangely + somewhere "/.emacs" is passed. A temporary fix for now. */ + if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0) + { + if (strlen (p) + 1 > mfnbuflen) + return 0; + strcpy (mfn, p+1); + strcat (mfn, ":"); + return 1; + } + + /* expand to emacs dir found by init_emacs_passwd_dir */ + if (strncmp (p, "~emacs/", 7) == 0) + { + struct passwd *pw = getpwnam ("emacs"); + p += 7; + if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN) + return 0; + strcpy (expanded_pathname, pw->pw_dir); + strcat (expanded_pathname, p); + p = expanded_pathname; + /* now p points to the pathname with emacs dir prefix */ + } + else if (strncmp (p, "/tmp/", 5) == 0) + { + char *t = get_temp_dir_name (); + p += 5; + if (strlen (t) + strlen (p) > MAXPATHLEN) + return 0; + strcpy (expanded_pathname, t); + strcat (expanded_pathname, p); + p = expanded_pathname; + /* now p points to the pathname with emacs dir prefix */ + } + else if (*p != '/') /* relative pathname */ + strcat (mfn, ":"); + + if (*p == '/') + p++; + + pe = p + strlen (p); + while (p < pe) + { + q = strchr (p, '/'); + if (q) + { + if (q - p == 2 && *p == '.' && *(p+1) == '.') + { + if (strlen (mfn) + 1 >= mfnbuflen) + return 0; + strcat (mfn, ":"); + } + else + { + if (strlen (mfn) + (q - p) + 1 >= mfnbuflen) + return 0; + string_cat_and_replace (mfn, p, q - p, ':', '/'); + strcat (mfn, ":"); + } + p = q + 1; + } + else + { + if (strlen (mfn) + (pe - p) >= mfnbuflen) + return 0; + string_cat_and_replace (mfn, p, pe - p, ':', '/'); + p = pe; + } + } + + return 1; +} + + +/* The following functions with "sys_" prefix are stubs to Unix + functions that have already been implemented by CW or MPW. The + calls to them in Emacs source course are #define'd to call the sys_ + versions by the header files s-mac.h. In these stubs pathnames are + converted between their Unix and Mac forms. */ + + +/* Unix epoch is Jan 1, 1970 while Mac epoch is Jan 1, 1904: 66 years + + 17 leap days. These are for adjusting time values returned by + MacOS Toolbox functions. */ + +#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60) + +#ifdef __MWERKS__ +#ifndef CODEWARRIOR_VERSION_6 +/* CW Pro 5 epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not + a leap year! This is for adjusting time_t values returned by MSL + functions. */ +#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60) +#else +/* CW changes Pro 6 to following Unix! */ +#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60) +#endif +#elif __MRC__ +/* MPW library functions follow Unix (confused?). */ +#define CW_OR_MPW_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60) +#else +You lose!!! +#endif + + +/* Define our own stat function for both MrC and CW. The reason for + doing this: "stat" is both the name of a struct and function name: + can't use the same trick like that for sys_open, sys_close, etc. to + redirect Emacs's calls to our own version that converts Unix style + filenames to Mac style filename because all sorts of compilation + errors will be generated if stat is #define'd to be sys_stat. */ + +int +stat_noalias (const char *path, struct stat *buf) +{ + char mac_pathname[MAXPATHLEN+1]; + CInfoPBRec cipb; + + if (unix_to_mac_pathname (path, mac_pathname, MAXPATHLEN+1) == 0) + return -1; + + c2pstr (mac_pathname); + cipb.hFileInfo.ioNamePtr = mac_pathname; + cipb.hFileInfo.ioVRefNum = 0; + cipb.hFileInfo.ioDirID = 0; + cipb.hFileInfo.ioFDirIndex = 0; + /* set to 0 to get information about specific dir or file */ + + errno = PBGetCatInfo (&cipb, false); + if (errno == -43) /* -43: fnfErr defined in Errors.h */ + errno = ENOENT; + if (errno != noErr) + return -1; + + if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */ + { + buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC; + + if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) + buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */ + buf->st_ino = cipb.dirInfo.ioDrDirID; + buf->st_dev = cipb.dirInfo.ioVRefNum; + buf->st_size = cipb.dirInfo.ioDrNmFls; + /* size of dir = number of files and dirs */ + buf->st_atime + = buf->st_mtime + = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF; + buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF; + } + else + { + buf->st_mode = S_IFREG | S_IREAD; + if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) + buf->st_mode |= S_IWRITE; /* bit 1 = 1 for locked files/directories */ + if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL') + buf->st_mode |= S_IEXEC; + buf->st_ino = cipb.hFileInfo.ioDirID; + buf->st_dev = cipb.hFileInfo.ioVRefNum; + buf->st_size = cipb.hFileInfo.ioFlLgLen; + buf->st_atime + = buf->st_mtime + = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF; + buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF; + } + + if (cipb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) + { + /* identify alias files as symlinks */ + buf->st_mode |= S_IFLNK; + buf->st_mode &= ~S_IFREG; + } + + buf->st_nlink = 1; + buf->st_uid = getuid (); + buf->st_gid = getgid (); + buf->st_rdev = 0; + + return 0; +} + + +int +lstat (const char *path, struct stat *buf) +{ + int result; + char true_pathname[MAXPATHLEN+1]; + + /* Try looking for the file without resolving aliases first. */ + if ((result = stat_noalias (path, buf)) >= 0) + return result; + + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + return stat_noalias (true_pathname, buf); +} + + +int +stat (const char *path, struct stat *sb) +{ + int result; + char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + int len; + + if ((result = stat_noalias (path, sb)) >= 0) + return result; + + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN); + if (len > -1) + { + fully_resolved_name[len] = '\0'; + /* in fact our readlink terminates strings */ + return lstat (fully_resolved_name, sb); + } + else + return lstat (true_pathname, sb); +} + + +#if __MRC__ +/* CW defines fstat in stat.mac.c while MPW does not provide this + function. Without the information of how to get from a file + descriptor in MPW StdCLib to a Mac OS file spec, it should be hard + to implement this function. Fortunately, there is only one place + where this function is called in our configuration: in fileio.c, + where only the st_dev and st_ino fields are used to determine + whether two fildes point to different i-nodes to prevent copying + a file onto itself equal. What we have here probably needs + improvement. */ + +int +fstat (int fildes, struct stat *buf) +{ + buf->st_dev = 0; + buf->st_ino = fildes; + buf->st_mode = S_IFREG; /* added by T.I. for the copy-file */ + return 0; /* success */ +} +#endif /* __MRC__ */ + + +/* Adapted from Think Reference code example. */ + +int +mkdir (const char *dirname, int mode) +{ +#pragma unused(mode) + + HFileParam hfpb; + char true_pathname[MAXPATHLEN+1], mac_pathname[MAXPATHLEN+1]; + + if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + if (unix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1) == 0) + return -1; + + c2pstr (mac_pathname); + hfpb.ioNamePtr = mac_pathname; + hfpb.ioVRefNum = 0; /* ignored unless name is invalid */ + hfpb.ioDirID = 0; /* parent is the root */ + + errno = PBDirCreate ((HParmBlkPtr) &hfpb, false); + /* just return the Mac OSErr code for now */ + return errno == noErr ? 0 : -1; +} + + +#undef rmdir +sys_rmdir (const char *dirname) +{ + HFileParam hfpb; + char mac_pathname[MAXPATHLEN+1]; + + if (unix_to_mac_pathname (dirname, mac_pathname, MAXPATHLEN+1) == 0) + return -1; + + c2pstr (mac_pathname); + hfpb.ioNamePtr = mac_pathname; + hfpb.ioVRefNum = 0; /* ignored unless name is invalid */ + hfpb.ioDirID = 0; /* parent is the root */ + + errno = PBHDelete ((HParmBlkPtr) &hfpb, false); + return errno == noErr ? 0 : -1; +} + + +#ifdef __MRC__ +/* No implementation yet. */ +int +execvp (const char *path, ...) +{ + return -1; +} +#endif /* __MRC__ */ + + +int +utime (const char *path, const struct utimbuf *times) +{ + char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + int len; + char mac_pathname[MAXPATHLEN+1]; + CInfoPBRec cipb; + + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN); + if (len > -1) + fully_resolved_name[len] = '\0'; + else + strcpy (fully_resolved_name, true_pathname); + + if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1)) + return -1; + + c2pstr (mac_pathname); + cipb.hFileInfo.ioNamePtr = mac_pathname; + cipb.hFileInfo.ioVRefNum = 0; + cipb.hFileInfo.ioDirID = 0; + cipb.hFileInfo.ioFDirIndex = 0; + /* set to 0 to get information about specific dir or file */ + + errno = PBGetCatInfo (&cipb, false); + if (errno != noErr) + return -1; + + if (cipb.hFileInfo.ioFlAttrib & 0x10) /* bit 4 = 1 for directories */ + { + if (times) + cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF; + else + GetDateTime (&cipb.dirInfo.ioDrMdDat); + } + else + { + if (times) + cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF; + else + GetDateTime (&cipb.hFileInfo.ioFlMdDat); + } + + errno = PBSetCatInfo (&cipb, false); + return errno == noErr ? 0 : -1; +} + + +#ifndef F_OK +#define F_OK 0 +#endif +#ifndef X_OK +#define X_OK 1 +#endif +#ifndef W_OK +#define W_OK 2 +#endif + +/* Like stat, but test for access mode in hfpb.ioFlAttrib */ +int +access (const char *path, int mode) +{ + char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + int len; + char mac_pathname[MAXPATHLEN+1]; + CInfoPBRec cipb; + + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN); + if (len > -1) + fully_resolved_name[len] = '\0'; + else + strcpy (fully_resolved_name, true_pathname); + + if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1)) + return -1; + + c2pstr (mac_pathname); + cipb.hFileInfo.ioNamePtr = mac_pathname; + cipb.hFileInfo.ioVRefNum = 0; + cipb.hFileInfo.ioDirID = 0; + cipb.hFileInfo.ioFDirIndex = 0; + /* set to 0 to get information about specific dir or file */ + + errno = PBGetCatInfo (&cipb, false); + if (errno != noErr) + return -1; + + if (mode == F_OK) /* got this far, file exists */ + return 0; + + if (mode & X_OK) + if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */ + return 0; + else + { + if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL') + return 0; + else + return -1; + } + + if (mode & W_OK) + return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0; + /* don't allow if lock bit is on */ + + return -1; +} + + +#define DEV_NULL_FD 0x10000 + +#undef open +int +sys_open (const char *path, int oflag) +{ + char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + int len; + char mac_pathname[MAXPATHLEN+1]; + + if (strcmp (path, "/dev/null") == 0) + return DEV_NULL_FD; /* some bogus fd to be ignored in write */ + + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN); + if (len > -1) + fully_resolved_name[len] = '\0'; + else + strcpy (fully_resolved_name, true_pathname); + + if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1)) + return -1; + else + { +#ifdef __MRC__ + if (oflag == O_WRONLY || oflag == O_RDWR) + fsetfileinfo (mac_pathname, 'EMAx', 'TEXT'); +#endif + return open (mac_pathname, oflag); + } +} + + +#undef creat +int +sys_creat (const char *path, mode_t mode) +{ + char true_pathname[MAXPATHLEN+1]; + int len; + char mac_pathname[MAXPATHLEN+1]; + + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + if (!unix_to_mac_pathname (true_pathname, mac_pathname, MAXPATHLEN+1)) + return -1; + else + { +#ifdef __MRC__ + int result = creat (mac_pathname); + fsetfileinfo (mac_pathname, 'EMAx', 'TEXT'); + return result; +#else + return creat (mac_pathname, mode); +#endif + } +} + + +#undef unlink +int +sys_unlink (const char *path) +{ + char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + int len; + char mac_pathname[MAXPATHLEN+1]; + + if (find_true_pathname (path, true_pathname, MAXPATHLEN+1) == -1) + return -1; + + len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN); + if (len > -1) + fully_resolved_name[len] = '\0'; + else + strcpy (fully_resolved_name, true_pathname); + + if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1)) + return -1; + else + return unlink (mac_pathname); +} + + +#undef read +int +sys_read (int fildes, char *buf, int count) +{ + if (fildes == 0) /* this should not be used for console input */ + return -1; + else +#ifdef CODEWARRIOR_VERSION_6 + return _read (fildes, buf, count); +#else + return read (fildes, buf, count); +#endif +} + + +#undef write +int +sys_write (int fildes, const char *buf, int count) +{ + if (fildes == DEV_NULL_FD) + return count; + else +#ifdef CODEWARRIOR_VERSION_6 + return _write (fildes, buf, count); +#else + return write (fildes, buf, count); +#endif +} + + +#undef rename +int +sys_rename (const char * old_name, const char * new_name) +{ + char true_old_pathname[MAXPATHLEN+1], true_new_pathname[MAXPATHLEN+1]; + char fully_resolved_old_name[MAXPATHLEN+1]; + int len; + char mac_old_name[MAXPATHLEN+1], mac_new_name[MAXPATHLEN+1]; + + if (find_true_pathname (old_name, true_old_pathname, MAXPATHLEN+1) == -1) + return -1; + + len = readlink (true_old_pathname, fully_resolved_old_name, MAXPATHLEN); + if (len > -1) + fully_resolved_old_name[len] = '\0'; + else + strcpy (fully_resolved_old_name, true_old_pathname); + + if (find_true_pathname (new_name, true_new_pathname, MAXPATHLEN+1) == -1) + return -1; + + if (strcmp (fully_resolved_old_name, true_new_pathname) == 0) + return 0; + + if (!unix_to_mac_pathname (fully_resolved_old_name, + mac_old_name, + MAXPATHLEN+1)) + return -1; + + if (!unix_to_mac_pathname(true_new_pathname, mac_new_name, MAXPATHLEN+1)) + return -1; + + /* If a file with new_name already exists, rename deletes the old + file in Unix. CW version fails in these situation. So we add a + call to unlink here. */ + (void) unlink (mac_new_name); + + return rename (mac_old_name, mac_new_name); +} + + +#undef fopen +extern FILE *fopen (const char *name, const char *mode); +FILE * +sys_fopen (const char *name, const char *mode) +{ + char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + int len; + char mac_pathname[MAXPATHLEN+1]; + + if (find_true_pathname (name, true_pathname, MAXPATHLEN+1) == -1) + return 0; + + len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN); + if (len > -1) + fully_resolved_name[len] = '\0'; + else + strcpy (fully_resolved_name, true_pathname); + + if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1)) + return 0; + else + { +#ifdef __MRC__ + if (mode[0] == 'w' || mode[0] == 'a') + fsetfileinfo (mac_pathname, 'EMAx', 'TEXT'); +#endif + return fopen (mac_pathname, mode); + } +} + + +#include + +long target_ticks = 0; + +#ifdef __MRC__ +__sigfun alarm_signal_func = (__sigfun) 0; +#elif __MWERKS__ +__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0; +#else +You lose!!! +#endif + + +/* These functions simulate SIG_ALRM. The stub for function signal + stores the signal handler function in alarm_signal_func if a + SIG_ALRM is encountered. check_alarm is called in XTread_socket, + which emacs calls periodically. A pending alarm is represented by + a non-zero target_ticks value. check_alarm calls the handler + function pointed to by alarm_signal_func if one has been set up and + an alarm is pending. */ + +void +check_alarm () +{ + if (target_ticks && TickCount () > target_ticks) + { + target_ticks = 0; + if (alarm_signal_func) + (*alarm_signal_func)(SIGALRM); + } +} + + +int +select(n, rfds, wfds, efds, timeout) + int n; + SELECT_TYPE *rfds; + SELECT_TYPE *wfds; + SELECT_TYPE *efds; + struct timeval *timeout; +{ + EMACS_TIME end_time, now; + EventRecord e; + unsigned long final_tick; + + /* Can only handle wait for keyboard input. */ + if (n > 1 || wfds || efds) + return -1; + + EMACS_GET_TIME (end_time); + EMACS_ADD_TIME (end_time, end_time, *timeout); + + do + { + /* Also return true if an event other than a keyDown has + occurred. This causes kbd_buffer_get_event in keyboard.c to + call read_avail_input which in turn calls XTread_socket to + poll for these events. Otherwise these never get processed + except but a very slow poll timer. */ + if (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e)) + return 1; + + /* Also check movement of the mouse. */ + { + Point mouse_pos; + static Point old_mouse_pos = {-1, -1}; + + GetMouse (&mouse_pos); + if (!EqualPt (mouse_pos, old_mouse_pos)) + { + old_mouse_pos = mouse_pos; + return 1; + } + } + + Delay (1UL, &final_tick); + + EMACS_GET_TIME (now); + EMACS_SUB_TIME (now, end_time, now); + } + while (!EMACS_TIME_NEG_P (now)); + + return 0; +} + + +/* Called in sys_select to wait for an alarm signal to arrive. */ + +int +pause () +{ + unsigned long final_tick; + + if (!target_ticks) /* no alarm pending */ + return -1; + + while (TickCount () <= target_ticks) + Delay (1UL, &final_tick); /* wait 1/60 second before retrying */ + + target_ticks = 0; + if (alarm_signal_func) + (*alarm_signal_func)(SIGALRM); + + return 0; +} + + +int +alarm (int seconds) +{ + long remaining = target_ticks ? (TickCount () - target_ticks) / 60 : 0; + + target_ticks = seconds ? TickCount () + 60 * seconds : 0; + + return (remaining < 0) ? 0 : (unsigned int) remaining; +} + + +#undef signal +#ifdef __MRC__ +extern __sigfun signal (int signal, __sigfun signal_func); +__sigfun +sys_signal (int signal_num, __sigfun signal_func) +#elif __MWERKS__ +extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func); +__signal_func_ptr +sys_signal (int signal_num, __signal_func_ptr signal_func) +#else + You lose!!! +#endif +{ + if (signal_num != SIGALRM) + return signal (signal_num, signal_func); + else + { +#ifdef __MRC__ + __sigfun old_signal_func; +#elif __MWERKS__ + __signal_func_ptr old_signal_func; +#else + You lose!!! +#endif + old_signal_func = alarm_signal_func; + alarm_signal_func = signal_func; + return old_signal_func; + } +} + + +/* gettimeofday should return the amount of time (in a timeval + structure) since midnight today. The toolbox function Microseconds + returns the number of microseconds (in a UnsignedWide value) since + the machine was booted. Also making this complicated is WideAdd, + WideSubtract, etc. take wide values. */ + +int +gettimeofday (tp) + struct timeval *tp; +{ + static inited = 0; + static wide wall_clock_at_epoch, clicks_at_epoch; + UnsignedWide uw_microseconds; + wide w_microseconds; + time_t sys_time (time_t *); + + /* If this function is called for the first time, record the number + of seconds since midnight and the number of microseconds since + boot at the time of this first call. */ + if (!inited) + { + time_t systime; + inited = 1; + systime = sys_time (NULL); + /* Store microseconds since midnight in wall_clock_at_epoch. */ + WideMultiply (systime, 1000000L, &wall_clock_at_epoch); + Microseconds (&uw_microseconds); + /* Store microseconds since boot in clicks_at_epoch. */ + clicks_at_epoch.hi = uw_microseconds.hi; + clicks_at_epoch.lo = uw_microseconds.lo; + } + + /* Get time since boot */ + Microseconds (&uw_microseconds); + + /* Convert to time since midnight*/ + w_microseconds.hi = uw_microseconds.hi; + w_microseconds.lo = uw_microseconds.lo; + WideSubtract (&w_microseconds, &clicks_at_epoch); + WideAdd (&w_microseconds, &wall_clock_at_epoch); + tp->tv_sec = WideDivide (&w_microseconds, 1000000L, &tp->tv_usec); + + return 0; +} + + +#ifdef __MRC__ +unsigned int +sleep (unsigned int seconds) +{ + unsigned long final_tick; + + Delay (seconds * 60UL, &final_tick); + return (0); +} +#endif /* __MRC__ */ + + +/* The time functions adjust time values according to the difference + between the Unix and CW epoches. */ + +#undef gmtime +extern struct tm *gmtime (const time_t *); +struct tm * +sys_gmtime (const time_t *timer) +{ + time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF; + + return gmtime (&unix_time); +} + + +#undef localtime +extern struct tm *localtime (const time_t *); +struct tm * +sys_localtime (const time_t *timer) +{ +#ifdef CODEWARRIOR_VERSION_6 + time_t unix_time = *timer; +#else + time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF; +#endif + + return localtime (&unix_time); +} + + +#undef ctime +extern char *ctime (const time_t *); +char * +sys_ctime (const time_t *timer) +{ +#ifdef CODEWARRIOR_VERSION_6 + time_t unix_time = *timer; +#else + time_t unix_time = *timer + CW_OR_MPW_UNIX_EPOCH_DIFF; +#endif + + return ctime (&unix_time); +} + + +#undef time +extern time_t time (time_t *); +time_t +sys_time (time_t *timer) +{ +#ifdef CODEWARRIOR_VERSION_6 + time_t mac_time = time (NULL); +#else + time_t mac_time = time (NULL) - CW_OR_MPW_UNIX_EPOCH_DIFF; +#endif + + if (timer) + *timer = mac_time; + + return mac_time; +} + + +/* MPW strftime broken for "%p" format */ +#ifdef __MRC__ +#undef strftime +#include +size_t +sys_strftime (char * s, size_t maxsize, const char * format, + const struct tm * timeptr) +{ + if (strcmp (format, "%p") == 0) + { + if (maxsize < 3) + return 0; + if (timeptr->tm_hour < 12) + { + strcpy (s, "AM"); + return 2; + } + else + { + strcpy (s, "PM"); + return 2; + } + } + else + return strftime (s, maxsize, format, timeptr); +} +#endif /* __MRC__ */ + + +/* no subprocesses, empty wait */ + +int +wait (int pid) +{ + return 0; +} + + +void +croak (char *badfunc) +{ + printf ("%s not yet implemented\r\n", badfunc); + exit (1); +} + + +char * +index (const char * str, int chr) +{ + return strchr (str, chr); +} + + +char * +mktemp (char *template) +{ + int len, k; + static seqnum = 0; + + len = strlen (template); + k = len - 1; + while (k >= 0 && template[k] == 'X') + k--; + + k++; /* make k index of first 'X' */ + + if (k < len) + { + /* Zero filled, number of digits equal to the number of X's. */ + sprintf (&template[k], "%0*d", len-k, seqnum++); + + return template; + } + else + return 0; +} + + +/* Emulate getpwuid, getpwnam and others. */ + +#define PASSWD_FIELD_SIZE 256 + +static char my_passwd_name[PASSWD_FIELD_SIZE]; +static char my_passwd_dir[MAXPATHLEN+1]; + +static struct passwd my_passwd = +{ + my_passwd_name, + my_passwd_dir, +}; + + +/* Initialized by main () in macterm.c to pathname of emacs directory. */ + +char emacs_passwd_dir[MAXPATHLEN+1]; + +char * +getwd (char *); + +void +init_emacs_passwd_dir () +{ + int found = false; + + if (getwd (emacs_passwd_dir) && getwd (my_passwd_dir)) + { + /* Need pathname of first ancestor that begins with "emacs" + since Mac emacs application is somewhere in the emacs-* + tree. */ + int len = strlen (emacs_passwd_dir); + int j = len - 1; + /* j points to the "/" following the directory name being + compared. */ + int i = j - 1; + while (i >= 0 && !found) + { + while (i >= 0 && emacs_passwd_dir[i] != '/') + i--; + if (emacs_passwd_dir[i] == '/' && i+5 < len) + found = (strncmp (&(emacs_passwd_dir[i+1]), "emacs", 5) == 0); + if (found) + emacs_passwd_dir[j+1] = '\0'; + else + { + j = i; + i = j - 1; + } + } + } + + if (!found) + { + /* Setting to "/" probably won't work but set it to something + anyway. */ + strcpy (emacs_passwd_dir, "/"); + strcpy (my_passwd_dir, "/"); + } +} + + +static struct passwd emacs_passwd = +{ + "emacs", + emacs_passwd_dir, +}; + +static int my_passwd_inited = 0; + + +static void +init_my_passwd () +{ + char **owner_name; + + /* Note: my_passwd_dir initialized in int_emacs_passwd_dir to + directory where Emacs was started. */ + + owner_name = (char **) GetResource ('STR ',-16096); + if (owner_name) + { + HLock (owner_name); + BlockMove ((unsigned char *) *owner_name, + (unsigned char *) my_passwd_name, + *owner_name[0]+1); + HUnlock (owner_name); + p2cstr ((unsigned char *) my_passwd_name); + } + else + my_passwd_name[0] = 0; +} + + +struct passwd * +getpwuid (uid_t uid) +{ + if (!my_passwd_inited) + { + init_my_passwd (); + my_passwd_inited = 1; + } + + return &my_passwd; +} + + +struct passwd * +getpwnam (const char *name) +{ + if (strcmp (name, "emacs") == 0) + return &emacs_passwd; + + if (!my_passwd_inited) + { + init_my_passwd (); + my_passwd_inited = 1; + } + + return &my_passwd; +} + + +/* The functions fork, kill, sigsetmask, sigblock, request_sigio, + setpgrp, setpriority, and unrequest_sigio are defined to be empty + as in msdos.c. */ + + +int +fork () +{ + return -1; +} + + +int +kill (int x, int y) +{ + return -1; +} + + +void +sys_subshell () +{ + error ("Can't spawn subshell"); +} + + +int +sigsetmask (int x) +{ + return 0; +} + + +int +sigblock (int mask) +{ + return 0; +} + + +void +request_sigio (void) +{ +} + + +void +unrequest_sigio (void) +{ +} + + +int +setpgrp () +{ + return 0; +} + + +/* No pipes yet. */ + +int +pipe (int _fildes[2]) +{ + errno = EACCES; + return -1; +} + + +/* Hard and symbolic links. */ + +int +symlink (const char *name1, const char *name2) +{ + errno = ENOENT; + return -1; +} + + +int +link (const char *name1, const char *name2) +{ + errno = ENOENT; + return -1; +} + + +/* Determine the path name of the file specified by VREFNUM, DIRID, + and NAME and place that in the buffer PATH of length + MAXPATHLEN. */ +int +path_from_vol_dir_name (char *path, int man_path_len, short vol_ref_num, + long dir_id, ConstStr255Param name) +{ + Str255 dir_name; + CInfoPBRec cipb; + OSErr err; + + if (strlen (name) > man_path_len) + return 0; + + memcpy (dir_name, name, name[0]+1); + memcpy (path, name, name[0]+1); + p2cstr (path); + + cipb.dirInfo.ioDrParID = dir_id; + cipb.dirInfo.ioNamePtr = dir_name; + + do + { + cipb.dirInfo.ioVRefNum = vol_ref_num; + cipb.dirInfo.ioFDirIndex = -1; + cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID; + /* go up to parent each time */ + + err = PBGetCatInfo (&cipb, false); + if (err != noErr) + return 0; + + p2cstr (dir_name); + if (strlen (dir_name) + strlen (path) + 1 >= man_path_len) + return 0; + + strcat (dir_name, ":"); + strcat (dir_name, path); + /* attach to front since we're going up directory tree */ + strcpy (path, dir_name); + } + while (cipb.dirInfo.ioDrDirID != fsRtDirID); + /* stop when we see the volume's root directory */ + + return 1; /* success */ +} + + +int +readlink (const char *path, char *buf, int bufsiz) +{ + char mac_sym_link_name[MAXPATHLEN+1]; + OSErr err; + FSSpec fsspec; + Boolean target_is_folder, was_aliased; + Str255 directory_name, mac_pathname; + CInfoPBRec cipb; + + if (unix_to_mac_pathname (path, mac_sym_link_name, MAXPATHLEN+1) == 0) + return -1; + + c2pstr (mac_sym_link_name); + err = FSMakeFSSpec (0, 0, mac_sym_link_name, &fsspec); + if (err != noErr) + { + errno = ENOENT; + return -1; + } + + err = ResolveAliasFile (&fsspec, true, &target_is_folder, &was_aliased); + if (err != noErr || !was_aliased) + { + errno = ENOENT; + return -1; + } + + if (path_from_vol_dir_name (mac_pathname, 255, fsspec.vRefNum, fsspec.parID, + fsspec.name) == 0) + { + errno = ENOENT; + return -1; + } + + if (mac_to_unix_pathname (mac_pathname, buf, bufsiz) == 0) + { + errno = ENOENT; + return -1; + } + + return strlen (buf); +} + + +/* Convert a path to one with aliases fully expanded. */ + +static int +find_true_pathname (const char *path, char *buf, int bufsiz) +{ + char *q, temp[MAXPATHLEN+1]; + const char *p; + int len; + + if (bufsiz <= 0 || path == 0 || path[0] == '\0') + return -1; + + buf[0] = '\0'; + + p = path; + if (*p == '/') + q = strchr (p + 1, '/'); + else + q = strchr (p, '/'); + len = 0; /* loop may not be entered, e.g., for "/" */ + + while (q) + { + strcpy (temp, buf); + strncat (temp, p, q - p); + len = readlink (temp, buf, bufsiz); + if (len <= -1) + { + if (strlen (temp) + 1 > bufsiz) + return -1; + strcpy (buf, temp); + } + strcat (buf, "/"); + len++; + p = q + 1; + q = strchr(p, '/'); + } + + if (len + strlen (p) + 1 >= bufsiz) + return -1; + + strcat (buf, p); + return len + strlen (p); +} + + +mode_t +umask (mode_t numask) +{ + static mode_t mask = 022; + mode_t oldmask = mask; + mask = numask; + return oldmask; +} + + +int +chmod (const char *path, mode_t mode) +{ + /* say it always succeed for now */ + return 0; +} + + +int +dup (int oldd) +{ +#ifdef __MRC__ + return fcntl (oldd, F_DUPFD, 0); +#elif __MWERKS__ + /* current implementation of fcntl in fcntl.mac.c simply returns old + descriptor */ + return fcntl (oldd, F_DUPFD); +#else +You lose!!! +#endif +} + + +/* This is from the original sysdep.c. Emulate BSD dup2. First close + newd if it already exists. Then, attempt to dup oldd. If not + successful, call dup2 recursively until we are, then close the + unsuccessful ones. */ + +int +dup2 (int oldd, int newd) +{ + int fd, ret; + + close (newd); + + fd = dup (oldd); + if (fd == -1) + return -1; + if (fd == newd) + return newd; + ret = dup2 (oldd, newd); + close (fd); + return ret; +} + + +/* let it fail for now */ + +char * +sbrk (int incr) +{ + return (char *) -1; +} + + +int +fsync (int fd) +{ + return 0; +} + + +int +ioctl (int d, int request, void *argp) +{ + return -1; +} + + +#ifdef __MRC__ +int +isatty (int fildes) +{ + if (fildes >=0 && fildes <= 2) + return 1; + else + return 0; +} + + +int +getgid () +{ + return 100; +} + + +int +getegid () +{ + return 100; +} + + +int +getuid () +{ + return 200; +} + + +int +geteuid () +{ + return 200; +} +#endif /* __MRC__ */ + + +#ifdef __MWERKS__ +#ifndef CODEWARRIOR_VERSION_6 +#undef getpid +int +getpid () +{ + return 9999; +} +#endif +#endif /* __MWERKS__ */ + + +/* Return the path to the directory in which Emacs can create + temporary files. The MacOS "temporary items" directory cannot be + used because it removes the file written by a process when it + exits. In that sense it's more like "/dev/null" than "/tmp" (but + again not exactly). And of course Emacs needs to read back the + files written by its subprocesses. So here we write the files to a + directory "Emacs" in the Preferences Folder. This directory is + created if it does not exist. */ + +static char * +get_temp_dir_name () +{ + static char *temp_dir_name = NULL; + short vol_ref_num; + long dir_id; + OSErr err; + Str255 dir_name, full_path; + CInfoPBRec cpb; + char unix_dir_name[MAXPATHLEN+1]; + DIR *dir; + + /* Cache directory name with pointer temp_dir_name. + Look for it only the first time. */ + if (!temp_dir_name) + { + err = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder, + &vol_ref_num, &dir_id); + if (err != noErr) + return NULL; + + if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p")) + return NULL; + + if (strlen (full_path) + 6 <= MAXPATHLEN) + strcat (full_path, "Emacs:"); + else + return NULL; + + if (!mac_to_unix_pathname (full_path, unix_dir_name, MAXPATHLEN+1)) + return NULL; + + dir = opendir (unix_dir_name); /* check whether temp directory exists */ + if (dir) + closedir (dir); + else if (mkdir (unix_dir_name, 0700) != 0) /* create it if not */ + return NULL; + + temp_dir_name = (char *) malloc (strlen (unix_dir_name) + 1); + strcpy (temp_dir_name, unix_dir_name); + } + + return temp_dir_name; +} + + +/* Allocate and construct an array of pointers to strings from a list + of strings stored in a 'STR#' resource. The returned pointer array + is stored in the style of argv and environ: if the 'STR#' resource + contains numString strings, an pointer array with numString+1 + elements is returned in which the last entry contains a null + pointer. The pointer to the pointer array is passed by pointer in + parameter t. The resource ID of the 'STR#' resource is passed in + parameter StringListID. + */ + +void +get_string_list (char ***t, short string_list_id) +{ + Handle h; + Ptr p; + int i, num_strings; + + h = GetResource ('STR#', string_list_id); + if (h) + { + HLock (h); + p = *h; + num_strings = * (short *) p; + p += sizeof(short); + *t = (char **) malloc (sizeof (char *) * (num_strings + 1)); + for (i = 0; i < num_strings; i++) + { + short length = *p++; + (*t)[i] = (char *) malloc (length + 1); + strncpy ((*t)[i], p, length); + (*t)[i][length] = '\0'; + p += length; + } + (*t)[num_strings] = 0; + HUnlock (h); + } + else + { + /* Return no string in case GetResource fails. Bug fixed by + Ikegami Tsutomu. Caused MPW build to crash without sym -on + option (no sym -on implies -opt local). */ + *t = (char **) malloc (sizeof (char *)); + (*t)[0] = 0; + } +} + + +static char * +get_path_to_system_folder () +{ + short vol_ref_num; + long dir_id; + OSErr err; + Str255 dir_name, full_path; + CInfoPBRec cpb; + static char system_folder_unix_name[MAXPATHLEN+1]; + DIR *dir; + + err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder, + &vol_ref_num, &dir_id); + if (err != noErr) + return NULL; + + if (!path_from_vol_dir_name (full_path, 255, vol_ref_num, dir_id, "\p")) + return NULL; + + if (!mac_to_unix_pathname (full_path, system_folder_unix_name, MAXPATHLEN+1)) + return NULL; + + return system_folder_unix_name; +} + + +char **environ; + +#define ENVIRON_STRING_LIST_ID 128 + +/* Get environment variable definitions from STR# resource. */ + +void +init_environ () +{ + int i; + + get_string_list (&environ, ENVIRON_STRING_LIST_ID); + + i = 0; + while (environ[i]) + i++; + + /* Make HOME directory the one Emacs starts up in if not specified + by resource. */ + if (getenv ("HOME") == NULL) + { + environ = (char **) realloc (environ, sizeof (char *) * (i + 2)); + if (environ) + { + environ[i] = (char *) malloc (strlen (my_passwd_dir) + 6); + if (environ[i]) + { + strcpy (environ[i], "HOME="); + strcat (environ[i], my_passwd_dir); + } + environ[i+1] = 0; + i++; + } + } + + /* Make HOME directory the one Emacs starts up in if not specified + by resource. */ + if (getenv ("MAIL") == NULL) + { + environ = (char **) realloc (environ, sizeof (char *) * (i + 2)); + if (environ) + { + char * path_to_system_folder = get_path_to_system_folder (); + environ[i] = (char *) malloc (strlen (path_to_system_folder) + 22); + if (environ[i]) + { + strcpy (environ[i], "MAIL="); + strcat (environ[i], path_to_system_folder); + strcat (environ[i], "Eudora Folder/In"); + } + environ[i+1] = 0; + } + } +} + + +/* Return the value of the environment variable NAME. */ + +char * +getenv (const char *name) +{ + int length = strlen(name); + char **e; + + for (e = environ; *e != 0; e++) + if (strncmp(*e, name, length) == 0 && (*e)[length] == '=') + return &(*e)[length + 1]; + + if (strcmp (name, "TMPDIR") == 0) + return get_temp_dir_name (); + + return 0; +} + + +#ifdef __MRC__ +/* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */ +char *sys_siglist[] = +{ + "Zero is not a signal!!!", + "Abort", /* 1 */ + "Interactive user interrupt", /* 2 */ "?", + "Floating point exception", /* 4 */ "?", "?", "?", + "Illegal instruction", /* 8 */ "?", "?", "?", "?", "?", "?", "?", + "Segment violation", /* 16 */ "?", "?", "?", "?", "?", "?", "?", + "?", "?", "?", "?", "?", "?", "?", "?", + "Terminal" /* 32 */ +}; +#elif __MWERKS__ +char *sys_siglist[] = +{ + "Zero is not a signal!!!", + "Abort", + "Floating point exception", + "Illegal instruction", + "Interactive user interrupt", + "Segment violation", + "Terminal" +}; +#else +You lose!!! +#endif + + +#include + +int +uname (struct utsname *name) +{ + char **system_name; + system_name = GetString (-16413); /* IM - Resource Manager Reference */ + if (system_name) + { + BlockMove (*system_name, name->nodename, (*system_name)[0]+1); + p2cstr (name->nodename); + return 0; + } + else + return -1; +} + + +#include +#include + +/* Event class of HLE sent to subprocess. */ +const OSType kEmacsSubprocessSend = 'ESND'; + +/* Event class of HLE sent back from subprocess. */ +const OSType kEmacsSubprocessReply = 'ERPY'; + + +char * +mystrchr (char *s, char c) +{ + while (*s && *s != c) + { + if (*s == '\\') + s++; + s++; + } + + if (*s) + { + *s = '\0'; + return s; + } + else + return NULL; +} + + +char * +mystrtok (char *s) +{ + while (*s) + s++; + + return s + 1; +} + + +void +mystrcpy (char *to, char *from) +{ + while (*from) + { + if (*from == '\\') + from++; + *to++ = *from++; + } + *to = '\0'; +} + + +/* Start a Mac subprocess. Arguments for it is passed in argv (null + terminated). The process should run with the default directory + "workdir", read input from "infn", and write output and error to + "outfn" and "errfn", resp. The Process Manager call + LaunchApplication is used to start the subprocess. We use high + level events as the mechanism to pass arguments to the subprocess + and to make Emacs wait for the subprocess to terminate and pass + back a result code. The bulk of the code here packs the arguments + into one message to be passed together with the high level event. + Emacs also sometimes starts a subprocess using a shell to perform + wildcard filename expansion. Since we don't really have a shell on + the Mac, this case is detected and the starting of the shell is + by-passed. We really need to add code here to do filename + expansion to support such functionality. */ + +int +run_mac_command (argv, workdir, infn, outfn, errfn) + unsigned char **argv; + const char *workdir; + const char *infn, *outfn, *errfn; +{ + char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1]; + char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1]; + int paramlen, argc, newargc, j, retries; + char **newargv, *param, *p; + OSErr iErr; + FSSpec spec; + LaunchParamBlockRec lpbr; + EventRecord send_event, reply_event; + RgnHandle cursor_region_handle; + TargetID targ; + unsigned long ref_con, len; + + if (unix_to_mac_pathname (workdir, macworkdir, MAXPATHLEN+1) == 0) + return -1; + if (unix_to_mac_pathname (infn, macinfn, MAXPATHLEN+1) == 0) + return -1; + if (unix_to_mac_pathname (outfn, macoutfn, MAXPATHLEN+1) == 0) + return -1; + if (unix_to_mac_pathname (errfn, macerrfn, MAXPATHLEN+1) == 0) + return -1; + + paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn) + + strlen (macerrfn) + 4; /* count nulls at end of strings */ + + argc = 0; + while (argv[argc]) + argc++; + + if (argc == 0) + return -1; + + /* If a subprocess is invoked with a shell, we receive 3 arguments + of the form: "/sh" "-c" "/ " */ + j = strlen (argv[0]); + if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0 + && argc == 3 && strcmp (argv[1], "-c") == 0) + { + char *command, *t, tempmacpathname[MAXPATHLEN+1]; + + /* The arguments for the command in argv[2] are separated by + spaces. Count them and put the count in newargc. */ + command = (char *) alloca (strlen (argv[2])+2); + strcpy (command, argv[2]); + if (command[strlen (command) - 1] != ' ') + strcat (command, " "); + + t = command; + newargc = 0; + t = mystrchr (t, ' '); + while (t) + { + newargc++; + t = mystrchr (t+1, ' '); + } + + newargv = (char **) alloca (sizeof (char *) * newargc); + + t = command; + for (j = 0; j < newargc; j++) + { + newargv[j] = (char *) alloca (strlen (t) + 1); + mystrcpy (newargv[j], t); + + t = mystrtok (t); + paramlen += strlen (newargv[j]) + 1; + } + + if (strncmp (newargv[0], "~emacs/", 7) == 0) + { + if (unix_to_mac_pathname (newargv[0], tempmacpathname, MAXPATHLEN+1) + == 0) + return -1; + } + else + { /* sometimes Emacs call "sh" without a path for the command */ +#if 0 + char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1); + strcpy (t, "~emacs/"); + strcat (t, newargv[0]); +#endif + Lisp_Object path; + openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, + 1); + + if (NILP (path)) + return -1; + if (unix_to_mac_pathname (XSTRING (path)->data, tempmacpathname, + MAXPATHLEN+1) == 0) + return -1; + } + strcpy (macappname, tempmacpathname); + } + else + { + if (unix_to_mac_pathname (argv[0], macappname, MAXPATHLEN+1) == 0) + return -1; + + newargv = (char **) alloca (sizeof (char *) * argc); + newargc = argc; + for (j = 1; j < argc; j++) + { + if (strncmp (argv[j], "~emacs/", 7) == 0) + { + char *t = strchr (argv[j], ' '); + if (t) + { + char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1]; + strncpy (tempcmdname, argv[j], t-argv[j]); + tempcmdname[t-argv[j]] = '\0'; + if (unix_to_mac_pathname (tempcmdname, tempmaccmdname, + MAXPATHLEN+1) == 0) + return -1; + newargv[j] = (char *) alloca (strlen (tempmaccmdname) + + strlen (t) + 1); + strcpy (newargv[j], tempmaccmdname); + strcat (newargv[j], t); + } + else + { + char tempmaccmdname[MAXPATHLEN+1]; + if (unix_to_mac_pathname (argv[j], tempmaccmdname, + MAXPATHLEN+1) == 0) + return -1; + newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1); + strcpy (newargv[j], tempmaccmdname); + } + } + else + newargv[j] = argv[j]; + paramlen += strlen (newargv[j]) + 1; + } + } + + /* After expanding all the arguments, we now know the length of the + parameter block to be sent to the subprocess as a message + attached to the HLE. */ + param = (char *) malloc (paramlen + 1); + if (!param) + return -1; + + p = param; + *p++ = newargc; + /* first byte of message contains number of arguments for command */ + strcpy (p, macworkdir); + p += strlen (macworkdir); + *p++ = '\0'; + /* null terminate strings sent so it's possible to use strcpy over there */ + strcpy (p, macinfn); + p += strlen (macinfn); + *p++ = '\0'; + strcpy (p, macoutfn); + p += strlen (macoutfn); + *p++ = '\0'; + strcpy (p, macerrfn); + p += strlen (macerrfn); + *p++ = '\0'; + for (j = 1; j < newargc; j++) + { + strcpy (p, newargv[j]); + p += strlen (newargv[j]); + *p++ = '\0'; + } + + c2pstr (macappname); + + iErr = FSMakeFSSpec (0, 0, macappname, &spec); + + if (iErr != noErr) + { + free (param); + return -1; + } + + lpbr.launchBlockID = extendedBlock; + lpbr.launchEPBLength = extendedBlockLen; + lpbr.launchControlFlags = launchContinue + launchNoFileFlags; + lpbr.launchAppSpec = &spec; + lpbr.launchAppParameters = NULL; + + iErr = LaunchApplication (&lpbr); /* call the subprocess */ + if (iErr != noErr) + { + free (param); + return -1; + } + + send_event.what = kHighLevelEvent; + send_event.message = kEmacsSubprocessSend; + /* Event ID stored in "where" unused */ + + retries = 3; + /* OS may think current subprocess has terminated if previous one + terminated recently. */ + do + { + iErr = PostHighLevelEvent (&send_event, &lpbr.launchProcessSN, 0, param, + paramlen + 1, receiverIDisPSN); + } + while (iErr == sessClosedErr && retries-- > 0); + + if (iErr != noErr) + { + free (param); + return -1; + } + + cursor_region_handle = NewRgn (); + + /* Wait for the subprocess to finish, when it will send us a ERPY + high level event. */ + while (1) + if (WaitNextEvent (highLevelEventMask, &reply_event, 180, + cursor_region_handle) + && reply_event.message == kEmacsSubprocessReply) + break; + + /* The return code is sent through the refCon */ + iErr = AcceptHighLevelEvent (&targ, &ref_con, NULL, &len); + if (iErr != noErr) + { + DisposeHandle ((Handle) cursor_region_handle); + free (param); + return -1; + } + + DisposeHandle ((Handle) cursor_region_handle); + free (param); + + return ref_con; +} + + +DIR * +opendir (const char *dirname) +{ + char true_pathname[MAXPATHLEN+1], fully_resolved_name[MAXPATHLEN+1]; + char mac_pathname[MAXPATHLEN+1], vol_name[MAXPATHLEN+1]; + DIR *dirp; + CInfoPBRec cipb; + HVolumeParam vpb; + int len, vol_name_len; + + if (find_true_pathname (dirname, true_pathname, MAXPATHLEN+1) == -1) + return 0; + + len = readlink (true_pathname, fully_resolved_name, MAXPATHLEN); + if (len > -1) + fully_resolved_name[len] = '\0'; + else + strcpy (fully_resolved_name, true_pathname); + + dirp = (DIR *) malloc (sizeof(DIR)); + if (!dirp) + return 0; + + /* Handle special case when dirname is "/": sets up for readir to + get all mount volumes. */ + if (strcmp (fully_resolved_name, "/") == 0) + { + dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */ + dirp->current_index = 1; /* index for first volume */ + return dirp; + } + + /* Handle typical cases: not accessing all mounted volumes. */ + if (!unix_to_mac_pathname (fully_resolved_name, mac_pathname, MAXPATHLEN+1)) + return 0; + + /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */ + len = strlen (mac_pathname); + if (mac_pathname[len - 1] != ':' && len < MAXPATHLEN) + strcat (mac_pathname, ":"); + + /* Extract volume name */ + vol_name_len = strchr (mac_pathname, ':') - mac_pathname; + strncpy (vol_name, mac_pathname, vol_name_len); + vol_name[vol_name_len] = '\0'; + strcat (vol_name, ":"); + + c2pstr (mac_pathname); + cipb.hFileInfo.ioNamePtr = mac_pathname; + /* using full pathname so vRefNum and DirID ignored */ + cipb.hFileInfo.ioVRefNum = 0; + cipb.hFileInfo.ioDirID = 0; + cipb.hFileInfo.ioFDirIndex = 0; + /* set to 0 to get information about specific dir or file */ + + errno = PBGetCatInfo (&cipb, false); + if (errno != noErr) + { + errno = ENOENT; + return 0; + } + + if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */ + return 0; /* not a directory */ + + dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */ + dirp->getting_volumes = 0; + dirp->current_index = 1; /* index for first file/directory */ + + c2pstr (vol_name); + vpb.ioNamePtr = vol_name; + /* using full pathname so vRefNum and DirID ignored */ + vpb.ioVRefNum = 0; + vpb.ioVolIndex = -1; + errno = PBHGetVInfo ((union HParamBlockRec *) &vpb, false); + if (errno != noErr) + { + errno = ENOENT; + return 0; + } + + dirp->vol_ref_num = vpb.ioVRefNum; + + return dirp; +} + +int +closedir (DIR *dp) +{ + free (dp); + + return 0; +} + + +struct dirent * +readdir (DIR *dp) +{ + HParamBlockRec hpblock; + CInfoPBRec cipb; + static struct dirent s_dirent; + static Str255 s_name; + int done; + char *p; + + /* Handle the root directory containing the mounted volumes. Call + PBHGetVInfo specifying an index to obtain the info for a volume. + PBHGetVInfo returns an error when it receives an index beyond the + last volume, at which time we should return a nil dirent struct + pointer. */ + if (dp->getting_volumes) + { + hpblock.volumeParam.ioNamePtr = s_name; + hpblock.volumeParam.ioVRefNum = 0; + hpblock.volumeParam.ioVolIndex = dp->current_index; + + errno = PBHGetVInfo (&hpblock, false); + if (errno != noErr) + { + errno = ENOENT; + return 0; + } + + p2cstr (s_name); + strcat (s_name, "/"); /* need "/" for stat to work correctly */ + + dp->current_index++; + + s_dirent.d_ino = hpblock.volumeParam.ioVRefNum; + s_dirent.d_name = s_name; + + return &s_dirent; + } + else + { + cipb.hFileInfo.ioVRefNum = dp->vol_ref_num; + cipb.hFileInfo.ioNamePtr = s_name; + /* location to receive filename returned */ + + /* return only visible files */ + done = false; + while (!done) + { + cipb.hFileInfo.ioDirID = dp->dir_id; + /* directory ID found by opendir */ + cipb.hFileInfo.ioFDirIndex = dp->current_index; + + errno = PBGetCatInfo (&cipb, false); + if (errno != noErr) + { + errno = ENOENT; + return 0; + } + + /* insist on an visibile entry */ + if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */ + done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible); + else + done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible); + + dp->current_index++; + } + + p2cstr (s_name); + + p = s_name; + while (*p) + { + if (*p == '/') + *p = ':'; + p++; + } + + s_dirent.d_ino = cipb.dirInfo.ioDrDirID; + /* value unimportant: non-zero for valid file */ + s_dirent.d_name = s_name; + + return &s_dirent; + } +} + + +char * +getwd (char *path) +{ + char mac_pathname[MAXPATHLEN+1]; + Str255 directory_name; + OSErr errno; + CInfoPBRec cipb; + + if (path_from_vol_dir_name (mac_pathname, 255, 0, 0, "\p") == 0) + return NULL; + + if (mac_to_unix_pathname (mac_pathname, path, MAXPATHLEN+1) == 0) + return 0; + else + return path; +} + + +void +initialize_applescript () +{ + AEDesc null_desc; + OSAError osaerror; + + /* if open fails, as_scripting_component is set to NULL. Its + subsequent use in OSA calls will fail with badComponentInstance + error. */ + as_scripting_component = OpenDefaultComponent (kOSAComponentType, + kAppleScriptSubtype); + + null_desc.descriptorType = typeNull; + null_desc.dataHandle = 0; + osaerror = OSAMakeContext (as_scripting_component, &null_desc, + kOSANullScript, &as_script_context); + if (osaerror) + as_script_context = kOSANullScript; + /* use default context if create fails */ +} + + +void terminate_applescript() +{ + OSADispose (as_scripting_component, as_script_context); + CloseComponent (as_scripting_component); +} + + +/* Compile and execute the AppleScript SCRIPT and return the error + status as function value. A zero is returned if compilation and + execution is successful, in which case RESULT returns a pointer to + a string containing the resulting script value. Otherwise, the Mac + error code is returned and RESULT returns a pointer to an error + string. In both cases the caller should deallocate the storage + used by the string pointed to by RESULT if it is non-NULL. For + documentation on the MacOS scripting architecture, see Inside + Macintosh - Interapplication Communications: Scripting Components. */ + +static long +do_applescript (char *script, char **result) +{ + AEDesc script_desc, result_desc, error_desc; + OSErr error; + OSAError osaerror; + long length; + + *result = 0; + + error = AECreateDesc (typeChar, script, strlen(script), &script_desc); + if (error) + return error; + + osaerror = OSADoScript (as_scripting_component, &script_desc, kOSANullScript, + typeChar, kOSAModeNull, &result_desc); + + if (osaerror == errOSAScriptError) + { + /* error executing AppleScript: retrieve error message */ + if (!OSAScriptError (as_scripting_component, kOSAErrorMessage, typeChar, + &error_desc)) + { + HLock (error_desc.dataHandle); + length = GetHandleSize(error_desc.dataHandle); + *result = (char *) xmalloc (length + 1); + if (*result) + { + memcpy (*result, *(error_desc.dataHandle), length); + *(*result + length) = '\0'; + } + HUnlock (error_desc.dataHandle); + AEDisposeDesc (&error_desc); + } + } + else if (osaerror == noErr) /* success: retrieve resulting script value */ + { + HLock (result_desc.dataHandle); + length = GetHandleSize(result_desc.dataHandle); + *result = (char *) xmalloc (length + 1); + if (*result) + { + memcpy (*result, *(result_desc.dataHandle), length); + *(*result + length) = '\0'; + } + HUnlock (result_desc.dataHandle); + } + + AEDisposeDesc (&script_desc); + AEDisposeDesc (&result_desc); + + return osaerror; +} + + +DEFUN ("do-applescript", Fdo_applescript, Sdo_applescript, 1, 1, 0, + "Compile and execute AppleScript SCRIPT and retrieve and return the\n\ +result. If compilation and execution are successful, the resulting script\n\ +value is returned as a string. Otherwise the function aborts and\n\ +displays the error message returned by the AppleScript scripting\n\ +component.") + (script) + Lisp_Object script; +{ + char *result, *temp; + Lisp_Object lisp_result; + long status; + + CHECK_STRING (script, 0); + + status = do_applescript (XSTRING (script)->data, &result); + if (status) + { + if (!result) + error ("AppleScript error %ld", status); + else + { + /* Unfortunately only OSADoScript in do_applescript knows how + how large the resulting script value or error message is + going to be and therefore as caller memory must be + deallocated here. It is necessary to free the error + message before calling error to avoid a memory leak. */ + temp = (char *) alloca (strlen (result) + 1); + strcpy (temp, result); + xfree (result); + error (temp); + } + } + else + { + lisp_result = build_string (result); + xfree (result); + return lisp_result; + } +} + + +DEFUN ("mac-filename-to-unix", Fmac_filename_to_unix, Smac_filename_to_unix, 1, + 1, 0, + "Convert Macintosh filename to Unix form.") + (mac_filename) + Lisp_Object mac_filename; +{ + char unix_filename[MAXPATHLEN+1]; + + CHECK_STRING (mac_filename, 0); + + if (mac_to_unix_pathname(XSTRING (mac_filename)->data, unix_filename, + MAXPATHLEN)) + return build_string (unix_filename); + else + return Qnil; +} + + +DEFUN ("unix-filename-to-mac", Funix_filename_to_mac, Sunix_filename_to_mac, 1, + 1, 0, + "Convert Unix filename to Mac form.") + (unix_filename) + Lisp_Object unix_filename; +{ + char mac_filename[MAXPATHLEN+1]; + + CHECK_STRING (unix_filename, 0); + + if (unix_to_mac_pathname(XSTRING (unix_filename)->data, mac_filename, + MAXPATHLEN)) + return build_string (mac_filename); + else + return Qnil; +} + + +/* set interprogram-paste-function to mac-paste-function in mac-win.el + to enable Emacs to obtain the contents of the Mac clipboard. */ +DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0, + "Return the contents of the Mac clipboard as a string.") + () +{ + Lisp_Object value; + Handle my_handle; + long scrap_offset, rc, i; + + my_handle = NewHandle (0); /* allocate 0-length data area */ + + rc = GetScrap (my_handle, 'TEXT', &scrap_offset); + if (rc < 0) + return Qnil; + + HLock (my_handle); + + /* Emacs expects clipboard contents have Unix-style eol's */ + for (i = 0; i < rc; i++) + if ((*my_handle)[i] == '\r') + (*my_handle)[i] = '\n'; + + value = make_string (*my_handle, rc); + + HUnlock (my_handle); + + DisposeHandle (my_handle); + + return value; +} + + +/* set interprogram-cut-function to mac-cut-function in mac-win.el + to enable Emacs to write the top of the kill-ring to the Mac clipboard. */ +DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0, + "Put the value of the string parameter to the Mac clipboard.") + (value, push) + Lisp_Object value, push; +{ + char *buf; + int len, i; + + /* fixme: ignore the push flag for now */ + + CHECK_STRING (value, 0); + + len = XSTRING (value)->size; + buf = (char *) alloca (len); + bcopy(XSTRING (value)->data, buf, len); + + /* convert to Mac-style eol's before sending to clipboard */ + for (i = 0; i < len; i++) + if (buf[i] == '\n') + buf[i] = '\r'; + + ZeroScrap (); + PutScrap (len, 'TEXT', buf); + + return Qnil; +} + + +DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p, + 0, 1, 0, + "Whether there is an owner for the given X Selection.\n\ +The arg should be the name of the selection in question, typically one of\n\ +the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\ +\(Those are literal upper-case symbol names, since that's what X expects.)\n\ +For convenience, the symbol nil is the same as `PRIMARY',\n\ +and t is the same as `SECONDARY'.") + (selection) + Lisp_Object selection; +{ + CHECK_SYMBOL (selection, 0); + + /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check + if the clipboard currently has valid text format contents. */ + + if (EQ (selection, QCLIPBOARD)) + { + Lisp_Object val = Qnil; + Lisp_Object value; + Handle my_handle; + long rc, scrap_offset; + + my_handle = NewHandle (0); + + rc = GetScrap (my_handle, 'TEXT', &scrap_offset); + if (rc >= 0) + val = Qt; + + DisposeHandle (my_handle); + + return val; + } + return Qnil; +} + + +void +syms_of_mac () +{ + QCLIPBOARD = intern ("CLIPBOARD"); + staticpro (&QCLIPBOARD); + + defsubr (&Smac_paste_function); + defsubr (&Smac_cut_function); + defsubr (&Sx_selection_exists_p); + + defsubr (&Sdo_applescript); + defsubr (&Smac_filename_to_unix); + defsubr (&Sunix_filename_to_mac); +} diff --git a/mac/src/macfns.c b/mac/src/macfns.c new file mode 100644 index 00000000000..bb3ba197cac --- /dev/null +++ b/mac/src/macfns.c @@ -0,0 +1,9913 @@ +/* Graphical user interface functions for Mac OS. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include + +#include +#include +#include +#include +#include + +#include "lisp.h" +#include "charset.h" +#include "macterm.h" +#include "frame.h" +#include "window.h" +#include "buffer.h" +#include "dispextern.h" +#include "fontset.h" +#include "intervals.h" +#include "keyboard.h" +#include "blockinput.h" +#include "epaths.h" +#include "termhooks.h" +#include "coding.h" +#include "ccl.h" +#include "systime.h" + +/* #include "bitmaps/gray.xbm" */ +#define gray_width 2 +#define gray_height 2 +static unsigned char gray_bits[] = { + 0x01, 0x02}; + +/*#include +#include */ +#include + +#include +#include +#include +#if 0 +#include +#endif + +#include +#include +#include + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/*extern void free_frame_menubar (); +extern double atof (); +extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state); +extern int quit_char;*/ + +/* A definition of XColor for non-X frames. */ +#ifndef HAVE_X_WINDOWS +typedef struct { + unsigned long pixel; + unsigned short red, green, blue; + char flags; + char pad; +} XColor; +#endif + +extern char *lispy_function_keys[]; + +/* The gray bitmap `bitmaps/gray'. This is done because macterm.c uses + it, and including `bitmaps/gray' more than once is a problem when + config.h defines `static' as an empty replacement string. */ + +int gray_bitmap_width = gray_width; +int gray_bitmap_height = gray_height; +unsigned char *gray_bitmap_bits = gray_bits; + +/* The name we're using in resource queries. */ + +Lisp_Object Vx_resource_name; + +/* Non nil if no window manager is in use. */ + +Lisp_Object Vx_no_window_manager; + +/* Non-zero means we're allowed to display a busy cursor. */ + +int display_busy_cursor_p; + +/* The background and shape of the mouse pointer, and shape when not + over text or in the modeline. */ + +Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape; +Lisp_Object Vx_busy_pointer_shape; + +/* The shape when over mouse-sensitive text. */ + +Lisp_Object Vx_sensitive_text_pointer_shape; + +/* Color of chars displayed in cursor box. */ + +Lisp_Object Vx_cursor_fore_pixel; + +/* Nonzero if using Windows. */ + +static int mac_in_use; + +/* Search path for bitmap files. */ + +Lisp_Object Vx_bitmap_file_path; + +/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */ + +Lisp_Object Vx_pixel_size_width_font_regexp; + +/* Evaluate this expression to rebuild the section of syms_of_macfns + that initializes and staticpros the symbols declared below. Note + that Emacs 18 has a bug that keeps C-x C-e from being able to + evaluate this expression. + +(progn + ;; Accumulate a list of the symbols we want to initialize from the + ;; declarations at the top of the file. + (goto-char (point-min)) + (search-forward "/\*&&& symbols declared here &&&*\/\n") + (let (symbol-list) + (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)") + (setq symbol-list + (cons (buffer-substring (match-beginning 1) (match-end 1)) + symbol-list)) + (forward-line 1)) + (setq symbol-list (nreverse symbol-list)) + ;; Delete the section of syms_of_... where we initialize the symbols. + (search-forward "\n /\*&&& init symbols here &&&*\/\n") + (let ((start (point))) + (while (looking-at "^ Q") + (forward-line 2)) + (kill-region start (point))) + ;; Write a new symbol initialization section. + (while symbol-list + (insert (format " %s = intern (\"" (car symbol-list))) + (let ((start (point))) + (insert (substring (car symbol-list) 1)) + (subst-char-in-region start (point) ?_ ?-)) + (insert (format "\");\n staticpro (&%s);\n" (car symbol-list))) + (setq symbol-list (cdr symbol-list))))) + + */ + +/*&&& symbols declared here &&&*/ +Lisp_Object Qauto_raise; +Lisp_Object Qauto_lower; +Lisp_Object Qbar; +Lisp_Object Qborder_color; +Lisp_Object Qborder_width; +Lisp_Object Qbox; +Lisp_Object Qcursor_color; +Lisp_Object Qcursor_type; +Lisp_Object Qgeometry; +Lisp_Object Qicon_left; +Lisp_Object Qicon_top; +Lisp_Object Qicon_type; +Lisp_Object Qicon_name; +Lisp_Object Qinternal_border_width; +Lisp_Object Qleft; +Lisp_Object Qright; +Lisp_Object Qmouse_color; +Lisp_Object Qnone; +Lisp_Object Qparent_id; +Lisp_Object Qscroll_bar_width; +Lisp_Object Qsuppress_icon; +Lisp_Object Qundefined_color; +Lisp_Object Qvertical_scroll_bars; +Lisp_Object Qvisibility; +Lisp_Object Qwindow_id; +Lisp_Object Qx_frame_parameter; +Lisp_Object Qx_resource_name; +Lisp_Object Quser_position; +Lisp_Object Quser_size; +Lisp_Object Qscreen_gamma; +Lisp_Object Qline_spacing; +Lisp_Object Qcenter; +Lisp_Object Qhyper; +Lisp_Object Qsuper; +Lisp_Object Qmeta; +Lisp_Object Qalt; +Lisp_Object Qctrl; +Lisp_Object Qcontrol; +Lisp_Object Qshift; + +extern Lisp_Object Qtop; +extern Lisp_Object Qdisplay; +Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background; +extern Lisp_Object Qtool_bar_lines; + +/* These are defined in frame.c. */ +extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth; +extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle; +extern Lisp_Object Qtool_bar_lines; + +extern Lisp_Object Vwindow_system_version; + +Lisp_Object Qface_set_after_frame_default; + +/* Functions in macterm.c. */ +extern void x_set_offset (struct frame *, int, int, int); +extern void x_wm_set_icon_position (struct frame *, int, int); +extern void x_display_cursor (struct window *, int, int, int, int, int); +extern void x_set_window_size (struct frame *, int, int, int); +extern void x_make_frame_visible (struct frame *); +extern struct mac_display_info *x_term_init (Lisp_Object, char *, char *); +extern struct font_info *x_get_font_info (FRAME_PTR, int); +extern struct font_info *x_load_font (struct frame *, char *, int); +extern void x_find_ccl_program (struct font_info *); +extern struct font_info *x_query_font (struct frame *, char *); + + +/* compare two strings ignoring case */ + +static int +stricmp (const char *s, const char *t) +{ + for ( ; tolower (*s) == tolower (*t); s++, t++) + if (*s == '\0') + return 0; + return tolower (*s) - tolower (*t); +} + +/* compare two strings up to n characters, ignoring case */ + +static int +strnicmp (const char *s, const char *t, unsigned int n) +{ + for ( ; n-- > 0 && tolower (*s) == tolower (*t); s++, t++) + if (*s == '\0') + return 0; + return n == 0 ? 0 : tolower (*s) - tolower (*t); +} + + +/* Error if we are not running on Mac OS. */ + +void +check_mac () +{ + if (! mac_in_use) + error ("Mac OS not in use or not initialized"); +} + +/* Nonzero if we can use mouse menus. + You should not call this unless HAVE_MENUS is defined. */ + +int +have_menus_p () +{ + return mac_in_use; +} + +/* Extract a frame as a FRAME_PTR, defaulting to the selected frame + and checking validity for W32. */ + +FRAME_PTR +check_x_frame (frame) + Lisp_Object frame; +{ + FRAME_PTR f; + + if (NILP (frame)) + frame = selected_frame; + CHECK_LIVE_FRAME (frame, 0); + f = XFRAME (frame); + if (! FRAME_MAC_P (f)) + error ("non-mac frame used"); + return f; +} + +/* Let the user specify an display with a frame. + nil stands for the selected frame--or, if that is not a mac frame, + the first display on the list. */ + +static struct mac_display_info * +check_x_display_info (frame) + Lisp_Object frame; +{ + if (NILP (frame)) + { + struct frame *sf = XFRAME (selected_frame); + + if (FRAME_MAC_P (sf) && FRAME_LIVE_P (sf)) + return FRAME_MAC_DISPLAY_INFO (sf); + else + return &one_mac_display_info; + } + else if (STRINGP (frame)) + return x_display_info_for_name (frame); + else + { + FRAME_PTR f; + + CHECK_LIVE_FRAME (frame, 0); + f = XFRAME (frame); + if (! FRAME_MAC_P (f)) + error ("non-mac frame used"); + return FRAME_MAC_DISPLAY_INFO (f); + } +} + +/* Return the Emacs frame-object corresponding to an mac window. + It could be the frame's main window or an icon window. */ + +/* This function can be called during GC, so use GC_xxx type test macros. */ + +struct frame * +x_window_to_frame (dpyinfo, wdesc) + struct mac_display_info *dpyinfo; + WindowPtr wdesc; +{ + Lisp_Object tail, frame; + struct frame *f; + + for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) + { + frame = XCAR (tail); + if (!GC_FRAMEP (frame)) + continue; + f = XFRAME (frame); + if (!FRAME_W32_P (f) || FRAME_MAC_DISPLAY_INFO (f) != dpyinfo) + continue; + /*if (f->output_data.w32->busy_window == wdesc) + return f;*/ + + /* MAC_TODO: Check tooltips when supported. */ + if (FRAME_MAC_WINDOW (f) == wdesc) + return f; + } + return 0; +} + + + +/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap + id, which is just an int that this section returns. Bitmaps are + reference counted so they can be shared among frames. + + Bitmap indices are guaranteed to be > 0, so a negative number can + be used to indicate no bitmap. + + If you use x_create_bitmap_from_data, then you must keep track of + the bitmaps yourself. That is, creating a bitmap from the same + data more than once will not be caught. */ + + +/* Functions to access the contents of a bitmap, given an id. */ + +int +x_bitmap_height (f, id) + FRAME_PTR f; + int id; +{ + return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height; +} + +int +x_bitmap_width (f, id) + FRAME_PTR f; + int id; +{ + return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width; +} + +#if 0 /* MAC_TODO : not used anywhere (?) */ +int +x_bitmap_pixmap (f, id) + FRAME_PTR f; + int id; +{ + return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; +} +#endif + +/* Allocate a new bitmap record. Returns index of new record. */ + +static int +x_allocate_bitmap_record (f) + FRAME_PTR f; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + int i; + + if (dpyinfo->bitmaps == NULL) + { + dpyinfo->bitmaps_size = 10; + dpyinfo->bitmaps = (struct mac_bitmap_record *) + xmalloc (dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record)); + dpyinfo->bitmaps_last = 1; + return 1; + } + + if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size) + return ++dpyinfo->bitmaps_last; + + for (i = 0; i < dpyinfo->bitmaps_size; ++i) + if (dpyinfo->bitmaps[i].refcount == 0) + return i + 1; + + dpyinfo->bitmaps_size *= 2; + dpyinfo->bitmaps = (struct mac_bitmap_record *) + xrealloc (dpyinfo->bitmaps, + dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record)); + return ++dpyinfo->bitmaps_last; +} + +/* Add one reference to the reference count of the bitmap with id + ID. */ + +void +x_reference_bitmap (f, id) + FRAME_PTR f; + int id; +{ + ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount; +} + +/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at + BITS. */ + +int +x_create_bitmap_from_data (f, bits, width, height) + struct frame *f; + char *bits; + unsigned int width, height; +{ + struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + int id; + + /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */ + + id = x_allocate_bitmap_record (f); + + if (width % 16 != 0) + return -1; + + dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width); + if (! dpyinfo->bitmaps[id - 1].bitmap_data) + return -1; + + bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width); + + dpyinfo->bitmaps[id - 1].refcount = 1; + dpyinfo->bitmaps[id - 1].height = height; + dpyinfo->bitmaps[id - 1].width = width; + + return id; +} + +/* Create bitmap from file FILE for frame F. */ + +int +x_create_bitmap_from_file (f, file) + struct frame *f; + Lisp_Object file; +{ + return -1; +#if 0 /* MAC_TODO : bitmap support */ + struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); + unsigned int width, height; + HBITMAP bitmap; + int xhot, yhot, result, id; + Lisp_Object found; + int fd; + char *filename; + HINSTANCE hinst; + + /* Look for an existing bitmap with the same name. */ + for (id = 0; id < dpyinfo->bitmaps_last; ++id) + { + if (dpyinfo->bitmaps[id].refcount + && dpyinfo->bitmaps[id].file + && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data)) + { + ++dpyinfo->bitmaps[id].refcount; + return id + 1; + } + } + + /* Search bitmap-file-path for the file, if appropriate. */ + fd = openp (Vx_bitmap_file_path, file, "", &found, 0); + if (fd < 0) + return -1; + /* LoadLibraryEx won't handle special files handled by Emacs handler. */ + if (fd == 0) + return -1; + emacs_close (fd); + + filename = (char *) XSTRING (found)->data; + + hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE); + + if (hinst == NULL) + return -1; + + + result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), + filename, &width, &height, &bitmap, &xhot, &yhot); + if (result != BitmapSuccess) + return -1; + + id = x_allocate_bitmap_record (f); + dpyinfo->bitmaps[id - 1].pixmap = bitmap; + dpyinfo->bitmaps[id - 1].refcount = 1; + dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1); + dpyinfo->bitmaps[id - 1].depth = 1; + dpyinfo->bitmaps[id - 1].height = height; + dpyinfo->bitmaps[id - 1].width = width; + strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data); + + return id; +#endif /* MAC_TODO */ +} + +/* Remove reference to bitmap with id number ID. */ + +void +x_destroy_bitmap (f, id) + FRAME_PTR f; + int id; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + if (id > 0) + { + --dpyinfo->bitmaps[id - 1].refcount; + if (dpyinfo->bitmaps[id - 1].refcount == 0) + { + BLOCK_INPUT; + dpyinfo->bitmaps[id - 1].bitmap_data = NULL; + UNBLOCK_INPUT; + } + } +} + +/* Free all the bitmaps for the display specified by DPYINFO. */ + +static void +x_destroy_all_bitmaps (dpyinfo) + struct mac_display_info *dpyinfo; +{ + int i; + for (i = 0; i < dpyinfo->bitmaps_last; i++) + if (dpyinfo->bitmaps[i].refcount > 0) + xfree (dpyinfo->bitmaps[i].bitmap_data); + dpyinfo->bitmaps_last = 0; +} + +/* Connect the frame-parameter names for W32 frames + to the ways of passing the parameter values to the window system. + + The name of a parameter, as a Lisp symbol, + has an `x-frame-parameter' property which is an integer in Lisp + but can be interpreted as an `enum x_frame_parm' in C. */ + +struct x_frame_parm_table +{ + char *name; + void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object)); +}; + +void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); +static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_internal_border_width P_ ((struct frame *, Lisp_Object, + Lisp_Object)); +void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object, + Lisp_Object)); +void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object)); +void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object, + Lisp_Object)); +void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object, + Lisp_Object)); +static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *, + Lisp_Object, + Lisp_Object, + char *, char *, + int)); +static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object)); + +static struct x_frame_parm_table x_frame_parms[] = +{ + "auto-raise", x_set_autoraise, + "auto-lower", x_set_autolower, + "background-color", x_set_background_color, + "border-color", x_set_border_color, + "border-width", x_set_border_width, + "cursor-color", x_set_cursor_color, + "cursor-type", x_set_cursor_type, + "font", x_set_font, + "foreground-color", x_set_foreground_color, + "icon-name", x_set_icon_name, +#if 0 /* MAC_TODO: no icons for Mac */ + "icon-type", x_set_icon_type, +#endif + "internal-border-width", x_set_internal_border_width, + "menu-bar-lines", x_set_menu_bar_lines, + "mouse-color", x_set_mouse_color, + "name", x_explicitly_set_name, + "scroll-bar-width", x_set_scroll_bar_width, + "title", x_set_title, + "unsplittable", x_set_unsplittable, + "vertical-scroll-bars", x_set_vertical_scroll_bars, + "visibility", x_set_visibility, + "tool-bar-lines", x_set_tool_bar_lines, +#if 0 /* MAC_TODO: cannot set color of scroll bar on the Mac? */ + "scroll-bar-foreground", x_set_scroll_bar_foreground, + "scroll-bar-background", x_set_scroll_bar_background, +#endif + "screen-gamma", x_set_screen_gamma, + "line-spacing", x_set_line_spacing +}; + +/* Attach the `x-frame-parameter' properties to + the Lisp symbol names of parameters relevant to Mac. */ + +void +init_x_parm_symbols () +{ + int i; + + for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++) + Fput (intern (x_frame_parms[i].name), Qx_frame_parameter, + make_number (i)); +} + +/* Change the parameters of frame F as specified by ALIST. + If a parameter is not specially recognized, do nothing; + otherwise call the `x_set_...' function for that parameter. */ + +void +x_set_frame_parameters (f, alist) + FRAME_PTR f; + Lisp_Object alist; +{ + Lisp_Object tail; + + /* If both of these parameters are present, it's more efficient to + set them both at once. So we wait until we've looked at the + entire list before we set them. */ + int width, height; + + /* Same here. */ + Lisp_Object left, top; + + /* Same with these. */ + Lisp_Object icon_left, icon_top; + + /* Record in these vectors all the parms specified. */ + Lisp_Object *parms; + Lisp_Object *values; + int i, p; + int left_no_change = 0, top_no_change = 0; + int icon_left_no_change = 0, icon_top_no_change = 0; + + struct gcpro gcpro1, gcpro2; + + i = 0; + for (tail = alist; CONSP (tail); tail = Fcdr (tail)) + i++; + + parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object)); + values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object)); + + /* Extract parm names and values into those vectors. */ + + i = 0; + for (tail = alist; CONSP (tail); tail = Fcdr (tail)) + { + Lisp_Object elt; + + elt = Fcar (tail); + parms[i] = Fcar (elt); + values[i] = Fcdr (elt); + i++; + } + /* TAIL and ALIST are not used again below here. */ + alist = tail = Qnil; + + GCPRO2 (*parms, *values); + gcpro1.nvars = i; + gcpro2.nvars = i; + + /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP, + because their values appear in VALUES and strings are not valid. */ + top = left = Qunbound; + icon_left = icon_top = Qunbound; + + /* Provide default values for HEIGHT and WIDTH. */ + if (FRAME_NEW_WIDTH (f)) + width = FRAME_NEW_WIDTH (f); + else + width = FRAME_WIDTH (f); + + if (FRAME_NEW_HEIGHT (f)) + height = FRAME_NEW_HEIGHT (f); + else + height = FRAME_HEIGHT (f); + + /* Process foreground_color and background_color before anything else. + They are independent of other properties, but other properties (e.g., + cursor_color) are dependent upon them. */ + for (p = 0; p < i; p++) + { + Lisp_Object prop, val; + + prop = parms[p]; + val = values[p]; + if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color)) + { + register Lisp_Object param_index, old_value; + + param_index = Fget (prop, Qx_frame_parameter); + old_value = get_frame_param (f, prop); + store_frame_param (f, prop, val); + if (NATNUMP (param_index) + && (XFASTINT (param_index) + < sizeof (x_frame_parms)/sizeof (x_frame_parms[0]))) + (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value); + } + } + + /* Now process them in reverse of specified order. */ + for (i--; i >= 0; i--) + { + Lisp_Object prop, val; + + prop = parms[i]; + val = values[i]; + + if (EQ (prop, Qwidth) && NUMBERP (val)) + width = XFASTINT (val); + else if (EQ (prop, Qheight) && NUMBERP (val)) + height = XFASTINT (val); + else if (EQ (prop, Qtop)) + top = val; + else if (EQ (prop, Qleft)) + left = val; + else if (EQ (prop, Qicon_top)) + icon_top = val; + else if (EQ (prop, Qicon_left)) + icon_left = val; + else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color)) + /* Processed above. */ + continue; + else + { + register Lisp_Object param_index, old_value; + + param_index = Fget (prop, Qx_frame_parameter); + old_value = get_frame_param (f, prop); + store_frame_param (f, prop, val); + if (NATNUMP (param_index) + && (XFASTINT (param_index) + < sizeof (x_frame_parms)/sizeof (x_frame_parms[0]))) + (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value); + } + } + + /* Don't die if just one of these was set. */ + if (EQ (left, Qunbound)) + { + left_no_change = 1; + if (f->output_data.mac->left_pos < 0) + left = Fcons (Qplus, + Fcons (make_number (f->output_data.mac->left_pos), + Qnil)); + else + XSETINT (left, f->output_data.mac->left_pos); + } + if (EQ (top, Qunbound)) + { + top_no_change = 1; + if (f->output_data.mac->top_pos < 0) + top = Fcons (Qplus, + Fcons (make_number (f->output_data.mac->top_pos), Qnil)); + else + XSETINT (top, f->output_data.mac->top_pos); + } + + /* If one of the icon positions was not set, preserve or default it. */ + if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left)) + { + icon_left_no_change = 1; + icon_left = Fcdr (Fassq (Qicon_left, f->param_alist)); + if (NILP (icon_left)) + XSETINT (icon_left, 0); + } + if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top)) + { + icon_top_no_change = 1; + icon_top = Fcdr (Fassq (Qicon_top, f->param_alist)); + if (NILP (icon_top)) + XSETINT (icon_top, 0); + } + + /* Don't set these parameters unless they've been explicitly + specified. The window might be mapped or resized while we're in + this function, and we don't want to override that unless the lisp + code has asked for it. + + Don't set these parameters unless they actually differ from the + window's current parameters; the window may not actually exist + yet. */ + { + Lisp_Object frame; + + check_frame_size (f, &height, &width); + + XSETFRAME (frame, f); + + if (width != FRAME_WIDTH (f) + || height != FRAME_HEIGHT (f) + || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f)) + Fset_frame_size (frame, make_number (width), make_number (height)); + + if ((!NILP (left) || !NILP (top)) + && ! (left_no_change && top_no_change) + && ! (NUMBERP (left) && XINT (left) == f->output_data.mac->left_pos + && NUMBERP (top) && XINT (top) == f->output_data.mac->top_pos)) + { + int leftpos = 0; + int toppos = 0; + + /* Record the signs. */ + f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative); + if (EQ (left, Qminus)) + f->output_data.mac->size_hint_flags |= XNegative; + else if (INTEGERP (left)) + { + leftpos = XINT (left); + if (leftpos < 0) + f->output_data.mac->size_hint_flags |= XNegative; + } + else if (CONSP (left) && EQ (XCAR (left), Qminus) + && CONSP (XCDR (left)) + && INTEGERP (XCAR (XCDR (left)))) + { + leftpos = - XINT (XCAR (XCDR (left))); + f->output_data.mac->size_hint_flags |= XNegative; + } + else if (CONSP (left) && EQ (XCAR (left), Qplus) + && CONSP (XCDR (left)) + && INTEGERP (XCAR (XCDR (left)))) + { + leftpos = XINT (XCAR (XCDR (left))); + } + + if (EQ (top, Qminus)) + f->output_data.mac->size_hint_flags |= YNegative; + else if (INTEGERP (top)) + { + toppos = XINT (top); + if (toppos < 0) + f->output_data.mac->size_hint_flags |= YNegative; + } + else if (CONSP (top) && EQ (XCAR (top), Qminus) + && CONSP (XCDR (top)) + && INTEGERP (XCAR (XCDR (top)))) + { + toppos = - XINT (XCAR (XCDR (top))); + f->output_data.mac->size_hint_flags |= YNegative; + } + else if (CONSP (top) && EQ (XCAR (top), Qplus) + && CONSP (XCDR (top)) + && INTEGERP (XCAR (XCDR (top)))) + { + toppos = XINT (XCAR (XCDR (top))); + } + + + /* Store the numeric value of the position. */ + f->output_data.mac->top_pos = toppos; + f->output_data.mac->left_pos = leftpos; + + f->output_data.mac->win_gravity = NorthWestGravity; + + /* Actually set that position, and convert to absolute. */ + x_set_offset (f, leftpos, toppos, -1); + } + + if ((!NILP (icon_left) || !NILP (icon_top)) + && ! (icon_left_no_change && icon_top_no_change)) + x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top)); + } + + UNGCPRO; +} + +/* Store the screen positions of frame F into XPTR and YPTR. + These are the positions of the containing window manager window, + not Emacs's own window. */ + +void +x_real_positions (f, xptr, yptr) + FRAME_PTR f; + int *xptr, *yptr; +{ + Point pt; + GrafPtr oldport; + + SetPt (&pt, + f->output_data.mac->mWP->portRect.left, + f->output_data.mac->mWP->portRect.top); + GetPort (&oldport); + LocalToGlobal (&pt); + SetPort (oldport); + + *xptr = pt.h; + *yptr = pt.v; +} + +/* Insert a description of internally-recorded parameters of frame X + into the parameter alist *ALISTPTR that is to be given to the user. + Only parameters that are specific to Mac and whose values are not + correctly recorded in the frame's param_alist need to be considered + here. */ + +void +x_report_frame_params (f, alistptr) + struct frame *f; + Lisp_Object *alistptr; +{ + char buf[16]; + Lisp_Object tem; + + /* Represent negative positions (off the top or left screen edge) + in a way that Fmodify_frame_parameters will understand correctly. */ + XSETINT (tem, f->output_data.mac->left_pos); + if (f->output_data.mac->left_pos >= 0) + store_in_alist (alistptr, Qleft, tem); + else + store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil))); + + XSETINT (tem, f->output_data.mac->top_pos); + if (f->output_data.mac->top_pos >= 0) + store_in_alist (alistptr, Qtop, tem); + else + store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil))); + + store_in_alist (alistptr, Qborder_width, + make_number (f->output_data.mac->border_width)); + store_in_alist (alistptr, Qinternal_border_width, + make_number (f->output_data.mac->internal_border_width)); + sprintf (buf, "%ld", (long) FRAME_MAC_WINDOW (f)); + store_in_alist (alistptr, Qwindow_id, + build_string (buf)); + store_in_alist (alistptr, Qicon_name, f->icon_name); + FRAME_SAMPLE_VISIBILITY (f); + store_in_alist (alistptr, Qvisibility, + (FRAME_VISIBLE_P (f) ? Qt + : FRAME_ICONIFIED_P (f) ? Qicon : Qnil)); + store_in_alist (alistptr, Qdisplay, + XCAR (FRAME_MAC_DISPLAY_INFO (f)->name_list_element)); +} + +/* The default colors for the Mac color map */ +typedef struct colormap_t +{ + unsigned long color; + char *name; +} colormap_t; + +colormap_t mac_color_map[] = +{ + { RGB_TO_ULONG(255, 250, 250), "snow" }, + { RGB_TO_ULONG(248, 248, 255), "ghost white" }, + { RGB_TO_ULONG(248, 248, 255), "GhostWhite" }, + { RGB_TO_ULONG(245, 245, 245), "white smoke" }, + { RGB_TO_ULONG(245, 245, 245), "WhiteSmoke" }, + { RGB_TO_ULONG(220, 220, 220), "gainsboro" }, + { RGB_TO_ULONG(255, 250, 240), "floral white" }, + { RGB_TO_ULONG(255, 250, 240), "FloralWhite" }, + { RGB_TO_ULONG(253, 245, 230), "old lace" }, + { RGB_TO_ULONG(253, 245, 230), "OldLace" }, + { RGB_TO_ULONG(250, 240, 230), "linen" }, + { RGB_TO_ULONG(250, 235, 215), "antique white" }, + { RGB_TO_ULONG(250, 235, 215), "AntiqueWhite" }, + { RGB_TO_ULONG(255, 239, 213), "papaya whip" }, + { RGB_TO_ULONG(255, 239, 213), "PapayaWhip" }, + { RGB_TO_ULONG(255, 235, 205), "blanched almond" }, + { RGB_TO_ULONG(255, 235, 205), "BlanchedAlmond" }, + { RGB_TO_ULONG(255, 228, 196), "bisque" }, + { RGB_TO_ULONG(255, 218, 185), "peach puff" }, + { RGB_TO_ULONG(255, 218, 185), "PeachPuff" }, + { RGB_TO_ULONG(255, 222, 173), "navajo white" }, + { RGB_TO_ULONG(255, 222, 173), "NavajoWhite" }, + { RGB_TO_ULONG(255, 228, 181), "moccasin" }, + { RGB_TO_ULONG(255, 248, 220), "cornsilk" }, + { RGB_TO_ULONG(255, 255, 240), "ivory" }, + { RGB_TO_ULONG(255, 250, 205), "lemon chiffon" }, + { RGB_TO_ULONG(255, 250, 205), "LemonChiffon" }, + { RGB_TO_ULONG(255, 245, 238), "seashell" }, + { RGB_TO_ULONG(240, 255, 240), "honeydew" }, + { RGB_TO_ULONG(245, 255, 250), "mint cream" }, + { RGB_TO_ULONG(245, 255, 250), "MintCream" }, + { RGB_TO_ULONG(240, 255, 255), "azure" }, + { RGB_TO_ULONG(240, 248, 255), "alice blue" }, + { RGB_TO_ULONG(240, 248, 255), "AliceBlue" }, + { RGB_TO_ULONG(230, 230, 250), "lavender" }, + { RGB_TO_ULONG(255, 240, 245), "lavender blush" }, + { RGB_TO_ULONG(255, 240, 245), "LavenderBlush" }, + { RGB_TO_ULONG(255, 228, 225), "misty rose" }, + { RGB_TO_ULONG(255, 228, 225), "MistyRose" }, + { RGB_TO_ULONG(255, 255, 255), "white" }, + { RGB_TO_ULONG(0 , 0 , 0 ), "black" }, + { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate gray" }, + { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGray" }, + { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate grey" }, + { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGrey" }, + { RGB_TO_ULONG(105, 105, 105), "dim gray" }, + { RGB_TO_ULONG(105, 105, 105), "DimGray" }, + { RGB_TO_ULONG(105, 105, 105), "dim grey" }, + { RGB_TO_ULONG(105, 105, 105), "DimGrey" }, + { RGB_TO_ULONG(112, 128, 144), "slate gray" }, + { RGB_TO_ULONG(112, 128, 144), "SlateGray" }, + { RGB_TO_ULONG(112, 128, 144), "slate grey" }, + { RGB_TO_ULONG(112, 128, 144), "SlateGrey" }, + { RGB_TO_ULONG(119, 136, 153), "light slate gray" }, + { RGB_TO_ULONG(119, 136, 153), "LightSlateGray" }, + { RGB_TO_ULONG(119, 136, 153), "light slate grey" }, + { RGB_TO_ULONG(119, 136, 153), "LightSlateGrey" }, + { RGB_TO_ULONG(190, 190, 190), "gray" }, + { RGB_TO_ULONG(190, 190, 190), "grey" }, + { RGB_TO_ULONG(211, 211, 211), "light grey" }, + { RGB_TO_ULONG(211, 211, 211), "LightGrey" }, + { RGB_TO_ULONG(211, 211, 211), "light gray" }, + { RGB_TO_ULONG(211, 211, 211), "LightGray" }, + { RGB_TO_ULONG(25 , 25 , 112), "midnight blue" }, + { RGB_TO_ULONG(25 , 25 , 112), "MidnightBlue" }, + { RGB_TO_ULONG(0 , 0 , 128), "navy" }, + { RGB_TO_ULONG(0 , 0 , 128), "navy blue" }, + { RGB_TO_ULONG(0 , 0 , 128), "NavyBlue" }, + { RGB_TO_ULONG(100, 149, 237), "cornflower blue" }, + { RGB_TO_ULONG(100, 149, 237), "CornflowerBlue" }, + { RGB_TO_ULONG(72 , 61 , 139), "dark slate blue" }, + { RGB_TO_ULONG(72 , 61 , 139), "DarkSlateBlue" }, + { RGB_TO_ULONG(106, 90 , 205), "slate blue" }, + { RGB_TO_ULONG(106, 90 , 205), "SlateBlue" }, + { RGB_TO_ULONG(123, 104, 238), "medium slate blue" }, + { RGB_TO_ULONG(123, 104, 238), "MediumSlateBlue" }, + { RGB_TO_ULONG(132, 112, 255), "light slate blue" }, + { RGB_TO_ULONG(132, 112, 255), "LightSlateBlue" }, + { RGB_TO_ULONG(0 , 0 , 205), "medium blue" }, + { RGB_TO_ULONG(0 , 0 , 205), "MediumBlue" }, + { RGB_TO_ULONG(65 , 105, 225), "royal blue" }, + { RGB_TO_ULONG(65 , 105, 225), "RoyalBlue" }, + { RGB_TO_ULONG(0 , 0 , 255), "blue" }, + { RGB_TO_ULONG(30 , 144, 255), "dodger blue" }, + { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue" }, + { RGB_TO_ULONG(0 , 191, 255), "deep sky blue" }, + { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue" }, + { RGB_TO_ULONG(135, 206, 235), "sky blue" }, + { RGB_TO_ULONG(135, 206, 235), "SkyBlue" }, + { RGB_TO_ULONG(135, 206, 250), "light sky blue" }, + { RGB_TO_ULONG(135, 206, 250), "LightSkyBlue" }, + { RGB_TO_ULONG(70 , 130, 180), "steel blue" }, + { RGB_TO_ULONG(70 , 130, 180), "SteelBlue" }, + { RGB_TO_ULONG(176, 196, 222), "light steel blue" }, + { RGB_TO_ULONG(176, 196, 222), "LightSteelBlue" }, + { RGB_TO_ULONG(173, 216, 230), "light blue" }, + { RGB_TO_ULONG(173, 216, 230), "LightBlue" }, + { RGB_TO_ULONG(176, 224, 230), "powder blue" }, + { RGB_TO_ULONG(176, 224, 230), "PowderBlue" }, + { RGB_TO_ULONG(175, 238, 238), "pale turquoise" }, + { RGB_TO_ULONG(175, 238, 238), "PaleTurquoise" }, + { RGB_TO_ULONG(0 , 206, 209), "dark turquoise" }, + { RGB_TO_ULONG(0 , 206, 209), "DarkTurquoise" }, + { RGB_TO_ULONG(72 , 209, 204), "medium turquoise" }, + { RGB_TO_ULONG(72 , 209, 204), "MediumTurquoise" }, + { RGB_TO_ULONG(64 , 224, 208), "turquoise" }, + { RGB_TO_ULONG(0 , 255, 255), "cyan" }, + { RGB_TO_ULONG(224, 255, 255), "light cyan" }, + { RGB_TO_ULONG(224, 255, 255), "LightCyan" }, + { RGB_TO_ULONG(95 , 158, 160), "cadet blue" }, + { RGB_TO_ULONG(95 , 158, 160), "CadetBlue" }, + { RGB_TO_ULONG(102, 205, 170), "medium aquamarine" }, + { RGB_TO_ULONG(102, 205, 170), "MediumAquamarine" }, + { RGB_TO_ULONG(127, 255, 212), "aquamarine" }, + { RGB_TO_ULONG(0 , 100, 0 ), "dark green" }, + { RGB_TO_ULONG(0 , 100, 0 ), "DarkGreen" }, + { RGB_TO_ULONG(85 , 107, 47 ), "dark olive green" }, + { RGB_TO_ULONG(85 , 107, 47 ), "DarkOliveGreen" }, + { RGB_TO_ULONG(143, 188, 143), "dark sea green" }, + { RGB_TO_ULONG(143, 188, 143), "DarkSeaGreen" }, + { RGB_TO_ULONG(46 , 139, 87 ), "sea green" }, + { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen" }, + { RGB_TO_ULONG(60 , 179, 113), "medium sea green" }, + { RGB_TO_ULONG(60 , 179, 113), "MediumSeaGreen" }, + { RGB_TO_ULONG(32 , 178, 170), "light sea green" }, + { RGB_TO_ULONG(32 , 178, 170), "LightSeaGreen" }, + { RGB_TO_ULONG(152, 251, 152), "pale green" }, + { RGB_TO_ULONG(152, 251, 152), "PaleGreen" }, + { RGB_TO_ULONG(0 , 255, 127), "spring green" }, + { RGB_TO_ULONG(0 , 255, 127), "SpringGreen" }, + { RGB_TO_ULONG(124, 252, 0 ), "lawn green" }, + { RGB_TO_ULONG(124, 252, 0 ), "LawnGreen" }, + { RGB_TO_ULONG(0 , 255, 0 ), "green" }, + { RGB_TO_ULONG(127, 255, 0 ), "chartreuse" }, + { RGB_TO_ULONG(0 , 250, 154), "medium spring green" }, + { RGB_TO_ULONG(0 , 250, 154), "MediumSpringGreen" }, + { RGB_TO_ULONG(173, 255, 47 ), "green yellow" }, + { RGB_TO_ULONG(173, 255, 47 ), "GreenYellow" }, + { RGB_TO_ULONG(50 , 205, 50 ), "lime green" }, + { RGB_TO_ULONG(50 , 205, 50 ), "LimeGreen" }, + { RGB_TO_ULONG(154, 205, 50 ), "yellow green" }, + { RGB_TO_ULONG(154, 205, 50 ), "YellowGreen" }, + { RGB_TO_ULONG(34 , 139, 34 ), "forest green" }, + { RGB_TO_ULONG(34 , 139, 34 ), "ForestGreen" }, + { RGB_TO_ULONG(107, 142, 35 ), "olive drab" }, + { RGB_TO_ULONG(107, 142, 35 ), "OliveDrab" }, + { RGB_TO_ULONG(189, 183, 107), "dark khaki" }, + { RGB_TO_ULONG(189, 183, 107), "DarkKhaki" }, + { RGB_TO_ULONG(240, 230, 140), "khaki" }, + { RGB_TO_ULONG(238, 232, 170), "pale goldenrod" }, + { RGB_TO_ULONG(238, 232, 170), "PaleGoldenrod" }, + { RGB_TO_ULONG(250, 250, 210), "light goldenrod yellow" }, + { RGB_TO_ULONG(250, 250, 210), "LightGoldenrodYellow" }, + { RGB_TO_ULONG(255, 255, 224), "light yellow" }, + { RGB_TO_ULONG(255, 255, 224), "LightYellow" }, + { RGB_TO_ULONG(255, 255, 0 ), "yellow" }, + { RGB_TO_ULONG(255, 215, 0 ), "gold" }, + { RGB_TO_ULONG(238, 221, 130), "light goldenrod" }, + { RGB_TO_ULONG(238, 221, 130), "LightGoldenrod" }, + { RGB_TO_ULONG(218, 165, 32 ), "goldenrod" }, + { RGB_TO_ULONG(184, 134, 11 ), "dark goldenrod" }, + { RGB_TO_ULONG(184, 134, 11 ), "DarkGoldenrod" }, + { RGB_TO_ULONG(188, 143, 143), "rosy brown" }, + { RGB_TO_ULONG(188, 143, 143), "RosyBrown" }, + { RGB_TO_ULONG(205, 92 , 92 ), "indian red" }, + { RGB_TO_ULONG(205, 92 , 92 ), "IndianRed" }, + { RGB_TO_ULONG(139, 69 , 19 ), "saddle brown" }, + { RGB_TO_ULONG(139, 69 , 19 ), "SaddleBrown" }, + { RGB_TO_ULONG(160, 82 , 45 ), "sienna" }, + { RGB_TO_ULONG(205, 133, 63 ), "peru" }, + { RGB_TO_ULONG(222, 184, 135), "burlywood" }, + { RGB_TO_ULONG(245, 245, 220), "beige" }, + { RGB_TO_ULONG(245, 222, 179), "wheat" }, + { RGB_TO_ULONG(244, 164, 96 ), "sandy brown" }, + { RGB_TO_ULONG(244, 164, 96 ), "SandyBrown" }, + { RGB_TO_ULONG(210, 180, 140), "tan" }, + { RGB_TO_ULONG(210, 105, 30 ), "chocolate" }, + { RGB_TO_ULONG(178, 34 , 34 ), "firebrick" }, + { RGB_TO_ULONG(165, 42 , 42 ), "brown" }, + { RGB_TO_ULONG(233, 150, 122), "dark salmon" }, + { RGB_TO_ULONG(233, 150, 122), "DarkSalmon" }, + { RGB_TO_ULONG(250, 128, 114), "salmon" }, + { RGB_TO_ULONG(255, 160, 122), "light salmon" }, + { RGB_TO_ULONG(255, 160, 122), "LightSalmon" }, + { RGB_TO_ULONG(255, 165, 0 ), "orange" }, + { RGB_TO_ULONG(255, 140, 0 ), "dark orange" }, + { RGB_TO_ULONG(255, 140, 0 ), "DarkOrange" }, + { RGB_TO_ULONG(255, 127, 80 ), "coral" }, + { RGB_TO_ULONG(240, 128, 128), "light coral" }, + { RGB_TO_ULONG(240, 128, 128), "LightCoral" }, + { RGB_TO_ULONG(255, 99 , 71 ), "tomato" }, + { RGB_TO_ULONG(255, 69 , 0 ), "orange red" }, + { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed" }, + { RGB_TO_ULONG(255, 0 , 0 ), "red" }, + { RGB_TO_ULONG(255, 105, 180), "hot pink" }, + { RGB_TO_ULONG(255, 105, 180), "HotPink" }, + { RGB_TO_ULONG(255, 20 , 147), "deep pink" }, + { RGB_TO_ULONG(255, 20 , 147), "DeepPink" }, + { RGB_TO_ULONG(255, 192, 203), "pink" }, + { RGB_TO_ULONG(255, 182, 193), "light pink" }, + { RGB_TO_ULONG(255, 182, 193), "LightPink" }, + { RGB_TO_ULONG(219, 112, 147), "pale violet red" }, + { RGB_TO_ULONG(219, 112, 147), "PaleVioletRed" }, + { RGB_TO_ULONG(176, 48 , 96 ), "maroon" }, + { RGB_TO_ULONG(199, 21 , 133), "medium violet red" }, + { RGB_TO_ULONG(199, 21 , 133), "MediumVioletRed" }, + { RGB_TO_ULONG(208, 32 , 144), "violet red" }, + { RGB_TO_ULONG(208, 32 , 144), "VioletRed" }, + { RGB_TO_ULONG(255, 0 , 255), "magenta" }, + { RGB_TO_ULONG(238, 130, 238), "violet" }, + { RGB_TO_ULONG(221, 160, 221), "plum" }, + { RGB_TO_ULONG(218, 112, 214), "orchid" }, + { RGB_TO_ULONG(186, 85 , 211), "medium orchid" }, + { RGB_TO_ULONG(186, 85 , 211), "MediumOrchid" }, + { RGB_TO_ULONG(153, 50 , 204), "dark orchid" }, + { RGB_TO_ULONG(153, 50 , 204), "DarkOrchid" }, + { RGB_TO_ULONG(148, 0 , 211), "dark violet" }, + { RGB_TO_ULONG(148, 0 , 211), "DarkViolet" }, + { RGB_TO_ULONG(138, 43 , 226), "blue violet" }, + { RGB_TO_ULONG(138, 43 , 226), "BlueViolet" }, + { RGB_TO_ULONG(160, 32 , 240), "purple" }, + { RGB_TO_ULONG(147, 112, 219), "medium purple" }, + { RGB_TO_ULONG(147, 112, 219), "MediumPurple" }, + { RGB_TO_ULONG(216, 191, 216), "thistle" }, + { RGB_TO_ULONG(255, 250, 250), "snow1" }, + { RGB_TO_ULONG(238, 233, 233), "snow2" }, + { RGB_TO_ULONG(205, 201, 201), "snow3" }, + { RGB_TO_ULONG(139, 137, 137), "snow4" }, + { RGB_TO_ULONG(255, 245, 238), "seashell1" }, + { RGB_TO_ULONG(238, 229, 222), "seashell2" }, + { RGB_TO_ULONG(205, 197, 191), "seashell3" }, + { RGB_TO_ULONG(139, 134, 130), "seashell4" }, + { RGB_TO_ULONG(255, 239, 219), "AntiqueWhite1" }, + { RGB_TO_ULONG(238, 223, 204), "AntiqueWhite2" }, + { RGB_TO_ULONG(205, 192, 176), "AntiqueWhite3" }, + { RGB_TO_ULONG(139, 131, 120), "AntiqueWhite4" }, + { RGB_TO_ULONG(255, 228, 196), "bisque1" }, + { RGB_TO_ULONG(238, 213, 183), "bisque2" }, + { RGB_TO_ULONG(205, 183, 158), "bisque3" }, + { RGB_TO_ULONG(139, 125, 107), "bisque4" }, + { RGB_TO_ULONG(255, 218, 185), "PeachPuff1" }, + { RGB_TO_ULONG(238, 203, 173), "PeachPuff2" }, + { RGB_TO_ULONG(205, 175, 149), "PeachPuff3" }, + { RGB_TO_ULONG(139, 119, 101), "PeachPuff4" }, + { RGB_TO_ULONG(255, 222, 173), "NavajoWhite1" }, + { RGB_TO_ULONG(238, 207, 161), "NavajoWhite2" }, + { RGB_TO_ULONG(205, 179, 139), "NavajoWhite3" }, + { RGB_TO_ULONG(139, 121, 94), "NavajoWhite4" }, + { RGB_TO_ULONG(255, 250, 205), "LemonChiffon1" }, + { RGB_TO_ULONG(238, 233, 191), "LemonChiffon2" }, + { RGB_TO_ULONG(205, 201, 165), "LemonChiffon3" }, + { RGB_TO_ULONG(139, 137, 112), "LemonChiffon4" }, + { RGB_TO_ULONG(255, 248, 220), "cornsilk1" }, + { RGB_TO_ULONG(238, 232, 205), "cornsilk2" }, + { RGB_TO_ULONG(205, 200, 177), "cornsilk3" }, + { RGB_TO_ULONG(139, 136, 120), "cornsilk4" }, + { RGB_TO_ULONG(255, 255, 240), "ivory1" }, + { RGB_TO_ULONG(238, 238, 224), "ivory2" }, + { RGB_TO_ULONG(205, 205, 193), "ivory3" }, + { RGB_TO_ULONG(139, 139, 131), "ivory4" }, + { RGB_TO_ULONG(240, 255, 240), "honeydew1" }, + { RGB_TO_ULONG(224, 238, 224), "honeydew2" }, + { RGB_TO_ULONG(193, 205, 193), "honeydew3" }, + { RGB_TO_ULONG(131, 139, 131), "honeydew4" }, + { RGB_TO_ULONG(255, 240, 245), "LavenderBlush1" }, + { RGB_TO_ULONG(238, 224, 229), "LavenderBlush2" }, + { RGB_TO_ULONG(205, 193, 197), "LavenderBlush3" }, + { RGB_TO_ULONG(139, 131, 134), "LavenderBlush4" }, + { RGB_TO_ULONG(255, 228, 225), "MistyRose1" }, + { RGB_TO_ULONG(238, 213, 210), "MistyRose2" }, + { RGB_TO_ULONG(205, 183, 181), "MistyRose3" }, + { RGB_TO_ULONG(139, 125, 123), "MistyRose4" }, + { RGB_TO_ULONG(240, 255, 255), "azure1" }, + { RGB_TO_ULONG(224, 238, 238), "azure2" }, + { RGB_TO_ULONG(193, 205, 205), "azure3" }, + { RGB_TO_ULONG(131, 139, 139), "azure4" }, + { RGB_TO_ULONG(131, 111, 255), "SlateBlue1" }, + { RGB_TO_ULONG(122, 103, 238), "SlateBlue2" }, + { RGB_TO_ULONG(105, 89 , 205), "SlateBlue3" }, + { RGB_TO_ULONG(71 , 60 , 139), "SlateBlue4" }, + { RGB_TO_ULONG(72 , 118, 255), "RoyalBlue1" }, + { RGB_TO_ULONG(67 , 110, 238), "RoyalBlue2" }, + { RGB_TO_ULONG(58 , 95 , 205), "RoyalBlue3" }, + { RGB_TO_ULONG(39 , 64 , 139), "RoyalBlue4" }, + { RGB_TO_ULONG(0 , 0 , 255), "blue1" }, + { RGB_TO_ULONG(0 , 0 , 238), "blue2" }, + { RGB_TO_ULONG(0 , 0 , 205), "blue3" }, + { RGB_TO_ULONG(0 , 0 , 139), "blue4" }, + { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue1" }, + { RGB_TO_ULONG(28 , 134, 238), "DodgerBlue2" }, + { RGB_TO_ULONG(24 , 116, 205), "DodgerBlue3" }, + { RGB_TO_ULONG(16 , 78 , 139), "DodgerBlue4" }, + { RGB_TO_ULONG(99 , 184, 255), "SteelBlue1" }, + { RGB_TO_ULONG(92 , 172, 238), "SteelBlue2" }, + { RGB_TO_ULONG(79 , 148, 205), "SteelBlue3" }, + { RGB_TO_ULONG(54 , 100, 139), "SteelBlue4" }, + { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue1" }, + { RGB_TO_ULONG(0 , 178, 238), "DeepSkyBlue2" }, + { RGB_TO_ULONG(0 , 154, 205), "DeepSkyBlue3" }, + { RGB_TO_ULONG(0 , 104, 139), "DeepSkyBlue4" }, + { RGB_TO_ULONG(135, 206, 255), "SkyBlue1" }, + { RGB_TO_ULONG(126, 192, 238), "SkyBlue2" }, + { RGB_TO_ULONG(108, 166, 205), "SkyBlue3" }, + { RGB_TO_ULONG(74 , 112, 139), "SkyBlue4" }, + { RGB_TO_ULONG(176, 226, 255), "LightSkyBlue1" }, + { RGB_TO_ULONG(164, 211, 238), "LightSkyBlue2" }, + { RGB_TO_ULONG(141, 182, 205), "LightSkyBlue3" }, + { RGB_TO_ULONG(96 , 123, 139), "LightSkyBlue4" }, + { RGB_TO_ULONG(198, 226, 255), "SlateGray1" }, + { RGB_TO_ULONG(185, 211, 238), "SlateGray2" }, + { RGB_TO_ULONG(159, 182, 205), "SlateGray3" }, + { RGB_TO_ULONG(108, 123, 139), "SlateGray4" }, + { RGB_TO_ULONG(202, 225, 255), "LightSteelBlue1" }, + { RGB_TO_ULONG(188, 210, 238), "LightSteelBlue2" }, + { RGB_TO_ULONG(162, 181, 205), "LightSteelBlue3" }, + { RGB_TO_ULONG(110, 123, 139), "LightSteelBlue4" }, + { RGB_TO_ULONG(191, 239, 255), "LightBlue1" }, + { RGB_TO_ULONG(178, 223, 238), "LightBlue2" }, + { RGB_TO_ULONG(154, 192, 205), "LightBlue3" }, + { RGB_TO_ULONG(104, 131, 139), "LightBlue4" }, + { RGB_TO_ULONG(224, 255, 255), "LightCyan1" }, + { RGB_TO_ULONG(209, 238, 238), "LightCyan2" }, + { RGB_TO_ULONG(180, 205, 205), "LightCyan3" }, + { RGB_TO_ULONG(122, 139, 139), "LightCyan4" }, + { RGB_TO_ULONG(187, 255, 255), "PaleTurquoise1" }, + { RGB_TO_ULONG(174, 238, 238), "PaleTurquoise2" }, + { RGB_TO_ULONG(150, 205, 205), "PaleTurquoise3" }, + { RGB_TO_ULONG(102, 139, 139), "PaleTurquoise4" }, + { RGB_TO_ULONG(152, 245, 255), "CadetBlue1" }, + { RGB_TO_ULONG(142, 229, 238), "CadetBlue2" }, + { RGB_TO_ULONG(122, 197, 205), "CadetBlue3" }, + { RGB_TO_ULONG(83 , 134, 139), "CadetBlue4" }, + { RGB_TO_ULONG(0 , 245, 255), "turquoise1" }, + { RGB_TO_ULONG(0 , 229, 238), "turquoise2" }, + { RGB_TO_ULONG(0 , 197, 205), "turquoise3" }, + { RGB_TO_ULONG(0 , 134, 139), "turquoise4" }, + { RGB_TO_ULONG(0 , 255, 255), "cyan1" }, + { RGB_TO_ULONG(0 , 238, 238), "cyan2" }, + { RGB_TO_ULONG(0 , 205, 205), "cyan3" }, + { RGB_TO_ULONG(0 , 139, 139), "cyan4" }, + { RGB_TO_ULONG(151, 255, 255), "DarkSlateGray1" }, + { RGB_TO_ULONG(141, 238, 238), "DarkSlateGray2" }, + { RGB_TO_ULONG(121, 205, 205), "DarkSlateGray3" }, + { RGB_TO_ULONG(82 , 139, 139), "DarkSlateGray4" }, + { RGB_TO_ULONG(127, 255, 212), "aquamarine1" }, + { RGB_TO_ULONG(118, 238, 198), "aquamarine2" }, + { RGB_TO_ULONG(102, 205, 170), "aquamarine3" }, + { RGB_TO_ULONG(69 , 139, 116), "aquamarine4" }, + { RGB_TO_ULONG(193, 255, 193), "DarkSeaGreen1" }, + { RGB_TO_ULONG(180, 238, 180), "DarkSeaGreen2" }, + { RGB_TO_ULONG(155, 205, 155), "DarkSeaGreen3" }, + { RGB_TO_ULONG(105, 139, 105), "DarkSeaGreen4" }, + { RGB_TO_ULONG(84 , 255, 159), "SeaGreen1" }, + { RGB_TO_ULONG(78 , 238, 148), "SeaGreen2" }, + { RGB_TO_ULONG(67 , 205, 128), "SeaGreen3" }, + { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen4" }, + { RGB_TO_ULONG(154, 255, 154), "PaleGreen1" }, + { RGB_TO_ULONG(144, 238, 144), "PaleGreen2" }, + { RGB_TO_ULONG(124, 205, 124), "PaleGreen3" }, + { RGB_TO_ULONG(84 , 139, 84 ), "PaleGreen4" }, + { RGB_TO_ULONG(0 , 255, 127), "SpringGreen1" }, + { RGB_TO_ULONG(0 , 238, 118), "SpringGreen2" }, + { RGB_TO_ULONG(0 , 205, 102), "SpringGreen3" }, + { RGB_TO_ULONG(0 , 139, 69 ), "SpringGreen4" }, + { RGB_TO_ULONG(0 , 255, 0 ), "green1" }, + { RGB_TO_ULONG(0 , 238, 0 ), "green2" }, + { RGB_TO_ULONG(0 , 205, 0 ), "green3" }, + { RGB_TO_ULONG(0 , 139, 0 ), "green4" }, + { RGB_TO_ULONG(127, 255, 0 ), "chartreuse1" }, + { RGB_TO_ULONG(118, 238, 0 ), "chartreuse2" }, + { RGB_TO_ULONG(102, 205, 0 ), "chartreuse3" }, + { RGB_TO_ULONG(69 , 139, 0 ), "chartreuse4" }, + { RGB_TO_ULONG(192, 255, 62 ), "OliveDrab1" }, + { RGB_TO_ULONG(179, 238, 58 ), "OliveDrab2" }, + { RGB_TO_ULONG(154, 205, 50 ), "OliveDrab3" }, + { RGB_TO_ULONG(105, 139, 34 ), "OliveDrab4" }, + { RGB_TO_ULONG(202, 255, 112), "DarkOliveGreen1" }, + { RGB_TO_ULONG(188, 238, 104), "DarkOliveGreen2" }, + { RGB_TO_ULONG(162, 205, 90 ), "DarkOliveGreen3" }, + { RGB_TO_ULONG(110, 139, 61 ), "DarkOliveGreen4" }, + { RGB_TO_ULONG(255, 246, 143), "khaki1" }, + { RGB_TO_ULONG(238, 230, 133), "khaki2" }, + { RGB_TO_ULONG(205, 198, 115), "khaki3" }, + { RGB_TO_ULONG(139, 134, 78 ), "khaki4" }, + { RGB_TO_ULONG(255, 236, 139), "LightGoldenrod1" }, + { RGB_TO_ULONG(238, 220, 130), "LightGoldenrod2" }, + { RGB_TO_ULONG(205, 190, 112), "LightGoldenrod3" }, + { RGB_TO_ULONG(139, 129, 76 ), "LightGoldenrod4" }, + { RGB_TO_ULONG(255, 255, 224), "LightYellow1" }, + { RGB_TO_ULONG(238, 238, 209), "LightYellow2" }, + { RGB_TO_ULONG(205, 205, 180), "LightYellow3" }, + { RGB_TO_ULONG(139, 139, 122), "LightYellow4" }, + { RGB_TO_ULONG(255, 255, 0 ), "yellow1" }, + { RGB_TO_ULONG(238, 238, 0 ), "yellow2" }, + { RGB_TO_ULONG(205, 205, 0 ), "yellow3" }, + { RGB_TO_ULONG(139, 139, 0 ), "yellow4" }, + { RGB_TO_ULONG(255, 215, 0 ), "gold1" }, + { RGB_TO_ULONG(238, 201, 0 ), "gold2" }, + { RGB_TO_ULONG(205, 173, 0 ), "gold3" }, + { RGB_TO_ULONG(139, 117, 0 ), "gold4" }, + { RGB_TO_ULONG(255, 193, 37 ), "goldenrod1" }, + { RGB_TO_ULONG(238, 180, 34 ), "goldenrod2" }, + { RGB_TO_ULONG(205, 155, 29 ), "goldenrod3" }, + { RGB_TO_ULONG(139, 105, 20 ), "goldenrod4" }, + { RGB_TO_ULONG(255, 185, 15 ), "DarkGoldenrod1" }, + { RGB_TO_ULONG(238, 173, 14 ), "DarkGoldenrod2" }, + { RGB_TO_ULONG(205, 149, 12 ), "DarkGoldenrod3" }, + { RGB_TO_ULONG(139, 101, 8 ), "DarkGoldenrod4" }, + { RGB_TO_ULONG(255, 193, 193), "RosyBrown1" }, + { RGB_TO_ULONG(238, 180, 180), "RosyBrown2" }, + { RGB_TO_ULONG(205, 155, 155), "RosyBrown3" }, + { RGB_TO_ULONG(139, 105, 105), "RosyBrown4" }, + { RGB_TO_ULONG(255, 106, 106), "IndianRed1" }, + { RGB_TO_ULONG(238, 99 , 99 ), "IndianRed2" }, + { RGB_TO_ULONG(205, 85 , 85 ), "IndianRed3" }, + { RGB_TO_ULONG(139, 58 , 58 ), "IndianRed4" }, + { RGB_TO_ULONG(255, 130, 71 ), "sienna1" }, + { RGB_TO_ULONG(238, 121, 66 ), "sienna2" }, + { RGB_TO_ULONG(205, 104, 57 ), "sienna3" }, + { RGB_TO_ULONG(139, 71 , 38 ), "sienna4" }, + { RGB_TO_ULONG(255, 211, 155), "burlywood1" }, + { RGB_TO_ULONG(238, 197, 145), "burlywood2" }, + { RGB_TO_ULONG(205, 170, 125), "burlywood3" }, + { RGB_TO_ULONG(139, 115, 85 ), "burlywood4" }, + { RGB_TO_ULONG(255, 231, 186), "wheat1" }, + { RGB_TO_ULONG(238, 216, 174), "wheat2" }, + { RGB_TO_ULONG(205, 186, 150), "wheat3" }, + { RGB_TO_ULONG(139, 126, 102), "wheat4" }, + { RGB_TO_ULONG(255, 165, 79 ), "tan1" }, + { RGB_TO_ULONG(238, 154, 73 ), "tan2" }, + { RGB_TO_ULONG(205, 133, 63 ), "tan3" }, + { RGB_TO_ULONG(139, 90 , 43 ), "tan4" }, + { RGB_TO_ULONG(255, 127, 36 ), "chocolate1" }, + { RGB_TO_ULONG(238, 118, 33 ), "chocolate2" }, + { RGB_TO_ULONG(205, 102, 29 ), "chocolate3" }, + { RGB_TO_ULONG(139, 69 , 19 ), "chocolate4" }, + { RGB_TO_ULONG(255, 48 , 48 ), "firebrick1" }, + { RGB_TO_ULONG(238, 44 , 44 ), "firebrick2" }, + { RGB_TO_ULONG(205, 38 , 38 ), "firebrick3" }, + { RGB_TO_ULONG(139, 26 , 26 ), "firebrick4" }, + { RGB_TO_ULONG(255, 64 , 64 ), "brown1" }, + { RGB_TO_ULONG(238, 59 , 59 ), "brown2" }, + { RGB_TO_ULONG(205, 51 , 51 ), "brown3" }, + { RGB_TO_ULONG(139, 35 , 35 ), "brown4" }, + { RGB_TO_ULONG(255, 140, 105), "salmon1" }, + { RGB_TO_ULONG(238, 130, 98 ), "salmon2" }, + { RGB_TO_ULONG(205, 112, 84 ), "salmon3" }, + { RGB_TO_ULONG(139, 76 , 57 ), "salmon4" }, + { RGB_TO_ULONG(255, 160, 122), "LightSalmon1" }, + { RGB_TO_ULONG(238, 149, 114), "LightSalmon2" }, + { RGB_TO_ULONG(205, 129, 98 ), "LightSalmon3" }, + { RGB_TO_ULONG(139, 87 , 66 ), "LightSalmon4" }, + { RGB_TO_ULONG(255, 165, 0 ), "orange1" }, + { RGB_TO_ULONG(238, 154, 0 ), "orange2" }, + { RGB_TO_ULONG(205, 133, 0 ), "orange3" }, + { RGB_TO_ULONG(139, 90 , 0 ), "orange4" }, + { RGB_TO_ULONG(255, 127, 0 ), "DarkOrange1" }, + { RGB_TO_ULONG(238, 118, 0 ), "DarkOrange2" }, + { RGB_TO_ULONG(205, 102, 0 ), "DarkOrange3" }, + { RGB_TO_ULONG(139, 69 , 0 ), "DarkOrange4" }, + { RGB_TO_ULONG(255, 114, 86 ), "coral1" }, + { RGB_TO_ULONG(238, 106, 80 ), "coral2" }, + { RGB_TO_ULONG(205, 91 , 69 ), "coral3" }, + { RGB_TO_ULONG(139, 62 , 47 ), "coral4" }, + { RGB_TO_ULONG(255, 99 , 71 ), "tomato1" }, + { RGB_TO_ULONG(238, 92 , 66 ), "tomato2" }, + { RGB_TO_ULONG(205, 79 , 57 ), "tomato3" }, + { RGB_TO_ULONG(139, 54 , 38 ), "tomato4" }, + { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed1" }, + { RGB_TO_ULONG(238, 64 , 0 ), "OrangeRed2" }, + { RGB_TO_ULONG(205, 55 , 0 ), "OrangeRed3" }, + { RGB_TO_ULONG(139, 37 , 0 ), "OrangeRed4" }, + { RGB_TO_ULONG(255, 0 , 0 ), "red1" }, + { RGB_TO_ULONG(238, 0 , 0 ), "red2" }, + { RGB_TO_ULONG(205, 0 , 0 ), "red3" }, + { RGB_TO_ULONG(139, 0 , 0 ), "red4" }, + { RGB_TO_ULONG(255, 20 , 147), "DeepPink1" }, + { RGB_TO_ULONG(238, 18 , 137), "DeepPink2" }, + { RGB_TO_ULONG(205, 16 , 118), "DeepPink3" }, + { RGB_TO_ULONG(139, 10 , 80 ), "DeepPink4" }, + { RGB_TO_ULONG(255, 110, 180), "HotPink1" }, + { RGB_TO_ULONG(238, 106, 167), "HotPink2" }, + { RGB_TO_ULONG(205, 96 , 144), "HotPink3" }, + { RGB_TO_ULONG(139, 58 , 98 ), "HotPink4" }, + { RGB_TO_ULONG(255, 181, 197), "pink1" }, + { RGB_TO_ULONG(238, 169, 184), "pink2" }, + { RGB_TO_ULONG(205, 145, 158), "pink3" }, + { RGB_TO_ULONG(139, 99 , 108), "pink4" }, + { RGB_TO_ULONG(255, 174, 185), "LightPink1" }, + { RGB_TO_ULONG(238, 162, 173), "LightPink2" }, + { RGB_TO_ULONG(205, 140, 149), "LightPink3" }, + { RGB_TO_ULONG(139, 95 , 101), "LightPink4" }, + { RGB_TO_ULONG(255, 130, 171), "PaleVioletRed1" }, + { RGB_TO_ULONG(238, 121, 159), "PaleVioletRed2" }, + { RGB_TO_ULONG(205, 104, 137), "PaleVioletRed3" }, + { RGB_TO_ULONG(139, 71 , 93 ), "PaleVioletRed4" }, + { RGB_TO_ULONG(255, 52 , 179), "maroon1" }, + { RGB_TO_ULONG(238, 48 , 167), "maroon2" }, + { RGB_TO_ULONG(205, 41 , 144), "maroon3" }, + { RGB_TO_ULONG(139, 28 , 98 ), "maroon4" }, + { RGB_TO_ULONG(255, 62 , 150), "VioletRed1" }, + { RGB_TO_ULONG(238, 58 , 140), "VioletRed2" }, + { RGB_TO_ULONG(205, 50 , 120), "VioletRed3" }, + { RGB_TO_ULONG(139, 34 , 82 ), "VioletRed4" }, + { RGB_TO_ULONG(255, 0 , 255), "magenta1" }, + { RGB_TO_ULONG(238, 0 , 238), "magenta2" }, + { RGB_TO_ULONG(205, 0 , 205), "magenta3" }, + { RGB_TO_ULONG(139, 0 , 139), "magenta4" }, + { RGB_TO_ULONG(255, 131, 250), "orchid1" }, + { RGB_TO_ULONG(238, 122, 233), "orchid2" }, + { RGB_TO_ULONG(205, 105, 201), "orchid3" }, + { RGB_TO_ULONG(139, 71 , 137), "orchid4" }, + { RGB_TO_ULONG(255, 187, 255), "plum1" }, + { RGB_TO_ULONG(238, 174, 238), "plum2" }, + { RGB_TO_ULONG(205, 150, 205), "plum3" }, + { RGB_TO_ULONG(139, 102, 139), "plum4" }, + { RGB_TO_ULONG(224, 102, 255), "MediumOrchid1" }, + { RGB_TO_ULONG(209, 95 , 238), "MediumOrchid2" }, + { RGB_TO_ULONG(180, 82 , 205), "MediumOrchid3" }, + { RGB_TO_ULONG(122, 55 , 139), "MediumOrchid4" }, + { RGB_TO_ULONG(191, 62 , 255), "DarkOrchid1" }, + { RGB_TO_ULONG(178, 58 , 238), "DarkOrchid2" }, + { RGB_TO_ULONG(154, 50 , 205), "DarkOrchid3" }, + { RGB_TO_ULONG(104, 34 , 139), "DarkOrchid4" }, + { RGB_TO_ULONG(155, 48 , 255), "purple1" }, + { RGB_TO_ULONG(145, 44 , 238), "purple2" }, + { RGB_TO_ULONG(125, 38 , 205), "purple3" }, + { RGB_TO_ULONG(85 , 26 , 139), "purple4" }, + { RGB_TO_ULONG(171, 130, 255), "MediumPurple1" }, + { RGB_TO_ULONG(159, 121, 238), "MediumPurple2" }, + { RGB_TO_ULONG(137, 104, 205), "MediumPurple3" }, + { RGB_TO_ULONG(93 , 71 , 139), "MediumPurple4" }, + { RGB_TO_ULONG(255, 225, 255), "thistle1" }, + { RGB_TO_ULONG(238, 210, 238), "thistle2" }, + { RGB_TO_ULONG(205, 181, 205), "thistle3" }, + { RGB_TO_ULONG(139, 123, 139), "thistle4" }, + { RGB_TO_ULONG(0 , 0 , 0 ), "gray0" }, + { RGB_TO_ULONG(0 , 0 , 0 ), "grey0" }, + { RGB_TO_ULONG(3 , 3 , 3 ), "gray1" }, + { RGB_TO_ULONG(3 , 3 , 3 ), "grey1" }, + { RGB_TO_ULONG(5 , 5 , 5 ), "gray2" }, + { RGB_TO_ULONG(5 , 5 , 5 ), "grey2" }, + { RGB_TO_ULONG(8 , 8 , 8 ), "gray3" }, + { RGB_TO_ULONG(8 , 8 , 8 ), "grey3" }, + { RGB_TO_ULONG(10 , 10 , 10 ), "gray4" }, + { RGB_TO_ULONG(10 , 10 , 10 ), "grey4" }, + { RGB_TO_ULONG(13 , 13 , 13 ), "gray5" }, + { RGB_TO_ULONG(13 , 13 , 13 ), "grey5" }, + { RGB_TO_ULONG(15 , 15 , 15 ), "gray6" }, + { RGB_TO_ULONG(15 , 15 , 15 ), "grey6" }, + { RGB_TO_ULONG(18 , 18 , 18 ), "gray7" }, + { RGB_TO_ULONG(18 , 18 , 18 ), "grey7" }, + { RGB_TO_ULONG(20 , 20 , 20 ), "gray8" }, + { RGB_TO_ULONG(20 , 20 , 20 ), "grey8" }, + { RGB_TO_ULONG(23 , 23 , 23 ), "gray9" }, + { RGB_TO_ULONG(23 , 23 , 23 ), "grey9" }, + { RGB_TO_ULONG(26 , 26 , 26 ), "gray10" }, + { RGB_TO_ULONG(26 , 26 , 26 ), "grey10" }, + { RGB_TO_ULONG(28 , 28 , 28 ), "gray11" }, + { RGB_TO_ULONG(28 , 28 , 28 ), "grey11" }, + { RGB_TO_ULONG(31 , 31 , 31 ), "gray12" }, + { RGB_TO_ULONG(31 , 31 , 31 ), "grey12" }, + { RGB_TO_ULONG(33 , 33 , 33 ), "gray13" }, + { RGB_TO_ULONG(33 , 33 , 33 ), "grey13" }, + { RGB_TO_ULONG(36 , 36 , 36 ), "gray14" }, + { RGB_TO_ULONG(36 , 36 , 36 ), "grey14" }, + { RGB_TO_ULONG(38 , 38 , 38 ), "gray15" }, + { RGB_TO_ULONG(38 , 38 , 38 ), "grey15" }, + { RGB_TO_ULONG(41 , 41 , 41 ), "gray16" }, + { RGB_TO_ULONG(41 , 41 , 41 ), "grey16" }, + { RGB_TO_ULONG(43 , 43 , 43 ), "gray17" }, + { RGB_TO_ULONG(43 , 43 , 43 ), "grey17" }, + { RGB_TO_ULONG(46 , 46 , 46 ), "gray18" }, + { RGB_TO_ULONG(46 , 46 , 46 ), "grey18" }, + { RGB_TO_ULONG(48 , 48 , 48 ), "gray19" }, + { RGB_TO_ULONG(48 , 48 , 48 ), "grey19" }, + { RGB_TO_ULONG(51 , 51 , 51 ), "gray20" }, + { RGB_TO_ULONG(51 , 51 , 51 ), "grey20" }, + { RGB_TO_ULONG(54 , 54 , 54 ), "gray21" }, + { RGB_TO_ULONG(54 , 54 , 54 ), "grey21" }, + { RGB_TO_ULONG(56 , 56 , 56 ), "gray22" }, + { RGB_TO_ULONG(56 , 56 , 56 ), "grey22" }, + { RGB_TO_ULONG(59 , 59 , 59 ), "gray23" }, + { RGB_TO_ULONG(59 , 59 , 59 ), "grey23" }, + { RGB_TO_ULONG(61 , 61 , 61 ), "gray24" }, + { RGB_TO_ULONG(61 , 61 , 61 ), "grey24" }, + { RGB_TO_ULONG(64 , 64 , 64 ), "gray25" }, + { RGB_TO_ULONG(64 , 64 , 64 ), "grey25" }, + { RGB_TO_ULONG(66 , 66 , 66 ), "gray26" }, + { RGB_TO_ULONG(66 , 66 , 66 ), "grey26" }, + { RGB_TO_ULONG(69 , 69 , 69 ), "gray27" }, + { RGB_TO_ULONG(69 , 69 , 69 ), "grey27" }, + { RGB_TO_ULONG(71 , 71 , 71 ), "gray28" }, + { RGB_TO_ULONG(71 , 71 , 71 ), "grey28" }, + { RGB_TO_ULONG(74 , 74 , 74 ), "gray29" }, + { RGB_TO_ULONG(74 , 74 , 74 ), "grey29" }, + { RGB_TO_ULONG(77 , 77 , 77 ), "gray30" }, + { RGB_TO_ULONG(77 , 77 , 77 ), "grey30" }, + { RGB_TO_ULONG(79 , 79 , 79 ), "gray31" }, + { RGB_TO_ULONG(79 , 79 , 79 ), "grey31" }, + { RGB_TO_ULONG(82 , 82 , 82 ), "gray32" }, + { RGB_TO_ULONG(82 , 82 , 82 ), "grey32" }, + { RGB_TO_ULONG(84 , 84 , 84 ), "gray33" }, + { RGB_TO_ULONG(84 , 84 , 84 ), "grey33" }, + { RGB_TO_ULONG(87 , 87 , 87 ), "gray34" }, + { RGB_TO_ULONG(87 , 87 , 87 ), "grey34" }, + { RGB_TO_ULONG(89 , 89 , 89 ), "gray35" }, + { RGB_TO_ULONG(89 , 89 , 89 ), "grey35" }, + { RGB_TO_ULONG(92 , 92 , 92 ), "gray36" }, + { RGB_TO_ULONG(92 , 92 , 92 ), "grey36" }, + { RGB_TO_ULONG(94 , 94 , 94 ), "gray37" }, + { RGB_TO_ULONG(94 , 94 , 94 ), "grey37" }, + { RGB_TO_ULONG(97 , 97 , 97 ), "gray38" }, + { RGB_TO_ULONG(97 , 97 , 97 ), "grey38" }, + { RGB_TO_ULONG(99 , 99 , 99 ), "gray39" }, + { RGB_TO_ULONG(99 , 99 , 99 ), "grey39" }, + { RGB_TO_ULONG(102, 102, 102), "gray40" }, + { RGB_TO_ULONG(102, 102, 102), "grey40" }, + { RGB_TO_ULONG(105, 105, 105), "gray41" }, + { RGB_TO_ULONG(105, 105, 105), "grey41" }, + { RGB_TO_ULONG(107, 107, 107), "gray42" }, + { RGB_TO_ULONG(107, 107, 107), "grey42" }, + { RGB_TO_ULONG(110, 110, 110), "gray43" }, + { RGB_TO_ULONG(110, 110, 110), "grey43" }, + { RGB_TO_ULONG(112, 112, 112), "gray44" }, + { RGB_TO_ULONG(112, 112, 112), "grey44" }, + { RGB_TO_ULONG(115, 115, 115), "gray45" }, + { RGB_TO_ULONG(115, 115, 115), "grey45" }, + { RGB_TO_ULONG(117, 117, 117), "gray46" }, + { RGB_TO_ULONG(117, 117, 117), "grey46" }, + { RGB_TO_ULONG(120, 120, 120), "gray47" }, + { RGB_TO_ULONG(120, 120, 120), "grey47" }, + { RGB_TO_ULONG(122, 122, 122), "gray48" }, + { RGB_TO_ULONG(122, 122, 122), "grey48" }, + { RGB_TO_ULONG(125, 125, 125), "gray49" }, + { RGB_TO_ULONG(125, 125, 125), "grey49" }, + { RGB_TO_ULONG(127, 127, 127), "gray50" }, + { RGB_TO_ULONG(127, 127, 127), "grey50" }, + { RGB_TO_ULONG(130, 130, 130), "gray51" }, + { RGB_TO_ULONG(130, 130, 130), "grey51" }, + { RGB_TO_ULONG(133, 133, 133), "gray52" }, + { RGB_TO_ULONG(133, 133, 133), "grey52" }, + { RGB_TO_ULONG(135, 135, 135), "gray53" }, + { RGB_TO_ULONG(135, 135, 135), "grey53" }, + { RGB_TO_ULONG(138, 138, 138), "gray54" }, + { RGB_TO_ULONG(138, 138, 138), "grey54" }, + { RGB_TO_ULONG(140, 140, 140), "gray55" }, + { RGB_TO_ULONG(140, 140, 140), "grey55" }, + { RGB_TO_ULONG(143, 143, 143), "gray56" }, + { RGB_TO_ULONG(143, 143, 143), "grey56" }, + { RGB_TO_ULONG(145, 145, 145), "gray57" }, + { RGB_TO_ULONG(145, 145, 145), "grey57" }, + { RGB_TO_ULONG(148, 148, 148), "gray58" }, + { RGB_TO_ULONG(148, 148, 148), "grey58" }, + { RGB_TO_ULONG(150, 150, 150), "gray59" }, + { RGB_TO_ULONG(150, 150, 150), "grey59" }, + { RGB_TO_ULONG(153, 153, 153), "gray60" }, + { RGB_TO_ULONG(153, 153, 153), "grey60" }, + { RGB_TO_ULONG(156, 156, 156), "gray61" }, + { RGB_TO_ULONG(156, 156, 156), "grey61" }, + { RGB_TO_ULONG(158, 158, 158), "gray62" }, + { RGB_TO_ULONG(158, 158, 158), "grey62" }, + { RGB_TO_ULONG(161, 161, 161), "gray63" }, + { RGB_TO_ULONG(161, 161, 161), "grey63" }, + { RGB_TO_ULONG(163, 163, 163), "gray64" }, + { RGB_TO_ULONG(163, 163, 163), "grey64" }, + { RGB_TO_ULONG(166, 166, 166), "gray65" }, + { RGB_TO_ULONG(166, 166, 166), "grey65" }, + { RGB_TO_ULONG(168, 168, 168), "gray66" }, + { RGB_TO_ULONG(168, 168, 168), "grey66" }, + { RGB_TO_ULONG(171, 171, 171), "gray67" }, + { RGB_TO_ULONG(171, 171, 171), "grey67" }, + { RGB_TO_ULONG(173, 173, 173), "gray68" }, + { RGB_TO_ULONG(173, 173, 173), "grey68" }, + { RGB_TO_ULONG(176, 176, 176), "gray69" }, + { RGB_TO_ULONG(176, 176, 176), "grey69" }, + { RGB_TO_ULONG(179, 179, 179), "gray70" }, + { RGB_TO_ULONG(179, 179, 179), "grey70" }, + { RGB_TO_ULONG(181, 181, 181), "gray71" }, + { RGB_TO_ULONG(181, 181, 181), "grey71" }, + { RGB_TO_ULONG(184, 184, 184), "gray72" }, + { RGB_TO_ULONG(184, 184, 184), "grey72" }, + { RGB_TO_ULONG(186, 186, 186), "gray73" }, + { RGB_TO_ULONG(186, 186, 186), "grey73" }, + { RGB_TO_ULONG(189, 189, 189), "gray74" }, + { RGB_TO_ULONG(189, 189, 189), "grey74" }, + { RGB_TO_ULONG(191, 191, 191), "gray75" }, + { RGB_TO_ULONG(191, 191, 191), "grey75" }, + { RGB_TO_ULONG(194, 194, 194), "gray76" }, + { RGB_TO_ULONG(194, 194, 194), "grey76" }, + { RGB_TO_ULONG(196, 196, 196), "gray77" }, + { RGB_TO_ULONG(196, 196, 196), "grey77" }, + { RGB_TO_ULONG(199, 199, 199), "gray78" }, + { RGB_TO_ULONG(199, 199, 199), "grey78" }, + { RGB_TO_ULONG(201, 201, 201), "gray79" }, + { RGB_TO_ULONG(201, 201, 201), "grey79" }, + { RGB_TO_ULONG(204, 204, 204), "gray80" }, + { RGB_TO_ULONG(204, 204, 204), "grey80" }, + { RGB_TO_ULONG(207, 207, 207), "gray81" }, + { RGB_TO_ULONG(207, 207, 207), "grey81" }, + { RGB_TO_ULONG(209, 209, 209), "gray82" }, + { RGB_TO_ULONG(209, 209, 209), "grey82" }, + { RGB_TO_ULONG(212, 212, 212), "gray83" }, + { RGB_TO_ULONG(212, 212, 212), "grey83" }, + { RGB_TO_ULONG(214, 214, 214), "gray84" }, + { RGB_TO_ULONG(214, 214, 214), "grey84" }, + { RGB_TO_ULONG(217, 217, 217), "gray85" }, + { RGB_TO_ULONG(217, 217, 217), "grey85" }, + { RGB_TO_ULONG(219, 219, 219), "gray86" }, + { RGB_TO_ULONG(219, 219, 219), "grey86" }, + { RGB_TO_ULONG(222, 222, 222), "gray87" }, + { RGB_TO_ULONG(222, 222, 222), "grey87" }, + { RGB_TO_ULONG(224, 224, 224), "gray88" }, + { RGB_TO_ULONG(224, 224, 224), "grey88" }, + { RGB_TO_ULONG(227, 227, 227), "gray89" }, + { RGB_TO_ULONG(227, 227, 227), "grey89" }, + { RGB_TO_ULONG(229, 229, 229), "gray90" }, + { RGB_TO_ULONG(229, 229, 229), "grey90" }, + { RGB_TO_ULONG(232, 232, 232), "gray91" }, + { RGB_TO_ULONG(232, 232, 232), "grey91" }, + { RGB_TO_ULONG(235, 235, 235), "gray92" }, + { RGB_TO_ULONG(235, 235, 235), "grey92" }, + { RGB_TO_ULONG(237, 237, 237), "gray93" }, + { RGB_TO_ULONG(237, 237, 237), "grey93" }, + { RGB_TO_ULONG(240, 240, 240), "gray94" }, + { RGB_TO_ULONG(240, 240, 240), "grey94" }, + { RGB_TO_ULONG(242, 242, 242), "gray95" }, + { RGB_TO_ULONG(242, 242, 242), "grey95" }, + { RGB_TO_ULONG(245, 245, 245), "gray96" }, + { RGB_TO_ULONG(245, 245, 245), "grey96" }, + { RGB_TO_ULONG(247, 247, 247), "gray97" }, + { RGB_TO_ULONG(247, 247, 247), "grey97" }, + { RGB_TO_ULONG(250, 250, 250), "gray98" }, + { RGB_TO_ULONG(250, 250, 250), "grey98" }, + { RGB_TO_ULONG(252, 252, 252), "gray99" }, + { RGB_TO_ULONG(252, 252, 252), "grey99" }, + { RGB_TO_ULONG(255, 255, 255), "gray100" }, + { RGB_TO_ULONG(255, 255, 255), "grey100" }, + { RGB_TO_ULONG(169, 169, 169), "dark grey" }, + { RGB_TO_ULONG(169, 169, 169), "DarkGrey" }, + { RGB_TO_ULONG(169, 169, 169), "dark gray" }, + { RGB_TO_ULONG(169, 169, 169), "DarkGray" }, + { RGB_TO_ULONG(0 , 0 , 139), "dark blue" }, + { RGB_TO_ULONG(0 , 0 , 139), "DarkBlue" }, + { RGB_TO_ULONG(0 , 139, 139), "dark cyan" }, + { RGB_TO_ULONG(0 , 139, 139), "DarkCyan" }, + { RGB_TO_ULONG(139, 0 , 139), "dark magenta" }, + { RGB_TO_ULONG(139, 0 , 139), "DarkMagenta" }, + { RGB_TO_ULONG(139, 0 , 0 ), "dark red" }, + { RGB_TO_ULONG(139, 0 , 0 ), "DarkRed" }, + { RGB_TO_ULONG(144, 238, 144), "light green" }, + { RGB_TO_ULONG(144, 238, 144), "LightGreen" } +}; + +unsigned long +mac_color_map_lookup (colorname) + char *colorname; +{ + Lisp_Object ret = Qnil; + int i; + + BLOCK_INPUT; + + for (i = 0; i < sizeof (mac_color_map) / sizeof (mac_color_map[0]); i++) + if (stricmp (colorname, mac_color_map[i].name) == 0) + { + ret = mac_color_map[i].color; + break; + } + + UNBLOCK_INPUT; + + return ret; +} + +Lisp_Object +x_to_mac_color (colorname) + char * colorname; +{ + register Lisp_Object tail, ret = Qnil; + + BLOCK_INPUT; + + if (colorname[0] == '#') + { + /* Could be an old-style RGB Device specification. */ + char *color; + int size; + color = colorname + 1; + + size = strlen(color); + if (size == 3 || size == 6 || size == 9 || size == 12) + { + unsigned long colorval; + int i, pos; + pos = 0; + size /= 3; + colorval = 0; + + for (i = 0; i < 3; i++) + { + char *end; + char t; + unsigned long value; + + /* The check for 'x' in the following conditional takes into + account the fact that strtol allows a "0x" in front of + our numbers, and we don't. */ + if (!isxdigit(color[0]) || color[1] == 'x') + break; + t = color[size]; + color[size] = '\0'; + value = strtoul(color, &end, 16); + color[size] = t; + if (errno == ERANGE || end - color != size) + break; + switch (size) + { + case 1: + value = value * 0x10; + break; + case 2: + break; + case 3: + value /= 0x10; + break; + case 4: + value /= 0x100; + break; + } + colorval |= (value << pos); + pos += 0x8; + if (i == 2) + { + UNBLOCK_INPUT; + return (colorval); + } + color = end; + } + } + } + else if (strnicmp(colorname, "rgb:", 4) == 0) + { + char *color; + unsigned long colorval; + int i, pos; + pos = 0; + + colorval = 0; + color = colorname + 4; + for (i = 0; i < 3; i++) + { + char *end; + unsigned long value; + + /* The check for 'x' in the following conditional takes into + account the fact that strtol allows a "0x" in front of + our numbers, and we don't. */ + if (!isxdigit(color[0]) || color[1] == 'x') + break; + value = strtoul(color, &end, 16); + if (errno == ERANGE) + break; + switch (end - color) + { + case 1: + value = value * 0x10 + value; + break; + case 2: + break; + case 3: + value /= 0x10; + break; + case 4: + value /= 0x100; + break; + default: + value = ULONG_MAX; + } + if (value == ULONG_MAX) + break; + colorval |= (value << pos); + pos += 0x8; + if (i == 2) + { + if (*end != '\0') + break; + UNBLOCK_INPUT; + return (colorval); + } + if (*end != '/') + break; + color = end + 1; + } + } + else if (strnicmp(colorname, "rgbi:", 5) == 0) + { + /* This is an RGB Intensity specification. */ + char *color; + unsigned long colorval; + int i, pos; + pos = 0; + + colorval = 0; + color = colorname + 5; + for (i = 0; i < 3; i++) + { + char *end; + double value; + unsigned long val; + + value = strtod(color, &end); + if (errno == ERANGE) + break; + if (value < 0.0 || value > 1.0) + break; + val = (unsigned long)(0x100 * value); + /* We used 0x100 instead of 0xFF to give an continuous + range between 0.0 and 1.0 inclusive. The next statement + fixes the 1.0 case. */ + if (val == 0x100) + val = 0xFF; + colorval |= (val << pos); + pos += 0x8; + if (i == 2) + { + if (*end != '\0') + break; + UNBLOCK_INPUT; + return (colorval); + } + if (*end != '/') + break; + color = end + 1; + } + } + + ret = mac_color_map_lookup (colorname); + + UNBLOCK_INPUT; + return ret; +} + +/* Gamma-correct COLOR on frame F. */ + +void +gamma_correct (f, color) + struct frame *f; + unsigned long *color; +{ + if (f->gamma) + { + unsigned long red, green, blue; + + red = pow (RED_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5; + green = pow (GREEN_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5; + blue = pow (BLUE_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5; + *color = RGB_TO_ULONG (red, green, blue); + } +} + +/* Decide if color named COLOR is valid for the display associated + with the selected frame; if so, return the rgb values in COLOR_DEF. + If ALLOC is nonzero, allocate a new colormap cell. */ + +int +mac_defined_color (f, color, color_def, alloc) + FRAME_PTR f; + char *color; + XColor *color_def; + int alloc; +{ + register Lisp_Object tem; + unsigned long mac_color_ref; + + tem = x_to_mac_color (color); + + if (!NILP (tem)) + { + if (f) + { + /* Apply gamma correction. */ + mac_color_ref = XUINT (tem); + gamma_correct (f, &mac_color_ref); + XSETINT (tem, mac_color_ref); + } + + color_def->pixel = mac_color_ref; + color_def->red = RED_FROM_ULONG (mac_color_ref); + color_def->green = GREEN_FROM_ULONG (mac_color_ref); + color_def->blue = BLUE_FROM_ULONG (mac_color_ref); + + return 1; + } + else + { + return 0; + } +} + +/* Given a string ARG naming a color, compute a pixel value from it + suitable for screen F. + If F is not a color screen, return DEF (default) regardless of what + ARG says. */ + +int +x_decode_color (f, arg, def) + FRAME_PTR f; + Lisp_Object arg; + int def; +{ + XColor cdef; + + CHECK_STRING (arg, 0); + + if (strcmp (XSTRING (arg)->data, "black") == 0) + return BLACK_PIX_DEFAULT (f); + else if (strcmp (XSTRING (arg)->data, "white") == 0) + return WHITE_PIX_DEFAULT (f); + +#if 0 + if ((FRAME_MAC_DISPLAY_INFO (f)->n_planes + * FRAME_MAC_DISPLAY_INFO (f)->n_cbits) == 1) + return def; +#endif + + if (mac_defined_color (f, XSTRING (arg)->data, &cdef, 1)) + return cdef.pixel; + + /* defined_color failed; return an ultimate default. */ + return def; +} + +/* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is + the previous value of that parameter, NEW_VALUE is the new value. */ + +static void +x_set_line_spacing (f, new_value, old_value) + struct frame *f; + Lisp_Object new_value, old_value; +{ + if (NILP (new_value)) + f->extra_line_spacing = 0; + else if (NATNUMP (new_value)) + f->extra_line_spacing = XFASTINT (new_value); + else + Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"), + Fcons (new_value, Qnil))); + if (FRAME_VISIBLE_P (f)) + redraw_frame (f); +} + + +/* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is + the previous value of that parameter, NEW_VALUE is the new value. */ + +static void +x_set_screen_gamma (f, new_value, old_value) + struct frame *f; + Lisp_Object new_value, old_value; +{ + if (NILP (new_value)) + f->gamma = 0; + else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0) + /* The value 0.4545 is the normal viewing gamma. */ + f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value)); + else + Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"), + Fcons (new_value, Qnil))); + + clear_face_cache (0); +} + + +/* Functions called only from `x_set_frame_param' + to set individual parameters. + + If FRAME_MAC_WINDOW (f) is 0, + the frame is being created and its window does not exist yet. + In that case, just record the parameter's new value + in the standard place; do not attempt to change the window. */ + +void +x_set_foreground_color (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + FRAME_FOREGROUND_PIXEL (f) + = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + + if (FRAME_MAC_WINDOW (f) != 0) + { + update_face_from_frame_parameter (f, Qforeground_color, arg); + if (FRAME_VISIBLE_P (f)) + redraw_frame (f); + } +} + +void +x_set_background_color (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + FRAME_BACKGROUND_PIXEL (f) + = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f)); + + if (FRAME_MAC_WINDOW (f) != 0) + { + update_face_from_frame_parameter (f, Qbackground_color, arg); + + if (FRAME_VISIBLE_P (f)) + redraw_frame (f); + } +} + +void +x_set_mouse_color (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + + Cursor cursor, nontext_cursor, mode_cursor, cross_cursor; + int count; + int mask_color; + + if (!EQ (Qnil, arg)) + f->output_data.mac->mouse_pixel + = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + mask_color = FRAME_BACKGROUND_PIXEL (f); + + /* Don't let pointers be invisible. */ + if (mask_color == f->output_data.mac->mouse_pixel + && mask_color == FRAME_BACKGROUND_PIXEL (f)) + f->output_data.mac->mouse_pixel = FRAME_FOREGROUND_PIXEL (f); + +#if 0 /* MAC_TODO : cursor changes */ + BLOCK_INPUT; + + /* It's not okay to crash if the user selects a screwy cursor. */ + count = x_catch_errors (FRAME_W32_DISPLAY (f)); + + if (!EQ (Qnil, Vx_pointer_shape)) + { + CHECK_NUMBER (Vx_pointer_shape, 0); + cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape)); + } + else + cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm); + x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s"); + + if (!EQ (Qnil, Vx_nontext_pointer_shape)) + { + CHECK_NUMBER (Vx_nontext_pointer_shape, 0); + nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), + XINT (Vx_nontext_pointer_shape)); + } + else + nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr); + x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s"); + + if (!EQ (Qnil, Vx_busy_pointer_shape)) + { + CHECK_NUMBER (Vx_busy_pointer_shape, 0); + busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), + XINT (Vx_busy_pointer_shape)); + } + else + busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch); + x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s"); + + x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s"); + if (!EQ (Qnil, Vx_mode_pointer_shape)) + { + CHECK_NUMBER (Vx_mode_pointer_shape, 0); + mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), + XINT (Vx_mode_pointer_shape)); + } + else + mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm); + x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s"); + + if (!EQ (Qnil, Vx_sensitive_text_pointer_shape)) + { + CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0); + cross_cursor + = XCreateFontCursor (FRAME_W32_DISPLAY (f), + XINT (Vx_sensitive_text_pointer_shape)); + } + else + cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair); + + /* Check and report errors with the above calls. */ + x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s"); + x_uncatch_errors (FRAME_W32_DISPLAY (f), count); + + { + XColor fore_color, back_color; + + fore_color.pixel = f->output_data.w32->mouse_pixel; + back_color.pixel = mask_color; + XQueryColor (FRAME_W32_DISPLAY (f), + DefaultColormap (FRAME_W32_DISPLAY (f), + DefaultScreen (FRAME_W32_DISPLAY (f))), + &fore_color); + XQueryColor (FRAME_W32_DISPLAY (f), + DefaultColormap (FRAME_W32_DISPLAY (f), + DefaultScreen (FRAME_W32_DISPLAY (f))), + &back_color); + XRecolorCursor (FRAME_W32_DISPLAY (f), cursor, + &fore_color, &back_color); + XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor, + &fore_color, &back_color); + XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor, + &fore_color, &back_color); + XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor, + &fore_color, &back_color); + XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor, + &fore_color, &back_color); + } + + if (FRAME_W32_WINDOW (f) != 0) + XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor); + + if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0) + XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor); + f->output_data.w32->text_cursor = cursor; + + if (nontext_cursor != f->output_data.w32->nontext_cursor + && f->output_data.w32->nontext_cursor != 0) + XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor); + f->output_data.w32->nontext_cursor = nontext_cursor; + + if (busy_cursor != f->output_data.w32->busy_cursor + && f->output_data.w32->busy_cursor != 0) + XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor); + f->output_data.w32->busy_cursor = busy_cursor; + + if (mode_cursor != f->output_data.w32->modeline_cursor + && f->output_data.w32->modeline_cursor != 0) + XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor); + f->output_data.w32->modeline_cursor = mode_cursor; + + if (cross_cursor != f->output_data.w32->cross_cursor + && f->output_data.w32->cross_cursor != 0) + XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor); + f->output_data.w32->cross_cursor = cross_cursor; + + XFlush (FRAME_W32_DISPLAY (f)); + UNBLOCK_INPUT; + + update_face_from_frame_parameter (f, Qmouse_color, arg); +#endif /* MAC_TODO */ +} + +void +x_set_cursor_color (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + unsigned long fore_pixel; + + if (!NILP (Vx_cursor_fore_pixel)) + fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel, + WHITE_PIX_DEFAULT (f)); + else + fore_pixel = FRAME_BACKGROUND_PIXEL (f); + f->output_data.mac->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + + /* Make sure that the cursor color differs from the background color. */ + if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f)) + { + f->output_data.mac->cursor_pixel = f->output_data.mac->mouse_pixel; + if (f->output_data.mac->cursor_pixel == fore_pixel) + fore_pixel = FRAME_BACKGROUND_PIXEL (f); + } + FRAME_FOREGROUND_PIXEL (f) = fore_pixel; + +#if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */ + if (FRAME_MAC_WINDOW (f) != 0) + { + if (FRAME_VISIBLE_P (f)) + { + x_display_cursor (f, 0); + x_display_cursor (f, 1); + } + } +#endif + + update_face_from_frame_parameter (f, Qcursor_color, arg); +} + +/* Set the border-color of frame F to pixel value PIX. + Note that this does not fully take effect if done before + F has an window. */ +void +x_set_border_pixel (f, pix) + struct frame *f; + int pix; +{ + f->output_data.mac->border_pixel = pix; + + if (FRAME_MAC_WINDOW (f) != 0 && f->output_data.mac->border_width > 0) + { + if (FRAME_VISIBLE_P (f)) + redraw_frame (f); + } +} + +/* Set the border-color of frame F to value described by ARG. + ARG can be a string naming a color. + The border-color is used for the border that is drawn by the server. + Note that this does not fully take effect if done before + F has a window; it must be redone when the window is created. */ + +void +x_set_border_color (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + int pix; + + CHECK_STRING (arg, 0); + pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + x_set_border_pixel (f, pix); + update_face_from_frame_parameter (f, Qborder_color, arg); +} + +/* Value is the internal representation of the specified cursor type + ARG. If type is BAR_CURSOR, return in *WIDTH the specified width + of the bar cursor. */ + +enum text_cursor_kinds +x_specified_cursor_type (arg, width) + Lisp_Object arg; + int *width; +{ + enum text_cursor_kinds type; + + if (EQ (arg, Qbar)) + { + type = BAR_CURSOR; + *width = 2; + } + else if (CONSP (arg) + && EQ (XCAR (arg), Qbar) + && INTEGERP (XCDR (arg)) + && XINT (XCDR (arg)) >= 0) + { + type = BAR_CURSOR; + *width = XINT (XCDR (arg)); + } + else if (NILP (arg)) + type = NO_CURSOR; + else + /* Treat anything unknown as "box cursor". + It was bad to signal an error; people have trouble fixing + .Xdefaults with Emacs, when it has something bad in it. */ + type = FILLED_BOX_CURSOR; + + return type; +} + +void +x_set_cursor_type (f, arg, oldval) + FRAME_PTR f; + Lisp_Object arg, oldval; +{ + int width; + + FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width); + f->output_data.mac->cursor_width = width; + + /* Make sure the cursor gets redrawn. This is overkill, but how + often do people change cursor types? */ + update_mode_lines++; +} + +#if 0 /* MAC_TODO: really no icon for Mac */ +void +x_set_icon_type (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + int result; + + if (NILP (arg) && NILP (oldval)) + return; + + if (STRINGP (arg) && STRINGP (oldval) + && EQ (Fstring_equal (oldval, arg), Qt)) + return; + + if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval)) + return; + + BLOCK_INPUT; + + result = x_bitmap_icon (f, arg); + if (result) + { + UNBLOCK_INPUT; + error ("No icon window available"); + } + + UNBLOCK_INPUT; +} +#endif + +/* Return non-nil if frame F wants a bitmap icon. */ + +Lisp_Object +x_icon_type (f) + FRAME_PTR f; +{ + Lisp_Object tem; + + tem = assq_no_quit (Qicon_type, f->param_alist); + if (CONSP (tem)) + return XCDR (tem); + else + return Qnil; +} + +void +x_set_icon_name (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + int result; + + if (STRINGP (arg)) + { + if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt)) + return; + } + else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil)) + return; + + f->icon_name = arg; + +#if 0 + if (f->output_data.w32->icon_bitmap != 0) + return; + + BLOCK_INPUT; + + result = x_text_icon (f, + (char *) XSTRING ((!NILP (f->icon_name) + ? f->icon_name + : !NILP (f->title) + ? f->title + : f->name))->data); + + if (result) + { + UNBLOCK_INPUT; + error ("No icon window available"); + } + + /* If the window was unmapped (and its icon was mapped), + the new icon is not mapped, so map the window in its stead. */ + if (FRAME_VISIBLE_P (f)) + { +#ifdef USE_X_TOOLKIT + XtPopup (f->output_data.w32->widget, XtGrabNone); +#endif + XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f)); + } + + XFlush (FRAME_W32_DISPLAY (f)); + UNBLOCK_INPUT; +#endif +} + +extern Lisp_Object x_new_font (); +extern Lisp_Object x_new_fontset(); + +void +x_set_font (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + Lisp_Object result; + Lisp_Object fontset_name; + Lisp_Object frame; + + CHECK_STRING (arg, 1); + + fontset_name = Fquery_fontset (arg, Qnil); + + BLOCK_INPUT; + result = (STRINGP (fontset_name) + ? x_new_fontset (f, XSTRING (fontset_name)->data) + : x_new_font (f, XSTRING (arg)->data)); + UNBLOCK_INPUT; + + if (EQ (result, Qnil)) + error ("Font `%s' is not defined", XSTRING (arg)->data); + else if (EQ (result, Qt)) + error ("The characters of the given font have varying widths"); + else if (STRINGP (result)) + { + store_frame_param (f, Qfont, result); + recompute_basic_faces (f); + } + else + abort (); + + do_pending_window_change (0); + + /* Don't call `face-set-after-frame-default' when faces haven't been + initialized yet. This is the case when called from + Fx_create_frame. In that case, the X widget or window doesn't + exist either, and we can end up in x_report_frame_params with a + null widget which gives a segfault. */ + if (FRAME_FACE_CACHE (f)) + { + XSETFRAME (frame, f); + call1 (Qface_set_after_frame_default, frame); + } +} + +void +x_set_border_width (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + CHECK_NUMBER (arg, 0); + + if (XINT (arg) == f->output_data.mac->border_width) + return; + +#if 0 + if (FRAME_MAC_WINDOW (f) != 0) + error ("Cannot change the border width of a window"); +#endif + + f->output_data.mac->border_width = XINT (arg); +} + +void +x_set_internal_border_width (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + int old = f->output_data.mac->internal_border_width; + + CHECK_NUMBER (arg, 0); + f->output_data.mac->internal_border_width = XINT (arg); + if (f->output_data.mac->internal_border_width < 0) + f->output_data.mac->internal_border_width = 0; + + if (f->output_data.mac->internal_border_width == old) + return; + + if (FRAME_MAC_WINDOW (f) != 0) + { + x_set_window_size (f, 0, f->width, f->height); + SET_FRAME_GARBAGED (f); + do_pending_window_change (0); + } +} + +void +x_set_visibility (f, value, oldval) + struct frame *f; + Lisp_Object value, oldval; +{ + Lisp_Object frame; + XSETFRAME (frame, f); + + if (NILP (value)) + Fmake_frame_invisible (frame, Qt); + else if (EQ (value, Qicon)) + Ficonify_frame (frame); + else + Fmake_frame_visible (frame); +} + +void +x_set_menu_bar_lines (f, value, oldval) + struct frame *f; + Lisp_Object value, oldval; +{ + int nlines; + int olines = FRAME_MENU_BAR_LINES (f); + + /* Right now, menu bars don't work properly in minibuf-only frames; + most of the commands try to apply themselves to the minibuffer + frame itself, and get an error because you can't switch buffers + in or split the minibuffer window. */ + if (FRAME_MINIBUF_ONLY_P (f)) + return; + + if (INTEGERP (value)) + nlines = XINT (value); + else + nlines = 0; + + FRAME_MENU_BAR_LINES (f) = 0; + if (nlines) + FRAME_EXTERNAL_MENU_BAR (f) = 1; + else + { + if (FRAME_EXTERNAL_MENU_BAR (f) == 1) + free_frame_menubar (f); + FRAME_EXTERNAL_MENU_BAR (f) = 0; + + /* Adjust the frame size so that the client (text) dimensions + remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being + set correctly. */ + x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + do_pending_window_change (0); + } + adjust_glyphs (f); +} + +/* Set the number of lines used for the tool bar of frame F to VALUE. + VALUE not an integer, or < 0 means set the lines to zero. OLDVAL + is the old number of tool bar lines. This function changes the + height of all windows on frame F to match the new tool bar height. + The frame's height doesn't change. */ + +void +x_set_tool_bar_lines (f, value, oldval) + struct frame *f; + Lisp_Object value, oldval; +{ + int delta, nlines; + + /* Use VALUE only if an integer >= 0. */ + if (INTEGERP (value) && XINT (value) >= 0) + nlines = XFASTINT (value); + else + nlines = 0; + + /* Make sure we redisplay all windows in this frame. */ + ++windows_or_buffers_changed; + + delta = nlines - FRAME_TOOL_BAR_LINES (f); + FRAME_TOOL_BAR_LINES (f) = nlines; + x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + do_pending_window_change (0); + adjust_glyphs (f); +} + + +/* Change the name of frame F to NAME. If NAME is nil, set F's name to + w32_id_name. + + If EXPLICIT is non-zero, that indicates that lisp code is setting the + name; if NAME is a string, set F's name to NAME and set + F->explicit_name; if NAME is Qnil, then clear F->explicit_name. + + If EXPLICIT is zero, that indicates that Emacs redisplay code is + suggesting a new name, which lisp code should override; if + F->explicit_name is set, ignore the new name; otherwise, set it. */ + +void +x_set_name (f, name, explicit) + struct frame *f; + Lisp_Object name; + int explicit; +{ + /* Make sure that requests from lisp code override requests from + Emacs redisplay code. */ + if (explicit) + { + /* If we're switching from explicit to implicit, we had better + update the mode lines and thereby update the title. */ + if (f->explicit_name && NILP (name)) + update_mode_lines = 1; + + f->explicit_name = ! NILP (name); + } + else if (f->explicit_name) + return; + + /* If NAME is nil, set the name to the w32_id_name. */ + if (NILP (name)) + { + /* Check for no change needed in this very common case + before we do any consing. */ + if (!strcmp (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name, + XSTRING (f->name)->data)) + return; + name = build_string (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name); + } + else + CHECK_STRING (name, 0); + + /* Don't change the name if it's already NAME. */ + if (! NILP (Fstring_equal (name, f->name))) + return; + + f->name = name; + + /* For setting the frame title, the title parameter should override + the name parameter. */ + if (! NILP (f->title)) + name = f->title; + + if (FRAME_MAC_WINDOW (f)) + { + if (STRING_MULTIBYTE (name)) +#if 0 /* MAC_TODO: encoding title string */ + name = ENCODE_SYSTEM (name); +#else + return; +#endif + + BLOCK_INPUT; + + { + Str255 windowTitle; + if (strlen (XSTRING (name)->data) < 255) + { + strcpy (windowTitle, XSTRING (name)->data); + c2pstr (windowTitle); + SetWTitle (FRAME_MAC_WINDOW (f), windowTitle); + } + } + + UNBLOCK_INPUT; + } +} + +/* This function should be called when the user's lisp code has + specified a name for the frame; the name will override any set by the + redisplay code. */ +void +x_explicitly_set_name (f, arg, oldval) + FRAME_PTR f; + Lisp_Object arg, oldval; +{ + x_set_name (f, arg, 1); +} + +/* This function should be called by Emacs redisplay code to set the + name; names set this way will never override names set by the user's + lisp code. */ +void +x_implicitly_set_name (f, arg, oldval) + FRAME_PTR f; + Lisp_Object arg, oldval; +{ + x_set_name (f, arg, 0); +} + +/* Change the title of frame F to NAME. + If NAME is nil, use the frame name as the title. + + If EXPLICIT is non-zero, that indicates that lisp code is setting the + name; if NAME is a string, set F's name to NAME and set + F->explicit_name; if NAME is Qnil, then clear F->explicit_name. + + If EXPLICIT is zero, that indicates that Emacs redisplay code is + suggesting a new name, which lisp code should override; if + F->explicit_name is set, ignore the new name; otherwise, set it. */ + +void +x_set_title (f, name, old_name) + struct frame *f; + Lisp_Object name, old_name; +{ + /* Don't change the title if it's already NAME. */ + if (EQ (name, f->title)) + return; + + update_mode_lines = 1; + + f->title = name; + + if (NILP (name)) + name = f->name; + + if (FRAME_MAC_WINDOW (f)) + { + if (STRING_MULTIBYTE (name)) +#if 0 /* MAC_TODO: encoding title string */ + name = ENCODE_SYSTEM (name); +#else + return; +#endif + + BLOCK_INPUT; + + { + Str255 windowTitle; + if (strlen (XSTRING (name)->data) < 255) + { + strcpy (windowTitle, XSTRING (name)->data); + c2pstr (windowTitle); + SetWTitle (FRAME_MAC_WINDOW (f), windowTitle); + } + } + + UNBLOCK_INPUT; + } +} + +void +x_set_autoraise (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + f->auto_raise = !EQ (Qnil, arg); +} + +void +x_set_autolower (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + f->auto_lower = !EQ (Qnil, arg); +} + +void +x_set_unsplittable (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + f->no_split = !NILP (arg); +} + +void +x_set_vertical_scroll_bars (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) + || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)) + || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f))) + { + FRAME_VERTICAL_SCROLL_BAR_TYPE (f) + = (NILP (arg) + ? vertical_scroll_bar_none + : EQ (Qright, arg) + ? vertical_scroll_bar_right + : vertical_scroll_bar_left); + + /* We set this parameter before creating the window for the + frame, so we can get the geometry right from the start. + However, if the window hasn't been created yet, we shouldn't + call x_set_window_size. */ + if (FRAME_MAC_WINDOW (f)) + x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + do_pending_window_change (0); + } +} + +void +x_set_scroll_bar_width (f, arg, oldval) + struct frame *f; + Lisp_Object arg, oldval; +{ + /* Imitate X without X Toolkit */ + + int wid = FONT_WIDTH (f->output_data.mac->font); + + if (NILP (arg)) + { + /* Make the actual width at least 14 pixels and a multiple of a + character width. */ + FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid; + + /* Use all of that space (aside from required margins) for the + scroll bar. */ + FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0; + + if (FRAME_MAC_WINDOW (f)) + x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + do_pending_window_change (0); + } + else if (INTEGERP (arg) && XINT (arg) > 0 + && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f)) + { + if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM) + XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1); + + FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg); + FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid; + if (FRAME_MAC_WINDOW (f)) + x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + do_pending_window_change (0); + } + change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0); + XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0; + XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0; +} + +/* Subroutines of creating an frame. */ + +/* Make sure that Vx_resource_name is set to a reasonable value. + Fix it up, or set it to `emacs' if it is too hopeless. */ + +static void +validate_x_resource_name () +{ + int len = 0; + /* Number of valid characters in the resource name. */ + int good_count = 0; + /* Number of invalid characters in the resource name. */ + int bad_count = 0; + Lisp_Object new; + int i; + + if (STRINGP (Vx_resource_name)) + { + unsigned char *p = XSTRING (Vx_resource_name)->data; + int i; + + len = STRING_BYTES (XSTRING (Vx_resource_name)); + + /* Only letters, digits, - and _ are valid in resource names. + Count the valid characters and count the invalid ones. */ + for (i = 0; i < len; i++) + { + int c = p[i]; + if (! ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c == '-' || c == '_')) + bad_count++; + else + good_count++; + } + } + else + /* Not a string => completely invalid. */ + bad_count = 5, good_count = 0; + + /* If name is valid already, return. */ + if (bad_count == 0) + return; + + /* If name is entirely invalid, or nearly so, use `emacs'. */ + if (good_count == 0 + || (good_count == 1 && bad_count > 0)) + { + Vx_resource_name = build_string ("emacs"); + return; + } + + /* Name is partly valid. Copy it and replace the invalid characters + with underscores. */ + + Vx_resource_name = new = Fcopy_sequence (Vx_resource_name); + + for (i = 0; i < len; i++) + { + int c = XSTRING (new)->data[i]; + if (! ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c == '-' || c == '_')) + XSTRING (new)->data[i] = '_'; + } +} + + +#if 0 /* MAC_TODO: implement resource strings */ +extern char *x_get_string_resource (); + +DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0, + "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\ +This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\ +class, where INSTANCE is the name under which Emacs was invoked, or\n\ +the name specified by the `-name' or `-rn' command-line arguments.\n\ +\n\ +The optional arguments COMPONENT and SUBCLASS add to the key and the\n\ +class, respectively. You must specify both of them or neither.\n\ +If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\ +and the class is `Emacs.CLASS.SUBCLASS'.") + (attribute, class, component, subclass) + Lisp_Object attribute, class, component, subclass; +{ + register char *value; + char *name_key; + char *class_key; + + CHECK_STRING (attribute, 0); + CHECK_STRING (class, 0); + + if (!NILP (component)) + CHECK_STRING (component, 1); + if (!NILP (subclass)) + CHECK_STRING (subclass, 2); + if (NILP (component) != NILP (subclass)) + error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither"); + + validate_x_resource_name (); + + /* Allocate space for the components, the dots which separate them, + and the final '\0'. Make them big enough for the worst case. */ + name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name)) + + (STRINGP (component) + ? STRING_BYTES (XSTRING (component)) : 0) + + STRING_BYTES (XSTRING (attribute)) + + 3); + + class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1) + + STRING_BYTES (XSTRING (class)) + + (STRINGP (subclass) + ? STRING_BYTES (XSTRING (subclass)) : 0) + + 3); + + /* Start with emacs.FRAMENAME for the name (the specific one) + and with `Emacs' for the class key (the general one). */ + strcpy (name_key, XSTRING (Vx_resource_name)->data); + strcpy (class_key, EMACS_CLASS); + + strcat (class_key, "."); + strcat (class_key, XSTRING (class)->data); + + if (!NILP (component)) + { + strcat (class_key, "."); + strcat (class_key, XSTRING (subclass)->data); + + strcat (name_key, "."); + strcat (name_key, XSTRING (component)->data); + } + + strcat (name_key, "."); + strcat (name_key, XSTRING (attribute)->data); + + value = x_get_string_resource (Qnil, + name_key, class_key); + + if (value != (char *) 0) + return build_string (value); + else + return Qnil; +} + +/* Used when C code wants a resource value. */ + +char * +x_get_resource_string (attribute, class) + char *attribute, *class; +{ + char *name_key; + char *class_key; + struct frame *sf = SELECTED_FRAME (); + + /* Allocate space for the components, the dots which separate them, + and the final '\0'. */ + name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name)) + + strlen (attribute) + 2); + class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1) + + strlen (class) + 2); + + sprintf (name_key, "%s.%s", + XSTRING (Vinvocation_name)->data, + attribute); + sprintf (class_key, "%s.%s", EMACS_CLASS, class); + + return x_get_string_resource (sf, name_key, class_key); +} +#endif + +/* Types we might convert a resource string into. */ +enum resource_types +{ + RES_TYPE_NUMBER, + RES_TYPE_FLOAT, + RES_TYPE_BOOLEAN, + RES_TYPE_STRING, + RES_TYPE_SYMBOL +}; + +/* Return the value of parameter PARAM. + + First search ALIST, then Vdefault_frame_alist, then the X defaults + database, using ATTRIBUTE as the attribute name and CLASS as its class. + + Convert the resource to the type specified by desired_type. + + If no default is specified, return Qunbound. If you call + w32_get_arg, make sure you deal with Qunbound in a reasonable way, + and don't let it get stored in any Lisp-visible variables! */ + +static Lisp_Object +mac_get_arg (alist, param, attribute, class, type) + Lisp_Object alist, param; + char *attribute; + char *class; + enum resource_types type; +{ + register Lisp_Object tem; + + tem = Fassq (param, alist); + if (EQ (tem, Qnil)) + tem = Fassq (param, Vdefault_frame_alist); + if (EQ (tem, Qnil)) + { + +#if 0 /* MAC_TODO: search resource also */ + if (attribute) + { + tem = Fx_get_resource (build_string (attribute), + build_string (class), + Qnil, Qnil); + + if (NILP (tem)) + return Qunbound; + + switch (type) + { + case RES_TYPE_NUMBER: + return make_number (atoi (XSTRING (tem)->data)); + + case RES_TYPE_FLOAT: + return make_float (atof (XSTRING (tem)->data)); + + case RES_TYPE_BOOLEAN: + tem = Fdowncase (tem); + if (!strcmp (XSTRING (tem)->data, "on") + || !strcmp (XSTRING (tem)->data, "true")) + return Qt; + else + return Qnil; + + case RES_TYPE_STRING: + return tem; + + case RES_TYPE_SYMBOL: + /* As a special case, we map the values `true' and `on' + to Qt, and `false' and `off' to Qnil. */ + { + Lisp_Object lower; + lower = Fdowncase (tem); + if (!strcmp (XSTRING (lower)->data, "on") + || !strcmp (XSTRING (lower)->data, "true")) + return Qt; + else if (!strcmp (XSTRING (lower)->data, "off") + || !strcmp (XSTRING (lower)->data, "false")) + return Qnil; + else + return Fintern (tem, Qnil); + } + + default: + abort (); + } + } + else +#endif + return Qunbound; + } + return Fcdr (tem); +} + +/* Record in frame F the specified or default value according to ALIST + of the parameter named PROP (a Lisp symbol). + If no value is specified for PROP, look for an X default for XPROP + on the frame named NAME. + If that is not found either, use the value DEFLT. */ + +static Lisp_Object +x_default_parameter (f, alist, prop, deflt, xprop, xclass, type) + struct frame *f; + Lisp_Object alist; + Lisp_Object prop; + Lisp_Object deflt; + char *xprop; + char *xclass; + enum resource_types type; +{ + Lisp_Object tem; + + tem = mac_get_arg (alist, prop, xprop, xclass, type); + if (EQ (tem, Qunbound)) + tem = deflt; + x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil)); + return tem; +} + +DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0, + "Parse an X-style geometry string STRING.\n\ +Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\ +The properties returned may include `top', `left', `height', and `width'.\n\ +The value of `left' or `top' may be an integer,\n\ +or a list (+ N) meaning N pixels relative to top/left corner,\n\ +or a list (- N) meaning -N pixels relative to bottom/right corner.") + (string) + Lisp_Object string; +{ + int geometry, x, y; + unsigned int width, height; + Lisp_Object result; + + CHECK_STRING (string, 0); + + geometry = XParseGeometry ((char *) XSTRING (string)->data, + &x, &y, &width, &height); + + result = Qnil; + if (geometry & XValue) + { + Lisp_Object element; + + if (x >= 0 && (geometry & XNegative)) + element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil))); + else if (x < 0 && ! (geometry & XNegative)) + element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil))); + else + element = Fcons (Qleft, make_number (x)); + result = Fcons (element, result); + } + + if (geometry & YValue) + { + Lisp_Object element; + + if (y >= 0 && (geometry & YNegative)) + element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil))); + else if (y < 0 && ! (geometry & YNegative)) + element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil))); + else + element = Fcons (Qtop, make_number (y)); + result = Fcons (element, result); + } + + if (geometry & WidthValue) + result = Fcons (Fcons (Qwidth, make_number (width)), result); + if (geometry & HeightValue) + result = Fcons (Fcons (Qheight, make_number (height)), result); + + return result; +} + +/* Calculate the desired size and position of this window, + and return the flags saying which aspects were specified. + + This function does not make the coordinates positive. */ + +#define DEFAULT_ROWS 40 +#define DEFAULT_COLS 80 + +static int +x_figure_window_size (f, parms) + struct frame *f; + Lisp_Object parms; +{ + register Lisp_Object tem0, tem1, tem2; + long window_prompting = 0; + + /* Default values if we fall through. + Actually, if that happens we should get + window manager prompting. */ + SET_FRAME_WIDTH (f, DEFAULT_COLS); + f->height = DEFAULT_ROWS; + /* Window managers expect that if program-specified + positions are not (0,0), they're intentional, not defaults. */ + f->output_data.mac->top_pos = 0; + f->output_data.mac->left_pos = 0; + + tem0 = mac_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER); + tem1 = mac_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER); + tem2 = mac_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER); + if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) + { + if (!EQ (tem0, Qunbound)) + { + CHECK_NUMBER (tem0, 0); + f->height = XINT (tem0); + } + if (!EQ (tem1, Qunbound)) + { + CHECK_NUMBER (tem1, 0); + SET_FRAME_WIDTH (f, XINT (tem1)); + } + if (!NILP (tem2) && !EQ (tem2, Qunbound)) + window_prompting |= USSize; + else + window_prompting |= PSize; + } + + f->output_data.mac->vertical_scroll_bar_extra + = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f) + ? 0 + : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0 + ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f) + : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font))); + f->output_data.mac->flags_areas_extra + = FRAME_FLAGS_AREA_WIDTH (f); + f->output_data.mac->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width); + f->output_data.mac->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height); + + tem0 = mac_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER); + tem1 = mac_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER); + tem2 = mac_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER); + if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound)) + { + if (EQ (tem0, Qminus)) + { + f->output_data.mac->top_pos = 0; + window_prompting |= YNegative; + } + else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus) + && CONSP (XCDR (tem0)) + && INTEGERP (XCAR (XCDR (tem0)))) + { + f->output_data.mac->top_pos = - XINT (XCAR (XCDR (tem0))); + window_prompting |= YNegative; + } + else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus) + && CONSP (XCDR (tem0)) + && INTEGERP (XCAR (XCDR (tem0)))) + { + f->output_data.mac->top_pos = XINT (XCAR (XCDR (tem0))); + } + else if (EQ (tem0, Qunbound)) + f->output_data.mac->top_pos = 0; + else + { + CHECK_NUMBER (tem0, 0); + f->output_data.mac->top_pos = XINT (tem0); + if (f->output_data.mac->top_pos < 0) + window_prompting |= YNegative; + } + + if (EQ (tem1, Qminus)) + { + f->output_data.mac->left_pos = 0; + window_prompting |= XNegative; + } + else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus) + && CONSP (XCDR (tem1)) + && INTEGERP (XCAR (XCDR (tem1)))) + { + f->output_data.mac->left_pos = - XINT (XCAR (XCDR (tem1))); + window_prompting |= XNegative; + } + else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus) + && CONSP (XCDR (tem1)) + && INTEGERP (XCAR (XCDR (tem1)))) + { + f->output_data.mac->left_pos = XINT (XCAR (XCDR (tem1))); + } + else if (EQ (tem1, Qunbound)) + f->output_data.mac->left_pos = 0; + else + { + CHECK_NUMBER (tem1, 0); + f->output_data.mac->left_pos = XINT (tem1); + if (f->output_data.mac->left_pos < 0) + window_prompting |= XNegative; + } + + if (!NILP (tem2) && ! EQ (tem2, Qunbound)) + window_prompting |= USPosition; + else + window_prompting |= PPosition; + } + + return window_prompting; +} + + +#if 0 +/* Create and set up the Mac window for frame F. */ + +static void +mac_window (f, window_prompting, minibuffer_only) + struct frame *f; + long window_prompting; + int minibuffer_only; +{ + Rect r; + + BLOCK_INPUT; + + /* Use the resource name as the top-level window name + for looking up resources. Make a non-Lisp copy + for the window manager, so GC relocation won't bother it. + + Elsewhere we specify the window name for the window manager. */ + + { + char *str = (char *) XSTRING (Vx_resource_name)->data; + f->namebuf = (char *) xmalloc (strlen (str) + 1); + strcpy (f->namebuf, str); + } + + SetRect (&r, f->output_data.mac->left_pos, f->output_data.mac->top_pos, + f->output_data.mac->left_pos + PIXEL_WIDTH (f), + f->output_data.mac->top_pos + PIXEL_HEIGHT (f)); + FRAME_MAC_WINDOW (f) + = NewCWindow (NULL, &r, "\p", 1, zoomDocProc, (WindowPtr) -1, 1, (long) f->output_data.mac); + + validate_x_resource_name (); + + /* x_set_name normally ignores requests to set the name if the + requested name is the same as the current name. This is the one + place where that assumption isn't correct; f->name is set, but + the server hasn't been told. */ + { + Lisp_Object name; + int explicit = f->explicit_name; + + f->explicit_name = 0; + name = f->name; + f->name = Qnil; + x_set_name (f, name, explicit); + } + + ShowWindow (FRAME_MAC_WINDOW (f)); + + UNBLOCK_INPUT; + + if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)) + initialize_frame_menubar (f); + + if (FRAME_MAC_WINDOW (f) == 0) + error ("Unable to create window"); +} +#endif + +/* Handle the icon stuff for this window. Perhaps later we might + want an x_set_icon_position which can be called interactively as + well. */ + +static void +x_icon (f, parms) + struct frame *f; + Lisp_Object parms; +{ + Lisp_Object icon_x, icon_y; + + /* Set the position of the icon. Note that Windows 95 groups all + icons in the tray. */ + icon_x = mac_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER); + icon_y = mac_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER); + if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound)) + { + CHECK_NUMBER (icon_x, 0); + CHECK_NUMBER (icon_y, 0); + } + else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound)) + error ("Both left and top icon corners of icon must be specified"); + + BLOCK_INPUT; + + if (! EQ (icon_x, Qunbound)) + x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y)); + +#if 0 /* TODO */ + /* Start up iconic or window? */ + x_wm_set_window_state + (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon) + ? IconicState + : NormalState)); + + x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name) + ? f->icon_name + : f->name))->data); +#endif + + UNBLOCK_INPUT; +} + + +static void +x_make_gc (f) + struct frame *f; +{ + XGCValues gc_values; + + BLOCK_INPUT; + + /* Create the GC's of this frame. + Note that many default values are used. */ + + /* Normal video */ + gc_values.font = f->output_data.mac->font; + gc_values.foreground = f->output_data.mac->foreground_pixel; + gc_values.background = f->output_data.mac->background_pixel; + f->output_data.mac->normal_gc = XCreateGC (FRAME_MAC_DISPLAY (f), + FRAME_MAC_WINDOW (f), + GCFont | GCForeground | GCBackground, + &gc_values); + + /* Reverse video style. */ + gc_values.foreground = f->output_data.mac->background_pixel; + gc_values.background = f->output_data.mac->foreground_pixel; + f->output_data.mac->reverse_gc = XCreateGC (FRAME_MAC_DISPLAY (f), + FRAME_MAC_WINDOW (f), + GCFont | GCForeground | GCBackground, + &gc_values); + + /* Cursor has cursor-color background, background-color foreground. */ + gc_values.foreground = f->output_data.mac->background_pixel; + gc_values.background = f->output_data.mac->cursor_pixel; + f->output_data.mac->cursor_gc = XCreateGC (FRAME_MAC_DISPLAY (f), + FRAME_MAC_WINDOW (f), + GCFont | GCForeground | GCBackground, + &gc_values); + + /* Reliefs. */ + f->output_data.mac->white_relief.gc = 0; + f->output_data.mac->black_relief.gc = 0; + + UNBLOCK_INPUT; +} + + +DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, + 1, 1, 0, + "Make a new window, which is called a \"frame\" in Emacs terms.\n\ +Returns an Emacs frame object.\n\ +ALIST is an alist of frame parameters.\n\ +If the parameters specify that the frame should not have a minibuffer,\n\ +and do not specify a specific minibuffer window to use,\n\ +then `default-minibuffer-frame' must be a frame whose minibuffer can\n\ +be shared by the new frame.\n\ +\n\ +This function is an internal primitive--use `make-frame' instead.") + (parms) + Lisp_Object parms; +{ + struct frame *f; + Lisp_Object frame, tem; + Lisp_Object name; + int minibuffer_only = 0; + long window_prompting = 0; + int width, height; + int count = specpdl_ptr - specpdl; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + Lisp_Object display; + struct mac_display_info *dpyinfo = NULL; + Lisp_Object parent; + struct kboard *kb; + char x_frame_name[10]; + static int x_frame_count = 2; /* starts from 2 because terminal frame is F1 */ + + check_mac (); + + /* Use this general default value to start with + until we know if this frame has a specified name. */ + Vx_resource_name = Vinvocation_name; + + display = mac_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING); + if (EQ (display, Qunbound)) + display = Qnil; + dpyinfo = check_x_display_info (display); +#ifdef MULTI_KBOARD + kb = dpyinfo->kboard; +#else + kb = &the_only_kboard; +#endif + + name = mac_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING); + if (!STRINGP (name) + && ! EQ (name, Qunbound) + && ! NILP (name)) + error ("Invalid frame name--not a string or nil"); + + if (STRINGP (name)) + Vx_resource_name = name; + + /* See if parent window is specified. */ + parent = mac_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER); + if (EQ (parent, Qunbound)) + parent = Qnil; + if (! NILP (parent)) + CHECK_NUMBER (parent, 0); + + /* make_frame_without_minibuffer can run Lisp code and garbage collect. */ + /* No need to protect DISPLAY because that's not used after passing + it to make_frame_without_minibuffer. */ + frame = Qnil; + GCPRO4 (parms, parent, name, frame); + tem = mac_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL); + if (EQ (tem, Qnone) || NILP (tem)) + f = make_frame_without_minibuffer (Qnil, kb, display); + else if (EQ (tem, Qonly)) + { + f = make_minibuffer_frame (); + minibuffer_only = 1; + } + else if (WINDOWP (tem)) + f = make_frame_without_minibuffer (tem, kb, display); + else + f = make_frame (1); + + if (EQ (name, Qunbound) || NILP (name)) + { + sprintf (x_frame_name, "F%d", x_frame_count++); + f->name = build_string (x_frame_name); + f->explicit_name = 0; + } + else + { + f->name = name; + f->explicit_name = 1; + } + + XSETFRAME (frame, f); + + /* Note that X Windows does support scroll bars. */ + FRAME_CAN_HAVE_SCROLL_BARS (f) = 1; + + f->output_method = output_mac; + f->output_data.mac = (struct mac_output *) xmalloc (sizeof (struct mac_output)); + bzero (f->output_data.mac, sizeof (struct mac_output)); + f->output_data.mac->fontset = -1; + f->output_data.mac->scroll_bar_foreground_pixel = -1; + f->output_data.mac->scroll_bar_background_pixel = -1; + +#if 0 + FRAME_FONTSET (f) = -1; +#endif + + f->icon_name + = mac_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING); + if (! STRINGP (f->icon_name)) + f->icon_name = Qnil; + +/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */ +#ifdef MULTI_KBOARD + FRAME_KBOARD (f) = kb; +#endif + + /* Specify the parent under which to make this window. */ + + if (!NILP (parent)) + { + f->output_data.mac->parent_desc = (Window) parent; + f->output_data.mac->explicit_parent = 1; + } + else + { + f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window; + f->output_data.mac->explicit_parent = 0; + } + + /* Set the name; the functions to which we pass f expect the name to + be set. */ + if (EQ (name, Qunbound) || NILP (name)) + { + f->name = build_string (dpyinfo->mac_id_name); + f->explicit_name = 0; + } + else + { + f->name = name; + f->explicit_name = 1; + /* use the frame's title when getting resources for this frame. */ + specbind (Qx_resource_name, name); + } + + /* Extract the window parameters from the supplied values + that are needed to determine window geometry. */ + { + Lisp_Object font; + + font = mac_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING); + + BLOCK_INPUT; + /* First, try whatever font the caller has specified. */ + if (STRINGP (font)) + { + tem = Fquery_fontset (font, Qnil); + if (STRINGP (tem)) + font = x_new_fontset (f, XSTRING (tem)->data); + else + font = x_new_font (f, XSTRING (font)->data); + } + /* Try out a font which we hope has bold and italic variations. */ + if (! STRINGP (font)) + font = x_new_font (f, "-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1"); + /* If those didn't work, look for something which will at least work. */ + if (!STRINGP (font)) + font = x_new_font (f, "-*-monaco-*-12-*-mac-roman"); + if (! STRINGP (font)) + font = x_new_font (f, "-*-courier-*-10-*-mac-roman"); + if (! STRINGP (font)) + error ("Cannot find any usable font"); + UNBLOCK_INPUT; + + x_default_parameter (f, parms, Qfont, font, + "font", "Font", RES_TYPE_STRING); + } + + x_default_parameter (f, parms, Qborder_width, make_number (0), + "borderwidth", "BorderWidth", RES_TYPE_NUMBER); + /* This defaults to 2 in order to match xterm. We recognize either + internalBorderWidth or internalBorder (which is what xterm calls + it). */ + if (NILP (Fassq (Qinternal_border_width, parms))) + { + Lisp_Object value; + + value = mac_get_arg (parms, Qinternal_border_width, + "internalBorder", "BorderWidth", RES_TYPE_NUMBER); + if (! EQ (value, Qunbound)) + parms = Fcons (Fcons (Qinternal_border_width, value), + parms); + } + + /* Default internalBorderWidth to 0 on Windows to match other programs. */ + x_default_parameter (f, parms, Qinternal_border_width, make_number (0), + "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER); + + x_default_parameter (f, parms, Qvertical_scroll_bars, Qt, + "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN); + + /* Also do the stuff which must be set before the window exists. */ + x_default_parameter (f, parms, Qforeground_color, build_string ("black"), + "foreground", "Foreground", RES_TYPE_STRING); + x_default_parameter (f, parms, Qbackground_color, build_string ("white"), + "background", "Background", RES_TYPE_STRING); + x_default_parameter (f, parms, Qmouse_color, build_string ("black"), + "pointerColor", "Foreground", RES_TYPE_STRING); + x_default_parameter (f, parms, Qcursor_color, build_string ("black"), + "cursorColor", "Foreground", RES_TYPE_STRING); + x_default_parameter (f, parms, Qborder_color, build_string ("black"), + "borderColor", "BorderColor", RES_TYPE_STRING); + x_default_parameter (f, parms, Qscreen_gamma, Qnil, + "screenGamma", "ScreenGamma", RES_TYPE_FLOAT); + x_default_parameter (f, parms, Qline_spacing, Qnil, + "lineSpacing", "LineSpacing", RES_TYPE_NUMBER); + + /* Init faces before x_default_parameter is called for scroll-bar + parameters because that function calls x_set_scroll_bar_width, + which calls change_frame_size, which calls Fset_window_buffer, + which runs hooks, which call Fvertical_motion. At the end, we + end up in init_iterator with a null face cache, which should not + happen. */ + init_frame_faces (f); + + x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1), + "menuBar", "MenuBar", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qtool_bar_lines, make_number (0), + "toolBar", "ToolBar", RES_TYPE_NUMBER); +#if 0 + x_default_parameter (f, parms, Qbuffer_predicate, Qnil, + "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL); +#endif + x_default_parameter (f, parms, Qtitle, Qnil, + "title", "Title", RES_TYPE_STRING); + + f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window; + window_prompting = x_figure_window_size (f, parms); + + if (window_prompting & XNegative) + { + if (window_prompting & YNegative) + f->output_data.mac->win_gravity = SouthEastGravity; + else + f->output_data.mac->win_gravity = NorthEastGravity; + } + else + { + if (window_prompting & YNegative) + f->output_data.mac->win_gravity = SouthWestGravity; + else + f->output_data.mac->win_gravity = NorthWestGravity; + } + + f->output_data.mac->size_hint_flags = window_prompting; + + tem = mac_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN); + f->no_split = minibuffer_only || EQ (tem, Qt); + + /* Create the window. Add the tool-bar height to the initial frame + height so that the user gets a text display area of the size he + specified with -g or via the registry. Later changes of the + tool-bar height don't change the frame size. This is done so that + users can create tall Emacs frames without having to guess how + tall the tool-bar will get. */ + f->height += FRAME_TOOL_BAR_LINES (f); + + /* mac_window (f, window_prompting, minibuffer_only); */ + make_mac_frame (f); + + x_icon (f, parms); + + x_make_gc (f); + + /* Now consider the frame official. */ + FRAME_MAC_DISPLAY_INFO (f)->reference_count++; + Vframe_list = Fcons (frame, Vframe_list); + + /* We need to do this after creating the window, so that the + icon-creation functions can say whose icon they're describing. */ + x_default_parameter (f, parms, Qicon_type, Qnil, + "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL); + + x_default_parameter (f, parms, Qauto_raise, Qnil, + "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); + x_default_parameter (f, parms, Qauto_lower, Qnil, + "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); + x_default_parameter (f, parms, Qcursor_type, Qbox, + "cursorType", "CursorType", RES_TYPE_SYMBOL); + x_default_parameter (f, parms, Qscroll_bar_width, Qnil, + "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER); + + /* Dimensions, especially f->height, must be done via change_frame_size. + Change will not be effected unless different from the current + f->height. */ + + width = f->width; + height = f->height; + f->height = 0; + SET_FRAME_WIDTH (f, 0); + change_frame_size (f, height, width, 1, 0, 0); + + /* Set up faces after all frame parameters are known. */ + call1 (Qface_set_after_frame_default, frame); + +#if 0 /* MAC_TODO: when we have window manager hints */ + /* Tell the server what size and position, etc, we want, and how + badly we want them. This should be done after we have the menu + bar so that its size can be taken into account. */ + BLOCK_INPUT; + x_wm_set_size_hint (f, window_prompting, 0); + UNBLOCK_INPUT; +#endif + + /* Make the window appear on the frame and enable display, unless + the caller says not to. However, with explicit parent, Emacs + cannot control visibility, so don't try. */ + if (! f->output_data.mac->explicit_parent) + { + Lisp_Object visibility; + + visibility = mac_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL); + if (EQ (visibility, Qunbound)) + visibility = Qt; + +#if 0 /* MAC_TODO: really no iconify on Mac */ + if (EQ (visibility, Qicon)) + x_iconify_frame (f); + else +#endif + if (! NILP (visibility)) + x_make_frame_visible (f); + else + /* Must have been Qnil. */ + ; + } + + UNGCPRO; + return unbind_to (count, frame); +} + +/* FRAME is used only to get a handle on the X display. We don't pass the + display info directly because we're called from frame.c, which doesn't + know about that structure. */ +Lisp_Object +x_get_focus_frame (frame) + struct frame *frame; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame); + Lisp_Object xfocus; + if (! dpyinfo->x_focus_frame) + return Qnil; + + XSETFRAME (xfocus, dpyinfo->x_focus_frame); + return xfocus; +} + +DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, + "Internal function called by `color-defined-p', which see.") + (color, frame) + Lisp_Object color, frame; +{ + XColor foo; + FRAME_PTR f = check_x_frame (frame); + + CHECK_STRING (color, 1); + + if (mac_defined_color (f, XSTRING (color)->data, &foo, 0)) + return Qt; + else + return Qnil; +} + +DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, + "Internal function called by `color-values', which see.") + (color, frame) + Lisp_Object color, frame; +{ + XColor foo; + FRAME_PTR f = check_x_frame (frame); + + CHECK_STRING (color, 1); + + if (mac_defined_color (f, XSTRING (color)->data, &foo, 0)) + { + Lisp_Object rgb[3]; + + rgb[0] = make_number ((RED_FROM_ULONG (foo.pixel) << 8) + | RED_FROM_ULONG (foo.pixel)); + rgb[1] = make_number ((GREEN_FROM_ULONG (foo.pixel) << 8) + | GREEN_FROM_ULONG (foo.pixel)); + rgb[2] = make_number ((BLUE_FROM_ULONG (foo.pixel) << 8) + | BLUE_FROM_ULONG (foo.pixel)); + return Flist (3, rgb); + } + else + return Qnil; +} + +DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, + "Internal function called by `display-color-p', which see.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + + if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2) + return Qnil; + + return Qt; +} + +DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p, + 0, 1, 0, + "Return t if the X display supports shades of gray.\n\ +Note that color displays do support shades of gray.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + + if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1) + return Qnil; + + return Qt; +} + +DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width, + 0, 1, 0, + "Returns the width in pixels of the X display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + + return make_number (dpyinfo->width); +} + +DEFUN ("x-display-pixel-height", Fx_display_pixel_height, + Sx_display_pixel_height, 0, 1, 0, + "Returns the height in pixels of the X display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + + return make_number (dpyinfo->height); +} + +DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, + 0, 1, 0, + "Returns the number of bitplanes of the display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + + return make_number (dpyinfo->n_planes * dpyinfo->n_cbits); +} + +DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, + 0, 1, 0, + "Returns the number of color cells of the display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + + /* MAC_TODO: check whether this is right */ + return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits))); +} + +DEFUN ("x-server-max-request-size", Fx_server_max_request_size, + Sx_server_max_request_size, + 0, 1, 0, + "Returns the maximum request size of the server of display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + + return make_number (1); +} + +DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, + "Returns the vendor ID string of the W32 system (Microsoft).\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + return build_string ("Apple Computers"); +} + +DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, + "Returns the version numbers of the server of display DISPLAY.\n\ +The value is a list of three integers: the major and minor\n\ +version numbers, and the vendor-specific release\n\ +number. See also the function `x-server-vendor'.\n\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + int mac_major_version, mac_minor_version; + SInt32 response; + + if (Gestalt (gestaltSystemVersion, &response) != noErr) + error ("Cannot get Mac OS version"); + + mac_major_version = (response >> 8) & 0xf; + mac_minor_version = (response >> 4) & 0xf; + + return Fcons (make_number (mac_major_version), + Fcons (make_number (mac_minor_version), Qnil)); +} + +DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0, + "Returns the number of screens on the server of display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + return make_number (1); +} + +DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, + "Returns the height in millimeters of the X display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + /* MAC_TODO: this is an approximation, and only of the main display */ + + struct mac_display_info *dpyinfo = check_x_display_info (display); + short h, v; + + ScreenRes (&h, &v); + + return make_number ((int) (v / 72.0 * 25.4)); +} + +DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0, + "Returns the width in millimeters of the X display DISPLAY.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + /* MAC_TODO: this is an approximation, and only of the main display */ + + struct mac_display_info *dpyinfo = check_x_display_info (display); + short h, v; + + ScreenRes (&h, &v); + + return make_number ((int) (h / 72.0 * 25.4)); +} + +DEFUN ("x-display-backing-store", Fx_display_backing_store, + Sx_display_backing_store, 0, 1, 0, + "Returns an indication of whether display DISPLAY does backing store.\n\ +The value may be `always', `when-mapped', or `not-useful'.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + return intern ("not-useful"); +} + +DEFUN ("x-display-visual-class", Fx_display_visual_class, + Sx_display_visual_class, 0, 1, 0, + "Returns the visual class of the display DISPLAY.\n\ +The value is one of the symbols `static-gray', `gray-scale',\n\ +`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + +#if 0 + switch (dpyinfo->visual->class) + { + case StaticGray: return (intern ("static-gray")); + case GrayScale: return (intern ("gray-scale")); + case StaticColor: return (intern ("static-color")); + case PseudoColor: return (intern ("pseudo-color")); + case TrueColor: return (intern ("true-color")); + case DirectColor: return (intern ("direct-color")); + default: + error ("Display has an unknown visual class"); + } +#endif + + error ("Display has an unknown visual class"); +} + +DEFUN ("x-display-save-under", Fx_display_save_under, + Sx_display_save_under, 0, 1, 0, + "Returns t if the display DISPLAY supports the save-under feature.\n\ +The optional argument DISPLAY specifies which display to ask about.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If omitted or nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + return Qnil; +} + +int +x_pixel_width (f) + register struct frame *f; +{ + return PIXEL_WIDTH (f); +} + +int +x_pixel_height (f) + register struct frame *f; +{ + return PIXEL_HEIGHT (f); +} + +int +x_char_width (f) + register struct frame *f; +{ + return FONT_WIDTH (f->output_data.mac->font); +} + +int +x_char_height (f) + register struct frame *f; +{ + return f->output_data.mac->line_height; +} + +int +x_screen_planes (f) + register struct frame *f; +{ + return FRAME_MAC_DISPLAY_INFO (f)->n_planes; +} + +/* Return the display structure for the display named NAME. + Open a new connection if necessary. */ + +struct mac_display_info * +x_display_info_for_name (name) + Lisp_Object name; +{ + Lisp_Object names; + struct mac_display_info *dpyinfo; + + CHECK_STRING (name, 0); + + for (dpyinfo = &one_mac_display_info, names = x_display_name_list; + dpyinfo; + dpyinfo = dpyinfo->next, names = XCDR (names)) + { + Lisp_Object tem; + tem = Fstring_equal (XCAR (XCAR (names)), name); + if (!NILP (tem)) + return dpyinfo; + } + + /* Use this general default value to start with. */ + Vx_resource_name = Vinvocation_name; + + validate_x_resource_name (); + + dpyinfo = x_term_init (name, (unsigned char *) 0, + (char *) XSTRING (Vx_resource_name)->data); + + if (dpyinfo == 0) + error ("Cannot connect to server %s", XSTRING (name)->data); + + mac_in_use = 1; + XSETFASTINT (Vwindow_system_version, 3); + + return dpyinfo; +} + +#if 0 /* MAC_TODO: implement network support */ +DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, + 1, 3, 0, "Open a connection to a server.\n\ +DISPLAY is the name of the display to connect to.\n\ +Optional second arg XRM-STRING is a string of resources in xrdb format.\n\ +If the optional third arg MUST-SUCCEED is non-nil,\n\ +terminate Emacs if we can't open the connection.") + (display, xrm_string, must_succeed) + Lisp_Object display, xrm_string, must_succeed; +{ + unsigned char *xrm_option; + struct mac_display_info *dpyinfo; + + CHECK_STRING (display, 0); + if (! NILP (xrm_string)) + CHECK_STRING (xrm_string, 1); + + if (! EQ (Vwindow_system, intern ("mac"))) + error ("Not using Mac OS"); + + if (! NILP (xrm_string)) + xrm_option = (unsigned char *) XSTRING (xrm_string)->data; + else + xrm_option = (unsigned char *) 0; + + validate_x_resource_name (); + + /* This is what opens the connection and sets x_current_display. + This also initializes many symbols, such as those used for input. */ + dpyinfo = mac_term_init (display, xrm_option, + (char *) XSTRING (Vx_resource_name)->data); + + if (dpyinfo == 0) + { + if (!NILP (must_succeed)) + fatal ("Cannot connect to server %s.\n", + XSTRING (display)->data); + else + error ("Cannot connect to server %s", XSTRING (display)->data); + } + + mac_in_use = 1; + + XSETFASTINT (Vwindow_system_version, 3); + return Qnil; +} + +DEFUN ("x-close-connection", Fx_close_connection, + Sx_close_connection, 1, 1, 0, + "Close the connection to DISPLAY's server.\n\ +For DISPLAY, specify either a frame or a display name (a string).\n\ +If DISPLAY is nil, that stands for the selected frame's display.") + (display) + Lisp_Object display; +{ + struct mac_display_info *dpyinfo = check_x_display_info (display); + int i; + + if (dpyinfo->reference_count > 0) + error ("Display still has frames on it"); + + BLOCK_INPUT; + /* Free the fonts in the font table. */ + for (i = 0; i < dpyinfo->n_fonts; i++) + if (dpyinfo->font_table[i].name) + { + if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name) + xfree (dpyinfo->font_table[i].full_name); + xfree (dpyinfo->font_table[i].name); + x_unload_font (dpyinfo, dpyinfo->font_table[i].font); + } + x_destroy_all_bitmaps (dpyinfo); + + x_delete_display (dpyinfo); + UNBLOCK_INPUT; + + return Qnil; +} +#endif + +DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, + "Return the list of display names that Emacs has connections to.") + () +{ + Lisp_Object tail, result; + + result = Qnil; + for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail)) + result = Fcons (XCAR (XCAR (tail)), result); + + return result; +} + +DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0, + "If ON is non-nil, report errors as soon as the erring request is made.\n\ +If ON is nil, allow buffering of requests.\n\ +This is a noop on W32 systems.\n\ +The optional second argument DISPLAY specifies which display to act on.\n\ +DISPLAY should be either a frame or a display name (a string).\n\ +If DISPLAY is omitted or nil, that stands for the selected frame's display.") + (on, display) + Lisp_Object display, on; +{ + return Qnil; +} + + +/*********************************************************************** + Image types + ***********************************************************************/ + +/* Value is the number of elements of vector VECTOR. */ + +#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR)) + +/* List of supported image types. Use define_image_type to add new + types. Use lookup_image_type to find a type for a given symbol. */ + +static struct image_type *image_types; + +/* The symbol `image' which is the car of the lists used to represent + images in Lisp. */ + +extern Lisp_Object Qimage; + +/* The symbol `xbm' which is used as the type symbol for XBM images. */ + +Lisp_Object Qxbm; + +/* Keywords. */ + +extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile; +extern Lisp_Object QCdata; +Lisp_Object QCtype, QCascent, QCmargin, QCrelief; +Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask; +Lisp_Object QCindex; + +/* Other symbols. */ + +Lisp_Object Qlaplace; + +/* Time in seconds after which images should be removed from the cache + if not displayed. */ + +Lisp_Object Vimage_cache_eviction_delay; + +/* Function prototypes. */ + +static void define_image_type P_ ((struct image_type *type)); +static struct image_type *lookup_image_type P_ ((Lisp_Object symbol)); +static void image_error P_ ((char *format, Lisp_Object, Lisp_Object)); +static void x_laplace P_ ((struct frame *, struct image *)); +static int x_build_heuristic_mask P_ ((struct frame *, struct image *, + Lisp_Object)); + + +/* Define a new image type from TYPE. This adds a copy of TYPE to + image_types and adds the symbol *TYPE->type to Vimage_types. */ + +static void +define_image_type (type) + struct image_type *type; +{ + /* Make a copy of TYPE to avoid a bus error in a dumped Emacs. + The initialized data segment is read-only. */ + struct image_type *p = (struct image_type *) xmalloc (sizeof *p); + bcopy (type, p, sizeof *p); + p->next = image_types; + image_types = p; + Vimage_types = Fcons (*p->type, Vimage_types); +} + + +/* Look up image type SYMBOL, and return a pointer to its image_type + structure. Value is null if SYMBOL is not a known image type. */ + +static INLINE struct image_type * +lookup_image_type (symbol) + Lisp_Object symbol; +{ + struct image_type *type; + + for (type = image_types; type; type = type->next) + if (EQ (symbol, *type->type)) + break; + + return type; +} + + +/* Value is non-zero if OBJECT is a valid Lisp image specification. A + valid image specification is a list whose car is the symbol + `image', and whose rest is a property list. The property list must + contain a value for key `:type'. That value must be the name of a + supported image type. The rest of the property list depends on the + image type. */ + +int +valid_image_p (object) + Lisp_Object object; +{ + int valid_p = 0; + + if (CONSP (object) && EQ (XCAR (object), Qimage)) + { + Lisp_Object symbol = Fplist_get (XCDR (object), QCtype); + struct image_type *type = lookup_image_type (symbol); + + if (type) + valid_p = type->valid_p (object); + } + + return valid_p; +} + + +/* Log error message with format string FORMAT and argument ARG. + Signaling an error, e.g. when an image cannot be loaded, is not a + good idea because this would interrupt redisplay, and the error + message display would lead to another redisplay. This function + therefore simply displays a message. */ + +static void +image_error (format, arg1, arg2) + char *format; + Lisp_Object arg1, arg2; +{ + add_to_log (format, arg1, arg2); +} + + + +/*********************************************************************** + Image specifications + ***********************************************************************/ + +enum image_value_type +{ + IMAGE_DONT_CHECK_VALUE_TYPE, + IMAGE_STRING_VALUE, + IMAGE_SYMBOL_VALUE, + IMAGE_POSITIVE_INTEGER_VALUE, + IMAGE_NON_NEGATIVE_INTEGER_VALUE, + IMAGE_ASCENT_VALUE, + IMAGE_INTEGER_VALUE, + IMAGE_FUNCTION_VALUE, + IMAGE_NUMBER_VALUE, + IMAGE_BOOL_VALUE +}; + +/* Structure used when parsing image specifications. */ + +struct image_keyword +{ + /* Name of keyword. */ + char *name; + + /* The type of value allowed. */ + enum image_value_type type; + + /* Non-zero means key must be present. */ + int mandatory_p; + + /* Used to recognize duplicate keywords in a property list. */ + int count; + + /* The value that was found. */ + Lisp_Object value; +}; + + +static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *, + int, Lisp_Object)); +static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *)); + + +/* Parse image spec SPEC according to KEYWORDS. A valid image spec + has the format (image KEYWORD VALUE ...). One of the keyword/ + value pairs must be `:type TYPE'. KEYWORDS is a vector of + image_keywords structures of size NKEYWORDS describing other + allowed keyword/value pairs. Value is non-zero if SPEC is valid. */ + +static int +parse_image_spec (spec, keywords, nkeywords, type) + Lisp_Object spec; + struct image_keyword *keywords; + int nkeywords; + Lisp_Object type; +{ + int i; + Lisp_Object plist; + + if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) + return 0; + + plist = XCDR (spec); + while (CONSP (plist)) + { + Lisp_Object key, value; + + /* First element of a pair must be a symbol. */ + key = XCAR (plist); + plist = XCDR (plist); + if (!SYMBOLP (key)) + return 0; + + /* There must follow a value. */ + if (!CONSP (plist)) + return 0; + value = XCAR (plist); + plist = XCDR (plist); + + /* Find key in KEYWORDS. Error if not found. */ + for (i = 0; i < nkeywords; ++i) + if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0) + break; + + if (i == nkeywords) + continue; + + /* Record that we recognized the keyword. If a keywords + was found more than once, it's an error. */ + keywords[i].value = value; + ++keywords[i].count; + + if (keywords[i].count > 1) + return 0; + + /* Check type of value against allowed type. */ + switch (keywords[i].type) + { + case IMAGE_STRING_VALUE: + if (!STRINGP (value)) + return 0; + break; + + case IMAGE_SYMBOL_VALUE: + if (!SYMBOLP (value)) + return 0; + break; + + case IMAGE_POSITIVE_INTEGER_VALUE: + if (!INTEGERP (value) || XINT (value) <= 0) + return 0; + break; + + case IMAGE_ASCENT_VALUE: + if (SYMBOLP (value) && EQ (value, Qcenter)) + break; + else if (INTEGERP (value) + && XINT (value) >= 0 + && XINT (value) <= 100) + break; + return 0; + + case IMAGE_NON_NEGATIVE_INTEGER_VALUE: + if (!INTEGERP (value) || XINT (value) < 0) + return 0; + break; + + case IMAGE_DONT_CHECK_VALUE_TYPE: + break; + + case IMAGE_FUNCTION_VALUE: + value = indirect_function (value); + if (SUBRP (value) + || COMPILEDP (value) + || (CONSP (value) && EQ (XCAR (value), Qlambda))) + break; + return 0; + + case IMAGE_NUMBER_VALUE: + if (!INTEGERP (value) && !FLOATP (value)) + return 0; + break; + + case IMAGE_INTEGER_VALUE: + if (!INTEGERP (value)) + return 0; + break; + + case IMAGE_BOOL_VALUE: + if (!NILP (value) && !EQ (value, Qt)) + return 0; + break; + + default: + abort (); + break; + } + + if (EQ (key, QCtype) && !EQ (type, value)) + return 0; + } + + /* Check that all mandatory fields are present. */ + for (i = 0; i < nkeywords; ++i) + if (keywords[i].mandatory_p && keywords[i].count == 0) + return 0; + + return NILP (plist); +} + + +/* Return the value of KEY in image specification SPEC. Value is nil + if KEY is not present in SPEC. if FOUND is not null, set *FOUND + to 1 if KEY was found in SPEC, set it to 0 otherwise. */ + +static Lisp_Object +image_spec_value (spec, key, found) + Lisp_Object spec, key; + int *found; +{ + Lisp_Object tail; + + xassert (valid_image_p (spec)); + + for (tail = XCDR (spec); + CONSP (tail) && CONSP (XCDR (tail)); + tail = XCDR (XCDR (tail))) + { + if (EQ (XCAR (tail), key)) + { + if (found) + *found = 1; + return XCAR (XCDR (tail)); + } + } + + if (found) + *found = 0; + return Qnil; +} + + + + +/*********************************************************************** + Image type independent image structures + ***********************************************************************/ + +static struct image *make_image P_ ((Lisp_Object spec, unsigned hash)); +static void free_image P_ ((struct frame *f, struct image *img)); + + +/* Allocate and return a new image structure for image specification + SPEC. SPEC has a hash value of HASH. */ + +static struct image * +make_image (spec, hash) + Lisp_Object spec; + unsigned hash; +{ + struct image *img = (struct image *) xmalloc (sizeof *img); + + xassert (valid_image_p (spec)); + bzero (img, sizeof *img); + img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL)); + xassert (img->type != NULL); + img->spec = spec; + img->data.lisp_val = Qnil; + img->ascent = DEFAULT_IMAGE_ASCENT; + img->hash = hash; + return img; +} + + +/* Free image IMG which was used on frame F, including its resources. */ + +static void +free_image (f, img) + struct frame *f; + struct image *img; +{ + if (img) + { + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + + /* Remove IMG from the hash table of its cache. */ + if (img->prev) + img->prev->next = img->next; + else + c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next; + + if (img->next) + img->next->prev = img->prev; + + c->images[img->id] = NULL; + + /* Free resources, then free IMG. */ + img->type->free (f, img); + xfree (img); + } +} + + +/* Prepare image IMG for display on frame F. Must be called before + drawing an image. */ + +void +prepare_image_for_display (f, img) + struct frame *f; + struct image *img; +{ + EMACS_TIME t; + + /* We're about to display IMG, so set its timestamp to `now'. */ + EMACS_GET_TIME (t); + img->timestamp = EMACS_SECS (t); + + /* If IMG doesn't have a pixmap yet, load it now, using the image + type dependent loader function. */ + if (img->pixmap == 0 && !img->load_failed_p) + img->load_failed_p = img->type->load (f, img) == 0; +} + + +/* Value is the number of pixels for the ascent of image IMG when + drawn in face FACE. */ + +int +image_ascent (img, face) + struct image *img; + struct face *face; +{ + int height = img->height + img->margin; + int ascent; + + if (img->ascent == CENTERED_IMAGE_ASCENT) + { + if (face->font) + ascent = height / 2 - (FONT_DESCENT(face->font) + - FONT_BASE(face->font)) / 2; + else + ascent = height / 2; + } + else + ascent = height * img->ascent / 100.0; + + return ascent; +} + + + +/*********************************************************************** + Helper functions for X image types + ***********************************************************************/ + +static void x_clear_image P_ ((struct frame *f, struct image *img)); +static unsigned long x_alloc_image_color P_ ((struct frame *f, + struct image *img, + Lisp_Object color_name, + unsigned long dflt)); + +/* Free X resources of image IMG which is used on frame F. */ + +static void +x_clear_image (f, img) + struct frame *f; + struct image *img; +{ +#if 0 /* MAC_TODO: W32 image support */ + + if (img->pixmap) + { + BLOCK_INPUT; + XFreePixmap (NULL, img->pixmap); + img->pixmap = 0; + UNBLOCK_INPUT; + } + + if (img->ncolors) + { + int class = FRAME_W32_DISPLAY_INFO (f)->visual->class; + + /* If display has an immutable color map, freeing colors is not + necessary and some servers don't allow it. So don't do it. */ + if (class != StaticColor + && class != StaticGray + && class != TrueColor) + { + Colormap cmap; + BLOCK_INPUT; + cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen); + XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors, + img->ncolors, 0); + UNBLOCK_INPUT; + } + + xfree (img->colors); + img->colors = NULL; + img->ncolors = 0; + } +#endif +} + + +/* Allocate color COLOR_NAME for image IMG on frame F. If color + cannot be allocated, use DFLT. Add a newly allocated color to + IMG->colors, so that it can be freed again. Value is the pixel + color. */ + +static unsigned long +x_alloc_image_color (f, img, color_name, dflt) + struct frame *f; + struct image *img; + Lisp_Object color_name; + unsigned long dflt; +{ +#if 0 /* MAC_TODO: allocing colors. */ + XColor color; + unsigned long result; + + xassert (STRINGP (color_name)); + + if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1)) + { + /* This isn't called frequently so we get away with simply + reallocating the color vector to the needed size, here. */ + ++img->ncolors; + img->colors = + (unsigned long *) xrealloc (img->colors, + img->ncolors * sizeof *img->colors); + img->colors[img->ncolors - 1] = color.pixel; + result = color.pixel; + } + else + result = dflt; + return result; +#endif + return 0; +} + + + +/*********************************************************************** + Image Cache + ***********************************************************************/ + +static void cache_image P_ ((struct frame *f, struct image *img)); + + +/* Return a new, initialized image cache that is allocated from the + heap. Call free_image_cache to free an image cache. */ + +struct image_cache * +make_image_cache () +{ + struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c); + int size; + + bzero (c, sizeof *c); + c->size = 50; + c->images = (struct image **) xmalloc (c->size * sizeof *c->images); + size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; + c->buckets = (struct image **) xmalloc (size); + bzero (c->buckets, size); + return c; +} + + +/* Free image cache of frame F. Be aware that X frames share images + caches. */ + +void +free_image_cache (f) + struct frame *f; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + if (c) + { + int i; + + /* Cache should not be referenced by any frame when freed. */ + xassert (c->refcount == 0); + + for (i = 0; i < c->used; ++i) + free_image (f, c->images[i]); + xfree (c->images); + xfree (c); + xfree (c->buckets); + FRAME_X_IMAGE_CACHE (f) = NULL; + } +} + + +/* Clear image cache of frame F. FORCE_P non-zero means free all + images. FORCE_P zero means clear only images that haven't been + displayed for some time. Should be called from time to time to + reduce the number of loaded images. If image-eviction-seconds is + non-nil, this frees images in the cache which weren't displayed for + at least that many seconds. */ + +void +clear_image_cache (f, force_p) + struct frame *f; + int force_p; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + + if (c && INTEGERP (Vimage_cache_eviction_delay)) + { + EMACS_TIME t; + unsigned long old; + int i, any_freed_p = 0; + + EMACS_GET_TIME (t); + old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); + + for (i = 0; i < c->used; ++i) + { + struct image *img = c->images[i]; + if (img != NULL + && (force_p + || (img->timestamp > old))) + { + free_image (f, img); + any_freed_p = 1; + } + } + + /* We may be clearing the image cache because, for example, + Emacs was iconified for a longer period of time. In that + case, current matrices may still contain references to + images freed above. So, clear these matrices. */ + if (any_freed_p) + { + clear_current_matrices (f); + ++windows_or_buffers_changed; + } + } +} + + +DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, + 0, 1, 0, + "Clear the image cache of FRAME.\n\ +FRAME nil or omitted means use the selected frame.\n\ +FRAME t means clear the image caches of all frames.") + (frame) + Lisp_Object frame; +{ + if (EQ (frame, Qt)) + { + Lisp_Object tail; + + FOR_EACH_FRAME (tail, frame) + if (FRAME_MAC_P (XFRAME (frame))) + clear_image_cache (XFRAME (frame), 1); + } + else + clear_image_cache (check_x_frame (frame), 1); + + return Qnil; +} + + +/* Return the id of image with Lisp specification SPEC on frame F. + SPEC must be a valid Lisp image specification (see valid_image_p). */ + +int +lookup_image (f, spec) + struct frame *f; + Lisp_Object spec; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + struct image *img; + int i; + unsigned hash; + struct gcpro gcpro1; + EMACS_TIME now; + + /* F must be a window-system frame, and SPEC must be a valid image + specification. */ + xassert (FRAME_WINDOW_P (f)); + xassert (valid_image_p (spec)); + + GCPRO1 (spec); + + /* Look up SPEC in the hash table of the image cache. */ + hash = sxhash (spec, 0); + i = hash % IMAGE_CACHE_BUCKETS_SIZE; + + for (img = c->buckets[i]; img; img = img->next) + if (img->hash == hash && !NILP (Fequal (img->spec, spec))) + break; + + /* If not found, create a new image and cache it. */ + if (img == NULL) + { + img = make_image (spec, hash); + cache_image (f, img); + img->load_failed_p = img->type->load (f, img) == 0; + xassert (!interrupt_input_blocked); + + /* If we can't load the image, and we don't have a width and + height, use some arbitrary width and height so that we can + draw a rectangle for it. */ + if (img->load_failed_p) + { + Lisp_Object value; + + value = image_spec_value (spec, QCwidth, NULL); + img->width = (INTEGERP (value) + ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH); + value = image_spec_value (spec, QCheight, NULL); + img->height = (INTEGERP (value) + ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT); + } + else + { + /* Handle image type independent image attributes + `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */ + Lisp_Object ascent, margin, relief, algorithm, heuristic_mask; + Lisp_Object file; + + ascent = image_spec_value (spec, QCascent, NULL); + if (INTEGERP (ascent)) + img->ascent = XFASTINT (ascent); + else if (EQ (ascent, Qcenter)) + img->ascent = CENTERED_IMAGE_ASCENT; + + margin = image_spec_value (spec, QCmargin, NULL); + if (INTEGERP (margin) && XINT (margin) >= 0) + img->margin = XFASTINT (margin); + + relief = image_spec_value (spec, QCrelief, NULL); + if (INTEGERP (relief)) + { + img->relief = XINT (relief); + img->margin += abs (img->relief); + } + + /* Should we apply a Laplace edge-detection algorithm? */ + algorithm = image_spec_value (spec, QCalgorithm, NULL); + if (img->pixmap && EQ (algorithm, Qlaplace)) + x_laplace (f, img); + + /* Should we built a mask heuristically? */ + heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL); + if (img->pixmap && !img->mask && !NILP (heuristic_mask)) + x_build_heuristic_mask (f, img, heuristic_mask); + } + } + + /* We're using IMG, so set its timestamp to `now'. */ + EMACS_GET_TIME (now); + img->timestamp = EMACS_SECS (now); + + UNGCPRO; + + /* Value is the image id. */ + return img->id; +} + + +/* Cache image IMG in the image cache of frame F. */ + +static void +cache_image (f, img) + struct frame *f; + struct image *img; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + int i; + + /* Find a free slot in c->images. */ + for (i = 0; i < c->used; ++i) + if (c->images[i] == NULL) + break; + + /* If no free slot found, maybe enlarge c->images. */ + if (i == c->used && c->used == c->size) + { + c->size *= 2; + c->images = (struct image **) xrealloc (c->images, + c->size * sizeof *c->images); + } + + /* Add IMG to c->images, and assign IMG an id. */ + c->images[i] = img; + img->id = i; + if (i == c->used) + ++c->used; + + /* Add IMG to the cache's hash table. */ + i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; + img->next = c->buckets[i]; + if (img->next) + img->next->prev = img; + img->prev = NULL; + c->buckets[i] = img; +} + + +/* Call FN on every image in the image cache of frame F. Used to mark + Lisp Objects in the image cache. */ + +void +forall_images_in_image_cache (f, fn) + struct frame *f; + void (*fn) P_ ((struct image *img)); +{ + if (FRAME_LIVE_P (f) && FRAME_MAC_P (f)) + { + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + if (c) + { + int i; + for (i = 0; i < c->used; ++i) + if (c->images[i]) + fn (c->images[i]); + } + } +} + + + +/*********************************************************************** + Mac support code + ***********************************************************************/ + +#if 0 /* MAC_TODO: Mac specific image code. */ + +static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int, + XImage **, Pixmap *)); +static void x_destroy_x_image P_ ((XImage *)); +static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int)); + + +/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on + frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. + Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated + via xmalloc. Print error messages via image_error if an error + occurs. Value is non-zero if successful. */ + +static int +x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap) + struct frame *f; + int width, height, depth; + XImage **ximg; + Pixmap *pixmap; +{ +#if 0 /* MAC_TODO: Image support for Mac */ + Display *display = FRAME_W32_DISPLAY (f); + Screen *screen = FRAME_X_SCREEN (f); + Window window = FRAME_W32_WINDOW (f); + + xassert (interrupt_input_blocked); + + if (depth <= 0) + depth = DefaultDepthOfScreen (screen); + *ximg = XCreateImage (display, DefaultVisualOfScreen (screen), + depth, ZPixmap, 0, NULL, width, height, + depth > 16 ? 32 : depth > 8 ? 16 : 8, 0); + if (*ximg == NULL) + { + image_error ("Unable to allocate X image", Qnil, Qnil); + return 0; + } + + /* Allocate image raster. */ + (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); + + /* Allocate a pixmap of the same size. */ + *pixmap = XCreatePixmap (display, window, width, height, depth); + if (*pixmap == 0) + { + x_destroy_x_image (*ximg); + *ximg = NULL; + image_error ("Unable to create X pixmap", Qnil, Qnil); + return 0; + } +#endif + return 1; +} + + +/* Destroy XImage XIMG. Free XIMG->data. */ + +static void +x_destroy_x_image (ximg) + XImage *ximg; +{ + xassert (interrupt_input_blocked); + if (ximg) + { + xfree (ximg->data); + ximg->data = NULL; + XDestroyImage (ximg); + } +} + + +/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT + are width and height of both the image and pixmap. */ + +static void +x_put_x_image (f, ximg, pixmap, width, height) + struct frame *f; + XImage *ximg; + Pixmap pixmap; +{ + GC gc; + + xassert (interrupt_input_blocked); + gc = XCreateGC (NULL, pixmap, 0, NULL); + XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height); + XFreeGC (NULL, gc); +} + +#endif + + +/*********************************************************************** + Searching files + ***********************************************************************/ + +static Lisp_Object x_find_image_file P_ ((Lisp_Object)); + +/* Find image file FILE. Look in data-directory, then + x-bitmap-file-path. Value is the full name of the file found, or + nil if not found. */ + +static Lisp_Object +x_find_image_file (file) + Lisp_Object file; +{ + Lisp_Object file_found, search_path; + struct gcpro gcpro1, gcpro2; + int fd; + + file_found = Qnil; + search_path = Fcons (Vdata_directory, Vx_bitmap_file_path); + GCPRO2 (file_found, search_path); + + /* Try to find FILE in data-directory, then x-bitmap-file-path. */ + fd = openp (search_path, file, "", &file_found, 0); + + if (fd < 0) + file_found = Qnil; + else + close (fd); + + UNGCPRO; + return file_found; +} + + +/*********************************************************************** + XBM images + ***********************************************************************/ + +static int xbm_load P_ ((struct frame *f, struct image *img)); +static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img, + Lisp_Object file)); +static int xbm_image_p P_ ((Lisp_Object object)); +static int xbm_read_bitmap_file_data P_ ((char *, int *, int *, + unsigned char **)); + + +/* Indices of image specification fields in xbm_format, below. */ + +enum xbm_keyword_index +{ + XBM_TYPE, + XBM_FILE, + XBM_WIDTH, + XBM_HEIGHT, + XBM_DATA, + XBM_FOREGROUND, + XBM_BACKGROUND, + XBM_ASCENT, + XBM_MARGIN, + XBM_RELIEF, + XBM_ALGORITHM, + XBM_HEURISTIC_MASK, + XBM_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid XBM image specifications. */ + +static struct image_keyword xbm_format[XBM_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 0}, + {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":foreground", IMAGE_STRING_VALUE, 0}, + {":background", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type XBM. */ + +static struct image_type xbm_type = +{ + &Qxbm, + xbm_image_p, + xbm_load, + x_clear_image, + NULL +}; + +/* Tokens returned from xbm_scan. */ + +enum xbm_token +{ + XBM_TK_IDENT = 256, + XBM_TK_NUMBER +}; + + +/* Return non-zero if OBJECT is a valid XBM-type image specification. + A valid specification is a list starting with the symbol `image' + The rest of the list is a property list which must contain an + entry `:type xbm.. + + If the specification specifies a file to load, it must contain + an entry `:file FILENAME' where FILENAME is a string. + + If the specification is for a bitmap loaded from memory it must + contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where + WIDTH and HEIGHT are integers > 0. DATA may be: + + 1. a string large enough to hold the bitmap data, i.e. it must + have a size >= (WIDTH + 7) / 8 * HEIGHT + + 2. a bool-vector of size >= WIDTH * HEIGHT + + 3. a vector of strings or bool-vectors, one for each line of the + bitmap. + + Both the file and data forms may contain the additional entries + `:background COLOR' and `:foreground COLOR'. If not present, + foreground and background of the frame on which the image is + displayed, is used. */ + +static int +xbm_image_p (object) + Lisp_Object object; +{ + struct image_keyword kw[XBM_LAST]; + + bcopy (xbm_format, kw, sizeof kw); + if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) + return 0; + + xassert (EQ (kw[XBM_TYPE].value, Qxbm)); + + if (kw[XBM_FILE].count) + { + if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count) + return 0; + } + else + { + Lisp_Object data; + int width, height; + + /* Entries for `:width', `:height' and `:data' must be present. */ + if (!kw[XBM_WIDTH].count + || !kw[XBM_HEIGHT].count + || !kw[XBM_DATA].count) + return 0; + + data = kw[XBM_DATA].value; + width = XFASTINT (kw[XBM_WIDTH].value); + height = XFASTINT (kw[XBM_HEIGHT].value); + + /* Check type of data, and width and height against contents of + data. */ + if (VECTORP (data)) + { + int i; + + /* Number of elements of the vector must be >= height. */ + if (XVECTOR (data)->size < height) + return 0; + + /* Each string or bool-vector in data must be large enough + for one line of the image. */ + for (i = 0; i < height; ++i) + { + Lisp_Object elt = XVECTOR (data)->contents[i]; + + if (STRINGP (elt)) + { + if (XSTRING (elt)->size + < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR) + return 0; + } + else if (BOOL_VECTOR_P (elt)) + { + if (XBOOL_VECTOR (elt)->size < width) + return 0; + } + else + return 0; + } + } + else if (STRINGP (data)) + { + if (XSTRING (data)->size + < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height) + return 0; + } + else if (BOOL_VECTOR_P (data)) + { + if (XBOOL_VECTOR (data)->size < width * height) + return 0; + } + else + return 0; + } + + /* Baseline must be a value between 0 and 100 (a percentage). */ + if (kw[XBM_ASCENT].count + && XFASTINT (kw[XBM_ASCENT].value) > 100) + return 0; + + return 1; +} + + +/* Scan a bitmap file. FP is the stream to read from. Value is + either an enumerator from enum xbm_token, or a character for a + single-character token, or 0 at end of file. If scanning an + identifier, store the lexeme of the identifier in SVAL. If + scanning a number, store its value in *IVAL. */ + +static int +xbm_scan (fp, sval, ival) + FILE *fp; + char *sval; + int *ival; +{ + int c; + + /* Skip white space. */ + while ((c = fgetc (fp)) != EOF && isspace (c)) + ; + + if (c == EOF) + c = 0; + else if (isdigit (c)) + { + int value = 0, digit; + + if (c == '0') + { + c = fgetc (fp); + if (c == 'x' || c == 'X') + { + while ((c = fgetc (fp)) != EOF) + { + if (isdigit (c)) + digit = c - '0'; + else if (c >= 'a' && c <= 'f') + digit = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + digit = c - 'A' + 10; + else + break; + value = 16 * value + digit; + } + } + else if (isdigit (c)) + { + value = c - '0'; + while ((c = fgetc (fp)) != EOF + && isdigit (c)) + value = 8 * value + c - '0'; + } + } + else + { + value = c - '0'; + while ((c = fgetc (fp)) != EOF + && isdigit (c)) + value = 10 * value + c - '0'; + } + + if (c != EOF) + ungetc (c, fp); + *ival = value; + c = XBM_TK_NUMBER; + } + else if (isalpha (c) || c == '_') + { + *sval++ = c; + while ((c = fgetc (fp)) != EOF + && (isalnum (c) || c == '_')) + *sval++ = c; + *sval = 0; + if (c != EOF) + ungetc (c, fp); + c = XBM_TK_IDENT; + } + + return c; +} + + +/* Replacement for XReadBitmapFileData which isn't available under old + X versions. FILE is the name of the bitmap file to read. Set + *WIDTH and *HEIGHT to the width and height of the image. Return in + *DATA the bitmap data allocated with xmalloc. Value is non-zero if + successful. */ + +static int +xbm_read_bitmap_file_data (file, width, height, data) + char *file; + int *width, *height; + unsigned char **data; +{ + FILE *fp; + char buffer[BUFSIZ]; + int padding_p = 0; + int v10 = 0; + int bytes_per_line, i, nbytes; + unsigned char *p; + int value; + int LA1; + +#define match() \ + LA1 = xbm_scan (fp, buffer, &value) + +#define expect(TOKEN) \ + if (LA1 != (TOKEN)) \ + goto failure; \ + else \ + match () + +#define expect_ident(IDENT) \ + if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ + match (); \ + else \ + goto failure + + fp = fopen (file, "r"); + if (fp == NULL) + return 0; + + *width = *height = -1; + *data = NULL; + LA1 = xbm_scan (fp, buffer, &value); + + /* Parse defines for width, height and hot-spots. */ + while (LA1 == '#') + { + match (); + expect_ident ("define"); + expect (XBM_TK_IDENT); + + if (LA1 == XBM_TK_NUMBER); + { + char *p = strrchr (buffer, '_'); + p = p ? p + 1 : buffer; + if (strcmp (p, "width") == 0) + *width = value; + else if (strcmp (p, "height") == 0) + *height = value; + } + expect (XBM_TK_NUMBER); + } + + if (*width < 0 || *height < 0) + goto failure; + + /* Parse bits. Must start with `static'. */ + expect_ident ("static"); + if (LA1 == XBM_TK_IDENT) + { + if (strcmp (buffer, "unsigned") == 0) + { + match (); + expect_ident ("char"); + } + else if (strcmp (buffer, "short") == 0) + { + match (); + v10 = 1; + if (*width % 16 && *width % 16 < 9) + padding_p = 1; + } + else if (strcmp (buffer, "char") == 0) + match (); + else + goto failure; + } + else + goto failure; + + expect (XBM_TK_IDENT); + expect ('['); + expect (']'); + expect ('='); + expect ('{'); + + bytes_per_line = (*width + 7) / 8 + padding_p; + nbytes = bytes_per_line * *height; + p = *data = (char *) xmalloc (nbytes); + + if (v10) + { + + for (i = 0; i < nbytes; i += 2) + { + int val = value; + expect (XBM_TK_NUMBER); + + *p++ = val; + if (!padding_p || ((i + 2) % bytes_per_line)) + *p++ = value >> 8; + + if (LA1 == ',' || LA1 == '}') + match (); + else + goto failure; + } + } + else + { + for (i = 0; i < nbytes; ++i) + { + int val = value; + expect (XBM_TK_NUMBER); + + *p++ = val; + + if (LA1 == ',' || LA1 == '}') + match (); + else + goto failure; + } + } + + fclose (fp); + return 1; + + failure: + + fclose (fp); + if (*data) + { + xfree (*data); + *data = NULL; + } + return 0; + +#undef match +#undef expect +#undef expect_ident +} + + +/* Load XBM image IMG which will be displayed on frame F from file + SPECIFIED_FILE. Value is non-zero if successful. */ + +static int +xbm_load_image_from_file (f, img, specified_file) + struct frame *f; + struct image *img; + Lisp_Object specified_file; +{ + int rc; + unsigned char *data; + int success_p = 0; + Lisp_Object file; + struct gcpro gcpro1; + + xassert (STRINGP (specified_file)); + file = Qnil; + GCPRO1 (file); + + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width, + &img->height, &data); + if (rc) + { + int depth = one_mac_display_info.n_cbits; + unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); + unsigned long background = FRAME_BACKGROUND_PIXEL (f); + Lisp_Object value; + + xassert (img->width > 0 && img->height > 0); + + /* Get foreground and background colors, maybe allocate colors. */ + value = image_spec_value (img->spec, QCforeground, NULL); + if (!NILP (value)) + foreground = x_alloc_image_color (f, img, value, foreground); + + value = image_spec_value (img->spec, QCbackground, NULL); + if (!NILP (value)) + background = x_alloc_image_color (f, img, value, background); + +#if 0 /* MAC_TODO : Port image display to Mac */ + BLOCK_INPUT; + img->pixmap + = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f), + FRAME_W32_WINDOW (f), + data, + img->width, img->height, + foreground, background, + depth); + xfree (data); + + if (img->pixmap == 0) + { + x_clear_image (f, img); + image_error ("Unable to create X pixmap for `%s'", file, Qnil); + } + else + success_p = 1; + + UNBLOCK_INPUT; +#endif + } + else + image_error ("Error loading XBM image `%s'", img->spec, Qnil); + + UNGCPRO; + return success_p; +} + + +/* Fill image IMG which is used on frame F with pixmap data. Value is + non-zero if successful. */ + +static int +xbm_load (f, img) + struct frame *f; + struct image *img; +{ + int success_p = 0; + Lisp_Object file_name; + + xassert (xbm_image_p (img->spec)); + + /* If IMG->spec specifies a file name, create a non-file spec from it. */ + file_name = image_spec_value (img->spec, QCfile, NULL); + if (STRINGP (file_name)) + success_p = xbm_load_image_from_file (f, img, file_name); + else + { + struct image_keyword fmt[XBM_LAST]; + Lisp_Object data; + int depth; + unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); + unsigned long background = FRAME_BACKGROUND_PIXEL (f); + char *bits; + int parsed_p; + + /* Parse the list specification. */ + bcopy (xbm_format, fmt, sizeof fmt); + parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm); + xassert (parsed_p); + + /* Get specified width, and height. */ + img->width = XFASTINT (fmt[XBM_WIDTH].value); + img->height = XFASTINT (fmt[XBM_HEIGHT].value); + xassert (img->width > 0 && img->height > 0); + + BLOCK_INPUT; + + if (fmt[XBM_ASCENT].count) + img->ascent = XFASTINT (fmt[XBM_ASCENT].value); + + /* Get foreground and background colors, maybe allocate colors. */ + if (fmt[XBM_FOREGROUND].count) + foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value, + foreground); + if (fmt[XBM_BACKGROUND].count) + background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, + background); + + /* Set bits to the bitmap image data. */ + data = fmt[XBM_DATA].value; + if (VECTORP (data)) + { + int i; + char *p; + int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; + + p = bits = (char *) alloca (nbytes * img->height); + for (i = 0; i < img->height; ++i, p += nbytes) + { + Lisp_Object line = XVECTOR (data)->contents[i]; + if (STRINGP (line)) + bcopy (XSTRING (line)->data, p, nbytes); + else + bcopy (XBOOL_VECTOR (line)->data, p, nbytes); + } + } + else if (STRINGP (data)) + bits = XSTRING (data)->data; + else + bits = XBOOL_VECTOR (data)->data; + +#if 0 /* MAC_TODO : port Mac display code */ + /* Create the pixmap. */ + depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); + img->pixmap + = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f), + FRAME_W32_WINDOW (f), + bits, + img->width, img->height, + foreground, background, + depth); +#endif /* MAC_TODO */ + + if (img->pixmap) + success_p = 1; + else + { + image_error ("Unable to create pixmap for XBM image `%s'", + img->spec, Qnil); + x_clear_image (f, img); + } + + UNBLOCK_INPUT; + } + + return success_p; +} + + + +/*********************************************************************** + XPM images + ***********************************************************************/ + +#if HAVE_XPM + +static int xpm_image_p P_ ((Lisp_Object object)); +static int xpm_load P_ ((struct frame *f, struct image *img)); +static int xpm_valid_color_symbols_p P_ ((Lisp_Object)); + +#include "X11/xpm.h" + +/* The symbol `xpm' identifying XPM-format images. */ + +Lisp_Object Qxpm; + +/* Indices of image specification fields in xpm_format, below. */ + +enum xpm_keyword_index +{ + XPM_TYPE, + XPM_FILE, + XPM_DATA, + XPM_ASCENT, + XPM_MARGIN, + XPM_RELIEF, + XPM_ALGORITHM, + XPM_HEURISTIC_MASK, + XPM_COLOR_SYMBOLS, + XPM_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid XPM image specifications. */ + +static struct image_keyword xpm_format[XPM_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 0}, + {":data", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type XBM. */ + +static struct image_type xpm_type = +{ + &Qxpm, + xpm_image_p, + xpm_load, + x_clear_image, + NULL +}; + + +/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list + for XPM images. Such a list must consist of conses whose car and + cdr are strings. */ + +static int +xpm_valid_color_symbols_p (color_symbols) + Lisp_Object color_symbols; +{ + while (CONSP (color_symbols)) + { + Lisp_Object sym = XCAR (color_symbols); + if (!CONSP (sym) + || !STRINGP (XCAR (sym)) + || !STRINGP (XCDR (sym))) + break; + color_symbols = XCDR (color_symbols); + } + + return NILP (color_symbols); +} + + +/* Value is non-zero if OBJECT is a valid XPM image specification. */ + +static int +xpm_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[XPM_LAST]; + bcopy (xpm_format, fmt, sizeof fmt); + return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) + /* Either `:file' or `:data' must be present. */ + && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 + /* Either no `:color-symbols' or it's a list of conses + whose car and cdr are strings. */ + && (fmt[XPM_COLOR_SYMBOLS].count == 0 + || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)) + && (fmt[XPM_ASCENT].count == 0 + || XFASTINT (fmt[XPM_ASCENT].value) < 100)); +} + + +/* Load image IMG which will be displayed on frame F. Value is + non-zero if successful. */ + +static int +xpm_load (f, img) + struct frame *f; + struct image *img; +{ + int rc, i; + XpmAttributes attrs; + Lisp_Object specified_file, color_symbols; + + /* Configure the XPM lib. Use the visual of frame F. Allocate + close colors. Return colors allocated. */ + bzero (&attrs, sizeof attrs); + attrs.visual = FRAME_X_VISUAL (f); + attrs.colormap = FRAME_X_COLORMAP (f); + attrs.valuemask |= XpmVisual; + attrs.valuemask |= XpmColormap; + attrs.valuemask |= XpmReturnAllocPixels; +#ifdef XpmAllocCloseColors + attrs.alloc_close_colors = 1; + attrs.valuemask |= XpmAllocCloseColors; +#else + attrs.closeness = 600; + attrs.valuemask |= XpmCloseness; +#endif + + /* If image specification contains symbolic color definitions, add + these to `attrs'. */ + color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); + if (CONSP (color_symbols)) + { + Lisp_Object tail; + XpmColorSymbol *xpm_syms; + int i, size; + + attrs.valuemask |= XpmColorSymbols; + + /* Count number of symbols. */ + attrs.numsymbols = 0; + for (tail = color_symbols; CONSP (tail); tail = XCDR (tail)) + ++attrs.numsymbols; + + /* Allocate an XpmColorSymbol array. */ + size = attrs.numsymbols * sizeof *xpm_syms; + xpm_syms = (XpmColorSymbol *) alloca (size); + bzero (xpm_syms, size); + attrs.colorsymbols = xpm_syms; + + /* Fill the color symbol array. */ + for (tail = color_symbols, i = 0; + CONSP (tail); + ++i, tail = XCDR (tail)) + { + Lisp_Object name = XCAR (XCAR (tail)); + Lisp_Object color = XCDR (XCAR (tail)); + xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1); + strcpy (xpm_syms[i].name, XSTRING (name)->data); + xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1); + strcpy (xpm_syms[i].value, XSTRING (color)->data); + } + } + + /* Create a pixmap for the image, either from a file, or from a + string buffer containing data in the same format as an XPM file. */ + BLOCK_INPUT; + specified_file = image_spec_value (img->spec, QCfile, NULL); + if (STRINGP (specified_file)) + { + Lisp_Object file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNBLOCK_INPUT; + return 0; + } + + rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f), + XSTRING (file)->data, &img->pixmap, &img->mask, + &attrs); + } + else + { + Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL); + rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f), + XSTRING (buffer)->data, + &img->pixmap, &img->mask, + &attrs); + } + UNBLOCK_INPUT; + + if (rc == XpmSuccess) + { + /* Remember allocated colors. */ + img->ncolors = attrs.nalloc_pixels; + img->colors = (unsigned long *) xmalloc (img->ncolors + * sizeof *img->colors); + for (i = 0; i < attrs.nalloc_pixels; ++i) + img->colors[i] = attrs.alloc_pixels[i]; + + img->width = attrs.width; + img->height = attrs.height; + xassert (img->width > 0 && img->height > 0); + + /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */ + BLOCK_INPUT; + XpmFreeAttributes (&attrs); + UNBLOCK_INPUT; + } + else + { + switch (rc) + { + case XpmOpenFailed: + image_error ("Error opening XPM file (%s)", img->spec, Qnil); + break; + + case XpmFileInvalid: + image_error ("Invalid XPM file (%s)", img->spec, Qnil); + break; + + case XpmNoMemory: + image_error ("Out of memory (%s)", img->spec, Qnil); + break; + + case XpmColorFailed: + image_error ("Color allocation error (%s)", img->spec, Qnil); + break; + + default: + image_error ("Unknown error (%s)", img->spec, Qnil); + break; + } + } + + return rc == XpmSuccess; +} + +#endif /* HAVE_XPM != 0 */ + + +#if 0 /* MAC_TODO : Color tables on Mac. */ +/*********************************************************************** + Color table + ***********************************************************************/ + +/* An entry in the color table mapping an RGB color to a pixel color. */ + +struct ct_color +{ + int r, g, b; + unsigned long pixel; + + /* Next in color table collision list. */ + struct ct_color *next; +}; + +/* The bucket vector size to use. Must be prime. */ + +#define CT_SIZE 101 + +/* Value is a hash of the RGB color given by R, G, and B. */ + +#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B)) + +/* The color hash table. */ + +struct ct_color **ct_table; + +/* Number of entries in the color table. */ + +int ct_colors_allocated; + +/* Function prototypes. */ + +static void init_color_table P_ ((void)); +static void free_color_table P_ ((void)); +static unsigned long *colors_in_color_table P_ ((int *n)); +static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); +static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); + + +/* Initialize the color table. */ + +static void +init_color_table () +{ + int size = CT_SIZE * sizeof (*ct_table); + ct_table = (struct ct_color **) xmalloc (size); + bzero (ct_table, size); + ct_colors_allocated = 0; +} + + +/* Free memory associated with the color table. */ + +static void +free_color_table () +{ + int i; + struct ct_color *p, *next; + + for (i = 0; i < CT_SIZE; ++i) + for (p = ct_table[i]; p; p = next) + { + next = p->next; + xfree (p); + } + + xfree (ct_table); + ct_table = NULL; +} + + +/* Value is a pixel color for RGB color R, G, B on frame F. If an + entry for that color already is in the color table, return the + pixel color of that entry. Otherwise, allocate a new color for R, + G, B, and make an entry in the color table. */ + +static unsigned long +lookup_rgb_color (f, r, g, b) + struct frame *f; + int r, g, b; +{ + unsigned hash = CT_HASH_RGB (r, g, b); + int i = hash % CT_SIZE; + struct ct_color *p; + + for (p = ct_table[i]; p; p = p->next) + if (p->r == r && p->g == g && p->b == b) + break; + + if (p == NULL) + { + COLORREF color; + Colormap cmap; + int rc; + + color = RGB_TO_ULONG (r, g, b); + + ++ct_colors_allocated; + + p = (struct ct_color *) xmalloc (sizeof *p); + p->r = r; + p->g = g; + p->b = b; + p->pixel = color; + p->next = ct_table[i]; + ct_table[i] = p; + } + + return p->pixel; +} + + +/* Look up pixel color PIXEL which is used on frame F in the color + table. If not already present, allocate it. Value is PIXEL. */ + +static unsigned long +lookup_pixel_color (f, pixel) + struct frame *f; + unsigned long pixel; +{ + int i = pixel % CT_SIZE; + struct ct_color *p; + + for (p = ct_table[i]; p; p = p->next) + if (p->pixel == pixel) + break; + + if (p == NULL) + { + XColor color; + Colormap cmap; + int rc; + + BLOCK_INPUT; + + cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); + color.pixel = pixel; + XQueryColor (NULL, cmap, &color); + rc = x_alloc_nearest_color (f, cmap, &color); + UNBLOCK_INPUT; + + if (rc) + { + ++ct_colors_allocated; + + p = (struct ct_color *) xmalloc (sizeof *p); + p->r = color.red; + p->g = color.green; + p->b = color.blue; + p->pixel = pixel; + p->next = ct_table[i]; + ct_table[i] = p; + } + else + return FRAME_FOREGROUND_PIXEL (f); + } + return p->pixel; +} + + +/* Value is a vector of all pixel colors contained in the color table, + allocated via xmalloc. Set *N to the number of colors. */ + +static unsigned long * +colors_in_color_table (n) + int *n; +{ + int i, j; + struct ct_color *p; + unsigned long *colors; + + if (ct_colors_allocated == 0) + { + *n = 0; + colors = NULL; + } + else + { + colors = (unsigned long *) xmalloc (ct_colors_allocated + * sizeof *colors); + *n = ct_colors_allocated; + + for (i = j = 0; i < CT_SIZE; ++i) + for (p = ct_table[i]; p; p = p->next) + colors[j++] = p->pixel; + } + + return colors; +} + +#endif /* MAC_TODO */ + + +/*********************************************************************** + Algorithms + ***********************************************************************/ + +#if 0 /* MAC_TODO : Mac versions of low level algorithms */ +static void x_laplace_write_row P_ ((struct frame *, long *, + int, XImage *, int)); +static void x_laplace_read_row P_ ((struct frame *, Colormap, + XColor *, int, XImage *, int)); + + +/* Fill COLORS with RGB colors from row Y of image XIMG. F is the + frame we operate on, CMAP is the color-map in effect, and WIDTH is + the width of one row in the image. */ + +static void +x_laplace_read_row (f, cmap, colors, width, ximg, y) + struct frame *f; + Colormap cmap; + XColor *colors; + int width; + XImage *ximg; + int y; +{ + int x; + + for (x = 0; x < width; ++x) + colors[x].pixel = XGetPixel (ximg, x, y); + + XQueryColors (NULL, cmap, colors, width); +} + + +/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs + containing the pixel colors to write. F is the frame we are + working on. */ + +static void +x_laplace_write_row (f, pixels, width, ximg, y) + struct frame *f; + long *pixels; + int width; + XImage *ximg; + int y; +{ + int x; + + for (x = 0; x < width; ++x) + XPutPixel (ximg, x, y, pixels[x]); +} +#endif + +/* Transform image IMG which is used on frame F with a Laplace + edge-detection algorithm. The result is an image that can be used + to draw disabled buttons, for example. */ + +static void +x_laplace (f, img) + struct frame *f; + struct image *img; +{ +#if 0 /* MAC_TODO : Mac version */ + Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); + XImage *ximg, *oimg; + XColor *in[3]; + long *out; + Pixmap pixmap; + int x, y, i; + long pixel; + int in_y, out_y, rc; + int mv2 = 45000; + + BLOCK_INPUT; + + /* Get the X image IMG->pixmap. */ + ximg = XGetImage (NULL, img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); + + /* Allocate 3 input rows, and one output row of colors. */ + for (i = 0; i < 3; ++i) + in[i] = (XColor *) alloca (img->width * sizeof (XColor)); + out = (long *) alloca (img->width * sizeof (long)); + + /* Create an X image for output. */ + rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0, + &oimg, &pixmap); + + /* Fill first two rows. */ + x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0); + x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1); + in_y = 2; + + /* Write first row, all zeros. */ + init_color_table (); + pixel = lookup_rgb_color (f, 0, 0, 0); + for (x = 0; x < img->width; ++x) + out[x] = pixel; + x_laplace_write_row (f, out, img->width, oimg, 0); + out_y = 1; + + for (y = 2; y < img->height; ++y) + { + int rowa = y % 3; + int rowb = (y + 2) % 3; + + x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++); + + for (x = 0; x < img->width - 2; ++x) + { + int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red; + int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green; + int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue; + + out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff, + b & 0xffff); + } + + x_laplace_write_row (f, out, img->width, oimg, out_y++); + } + + /* Write last line, all zeros. */ + for (x = 0; x < img->width; ++x) + out[x] = pixel; + x_laplace_write_row (f, out, img->width, oimg, out_y); + + /* Free the input image, and free resources of IMG. */ + XDestroyImage (ximg); + x_clear_image (f, img); + + /* Put the output image into pixmap, and destroy it. */ + x_put_x_image (f, oimg, pixmap, img->width, img->height); + x_destroy_x_image (oimg); + + /* Remember new pixmap and colors in IMG. */ + img->pixmap = pixmap; + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); + + UNBLOCK_INPUT; +#endif /* MAC_TODO */ +} + + +/* Build a mask for image IMG which is used on frame F. FILE is the + name of an image file, for error messages. HOW determines how to + determine the background color of IMG. If it is a list '(R G B)', + with R, G, and B being integers >= 0, take that as the color of the + background. Otherwise, determine the background color of IMG + heuristically. Value is non-zero if successful. */ + +static int +x_build_heuristic_mask (f, img, how) + struct frame *f; + struct image *img; + Lisp_Object how; +{ +#if 0 /* MAC_TODO : Mac version */ + Display *dpy = FRAME_W32_DISPLAY (f); + XImage *ximg, *mask_img; + int x, y, rc, look_at_corners_p; + unsigned long bg; + + BLOCK_INPUT; + + /* Create an image and pixmap serving as mask. */ + rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1, + &mask_img, &img->mask); + if (!rc) + { + UNBLOCK_INPUT; + return 0; + } + + /* Get the X image of IMG->pixmap. */ + ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height, + ~0, ZPixmap); + + /* Determine the background color of ximg. If HOW is `(R G B)' + take that as color. Otherwise, try to determine the color + heuristically. */ + look_at_corners_p = 1; + + if (CONSP (how)) + { + int rgb[3], i = 0; + + while (i < 3 + && CONSP (how) + && NATNUMP (XCAR (how))) + { + rgb[i] = XFASTINT (XCAR (how)) & 0xffff; + how = XCDR (how); + } + + if (i == 3 && NILP (how)) + { + char color_name[30]; + XColor exact, color; + Colormap cmap; + + sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]); + + cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); + if (XLookupColor (dpy, cmap, color_name, &exact, &color)) + { + bg = color.pixel; + look_at_corners_p = 0; + } + } + } + + if (look_at_corners_p) + { + unsigned long corners[4]; + int i, best_count; + + /* Get the colors at the corners of ximg. */ + corners[0] = XGetPixel (ximg, 0, 0); + corners[1] = XGetPixel (ximg, img->width - 1, 0); + corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1); + corners[3] = XGetPixel (ximg, 0, img->height - 1); + + /* Choose the most frequently found color as background. */ + for (i = best_count = 0; i < 4; ++i) + { + int j, n; + + for (j = n = 0; j < 4; ++j) + if (corners[i] == corners[j]) + ++n; + + if (n > best_count) + bg = corners[i], best_count = n; + } + } + + /* Set all bits in mask_img to 1 whose color in ximg is different + from the background color bg. */ + for (y = 0; y < img->height; ++y) + for (x = 0; x < img->width; ++x) + XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg); + + /* Put mask_img into img->mask. */ + x_put_x_image (f, mask_img, img->mask, img->width, img->height); + x_destroy_x_image (mask_img); + XDestroyImage (ximg); + + UNBLOCK_INPUT; +#endif /* MAC_TODO */ + + return 1; +} + + + +/*********************************************************************** + PBM (mono, gray, color) + ***********************************************************************/ +#ifdef HAVE_PBM + +static int pbm_image_p P_ ((Lisp_Object object)); +static int pbm_load P_ ((struct frame *f, struct image *img)); +static int pbm_scan_number P_ ((unsigned char **, unsigned char *)); + +/* The symbol `pbm' identifying images of this type. */ + +Lisp_Object Qpbm; + +/* Indices of image specification fields in gs_format, below. */ + +enum pbm_keyword_index +{ + PBM_TYPE, + PBM_FILE, + PBM_DATA, + PBM_ASCENT, + PBM_MARGIN, + PBM_RELIEF, + PBM_ALGORITHM, + PBM_HEURISTIC_MASK, + PBM_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword pbm_format[PBM_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 0}, + {":data", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type `pbm'. */ + +static struct image_type pbm_type = +{ + &Qpbm, + pbm_image_p, + pbm_load, + x_clear_image, + NULL +}; + + +/* Return non-zero if OBJECT is a valid PBM image specification. */ + +static int +pbm_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[PBM_LAST]; + + bcopy (pbm_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm) + || (fmt[PBM_ASCENT].count + && XFASTINT (fmt[PBM_ASCENT].value) > 100)) + return 0; + + /* Must specify either :data or :file. */ + return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1; +} + + +/* Scan a decimal number from *S and return it. Advance *S while + reading the number. END is the end of the string. Value is -1 at + end of input. */ + +static int +pbm_scan_number (s, end) + unsigned char **s, *end; +{ + int c, val = -1; + + while (*s < end) + { + /* Skip white-space. */ + while (*s < end && (c = *(*s)++, isspace (c))) + ; + + if (c == '#') + { + /* Skip comment to end of line. */ + while (*s < end && (c = *(*s)++, c != '\n')) + ; + } + else if (isdigit (c)) + { + /* Read decimal number. */ + val = c - '0'; + while (*s < end && (c = *(*s)++, isdigit (c))) + val = 10 * val + c - '0'; + break; + } + else + break; + } + + return val; +} + + +/* Read FILE into memory. Value is a pointer to a buffer allocated + with xmalloc holding FILE's contents. Value is null if an error + occured. *SIZE is set to the size of the file. */ + +static char * +pbm_read_file (file, size) + Lisp_Object file; + int *size; +{ + FILE *fp = NULL; + char *buf = NULL; + struct stat st; + + if (stat (XSTRING (file)->data, &st) == 0 + && (fp = fopen (XSTRING (file)->data, "r")) != NULL + && (buf = (char *) xmalloc (st.st_size), + fread (buf, 1, st.st_size, fp) == st.st_size)) + { + *size = st.st_size; + fclose (fp); + } + else + { + if (fp) + fclose (fp); + if (buf) + { + xfree (buf); + buf = NULL; + } + } + + return buf; +} + + +/* Load PBM image IMG for use on frame F. */ + +static int +pbm_load (f, img) + struct frame *f; + struct image *img; +{ + int raw_p, x, y; + int width, height, max_color_idx = 0; + XImage *ximg; + Lisp_Object file, specified_file; + enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; + struct gcpro gcpro1; + unsigned char *contents = NULL; + unsigned char *end, *p; + int size; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + file = Qnil; + GCPRO1 (file); + + if (STRINGP (specified_file)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + contents = pbm_read_file (file, &size); + if (contents == NULL) + { + image_error ("Error reading `%s'", file, Qnil); + UNGCPRO; + return 0; + } + + p = contents; + end = contents + size; + } + else + { + Lisp_Object data; + data = image_spec_value (img->spec, QCdata, NULL); + p = XSTRING (data)->data; + end = p + STRING_BYTES (XSTRING (data)); + } + + /* Check magic number. */ + if (end - p < 2 || *p++ != 'P') + { + image_error ("Not a PBM image: `%s'", img->spec, Qnil); + error: + xfree (contents); + UNGCPRO; + return 0; + } + + switch (*p++) + { + case '1': + raw_p = 0, type = PBM_MONO; + break; + + case '2': + raw_p = 0, type = PBM_GRAY; + break; + + case '3': + raw_p = 0, type = PBM_COLOR; + break; + + case '4': + raw_p = 1, type = PBM_MONO; + break; + + case '5': + raw_p = 1, type = PBM_GRAY; + break; + + case '6': + raw_p = 1, type = PBM_COLOR; + break; + + default: + image_error ("Not a PBM image: `%s'", img->spec, Qnil); + goto error; + } + + /* Read width, height, maximum color-component. Characters + starting with `#' up to the end of a line are ignored. */ + width = pbm_scan_number (&p, end); + height = pbm_scan_number (&p, end); + + if (type != PBM_MONO) + { + max_color_idx = pbm_scan_number (&p, end); + if (raw_p && max_color_idx > 255) + max_color_idx = 255; + } + + if (width < 0 + || height < 0 + || (type != PBM_MONO && max_color_idx < 0)) + goto error; + + BLOCK_INPUT; + if (!x_create_x_image_and_pixmap (f, width, height, 0, + &ximg, &img->pixmap)) + { + UNBLOCK_INPUT; + goto error; + } + + /* Initialize the color hash table. */ + init_color_table (); + + if (type == PBM_MONO) + { + int c = 0, g; + + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) + { + if (raw_p) + { + if ((x & 7) == 0) + c = *p++; + g = c & 0x80; + c <<= 1; + } + else + g = pbm_scan_number (&p, end); + + XPutPixel (ximg, x, y, (g + ? FRAME_FOREGROUND_PIXEL (f) + : FRAME_BACKGROUND_PIXEL (f))); + } + } + else + { + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) + { + int r, g, b; + + if (type == PBM_GRAY) + r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end); + else if (raw_p) + { + r = *p++; + g = *p++; + b = *p++; + } + else + { + r = pbm_scan_number (&p, end); + g = pbm_scan_number (&p, end); + b = pbm_scan_number (&p, end); + } + + if (r < 0 || g < 0 || b < 0) + { + xfree (ximg->data); + ximg->data = NULL; + XDestroyImage (ximg); + UNBLOCK_INPUT; + image_error ("Invalid pixel value in image `%s'", + img->spec, Qnil); + goto error; + } + + /* RGB values are now in the range 0..max_color_idx. + Scale this to the range 0..0xffff supported by X. */ + r = (double) r * 65535 / max_color_idx; + g = (double) g * 65535 / max_color_idx; + b = (double) b * 65535 / max_color_idx; + XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); + } + } + + /* Store in IMG->colors the colors allocated for the image, and + free the color table. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); + + /* Put the image into a pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + UNBLOCK_INPUT; + + img->width = width; + img->height = height; + + UNGCPRO; + xfree (contents); + return 1; +} +#endif /* HAVE_PBM */ + + +/*********************************************************************** + PNG + ***********************************************************************/ + +#if HAVE_PNG + +#include + +/* Function prototypes. */ + +static int png_image_p P_ ((Lisp_Object object)); +static int png_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `png' identifying images of this type. */ + +Lisp_Object Qpng; + +/* Indices of image specification fields in png_format, below. */ + +enum png_keyword_index +{ + PNG_TYPE, + PNG_DATA, + PNG_FILE, + PNG_ASCENT, + PNG_MARGIN, + PNG_RELIEF, + PNG_ALGORITHM, + PNG_HEURISTIC_MASK, + PNG_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword png_format[PNG_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type `png'. */ + +static struct image_type png_type = +{ + &Qpng, + png_image_p, + png_load, + x_clear_image, + NULL +}; + + +/* Return non-zero if OBJECT is a valid PNG image specification. */ + +static int +png_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[PNG_LAST]; + bcopy (png_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, PNG_LAST, Qpng) + || (fmt[PNG_ASCENT].count + && XFASTINT (fmt[PNG_ASCENT].value) > 100)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1; +} + + +/* Error and warning handlers installed when the PNG library + is initialized. */ + +static void +my_png_error (png_ptr, msg) + png_struct *png_ptr; + char *msg; +{ + xassert (png_ptr != NULL); + image_error ("PNG error: %s", build_string (msg), Qnil); + longjmp (png_ptr->jmpbuf, 1); +} + + +static void +my_png_warning (png_ptr, msg) + png_struct *png_ptr; + char *msg; +{ + xassert (png_ptr != NULL); + image_error ("PNG warning: %s", build_string (msg), Qnil); +} + +/* Memory source for PNG decoding. */ + +struct png_memory_storage +{ + unsigned char *bytes; /* The data */ + size_t len; /* How big is it? */ + int index; /* Where are we? */ +}; + + +/* Function set as reader function when reading PNG image from memory. + PNG_PTR is a pointer to the PNG control structure. Copy LENGTH + bytes from the input to DATA. */ + +static void +png_read_from_memory (png_ptr, data, length) + png_structp png_ptr; + png_bytep data; + png_size_t length; +{ + struct png_memory_storage *tbr + = (struct png_memory_storage *) png_get_io_ptr (png_ptr); + + if (length > tbr->len - tbr->index) + png_error (png_ptr, "Read error"); + + bcopy (tbr->bytes + tbr->index, data, length); + tbr->index = tbr->index + length; +} + +/* Load PNG image IMG for use on frame F. Value is non-zero if + successful. */ + +static int +png_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data; + int x, y, i; + XImage *ximg, *mask_img = NULL; + struct gcpro gcpro1; + png_struct *png_ptr = NULL; + png_info *info_ptr = NULL, *end_info = NULL; + FILE *fp = NULL; + png_byte sig[8]; + png_byte *pixels = NULL; + png_byte **rows = NULL; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + png_byte channels; + png_uint_32 row_bytes; + int transparent_p; + char *gamma_str; + double screen_gamma, image_gamma; + int intent; + struct png_memory_storage tbr; /* Data to be read */ + + /* Find out what file to load. */ + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + /* Open the image file. */ + fp = fopen (XSTRING (file)->data, "rb"); + if (!fp) + { + image_error ("Cannot open image file `%s'", file, Qnil); + UNGCPRO; + fclose (fp); + return 0; + } + + /* Check PNG signature. */ + if (fread (sig, 1, sizeof sig, fp) != sizeof sig + || !png_check_sig (sig, sizeof sig)) + { + image_error ("Not a PNG file:` %s'", file, Qnil); + UNGCPRO; + fclose (fp); + return 0; + } + } + else + { + /* Read from memory. */ + tbr.bytes = XSTRING (specified_data)->data; + tbr.len = STRING_BYTES (XSTRING (specified_data)); + tbr.index = 0; + + /* Check PNG signature. */ + if (tbr.len < sizeof sig + || !png_check_sig (tbr.bytes, sizeof sig)) + { + image_error ("Not a PNG image: `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + + /* Need to skip past the signature. */ + tbr.bytes += sizeof (sig); + } + + /* Initialize read and info structs for PNG lib. */ + png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, + my_png_error, my_png_warning); + if (!png_ptr) + { + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + png_destroy_read_struct (&png_ptr, NULL, NULL); + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + end_info = png_create_info_struct (png_ptr); + if (!end_info) + { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + /* Set error jump-back. We come back here when the PNG library + detects an error. */ + if (setjmp (png_ptr->jmpbuf)) + { + error: + if (png_ptr) + png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + xfree (pixels); + xfree (rows); + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + /* Read image info. */ + if (!NILP (specified_data)) + png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory); + else + png_init_io (png_ptr, fp); + + png_set_sig_bytes (png_ptr, sizeof sig); + png_read_info (png_ptr, info_ptr); + png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, NULL, NULL); + + /* If image contains simply transparency data, we prefer to + construct a clipping mask. */ + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + transparent_p = 1; + else + transparent_p = 0; + + /* This function is easier to write if we only have to handle + one data format: RGB or RGBA with 8 bits per channel. Let's + transform other formats into that format. */ + + /* Strip more than 8 bits per channel. */ + if (bit_depth == 16) + png_set_strip_16 (png_ptr); + + /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel + if available. */ + png_set_expand (png_ptr); + + /* Convert grayscale images to RGB. */ + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (png_ptr); + + /* The value 2.2 is a guess for PC monitors from PNG example.c. */ + gamma_str = getenv ("SCREEN_GAMMA"); + screen_gamma = gamma_str ? atof (gamma_str) : 2.2; + + /* Tell the PNG lib to handle gamma correction for us. */ + +#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED) + if (png_get_sRGB (png_ptr, info_ptr, &intent)) + /* There is a special chunk in the image specifying the gamma. */ + png_set_sRGB (png_ptr, info_ptr, intent); + else +#endif + if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) + /* Image contains gamma information. */ + png_set_gamma (png_ptr, screen_gamma, image_gamma); + else + /* Use a default of 0.5 for the image gamma. */ + png_set_gamma (png_ptr, screen_gamma, 0.5); + + /* Handle alpha channel by combining the image with a background + color. Do this only if a real alpha channel is supplied. For + simple transparency, we prefer a clipping mask. */ + if (!transparent_p) + { + png_color_16 *image_background; + + if (png_get_bKGD (png_ptr, info_ptr, &image_background)) + /* Image contains a background color with which to + combine the image. */ + png_set_background (png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + { + /* Image does not contain a background color with which + to combine the image data via an alpha channel. Use + the frame's background instead. */ + XColor color; + Colormap cmap; + png_color_16 frame_background; + + BLOCK_INPUT; + cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); + color.pixel = FRAME_BACKGROUND_PIXEL (f); + XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color); + UNBLOCK_INPUT; + + bzero (&frame_background, sizeof frame_background); + frame_background.red = color.red; + frame_background.green = color.green; + frame_background.blue = color.blue; + + png_set_background (png_ptr, &frame_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + } + + /* Update info structure. */ + png_read_update_info (png_ptr, info_ptr); + + /* Get number of channels. Valid values are 1 for grayscale images + and images with a palette, 2 for grayscale images with transparency + information (alpha channel), 3 for RGB images, and 4 for RGB + images with alpha channel, i.e. RGBA. If conversions above were + sufficient we should only have 3 or 4 channels here. */ + channels = png_get_channels (png_ptr, info_ptr); + xassert (channels == 3 || channels == 4); + + /* Number of bytes needed for one row of the image. */ + row_bytes = png_get_rowbytes (png_ptr, info_ptr); + + /* Allocate memory for the image. */ + pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels); + rows = (png_byte **) xmalloc (height * sizeof *rows); + for (i = 0; i < height; ++i) + rows[i] = pixels + i * row_bytes; + + /* Read the entire image. */ + png_read_image (png_ptr, rows); + png_read_end (png_ptr, info_ptr); + if (fp) + { + fclose (fp); + fp = NULL; + } + + BLOCK_INPUT; + + /* Create the X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, + &img->pixmap)) + { + UNBLOCK_INPUT; + goto error; + } + + /* Create an image and pixmap serving as mask if the PNG image + contains an alpha channel. */ + if (channels == 4 + && !transparent_p + && !x_create_x_image_and_pixmap (f, width, height, 1, + &mask_img, &img->mask)) + { + x_destroy_x_image (ximg); + XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap); + img->pixmap = 0; + UNBLOCK_INPUT; + goto error; + } + + /* Fill the X image and mask from PNG data. */ + init_color_table (); + + for (y = 0; y < height; ++y) + { + png_byte *p = rows[y]; + + for (x = 0; x < width; ++x) + { + unsigned r, g, b; + + r = *p++ << 8; + g = *p++ << 8; + b = *p++ << 8; + XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); + + /* An alpha channel, aka mask channel, associates variable + transparency with an image. Where other image formats + support binary transparency---fully transparent or fully + opaque---PNG allows up to 254 levels of partial transparency. + The PNG library implements partial transparency by combining + the image with a specified background color. + + I'm not sure how to handle this here nicely: because the + background on which the image is displayed may change, for + real alpha channel support, it would be necessary to create + a new image for each possible background. + + What I'm doing now is that a mask is created if we have + boolean transparency information. Otherwise I'm using + the frame's background color to combine the image with. */ + + if (channels == 4) + { + if (mask_img) + XPutPixel (mask_img, x, y, *p > 0); + ++p; + } + } + } + + /* Remember colors allocated for this image. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); + + /* Clean up. */ + png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + xfree (rows); + xfree (pixels); + + img->width = width; + img->height = height; + + /* Put the image into the pixmap, then free the X image and its buffer. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + + /* Same for the mask. */ + if (mask_img) + { + x_put_x_image (f, mask_img, img->mask, img->width, img->height); + x_destroy_x_image (mask_img); + } + + UNBLOCK_INPUT; + UNGCPRO; + return 1; +} + +#endif /* HAVE_PNG != 0 */ + + + +/*********************************************************************** + JPEG + ***********************************************************************/ + +#if HAVE_JPEG + +/* Work around a warning about HAVE_STDLIB_H being redefined in + jconfig.h. */ +#ifdef HAVE_STDLIB_H +#define HAVE_STDLIB_H_1 +#undef HAVE_STDLIB_H +#endif /* HAVE_STLIB_H */ + +#include +#include +#include + +#ifdef HAVE_STLIB_H_1 +#define HAVE_STDLIB_H 1 +#endif + +static int jpeg_image_p P_ ((Lisp_Object object)); +static int jpeg_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `jpeg' identifying images of this type. */ + +Lisp_Object Qjpeg; + +/* Indices of image specification fields in gs_format, below. */ + +enum jpeg_keyword_index +{ + JPEG_TYPE, + JPEG_DATA, + JPEG_FILE, + JPEG_ASCENT, + JPEG_MARGIN, + JPEG_RELIEF, + JPEG_ALGORITHM, + JPEG_HEURISTIC_MASK, + JPEG_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword jpeg_format[JPEG_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type `jpeg'. */ + +static struct image_type jpeg_type = +{ + &Qjpeg, + jpeg_image_p, + jpeg_load, + x_clear_image, + NULL +}; + + +/* Return non-zero if OBJECT is a valid JPEG image specification. */ + +static int +jpeg_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[JPEG_LAST]; + + bcopy (jpeg_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg) + || (fmt[JPEG_ASCENT].count + && XFASTINT (fmt[JPEG_ASCENT].value) > 100)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1; +} + + +struct my_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +static void +my_error_exit (cinfo) + j_common_ptr cinfo; +{ + struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err; + longjmp (mgr->setjmp_buffer, 1); +} + +/* Init source method for JPEG data source manager. Called by + jpeg_read_header() before any data is actually read. See + libjpeg.doc from the JPEG lib distribution. */ + +static void +our_init_source (cinfo) + j_decompress_ptr cinfo; +{ +} + + +/* Fill input buffer method for JPEG data source manager. Called + whenever more data is needed. We read the whole image in one step, + so this only adds a fake end of input marker at the end. */ + +static boolean +our_fill_input_buffer (cinfo) + j_decompress_ptr cinfo; +{ + /* Insert a fake EOI marker. */ + struct jpeg_source_mgr *src = cinfo->src; + static JOCTET buffer[2]; + + buffer[0] = (JOCTET) 0xFF; + buffer[1] = (JOCTET) JPEG_EOI; + + src->next_input_byte = buffer; + src->bytes_in_buffer = 2; + return TRUE; +} + + +/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src + is the JPEG data source manager. */ + +static void +our_skip_input_data (cinfo, num_bytes) + j_decompress_ptr cinfo; + long num_bytes; +{ + struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src; + + if (src) + { + if (num_bytes > src->bytes_in_buffer) + ERREXIT (cinfo, JERR_INPUT_EOF); + + src->bytes_in_buffer -= num_bytes; + src->next_input_byte += num_bytes; + } +} + + +/* Method to terminate data source. Called by + jpeg_finish_decompress() after all data has been processed. */ + +static void +our_term_source (cinfo) + j_decompress_ptr cinfo; +{ +} + + +/* Set up the JPEG lib for reading an image from DATA which contains + LEN bytes. CINFO is the decompression info structure created for + reading the image. */ + +static void +jpeg_memory_src (cinfo, data, len) + j_decompress_ptr cinfo; + JOCTET *data; + unsigned int len; +{ + struct jpeg_source_mgr *src; + + if (cinfo->src == NULL) + { + /* First time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof (struct jpeg_source_mgr)); + src = (struct jpeg_source_mgr *) cinfo->src; + src->next_input_byte = data; + } + + src = (struct jpeg_source_mgr *) cinfo->src; + src->init_source = our_init_source; + src->fill_input_buffer = our_fill_input_buffer; + src->skip_input_data = our_skip_input_data; + src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */ + src->term_source = our_term_source; + src->bytes_in_buffer = len; + src->next_input_byte = data; +} + + +/* Load image IMG for use on frame F. Patterned after example.c + from the JPEG lib. */ + +static int +jpeg_load (f, img) + struct frame *f; + struct image *img; +{ + struct jpeg_decompress_struct cinfo; + struct my_jpeg_error_mgr mgr; + Lisp_Object file, specified_file; + Lisp_Object specified_data; + FILE *fp = NULL; + JSAMPARRAY buffer; + int row_stride, x, y; + XImage *ximg = NULL; + int rc; + unsigned long *colors; + int width, height; + struct gcpro gcpro1; + + /* Open the JPEG file. */ + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + fp = fopen (XSTRING (file)->data, "r"); + if (fp == NULL) + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } + } + + /* Customize libjpeg's error handling to call my_error_exit when an + error is detected. This function will perform a longjmp. */ + mgr.pub.error_exit = my_error_exit; + cinfo.err = jpeg_std_error (&mgr.pub); + + if ((rc = setjmp (mgr.setjmp_buffer)) != 0) + { + if (rc == 1) + { + /* Called from my_error_exit. Display a JPEG error. */ + char buffer[JMSG_LENGTH_MAX]; + cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); + image_error ("Error reading JPEG image `%s': %s", img->spec, + build_string (buffer)); + } + + /* Close the input file and destroy the JPEG object. */ + if (fp) + fclose (fp); + jpeg_destroy_decompress (&cinfo); + + BLOCK_INPUT; + + /* If we already have an XImage, free that. */ + x_destroy_x_image (ximg); + + /* Free pixmap and colors. */ + x_clear_image (f, img); + + UNBLOCK_INPUT; + UNGCPRO; + return 0; + } + + /* Create the JPEG decompression object. Let it read from fp. + Read the JPEG image header. */ + jpeg_create_decompress (&cinfo); + + if (NILP (specified_data)) + jpeg_stdio_src (&cinfo, fp); + else + jpeg_memory_src (&cinfo, XSTRING (specified_data)->data, + STRING_BYTES (XSTRING (specified_data))); + + jpeg_read_header (&cinfo, TRUE); + + /* Customize decompression so that color quantization will be used. + Start decompression. */ + cinfo.quantize_colors = TRUE; + jpeg_start_decompress (&cinfo); + width = img->width = cinfo.output_width; + height = img->height = cinfo.output_height; + + BLOCK_INPUT; + + /* Create X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, + &img->pixmap)) + { + UNBLOCK_INPUT; + longjmp (mgr.setjmp_buffer, 2); + } + + /* Allocate colors. When color quantization is used, + cinfo.actual_number_of_colors has been set with the number of + colors generated, and cinfo.colormap is a two-dimensional array + of color indices in the range 0..cinfo.actual_number_of_colors. + No more than 255 colors will be generated. */ + { + int i, ir, ig, ib; + + if (cinfo.out_color_components > 2) + ir = 0, ig = 1, ib = 2; + else if (cinfo.out_color_components > 1) + ir = 0, ig = 1, ib = 0; + else + ir = 0, ig = 0, ib = 0; + + /* Use the color table mechanism because it handles colors that + cannot be allocated nicely. Such colors will be replaced with + a default color, and we don't have to care about which colors + can be freed safely, and which can't. */ + init_color_table (); + colors = (unsigned long *) alloca (cinfo.actual_number_of_colors + * sizeof *colors); + + for (i = 0; i < cinfo.actual_number_of_colors; ++i) + { + /* Multiply RGB values with 255 because X expects RGB values + in the range 0..0xffff. */ + int r = cinfo.colormap[ir][i] << 8; + int g = cinfo.colormap[ig][i] << 8; + int b = cinfo.colormap[ib][i] << 8; + colors[i] = lookup_rgb_color (f, r, g, b); + } + + /* Remember those colors actually allocated. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); + } + + /* Read pixels. */ + row_stride = width * cinfo.output_components; + buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, + row_stride, 1); + for (y = 0; y < height; ++y) + { + jpeg_read_scanlines (&cinfo, buffer, 1); + for (x = 0; x < cinfo.output_width; ++x) + XPutPixel (ximg, x, y, colors[buffer[0][x]]); + } + + /* Clean up. */ + jpeg_finish_decompress (&cinfo); + jpeg_destroy_decompress (&cinfo); + if (fp) + fclose (fp); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + UNBLOCK_INPUT; + UNGCPRO; + return 1; +} + +#endif /* HAVE_JPEG */ + + + +/*********************************************************************** + TIFF + ***********************************************************************/ + +#if HAVE_TIFF + +#include + +static int tiff_image_p P_ ((Lisp_Object object)); +static int tiff_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `tiff' identifying images of this type. */ + +Lisp_Object Qtiff; + +/* Indices of image specification fields in tiff_format, below. */ + +enum tiff_keyword_index +{ + TIFF_TYPE, + TIFF_DATA, + TIFF_FILE, + TIFF_ASCENT, + TIFF_MARGIN, + TIFF_RELIEF, + TIFF_ALGORITHM, + TIFF_HEURISTIC_MASK, + TIFF_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword tiff_format[TIFF_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type `tiff'. */ + +static struct image_type tiff_type = +{ + &Qtiff, + tiff_image_p, + tiff_load, + x_clear_image, + NULL +}; + + +/* Return non-zero if OBJECT is a valid TIFF image specification. */ + +static int +tiff_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[TIFF_LAST]; + bcopy (tiff_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff) + || (fmt[TIFF_ASCENT].count + && XFASTINT (fmt[TIFF_ASCENT].value) > 100)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1; +} + + +/* Reading from a memory buffer for TIFF images Based on the PNG + memory source, but we have to provide a lot of extra functions. + Blah. + + We really only need to implement read and seek, but I am not + convinced that the TIFF library is smart enough not to destroy + itself if we only hand it the function pointers we need to + override. */ + +typedef struct +{ + unsigned char *bytes; + size_t len; + int index; +} +tiff_memory_source; + +static size_t +tiff_read_from_memory (data, buf, size) + thandle_t data; + tdata_t buf; + tsize_t size; +{ + tiff_memory_source *src = (tiff_memory_source *) data; + + if (size > src->len - src->index) + return (size_t) -1; + bcopy (src->bytes + src->index, buf, size); + src->index += size; + return size; +} + +static size_t +tiff_write_from_memory (data, buf, size) + thandle_t data; + tdata_t buf; + tsize_t size; +{ + return (size_t) -1; +} + +static toff_t +tiff_seek_in_memory (data, off, whence) + thandle_t data; + toff_t off; + int whence; +{ + tiff_memory_source *src = (tiff_memory_source *) data; + int idx; + + switch (whence) + { + case SEEK_SET: /* Go from beginning of source. */ + idx = off; + break; + + case SEEK_END: /* Go from end of source. */ + idx = src->len + off; + break; + + case SEEK_CUR: /* Go from current position. */ + idx = src->index + off; + break; + + default: /* Invalid `whence'. */ + return -1; + } + + if (idx > src->len || idx < 0) + return -1; + + src->index = idx; + return src->index; +} + +static int +tiff_close_memory (data) + thandle_t data; +{ + /* NOOP */ + return 0; +} + +static int +tiff_mmap_memory (data, pbase, psize) + thandle_t data; + tdata_t *pbase; + toff_t *psize; +{ + /* It is already _IN_ memory. */ + return 0; +} + +static void +tiff_unmap_memory (data, base, size) + thandle_t data; + tdata_t base; + toff_t size; +{ + /* We don't need to do this. */ +} + +static toff_t +tiff_size_of_memory (data) + thandle_t data; +{ + return ((tiff_memory_source *) data)->len; +} + +/* Load TIFF image IMG for use on frame F. Value is non-zero if + successful. */ + +static int +tiff_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data; + TIFF *tiff; + int width, height, x, y; + uint32 *buf; + int rc; + XImage *ximg; + struct gcpro gcpro1; + tiff_memory_source memsrc; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + /* Read from a file */ + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", file, Qnil); + UNGCPRO; + return 0; + } + + /* Try to open the image file. */ + tiff = TIFFOpen (XSTRING (file)->data, "r"); + if (tiff == NULL) + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } + } + else + { + /* Memory source! */ + memsrc.bytes = XSTRING (specified_data)->data; + memsrc.len = STRING_BYTES (XSTRING (specified_data)); + memsrc.index = 0; + + tiff = TIFFClientOpen ("memory_source", "r", &memsrc, + (TIFFReadWriteProc) tiff_read_from_memory, + (TIFFReadWriteProc) tiff_write_from_memory, + tiff_seek_in_memory, + tiff_close_memory, + tiff_size_of_memory, + tiff_mmap_memory, + tiff_unmap_memory); + + if (!tiff) + { + image_error ("Cannot open memory source for `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + } + + /* Get width and height of the image, and allocate a raster buffer + of width x height 32-bit values. */ + TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height); + buf = (uint32 *) xmalloc (width * height * sizeof *buf); + + rc = TIFFReadRGBAImage (tiff, width, height, buf, 0); + TIFFClose (tiff); + if (!rc) + { + image_error ("Error reading TIFF image `%s'", img->spec, Qnil); + xfree (buf); + UNGCPRO; + return 0; + } + + BLOCK_INPUT; + + /* Create the X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + { + UNBLOCK_INPUT; + xfree (buf); + UNGCPRO; + return 0; + } + + /* Initialize the color table. */ + init_color_table (); + + /* Process the pixel raster. Origin is in the lower-left corner. */ + for (y = 0; y < height; ++y) + { + uint32 *row = buf + y * width; + + for (x = 0; x < width; ++x) + { + uint32 abgr = row[x]; + int r = TIFFGetR (abgr) << 8; + int g = TIFFGetG (abgr) << 8; + int b = TIFFGetB (abgr) << 8; + XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b)); + } + } + + /* Remember the colors allocated for the image. Free the color table. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); + + /* Put the image into the pixmap, then free the X image and its buffer. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + xfree (buf); + UNBLOCK_INPUT; + + img->width = width; + img->height = height; + + UNGCPRO; + return 1; +} + +#endif /* HAVE_TIFF != 0 */ + + + +/*********************************************************************** + GIF + ***********************************************************************/ + +#if HAVE_GIF + +#include + +static int gif_image_p P_ ((Lisp_Object object)); +static int gif_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `gif' identifying images of this type. */ + +Lisp_Object Qgif; + +/* Indices of image specification fields in gif_format, below. */ + +enum gif_keyword_index +{ + GIF_TYPE, + GIF_DATA, + GIF_FILE, + GIF_ASCENT, + GIF_MARGIN, + GIF_RELIEF, + GIF_ALGORITHM, + GIF_HEURISTIC_MASK, + GIF_IMAGE, + GIF_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword gif_format[GIF_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0} +}; + +/* Structure describing the image type `gif'. */ + +static struct image_type gif_type = +{ + &Qgif, + gif_image_p, + gif_load, + x_clear_image, + NULL +}; + +/* Return non-zero if OBJECT is a valid GIF image specification. */ + +static int +gif_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[GIF_LAST]; + bcopy (gif_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, GIF_LAST, Qgif) + || (fmt[GIF_ASCENT].count + && XFASTINT (fmt[GIF_ASCENT].value) > 100)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1; +} + +/* Reading a GIF image from memory + Based on the PNG memory stuff to a certain extent. */ + +typedef struct +{ + unsigned char *bytes; + size_t len; + int index; +} +gif_memory_source; + +/* Make the current memory source available to gif_read_from_memory. + It's done this way because not all versions of libungif support + a UserData field in the GifFileType structure. */ +static gif_memory_source *current_gif_memory_src; + +static int +gif_read_from_memory (file, buf, len) + GifFileType *file; + GifByteType *buf; + int len; +{ + gif_memory_source *src = current_gif_memory_src; + + if (len > src->len - src->index) + return -1; + + bcopy (src->bytes + src->index, buf, len); + src->index += len; + return len; +} + + +/* Load GIF image IMG for use on frame F. Value is non-zero if + successful. */ + +static int +gif_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data; + int rc, width, height, x, y, i; + XImage *ximg; + ColorMapObject *gif_color_map; + unsigned long pixel_colors[256]; + GifFileType *gif; + struct gcpro gcpro1; + Lisp_Object image; + int ino, image_left, image_top, image_width, image_height; + gif_memory_source memsrc; + unsigned char *raster; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + /* Open the GIF file. */ + gif = DGifOpenFileName (XSTRING (file)->data); + if (gif == NULL) + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } + } + else + { + /* Read from memory! */ + current_gif_memory_src = &memsrc; + memsrc.bytes = XSTRING (specified_data)->data; + memsrc.len = STRING_BYTES (XSTRING (specified_data)); + memsrc.index = 0; + + gif = DGifOpen(&memsrc, gif_read_from_memory); + if (!gif) + { + image_error ("Cannot open memory source `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + } + + /* Read entire contents. */ + rc = DGifSlurp (gif); + if (rc == GIF_ERROR) + { + image_error ("Error reading `%s'", img->spec, Qnil); + DGifCloseFile (gif); + UNGCPRO; + return 0; + } + + image = image_spec_value (img->spec, QCindex, NULL); + ino = INTEGERP (image) ? XFASTINT (image) : 0; + if (ino >= gif->ImageCount) + { + image_error ("Invalid image number `%s' in image `%s'", + image, img->spec); + DGifCloseFile (gif); + UNGCPRO; + return 0; + } + + width = img->width = gif->SWidth; + height = img->height = gif->SHeight; + + BLOCK_INPUT; + + /* Create the X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + { + UNBLOCK_INPUT; + DGifCloseFile (gif); + UNGCPRO; + return 0; + } + + /* Allocate colors. */ + gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; + if (!gif_color_map) + gif_color_map = gif->SColorMap; + init_color_table (); + bzero (pixel_colors, sizeof pixel_colors); + + for (i = 0; i < gif_color_map->ColorCount; ++i) + { + int r = gif_color_map->Colors[i].Red << 8; + int g = gif_color_map->Colors[i].Green << 8; + int b = gif_color_map->Colors[i].Blue << 8; + pixel_colors[i] = lookup_rgb_color (f, r, g, b); + } + + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); + + /* Clear the part of the screen image that are not covered by + the image from the GIF file. Full animated GIF support + requires more than can be done here (see the gif89 spec, + disposal methods). Let's simply assume that the part + not covered by a sub-image is in the frame's background color. */ + image_top = gif->SavedImages[ino].ImageDesc.Top; + image_left = gif->SavedImages[ino].ImageDesc.Left; + image_width = gif->SavedImages[ino].ImageDesc.Width; + image_height = gif->SavedImages[ino].ImageDesc.Height; + + for (y = 0; y < image_top; ++y) + for (x = 0; x < width; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + + for (y = image_top + image_height; y < height; ++y) + for (x = 0; x < width; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + + for (y = image_top; y < image_top + image_height; ++y) + { + for (x = 0; x < image_left; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + for (x = image_left + image_width; x < width; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + } + + /* Read the GIF image into the X image. We use a local variable + `raster' here because RasterBits below is a char *, and invites + problems with bytes >= 0x80. */ + raster = (unsigned char *) gif->SavedImages[ino].RasterBits; + + if (gif->SavedImages[ino].ImageDesc.Interlace) + { + static int interlace_start[] = {0, 4, 2, 1}; + static int interlace_increment[] = {8, 8, 4, 2}; + int pass, inc; + int row = interlace_start[0]; + + pass = 0; + + for (y = 0; y < image_height; y++) + { + if (row >= image_height) + { + row = interlace_start[++pass]; + while (row >= image_height) + row = interlace_start[++pass]; + } + + for (x = 0; x < image_width; x++) + { + int i = raster[(y * image_width) + x]; + XPutPixel (ximg, x + image_left, row + image_top, + pixel_colors[i]); + } + + row += interlace_increment[pass]; + } + } + else + { + for (y = 0; y < image_height; ++y) + for (x = 0; x < image_width; ++x) + { + int i = raster[y* image_width + x]; + XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); + } + } + + DGifCloseFile (gif); + + /* Put the image into the pixmap, then free the X image and its buffer. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + UNBLOCK_INPUT; + + UNGCPRO; + return 1; +} + +#endif /* HAVE_GIF != 0 */ + + + +/*********************************************************************** + Ghostscript + ***********************************************************************/ + +#ifdef HAVE_GHOSTSCRIPT +static int gs_image_p P_ ((Lisp_Object object)); +static int gs_load P_ ((struct frame *f, struct image *img)); +static void gs_clear_image P_ ((struct frame *f, struct image *img)); + +/* The symbol `postscript' identifying images of this type. */ + +Lisp_Object Qpostscript; + +/* Keyword symbols. */ + +Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; + +/* Indices of image specification fields in gs_format, below. */ + +enum gs_keyword_index +{ + GS_TYPE, + GS_PT_WIDTH, + GS_PT_HEIGHT, + GS_FILE, + GS_LOADER, + GS_BOUNDING_BOX, + GS_ASCENT, + GS_MARGIN, + GS_RELIEF, + GS_ALGORITHM, + GS_HEURISTIC_MASK, + GS_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword gs_format[GS_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1}, + {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 1}, + {":loader", IMAGE_FUNCTION_VALUE, 0}, + {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, + {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type `ghostscript'. */ + +static struct image_type gs_type = +{ + &Qpostscript, + gs_image_p, + gs_load, + gs_clear_image, + NULL +}; + + +/* Free X resources of Ghostscript image IMG which is used on frame F. */ + +static void +gs_clear_image (f, img) + struct frame *f; + struct image *img; +{ + /* IMG->data.ptr_val may contain a recorded colormap. */ + xfree (img->data.ptr_val); + x_clear_image (f, img); +} + + +/* Return non-zero if OBJECT is a valid Ghostscript image + specification. */ + +static int +gs_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[GS_LAST]; + Lisp_Object tem; + int i; + + bcopy (gs_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript) + || (fmt[GS_ASCENT].count + && XFASTINT (fmt[GS_ASCENT].value) > 100)) + return 0; + + /* Bounding box must be a list or vector containing 4 integers. */ + tem = fmt[GS_BOUNDING_BOX].value; + if (CONSP (tem)) + { + for (i = 0; i < 4; ++i, tem = XCDR (tem)) + if (!CONSP (tem) || !INTEGERP (XCAR (tem))) + return 0; + if (!NILP (tem)) + return 0; + } + else if (VECTORP (tem)) + { + if (XVECTOR (tem)->size != 4) + return 0; + for (i = 0; i < 4; ++i) + if (!INTEGERP (XVECTOR (tem)->contents[i])) + return 0; + } + else + return 0; + + return 1; +} + + +/* Load Ghostscript image IMG for use on frame F. Value is non-zero + if successful. */ + +static int +gs_load (f, img) + struct frame *f; + struct image *img; +{ + char buffer[100]; + Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; + struct gcpro gcpro1, gcpro2; + Lisp_Object frame; + double in_width, in_height; + Lisp_Object pixel_colors = Qnil; + + /* Compute pixel size of pixmap needed from the given size in the + image specification. Sizes in the specification are in pt. 1 pt + = 1/72 in, xdpi and ydpi are stored in the frame's X display + info. */ + pt_width = image_spec_value (img->spec, QCpt_width, NULL); + in_width = XFASTINT (pt_width) / 72.0; + img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx; + pt_height = image_spec_value (img->spec, QCpt_height, NULL); + in_height = XFASTINT (pt_height) / 72.0; + img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy; + + /* Create the pixmap. */ + BLOCK_INPUT; + xassert (img->pixmap == 0); + img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), + img->width, img->height, + DefaultDepthOfScreen (FRAME_X_SCREEN (f))); + UNBLOCK_INPUT; + + if (!img->pixmap) + { + image_error ("Unable to create pixmap for `%s'", img->spec, Qnil); + return 0; + } + + /* Call the loader to fill the pixmap. It returns a process object + if successful. We do not record_unwind_protect here because + other places in redisplay like calling window scroll functions + don't either. Let the Lisp loader use `unwind-protect' instead. */ + GCPRO2 (window_and_pixmap_id, pixel_colors); + + sprintf (buffer, "%lu %lu", + (unsigned long) FRAME_W32_WINDOW (f), + (unsigned long) img->pixmap); + window_and_pixmap_id = build_string (buffer); + + sprintf (buffer, "%lu %lu", + FRAME_FOREGROUND_PIXEL (f), + FRAME_BACKGROUND_PIXEL (f)); + pixel_colors = build_string (buffer); + + XSETFRAME (frame, f); + loader = image_spec_value (img->spec, QCloader, NULL); + if (NILP (loader)) + loader = intern ("gs-load-image"); + + img->data.lisp_val = call6 (loader, frame, img->spec, + make_number (img->width), + make_number (img->height), + window_and_pixmap_id, + pixel_colors); + UNGCPRO; + return PROCESSP (img->data.lisp_val); +} + + +/* Kill the Ghostscript process that was started to fill PIXMAP on + frame F. Called from XTread_socket when receiving an event + telling Emacs that Ghostscript has finished drawing. */ + +void +x_kill_gs_process (pixmap, f) + Pixmap pixmap; + struct frame *f; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + int class, i; + struct image *img; + + /* Find the image containing PIXMAP. */ + for (i = 0; i < c->used; ++i) + if (c->images[i]->pixmap == pixmap) + break; + + /* Kill the GS process. We should have found PIXMAP in the image + cache and its image should contain a process object. */ + xassert (i < c->used); + img = c->images[i]; + xassert (PROCESSP (img->data.lisp_val)); + Fkill_process (img->data.lisp_val, Qnil); + img->data.lisp_val = Qnil; + + /* On displays with a mutable colormap, figure out the colors + allocated for the image by looking at the pixels of an XImage for + img->pixmap. */ + class = FRAME_W32_DISPLAY_INFO (f)->visual->class; + if (class != StaticColor && class != StaticGray && class != TrueColor) + { + XImage *ximg; + + BLOCK_INPUT; + + /* Try to get an XImage for img->pixmep. */ + ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); + if (ximg) + { + int x, y; + + /* Initialize the color table. */ + init_color_table (); + + /* For each pixel of the image, look its color up in the + color table. After having done so, the color table will + contain an entry for each color used by the image. */ + for (y = 0; y < img->height; ++y) + for (x = 0; x < img->width; ++x) + { + unsigned long pixel = XGetPixel (ximg, x, y); + lookup_pixel_color (f, pixel); + } + + /* Record colors in the image. Free color table and XImage. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); + XDestroyImage (ximg); + +#if 0 /* This doesn't seem to be the case. If we free the colors + here, we get a BadAccess later in x_clear_image when + freeing the colors. */ + /* We have allocated colors once, but Ghostscript has also + allocated colors on behalf of us. So, to get the + reference counts right, free them once. */ + if (img->ncolors) + { + Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); + XFreeColors (FRAME_W32_DISPLAY (f), cmap, + img->colors, img->ncolors, 0); + } +#endif + } + else + image_error ("Cannot get X image of `%s'; colors will not be freed", + img->spec, Qnil); + + UNBLOCK_INPUT; + } +} + +#endif /* HAVE_GHOSTSCRIPT */ + + +/*********************************************************************** + Window properties + ***********************************************************************/ + +DEFUN ("x-change-window-property", Fx_change_window_property, + Sx_change_window_property, 2, 3, 0, + "Change window property PROP to VALUE on the X window of FRAME.\n\ +PROP and VALUE must be strings. FRAME nil or omitted means use the\n\ +selected frame. Value is VALUE.") + (prop, value, frame) + Lisp_Object frame, prop, value; +{ +#if 0 /* MAC_TODO : port window properties to Mac */ + struct frame *f = check_x_frame (frame); + Atom prop_atom; + + CHECK_STRING (prop, 1); + CHECK_STRING (value, 2); + + BLOCK_INPUT; + prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False); + XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), + prop_atom, XA_STRING, 8, PropModeReplace, + XSTRING (value)->data, XSTRING (value)->size); + + /* Make sure the property is set when we return. */ + XFlush (FRAME_W32_DISPLAY (f)); + UNBLOCK_INPUT; + +#endif /* MAC_TODO */ + + return value; +} + + +DEFUN ("x-delete-window-property", Fx_delete_window_property, + Sx_delete_window_property, 1, 2, 0, + "Remove window property PROP from X window of FRAME.\n\ +FRAME nil or omitted means use the selected frame. Value is PROP.") + (prop, frame) + Lisp_Object prop, frame; +{ +#if 0 /* MAC_TODO : port window properties to Mac */ + + struct frame *f = check_x_frame (frame); + Atom prop_atom; + + CHECK_STRING (prop, 1); + BLOCK_INPUT; + prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False); + XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom); + + /* Make sure the property is removed when we return. */ + XFlush (FRAME_W32_DISPLAY (f)); + UNBLOCK_INPUT; +#endif /* MAC_TODO */ + + return prop; +} + + +DEFUN ("x-window-property", Fx_window_property, Sx_window_property, + 1, 2, 0, + "Value is the value of window property PROP on FRAME.\n\ +If FRAME is nil or omitted, use the selected frame. Value is nil\n\ +if FRAME hasn't a property with name PROP or if PROP has no string\n\ +value.") + (prop, frame) + Lisp_Object prop, frame; +{ +#if 0 /* MAC_TODO : port window properties to Mac */ + + struct frame *f = check_x_frame (frame); + Atom prop_atom; + int rc; + Lisp_Object prop_value = Qnil; + char *tmp_data = NULL; + Atom actual_type; + int actual_format; + unsigned long actual_size, bytes_remaining; + + CHECK_STRING (prop, 1); + BLOCK_INPUT; + prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False); + rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), + prop_atom, 0, 0, False, XA_STRING, + &actual_type, &actual_format, &actual_size, + &bytes_remaining, (unsigned char **) &tmp_data); + if (rc == Success) + { + int size = bytes_remaining; + + XFree (tmp_data); + tmp_data = NULL; + + rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), + prop_atom, 0, bytes_remaining, + False, XA_STRING, + &actual_type, &actual_format, + &actual_size, &bytes_remaining, + (unsigned char **) &tmp_data); + if (rc == Success) + prop_value = make_string (tmp_data, size); + + XFree (tmp_data); + } + + UNBLOCK_INPUT; + + return prop_value; + +#endif /* MAC_TODO */ + return Qnil; +} + + + +/*********************************************************************** + Busy cursor + ***********************************************************************/ + +/* If non-null, an asynchronous timer that, when it expires, displays + a busy cursor on all frames. */ + +static struct atimer *busy_cursor_atimer; + +/* Non-zero means a busy cursor is currently shown. */ + +static int busy_cursor_shown_p; + +/* Number of seconds to wait before displaying a busy cursor. */ + +static Lisp_Object Vbusy_cursor_delay; + +/* Default number of seconds to wait before displaying a busy + cursor. */ + +#define DEFAULT_BUSY_CURSOR_DELAY 1 + +/* Function prototypes. */ + +static void show_busy_cursor P_ ((struct atimer *)); +static void hide_busy_cursor P_ ((void)); + + +/* Cancel a currently active busy-cursor timer, and start a new one. */ + +void +start_busy_cursor () +{ +#if 0 /* MAC_TODO: cursor shape changes. */ + EMACS_TIME delay; + int secs, usecs = 0; + + cancel_busy_cursor (); + + if (INTEGERP (Vbusy_cursor_delay) + && XINT (Vbusy_cursor_delay) > 0) + secs = XFASTINT (Vbusy_cursor_delay); + else if (FLOATP (Vbusy_cursor_delay) + && XFLOAT_DATA (Vbusy_cursor_delay) > 0) + { + Lisp_Object tem; + tem = Ftruncate (Vbusy_cursor_delay, Qnil); + secs = XFASTINT (tem); + usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000; + } + else + secs = DEFAULT_BUSY_CURSOR_DELAY; + + EMACS_SET_SECS_USECS (delay, secs, usecs); + busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay, + show_busy_cursor, NULL); +#endif +} + + +/* Cancel the busy cursor timer if active, hide a busy cursor if + shown. */ + +void +cancel_busy_cursor () +{ + if (busy_cursor_atimer) + { + cancel_atimer (busy_cursor_atimer); + busy_cursor_atimer = NULL; + } + + if (busy_cursor_shown_p) + hide_busy_cursor (); +} + + +/* Timer function of busy_cursor_atimer. TIMER is equal to + busy_cursor_atimer. + + Display a busy cursor on all frames by mapping the frames' + busy_window. Set the busy_p flag in the frames' output_data.x + structure to indicate that a busy cursor is shown on the + frames. */ + +static void +show_busy_cursor (timer) + struct atimer *timer; +{ +#if 0 /* MAC_TODO: cursor shape changes. */ + /* The timer implementation will cancel this timer automatically + after this function has run. Set busy_cursor_atimer to null + so that we know the timer doesn't have to be canceled. */ + busy_cursor_atimer = NULL; + + if (!busy_cursor_shown_p) + { + Lisp_Object rest, frame; + + BLOCK_INPUT; + + FOR_EACH_FRAME (rest, frame) + if (FRAME_X_P (XFRAME (frame))) + { + struct frame *f = XFRAME (frame); + + f->output_data.w32->busy_p = 1; + + if (!f->output_data.w32->busy_window) + { + unsigned long mask = CWCursor; + XSetWindowAttributes attrs; + + attrs.cursor = f->output_data.w32->busy_cursor; + + f->output_data.w32->busy_window + = XCreateWindow (FRAME_X_DISPLAY (f), + FRAME_OUTER_WINDOW (f), + 0, 0, 32000, 32000, 0, 0, + InputOnly, + CopyFromParent, + mask, &attrs); + } + + XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window); + XFlush (FRAME_X_DISPLAY (f)); + } + + busy_cursor_shown_p = 1; + UNBLOCK_INPUT; + } +#endif +} + + +/* Hide the busy cursor on all frames, if it is currently shown. */ + +static void +hide_busy_cursor () +{ +#if 0 /* MAC_TODO: cursor shape changes. */ + if (busy_cursor_shown_p) + { + Lisp_Object rest, frame; + + BLOCK_INPUT; + FOR_EACH_FRAME (rest, frame) + { + struct frame *f = XFRAME (frame); + + if (FRAME_X_P (f) + /* Watch out for newly created frames. */ + && f->output_data.x->busy_window) + { + XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window); + /* Sync here because XTread_socket looks at the busy_p flag + that is reset to zero below. */ + XSync (FRAME_X_DISPLAY (f), False); + f->output_data.x->busy_p = 0; + } + } + + busy_cursor_shown_p = 0; + UNBLOCK_INPUT; + } +#endif +} + + + +/*********************************************************************** + Tool tips + ***********************************************************************/ + +static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *, + Lisp_Object)); + +/* The frame of a currently visible tooltip, or null. */ + +struct frame *tip_frame; + +/* If non-nil, a timer started that hides the last tooltip when it + fires. */ + +Lisp_Object tip_timer; +Window tip_window; + +/* Create a frame for a tooltip on the display described by DPYINFO. + PARMS is a list of frame parameters. Value is the frame. */ + +static Lisp_Object +x_create_tip_frame (dpyinfo, parms) + struct w32_display_info *dpyinfo; + Lisp_Object parms; +{ +#if 0 /* MAC_TODO : Mac version */ + struct frame *f; + Lisp_Object frame, tem; + Lisp_Object name; + long window_prompting = 0; + int width, height; + int count = specpdl_ptr - specpdl; + struct gcpro gcpro1, gcpro2, gcpro3; + struct kboard *kb; + + check_x (); + + /* Use this general default value to start with until we know if + this frame has a specified name. */ + Vx_resource_name = Vinvocation_name; + +#ifdef MULTI_KBOARD + kb = dpyinfo->kboard; +#else + kb = &the_only_kboard; +#endif + + /* Get the name of the frame to use for resource lookup. */ + name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING); + if (!STRINGP (name) + && !EQ (name, Qunbound) + && !NILP (name)) + error ("Invalid frame name--not a string or nil"); + Vx_resource_name = name; + + frame = Qnil; + GCPRO3 (parms, name, frame); + tip_frame = f = make_frame (1); + XSETFRAME (frame, f); + FRAME_CAN_HAVE_SCROLL_BARS (f) = 0; + + f->output_method = output_w32; + f->output_data.w32 = + (struct w32_output *) xmalloc (sizeof (struct w32_output)); + bzero (f->output_data.w32, sizeof (struct w32_output)); +#if 0 + f->output_data.w32->icon_bitmap = -1; +#endif + f->output_data.w32->fontset = -1; + f->icon_name = Qnil; + +#ifdef MULTI_KBOARD + FRAME_KBOARD (f) = kb; +#endif + f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window; + f->output_data.w32->explicit_parent = 0; + + /* Set the name; the functions to which we pass f expect the name to + be set. */ + if (EQ (name, Qunbound) || NILP (name)) + { + f->name = build_string (dpyinfo->x_id_name); + f->explicit_name = 0; + } + else + { + f->name = name; + f->explicit_name = 1; + /* use the frame's title when getting resources for this frame. */ + specbind (Qx_resource_name, name); + } + + /* Extract the window parameters from the supplied values + that are needed to determine window geometry. */ + { + Lisp_Object font; + + font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING); + + BLOCK_INPUT; + /* First, try whatever font the caller has specified. */ + if (STRINGP (font)) + { + tem = Fquery_fontset (font, Qnil); + if (STRINGP (tem)) + font = x_new_fontset (f, XSTRING (tem)->data); + else + font = x_new_font (f, XSTRING (font)->data); + } + + /* Try out a font which we hope has bold and italic variations. */ + if (!STRINGP (font)) + font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1"); + if (!STRINGP (font)) + font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); + if (! STRINGP (font)) + font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1"); + if (! STRINGP (font)) + /* This was formerly the first thing tried, but it finds too many fonts + and takes too long. */ + font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1"); + /* If those didn't work, look for something which will at least work. */ + if (! STRINGP (font)) + font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1"); + UNBLOCK_INPUT; + if (! STRINGP (font)) + font = build_string ("fixed"); + + x_default_parameter (f, parms, Qfont, font, + "font", "Font", RES_TYPE_STRING); + } + + x_default_parameter (f, parms, Qborder_width, make_number (2), + "borderWidth", "BorderWidth", RES_TYPE_NUMBER); + + /* This defaults to 2 in order to match xterm. We recognize either + internalBorderWidth or internalBorder (which is what xterm calls + it). */ + if (NILP (Fassq (Qinternal_border_width, parms))) + { + Lisp_Object value; + + value = w32_get_arg (parms, Qinternal_border_width, + "internalBorder", "internalBorder", RES_TYPE_NUMBER); + if (! EQ (value, Qunbound)) + parms = Fcons (Fcons (Qinternal_border_width, value), + parms); + } + + x_default_parameter (f, parms, Qinternal_border_width, make_number (1), + "internalBorderWidth", "internalBorderWidth", + RES_TYPE_NUMBER); + + /* Also do the stuff which must be set before the window exists. */ + x_default_parameter (f, parms, Qforeground_color, build_string ("black"), + "foreground", "Foreground", RES_TYPE_STRING); + x_default_parameter (f, parms, Qbackground_color, build_string ("white"), + "background", "Background", RES_TYPE_STRING); + x_default_parameter (f, parms, Qmouse_color, build_string ("black"), + "pointerColor", "Foreground", RES_TYPE_STRING); + x_default_parameter (f, parms, Qcursor_color, build_string ("black"), + "cursorColor", "Foreground", RES_TYPE_STRING); + x_default_parameter (f, parms, Qborder_color, build_string ("black"), + "borderColor", "BorderColor", RES_TYPE_STRING); + + /* Init faces before x_default_parameter is called for scroll-bar + parameters because that function calls x_set_scroll_bar_width, + which calls change_frame_size, which calls Fset_window_buffer, + which runs hooks, which call Fvertical_motion. At the end, we + end up in init_iterator with a null face cache, which should not + happen. */ + init_frame_faces (f); + + f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window; + window_prompting = x_figure_window_size (f, parms); + + if (window_prompting & XNegative) + { + if (window_prompting & YNegative) + f->output_data.w32->win_gravity = SouthEastGravity; + else + f->output_data.w32->win_gravity = NorthEastGravity; + } + else + { + if (window_prompting & YNegative) + f->output_data.w32->win_gravity = SouthWestGravity; + else + f->output_data.w32->win_gravity = NorthWestGravity; + } + + f->output_data.w32->size_hint_flags = window_prompting; + { + XSetWindowAttributes attrs; + unsigned long mask; + + BLOCK_INPUT; + mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask; + /* Window managers looks at the override-redirect flag to + determine whether or net to give windows a decoration (Xlib + 3.2.8). */ + attrs.override_redirect = True; + attrs.save_under = True; + attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f); + /* Arrange for getting MapNotify and UnmapNotify events. */ + attrs.event_mask = StructureNotifyMask; + tip_window + = FRAME_W32_WINDOW (f) + = XCreateWindow (FRAME_W32_DISPLAY (f), + FRAME_W32_DISPLAY_INFO (f)->root_window, + /* x, y, width, height */ + 0, 0, 1, 1, + /* Border. */ + 1, + CopyFromParent, InputOutput, CopyFromParent, + mask, &attrs); + UNBLOCK_INPUT; + } + + x_make_gc (f); + + x_default_parameter (f, parms, Qauto_raise, Qnil, + "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); + x_default_parameter (f, parms, Qauto_lower, Qnil, + "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); + x_default_parameter (f, parms, Qcursor_type, Qbox, + "cursorType", "CursorType", RES_TYPE_SYMBOL); + + /* Dimensions, especially f->height, must be done via change_frame_size. + Change will not be effected unless different from the current + f->height. */ + width = f->width; + height = f->height; + f->height = 0; + SET_FRAME_WIDTH (f, 0); + change_frame_size (f, height, width, 1, 0, 0); + + f->no_split = 1; + + UNGCPRO; + + /* It is now ok to make the frame official even if we get an error + below. And the frame needs to be on Vframe_list or making it + visible won't work. */ + Vframe_list = Fcons (frame, Vframe_list); + + /* Now that the frame is official, it counts as a reference to + its display. */ + FRAME_W32_DISPLAY_INFO (f)->reference_count++; + + return unbind_to (count, frame); +#endif /* MAC_TODO */ + return Qnil; +} + + +DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, + "Show STRING in a \"tooltip\" window on frame FRAME.\n\ +A tooltip window is a small X window displaying STRING at\n\ +the current mouse position.\n\ +FRAME nil or omitted means use the selected frame.\n\ +PARMS is an optional list of frame parameters which can be\n\ +used to change the tooltip's appearance.\n\ +Automatically hide the tooltip after TIMEOUT seconds.\n\ +TIMEOUT nil means use the default timeout of 5 seconds.") + (string, frame, parms, timeout) + Lisp_Object string, frame, parms, timeout; +{ + struct frame *f; + struct window *w; + Window root, child; + Lisp_Object buffer; + struct buffer *old_buffer; + struct text_pos pos; + int i, width, height; + int root_x, root_y, win_x, win_y; + unsigned pmask; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + int old_windows_or_buffers_changed = windows_or_buffers_changed; + int count = specpdl_ptr - specpdl; + + specbind (Qinhibit_redisplay, Qt); + + GCPRO4 (string, parms, frame, timeout); + + CHECK_STRING (string, 0); + f = check_x_frame (frame); + if (NILP (timeout)) + timeout = make_number (5); + else + CHECK_NATNUM (timeout, 2); + + /* Hide a previous tip, if any. */ + Fx_hide_tip (); + + /* Add default values to frame parameters. */ + if (NILP (Fassq (Qname, parms))) + parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); + if (NILP (Fassq (Qinternal_border_width, parms))) + parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms); + if (NILP (Fassq (Qborder_width, parms))) + parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); + if (NILP (Fassq (Qborder_color, parms))) + parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); + if (NILP (Fassq (Qbackground_color, parms))) + parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), + parms); + + /* Create a frame for the tooltip, and record it in the global + variable tip_frame. */ + frame = x_create_tip_frame (FRAME_MAC_DISPLAY_INFO (f), parms); + tip_frame = f = XFRAME (frame); + + /* Set up the frame's root window. Currently we use a size of 80 + columns x 40 lines. If someone wants to show a larger tip, he + will loose. I don't think this is a realistic case. */ + w = XWINDOW (FRAME_ROOT_WINDOW (f)); + w->left = w->top = make_number (0); + w->width = 80; + w->height = 40; + adjust_glyphs (f); + w->pseudo_window_p = 1; + + /* Display the tooltip text in a temporary buffer. */ + buffer = Fget_buffer_create (build_string (" *tip*")); + Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer); + old_buffer = current_buffer; + set_buffer_internal_1 (XBUFFER (buffer)); + Ferase_buffer (); + Finsert (make_number (1), &string); + clear_glyph_matrix (w->desired_matrix); + clear_glyph_matrix (w->current_matrix); + SET_TEXT_POS (pos, BEGV, BEGV_BYTE); + try_window (FRAME_ROOT_WINDOW (f), pos); + + /* Compute width and height of the tooltip. */ + width = height = 0; + for (i = 0; i < w->desired_matrix->nrows; ++i) + { + struct glyph_row *row = &w->desired_matrix->rows[i]; + struct glyph *last; + int row_width; + + /* Stop at the first empty row at the end. */ + if (!row->enabled_p || !row->displays_text_p) + break; + + /* Let the row go over the full width of the frame. */ + row->full_width_p = 1; + + /* There's a glyph at the end of rows that is use to place + the cursor there. Don't include the width of this glyph. */ + if (row->used[TEXT_AREA]) + { + last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1]; + row_width = row->pixel_width - last->pixel_width; + } + else + row_width = row->pixel_width; + + height += row->height; + width = max (width, row_width); + } + + /* Add the frame's internal border to the width and height the X + window should have. */ + height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); + width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); + + /* Move the tooltip window where the mouse pointer is. Resize and + show it. */ +#if 0 /* MAC_TODO : Mac specifics */ + BLOCK_INPUT; + XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window, + &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask); + XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), + root_x + 5, root_y - height - 5, width, height); + XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f)); + UNBLOCK_INPUT; +#endif /* MAC_TODO */ + + /* Draw into the window. */ + w->must_be_updated_p = 1; + update_single_window (w, 1); + + /* Restore original current buffer. */ + set_buffer_internal_1 (old_buffer); + windows_or_buffers_changed = old_windows_or_buffers_changed; + + /* Let the tip disappear after timeout seconds. */ + tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, + intern ("x-hide-tip")); + + UNGCPRO; + return unbind_to (count, Qnil); +} + +DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, + "Hide the current tooltip window, if there is any.\n\ +Value is t is tooltip was open, nil otherwise.") + () +{ + int count = specpdl_ptr - specpdl; + int deleted_p = 0; + + specbind (Qinhibit_redisplay, Qt); + + if (!NILP (tip_timer)) + { + call1 (intern ("cancel-timer"), tip_timer); + tip_timer = Qnil; + } + + if (tip_frame) + { + Lisp_Object frame; + + XSETFRAME (frame, tip_frame); + Fdelete_frame (frame, Qt); + tip_frame = NULL; + deleted_p = 1; + } + + return unbind_to (count, deleted_p ? Qt : Qnil); +} + + + +/*********************************************************************** + File selection dialog + ***********************************************************************/ + +#if 0 /* MAC_TODO: can standard file dialog */ +extern Lisp_Object Qfile_name_history; + +DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0, + "Read file name, prompting with PROMPT in directory DIR.\n\ +Use a file selection dialog.\n\ +Select DEFAULT-FILENAME in the dialog's file selection box, if\n\ +specified. Don't let the user enter a file name in the file\n\ +selection dialog's entry field, if MUSTMATCH is non-nil.") + (prompt, dir, default_filename, mustmatch) + Lisp_Object prompt, dir, default_filename, mustmatch; +{ + struct frame *f = SELECTED_FRAME (); + Lisp_Object file = Qnil; + int count = specpdl_ptr - specpdl; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; + char filename[MAX_PATH + 1]; + char init_dir[MAX_PATH + 1]; + int use_dialog_p = 1; + + GCPRO5 (prompt, dir, default_filename, mustmatch, file); + CHECK_STRING (prompt, 0); + CHECK_STRING (dir, 1); + + /* Create the dialog with PROMPT as title, using DIR as initial + directory and using "*" as pattern. */ + dir = Fexpand_file_name (dir, Qnil); + strncpy (init_dir, XSTRING (dir)->data, MAX_PATH); + init_dir[MAX_PATH] = '\0'; + unixtodos_filename (init_dir); + + if (STRINGP (default_filename)) + { + char *file_name_only; + char *full_path_name = XSTRING (default_filename)->data; + + unixtodos_filename (full_path_name); + + file_name_only = strrchr (full_path_name, '\\'); + if (!file_name_only) + file_name_only = full_path_name; + else + { + file_name_only++; + + /* If default_file_name is a directory, don't use the open + file dialog, as it does not support selecting + directories. */ + if (!(*file_name_only)) + use_dialog_p = 0; + } + + strncpy (filename, file_name_only, MAX_PATH); + filename[MAX_PATH] = '\0'; + } + else + filename[0] = '\0'; + + if (use_dialog_p) + { + OPENFILENAME file_details; + char *filename_file; + + /* Prevent redisplay. */ + specbind (Qinhibit_redisplay, Qt); + BLOCK_INPUT; + + bzero (&file_details, sizeof (file_details)); + file_details.lStructSize = sizeof (file_details); + file_details.hwndOwner = FRAME_W32_WINDOW (f); + file_details.lpstrFile = filename; + file_details.nMaxFile = sizeof (filename); + file_details.lpstrInitialDir = init_dir; + file_details.lpstrTitle = XSTRING (prompt)->data; + file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + + if (!NILP (mustmatch)) + file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; + + if (GetOpenFileName (&file_details)) + { + dostounix_filename (filename); + file = build_string (filename); + } + else + file = Qnil; + + UNBLOCK_INPUT; + file = unbind_to (count, file); + } + /* Open File dialog will not allow folders to be selected, so resort + to minibuffer completing reads for directories. */ + else + file = Fcompleting_read (prompt, intern ("read-file-name-internal"), + dir, mustmatch, dir, Qfile_name_history, + default_filename, Qnil); + + UNGCPRO; + + /* Make "Cancel" equivalent to C-g. */ + if (NILP (file)) + Fsignal (Qquit, Qnil); + + return unbind_to (count, file); +} +#endif + + + +/*********************************************************************** + Tests + ***********************************************************************/ + +#if GLYPH_DEBUG + +DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0, + "Value is non-nil if SPEC is a valid image specification.") + (spec) + Lisp_Object spec; +{ + return valid_image_p (spec) ? Qt : Qnil; +} + + +DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "") + (spec) + Lisp_Object spec; +{ + int id = -1; + + if (valid_image_p (spec)) + id = lookup_image (SELECTED_FRAME (), spec); + + debug_print (spec); + return make_number (id); +} + +#endif /* GLYPH_DEBUG != 0 */ + + + +void +syms_of_macfns () +{ + /* Certainly running on Mac. */ + mac_in_use = 1; + + /* The section below is built by the lisp expression at the top of the file, + just above where these variables are declared. */ + /*&&& init symbols here &&&*/ + Qauto_raise = intern ("auto-raise"); + staticpro (&Qauto_raise); + Qauto_lower = intern ("auto-lower"); + staticpro (&Qauto_lower); + Qbar = intern ("bar"); + staticpro (&Qbar); + Qborder_color = intern ("border-color"); + staticpro (&Qborder_color); + Qborder_width = intern ("border-width"); + staticpro (&Qborder_width); + Qbox = intern ("box"); + staticpro (&Qbox); + Qcursor_color = intern ("cursor-color"); + staticpro (&Qcursor_color); + Qcursor_type = intern ("cursor-type"); + staticpro (&Qcursor_type); + Qgeometry = intern ("geometry"); + staticpro (&Qgeometry); + Qicon_left = intern ("icon-left"); + staticpro (&Qicon_left); + Qicon_top = intern ("icon-top"); + staticpro (&Qicon_top); + Qicon_type = intern ("icon-type"); + staticpro (&Qicon_type); + Qicon_name = intern ("icon-name"); + staticpro (&Qicon_name); + Qinternal_border_width = intern ("internal-border-width"); + staticpro (&Qinternal_border_width); + Qleft = intern ("left"); + staticpro (&Qleft); + Qright = intern ("right"); + staticpro (&Qright); + Qmouse_color = intern ("mouse-color"); + staticpro (&Qmouse_color); + Qnone = intern ("none"); + staticpro (&Qnone); + Qparent_id = intern ("parent-id"); + staticpro (&Qparent_id); + Qscroll_bar_width = intern ("scroll-bar-width"); + staticpro (&Qscroll_bar_width); + Qsuppress_icon = intern ("suppress-icon"); + staticpro (&Qsuppress_icon); + Qundefined_color = intern ("undefined-color"); + staticpro (&Qundefined_color); + Qvertical_scroll_bars = intern ("vertical-scroll-bars"); + staticpro (&Qvertical_scroll_bars); + Qvisibility = intern ("visibility"); + staticpro (&Qvisibility); + Qwindow_id = intern ("window-id"); + staticpro (&Qwindow_id); + Qx_frame_parameter = intern ("x-frame-parameter"); + staticpro (&Qx_frame_parameter); + Qx_resource_name = intern ("x-resource-name"); + staticpro (&Qx_resource_name); + Quser_position = intern ("user-position"); + staticpro (&Quser_position); + Quser_size = intern ("user-size"); + staticpro (&Quser_size); + Qscreen_gamma = intern ("screen-gamma"); + staticpro (&Qscreen_gamma); + Qline_spacing = intern ("line-spacing"); + staticpro (&Qline_spacing); + Qcenter = intern ("center"); + staticpro (&Qcenter); + /* This is the end of symbol initialization. */ + + Qhyper = intern ("hyper"); + staticpro (&Qhyper); + Qsuper = intern ("super"); + staticpro (&Qsuper); + Qmeta = intern ("meta"); + staticpro (&Qmeta); + Qalt = intern ("alt"); + staticpro (&Qalt); + Qctrl = intern ("ctrl"); + staticpro (&Qctrl); + Qcontrol = intern ("control"); + staticpro (&Qcontrol); + Qshift = intern ("shift"); + staticpro (&Qshift); + + /* Text property `display' should be nonsticky by default. */ + Vtext_property_default_nonsticky + = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky); + + + Qlaplace = intern ("laplace"); + staticpro (&Qlaplace); + + Qface_set_after_frame_default = intern ("face-set-after-frame-default"); + staticpro (&Qface_set_after_frame_default); + + Fput (Qundefined_color, Qerror_conditions, + Fcons (Qundefined_color, Fcons (Qerror, Qnil))); + Fput (Qundefined_color, Qerror_message, + build_string ("Undefined color")); + + init_x_parm_symbols (); + + DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path, + "List of directories to search for bitmap files for w32."); + Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH"); + + DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape, + "The shape of the pointer when over text.\n\ +Changing the value does not affect existing frames\n\ +unless you set the mouse color."); + Vx_pointer_shape = Qnil; + + DEFVAR_LISP ("x-resource-name", &Vx_resource_name, + "The name Emacs uses to look up resources; for internal use only.\n\ +`x-get-resource' uses this as the first component of the instance name\n\ +when requesting resource values.\n\ +Emacs initially sets `x-resource-name' to the name under which Emacs\n\ +was invoked, or to the value specified with the `-name' or `-rn'\n\ +switches, if present."); + Vx_resource_name = Qnil; + + Vx_nontext_pointer_shape = Qnil; + + Vx_mode_pointer_shape = Qnil; + + DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape, + "The shape of the pointer when Emacs is busy.\n\ +This variable takes effect when you create a new frame\n\ +or when you set the mouse color."); + Vx_busy_pointer_shape = Qnil; + + DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p, + "Non-zero means Emacs displays a busy cursor on window systems."); + display_busy_cursor_p = 1; + + DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay, + "*Seconds to wait before displaying a busy-cursor.\n\ +Value must be an integer or float."); + Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY); + + DEFVAR_LISP ("x-sensitive-text-pointer-shape", + &Vx_sensitive_text_pointer_shape, + "The shape of the pointer when over mouse-sensitive text.\n\ +This variable takes effect when you create a new frame\n\ +or when you set the mouse color."); + Vx_sensitive_text_pointer_shape = Qnil; + + DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel, + "A string indicating the foreground color of the cursor box."); + Vx_cursor_fore_pixel = Qnil; + + DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager, + "Non-nil if no window manager is in use.\n\ +Emacs doesn't try to figure this out; this is always nil\n\ +unless you set it to something else."); + /* We don't have any way to find this out, so set it to nil + and maybe the user would like to set it to t. */ + Vx_no_window_manager = Qnil; + + DEFVAR_LISP ("x-pixel-size-width-font-regexp", + &Vx_pixel_size_width_font_regexp, + "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\ +\n\ +Since Emacs gets width of a font matching with this regexp from\n\ +PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\ +such a font. This is especially effective for such large fonts as\n\ +Chinese, Japanese, and Korean."); + Vx_pixel_size_width_font_regexp = Qnil; + + DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, + "Time after which cached images are removed from the cache.\n\ +When an image has not been displayed this many seconds, remove it\n\ +from the image cache. Value must be an integer or nil with nil\n\ +meaning don't clear the cache."); + Vimage_cache_eviction_delay = make_number (30 * 60); + +#if 0 /* MAC_TODO: implement get X resource */ + defsubr (&Sx_get_resource); +#endif + defsubr (&Sx_change_window_property); + defsubr (&Sx_delete_window_property); + defsubr (&Sx_window_property); + defsubr (&Sxw_display_color_p); + defsubr (&Sx_display_grayscale_p); + defsubr (&Sxw_color_defined_p); + defsubr (&Sxw_color_values); + defsubr (&Sx_server_max_request_size); + defsubr (&Sx_server_vendor); + defsubr (&Sx_server_version); + defsubr (&Sx_display_pixel_width); + defsubr (&Sx_display_pixel_height); + defsubr (&Sx_display_mm_width); + defsubr (&Sx_display_mm_height); + defsubr (&Sx_display_screens); + defsubr (&Sx_display_planes); + defsubr (&Sx_display_color_cells); + defsubr (&Sx_display_visual_class); + defsubr (&Sx_display_backing_store); + defsubr (&Sx_display_save_under); +#if 0 /* MAC_TODO: implement XParseGeometry */ + defsubr (&Sx_parse_geometry); +#endif + defsubr (&Sx_create_frame); +#if 0 /* MAC_TODO: implement network support */ + defsubr (&Sx_open_connection); + defsubr (&Sx_close_connection); +#endif + defsubr (&Sx_display_list); + defsubr (&Sx_synchronize); + + /* Setting callback functions for fontset handler. */ + get_font_info_func = x_get_font_info; + +#if 0 /* This function pointer doesn't seem to be used anywhere. + And the pointer assigned has the wrong type, anyway. */ + list_fonts_func = x_list_fonts; +#endif + + load_font_func = x_load_font; + find_ccl_program_func = x_find_ccl_program; + query_font_func = x_query_font; + + set_frame_fontset_func = x_set_font; + check_window_system_func = check_mac; + +#if 0 /* MAC_TODO: Image support for Mac Images. */ + Qxbm = intern ("xbm"); + staticpro (&Qxbm); + QCtype = intern (":type"); + staticpro (&QCtype); + QCalgorithm = intern (":algorithm"); + staticpro (&QCalgorithm); + QCheuristic_mask = intern (":heuristic-mask"); + staticpro (&QCheuristic_mask); + QCcolor_symbols = intern (":color-symbols"); + staticpro (&QCcolor_symbols); + QCascent = intern (":ascent"); + staticpro (&QCascent); + QCmargin = intern (":margin"); + staticpro (&QCmargin); + QCrelief = intern (":relief"); + staticpro (&QCrelief); + Qpostscript = intern ("postscript"); + staticpro (&Qpostscript); + QCloader = intern (":loader"); + staticpro (&QCloader); + QCbounding_box = intern (":bounding-box"); + staticpro (&QCbounding_box); + QCpt_width = intern (":pt-width"); + staticpro (&QCpt_width); + QCpt_height = intern (":pt-height"); + staticpro (&QCpt_height); + QCindex = intern (":index"); + staticpro (&QCindex); + Qpbm = intern ("pbm"); + staticpro (&Qpbm); + +#if HAVE_XPM + Qxpm = intern ("xpm"); + staticpro (&Qxpm); +#endif + +#if HAVE_JPEG + Qjpeg = intern ("jpeg"); + staticpro (&Qjpeg); +#endif + +#if HAVE_TIFF + Qtiff = intern ("tiff"); + staticpro (&Qtiff); +#endif + +#if HAVE_GIF + Qgif = intern ("gif"); + staticpro (&Qgif); +#endif + +#if HAVE_PNG + Qpng = intern ("png"); + staticpro (&Qpng); +#endif + + defsubr (&Sclear_image_cache); + +#if GLYPH_DEBUG + defsubr (&Simagep); + defsubr (&Slookup_image); +#endif +#endif /* MAC_TODO */ + + busy_cursor_atimer = NULL; + busy_cursor_shown_p = 0; + + defsubr (&Sx_show_tip); + defsubr (&Sx_hide_tip); + staticpro (&tip_timer); + tip_timer = Qnil; + +#if 0 /* MAC_TODO */ + defsubr (&Sx_file_dialog); +#endif +} + + +void +init_xfns () +{ + image_types = NULL; + Vimage_types = Qnil; + + define_image_type (&xbm_type); +#if 0 /* NTEMACS_TODO : Image support for W32 */ + define_image_type (&gs_type); + define_image_type (&pbm_type); + +#if HAVE_XPM + define_image_type (&xpm_type); +#endif + +#if HAVE_JPEG + define_image_type (&jpeg_type); +#endif + +#if HAVE_TIFF + define_image_type (&tiff_type); +#endif + +#if HAVE_GIF + define_image_type (&gif_type); +#endif + +#if HAVE_PNG + define_image_type (&png_type); +#endif +#endif /* NTEMACS_TODO */ +} + +#undef abort + +#if 0 +void +w32_abort() +{ + int button; + button = MessageBox (NULL, + "A fatal error has occurred!\n\n" + "Select Abort to exit, Retry to debug, Ignore to continue", + "Emacs Abort Dialog", + MB_ICONEXCLAMATION | MB_TASKMODAL + | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE); + switch (button) + { + case IDRETRY: + DebugBreak (); + break; + case IDIGNORE: + break; + case IDABORT: + default: + abort (); + break; + } +} + +/* For convenience when debugging. */ +int +w32_last_error() +{ + return GetLastError (); +} +#endif diff --git a/mac/src/macmenu.c b/mac/src/macmenu.c new file mode 100644 index 00000000000..ac697cf7490 --- /dev/null +++ b/mac/src/macmenu.c @@ -0,0 +1,2206 @@ +/* Menu support for GNU Emacs on the for Mac OS. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include +#include + +#include +#include "lisp.h" +#include "termhooks.h" +#include "frame.h" +#include "window.h" +#include "keyboard.h" +#include "blockinput.h" +#include "buffer.h" +#include "charset.h" +#include "coding.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#if defined (__MRC__) || defined (CODEWARRIOR_VERSION_6) +#include +#endif + +/* This may include sys/types.h, and that somehow loses + if this is not done before the other system files. */ +#include "macterm.h" + +/* Load sys/types.h if not already loaded. + In some systems loading it twice is suicidal. */ +#ifndef makedev +#include +#endif + +#include "dispextern.h" + +#define POPUP_SUBMENU_ID 235 +#define MIN_MENU_ID 256 +#define MIN_SUBMENU_ID 1 + +#define DIALOG_WINDOW_RESOURCE 130 + +#define HAVE_DIALOGS 1 + +#undef HAVE_MULTILINGUAL_MENU + +/******************************************************************/ +/* Definitions copied from lwlib.h */ + +typedef void * XtPointer; + +#define True 1 +#define False 0 + +enum button_type +{ + BUTTON_TYPE_NONE, + BUTTON_TYPE_TOGGLE, + BUTTON_TYPE_RADIO +}; + +typedef struct _widget_value +{ + /* name of widget */ + char* name; + /* value (meaning depend on widget type) */ + char* value; + /* keyboard equivalent. no implications for XtTranslations */ + char* key; + /* Help string or null if none. */ + char *help; + /* true if enabled */ + Boolean enabled; + /* true if selected */ + Boolean selected; + /* The type of a button. */ + enum button_type button_type; + /* true if menu title */ + Boolean title; +#if 0 + /* true if was edited (maintained by get_value) */ + Boolean edited; + /* true if has changed (maintained by lw library) */ + change_type change; + /* true if this widget itself has changed, + but not counting the other widgets found in the `next' field. */ + change_type this_one_change; +#endif + /* Contents of the sub-widgets, also selected slot for checkbox */ + struct _widget_value* contents; + /* data passed to callback */ + XtPointer call_data; + /* next one in the list */ + struct _widget_value* next; +#if 0 + /* slot for the toolkit dependent part. Always initialize to NULL. */ + void* toolkit_data; + /* tell us if we should free the toolkit data slot when freeing the + widget_value itself. */ + Boolean free_toolkit_data; + + /* we resource the widget_value structures; this points to the next + one on the free list if this one has been deallocated. + */ + struct _widget_value *free_list; +#endif +} widget_value; + +/* Assumed by other routines to zero area returned. */ +#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\ + 0, (sizeof (widget_value))) +#define free_widget_value(wv) xfree (wv) + +/******************************************************************/ + +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define max(x,y) (((x) > (y)) ? (x) : (y)) + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif /* no TRUE */ + +Lisp_Object Vmenu_updating_frame; + +Lisp_Object Qdebug_on_next_call; + +extern Lisp_Object Qmenu_bar; +extern Lisp_Object Qmouse_click, Qevent_kind; + +extern Lisp_Object QCtoggle, QCradio; + +extern Lisp_Object Voverriding_local_map; +extern Lisp_Object Voverriding_local_map_menu_flag; + +extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; + +extern Lisp_Object Qmenu_bar_update_hook; + +void set_frame_menubar (); + +static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, + Lisp_Object, Lisp_Object, Lisp_Object, + Lisp_Object, Lisp_Object)); +static Lisp_Object mac_dialog_show (); +static Lisp_Object mac_menu_show (); + +static void keymap_panes (); +static void single_keymap_panes (); +static void single_menu_item (); +static void list_of_panes (); +static void list_of_items (); + +static void fill_submenu (MenuHandle, widget_value *, int); +static void fill_menubar (widget_value *); + + +/* This holds a Lisp vector that holds the results of decoding + the keymaps or alist-of-alists that specify a menu. + + It describes the panes and items within the panes. + + Each pane is described by 3 elements in the vector: + t, the pane name, the pane's prefix key. + Then follow the pane's items, with 5 elements per item: + the item string, the enable flag, the item's value, + the definition, and the equivalent keyboard key's description string. + + In some cases, multiple levels of menus may be described. + A single vector slot containing nil indicates the start of a submenu. + A single vector slot containing lambda indicates the end of a submenu. + The submenu follows a menu item which is the way to reach the submenu. + + A single vector slot containing quote indicates that the + following items should appear on the right of a dialog box. + + Using a Lisp vector to hold this information while we decode it + takes care of protecting all the data from GC. */ + +#define MENU_ITEMS_PANE_NAME 1 +#define MENU_ITEMS_PANE_PREFIX 2 +#define MENU_ITEMS_PANE_LENGTH 3 + +enum menu_item_idx +{ + MENU_ITEMS_ITEM_NAME = 0, + MENU_ITEMS_ITEM_ENABLE, + MENU_ITEMS_ITEM_VALUE, + MENU_ITEMS_ITEM_EQUIV_KEY, + MENU_ITEMS_ITEM_DEFINITION, + MENU_ITEMS_ITEM_TYPE, + MENU_ITEMS_ITEM_SELECTED, + MENU_ITEMS_ITEM_HELP, + MENU_ITEMS_ITEM_LENGTH +}; + +static Lisp_Object menu_items; + +/* Number of slots currently allocated in menu_items. */ +static int menu_items_allocated; + +/* This is the index in menu_items of the first empty slot. */ +static int menu_items_used; + +/* The number of panes currently recorded in menu_items, + excluding those within submenus. */ +static int menu_items_n_panes; + +/* Current depth within submenus. */ +static int menu_items_submenu_depth; + +/* Flag which when set indicates a dialog or menu has been posted by + Xt on behalf of one of the widget sets. */ +static int popup_activated_flag; + +static int next_menubar_widget_id; + +/* This is set nonzero after the user activates the menu bar, and set + to zero again after the menu bars are redisplayed by prepare_menu_bar. + While it is nonzero, all calls to set_frame_menubar go deep. + + I don't understand why this is needed, but it does seem to be + needed on Motif, according to Marcus Daniels . */ + +int pending_menu_activation; + +/* Initialize the menu_items structure if we haven't already done so. + Also mark it as currently empty. */ + +static void +init_menu_items () +{ + if (NILP (menu_items)) + { + menu_items_allocated = 60; + menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil); + } + + menu_items_used = 0; + menu_items_n_panes = 0; + menu_items_submenu_depth = 0; +} + +/* Call at the end of generating the data in menu_items. + This fills in the number of items in the last pane. */ + +static void +finish_menu_items () +{ +} + +/* Call when finished using the data for the current menu + in menu_items. */ + +static void +discard_menu_items () +{ + /* Free the structure if it is especially large. + Otherwise, hold on to it, to save time. */ + if (menu_items_allocated > 200) + { + menu_items = Qnil; + menu_items_allocated = 0; + } +} + +/* Make the menu_items vector twice as large. */ + +static void +grow_menu_items () +{ + Lisp_Object old; + int old_size = menu_items_allocated; + old = menu_items; + + menu_items_allocated *= 2; + menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil); + bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents, + old_size * sizeof (Lisp_Object)); +} + +/* Begin a submenu. */ + +static void +push_submenu_start () +{ + if (menu_items_used + 1 > menu_items_allocated) + grow_menu_items (); + + XVECTOR (menu_items)->contents[menu_items_used++] = Qnil; + menu_items_submenu_depth++; +} + +/* End a submenu. */ + +static void +push_submenu_end () +{ + if (menu_items_used + 1 > menu_items_allocated) + grow_menu_items (); + + XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda; + menu_items_submenu_depth--; +} + +/* Indicate boundary between left and right. */ + +static void +push_left_right_boundary () +{ + if (menu_items_used + 1 > menu_items_allocated) + grow_menu_items (); + + XVECTOR (menu_items)->contents[menu_items_used++] = Qquote; +} + +/* Start a new menu pane in menu_items.. + NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */ + +static void +push_menu_pane (name, prefix_vec) + Lisp_Object name, prefix_vec; +{ + if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated) + grow_menu_items (); + + if (menu_items_submenu_depth == 0) + menu_items_n_panes++; + XVECTOR (menu_items)->contents[menu_items_used++] = Qt; + XVECTOR (menu_items)->contents[menu_items_used++] = name; + XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec; +} + +/* Push one menu item into the current pane. NAME is the string to + display. ENABLE if non-nil means this item can be selected. KEY + is the key generated by choosing this item, or nil if this item + doesn't really have a definition. DEF is the definition of this + item. EQUIV is the textual description of the keyboard equivalent + for this item (or nil if none). TYPE is the type of this menu + item, one of nil, `toggle' or `radio'. */ + +static void +push_menu_item (name, enable, key, def, equiv, type, selected, help) + Lisp_Object name, enable, key, def, equiv, type, selected, help; +{ + if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated) + grow_menu_items (); + + XVECTOR (menu_items)->contents[menu_items_used++] = name; + XVECTOR (menu_items)->contents[menu_items_used++] = enable; + XVECTOR (menu_items)->contents[menu_items_used++] = key; + XVECTOR (menu_items)->contents[menu_items_used++] = equiv; + XVECTOR (menu_items)->contents[menu_items_used++] = def; + XVECTOR (menu_items)->contents[menu_items_used++] = type; + XVECTOR (menu_items)->contents[menu_items_used++] = selected; + XVECTOR (menu_items)->contents[menu_items_used++] = help; +} + +/* Look through KEYMAPS, a vector of keymaps that is NMAPS long, + and generate menu panes for them in menu_items. + If NOTREAL is nonzero, + don't bother really computing whether an item is enabled. */ + +static void +keymap_panes (keymaps, nmaps, notreal) + Lisp_Object *keymaps; + int nmaps; + int notreal; +{ + int mapno; + + init_menu_items (); + + /* Loop over the given keymaps, making a pane for each map. + But don't make a pane that is empty--ignore that map instead. + P is the number of panes we have made so far. */ + for (mapno = 0; mapno < nmaps; mapno++) + single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10); + + finish_menu_items (); +} + +/* This is a recursive subroutine of keymap_panes. + It handles one keymap, KEYMAP. + The other arguments are passed along + or point to local variables of the previous function. + If NOTREAL is nonzero, only check for equivalent key bindings, don't + evaluate expressions in menu items and don't make any menu. + + If we encounter submenus deeper than MAXDEPTH levels, ignore them. */ + +static void +single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth) + Lisp_Object keymap; + Lisp_Object pane_name; + Lisp_Object prefix; + int notreal; + int maxdepth; +{ + Lisp_Object pending_maps = Qnil; + Lisp_Object tail, item; + struct gcpro gcpro1, gcpro2; + + if (maxdepth <= 0) + return; + + push_menu_pane (pane_name, prefix); + + for (tail = keymap; CONSP (tail); tail = XCDR (tail)) + { + GCPRO2 (keymap, pending_maps); + /* Look at each key binding, and if it is a menu item add it + to this menu. */ + item = XCAR (tail); + if (CONSP (item)) + single_menu_item (XCAR (item), XCDR (item), + &pending_maps, notreal, maxdepth); + else if (VECTORP (item)) + { + /* Loop over the char values represented in the vector. */ + int len = XVECTOR (item)->size; + int c; + for (c = 0; c < len; c++) + { + Lisp_Object character; + XSETFASTINT (character, c); + single_menu_item (character, XVECTOR (item)->contents[c], + &pending_maps, notreal, maxdepth); + } + } + UNGCPRO; + } + + /* Process now any submenus which want to be panes at this level. */ + while (!NILP (pending_maps)) + { + Lisp_Object elt, eltcdr, string; + elt = Fcar (pending_maps); + eltcdr = XCDR (elt); + string = XCAR (eltcdr); + /* We no longer discard the @ from the beginning of the string here. + Instead, we do this in mac_menu_show. */ + single_keymap_panes (Fcar (elt), string, + XCDR (eltcdr), notreal, maxdepth - 1); + pending_maps = Fcdr (pending_maps); + } +} + +/* This is a subroutine of single_keymap_panes that handles one + keymap entry. + KEY is a key in a keymap and ITEM is its binding. + PENDING_MAPS_PTR points to a list of keymaps waiting to be made into + separate panes. + If NOTREAL is nonzero, only check for equivalent key bindings, don't + evaluate expressions in menu items and don't make any menu. + If we encounter submenus deeper than MAXDEPTH levels, ignore them. */ + +static void +single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth) + Lisp_Object key, item; + Lisp_Object *pending_maps_ptr; + int maxdepth, notreal; +{ + Lisp_Object map, item_string, enabled; + struct gcpro gcpro1, gcpro2; + int res; + + /* Parse the menu item and leave the result in item_properties. */ + GCPRO2 (key, item); + res = parse_menu_item (item, notreal, 0); + UNGCPRO; + if (!res) + return; /* Not a menu item. */ + + map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; + + if (notreal) + { + /* We don't want to make a menu, just traverse the keymaps to + precompute equivalent key bindings. */ + if (!NILP (map)) + single_keymap_panes (map, Qnil, key, 1, maxdepth - 1); + return; + } + + enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; + item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; + + if (!NILP (map) && XSTRING (item_string)->data[0] == '@') + { + if (!NILP (enabled)) + /* An enabled separate pane. Remember this to handle it later. */ + *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)), + *pending_maps_ptr); + return; + } + + push_menu_item (item_string, enabled, key, + XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF], + XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ], + XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE], + XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], + XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); + + /* Display a submenu using the toolkit. */ + if (! (NILP (map) || NILP (enabled))) + { + push_submenu_start (); + single_keymap_panes (map, Qnil, key, 0, maxdepth - 1); + push_submenu_end (); + } +} + +/* Push all the panes and items of a menu described by the + alist-of-alists MENU. + This handles old-fashioned calls to x-popup-menu. */ + +static void +list_of_panes (menu) + Lisp_Object menu; +{ + Lisp_Object tail; + + init_menu_items (); + + for (tail = menu; !NILP (tail); tail = Fcdr (tail)) + { + Lisp_Object elt, pane_name, pane_data; + elt = Fcar (tail); + pane_name = Fcar (elt); + CHECK_STRING (pane_name, 0); + push_menu_pane (pane_name, Qnil); + pane_data = Fcdr (elt); + CHECK_CONS (pane_data, 0); + list_of_items (pane_data); + } + + finish_menu_items (); +} + +/* Push the items in a single pane defined by the alist PANE. */ + +static void +list_of_items (pane) + Lisp_Object pane; +{ + Lisp_Object tail, item, item1; + + for (tail = pane; !NILP (tail); tail = Fcdr (tail)) + { + item = Fcar (tail); + if (STRINGP (item)) + push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil); + else if (NILP (item)) + push_left_right_boundary (); + else + { + CHECK_CONS (item, 0); + item1 = Fcar (item); + CHECK_STRING (item1, 1); + push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil); + } + } +} + +DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, + "Pop up a deck-of-cards menu and return user's selection.\n\ +POSITION is a position specification. This is either a mouse button event\n\ +or a list ((XOFFSET YOFFSET) WINDOW)\n\ +where XOFFSET and YOFFSET are positions in pixels from the top left\n\ +corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\ +This controls the position of the center of the first line\n\ +in the first pane of the menu, not the top left of the menu as a whole.\n\ +If POSITION is t, it means to use the current mouse position.\n\ +\n\ +MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\ +The menu items come from key bindings that have a menu string as well as\n\ +a definition; actually, the \"definition\" in such a key binding looks like\n\ +\(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\ +the keymap as a top-level element.\n\n\ +If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.\n\ +Otherwise, REAL-DEFINITION should be a valid key binding definition.\n\ +\n\ +You can also use a list of keymaps as MENU.\n\ + Then each keymap makes a separate pane.\n\ +When MENU is a keymap or a list of keymaps, the return value\n\ +is a list of events.\n\n\ +\n\ +Alternatively, you can specify a menu of multiple panes\n\ + with a list of the form (TITLE PANE1 PANE2...),\n\ +where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\ +Each ITEM is normally a cons cell (STRING . VALUE);\n\ +but a string can appear as an item--that makes a nonselectable line\n\ +in the menu.\n\ +With this form of menu, the return value is VALUE from the chosen item.\n\ +\n\ +If POSITION is nil, don't display the menu at all, just precalculate the\n\ +cached information about equivalent key sequences.") + (position, menu) + Lisp_Object position, menu; +{ + Lisp_Object keymap, tem; + int xpos, ypos; + Lisp_Object title; + char *error_name; + Lisp_Object selection; + FRAME_PTR f; + Lisp_Object x, y, window; + int keymaps = 0; + int for_click = 0; + struct gcpro gcpro1; + +#ifdef HAVE_MENUS + if (! NILP (position)) + { + check_mac (); + + /* Decode the first argument: find the window and the coordinates. */ + if (EQ (position, Qt) + || (CONSP (position) && EQ (XCAR (position), Qmenu_bar))) + { + /* Use the mouse's current position. */ + FRAME_PTR new_f = SELECTED_FRAME (); + Lisp_Object bar_window; + enum scroll_bar_part part; + unsigned long time; + + if (mouse_position_hook) + (*mouse_position_hook) (&new_f, 1, &bar_window, + &part, &x, &y, &time); + if (new_f != 0) + XSETFRAME (window, new_f); + else + { + window = selected_window; + XSETFASTINT (x, 0); + XSETFASTINT (y, 0); + } + } + else + { + tem = Fcar (position); + if (CONSP (tem)) + { + window = Fcar (Fcdr (position)); + x = Fcar (tem); + y = Fcar (Fcdr (tem)); + } + else + { + for_click = 1; + tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ + window = Fcar (tem); /* POSN_WINDOW (tem) */ + tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */ + x = Fcar (tem); + y = Fcdr (tem); + } + } + + CHECK_NUMBER (x, 0); + CHECK_NUMBER (y, 0); + + /* Decode where to put the menu. */ + + if (FRAMEP (window)) + { + f = XFRAME (window); + xpos = 0; + ypos = 0; + } + else if (WINDOWP (window)) + { + CHECK_LIVE_WINDOW (window, 0); + f = XFRAME (WINDOW_FRAME (XWINDOW (window))); + + xpos = (FONT_WIDTH (FRAME_FONT (f)) + * XFASTINT (XWINDOW (window)->left)); + ypos = (FRAME_LINE_HEIGHT (f) + * XFASTINT (XWINDOW (window)->top)); + } + else + /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, + but I don't want to make one now. */ + CHECK_WINDOW (window, 0); + + xpos += XINT (x); + ypos += XINT (y); + + XSETFRAME (Vmenu_updating_frame, f); + } + Vmenu_updating_frame = Qnil; +#endif /* HAVE_MENUS */ + + title = Qnil; + GCPRO1 (title); + + /* Decode the menu items from what was specified. */ + + keymap = Fkeymapp (menu); + tem = Qnil; + if (CONSP (menu)) + tem = Fkeymapp (Fcar (menu)); + if (!NILP (keymap)) + { + /* We were given a keymap. Extract menu info from the keymap. */ + Lisp_Object prompt; + keymap = get_keymap (menu); + + /* Extract the detailed info to make one pane. */ + keymap_panes (&menu, 1, NILP (position)); + + /* Search for a string appearing directly as an element of the keymap. + That string is the title of the menu. */ + prompt = map_prompt (keymap); + if (NILP (title) && !NILP (prompt)) + title = prompt; + + /* Make that be the pane title of the first pane. */ + if (!NILP (prompt) && menu_items_n_panes >= 0) + XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt; + + keymaps = 1; + } + else if (!NILP (tem)) + { + /* We were given a list of keymaps. */ + int nmaps = XFASTINT (Flength (menu)); + Lisp_Object *maps + = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object)); + int i; + + title = Qnil; + + /* The first keymap that has a prompt string + supplies the menu title. */ + for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem)) + { + Lisp_Object prompt; + + maps[i++] = keymap = get_keymap (Fcar (tem)); + + prompt = map_prompt (keymap); + if (NILP (title) && !NILP (prompt)) + title = prompt; + } + + /* Extract the detailed info to make one pane. */ + keymap_panes (maps, nmaps, NILP (position)); + + /* Make the title be the pane title of the first pane. */ + if (!NILP (title) && menu_items_n_panes >= 0) + XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title; + + keymaps = 1; + } + else + { + /* We were given an old-fashioned menu. */ + title = Fcar (menu); + CHECK_STRING (title, 1); + + list_of_panes (Fcdr (menu)); + + keymaps = 0; + } + + if (NILP (position)) + { + discard_menu_items (); + UNGCPRO; + return Qnil; + } + +#ifdef HAVE_MENUS + /* Display them in a menu. */ + BLOCK_INPUT; + + selection = mac_menu_show (f, xpos, ypos, for_click, + keymaps, title, &error_name); + UNBLOCK_INPUT; + + discard_menu_items (); + + UNGCPRO; +#endif /* HAVE_MENUS */ + + if (error_name) error (error_name); + return selection; +} + +#ifdef HAVE_MENUS + +DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0, + "Pop up a dialog box and return user's selection.\n\ +POSITION specifies which frame to use.\n\ +This is normally a mouse button event or a window or frame.\n\ +If POSITION is t, it means to use the frame the mouse is on.\n\ +The dialog box appears in the middle of the specified frame.\n\ +\n\ +CONTENTS specifies the alternatives to display in the dialog box.\n\ +It is a list of the form (TITLE ITEM1 ITEM2...).\n\ +Each ITEM is a cons cell (STRING . VALUE).\n\ +The return value is VALUE from the chosen item.\n\n\ +An ITEM may also be just a string--that makes a nonselectable item.\n\ +An ITEM may also be nil--that means to put all preceding items\n\ +on the left of the dialog box and all following items on the right.\n\ +\(By default, approximately half appear on each side.)") + (position, contents) + Lisp_Object position, contents; +{ + FRAME_PTR f; + Lisp_Object window; + + check_mac (); + + /* Decode the first argument: find the window or frame to use. */ + if (EQ (position, Qt) + || (CONSP (position) && EQ (XCAR (position), Qmenu_bar))) + { +#if 0 /* Using the frame the mouse is on may not be right. */ + /* Use the mouse's current position. */ + FRAME_PTR new_f = SELECTED_FRAME (); + Lisp_Object bar_window; + int part; + unsigned long time; + Lisp_Object x, y; + + (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time); + + if (new_f != 0) + XSETFRAME (window, new_f); + else + window = selected_window; +#endif + window = selected_window; + } + else if (CONSP (position)) + { + Lisp_Object tem; + tem = Fcar (position); + if (CONSP (tem)) + window = Fcar (Fcdr (position)); + else + { + tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ + window = Fcar (tem); /* POSN_WINDOW (tem) */ + } + } + else if (WINDOWP (position) || FRAMEP (position)) + window = position; + else + window = Qnil; + + /* Decode where to put the menu. */ + + if (FRAMEP (window)) + f = XFRAME (window); + else if (WINDOWP (window)) + { + CHECK_LIVE_WINDOW (window, 0); + f = XFRAME (WINDOW_FRAME (XWINDOW (window))); + } + else + /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, + but I don't want to make one now. */ + CHECK_WINDOW (window, 0); + +#ifndef HAVE_DIALOGS + /* Display a menu with these alternatives + in the middle of frame F. */ + { + Lisp_Object x, y, frame, newpos; + XSETFRAME (frame, f); + XSETINT (x, x_pixel_width (f) / 2); + XSETINT (y, x_pixel_height (f) / 2); + newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil)); + + return Fx_popup_menu (newpos, + Fcons (Fcar (contents), Fcons (contents, Qnil))); + } +#else /* HAVE_DIALOGS */ + { + Lisp_Object title; + char *error_name; + Lisp_Object selection; + + /* Decode the dialog items from what was specified. */ + title = Fcar (contents); + CHECK_STRING (title, 1); + + list_of_panes (Fcons (contents, Qnil)); + + /* Display them in a dialog box. */ + BLOCK_INPUT; + selection = mac_dialog_show (f, 0, title, &error_name); + UNBLOCK_INPUT; + + discard_menu_items (); + + if (error_name) error (error_name); + return selection; + } +#endif /* HAVE_DIALOGS */ +} + +/* Activate the menu bar of frame F. + This is called from keyboard.c when it gets the + menu_bar_activate_event out of the Emacs event queue. + + To activate the menu bar, we signal to the input thread that it can + return from the WM_INITMENU message, allowing the normal Windows + processing of the menus. + + But first we recompute the menu bar contents (the whole tree). + + This way we can safely execute Lisp code. */ + +void +x_activate_menubar (f) + FRAME_PTR f; +{ + SInt32 menu_choice; + extern Point saved_menu_event_location; + + set_frame_menubar (f, 0, 1); + BLOCK_INPUT; + + menu_choice = MenuSelect (saved_menu_event_location); + do_menu_choice (menu_choice); + + UNBLOCK_INPUT; +} + +/* This callback is called from the menu bar pulldown menu + when the user makes a selection. + Figure out what the user chose + and put the appropriate events into the keyboard buffer. */ + +void +menubar_selection_callback (FRAME_PTR f, int client_data) +{ + Lisp_Object prefix, entry; + Lisp_Object vector; + Lisp_Object *subprefix_stack; + int submenu_depth = 0; + int i; + + if (!f) + return; + subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object)); + vector = f->menu_bar_vector; + prefix = Qnil; + i = 0; + while (i < f->menu_bar_items_used) + { + if (EQ (XVECTOR (vector)->contents[i], Qnil)) + { + subprefix_stack[submenu_depth++] = prefix; + prefix = entry; + i++; + } + else if (EQ (XVECTOR (vector)->contents[i], Qlambda)) + { + prefix = subprefix_stack[--submenu_depth]; + i++; + } + else if (EQ (XVECTOR (vector)->contents[i], Qt)) + { + prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX]; + i += MENU_ITEMS_PANE_LENGTH; + } + else + { + entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE]; + if (client_data == i) + { + int j; + struct input_event buf; + Lisp_Object frame; + + XSETFRAME (frame, f); + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = frame; + kbd_buffer_store_event (&buf); + + for (j = 0; j < submenu_depth; j++) + if (!NILP (subprefix_stack[j])) + { + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = subprefix_stack[j]; + kbd_buffer_store_event (&buf); + } + + if (!NILP (prefix)) + { + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = prefix; + kbd_buffer_store_event (&buf); + } + + buf.kind = MENU_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = entry; + kbd_buffer_store_event (&buf); + +#if 0 + /* Queue this to recompute possibly updated menubar. */ + buf.kind = menu_bar_activate_event; + buf.frame_or_window = frame; + buf.arg = Qnil; + kbd_buffer_store_event (&buf); +#endif + + return; + } + i += MENU_ITEMS_ITEM_LENGTH; + } + } +} + +/* Allocate a widget_value, blocking input. */ + +widget_value * +xmalloc_widget_value () +{ + widget_value *value; + + BLOCK_INPUT; + value = malloc_widget_value (); + UNBLOCK_INPUT; + + return value; +} + +/* This recursively calls free_widget_value on the tree of widgets. + It must free all data that was malloc'ed for these widget_values. + In Emacs, many slots are pointers into the data of Lisp_Strings, and + must be left alone. */ + +void +free_menubar_widget_value_tree (wv) + widget_value *wv; +{ + if (! wv) return; + + wv->name = wv->value = wv->key = (char *) 0xDEADBEEF; + + if (wv->contents && (wv->contents != (widget_value*)1)) + { + free_menubar_widget_value_tree (wv->contents); + wv->contents = (widget_value *) 0xDEADBEEF; + } + if (wv->next) + { + free_menubar_widget_value_tree (wv->next); + wv->next = (widget_value *) 0xDEADBEEF; + } + BLOCK_INPUT; + free_widget_value (wv); + UNBLOCK_INPUT; +} + +/* Return a tree of widget_value structures for a menu bar item + whose event type is ITEM_KEY (with string ITEM_NAME) + and whose contents come from the list of keymaps MAPS. */ + +static widget_value * +single_submenu (item_key, item_name, maps) + Lisp_Object item_key, item_name, maps; +{ + widget_value *wv, *prev_wv, *save_wv, *first_wv; + int i; + int submenu_depth = 0; + Lisp_Object length; + int len; + Lisp_Object *mapvec; + widget_value **submenu_stack; + int previous_items = menu_items_used; + int top_level_items = 0; + + length = Flength (maps); + len = XINT (length); + + /* Convert the list MAPS into a vector MAPVEC. */ + mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + for (i = 0; i < len; i++) + { + mapvec[i] = Fcar (maps); + maps = Fcdr (maps); + } + + menu_items_n_panes = 0; + + /* Loop over the given keymaps, making a pane for each map. + But don't make a pane that is empty--ignore that map instead. */ + for (i = 0; i < len; i++) + { + if (SYMBOLP (mapvec[i]) + || (CONSP (mapvec[i]) + && NILP (Fkeymapp (mapvec[i])))) + { + /* Here we have a command at top level in the menu bar + as opposed to a submenu. */ + top_level_items = 1; + push_menu_pane (Qnil, Qnil); + push_menu_item (item_name, Qt, item_key, mapvec[i], + Qnil, Qnil, Qnil, Qnil); + } + else + single_keymap_panes (mapvec[i], item_name, item_key, 0, 10); + } + + /* Create a tree of widget_value objects + representing the panes and their items. */ + + submenu_stack + = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); + wv = xmalloc_widget_value (); + wv->name = "menu"; + wv->value = 0; + wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; + first_wv = wv; + save_wv = 0; + prev_wv = 0; + + /* Loop over all panes and items made during this call + and construct a tree of widget_value objects. + Ignore the panes and items made by previous calls to + single_submenu, even though those are also in menu_items. */ + i = previous_items; + while (i < menu_items_used) + { + if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) + { + submenu_stack[submenu_depth++] = save_wv; + save_wv = prev_wv; + prev_wv = 0; + i++; + } + else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) + { + prev_wv = save_wv; + save_wv = submenu_stack[--submenu_depth]; + i++; + } + else if (EQ (XVECTOR (menu_items)->contents[i], Qt) + && submenu_depth != 0) + i += MENU_ITEMS_PANE_LENGTH; + /* Ignore a nil in the item list. + It's meaningful only for dialog boxes. */ + else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + i += 1; + else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + { + /* Create a new pane. */ + Lisp_Object pane_name, prefix; + char *pane_string; + pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; + prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; +#ifndef HAVE_MULTILINGUAL_MENU + if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) + pane_name = string_make_unibyte (pane_name); +#endif + pane_string = (NILP (pane_name) + ? "" : (char *) XSTRING (pane_name)->data); + /* If there is just one top-level pane, put all its items directly + under the top-level menu. */ + if (menu_items_n_panes == 1) + pane_string = ""; + + /* If the pane has a meaningful name, + make the pane a top-level menu item + with its items as a submenu beneath it. */ + if (strcmp (pane_string, "")) + { + wv = xmalloc_widget_value (); + if (save_wv) + save_wv->next = wv; + else + first_wv->contents = wv; + wv->name = pane_string; + /* Ignore the @ that means "separate pane". + This is a kludge, but this isn't worth more time. */ + if (!NILP (prefix) && wv->name[0] == '@') + wv->name++; + wv->value = 0; + wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; + } + save_wv = wv; + prev_wv = 0; + i += MENU_ITEMS_PANE_LENGTH; + } + else + { + /* Create a new item within current pane. */ + Lisp_Object item_name, enable, descrip, def, type, selected; + Lisp_Object help; + + item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; + enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; + descrip + = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; + def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION]; + type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE]; + selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED]; + help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; + +#ifndef HAVE_MULTILINGUAL_MENU + if (STRING_MULTIBYTE (item_name)) + item_name = string_make_unibyte (item_name); + if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) + descrip = string_make_unibyte (descrip); +#endif + + wv = xmalloc_widget_value (); + if (prev_wv) + prev_wv->next = wv; + else + save_wv->contents = wv; + + wv->name = (char *) XSTRING (item_name)->data; + if (!NILP (descrip)) + wv->key = (char *) XSTRING (descrip)->data; + wv->value = 0; + /* The EMACS_INT cast avoids a warning. There's no problem + as long as pointers have enough bits to hold small integers. */ + wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); + wv->enabled = !NILP (enable); + + if (NILP (type)) + wv->button_type = BUTTON_TYPE_NONE; + else if (EQ (type, QCradio)) + wv->button_type = BUTTON_TYPE_RADIO; + else if (EQ (type, QCtoggle)) + wv->button_type = BUTTON_TYPE_TOGGLE; + else + abort (); + + wv->selected = !NILP (selected); + if (STRINGP (help)) + wv->help = (char *) XSTRING (help)->data; + else + wv->help = NULL; + + prev_wv = wv; + + i += MENU_ITEMS_ITEM_LENGTH; + } + } + + /* If we have just one "menu item" + that was originally a button, return it by itself. */ + if (top_level_items && first_wv->contents && first_wv->contents->next == 0) + { + wv = first_wv->contents; + free_widget_value (first_wv); + return wv; + } + + return first_wv; +} + +/* Set the contents of the menubar widgets of frame F. + The argument FIRST_TIME is currently ignored; + it is set the first time this is called, from initialize_frame_menubar. */ + +void +set_frame_menubar (f, first_time, deep_p) + FRAME_PTR f; + int first_time; + int deep_p; +{ + int menubar_widget = f->output_data.mac->menubar_widget; + Lisp_Object items; + widget_value *wv, *first_wv, *prev_wv = 0; + int i; + + XSETFRAME (Vmenu_updating_frame, f); + + wv = xmalloc_widget_value (); + wv->name = "menubar"; + wv->value = 0; + wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; + first_wv = wv; + + { + /* Make a widget-value tree representing the entire menu trees. */ + + struct buffer *prev = current_buffer; + Lisp_Object buffer; + int specpdl_count = specpdl_ptr - specpdl; + int previous_menu_items_used = f->menu_bar_items_used; + Lisp_Object *previous_items + = (Lisp_Object *) alloca (previous_menu_items_used + * sizeof (Lisp_Object)); + + /* If we are making a new widget, its contents are empty, + do always reinitialize them. */ + if (! menubar_widget) + previous_menu_items_used = 0; + + buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer; + specbind (Qinhibit_quit, Qt); + /* Don't let the debugger step into this code + because it is not reentrant. */ + specbind (Qdebug_on_next_call, Qnil); + + record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil)); + if (NILP (Voverriding_local_map_menu_flag)) + { + specbind (Qoverriding_terminal_local_map, Qnil); + specbind (Qoverriding_local_map, Qnil); + } + + set_buffer_internal_1 (XBUFFER (buffer)); + + /* Run the Lucid hook. */ + call1 (Vrun_hooks, Qactivate_menubar_hook); + /* If it has changed current-menubar from previous value, + really recompute the menubar from the value. */ + if (! NILP (Vlucid_menu_bar_dirty_flag)) + call0 (Qrecompute_lucid_menubar); + safe_run_hooks (Qmenu_bar_update_hook); + FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); + + items = FRAME_MENU_BAR_ITEMS (f); + + inhibit_garbage_collection (); + + /* Save the frame's previous menu bar contents data. */ + bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items, + previous_menu_items_used * sizeof (Lisp_Object)); + + /* Fill in the current menu bar contents. */ + menu_items = f->menu_bar_vector; + menu_items_allocated = XVECTOR (menu_items)->size; + init_menu_items (); + for (i = 0; i < XVECTOR (items)->size; i += 4) + { + Lisp_Object key, string, maps; + + key = XVECTOR (items)->contents[i]; + string = XVECTOR (items)->contents[i + 1]; + maps = XVECTOR (items)->contents[i + 2]; + if (NILP (string)) + break; + + wv = single_submenu (key, string, maps); + if (prev_wv) + prev_wv->next = wv; + else + first_wv->contents = wv; + /* Don't set wv->name here; GC during the loop might relocate it. */ + wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; + prev_wv = wv; + } + + finish_menu_items (); + + set_buffer_internal_1 (prev); + unbind_to (specpdl_count, Qnil); + + /* If there has been no change in the Lisp-level contents + of the menu bar, skip redisplaying it. Just exit. */ + + for (i = 0; i < previous_menu_items_used; i++) + if (menu_items_used == i + || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i]))) + break; + if (i == menu_items_used && i == previous_menu_items_used && i != 0) + { + free_menubar_widget_value_tree (first_wv); + menu_items = Qnil; + + return; + } + + /* Now GC cannot happen during the lifetime of the widget_value, + so it's safe to store data from a Lisp_String. */ + wv = first_wv->contents; + for (i = 0; i < XVECTOR (items)->size; i += 4) + { + Lisp_Object string; + string = XVECTOR (items)->contents[i + 1]; + if (NILP (string)) + break; + wv->name = (char *) XSTRING (string)->data; + wv = wv->next; + } + + f->menu_bar_vector = menu_items; + f->menu_bar_items_used = menu_items_used; + menu_items = Qnil; + } + + /* Create or update the menu bar widget. */ + + BLOCK_INPUT; + + f->output_data.mac->menubar_widget = NULL; /* always NULL on Mac */ + + { + int i = MIN_MENU_ID; + MenuHandle menu = GetMenuHandle (i); + while (menu != NULL) + { + DeleteMenu (i); + DisposeMenu (menu); + menu = GetMenuHandle (++i); + } + + i = MIN_SUBMENU_ID; + menu = GetMenuHandle (i); + while (menu != NULL) + { + DeleteMenu (i); + DisposeMenu (menu); + menu = GetMenuHandle (++i); + } + } + + fill_menubar (first_wv->contents); + + DrawMenuBar (); + + free_menubar_widget_value_tree (first_wv); + + UNBLOCK_INPUT; +} + +/* Called from Fx_create_frame to create the initial menubar of a + frame before it is mapped, so that the window is mapped with the + menubar already there instead of us tacking it on later and + thrashing the window after it is visible. */ + +void +initialize_frame_menubar (f) + FRAME_PTR f; +{ + /* This function is called before the first chance to redisplay + the frame. It has to be, so the frame will have the right size. */ + FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); + set_frame_menubar (f, 1, 1); +} + +/* Get rid of the menu bar of frame F, and free its storage. + This is used when deleting a frame, and when turning off the menu bar. */ + +void +free_frame_menubar (f) + FRAME_PTR f; +{ + /* Nothing to do since set_frame_menubar disposes of menus before + installing new ones. */ +} + + +/* mac_menu_show actually displays a menu using the panes and items in + menu_items and returns the value selected from it; we assume input + is blocked by the caller. */ + +/* F is the frame the menu is for. + X and Y are the frame-relative specified position, + relative to the inside upper left corner of the frame F. + FOR_CLICK is nonzero if this menu was invoked for a mouse click. + KEYMAPS is 1 if this menu was specified with keymaps; + in that case, we return a list containing the chosen item's value + and perhaps also the pane's prefix. + TITLE is the specified menu title. + ERROR is a place to store an error message string in case of failure. + (We return nil on failure, but the value doesn't actually matter.) */ + +static Lisp_Object +mac_menu_show (f, x, y, for_click, keymaps, title, error) + FRAME_PTR f; + int x; + int y; + int for_click; + int keymaps; + Lisp_Object title; + char **error; +{ + int i; + int menu_item_selection; + MenuHandle menu; + Point pos; + widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; + widget_value **submenu_stack + = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); + Lisp_Object *subprefix_stack + = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); + int submenu_depth = 0; + int first_pane; + int next_release_must_exit = 0; + + *error = NULL; + + if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) + { + *error = "Empty menu"; + return Qnil; + } + + /* Create a tree of widget_value objects + representing the panes and their items. */ + wv = xmalloc_widget_value (); + wv->name = "menu"; + wv->value = 0; + wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; + first_wv = wv; + first_pane = 1; + + /* Loop over all panes and items, filling in the tree. */ + i = 0; + while (i < menu_items_used) + { + if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) + { + submenu_stack[submenu_depth++] = save_wv; + save_wv = prev_wv; + prev_wv = 0; + first_pane = 1; + i++; + } + else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) + { + prev_wv = save_wv; + save_wv = submenu_stack[--submenu_depth]; + first_pane = 0; + i++; + } + else if (EQ (XVECTOR (menu_items)->contents[i], Qt) + && submenu_depth != 0) + i += MENU_ITEMS_PANE_LENGTH; + /* Ignore a nil in the item list. + It's meaningful only for dialog boxes. */ + else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + i += 1; + else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + { + /* Create a new pane. */ + Lisp_Object pane_name, prefix; + char *pane_string; + pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; + prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; +#ifndef HAVE_MULTILINGUAL_MENU + if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) + pane_name = string_make_unibyte (pane_name); +#endif + pane_string = (NILP (pane_name) + ? "" : (char *) XSTRING (pane_name)->data); + /* If there is just one top-level pane, put all its items directly + under the top-level menu. */ + if (menu_items_n_panes == 1) + pane_string = ""; + + /* If the pane has a meaningful name, + make the pane a top-level menu item + with its items as a submenu beneath it. */ + if (!keymaps && strcmp (pane_string, "")) + { + wv = xmalloc_widget_value (); + if (save_wv) + save_wv->next = wv; + else + first_wv->contents = wv; + wv->name = pane_string; + if (keymaps && !NILP (prefix)) + wv->name++; + wv->value = 0; + wv->enabled = 1; + wv->button_type = BUTTON_TYPE_NONE; + save_wv = wv; + prev_wv = 0; + } + else if (first_pane) + { + save_wv = wv; + prev_wv = 0; + } + first_pane = 0; + i += MENU_ITEMS_PANE_LENGTH; + } + else + { + /* Create a new item within current pane. */ + Lisp_Object item_name, enable, descrip, def, type, selected, help; + + item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; + enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; + descrip + = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; + def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION]; + type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE]; + selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED]; + help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; + +#ifndef HAVE_MULTILINGUAL_MENU + if (STRING_MULTIBYTE (item_name)) + item_name = string_make_unibyte (item_name); + if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) + descrip = string_make_unibyte (descrip); +#endif + + wv = xmalloc_widget_value (); + if (prev_wv) + prev_wv->next = wv; + else + save_wv->contents = wv; + wv->name = (char *) XSTRING (item_name)->data; + if (!NILP (descrip)) + wv->key = (char *) XSTRING (descrip)->data; + wv->value = 0; + /* Use the contents index as call_data, since we are + restricted to 16-bits.. */ + wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0; + wv->enabled = !NILP (enable); + + if (NILP (type)) + wv->button_type = BUTTON_TYPE_NONE; + else if (EQ (type, QCtoggle)) + wv->button_type = BUTTON_TYPE_TOGGLE; + else if (EQ (type, QCradio)) + wv->button_type = BUTTON_TYPE_RADIO; + else + abort (); + + wv->selected = !NILP (selected); + + if (STRINGP (help)) + wv->help = (char *) XSTRING (help)->data; + else + wv->help = NULL; + + prev_wv = wv; + + i += MENU_ITEMS_ITEM_LENGTH; + } + } + + /* Deal with the title, if it is non-nil. */ + if (!NILP (title)) + { + widget_value *wv_title = xmalloc_widget_value (); + widget_value *wv_sep = xmalloc_widget_value (); + + /* Maybe replace this separator with a bitmap or owner-draw item + so that it looks better. Having two separators looks odd. */ + wv_sep->name = "--"; + wv_sep->next = first_wv->contents; + +#ifndef HAVE_MULTILINGUAL_MENU + if (STRING_MULTIBYTE (title)) + title = string_make_unibyte (title); +#endif + wv_title->name = (char *) XSTRING (title)->data; + wv_title->enabled = True; + wv_title->button_type = BUTTON_TYPE_NONE; + wv_title->next = wv_sep; + first_wv->contents = wv_title; + } + + /* Actually create the menu. */ + menu = NewMenu (POPUP_SUBMENU_ID, "\p"); + fill_submenu (menu, first_wv->contents, 0); + + /* Adjust coordinates to be root-window-relative. */ + pos.h = x; + pos.v = y; + SetPort (FRAME_MAC_WINDOW (f)); + LocalToGlobal (&pos); + + /* No selection has been chosen yet. */ + menu_item_selection = 0; + + InsertMenu (menu, -1); + + /* Display the menu. */ + menu_item_selection = LoWord (PopUpMenuSelect (menu, pos.v, pos.h, 0)); + + DeleteMenu (POPUP_SUBMENU_ID); + +#if 0 + /* Clean up extraneous mouse events which might have been generated + during the call. */ + discard_mouse_events (); +#endif + + /* Free the widget_value objects we used to specify the + contents. */ + free_menubar_widget_value_tree (first_wv); + + DisposeMenu (menu); + + /* Find the selected item, and its pane, to return the proper + value. */ + if (menu_item_selection != 0) + { + Lisp_Object prefix, entry; + + prefix = Qnil; + i = 0; + while (i < menu_items_used) + { + if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) + { + subprefix_stack[submenu_depth++] = prefix; + prefix = entry; + i++; + } + else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) + { + prefix = subprefix_stack[--submenu_depth]; + i++; + } + else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + { + prefix + = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; + i += MENU_ITEMS_PANE_LENGTH; + } + /* Ignore a nil in the item list. It's meaningful only for + dialog boxes. */ + else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + i += 1; + else + { + entry + = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; + if (menu_item_selection == i) + { + if (keymaps != 0) + { + int j; + + entry = Fcons (entry, Qnil); + if (!NILP (prefix)) + entry = Fcons (prefix, entry); + for (j = submenu_depth - 1; j >= 0; j--) + if (!NILP (subprefix_stack[j])) + entry = Fcons (subprefix_stack[j], entry); + } + return entry; + } + i += MENU_ITEMS_ITEM_LENGTH; + } + } + } + + return Qnil; +} + + +/* Construct native Mac OS menubar based on widget_value tree. */ + +static int +mac_dialog (widget_value *wv) +{ + char *dialog_name; + char *prompt; + char **button_labels; + UInt32 *ref_cons; + int nb_buttons; + int left_count; + int i; + int dialog_width; + Rect rect; + WindowPtr window_ptr; + ControlHandle ch; + int left; + EventRecord event_record; + SInt16 part_code; + int control_part_code; + Point mouse; + + dialog_name = wv->name; + nb_buttons = dialog_name[1] - '0'; + left_count = nb_buttons - (dialog_name[4] - '0'); + button_labels = (char **) alloca (sizeof (char *) * nb_buttons); + ref_cons = (int *) alloca (sizeof (UInt32) * nb_buttons); + + wv = wv->contents; + prompt = (char *) alloca (strlen (wv->value) + 1); + strcpy (prompt, wv->value); + c2pstr (prompt); + + wv = wv->next; + for (i = 0; i < nb_buttons; i++) + { + button_labels[i] = wv->value; + button_labels[i] = (char *) alloca (strlen (wv->value) + 1); + strcpy (button_labels[i], wv->value); + c2pstr (button_labels[i]); + ref_cons[i] = (UInt32) wv->call_data; + wv = wv->next; + } + + window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1); + SetPort (window_ptr); + + TextFont (0); + /* Left and right margins in the dialog are 13 pixels each.*/ + dialog_width = 14; + /* Calculate width of dialog box: 8 pixels on each side of the text + label in each button, 12 pixels between buttons. */ + for (i = 0; i < nb_buttons; i++) + dialog_width += StringWidth (button_labels[i]) + 16 + 12; + + if (left_count != 0 && nb_buttons - left_count != 0) + dialog_width += 12; + + dialog_width = max (dialog_width, StringWidth (prompt) + 26); + + SizeWindow (window_ptr, dialog_width, 78, 0); + ShowWindow (window_ptr); + + SetPort (window_ptr); + TextFont (0); + + MoveTo (13, 29); + DrawString (prompt); + + left = 13; + for (i = 0; i < nb_buttons; i++) + { + int button_width = StringWidth (button_labels[i]) + 16; + SetRect (&rect, left, 45, left + button_width, 65); + ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0, + kControlPushButtonProc, ref_cons[i]); + left += button_width + 12; + if (i == left_count - 1) + left += 12; + } + + i = 0; + while (!i) + { + if (WaitNextEvent (mDownMask, &event_record, 10, NULL)) + if (event_record.what == mouseDown) + { + part_code = FindWindow (event_record.where, &window_ptr); + if (part_code == inContent) + { + mouse = event_record.where; + GlobalToLocal (&mouse); + control_part_code = FindControl (mouse, window_ptr, &ch); + if (control_part_code == kControlButtonPart) + if (TrackControl (ch, mouse, NULL)) + i = GetControlReference (ch); + } + } + } + + DisposeWindow (window_ptr); + + return i; +} + +static char * button_names [] = { + "button1", "button2", "button3", "button4", "button5", + "button6", "button7", "button8", "button9", "button10" }; + +static Lisp_Object +mac_dialog_show (f, keymaps, title, error) + FRAME_PTR f; + int keymaps; + Lisp_Object title; + char **error; +{ + int i, nb_buttons=0; + char dialog_name[6]; + int menu_item_selection; + + widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; + + /* Number of elements seen so far, before boundary. */ + int left_count = 0; + /* 1 means we've seen the boundary between left-hand elts and + right-hand. */ + int boundary_seen = 0; + + *error = NULL; + + if (menu_items_n_panes > 1) + { + *error = "Multiple panes in dialog box"; + return Qnil; + } + + /* Create a tree of widget_value objects representing the text label + and buttons. */ + { + Lisp_Object pane_name, prefix; + char *pane_string; + pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME]; + prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX]; + pane_string = (NILP (pane_name) + ? "" : (char *) XSTRING (pane_name)->data); + prev_wv = xmalloc_widget_value (); + prev_wv->value = pane_string; + if (keymaps && !NILP (prefix)) + prev_wv->name++; + prev_wv->enabled = 1; + prev_wv->name = "message"; + first_wv = prev_wv; + + /* Loop over all panes and items, filling in the tree. */ + i = MENU_ITEMS_PANE_LENGTH; + while (i < menu_items_used) + { + + /* Create a new item within current pane. */ + Lisp_Object item_name, enable, descrip, help; + + item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; + enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; + descrip + = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; + help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; + + if (NILP (item_name)) + { + free_menubar_widget_value_tree (first_wv); + *error = "Submenu in dialog items"; + return Qnil; + } + if (EQ (item_name, Qquote)) + { + /* This is the boundary between left-side elts and + right-side elts. Stop incrementing right_count. */ + boundary_seen = 1; + i++; + continue; + } + if (nb_buttons >= 9) + { + free_menubar_widget_value_tree (first_wv); + *error = "Too many dialog items"; + return Qnil; + } + + wv = xmalloc_widget_value (); + prev_wv->next = wv; + wv->name = (char *) button_names[nb_buttons]; + if (!NILP (descrip)) + wv->key = (char *) XSTRING (descrip)->data; + wv->value = (char *) XSTRING (item_name)->data; + wv->call_data = (void *) i; + /* menu item is identified by its index in menu_items table */ + wv->enabled = !NILP (enable); + prev_wv = wv; + + if (! boundary_seen) + left_count++; + + nb_buttons++; + i += MENU_ITEMS_ITEM_LENGTH; + } + + /* If the boundary was not specified, by default put half on the + left and half on the right. */ + if (! boundary_seen) + left_count = nb_buttons - nb_buttons / 2; + + wv = xmalloc_widget_value (); + wv->name = dialog_name; + + /* Dialog boxes use a really stupid name encoding which specifies + how many buttons to use and how many buttons are on the right. + The Q means something also. */ + dialog_name[0] = 'Q'; + dialog_name[1] = '0' + nb_buttons; + dialog_name[2] = 'B'; + dialog_name[3] = 'R'; + /* Number of buttons to put on the right. */ + dialog_name[4] = '0' + nb_buttons - left_count; + dialog_name[5] = 0; + wv->contents = first_wv; + first_wv = wv; + } + + /* Actually create the dialog. */ +#ifdef HAVE_DIALOGS + menu_item_selection = mac_dialog (first_wv); +#else + menu_item_selection = 0; +#endif + + /* Free the widget_value objects we used to specify the + contents. */ + free_menubar_widget_value_tree (first_wv); + + /* Find the selected item, and its pane, to return the proper + value. */ + if (menu_item_selection != 0) + { + Lisp_Object prefix; + + prefix = Qnil; + i = 0; + while (i < menu_items_used) + { + Lisp_Object entry; + + if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + { + prefix + = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; + i += MENU_ITEMS_PANE_LENGTH; + } + else + { + entry + = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; + if (menu_item_selection == i) + { + if (keymaps != 0) + { + entry = Fcons (entry, Qnil); + if (!NILP (prefix)) + entry = Fcons (prefix, entry); + } + return entry; + } + i += MENU_ITEMS_ITEM_LENGTH; + } + } + } + + return Qnil; +} + + +/* Is this item a separator? */ +static int +name_is_separator (name) + char *name; +{ + /* Check if name string consists of only dashes ('-') */ + while (*name == '-') name++; + return (*name == '\0'); +} + +static void +add_menu_item (MenuHandle menu, widget_value *wv, int submenu, int indent, + int force_disable) +{ + Str255 item_name; + int pos, i; + + if (name_is_separator (wv->name)) + AppendMenu (menu, "\p-"); + else + { + AppendMenu (menu, "\pX"); + + pos = CountMItems (menu); + + strcpy (item_name, ""); + for (i = 0; i < indent; i++) + strcat (item_name, " "); + strcat (item_name, wv->name); + if (wv->key != NULL) + { + strcat (item_name, " "); + strcat (item_name, wv->key); + } + c2pstr (item_name); + SetMenuItemText (menu, pos, item_name); + + if (wv->enabled && !force_disable) + EnableItem (menu, pos); + else + DisableItem (menu, pos); + + /* Draw radio buttons and tickboxes. */ + { + if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE || + wv->button_type == BUTTON_TYPE_RADIO)) + SetItemMark (menu, pos, checkMark); + else + SetItemMark (menu, pos, noMark); + } + } + + SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data); + + if (submenu != NULL) + SetMenuItemHierarchicalID (menu, pos, submenu); +} + +static int submenu_id; + +/* Construct native Mac OS menubar based on widget_value tree. */ + +static void +fill_submenu (MenuHandle menu, widget_value *wv, int indent) +{ + for ( ; wv != NULL; wv = wv->next) + if (wv->contents) + { + add_menu_item (menu, wv, NULL, indent, 1); + + fill_submenu (menu, wv->contents, indent + 1); + } + else + add_menu_item (menu, wv, NULL, indent, 0); +} + + +/* Construct native Mac OS menu based on widget_value tree. */ + +static void +fill_menu (MenuHandle menu, widget_value *wv) +{ + for ( ; wv != NULL; wv = wv->next) + if (wv->contents) + { + MenuHandle submenu = NewMenu (submenu_id, "\pX"); + fill_submenu (submenu, wv->contents, 0); + InsertMenu (submenu, -1); + add_menu_item (menu, wv, submenu_id, 0, 0); + submenu_id++; + } + else + add_menu_item (menu, wv, NULL, 0, 0); +} + +/* Construct native Mac OS menubar based on widget_value tree. */ + +static void +fill_menubar (widget_value *wv) +{ + int id; + + submenu_id = MIN_SUBMENU_ID; + + for (id = MIN_MENU_ID; wv != NULL; wv = wv->next, id++) + { + MenuHandle menu; + Str255 title; + + strcpy (title, wv->name); + c2pstr (title); + menu = NewMenu (id, title); + + if (wv->contents) + fill_menu (menu, wv->contents); + + InsertMenu (menu, 0); + } +} + +#endif /* HAVE_MENUS */ + +void +syms_of_macmenu () +{ + staticpro (&menu_items); + menu_items = Qnil; + + Qdebug_on_next_call = intern ("debug-on-next-call"); + staticpro (&Qdebug_on_next_call); + + DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame, + "Frame for which we are updating a menu.\n\ +The enable predicate for a menu command should check this variable."); + Vmenu_updating_frame = Qnil; + + defsubr (&Sx_popup_menu); +#ifdef HAVE_MENUS + defsubr (&Sx_popup_dialog); +#endif +} diff --git a/mac/src/macterm.c b/mac/src/macterm.c new file mode 100644 index 00000000000..194af28b91d --- /dev/null +++ b/mac/src/macterm.c @@ -0,0 +1,12446 @@ +/* Implementation of GUI terminal on the Mac OS. + Copyright (C) 2000 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Contributed by Andrew Choi (akochoi@users.sourceforge.net). */ + +#include + +/* On 4.3 these lose if they come after xterm.h. */ +/* Putting these at the beginning seems to be standard for other .c files. */ +#include + +#include + +#include "lisp.h" +#include "blockinput.h" + +/* Need syssignal.h for various externs and definitions that may be required + by some configurations for calls to signal later in this source file. */ +#include "syssignal.h" + +/* This may include sys/types.h, and that somehow loses + if this is not done before the other system files. */ +#include "macterm.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined (__MRC__) || defined (CODEWARRIOR_VERSION_6) +#include +#endif + +#if __profile__ +#include +#endif + +#include + +#include "systty.h" +#include "systime.h" + +#ifndef INCLUDED_FCNTL +#include +#endif +#include +#include +#include +#include + +#include "charset.h" +#include "ccl.h" +#include "frame.h" +#include "dispextern.h" +#include "fontset.h" +#include "termhooks.h" +#include "termopts.h" +#include "termchar.h" +#include "gnu.h" +#include "disptab.h" +#include "buffer.h" +#include "window.h" +#include "keyboard.h" +#include "intervals.h" +#include "process.h" +#include "atimer.h" +#include "coding.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef USE_X_TOOLKIT +#define x_any_window_to_frame x_window_to_frame +#define x_top_window_to_frame x_window_to_frame +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER)) + + +/* Bitmaps for truncated lines. */ + +enum bitmap_type +{ + NO_BITMAP, + LEFT_TRUNCATION_BITMAP, + RIGHT_TRUNCATION_BITMAP, + OVERLAY_ARROW_BITMAP, + CONTINUED_LINE_BITMAP, + CONTINUATION_LINE_BITMAP, + ZV_LINE_BITMAP +}; + +/* Bitmap drawn to indicate lines not displaying text if + `indicate-empty-lines' is non-nil. */ + +#define zv_width 8 +#define zv_height 8 +static unsigned char zv_bits[] = { + 0x00, 0x00, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00}; + +/* An arrow like this: `<-'. */ + +#define left_width 8 +#define left_height 8 +static unsigned char left_bits[] = { + 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18}; + +/* Right truncation arrow bitmap `->'. */ + +#define right_width 8 +#define right_height 8 +static unsigned char right_bits[] = { + 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18}; + +/* Marker for continued lines. */ + +#define continued_width 8 +#define continued_height 8 +static unsigned char continued_bits[] = { + 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e}; + +/* Marker for continuation lines. */ + +#define continuation_width 8 +#define continuation_height 8 +static unsigned char continuation_bits[] = { + 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c}; + +/* Overlay arrow bitmap. */ + +#if 0 +/* A bomb. */ +#define ov_width 8 +#define ov_height 8 +static unsigned char ov_bits[] = { + 0x0c, 0x10, 0x3c, 0x7e, 0x5e, 0x5e, 0x46, 0x3c}; +#else +/* A triangular arrow. */ +#define ov_width 8 +#define ov_height 8 +static unsigned char ov_bits[] = { + 0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xf8, 0xf0, 0xc0}; +#endif + +extern Lisp_Object Qhelp_echo; + + +/* Non-zero means Emacs uses toolkit scroll bars. */ + +int x_toolkit_scroll_bars_p; + +/* If a string, XTread_socket generates an event to display that string. + (The display is done in read_char.) */ + +static Lisp_Object help_echo; +static Lisp_Object help_echo_window; +static Lisp_Object help_echo_object; +static int help_echo_pos; + +/* Temporary variable for XTread_socket. */ + +static Lisp_Object previous_help_echo; + +/* Non-zero means that a HELP_EVENT has been generated since Emacs + start. */ + +static int any_help_event_p; + +/* Non-zero means draw block and hollow cursor as wide as the glyph + under it. For example, if a block cursor is over a tab, it will be + drawn as wide as that tab on the display. */ + +int x_stretch_cursor_p; + +/* This is a chain of structures for all the X displays currently in + use. */ + +struct x_display_info *x_display_list; + +/* This is a list of cons cells, each of the form (NAME + . FONT-LIST-CACHE), one for each element of x_display_list and in + the same order. NAME is the name of the frame. FONT-LIST-CACHE + records previous values returned by x-list-fonts. */ + +Lisp_Object x_display_name_list; + +/* This is display since Mac does not support multiple ones. */ +struct mac_display_info one_mac_display_info; + +/* Frame being updated by update_frame. This is declared in term.c. + This is set by update_begin and looked at by all the XT functions. + It is zero while not inside an update. In that case, the XT + functions assume that `selected_frame' is the frame to apply to. */ + +extern struct frame *updating_frame; + +extern int waiting_for_input; + +/* This is a frame waiting to be auto-raised, within XTread_socket. */ + +struct frame *pending_autoraise_frame; + +/* Nominal cursor position -- where to draw output. + HPOS and VPOS are window relative glyph matrix coordinates. + X and Y are window relative pixel coordinates. */ + +struct cursor_pos output_cursor; + +/* Non-zero means user is interacting with a toolkit scroll bar. */ + +static int toolkit_scroll_bar_interaction; + +/* Mouse movement. + + Formerly, we used PointerMotionHintMask (in standard_event_mask) + so that we would have to call XQueryPointer after each MotionNotify + event to ask for another such event. However, this made mouse tracking + slow, and there was a bug that made it eventually stop. + + Simply asking for MotionNotify all the time seems to work better. + + In order to avoid asking for motion events and then throwing most + of them away or busy-polling the server for mouse positions, we ask + the server for pointer motion hints. This means that we get only + one event per group of mouse movements. "Groups" are delimited by + other kinds of events (focus changes and button clicks, for + example), or by XQueryPointer calls; when one of these happens, we + get another MotionNotify event the next time the mouse moves. This + is at least as efficient as getting motion events when mouse + tracking is on, and I suspect only negligibly worse when tracking + is off. */ + +/* Where the mouse was last time we reported a mouse event. */ + +FRAME_PTR last_mouse_frame; +static Rect last_mouse_glyph; +static Lisp_Object last_mouse_press_frame; + +/* The scroll bar in which the last X motion event occurred. + + If the last X motion event occurred in a scroll bar, we set this so + XTmouse_position can know whether to report a scroll bar motion or + an ordinary motion. + + If the last X motion event didn't occur in a scroll bar, we set + this to Qnil, to tell XTmouse_position to return an ordinary motion + event. */ + +static Lisp_Object last_mouse_scroll_bar; + +/* This is a hack. We would really prefer that XTmouse_position would + return the time associated with the position it returns, but there + doesn't seem to be any way to wrest the time-stamp from the server + along with the position query. So, we just keep track of the time + of the last movement we received, and return that in hopes that + it's somewhat accurate. */ + +static Time last_mouse_movement_time; + +enum mouse_tracking_type { + mouse_tracking_none, + mouse_tracking_mouse_movement, + mouse_tracking_scroll_bar +}; + +enum mouse_tracking_type mouse_tracking_in_progress = mouse_tracking_none; + +struct scroll_bar *tracked_scroll_bar = NULL; + +/* Incremented by XTread_socket whenever it really tries to read + events. */ + +#ifdef __STDC__ +static int volatile input_signal_count; +#else +static int input_signal_count; +#endif + +/* Used locally within XTread_socket. */ + +static int x_noop_count; + +/* Initial values of argv and argc. */ + +extern char **initial_argv; +extern int initial_argc; + +extern Lisp_Object Vcommand_line_args, Vsystem_name; + +/* Tells if a window manager is present or not. */ + +extern Lisp_Object Vx_no_window_manager; + +extern Lisp_Object Qface, Qmouse_face; + +extern int errno; + +/* A mask of extra modifier bits to put into every keyboard char. */ + +extern int extra_keyboard_modifiers; + +static Lisp_Object Qvendor_specific_keysyms; + +#if 0 +extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *)); +#endif + +extern Lisp_Object x_icon_type P_ ((struct frame *)); + + +#if __MRC__ +QDGlobals qd; /* QuickDraw global information structure. */ +#endif + + +/* Enumeration for overriding/changing the face to use for drawing + glyphs in x_draw_glyphs. */ + +enum draw_glyphs_face +{ + DRAW_NORMAL_TEXT, + DRAW_INVERSE_VIDEO, + DRAW_CURSOR, + DRAW_MOUSE_FACE, + DRAW_IMAGE_RAISED, + DRAW_IMAGE_SUNKEN +}; + +struct frame * x_window_to_frame (struct mac_display_info *, WindowPtr); +struct mac_display_info *mac_display_info_for_display (Display *); +static void x_update_window_end P_ ((struct window *, int, int)); +static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *)); +void x_delete_display P_ ((struct x_display_info *)); +static unsigned int x_mac_to_emacs_modifiers P_ ((struct x_display_info *, + unsigned short)); +static int fast_find_position P_ ((struct window *, int, int *, int *, + int *, int *)); +static void set_output_cursor P_ ((struct cursor_pos *)); +static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int, + int *, int *, int *)); +static void note_mode_line_highlight P_ ((struct window *, int, int)); +static void note_mouse_highlight P_ ((struct frame *, int, int)); +static void note_tool_bar_highlight P_ ((struct frame *f, int, int)); +static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *)); +static void show_mouse_face P_ ((struct x_display_info *, + enum draw_glyphs_face)); +void clear_mouse_face P_ ((struct mac_display_info *)); +static int x_io_error_quitter P_ ((Display *)); +int x_catch_errors P_ ((Display *)); +void x_uncatch_errors P_ ((Display *, int)); +void x_lower_frame P_ ((struct frame *)); +void x_scroll_bar_clear P_ ((struct frame *)); +int x_had_errors_p P_ ((Display *)); +void x_wm_set_size_hint P_ ((struct frame *, long, int)); +void x_raise_frame P_ ((struct frame *)); +void x_set_window_size P_ ((struct frame *, int, int, int)); +void x_wm_set_window_state P_ ((struct frame *, int)); +void x_wm_set_icon_pixmap P_ ((struct frame *, int)); +void x_initialize P_ ((void)); +static void x_font_min_bounds P_ ((XFontStruct *, int *, int *)); +static int x_compute_min_glyph_bounds P_ ((struct frame *)); +enum text_cursor_kinds x_specified_cursor_type P_ ((Lisp_Object, int *)); +static void x_draw_phys_cursor_glyph P_ ((struct window *, + struct glyph_row *, + enum draw_glyphs_face)); +static void x_update_end P_ ((struct frame *)); +static void XTframe_up_to_date P_ ((struct frame *)); +static void XTreassert_line_highlight P_ ((int, int)); +static void x_change_line_highlight P_ ((int, int, int, int)); +static void XTset_terminal_modes P_ ((void)); +static void XTreset_terminal_modes P_ ((void)); +static void XTcursor_to P_ ((int, int, int, int)); +static void x_write_glyphs P_ ((struct glyph *, int)); +static void x_clear_end_of_line P_ ((int)); +static void x_clear_frame P_ ((void)); +static void x_clear_cursor P_ ((struct window *)); +static void frame_highlight P_ ((struct frame *)); +static void frame_unhighlight P_ ((struct frame *)); +static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *)); +static void XTframe_rehighlight P_ ((struct frame *)); +static void x_frame_rehighlight P_ ((struct x_display_info *)); +static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); +static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int)); +static int x_intersect_rectangles P_ ((Rect *, Rect *, Rect *)); +static void expose_frame P_ ((struct frame *, int, int, int, int)); +static void expose_window_tree P_ ((struct window *, Rect *)); +static void expose_window P_ ((struct window *, Rect *)); +static void expose_area P_ ((struct window *, struct glyph_row *, + XRectangle *, enum glyph_row_area)); +static void expose_line P_ ((struct window *, struct glyph_row *, + XRectangle *)); +void x_display_cursor (struct window *, int, int, int, int, int); +void x_update_cursor P_ ((struct frame *, int)); +static void x_update_cursor_in_window_tree P_ ((struct window *, int)); +static void x_update_window_cursor P_ ((struct window *, int)); +static void x_erase_phys_cursor P_ ((struct window *)); +void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int)); +static void x_draw_bitmap P_ ((struct window *, struct glyph_row *, + enum bitmap_type)); + +static void x_clip_to_row P_ ((struct window *, struct glyph_row *, + GC, int)); +static int x_phys_cursor_in_rect_p P_ ((struct window *, Rect *)); +static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *)); +static void note_overwritten_text_cursor P_ ((struct window *, int, int)); +static void x_flush P_ ((struct frame *f)); +static void x_update_begin P_ ((struct frame *)); +static void x_update_window_begin P_ ((struct window *)); +static void x_draw_vertical_border P_ ((struct window *)); +static void x_after_update_window_line P_ ((struct glyph_row *)); +static INLINE void take_vertical_position_into_account P_ ((struct it *)); +static void x_produce_stretch_glyph P_ ((struct it *)); + +static void activate_scroll_bars (FRAME_PTR); +static void deactivate_scroll_bars (FRAME_PTR); + +extern int image_ascent (struct image *, struct face *); +void x_set_offset (struct frame *, int, int, int); +int x_bitmap_icon (struct frame *, Lisp_Object); +void x_make_frame_visible (struct frame *); + +extern void window_scroll (Lisp_Object, int, int, int); + +/* Defined in macmenu.h. */ +extern void menubar_selection_callback (FRAME_PTR, int); +extern void set_frame_menubar (FRAME_PTR, int, int); + +/* X display function emulation */ + +/* Structure borrowed from Xlib.h to represent two-byte characters in + dumpglyphs. */ + +typedef struct { + unsigned char byte1; + unsigned char byte2; +} XChar2b; + +static void +XFreePixmap (display, pixmap) + Display *display; + Pixmap pixmap; +{ + PixMap *p = (PixMap *) pixmap; + + xfree (p->baseAddr); + xfree (p); +} + + +/* Set foreground color for subsequent QuickDraw commands. Assume + graphic port has already been set. */ + +static void +mac_set_forecolor (unsigned long color) +{ + RGBColor fg_color; + + fg_color.red = RED_FROM_ULONG (color) * 256; + fg_color.green = GREEN_FROM_ULONG (color) * 256; + fg_color.blue = BLUE_FROM_ULONG (color) * 256; + + RGBForeColor (&fg_color); +} + + +/* Set background color for subsequent QuickDraw commands. Assume + graphic port has already been set. */ + +static void +mac_set_backcolor (unsigned long color) +{ + RGBColor bg_color; + + bg_color.red = RED_FROM_ULONG (color) * 256; + bg_color.green = GREEN_FROM_ULONG (color) * 256; + bg_color.blue = BLUE_FROM_ULONG (color) * 256; + + RGBBackColor (&bg_color); +} + +/* Set foreground and background color for subsequent QuickDraw + commands. Assume that the graphic port has already been set. */ + +static void +mac_set_colors (GC gc) +{ + mac_set_forecolor (gc->foreground); + mac_set_backcolor (gc->background); +} + +/* Mac version of XDrawLine. */ + +static void +XDrawLine (display, w, gc, x1, y1, x2, y2) + Display *display; + WindowPtr w; + GC gc; + int x1, y1, x2, y2; +{ + SetPort (w); + mac_set_colors (gc); + + MoveTo (x1, y1); + LineTo (x2, y2); +} + +/* Mac version of XClearArea. */ + +static void +XClearArea (display, w, x, y, width, height, exposures) + Display *display; + WindowPtr w; + int x, y; + unsigned int width, height; + int exposures; +{ + struct mac_output *mwp = (mac_output *) GetWRefCon (w); + Rect r; + XGCValues xgc; + + xgc.foreground = mwp->foreground_pixel; + xgc.background = mwp->background_pixel; + + SetPort (w); + mac_set_colors (&xgc); + SetRect (&r, x, y, x + width, y + height); + + EraseRect (&r); +} + +/* Mac version of XClearWindow. */ + +static void +XClearWindow (display, w) + Display *display; + WindowPtr w; +{ + struct mac_output *mwp = (mac_output *) GetWRefCon (w); + XGCValues xgc; + + xgc.foreground = mwp->foreground_pixel; + xgc.background = mwp->background_pixel; + + SetPort (w); + mac_set_colors (&xgc); + + EraseRect (&(w->portRect)); +} + + +/* Mac replacement for XCopyArea. */ + +static void +mac_draw_bitmap (display, w, gc, x, y, bitmap) + Display *display; + WindowPtr w; + GC gc; + int x, y; + BitMap *bitmap; +{ + Rect r; + + SetPort (w); + mac_set_colors (gc); + SetRect (&r, x, y, x + bitmap->bounds.right, y + bitmap->bounds.bottom); + + CopyBits (bitmap, &(w->portBits), &(bitmap->bounds), &r, srcCopy, 0); +} + + +/* Mac replacement for XSetClipRectangles. */ + +static void +mac_set_clip_rectangle (display, w, r) + Display *display; + WindowPtr w; + Rect *r; +{ + SetPort (w); + + ClipRect (r); +} + + +/* Mac replacement for XSetClipMask. */ + +static void +mac_reset_clipping (display, w) + Display *display; + WindowPtr w; +{ + Rect r; + + SetPort (w); + + SetRect (&r, -32767, -32767, 32767, 32767); + ClipRect (&r); +} + + +/* Mac replacement for XCreateBitmapFromBitmapData. */ + +static void +mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h) + BitMap *bitmap; + char *bits; + int w, h; +{ + int bytes_per_row, i, j; + + bitmap->rowBytes = (w + 15) / 16 * 2; /* must be on word boundary */ + bitmap->baseAddr = xmalloc (bitmap->rowBytes * h); + if (!bitmap->baseAddr) + abort (); + + bzero (bitmap->baseAddr, bitmap->rowBytes * h); + for (i = 0; i < h; i++) + for (j = 0; j < w; j++) + if (BitTst (bits, i * w + j)) + BitSet (bitmap->baseAddr, i * bitmap->rowBytes * 8 + j); + + SetRect (&(bitmap->bounds), 0, 0, w, h); +} + + +static void +mac_free_bitmap (bitmap) + BitMap *bitmap; +{ + xfree (bitmap->baseAddr); +} + +/* Mac replacement for XFillRectangle. */ + +static void +XFillRectangle (display, w, gc, x, y, width, height) + Display *display; + WindowPtr w; + GC gc; + int x, y; + unsigned int width, height; +{ + Rect r; + + SetPort (w); + mac_set_colors (gc); + SetRect (&r, x, y, x + width, y + height); + + PaintRect (&r); /* using foreground color of gc */ +} + + +/* Mac replacement for XDrawRectangle: dest is a window. */ + +static void +mac_draw_rectangle (display, w, gc, x, y, width, height) + Display *display; + WindowPtr w; + GC gc; + int x, y; + unsigned int width, height; +{ + Rect r; + + SetPort (w); + mac_set_colors (gc); + SetRect (&r, x, y, x + width + 1, y + height + 1); + + FrameRect (&r); /* using foreground color of gc */ +} + + +/* Mac replacement for XDrawRectangle: dest is a Pixmap. */ + +static void +mac_draw_rectangle_to_pixmap (display, p, gc, x, y, width, height) + Display *display; + Pixmap p; + GC gc; + int x, y; + unsigned int width, height; +{ +#if 0 /* MAC_TODO: draw a rectangle in a PixMap */ + Rect r; + + SetPort (w); + mac_set_colors (gc); + SetRect (&r, x, y, x + width, y + height); + + FrameRect (&r); /* using foreground color of gc */ +#endif +} + + +static void +mac_draw_string_common (display, w, gc, x, y, buf, nchars, mode, + bytes_per_char) + Display *display; + WindowPtr w; + GC gc; + int x, y; + char *buf; + int nchars, mode, bytes_per_char; +{ + SetPort (w); + mac_set_colors (gc); + + TextFont (gc->font->mac_fontnum); + TextSize (gc->font->mac_fontsize); + TextFace (gc->font->mac_fontface); + TextMode (mode); + + MoveTo (x, y); + DrawText (buf, 0, nchars * bytes_per_char); +} + + +/* Mac replacement for XDrawString. */ + +static void +XDrawString (display, w, gc, x, y, buf, nchars) + Display *display; + WindowPtr w; + GC gc; + int x, y; + char *buf; + int nchars; +{ + mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcOr, 1); +} + + +/* Mac replacement for XDrawString16. */ + +static void +XDrawString16 (display, w, gc, x, y, buf, nchars) + Display *display; + WindowPtr w; + GC gc; + int x, y; + XChar2b *buf; + int nchars; +{ + mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcOr, + 2); +} + + +/* Mac replacement for XDrawImageString. */ + +static void +XDrawImageString (display, w, gc, x, y, buf, nchars) + Display *display; + WindowPtr w; + GC gc; + int x, y; + char *buf; + int nchars; +{ + mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcCopy, 1); +} + + +/* Mac replacement for XDrawString16. */ + +static void +XDrawImageString16 (display, w, gc, x, y, buf, nchars) + Display *display; + WindowPtr w; + GC gc; + int x, y; + XChar2b *buf; + int nchars; +{ + mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcCopy, + 2); +} + + +/* Mac replacement for XCopyArea: dest must be window. */ + +static void +mac_copy_area (display, src, dest, gc, src_x, src_y, width, height, dest_x, + dest_y) + Display *display; + Pixmap src; + WindowPtr dest; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r, dest_r; + + SetPort (dest); + mac_set_colors (gc); + + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + + CopyBits ((BitMap *) src, &(dest->portBits), &src_r, &dest_r, srcCopy, 0); +} + + +/* Convert a pair of local coordinates to global (screen) coordinates. + Assume graphic port has been properly set. */ +static void +local_to_global_coord (short *h, short *v) +{ + Point p; + + p.h = *h; + p.v = *v; + + LocalToGlobal (&p); + + *h = p.h; + *v = p.v; +} + + +/* Mac replacement for XCopyArea: used only for scrolling. */ + +static void +mac_scroll_area (display, w, gc, src_x, src_y, width, height, dest_x, dest_y) + Display *display; + WindowPtr w; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r, dest_r; + + SetPort (w); + mac_set_colors (gc); + + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + + /* Need to use global coordinates and screenBits since src and dest + areas overlap in general. */ + local_to_global_coord (&src_r.left, &src_r.top); + local_to_global_coord (&src_r.right, &src_r.bottom); + local_to_global_coord (&dest_r.left, &dest_r.top); + local_to_global_coord (&dest_r.right, &dest_r.bottom); + + CopyBits (&qd.screenBits, &qd.screenBits, &src_r, &dest_r, srcCopy, 0); +} + + +/* Mac replacement for XCopyArea: dest must be Pixmap. */ + +static void +mac_copy_area_to_pixmap (display, src, dest, gc, src_x, src_y, width, height, + dest_x, dest_y) + Display *display; + Pixmap src; + Pixmap dest; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r, dest_r; + int src_right = ((PixMap *) src)->bounds.right; + int src_bottom = ((PixMap *) src)->bounds.bottom; + int w = src_right - src_x; + int h = src_bottom - src_y; + + mac_set_colors (gc); + + SetRect (&src_r, src_x, src_y, src_right, src_bottom); + SetRect (&dest_r, dest_x, dest_y, dest_x + w, dest_y + h); + + CopyBits ((BitMap *) src, (BitMap *) dest, &src_r, &dest_r, srcCopy, 0); +} + + +/* Mac replacement for XChangeGC. */ + +static void +XChangeGC (void * ignore, XGCValues* gc, unsigned long mask, + XGCValues *xgcv) +{ + if (mask & GCForeground) + gc->foreground = xgcv->foreground; + if (mask & GCBackground) + gc->background = xgcv->background; + if (mask & GCFont) + gc->font = xgcv->font; +} + + +/* Mac replacement for XCreateGC. */ + +XGCValues * +XCreateGC (void * ignore, Window window, unsigned long mask, + XGCValues *xgcv) +{ + XGCValues *gc = (XGCValues *) xmalloc (sizeof (XGCValues)); + bzero (gc, sizeof (XGCValues)); + + XChangeGC (ignore, gc, mask, xgcv); + + return gc; +} + + +/* Used in xfaces.c. */ + +void +XFreeGC (display, gc) + Display *display; + GC gc; +{ + xfree (gc); +} + + +/* Mac replacement for XGetGCValues. */ + +static void +XGetGCValues (void* ignore, XGCValues *gc, + unsigned long mask, XGCValues *xgcv) +{ + XChangeGC (ignore, xgcv, mask, gc); +} + + +/* Mac replacement for XSetForeground. */ + +static void +XSetForeground (display, gc, color) + Display *display; + GC gc; + unsigned long color; +{ + gc->foreground = color; +} + + +/* Mac replacement for XSetFont. */ + +static void +XSetFont (display, gc, font) + Display *display; + GC gc; + XFontStruct *font; +{ + gc->font = font; +} + + +static void +XTextExtents16 (XFontStruct *font, XChar2b *text, int nchars, + int *direction,int *font_ascent, + int *font_descent, XCharStruct *cs) +{ + /* MAC_TODO: Use GetTextMetrics to do this and inline it below. */ +} + + +/* x_sync is a no-op on Mac. */ +void +x_sync (f) + void *f; +{ +} + + +/* Flush display of frame F, or of all frames if F is null. */ + +void +x_flush (f) + struct frame *f; +{ +#if 0 /* Nothing to do for Mac OS (needed in OS X perhaps?). */ + BLOCK_INPUT; + if (f == NULL) + { + Lisp_Object rest, frame; + FOR_EACH_FRAME (rest, frame) + x_flush (XFRAME (frame)); + } + else if (FRAME_X_P (f)) + XFlush (FRAME_MAC_DISPLAY (f)); + UNBLOCK_INPUT; +#endif +} + + +/* Remove calls to XFlush by defining XFlush to an empty replacement. + Calls to XFlush should be unnecessary because the X output buffer + is flushed automatically as needed by calls to XPending, + XNextEvent, or XWindowEvent according to the XFlush man page. + XTread_socket calls XPending. Removing XFlush improves + performance. */ + +#define XFlush(DISPLAY) (void) 0 + + +/* Return the struct mac_display_info corresponding to DPY. There's + only one. */ + +struct mac_display_info * +mac_display_info_for_display (dpy) + Display *dpy; +{ + return &one_mac_display_info; +} + + + +/*********************************************************************** + Starting and ending an update + ***********************************************************************/ + +/* Start an update of frame F. This function is installed as a hook + for update_begin, i.e. it is called when update_begin is called. + This function is called prior to calls to x_update_window_begin for + each window being updated. Currently, there is nothing to do here + because all interesting stuff is done on a window basis. */ + +void +x_update_begin (f) + struct frame *f; +{ + /* Nothing to do. */ +} + + +/* Start update of window W. Set the global variable updated_window + to the window being updated and set output_cursor to the cursor + position of W. */ + +void +x_update_window_begin (w) + struct window *w; +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f); + + updated_window = w; + set_output_cursor (&w->cursor); + + BLOCK_INPUT; + + if (f == display_info->mouse_face_mouse_frame) + { + /* Don't do highlighting for mouse motion during the update. */ + display_info->mouse_face_defer = 1; + + /* If F needs to be redrawn, simply forget about any prior mouse + highlighting. */ + if (FRAME_GARBAGED_P (f)) + display_info->mouse_face_window = Qnil; + +#if 0 /* Rows in a current matrix containing glyphs in mouse-face have + their mouse_face_p flag set, which means that they are always + unequal to rows in a desired matrix which never have that + flag set. So, rows containing mouse-face glyphs are never + scrolled, and we don't have to switch the mouse highlight off + here to prevent it from being scrolled. */ + + /* Can we tell that this update does not affect the window + where the mouse highlight is? If so, no need to turn off. + Likewise, don't do anything if the frame is garbaged; + in that case, the frame's current matrix that we would use + is all wrong, and we will redisplay that line anyway. */ + if (!NILP (display_info->mouse_face_window) + && w == XWINDOW (display_info->mouse_face_window)) + { + int i; + + for (i = 0; i < w->desired_matrix->nrows; ++i) + if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)) + break; + + if (i < w->desired_matrix->nrows) + clear_mouse_face (display_info); + } +#endif /* 0 */ + } + + UNBLOCK_INPUT; +} + + +/* Draw a vertical window border to the right of window W if W doesn't + have vertical scroll bars. */ + +static void +x_draw_vertical_border (w) + struct window *w; +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + + /* Redraw borders between horizontally adjacent windows. Don't + do it for frames with vertical scroll bars because either the + right scroll bar of a window, or the left scroll bar of its + neighbor will suffice as a border. */ + if (!WINDOW_RIGHTMOST_P (w) + && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + { + int x0, x1, y0, y1; + + window_box_edges (w, -1, &x0, &y0, &x1, &y1); + x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f); + y1 -= 1; + + XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + f->output_data.mac->normal_gc, x1, y0, x1, y1); + } +} + + +/* End update of window W (which is equal to updated_window). + + Draw vertical borders between horizontally adjacent windows, and + display W's cursor if CURSOR_ON_P is non-zero. + + MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing + glyphs in mouse-face were overwritten. In that case we have to + make sure that the mouse-highlight is properly redrawn. + + W may be a menu bar pseudo-window in case we don't have X toolkit + support. Such windows don't have a cursor, so don't display it + here. */ + +void +x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) + struct window *w; + int cursor_on_p, mouse_face_overwritten_p; +{ + if (!w->pseudo_window_p) + { + struct mac_display_info *dpyinfo + = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame)); + + BLOCK_INPUT; + + /* If a row with mouse-face was overwritten, arrange for + XTframe_up_to_date to redisplay the mouse highlight. */ + if (mouse_face_overwritten_p) + { + dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; + dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; + dpyinfo->mouse_face_window = Qnil; + } + + if (cursor_on_p) + x_display_and_set_cursor (w, 1, output_cursor.hpos, + output_cursor.vpos, + output_cursor.x, output_cursor.y); + + x_draw_vertical_border (w); + UNBLOCK_INPUT; + } + + updated_window = NULL; +} + + +/* End update of frame F. This function is installed as a hook in + update_end. */ + +void +x_update_end (f) + struct frame *f; +{ + /* Reset the background color of Mac OS Window to that of the frame after + update so that it is used by Mac Toolbox to clear the update region before + an update event is generated. */ + SetPort (FRAME_MAC_WINDOW (f)); + mac_set_backcolor (FRAME_BACKGROUND_PIXEL (f)); + + /* Mouse highlight may be displayed again. */ + FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0; + + BLOCK_INPUT; + XFlush (FRAME_MAC_DISPLAY (f)); + UNBLOCK_INPUT; +} + + +/* This function is called from various places in xdisp.c whenever a + complete update has been performed. The global variable + updated_window is not available here. */ + +void +XTframe_up_to_date (f) + struct frame *f; +{ + if (FRAME_X_P (f)) + { + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + if (dpyinfo->mouse_face_deferred_gc + || f == dpyinfo->mouse_face_mouse_frame) + { + BLOCK_INPUT; + if (dpyinfo->mouse_face_mouse_frame) + note_mouse_highlight (dpyinfo->mouse_face_mouse_frame, + dpyinfo->mouse_face_mouse_x, + dpyinfo->mouse_face_mouse_y); + dpyinfo->mouse_face_deferred_gc = 0; + UNBLOCK_INPUT; + } + } +} + + +/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay + arrow bitmaps, or clear the areas where they would be displayed + before DESIRED_ROW is made current. The window being updated is + found in updated_window. This function It is called from + update_window_line only if it is known that there are differences + between bitmaps to be drawn between current row and DESIRED_ROW. */ + +void +x_after_update_window_line (desired_row) + struct glyph_row *desired_row; +{ + struct window *w = updated_window; + + xassert (w); + + if (!desired_row->mode_line_p && !w->pseudo_window_p) + { + BLOCK_INPUT; + x_draw_row_bitmaps (w, desired_row); + + /* When a window has disappeared, make sure that no rest of + full-width rows stays visible in the internal border. */ + if (windows_or_buffers_changed) + { + struct frame *f = XFRAME (w->frame); + int width = FRAME_INTERNAL_BORDER_WIDTH (f); + int height = desired_row->visible_height; + int x = (window_box_right (w, -1) + + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)); + int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); + + XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + x, y, width, height, 0); + } + + UNBLOCK_INPUT; + } +} + + +/* Draw the bitmap WHICH in one of the areas to the left or right of + window W. ROW is the glyph row for which to display the bitmap; it + determines the vertical position at which the bitmap has to be + drawn. */ + +static void +x_draw_bitmap (w, row, which) + struct window *w; + struct glyph_row *row; + enum bitmap_type which; +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + Display *display = FRAME_MAC_DISPLAY (f); + WindowPtr window = FRAME_MAC_WINDOW (f); + int x, y, wd, h, dy; + unsigned char *bits; + BitMap bitmap; + XGCValues gcv; + struct face *face; + + /* Must clip because of partially visible lines. */ + x_clip_to_row (w, row, 1); + + switch (which) + { + case LEFT_TRUNCATION_BITMAP: + wd = left_width; + h = left_height; + bits = left_bits; + x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) + - wd + - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); + break; + + case OVERLAY_ARROW_BITMAP: + wd = left_width; + h = left_height; + bits = ov_bits; + x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) + - wd + - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); + break; + + case RIGHT_TRUNCATION_BITMAP: + wd = right_width; + h = right_height; + bits = right_bits; + x = window_box_right (w, -1); + x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2; + break; + + case CONTINUED_LINE_BITMAP: + wd = right_width; + h = right_height; + bits = continued_bits; + x = window_box_right (w, -1); + x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2; + break; + + case CONTINUATION_LINE_BITMAP: + wd = continuation_width; + h = continuation_height; + bits = continuation_bits; + x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) + - wd + - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); + break; + + case ZV_LINE_BITMAP: + wd = zv_width; + h = zv_height; + bits = zv_bits; + x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) + - wd + - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); + break; + + default: + abort (); + } + + /* Convert to frame coordinates. Set dy to the offset in the row to + start drawing the bitmap. */ + y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + dy = (row->height - h) / 2; + + /* Draw the bitmap. I believe these small pixmaps can be cached + by the server. */ + face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID); + + mac_create_bitmap_from_bitmap_data (&bitmap, bits, wd, h); + gcv.foreground = face->foreground; + gcv.background = face->background; + + mac_draw_bitmap (display, window, &gcv, x, y + dy, &bitmap); + + mac_free_bitmap (&bitmap); + mac_reset_clipping (display, window); +} + + +/* Draw flags bitmaps for glyph row ROW on window W. Call this + function with input blocked. */ + +static void +x_draw_row_bitmaps (w, row) + struct window *w; + struct glyph_row *row; +{ + struct frame *f = XFRAME (w->frame); + enum bitmap_type bitmap; + struct face *face; + int header_line_height = -1; + + xassert (interrupt_input_blocked); + + /* If row is completely invisible, because of vscrolling, we + don't have to draw anything. */ + if (row->visible_height <= 0) + return; + + face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID); + PREPARE_FACE_FOR_DISPLAY (f, face); + + /* Decide which bitmap to draw at the left side. */ + if (row->overlay_arrow_p) + bitmap = OVERLAY_ARROW_BITMAP; + else if (row->truncated_on_left_p) + bitmap = LEFT_TRUNCATION_BITMAP; + else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) + bitmap = CONTINUATION_LINE_BITMAP; + else if (row->indicate_empty_line_p) + bitmap = ZV_LINE_BITMAP; + else + bitmap = NO_BITMAP; + + /* Clear flags area if no bitmap to draw or if bitmap doesn't fill + the flags area. */ + if (bitmap == NO_BITMAP + || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) + || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f)) + { + /* If W has a vertical border to its left, don't draw over it. */ + int border = ((XFASTINT (w->left) > 0 + && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + ? 1 : 0); + int left = window_box_left (w, -1); + + if (header_line_height < 0) + header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); + +#if 0 /* MAC_TODO: stipple */ + /* In case the same realized face is used for bitmap areas and + for something displayed in the text (e.g. face `region' on + mono-displays, the fill style may have been changed to + FillSolid in x_draw_glyph_string_background. */ + if (face->stipple) + XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled); + else + XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background); + + XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + face->gc, + (left + - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) + + border), + WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + row->y)), + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border, + row->visible_height); + if (!face->stipple) + XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground); +#endif + { + XGCValues gcv; + gcv.foreground = face->background; + XFillRectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + &gcv, + (left + - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) + + border), + WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + row->y)), + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border, + row->visible_height); + } + + } + + /* Draw the left bitmap. */ + if (bitmap != NO_BITMAP) + x_draw_bitmap (w, row, bitmap); + + /* Decide which bitmap to draw at the right side. */ + if (row->truncated_on_right_p) + bitmap = RIGHT_TRUNCATION_BITMAP; + else if (row->continued_p) + bitmap = CONTINUED_LINE_BITMAP; + else + bitmap = NO_BITMAP; + + /* Clear flags area if no bitmap to draw of if bitmap doesn't fill + the flags area. */ + if (bitmap == NO_BITMAP + || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) + || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f)) + { + int right = window_box_right (w, -1); + + if (header_line_height < 0) + header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); + +#if 0 /* MAC_TODO: stipple */ + /* In case the same realized face is used for bitmap areas and + for something displayed in the text (e.g. face `region' on + mono-displays, the fill style may have been changed to + FillSolid in x_draw_glyph_string_background. */ + if (face->stipple) + XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled); + else + XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background); + XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + face->gc, + right, + WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + row->y)), + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f), + row->visible_height); + if (!face->stipple) + XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground); +#endif + { + XGCValues gcv; + gcv.foreground = face->background; + XFillRectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + &gcv, + right, + WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + row->y)), + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f), + row->visible_height); + } + + } + + /* Draw the right bitmap. */ + if (bitmap != NO_BITMAP) + x_draw_bitmap (w, row, bitmap); +} + + +/*********************************************************************** + Line Highlighting + ***********************************************************************/ + +/* External interface to control of standout mode. Not used for X + frames. Aborts when called. */ + +void +XTreassert_line_highlight (new, vpos) + int new, vpos; +{ + abort (); +} + + +/* Call this when about to modify line at position VPOS and change + whether it is highlighted. Not used for X frames. Aborts when + called. */ + +void +x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos) + int new_highlight, vpos, y, first_unused_hpos; +{ + abort (); +} + + +/* This is called when starting Emacs and when restarting after + suspend. When starting Emacs, no X window is mapped. And nothing + must be done to Emacs's own window if it is suspended (though that + rarely happens). */ + +void +XTset_terminal_modes () +{ +} + +/* This is called when exiting or suspending Emacs. Exiting will make + the X-windows go away, and suspending requires no action. */ + +void +XTreset_terminal_modes () +{ +} + + + +/*********************************************************************** + Output Cursor + ***********************************************************************/ + +/* Set the global variable output_cursor to CURSOR. All cursor + positions are relative to updated_window. */ + +static void +set_output_cursor (cursor) + struct cursor_pos *cursor; +{ + output_cursor.hpos = cursor->hpos; + output_cursor.vpos = cursor->vpos; + output_cursor.x = cursor->x; + output_cursor.y = cursor->y; +} + + +/* Set a nominal cursor position. + + HPOS and VPOS are column/row positions in a window glyph matrix. X + and Y are window text area relative pixel positions. + + If this is done during an update, updated_window will contain the + window that is being updated and the position is the future output + cursor position for that window. If updated_window is null, use + selected_window and display the cursor at the given position. */ + +void +XTcursor_to (vpos, hpos, y, x) + int vpos, hpos, y, x; +{ + struct window *w; + + /* If updated_window is not set, work on selected_window. */ + if (updated_window) + w = updated_window; + else + w = XWINDOW (selected_window); + + /* Set the output cursor. */ + output_cursor.hpos = hpos; + output_cursor.vpos = vpos; + output_cursor.x = x; + output_cursor.y = y; + + /* If not called as part of an update, really display the cursor. + This will also set the cursor position of W. */ + if (updated_window == NULL) + { + BLOCK_INPUT; + x_display_cursor (w, 1, hpos, vpos, x, y); + XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ())); + UNBLOCK_INPUT; + } +} + + + +/*********************************************************************** + Display Iterator + ***********************************************************************/ + +/* Function prototypes of this page. */ + +static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *, + struct glyph *, + XChar2b *, + int *)); +static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int, + int, XChar2b *, int)); +static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *)); +static void x_encode_char P_ ((int, XChar2b *, struct font_info *)); +static void x_append_glyph P_ ((struct it *)); +static void x_append_composite_glyph P_ ((struct it *)); +static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object, + int, int, double)); +static void x_produce_glyphs P_ ((struct it *)); +static void x_produce_image_glyph P_ ((struct it *it)); + + +/* Return a pointer to per-char metric information in FONT of a + character pointed by B which is a pointer to an XChar2b. */ + +#define PER_CHAR_METRIC(font, b) \ + ((font)->per_char \ + ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \ + + (((font)->min_byte1 || (font)->max_byte1) \ + ? (((b)->byte1 - (font)->min_byte1) \ + * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \ + : 0)) \ + : &((font)->max_bounds)) + + +/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B + is not contained in the font. */ + +static INLINE XCharStruct * +x_per_char_metric (font, char2b) + XFontStruct *font; + XChar2b *char2b; +{ + /* The result metric information. */ + XCharStruct *pcm = NULL; + + xassert (font && char2b); + + if (font->per_char != NULL) + { + if (font->min_byte1 == 0 && font->max_byte1 == 0) + { + /* min_char_or_byte2 specifies the linear character index + corresponding to the first element of the per_char array, + max_char_or_byte2 is the index of the last character. A + character with non-zero CHAR2B->byte1 is not in the font. + A character with byte2 less than min_char_or_byte2 or + greater max_char_or_byte2 is not in the font. */ + if (char2b->byte1 == 0 + && char2b->byte2 >= font->min_char_or_byte2 + && char2b->byte2 <= font->max_char_or_byte2) + pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2; + } + else + { + /* If either min_byte1 or max_byte1 are nonzero, both + min_char_or_byte2 and max_char_or_byte2 are less than + 256, and the 2-byte character index values corresponding + to the per_char array element N (counting from 0) are: + + byte1 = N/D + min_byte1 + byte2 = N\D + min_char_or_byte2 + + where: + + D = max_char_or_byte2 - min_char_or_byte2 + 1 + / = integer division + \ = integer modulus */ + if (char2b->byte1 >= font->min_byte1 + && char2b->byte1 <= font->max_byte1 + && char2b->byte2 >= font->min_char_or_byte2 + && char2b->byte2 <= font->max_char_or_byte2) + { + pcm = (font->per_char + + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1) + * (char2b->byte1 - font->min_byte1)) + + (char2b->byte2 - font->min_char_or_byte2)); + } + } + } + else + { + /* If the per_char pointer is null, all glyphs between the first + and last character indexes inclusive have the same + information, as given by both min_bounds and max_bounds. */ + if (char2b->byte2 >= font->min_char_or_byte2 + && char2b->byte2 <= font->max_char_or_byte2) + pcm = &font->max_bounds; + } + + return ((pcm == NULL + || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0)) + ? NULL : pcm); +} + + +/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is + the two-byte form of C. Encoding is returned in *CHAR2B. */ + +static INLINE void +x_encode_char (c, char2b, font_info) + int c; + XChar2b *char2b; + struct font_info *font_info; +{ + int charset = CHAR_CHARSET (c); + XFontStruct *font = font_info->font; + + /* FONT_INFO may define a scheme by which to encode byte1 and byte2. + This may be either a program in a special encoder language or a + fixed encoding. */ + if (font_info->font_encoder) + { + /* It's a program. */ + struct ccl_program *ccl = font_info->font_encoder; + + if (CHARSET_DIMENSION (charset) == 1) + { + ccl->reg[0] = charset; + ccl->reg[1] = char2b->byte2; + } + else + { + ccl->reg[0] = charset; + ccl->reg[1] = char2b->byte1; + ccl->reg[2] = char2b->byte2; + } + + ccl_driver (ccl, NULL, NULL, 0, 0, NULL); + + /* We assume that MSBs are appropriately set/reset by CCL + program. */ + if (font->max_byte1 == 0) /* 1-byte font */ + char2b->byte1 = 0, char2b->byte2 = ccl->reg[1]; + else + char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2]; + } + else if (font_info->encoding[charset]) + { + /* Fixed encoding scheme. See fontset.h for the meaning of the + encoding numbers. */ + int enc = font_info->encoding[charset]; + + if ((enc == 1 || enc == 2) + && CHARSET_DIMENSION (charset) == 2) + char2b->byte1 |= 0x80; + + if (enc == 1 || enc == 3) + char2b->byte2 |= 0x80; + + if (enc == 4) + { + int sjis1, sjis2; + + ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2); + char2b->byte1 = sjis1; + char2b->byte2 = sjis2; + } + } +} + + +/* Get face and two-byte form of character C in face FACE_ID on frame + F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero + means we want to display multibyte text. Value is a pointer to a + realized face that is ready for display. */ + +static INLINE struct face * +x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p) + struct frame *f; + int c, face_id; + XChar2b *char2b; + int multibyte_p; +{ + struct face *face = FACE_FROM_ID (f, face_id); + + if (!multibyte_p) + { + /* Unibyte case. We don't have to encode, but we have to make + sure to use a face suitable for unibyte. */ + char2b->byte1 = 0; + char2b->byte2 = c; + face_id = FACE_FOR_CHAR (f, face, c); + face = FACE_FROM_ID (f, face_id); + } + else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL) + { + /* Case of ASCII in a face known to fit ASCII. */ + char2b->byte1 = 0; + char2b->byte2 = c; + } + else + { + int c1, c2, charset; + + /* Split characters into bytes. If c2 is -1 afterwards, C is + really a one-byte character so that byte1 is zero. */ + SPLIT_CHAR (c, charset, c1, c2); + if (c2 > 0) + char2b->byte1 = c1, char2b->byte2 = c2; + else + char2b->byte1 = 0, char2b->byte2 = c1; + + /* Maybe encode the character in *CHAR2B. */ + if (face->font != NULL) + { + struct font_info *font_info + = FONT_INFO_FROM_ID (f, face->font_info_id); + if (font_info) + x_encode_char (c, char2b, font_info); + } + } + + /* Make sure X resources of the face are allocated. */ + xassert (face != NULL); + PREPARE_FACE_FOR_DISPLAY (f, face); + + return face; +} + + +/* Get face and two-byte form of character glyph GLYPH on frame F. + The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is + a pointer to a realized face that is ready for display. */ + +static INLINE struct face * +x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p) + struct frame *f; + struct glyph *glyph; + XChar2b *char2b; + int *two_byte_p; +{ + struct face *face; + + xassert (glyph->type == CHAR_GLYPH); + face = FACE_FROM_ID (f, glyph->face_id); + + if (two_byte_p) + *two_byte_p = 0; + + if (!glyph->multibyte_p) + { + /* Unibyte case. We don't have to encode, but we have to make + sure to use a face suitable for unibyte. */ + char2b->byte1 = 0; + char2b->byte2 = glyph->u.ch; + } + else if (glyph->u.ch < 128 + && glyph->face_id < BASIC_FACE_ID_SENTINEL) + { + /* Case of ASCII in a face known to fit ASCII. */ + char2b->byte1 = 0; + char2b->byte2 = glyph->u.ch; + } + else + { + int c1, c2, charset; + + /* Split characters into bytes. If c2 is -1 afterwards, C is + really a one-byte character so that byte1 is zero. */ + SPLIT_CHAR (glyph->u.ch, charset, c1, c2); + if (c2 > 0) + char2b->byte1 = c1, char2b->byte2 = c2; + else + char2b->byte1 = 0, char2b->byte2 = c1; + + /* Maybe encode the character in *CHAR2B. */ + if (charset != CHARSET_ASCII) + { + struct font_info *font_info + = FONT_INFO_FROM_ID (f, face->font_info_id); + if (font_info) + { + x_encode_char (glyph->u.ch, char2b, font_info); + if (two_byte_p) + *two_byte_p + = ((XFontStruct *) (font_info->font))->max_byte1 > 0; + } + } + } + + /* Make sure X resources of the face are allocated. */ + xassert (face != NULL); + PREPARE_FACE_FOR_DISPLAY (f, face); + return face; +} + + +/* Store one glyph for IT->char_to_display in IT->glyph_row. + Called from x_produce_glyphs when IT->glyph_row is non-null. */ + +static INLINE void +x_append_glyph (it) + struct it *it; +{ + struct glyph *glyph; + enum glyph_row_area area = it->area; + + xassert (it->glyph_row); + xassert (it->char_to_display != '\n' && it->char_to_display != '\t'); + + glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; + if (glyph < it->glyph_row->glyphs[area + 1]) + { + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + glyph->pixel_width = it->pixel_width; + glyph->voffset = it->voffset; + glyph->type = CHAR_GLYPH; + glyph->multibyte_p = it->multibyte_p; + glyph->left_box_line_p = it->start_of_box_run_p; + glyph->right_box_line_p = it->end_of_box_run_p; + glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent + || it->phys_descent > it->descent); + glyph->padding_p = 0; + glyph->glyph_not_available_p = it->glyph_not_available_p; + glyph->face_id = it->face_id; + glyph->u.ch = it->char_to_display; + ++it->glyph_row->used[area]; + } +} + +/* Store one glyph for the composition IT->cmp_id in IT->glyph_row. + Called from x_produce_glyphs when IT->glyph_row is non-null. */ + +static INLINE void +x_append_composite_glyph (it) + struct it *it; +{ + struct glyph *glyph; + enum glyph_row_area area = it->area; + + xassert (it->glyph_row); + + glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; + if (glyph < it->glyph_row->glyphs[area + 1]) + { + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + glyph->pixel_width = it->pixel_width; + glyph->voffset = it->voffset; + glyph->type = COMPOSITE_GLYPH; + glyph->multibyte_p = it->multibyte_p; + glyph->left_box_line_p = it->start_of_box_run_p; + glyph->right_box_line_p = it->end_of_box_run_p; + glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent + || it->phys_descent > it->descent); + glyph->padding_p = 0; + glyph->glyph_not_available_p = 0; + glyph->face_id = it->face_id; + glyph->u.cmp_id = it->cmp_id; + ++it->glyph_row->used[area]; + } +} + + +/* Change IT->ascent and IT->height according to the setting of + IT->voffset. */ + +static INLINE void +take_vertical_position_into_account (it) + struct it *it; +{ + if (it->voffset) + { + if (it->voffset < 0) + /* Increase the ascent so that we can display the text higher + in the line. */ + it->ascent += abs (it->voffset); + else + /* Increase the descent so that we can display the text lower + in the line. */ + it->descent += it->voffset; + } +} + + +/* Produce glyphs/get display metrics for the image IT is loaded with. + See the description of struct display_iterator in dispextern.h for + an overview of struct display_iterator. */ + +static void +x_produce_image_glyph (it) + struct it *it; +{ + struct image *img; + struct face *face; + + xassert (it->what == IT_IMAGE); + + face = FACE_FROM_ID (it->f, it->face_id); + img = IMAGE_FROM_ID (it->f, it->image_id); + xassert (img); + + /* Make sure X resources of the face and image are loaded. */ + PREPARE_FACE_FOR_DISPLAY (it->f, face); + prepare_image_for_display (it->f, img); + + it->ascent = it->phys_ascent = image_ascent (img, face); + it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent; + it->pixel_width = img->width + 2 * img->margin; + + it->nglyphs = 1; + + if (face->box != FACE_NO_BOX) + { + it->ascent += face->box_line_width; + it->descent += face->box_line_width; + + if (it->start_of_box_run_p) + it->pixel_width += face->box_line_width; + if (it->end_of_box_run_p) + it->pixel_width += face->box_line_width; + } + + take_vertical_position_into_account (it); + + if (it->glyph_row) + { + struct glyph *glyph; + enum glyph_row_area area = it->area; + + glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; + if (glyph < it->glyph_row->glyphs[area + 1]) + { + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + glyph->pixel_width = it->pixel_width; + glyph->voffset = it->voffset; + glyph->type = IMAGE_GLYPH; + glyph->multibyte_p = it->multibyte_p; + glyph->left_box_line_p = it->start_of_box_run_p; + glyph->right_box_line_p = it->end_of_box_run_p; + glyph->overlaps_vertically_p = 0; + glyph->padding_p = 0; + glyph->glyph_not_available_p = 0; + glyph->face_id = it->face_id; + glyph->u.img_id = img->id; + ++it->glyph_row->used[area]; + } + } +} + + +/* Append a stretch glyph to IT->glyph_row. OBJECT is the source + of the glyph, WIDTH and HEIGHT are the width and height of the + stretch. ASCENT is the percentage/100 of HEIGHT to use for the + ascent of the glyph (0 <= ASCENT <= 1). */ + +static void +x_append_stretch_glyph (it, object, width, height, ascent) + struct it *it; + Lisp_Object object; + int width, height; + double ascent; +{ + struct glyph *glyph; + enum glyph_row_area area = it->area; + + xassert (ascent >= 0 && ascent <= 1); + + glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; + if (glyph < it->glyph_row->glyphs[area + 1]) + { + glyph->charpos = CHARPOS (it->position); + glyph->object = object; + glyph->pixel_width = width; + glyph->voffset = it->voffset; + glyph->type = STRETCH_GLYPH; + glyph->multibyte_p = it->multibyte_p; + glyph->left_box_line_p = it->start_of_box_run_p; + glyph->right_box_line_p = it->end_of_box_run_p; + glyph->overlaps_vertically_p = 0; + glyph->padding_p = 0; + glyph->glyph_not_available_p = 0; + glyph->face_id = it->face_id; + glyph->u.stretch.ascent = height * ascent; + glyph->u.stretch.height = height; + ++it->glyph_row->used[area]; + } +} + + +/* Produce a stretch glyph for iterator IT. IT->object is the value + of the glyph property displayed. The value must be a list + `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs + being recognized: + + 1. `:width WIDTH' specifies that the space should be WIDTH * + canonical char width wide. WIDTH may be an integer or floating + point number. + + 2. `:relative-width FACTOR' specifies that the width of the stretch + should be computed from the width of the first character having the + `glyph' property, and should be FACTOR times that width. + + 3. `:align-to HPOS' specifies that the space should be wide enough + to reach HPOS, a value in canonical character units. + + Exactly one of the above pairs must be present. + + 4. `:height HEIGHT' specifies that the height of the stretch produced + should be HEIGHT, measured in canonical character units. + + 5. `:relative-height FACTOR' specifies that the height of the the + stretch should be FACTOR times the height of the characters having + the glyph property. + + Either none or exactly one of 4 or 5 must be present. + + 6. `:ascent ASCENT' specifies that ASCENT percent of the height + of the stretch should be used for the ascent of the stretch. + ASCENT must be in the range 0 <= ASCENT <= 100. */ + +#define NUMVAL(X) \ + ((INTEGERP (X) || FLOATP (X)) \ + ? XFLOATINT (X) \ + : - 1) + + +static void +x_produce_stretch_glyph (it) + struct it *it; +{ + /* (space :width WIDTH :height HEIGHT. */ +#if GLYPH_DEBUG + extern Lisp_Object Qspace; +#endif + extern Lisp_Object QCwidth, QCheight, QCascent; + extern Lisp_Object QCrelative_width, QCrelative_height; + extern Lisp_Object QCalign_to; + Lisp_Object prop, plist; + double width = 0, height = 0, ascent = 0; + struct face *face = FACE_FROM_ID (it->f, it->face_id); + XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f); + + PREPARE_FACE_FOR_DISPLAY (it->f, face); + + /* List should start with `space'. */ + xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace)); + plist = XCDR (it->object); + + /* Compute the width of the stretch. */ + if (prop = Fplist_get (plist, QCwidth), + NUMVAL (prop) > 0) + /* Absolute width `:width WIDTH' specified and valid. */ + width = NUMVAL (prop) * CANON_X_UNIT (it->f); + else if (prop = Fplist_get (plist, QCrelative_width), + NUMVAL (prop) > 0) + { + /* Relative width `:relative-width FACTOR' specified and valid. + Compute the width of the characters having the `glyph' + property. */ + struct it it2; + unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it)); + + it2 = *it; + if (it->multibyte_p) + { + int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT) + - IT_BYTEPOS (*it)); + it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len); + } + else + it2.c = *p, it2.len = 1; + + it2.glyph_row = NULL; + it2.what = IT_CHARACTER; + x_produce_glyphs (&it2); + width = NUMVAL (prop) * it2.pixel_width; + } + else if (prop = Fplist_get (plist, QCalign_to), + NUMVAL (prop) > 0) + width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x; + else + /* Nothing specified -> width defaults to canonical char width. */ + width = CANON_X_UNIT (it->f); + + /* Compute height. */ + if (prop = Fplist_get (plist, QCheight), + NUMVAL (prop) > 0) + height = NUMVAL (prop) * CANON_Y_UNIT (it->f); + else if (prop = Fplist_get (plist, QCrelative_height), + NUMVAL (prop) > 0) + height = FONT_HEIGHT (font) * NUMVAL (prop); + else + height = FONT_HEIGHT (font); + + /* Compute percentage of height used for ascent. If + `:ascent ASCENT' is present and valid, use that. Otherwise, + derive the ascent from the font in use. */ + if (prop = Fplist_get (plist, QCascent), + NUMVAL (prop) > 0 && NUMVAL (prop) <= 100) + ascent = NUMVAL (prop) / 100.0; + else + ascent = (double) font->ascent / FONT_HEIGHT (font); + + if (width <= 0) + width = 1; + if (height <= 0) + height = 1; + + if (it->glyph_row) + { + Lisp_Object object = it->stack[it->sp - 1].string; + if (!STRINGP (object)) + object = it->w->buffer; + x_append_stretch_glyph (it, object, width, height, ascent); + } + + it->pixel_width = width; + it->ascent = it->phys_ascent = height * ascent; + it->descent = it->phys_descent = height - it->ascent; + it->nglyphs = 1; + + if (face->box != FACE_NO_BOX) + { + it->ascent += face->box_line_width; + it->descent += face->box_line_width; + + if (it->start_of_box_run_p) + it->pixel_width += face->box_line_width; + if (it->end_of_box_run_p) + it->pixel_width += face->box_line_width; + } + + take_vertical_position_into_account (it); +} + +/* Return proper value to be used as baseline offset of font that has + ASCENT and DESCENT to draw characters by the font at the vertical + center of the line of frame F. + + Here, out task is to find the value of BOFF in the following figure; + + -------------------------+-----------+- + -+-+---------+-+ | | + | | | | | | + | | | | F_ASCENT F_HEIGHT + | | | ASCENT | | + HEIGHT | | | | | + | | |-|-+------+-----------|------- baseline + | | | | BOFF | | + | |---------|-+-+ | | + | | | DESCENT | | + -+-+---------+-+ F_DESCENT | + -------------------------+-----------+- + + -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT + BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT + DESCENT = FONT->descent + HEIGHT = FONT_HEIGHT (FONT) + F_DESCENT = (F->output_data.x->font->descent + - F->output_data.x->baseline_offset) + F_HEIGHT = FRAME_LINE_HEIGHT (F) +*/ + +#define VCENTER_BASELINE_OFFSET(FONT, F) \ + ((FONT)->descent \ + + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \ + - ((F)->output_data.mac->font->descent - (F)->output_data.mac->baseline_offset)) + +/* Produce glyphs/get display metrics for the display element IT is + loaded with. See the description of struct display_iterator in + dispextern.h for an overview of struct display_iterator. */ + +void +x_produce_glyphs (it) + struct it *it; +{ + it->glyph_not_available_p = 0; + + if (it->what == IT_CHARACTER) + { + XChar2b char2b; + XFontStruct *font; + struct face *face = FACE_FROM_ID (it->f, it->face_id); + XCharStruct *pcm; + int font_not_found_p; + struct font_info *font_info; + int boff; /* baseline offset */ + + /* Maybe translate single-byte characters to multibyte, or the + other way. */ + it->char_to_display = it->c; + if (!ASCII_BYTE_P (it->c)) + { + if (unibyte_display_via_language_environment + && SINGLE_BYTE_CHAR_P (it->c) + && (it->c >= 0240 + || !NILP (Vnonascii_translation_table))) + { + it->char_to_display = unibyte_char_to_multibyte (it->c); + it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); + face = FACE_FROM_ID (it->f, it->face_id); + } + else if (!SINGLE_BYTE_CHAR_P (it->c) + && !it->multibyte_p) + { + it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil); + it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); + face = FACE_FROM_ID (it->f, it->face_id); + } + } + + /* Get font to use. Encode IT->char_to_display. */ + x_get_char_face_and_encoding (it->f, it->char_to_display, + it->face_id, &char2b, + it->multibyte_p); + font = face->font; + + /* When no suitable font found, use the default font. */ + font_not_found_p = font == NULL; + if (font_not_found_p) + { + font = FRAME_FONT (it->f); + boff = it->f->output_data.mac->baseline_offset; + font_info = NULL; + } + else + { + font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); + boff = font_info->baseline_offset; + if (font_info->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + } + + if (it->char_to_display >= ' ' + && (!it->multibyte_p || it->char_to_display < 128)) + { + /* Either unibyte or ASCII. */ + int stretched_p; + + it->nglyphs = 1; + + pcm = x_per_char_metric (font, &char2b); + it->ascent = font->ascent + boff; + it->descent = font->descent - boff; + + if (pcm) + { + it->phys_ascent = pcm->ascent + boff; + it->phys_descent = pcm->descent - boff; + it->pixel_width = pcm->width; + } + else + { + it->glyph_not_available_p = 1; + it->phys_ascent = font->ascent + boff; + it->phys_descent = font->descent - boff; + it->pixel_width = FONT_WIDTH (font); + } + + /* If this is a space inside a region of text with + `space-width' property, change its width. */ + stretched_p = it->char_to_display == ' ' && !NILP (it->space_width); + if (stretched_p) + it->pixel_width *= XFLOATINT (it->space_width); + + /* If face has a box, add the box thickness to the character + height. If character has a box line to the left and/or + right, add the box line width to the character's width. */ + if (face->box != FACE_NO_BOX) + { + int thick = face->box_line_width; + + it->ascent += thick; + it->descent += thick; + + if (it->start_of_box_run_p) + it->pixel_width += thick; + if (it->end_of_box_run_p) + it->pixel_width += thick; + } + + /* If face has an overline, add the height of the overline + (1 pixel) and a 1 pixel margin to the character height. */ + if (face->overline_p) + it->ascent += 2; + + take_vertical_position_into_account (it); + + /* If we have to actually produce glyphs, do it. */ + if (it->glyph_row) + { + if (stretched_p) + { + /* Translate a space with a `space-width' property + into a stretch glyph. */ + double ascent = (double) font->ascent / FONT_HEIGHT (font); + x_append_stretch_glyph (it, it->object, it->pixel_width, + it->ascent + it->descent, ascent); + } + else + x_append_glyph (it); + + /* If characters with lbearing or rbearing are displayed + in this line, record that fact in a flag of the + glyph row. This is used to optimize X output code. */ + if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width)) + it->glyph_row->contains_overlapping_glyphs_p = 1; + } + } + else if (it->char_to_display == '\n') + { + /* A newline has no width but we need the height of the line. */ + it->pixel_width = 0; + it->nglyphs = 0; + it->ascent = it->phys_ascent = font->ascent + boff; + it->descent = it->phys_descent = font->descent - boff; + + if (face->box != FACE_NO_BOX) + { + int thick = face->box_line_width; + it->ascent += thick; + it->descent += thick; + } + } + else if (it->char_to_display == '\t') + { + int tab_width = it->tab_width * CANON_X_UNIT (it->f); + int x = it->current_x + it->continuation_lines_width; + int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width; + + it->pixel_width = next_tab_x - x; + it->nglyphs = 1; + it->ascent = it->phys_ascent = font->ascent + boff; + it->descent = it->phys_descent = font->descent - boff; + + if (it->glyph_row) + { + double ascent = (double) it->ascent / (it->ascent + it->descent); + x_append_stretch_glyph (it, it->object, it->pixel_width, + it->ascent + it->descent, ascent); + } + } + else + { + /* A multi-byte character. Assume that the display width of the + character is the width of the character multiplied by the + width of the font. */ + + /* If we found a font, this font should give us the right + metrics. If we didn't find a font, use the frame's + default font and calculate the width of the character + from the charset width; this is what old redisplay code + did. */ + pcm = x_per_char_metric (font, &char2b); + if (font_not_found_p || !pcm) + { + int charset = CHAR_CHARSET (it->char_to_display); + + it->glyph_not_available_p = 1; + it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f)) + * CHARSET_WIDTH (charset)); + it->phys_ascent = font->ascent + boff; + it->phys_descent = font->descent - boff; + } + else + { + it->pixel_width = pcm->width; + it->phys_ascent = pcm->ascent + boff; + it->phys_descent = pcm->descent - boff; + if (it->glyph_row + && (pcm->lbearing < 0 + || pcm->rbearing > pcm->width)) + it->glyph_row->contains_overlapping_glyphs_p = 1; + } + it->nglyphs = 1; + it->ascent = font->ascent + boff; + it->descent = font->descent - boff; + if (face->box != FACE_NO_BOX) + { + int thick = face->box_line_width; + it->ascent += thick; + it->descent += thick; + + if (it->start_of_box_run_p) + it->pixel_width += thick; + if (it->end_of_box_run_p) + it->pixel_width += thick; + } + + /* If face has an overline, add the height of the overline + (1 pixel) and a 1 pixel margin to the character height. */ + if (face->overline_p) + it->ascent += 2; + + take_vertical_position_into_account (it); + + if (it->glyph_row) + x_append_glyph (it); + } + } + else if (it->what == IT_COMPOSITION) + { + /* Note: A composition is represented as one glyph in the + glyph matrix. There are no padding glyphs. */ + XChar2b char2b; + XFontStruct *font; + struct face *face = FACE_FROM_ID (it->f, it->face_id); + XCharStruct *pcm; + int font_not_found_p; + struct font_info *font_info; + int boff; /* baseline offset */ + struct composition *cmp = composition_table[it->cmp_id]; + + /* Maybe translate single-byte characters to multibyte. */ + it->char_to_display = it->c; + if (unibyte_display_via_language_environment + && SINGLE_BYTE_CHAR_P (it->c) + && (it->c >= 0240 + || (it->c >= 0200 + && !NILP (Vnonascii_translation_table)))) + { + it->char_to_display = unibyte_char_to_multibyte (it->c); + } + + /* Get face and font to use. Encode IT->char_to_display. */ + it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); + face = FACE_FROM_ID (it->f, it->face_id); + x_get_char_face_and_encoding (it->f, it->char_to_display, + it->face_id, &char2b, it->multibyte_p); + font = face->font; + + /* When no suitable font found, use the default font. */ + font_not_found_p = font == NULL; + if (font_not_found_p) + { + font = FRAME_FONT (it->f); + boff = it->f->output_data.mac->baseline_offset; + font_info = NULL; + } + else + { + font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); + boff = font_info->baseline_offset; + if (font_info->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + } + + /* There are no padding glyphs, so there is only one glyph to + produce for the composition. Important is that pixel_width, + ascent and descent are the values of what is drawn by + draw_glyphs (i.e. the values of the overall glyphs composed). */ + it->nglyphs = 1; + + /* If we have not yet calculated pixel size data of glyphs of + the composition for the current face font, calculate them + now. Theoretically, we have to check all fonts for the + glyphs, but that requires much time and memory space. So, + here we check only the font of the first glyph. This leads + to incorrect display very rarely, and C-l (recenter) can + correct the display anyway. */ + if (cmp->font != (void *) font) + { + /* Ascent and descent of the font of the first character of + this composition (adjusted by baseline offset). Ascent + and descent of overall glyphs should not be less than + them respectively. */ + int font_ascent = font->ascent + boff; + int font_descent = font->descent - boff; + /* Bounding box of the overall glyphs. */ + int leftmost, rightmost, lowest, highest; + int i, width, ascent, descent; + + cmp->font = (void *) font; + + /* Initialize the bounding box. */ + pcm = x_per_char_metric (font, &char2b); + if (pcm) + { + width = pcm->width; + ascent = pcm->ascent; + descent = pcm->descent; + } + else + { + width = FONT_WIDTH (font); + ascent = font->ascent; + descent = font->descent; + } + + rightmost = width; + lowest = - descent + boff; + highest = ascent + boff; + leftmost = 0; + + if (font_info + && font_info->default_ascent + && CHAR_TABLE_P (Vuse_default_ascent) + && !NILP (Faref (Vuse_default_ascent, + make_number (it->char_to_display)))) + highest = font_info->default_ascent + boff; + + /* Draw the first glyph at the normal position. It may be + shifted to right later if some other glyphs are drawn at + the left. */ + cmp->offsets[0] = 0; + cmp->offsets[1] = boff; + + /* Set cmp->offsets for the remaining glyphs. */ + for (i = 1; i < cmp->glyph_len; i++) + { + int left, right, btm, top; + int ch = COMPOSITION_GLYPH (cmp, i); + int face_id = FACE_FOR_CHAR (it->f, face, ch); + + face = FACE_FROM_ID (it->f, face_id); + x_get_char_face_and_encoding (it->f, ch, face->id, &char2b, + it->multibyte_p); + font = face->font; + if (font == NULL) + { + font = FRAME_FONT (it->f); + boff = it->f->output_data.mac->baseline_offset; + font_info = NULL; + } + else + { + font_info + = FONT_INFO_FROM_ID (it->f, face->font_info_id); + boff = font_info->baseline_offset; + if (font_info->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + } + + pcm = x_per_char_metric (font, &char2b); + if (pcm) + { + width = pcm->width; + ascent = pcm->ascent; + descent = pcm->descent; + } + else + { + width = FONT_WIDTH (font); + ascent = font->ascent; + descent = font->descent; + } + + if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS) + { + /* Relative composition with or without + alternate chars. */ + left = (leftmost + rightmost - width) / 2; + btm = - descent + boff; + if (font_info && font_info->relative_compose + && (! CHAR_TABLE_P (Vignore_relative_composition) + || NILP (Faref (Vignore_relative_composition, + make_number (ch))))) + { + + if (- descent >= font_info->relative_compose) + /* One extra pixel between two glyphs. */ + btm = highest + 1; + else if (ascent <= 0) + /* One extra pixel between two glyphs. */ + btm = lowest - 1 - ascent - descent; + } + } + else + { + /* A composition rule is specified by an integer + value that encodes global and new reference + points (GREF and NREF). GREF and NREF are + specified by numbers as below: + + 0---1---2 -- ascent + | | + | | + | | + 9--10--11 -- center + | | + ---3---4---5--- baseline + | | + 6---7---8 -- descent + */ + int rule = COMPOSITION_RULE (cmp, i); + int gref, nref, grefx, grefy, nrefx, nrefy; + + COMPOSITION_DECODE_RULE (rule, gref, nref); + grefx = gref % 3, nrefx = nref % 3; + grefy = gref / 3, nrefy = nref / 3; + + left = (leftmost + + grefx * (rightmost - leftmost) / 2 + - nrefx * width / 2); + btm = ((grefy == 0 ? highest + : grefy == 1 ? 0 + : grefy == 2 ? lowest + : (highest + lowest) / 2) + - (nrefy == 0 ? ascent + descent + : nrefy == 1 ? descent - boff + : nrefy == 2 ? 0 + : (ascent + descent) / 2)); + } + + cmp->offsets[i * 2] = left; + cmp->offsets[i * 2 + 1] = btm + descent; + + /* Update the bounding box of the overall glyphs. */ + right = left + width; + top = btm + descent + ascent; + if (left < leftmost) + leftmost = left; + if (right > rightmost) + rightmost = right; + if (top > highest) + highest = top; + if (btm < lowest) + lowest = btm; + } + + /* If there are glyphs whose x-offsets are negative, + shift all glyphs to the right and make all x-offsets + non-negative. */ + if (leftmost < 0) + { + for (i = 0; i < cmp->glyph_len; i++) + cmp->offsets[i * 2] -= leftmost; + rightmost -= leftmost; + } + + cmp->pixel_width = rightmost; + cmp->ascent = highest; + cmp->descent = - lowest; + if (cmp->ascent < font_ascent) + cmp->ascent = font_ascent; + if (cmp->descent < font_descent) + cmp->descent = font_descent; + } + + it->pixel_width = cmp->pixel_width; + it->ascent = it->phys_ascent = cmp->ascent; + it->descent = it->phys_descent = cmp->descent; + + if (face->box != FACE_NO_BOX) + { + int thick = face->box_line_width; + it->ascent += thick; + it->descent += thick; + + if (it->start_of_box_run_p) + it->pixel_width += thick; + if (it->end_of_box_run_p) + it->pixel_width += thick; + } + + /* If face has an overline, add the height of the overline + (1 pixel) and a 1 pixel margin to the character height. */ + if (face->overline_p) + it->ascent += 2; + + take_vertical_position_into_account (it); + + if (it->glyph_row) + x_append_composite_glyph (it); + } + else if (it->what == IT_IMAGE) + x_produce_image_glyph (it); + else if (it->what == IT_STRETCH) + x_produce_stretch_glyph (it); + + /* Accumulate dimensions. Note: can't assume that it->descent > 0 + because this isn't true for images with `:ascent 100'. */ + xassert (it->ascent >= 0 && it->descent >= 0); + if (it->area == TEXT_AREA) + it->current_x += it->pixel_width; + + it->descent += it->extra_line_spacing; + + it->max_ascent = max (it->max_ascent, it->ascent); + it->max_descent = max (it->max_descent, it->descent); + it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent); + it->max_phys_descent = max (it->max_phys_descent, it->phys_descent); +} + + +/* Estimate the pixel height of the mode or top line on frame F. + FACE_ID specifies what line's height to estimate. */ + +int +x_estimate_mode_line_height (f, face_id) + struct frame *f; + enum face_id face_id; +{ + int height = 1; + + /* This function is called so early when Emacs starts that the face + cache and mode line face are not yet initialized. */ + if (FRAME_FACE_CACHE (f)) + { + struct face *face = FACE_FROM_ID (f, face_id); + if (face) + height = FONT_HEIGHT (face->font) + 2 * face->box_line_width; + } + + return height; +} + + +/*********************************************************************** + Glyph display + ***********************************************************************/ + +/* A sequence of glyphs to be drawn in the same face. + + This data structure is not really completely X specific, so it + could possibly, at least partially, be useful for other systems. It + is currently not part of the external redisplay interface because + it's not clear what other systems will need. */ + +struct glyph_string +{ + /* X-origin of the string. */ + int x; + + /* Y-origin and y-position of the base line of this string. */ + int y, ybase; + + /* The width of the string, not including a face extension. */ + int width; + + /* The width of the string, including a face extension. */ + int background_width; + + /* The height of this string. This is the height of the line this + string is drawn in, and can be different from the height of the + font the string is drawn in. */ + int height; + + /* Number of pixels this string overwrites in front of its x-origin. + This number is zero if the string has an lbearing >= 0; it is + -lbearing, if the string has an lbearing < 0. */ + int left_overhang; + + /* Number of pixels this string overwrites past its right-most + nominal x-position, i.e. x + width. Zero if the string's + rbearing is <= its nominal width, rbearing - width otherwise. */ + int right_overhang; + + /* The frame on which the glyph string is drawn. */ + struct frame *f; + + /* The window on which the glyph string is drawn. */ + struct window *w; + + /* X display and window for convenience. */ + Display *display; + Window window; + + /* The glyph row for which this string was built. It determines the + y-origin and height of the string. */ + struct glyph_row *row; + + /* The area within row. */ + enum glyph_row_area area; + + /* Characters to be drawn, and number of characters. */ + XChar2b *char2b; + int nchars; + + /* A face-override for drawing cursors, mouse face and similar. */ + enum draw_glyphs_face hl; + + /* Face in which this string is to be drawn. */ + struct face *face; + + /* Font in which this string is to be drawn. */ + XFontStruct *font; + + /* Font info for this string. */ + struct font_info *font_info; + + /* Non-null means this string describes (part of) a composition. + All characters from char2b are drawn composed. */ + struct composition *cmp; + + /* Index of this glyph string's first character in the glyph + definition of CMP. If this is zero, this glyph string describes + the first character of a composition. */ + int gidx; + + /* 1 means this glyph strings face has to be drawn to the right end + of the window's drawing area. */ + unsigned extends_to_end_of_line_p : 1; + + /* 1 means the background of this string has been drawn. */ + unsigned background_filled_p : 1; + + /* 1 means glyph string must be drawn with 16-bit functions. */ + unsigned two_byte_p : 1; + + /* 1 means that the original font determined for drawing this glyph + string could not be loaded. The member `font' has been set to + the frame's default font in this case. */ + unsigned font_not_found_p : 1; + + /* 1 means that the face in which this glyph string is drawn has a + stipple pattern. */ + unsigned stippled_p : 1; + + /* 1 means only the foreground of this glyph string must be drawn, + and we should use the physical height of the line this glyph + string appears in as clip rect. */ + unsigned for_overlaps_p : 1; + + /* The GC to use for drawing this glyph string. */ + GC gc; + + /* A pointer to the first glyph in the string. This glyph + corresponds to char2b[0]. Needed to draw rectangles if + font_not_found_p is 1. */ + struct glyph *first_glyph; + + /* Image, if any. */ + struct image *img; + + struct glyph_string *next, *prev; +}; + + +#if 0 + +static void +x_dump_glyph_string (s) + struct glyph_string *s; +{ + fprintf (stderr, "glyph string\n"); + fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n", + s->x, s->y, s->width, s->height); + fprintf (stderr, " ybase = %d\n", s->ybase); + fprintf (stderr, " hl = %d\n", s->hl); + fprintf (stderr, " left overhang = %d, right = %d\n", + s->left_overhang, s->right_overhang); + fprintf (stderr, " nchars = %d\n", s->nchars); + fprintf (stderr, " extends to end of line = %d\n", + s->extends_to_end_of_line_p); + fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font)); + fprintf (stderr, " bg width = %d\n", s->background_width); +} + +#endif /* GLYPH_DEBUG */ + + + +static void x_append_glyph_string_lists P_ ((struct glyph_string **, + struct glyph_string **, + struct glyph_string *, + struct glyph_string *)); +static void x_prepend_glyph_string_lists P_ ((struct glyph_string **, + struct glyph_string **, + struct glyph_string *, + struct glyph_string *)); +static void x_append_glyph_string P_ ((struct glyph_string **, + struct glyph_string **, + struct glyph_string *)); +static int x_left_overwritten P_ ((struct glyph_string *)); +static int x_left_overwriting P_ ((struct glyph_string *)); +static int x_right_overwritten P_ ((struct glyph_string *)); +static int x_right_overwriting P_ ((struct glyph_string *)); +static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int, + int)); +static void x_init_glyph_string P_ ((struct glyph_string *, + XChar2b *, struct window *, + struct glyph_row *, + enum glyph_row_area, int, + enum draw_glyphs_face)); +static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *, + enum glyph_row_area, int, int, + enum draw_glyphs_face, int *, int *, int)); +static void x_set_glyph_string_clipping P_ ((struct glyph_string *)); +static void x_set_glyph_string_gc P_ ((struct glyph_string *)); +static void x_draw_glyph_string_background P_ ((struct glyph_string *, + int)); +static void x_draw_glyph_string_foreground P_ ((struct glyph_string *)); +static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *)); +static void x_draw_glyph_string_box P_ ((struct glyph_string *)); +static void x_draw_glyph_string P_ ((struct glyph_string *)); +static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *)); +static void x_set_cursor_gc P_ ((struct glyph_string *)); +static void x_set_mode_line_face_gc P_ ((struct glyph_string *)); +static void x_set_mouse_face_gc P_ ((struct glyph_string *)); +static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *, + int *, int *)); +static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int)); +static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap, + unsigned long *, double, int)); +static void x_setup_relief_color P_ ((struct frame *, struct relief *, + double, int, unsigned long)); +static void x_setup_relief_colors P_ ((struct glyph_string *)); +static void x_draw_image_glyph_string P_ ((struct glyph_string *)); +static void x_draw_image_relief P_ ((struct glyph_string *)); +static void x_draw_image_foreground P_ ((struct glyph_string *)); +static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap)); +static void x_fill_image_glyph_string P_ ((struct glyph_string *)); +static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int, + int, int, int)); +static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int, + int, int, int, int, XRectangle *)); +static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int, + int, int, int, XRectangle *)); +static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *, + enum glyph_row_area)); +static int x_fill_stretch_glyph_string P_ ((struct glyph_string *, + struct glyph_row *, + enum glyph_row_area, int, int)); + +#if GLYPH_DEBUG +static void x_check_font P_ ((struct frame *, XFontStruct *)); +#endif + + +/* Append the list of glyph strings with head H and tail T to the list + with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */ + +static INLINE void +x_append_glyph_string_lists (head, tail, h, t) + struct glyph_string **head, **tail; + struct glyph_string *h, *t; +{ + if (h) + { + if (*head) + (*tail)->next = h; + else + *head = h; + h->prev = *tail; + *tail = t; + } +} + + +/* Prepend the list of glyph strings with head H and tail T to the + list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the + result. */ + +static INLINE void +x_prepend_glyph_string_lists (head, tail, h, t) + struct glyph_string **head, **tail; + struct glyph_string *h, *t; +{ + if (h) + { + if (*head) + (*head)->prev = t; + else + *tail = t; + t->next = *head; + *head = h; + } +} + + +/* Append glyph string S to the list with head *HEAD and tail *TAIL. + Set *HEAD and *TAIL to the resulting list. */ + +static INLINE void +x_append_glyph_string (head, tail, s) + struct glyph_string **head, **tail; + struct glyph_string *s; +{ + s->next = s->prev = NULL; + x_append_glyph_string_lists (head, tail, s, s); +} + + +/* Set S->gc to a suitable GC for drawing glyph string S in cursor + face. */ + +static void +x_set_cursor_gc (s) + struct glyph_string *s; +{ + if (s->font == FRAME_FONT (s->f) + && s->face->background == FRAME_BACKGROUND_PIXEL (s->f) + && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f) + && !s->cmp) + s->gc = s->f->output_data.mac->cursor_gc; + else + { + /* Cursor on non-default face: must merge. */ + XGCValues xgcv; + unsigned long mask; + + xgcv.background = s->f->output_data.mac->cursor_pixel; + xgcv.foreground = s->face->background; + + /* If the glyph would be invisible, try a different foreground. */ + if (xgcv.foreground == xgcv.background) + xgcv.foreground = s->face->foreground; + if (xgcv.foreground == xgcv.background) + xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel; + if (xgcv.foreground == xgcv.background) + xgcv.foreground = s->face->foreground; + + /* Make sure the cursor is distinct from text in this face. */ + if (xgcv.background == s->face->background + && xgcv.foreground == s->face->foreground) + { + xgcv.background = s->face->foreground; + xgcv.foreground = s->face->background; + } + + IF_DEBUG (x_check_font (s->f, s->font)); + xgcv.font = s->font; + mask = GCForeground | GCBackground | GCFont; + + if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc) + XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc, + mask, &xgcv); + else + FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc + = XCreateGC (s->display, s->window, mask, &xgcv); + + s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc; + } +} + + +/* Set up S->gc of glyph string S for drawing text in mouse face. */ + +static void +x_set_mouse_face_gc (s) + struct glyph_string *s; +{ + int face_id; + struct face *face; + + /* What face has to be used for the mouse face? */ + face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id; + face = FACE_FROM_ID (s->f, face_id); + if (s->first_glyph->type == CHAR_GLYPH) + face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch); + else + face_id = FACE_FOR_CHAR (s->f, face, 0); + s->face = FACE_FROM_ID (s->f, face_id); + PREPARE_FACE_FOR_DISPLAY (s->f, s->face); + + /* If font in this face is same as S->font, use it. */ + if (s->font == s->face->font) + s->gc = s->face->gc; + else + { + /* Otherwise construct scratch_cursor_gc with values from FACE + but font FONT. */ + XGCValues xgcv; + unsigned long mask; + + xgcv.background = s->face->background; + xgcv.foreground = s->face->foreground; + IF_DEBUG (x_check_font (s->f, s->font)); + xgcv.font = s->font; + mask = GCForeground | GCBackground | GCFont; + + if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc) + XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc, + mask, &xgcv); + else + FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc + = XCreateGC (s->display, s->window, mask, &xgcv); + + s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc; + } + + xassert (s->gc != 0); +} + + +/* Set S->gc of glyph string S to a GC suitable for drawing a mode line. + Faces to use in the mode line have already been computed when the + matrix was built, so there isn't much to do, here. */ + +static INLINE void +x_set_mode_line_face_gc (s) + struct glyph_string *s; +{ + s->gc = s->face->gc; +} + + +/* Set S->gc of glyph string S for drawing that glyph string. Set + S->stippled_p to a non-zero value if the face of S has a stipple + pattern. */ + +static INLINE void +x_set_glyph_string_gc (s) + struct glyph_string *s; +{ + PREPARE_FACE_FOR_DISPLAY (s->f, s->face); + + if (s->hl == DRAW_NORMAL_TEXT) + { + s->gc = s->face->gc; + s->stippled_p = s->face->stipple != 0; + } + else if (s->hl == DRAW_INVERSE_VIDEO) + { + x_set_mode_line_face_gc (s); + s->stippled_p = s->face->stipple != 0; + } + else if (s->hl == DRAW_CURSOR) + { + x_set_cursor_gc (s); + s->stippled_p = 0; + } + else if (s->hl == DRAW_MOUSE_FACE) + { + x_set_mouse_face_gc (s); + s->stippled_p = s->face->stipple != 0; + } + else if (s->hl == DRAW_IMAGE_RAISED + || s->hl == DRAW_IMAGE_SUNKEN) + { + s->gc = s->face->gc; + s->stippled_p = s->face->stipple != 0; + } + else + { + s->gc = s->face->gc; + s->stippled_p = s->face->stipple != 0; + } + + /* GC must have been set. */ + xassert (s->gc != 0); +} + + +/* Return in *R the clipping rectangle for glyph string S. */ + +static void +x_get_glyph_string_clip_rect (s, r) + struct glyph_string *s; + Rect *r; +{ + int r_height, r_width; + + if (s->row->full_width_p) + { + /* Draw full-width. X coordinates are relative to S->w->left. */ + int canon_x = CANON_X_UNIT (s->f); + + r->left = WINDOW_LEFT_MARGIN (s->w) * canon_x; + r_width = XFASTINT (s->w->width) * canon_x; + + if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f)) + { + int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x; + if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f)) + r->left -= width; + } + + r->left += FRAME_INTERNAL_BORDER_WIDTH (s->f); + + /* Unless displaying a mode or menu bar line, which are always + fully visible, clip to the visible part of the row. */ + if (s->w->pseudo_window_p) + r_height = s->row->visible_height; + else + r_height = s->height; + } + else + { + /* This is a text line that may be partially visible. */ + r->left = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0); + r_width = window_box_width (s->w, s->area); + r_height = s->row->visible_height; + } + + /* Don't use S->y for clipping because it doesn't take partially + visible lines into account. For example, it can be negative for + partially visible lines at the top of a window. */ + if (!s->row->full_width_p + && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row)) + r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w); + else + r->top = max (0, s->row->y); + + /* If drawing a tool-bar window, draw it over the internal border + at the top of the window. */ + if (s->w == XWINDOW (s->f->tool_bar_window)) + r->top -= s->f->output_data.mac->internal_border_width; + + /* If S draws overlapping rows, it's sufficient to use the top and + bottom of the window for clipping because this glyph string + intentionally draws over other lines. */ + if (s->for_overlaps_p) + { + r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w); + r_height = window_text_bottom_y (s->w) - r->top; + } + + r->top = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->top); + + r->bottom = r->top + r_height; + r->right = r->left + r_width; +} + + +/* Set clipping for output of glyph string S. S may be part of a mode + line or menu if we don't have X toolkit support. */ + +static INLINE void +x_set_glyph_string_clipping (s) + struct glyph_string *s; +{ + Rect r; + x_get_glyph_string_clip_rect (s, &r); + mac_set_clip_rectangle (s->display, s->window, &r); +} + + +/* Compute left and right overhang of glyph string S. If S is a glyph + string for a composition, assume overhangs don't exist. */ + +static INLINE void +x_compute_glyph_string_overhangs (s) + struct glyph_string *s; +{ + if (s->cmp == NULL + && s->first_glyph->type == CHAR_GLYPH) + { + XCharStruct cs; + int direction, font_ascent, font_descent; + XTextExtents16 (s->font, s->char2b, s->nchars, &direction, + &font_ascent, &font_descent, &cs); + s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0; + s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0; + } +} + + +/* Compute overhangs and x-positions for glyph string S and its + predecessors, or successors. X is the starting x-position for S. + BACKWARD_P non-zero means process predecessors. */ + +static void +x_compute_overhangs_and_x (s, x, backward_p) + struct glyph_string *s; + int x; + int backward_p; +{ + if (backward_p) + { + while (s) + { + x_compute_glyph_string_overhangs (s); + x -= s->width; + s->x = x; + s = s->prev; + } + } + else + { + while (s) + { + x_compute_glyph_string_overhangs (s); + s->x = x; + x += s->width; + s = s->next; + } + } +} + + +/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on + frame F. Overhangs of glyphs other than type CHAR_GLYPH are + assumed to be zero. */ + +void +x_get_glyph_overhangs (glyph, f, left, right) + struct glyph *glyph; + struct frame *f; + int *left, *right; +{ + *left = *right = 0; + + if (glyph->type == CHAR_GLYPH) + { + XFontStruct *font; + struct face *face; + struct font_info *font_info; + XChar2b char2b; + XCharStruct *pcm; + + face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL); + font = face->font; + font_info = FONT_INFO_FROM_ID (f, face->font_info_id); + if (font + && (pcm = x_per_char_metric (font, &char2b))) + { + if (pcm->rbearing > pcm->width) + *right = pcm->rbearing - pcm->width; + if (pcm->lbearing < 0) + *left = -pcm->lbearing; + } + } +} + + +/* Return the index of the first glyph preceding glyph string S that + is overwritten by S because of S's left overhang. Value is -1 + if no glyphs are overwritten. */ + +static int +x_left_overwritten (s) + struct glyph_string *s; +{ + int k; + + if (s->left_overhang) + { + int x = 0, i; + struct glyph *glyphs = s->row->glyphs[s->area]; + int first = s->first_glyph - glyphs; + + for (i = first - 1; i >= 0 && x > -s->left_overhang; --i) + x -= glyphs[i].pixel_width; + + k = i + 1; + } + else + k = -1; + + return k; +} + + +/* Return the index of the first glyph preceding glyph string S that + is overwriting S because of its right overhang. Value is -1 if no + glyph in front of S overwrites S. */ + +static int +x_left_overwriting (s) + struct glyph_string *s; +{ + int i, k, x; + struct glyph *glyphs = s->row->glyphs[s->area]; + int first = s->first_glyph - glyphs; + + k = -1; + x = 0; + for (i = first - 1; i >= 0; --i) + { + int left, right; + x_get_glyph_overhangs (glyphs + i, s->f, &left, &right); + if (x + right > 0) + k = i; + x -= glyphs[i].pixel_width; + } + + return k; +} + + +/* Return the index of the last glyph following glyph string S that is + not overwritten by S because of S's right overhang. Value is -1 if + no such glyph is found. */ + +static int +x_right_overwritten (s) + struct glyph_string *s; +{ + int k = -1; + + if (s->right_overhang) + { + int x = 0, i; + struct glyph *glyphs = s->row->glyphs[s->area]; + int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars); + int end = s->row->used[s->area]; + + for (i = first; i < end && s->right_overhang > x; ++i) + x += glyphs[i].pixel_width; + + k = i; + } + + return k; +} + + +/* Return the index of the last glyph following glyph string S that + overwrites S because of its left overhang. Value is negative + if no such glyph is found. */ + +static int +x_right_overwriting (s) + struct glyph_string *s; +{ + int i, k, x; + int end = s->row->used[s->area]; + struct glyph *glyphs = s->row->glyphs[s->area]; + int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars); + + k = -1; + x = 0; + for (i = first; i < end; ++i) + { + int left, right; + x_get_glyph_overhangs (glyphs + i, s->f, &left, &right); + if (x - left < 0) + k = i; + x += glyphs[i].pixel_width; + } + + return k; +} + + +/* Fill rectangle X, Y, W, H with background color of glyph string S. */ + +static INLINE void +x_clear_glyph_string_rect (s, x, y, w, h) + struct glyph_string *s; + int x, y, w, h; +{ + XGCValues xgcv; + + xgcv.foreground = s->gc->background; + XFillRectangle (s->display, s->window, &xgcv, x, y, w, h); +} + + +/* Draw the background of glyph_string S. If S->background_filled_p + is non-zero don't draw it. FORCE_P non-zero means draw the + background even if it wouldn't be drawn normally. This is used + when a string preceding S draws into the background of S, or S + contains the first component of a composition. */ + +static void +x_draw_glyph_string_background (s, force_p) + struct glyph_string *s; + int force_p; +{ + /* Nothing to do if background has already been drawn or if it + shouldn't be drawn in the first place. */ + if (!s->background_filled_p) + { +#if 0 /* MAC_TODO: stipple */ + if (s->stippled_p) + { + /* Fill background with a stipple pattern. */ + XSetFillStyle (s->display, s->gc, FillOpaqueStippled); + XFillRectangle (s->display, s->window, s->gc, s->x, + s->y + s->face->box_line_width, + s->background_width, + s->height - 2 * s->face->box_line_width); + XSetFillStyle (s->display, s->gc, FillSolid); + s->background_filled_p = 1; + } + else +#endif + if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width + || s->font_not_found_p + || s->extends_to_end_of_line_p + || force_p) + { + x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width, + s->background_width, + s->height - 2 * s->face->box_line_width); + s->background_filled_p = 1; + } + } +} + + +/* Draw the foreground of glyph string S. */ + +static void +x_draw_glyph_string_foreground (s) + struct glyph_string *s; +{ + int i, x; + + /* If first glyph of S has a left box line, start drawing the text + of S to the right of that box line. */ + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->x + s->face->box_line_width; + else + x = s->x; + + /* Draw characters of S as rectangles if S's font could not be + loaded. */ + if (s->font_not_found_p) + { + for (i = 0; i < s->nchars; ++i) + { + struct glyph *g = s->first_glyph + i; + mac_draw_rectangle (s->display, s->window, + s->gc, x, s->y, g->pixel_width - 1, + s->height - 1); + x += g->pixel_width; + } + } + else + { + char *char1b = (char *) s->char2b; + int boff = s->font_info->baseline_offset; + + if (s->font_info->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff; + + /* If we can use 8-bit functions, condense S->char2b. */ + if (!s->two_byte_p) + for (i = 0; i < s->nchars; ++i) + char1b[i] = s->char2b[i].byte2; + + /* Draw text with XDrawString if background has already been + filled. Otherwise, use XDrawImageString. (Note that + XDrawImageString is usually faster than XDrawString.) Always + use XDrawImageString when drawing the cursor so that there is + no chance that characters under a box cursor are invisible. */ + if (s->for_overlaps_p + || (s->background_filled_p && s->hl != DRAW_CURSOR)) + { + /* Draw characters with 16-bit or 8-bit functions. */ + if (s->two_byte_p) + XDrawString16 (s->display, s->window, s->gc, x, + s->ybase - boff, s->char2b, s->nchars); + else + XDrawString (s->display, s->window, s->gc, x, + s->ybase - boff, char1b, s->nchars); + } + else + { + if (s->two_byte_p) + XDrawImageString16 (s->display, s->window, s->gc, x, + s->ybase - boff, s->char2b, s->nchars); + else + XDrawImageString (s->display, s->window, s->gc, x, + s->ybase - boff, char1b, s->nchars); + } + } +} + +/* Draw the foreground of composite glyph string S. */ + +static void +x_draw_composite_glyph_string_foreground (s) + struct glyph_string *s; +{ + int i, x; + + /* If first glyph of S has a left box line, start drawing the text + of S to the right of that box line. */ + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->x + s->face->box_line_width; + else + x = s->x; + + /* S is a glyph string for a composition. S->gidx is the index of + the first character drawn for glyphs of this composition. + S->gidx == 0 means we are drawing the very first character of + this composition. */ + + /* Draw a rectangle for the composition if the font for the very + first character of the composition could not be loaded. */ + if (s->font_not_found_p) + { + if (s->gidx == 0) + mac_draw_rectangle (s->display, s->window, s->gc, x, s->y, + s->width - 1, s->height - 1); + } + else + { + for (i = 0; i < s->nchars; i++, ++s->gidx) + XDrawString16 (s->display, s->window, s->gc, + x + s->cmp->offsets[s->gidx * 2], + s->ybase - s->cmp->offsets[s->gidx * 2 + 1], + s->char2b + i, 1); + } +} + + +#ifdef USE_X_TOOLKIT + +static struct frame *x_frame_of_widget P_ ((Widget)); + + +/* Return the frame on which widget WIDGET is used.. Abort if frame + cannot be determined. */ + +static struct frame * +x_frame_of_widget (widget) + Widget widget; +{ + struct x_display_info *dpyinfo; + Lisp_Object tail; + struct frame *f; + + dpyinfo = x_display_info_for_display (XtDisplay (widget)); + + /* Find the top-level shell of the widget. Note that this function + can be called when the widget is not yet realized, so XtWindow + (widget) == 0. That's the reason we can't simply use + x_any_window_to_frame. */ + while (!XtIsTopLevelShell (widget)) + widget = XtParent (widget); + + /* Look for a frame with that top-level widget. Allocate the color + on that frame to get the right gamma correction value. */ + for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) + if (GC_FRAMEP (XCAR (tail)) + && (f = XFRAME (XCAR (tail)), + (f->output_data.nothing != 1 + && FRAME_X_DISPLAY_INFO (f) == dpyinfo)) + && f->output_data.x->widget == widget) + return f; + + abort (); +} + + +/* Allocate the color COLOR->pixel on the screen and display of + widget WIDGET in colormap CMAP. If an exact match cannot be + allocated, try the nearest color available. Value is non-zero + if successful. This is called from lwlib. */ + +int +x_alloc_nearest_color_for_widget (widget, cmap, color) + Widget widget; + Colormap cmap; + XColor *color; +{ + struct frame *f = x_frame_of_widget (widget); + return x_alloc_nearest_color (f, cmap, color); +} + + +#endif /* USE_X_TOOLKIT */ + +#if 0 + +/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap + CMAP. If an exact match can't be allocated, try the nearest color + available. Value is non-zero if successful. Set *COLOR to the + color allocated. */ + +int +x_alloc_nearest_color (f, cmap, color) + struct frame *f; + Colormap cmap; + XColor *color; +{ + Display *display = FRAME_X_DISPLAY (f); + Screen *screen = FRAME_X_SCREEN (f); + int rc; + + gamma_correct (f, color); + rc = XAllocColor (display, cmap, color); + if (rc == 0) + { + /* If we got to this point, the colormap is full, so we're going + to try to get the next closest color. The algorithm used is + a least-squares matching, which is what X uses for closest + color matching with StaticColor visuals. */ + int nearest, i; + unsigned long nearest_delta = ~0; + int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen)); + XColor *cells = (XColor *) alloca (ncells * sizeof *cells); + + for (i = 0; i < ncells; ++i) + cells[i].pixel = i; + XQueryColors (display, cmap, cells, ncells); + + for (nearest = i = 0; i < ncells; ++i) + { + long dred = (color->red >> 8) - (cells[i].red >> 8); + long dgreen = (color->green >> 8) - (cells[i].green >> 8); + long dblue = (color->blue >> 8) - (cells[i].blue >> 8); + unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue; + + if (delta < nearest_delta) + { + nearest = i; + nearest_delta = delta; + } + } + + color->red = cells[nearest].red; + color->green = cells[nearest].green; + color->blue = cells[nearest].blue; + rc = XAllocColor (display, cmap, color); + } + +#ifdef DEBUG_X_COLORS + if (rc) + register_color (color->pixel); +#endif /* DEBUG_X_COLORS */ + + return rc; +} + + +/* Allocate color PIXEL on frame F. PIXEL must already be allocated. + It's necessary to do this instead of just using PIXEL directly to + get color reference counts right. */ + +unsigned long +x_copy_color (f, pixel) + struct frame *f; + unsigned long pixel; +{ + XColor color; + + color.pixel = pixel; + BLOCK_INPUT; + XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color); + XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color); + UNBLOCK_INPUT; +#ifdef DEBUG_X_COLORS + register_color (pixel); +#endif + return color.pixel; +} + + +/* Allocate color PIXEL on display DPY. PIXEL must already be allocated. + It's necessary to do this instead of just using PIXEL directly to + get color reference counts right. */ + +unsigned long +x_copy_dpy_color (dpy, cmap, pixel) + Display *dpy; + Colormap cmap; + unsigned long pixel; +{ + XColor color; + + color.pixel = pixel; + BLOCK_INPUT; + XQueryColor (dpy, cmap, &color); + XAllocColor (dpy, cmap, &color); + UNBLOCK_INPUT; +#ifdef DEBUG_X_COLORS + register_color (pixel); +#endif + return color.pixel; +} + +#endif + +/* Allocate a color which is lighter or darker than *COLOR by FACTOR + or DELTA. Try a color with RGB values multiplied by FACTOR first. + If this produces the same color as COLOR, try a color where all RGB + values have DELTA added. Return the allocated color in *COLOR. + DISPLAY is the X display, CMAP is the colormap to operate on. + Value is non-zero if successful. */ + +static int +mac_alloc_lighter_color (f, color, factor, delta) + struct frame *f; + unsigned long *color; + double factor; + int delta; +{ + unsigned long new; + + /* Change RGB values by specified FACTOR. Avoid overflow! */ + xassert (factor >= 0); + new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))), + min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))), + min (0xff, (int) (factor * BLUE_FROM_ULONG (*color)))); + if (new == *color) + new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))), + max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))), + max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color))))); + + /* MAC_TODO: Map to palette and retry with delta if same? */ + /* MAC_TODO: Free colors (if using palette)? */ + + if (new == *color) + return 0; + + *color = new; + + return 1; +} + + +/* Set up the foreground color for drawing relief lines of glyph + string S. RELIEF is a pointer to a struct relief containing the GC + with which lines will be drawn. Use a color that is FACTOR or + DELTA lighter or darker than the relief's background which is found + in S->f->output_data.x->relief_background. If such a color cannot + be allocated, use DEFAULT_PIXEL, instead. */ + +static void +x_setup_relief_color (f, relief, factor, delta, default_pixel) + struct frame *f; + struct relief *relief; + double factor; + int delta; + unsigned long default_pixel; +{ + XGCValues xgcv; + struct mac_output *di = f->output_data.mac; + unsigned long mask = GCForeground; + unsigned long pixel; + unsigned long background = di->relief_background; + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + /* MAC_TODO: Free colors (if using palette)? */ + + /* Allocate new color. */ + xgcv.foreground = default_pixel; + pixel = background; + if (mac_alloc_lighter_color (f, &pixel, factor, delta)) + { + relief->allocated_p = 1; + xgcv.foreground = relief->pixel = pixel; + } + + if (relief->gc == 0) + { +#if 0 /* MAC_TODO: stipple */ + xgcv.stipple = dpyinfo->gray; + mask |= GCStipple; +#endif + relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv); + } + else + XChangeGC (NULL, relief->gc, mask, &xgcv); +} + + +/* Set up colors for the relief lines around glyph string S. */ + +static void +x_setup_relief_colors (s) + struct glyph_string *s; +{ + struct mac_output *di = s->f->output_data.mac; + unsigned long color; + + if (s->face->use_box_color_for_shadows_p) + color = s->face->box_color; + else + { + XGCValues xgcv; + + /* Get the background color of the face. */ + XGetGCValues (s->display, s->gc, GCBackground, &xgcv); + color = xgcv.background; + } + + if (di->white_relief.gc == 0 + || color != di->relief_background) + { + di->relief_background = color; + x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000, + WHITE_PIX_DEFAULT (s->f)); + x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000, + BLACK_PIX_DEFAULT (s->f)); + } +} + + +/* Draw a relief on frame F inside the rectangle given by LEFT_X, + TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief + to draw, it must be >= 0. RAISED_P non-zero means draw a raised + relief. LEFT_P non-zero means draw a relief on the left side of + the rectangle. RIGHT_P non-zero means draw a relief on the right + side of the rectangle. CLIP_RECT is the clipping rectangle to use + when drawing. */ + +static void +x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, + raised_p, left_p, right_p, clip_rect) + struct frame *f; + int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p; + Rect *clip_rect; +{ + int i; + GC gc; + + if (raised_p) + gc = f->output_data.mac->white_relief.gc; + else + gc = f->output_data.mac->black_relief.gc; + mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect); + + /* Top. */ + for (i = 0; i < width; ++i) + XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + left_x + i * left_p, top_y + i, + right_x + 1 - i * right_p, top_y + i); + + /* Left. */ + if (left_p) + for (i = 0; i < width; ++i) + XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + left_x + i, top_y + i, left_x + i, bottom_y - i); + + mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); + if (raised_p) + gc = f->output_data.mac->black_relief.gc; + else + gc = f->output_data.mac->white_relief.gc; + mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect); + + /* Bottom. */ + for (i = 0; i < width; ++i) + XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + left_x + i * left_p, bottom_y - i, + right_x + 1 - i * right_p, bottom_y - i); + + /* Right. */ + if (right_p) + for (i = 0; i < width; ++i) + XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + right_x - i, top_y + i + 1, right_x - i, bottom_y - i); + + mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); +} + + +/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y, + RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to + draw, it must be >= 0. LEFT_P non-zero means draw a line on the + left side of the rectangle. RIGHT_P non-zero means draw a line + on the right side of the rectangle. CLIP_RECT is the clipping + rectangle to use when drawing. */ + +static void +x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width, + left_p, right_p, clip_rect) + struct glyph_string *s; + int left_x, top_y, right_x, bottom_y, left_p, right_p; + Rect *clip_rect; +{ + XGCValues xgcv; + + xgcv.foreground = s->face->box_color; + mac_set_clip_rectangle (s->display, s->window, clip_rect); + + /* Top. */ + XFillRectangle (s->display, s->window, &xgcv, + left_x, top_y, right_x - left_x, width); + + /* Left. */ + if (left_p) + XFillRectangle (s->display, s->window, &xgcv, + left_x, top_y, width, bottom_y - top_y); + + /* Bottom. */ + XFillRectangle (s->display, s->window, &xgcv, + left_x, bottom_y - width, right_x - left_x, width); + + /* Right. */ + if (right_p) + XFillRectangle (s->display, s->window, &xgcv, + right_x - width, top_y, width, bottom_y - top_y); + + mac_reset_clipping (s->display, s->window); +} + + +/* Draw a box around glyph string S. */ + +static void +x_draw_glyph_string_box (s) + struct glyph_string *s; +{ + int width, left_x, right_x, top_y, bottom_y, last_x, raised_p; + int left_p, right_p; + struct glyph *last_glyph; + Rect clip_rect; + + last_x = window_box_right (s->w, s->area); + if (s->row->full_width_p + && !s->w->pseudo_window_p) + { + last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f); + if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f)) + last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f); + } + + /* The glyph that may have a right box line. */ + last_glyph = (s->cmp || s->img + ? s->first_glyph + : s->first_glyph + s->nchars - 1); + + width = s->face->box_line_width; + raised_p = s->face->box == FACE_RAISED_BOX; + left_x = s->x; + right_x = ((s->row->full_width_p + ? last_x - 1 + : min (last_x, s->x + s->background_width) - 1)); + top_y = s->y; + bottom_y = top_y + s->height - 1; + + left_p = (s->first_glyph->left_box_line_p + || (s->hl == DRAW_MOUSE_FACE + && (s->prev == NULL + || s->prev->hl != s->hl))); + right_p = (last_glyph->right_box_line_p + || (s->hl == DRAW_MOUSE_FACE + && (s->next == NULL + || s->next->hl != s->hl))); + + x_get_glyph_string_clip_rect (s, &clip_rect); + + if (s->face->box == FACE_SIMPLE_BOX) + x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width, + left_p, right_p, &clip_rect); + else + { + x_setup_relief_colors (s); + x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y, + width, raised_p, left_p, right_p, &clip_rect); + } +} + + +/* Draw foreground of image glyph string S. */ + +static void +x_draw_image_foreground (s) + struct glyph_string *s; +{ + int x; + int y = s->ybase - image_ascent (s->img, s->face); + + /* If first glyph of S has a left box line, start drawing it to the + right of that line. */ + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->x + s->face->box_line_width; + else + x = s->x; + + /* If there is a margin around the image, adjust x- and y-position + by that margin. */ + if (s->img->margin) + { + x += s->img->margin; + y += s->img->margin; + } + + if (s->img->pixmap) + { +#if 0 /* MAC_TODO: image mask */ + if (s->img->mask) + { + /* We can't set both a clip mask and use XSetClipRectangles + because the latter also sets a clip mask. We also can't + trust on the shape extension to be available + (XShapeCombineRegion). So, compute the rectangle to draw + manually. */ + unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin + | GCFunction); + XGCValues xgcv; + XRectangle clip_rect, image_rect, r; + + xgcv.clip_mask = s->img->mask; + xgcv.clip_x_origin = x; + xgcv.clip_y_origin = y; + xgcv.function = GXcopy; + XChangeGC (s->display, s->gc, mask, &xgcv); + + x_get_glyph_string_clip_rect (s, &clip_rect); + image_rect.x = x; + image_rect.y = y; + image_rect.width = s->img->width; + image_rect.height = s->img->height; + if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) + XCopyArea (s->display, s->img->pixmap, s->window, s->gc, + r.x - x, r.y - y, r.width, r.height, r.x, r.y); + } + else +#endif + { + mac_copy_area (s->display, s->img->pixmap, s->window, s->gc, + 0, 0, s->img->width, s->img->height, x, y); + + /* When the image has a mask, we can expect that at + least part of a mouse highlight or a block cursor will + be visible. If the image doesn't have a mask, make + a block cursor visible by drawing a rectangle around + the image. I believe it's looking better if we do + nothing here for mouse-face. */ + if (s->hl == DRAW_CURSOR) + mac_draw_rectangle (s->display, s->window, s->gc, x, y, + s->img->width - 1, s->img->height - 1); + } + } + else + /* Draw a rectangle if image could not be loaded. */ + mac_draw_rectangle (s->display, s->window, s->gc, x, y, + s->img->width - 1, s->img->height - 1); +} + + +/* Draw a relief around the image glyph string S. */ + +static void +x_draw_image_relief (s) + struct glyph_string *s; +{ + int x0, y0, x1, y1, thick, raised_p; + Rect r; + int x; + int y = s->ybase - image_ascent (s->img, s->face); + + /* If first glyph of S has a left box line, start drawing it to the + right of that line. */ + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->x + s->face->box_line_width; + else + x = s->x; + + /* If there is a margin around the image, adjust x- and y-position + by that margin. */ + if (s->img->margin) + { + x += s->img->margin; + y += s->img->margin; + } + + if (s->hl == DRAW_IMAGE_SUNKEN + || s->hl == DRAW_IMAGE_RAISED) + { + thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3; + raised_p = s->hl == DRAW_IMAGE_RAISED; + } + else + { + thick = abs (s->img->relief); + raised_p = s->img->relief > 0; + } + + x0 = x - thick; + y0 = y - thick; + x1 = x + s->img->width + thick - 1; + y1 = y + s->img->height + thick - 1; + + x_setup_relief_colors (s); + x_get_glyph_string_clip_rect (s, &r); + x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r); +} + + +/* Draw the foreground of image glyph string S to PIXMAP. */ + +static void +x_draw_image_foreground_1 (s, pixmap) + struct glyph_string *s; + Pixmap pixmap; +{ + int x; + int y = s->ybase - s->y - image_ascent (s->img, s->face); + + /* If first glyph of S has a left box line, start drawing it to the + right of that line. */ + if (s->face->box != FACE_NO_BOX + && s->first_glyph->left_box_line_p) + x = s->face->box_line_width; + else + x = 0; + + /* If there is a margin around the image, adjust x- and y-position + by that margin. */ + if (s->img->margin) + { + x += s->img->margin; + y += s->img->margin; + } + + if (s->img->pixmap) + { +#if 0 /* MAC_TODO: image mask */ + if (s->img->mask) + { + /* We can't set both a clip mask and use XSetClipRectangles + because the latter also sets a clip mask. We also can't + trust on the shape extension to be available + (XShapeCombineRegion). So, compute the rectangle to draw + manually. */ + unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin + | GCFunction); + XGCValues xgcv; + + xgcv.clip_mask = s->img->mask; + xgcv.clip_x_origin = x; + xgcv.clip_y_origin = y; + xgcv.function = GXcopy; + XChangeGC (s->display, s->gc, mask, &xgcv); + + XCopyArea (s->display, s->img->pixmap, pixmap, s->gc, + 0, 0, s->img->width, s->img->height, x, y); + XSetClipMask (s->display, s->gc, None); + } + else +#endif + { + mac_copy_area_to_pixmap (s->display, s->img->pixmap, pixmap, s->gc, + 0, 0, s->img->width, s->img->height, x, y); + + /* When the image has a mask, we can expect that at + least part of a mouse highlight or a block cursor will + be visible. If the image doesn't have a mask, make + a block cursor visible by drawing a rectangle around + the image. I believe it's looking better if we do + nothing here for mouse-face. */ + if (s->hl == DRAW_CURSOR) + mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y, + s->img->width - 1, s->img->height - 1); + } + } + else + /* Draw a rectangle if image could not be loaded. */ + mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y, + s->img->width - 1, s->img->height - 1); +} + + +/* Draw part of the background of glyph string S. X, Y, W, and H + give the rectangle to draw. */ + +static void +x_draw_glyph_string_bg_rect (s, x, y, w, h) + struct glyph_string *s; + int x, y, w, h; +{ +#if 0 /* MAC_TODO: stipple */ + if (s->stippled_p) + { + /* Fill background with a stipple pattern. */ + XSetFillStyle (s->display, s->gc, FillOpaqueStippled); + XFillRectangle (s->display, s->window, s->gc, x, y, w, h); + XSetFillStyle (s->display, s->gc, FillSolid); + } + else +#endif + x_clear_glyph_string_rect (s, x, y, w, h); +} + + +/* Draw image glyph string S. + + s->y + s->x +------------------------- + | s->face->box + | + | +------------------------- + | | s->img->margin + | | + | | +------------------- + | | | the image + + */ + +static void +x_draw_image_glyph_string (s) + struct glyph_string *s; +{ + int x, y; + int box_line_width = s->face->box_line_width; + int margin = s->img->margin; + int height; + Pixmap pixmap = 0; + + height = s->height - 2 * box_line_width; + + /* Fill background with face under the image. Do it only if row is + taller than image or if image has a clip mask to reduce + flickering. */ + s->stippled_p = s->face->stipple != 0; + if (height > s->img->height + || margin +#if 0 /* MAC_TODO: image mask */ + || s->img->mask +#endif + || s->img->pixmap == 0 + || s->width != s->background_width) + { + if (box_line_width && s->first_glyph->left_box_line_p) + x = s->x + box_line_width; + else + x = s->x; + + y = s->y + box_line_width; + +#if 0 /* MAC_TODO: image mask */ + if (s->img->mask) + { + /* Create a pixmap as large as the glyph string Fill it with + the background color. Copy the image to it, using its + mask. Copy the temporary pixmap to the display. */ + Screen *screen = FRAME_X_SCREEN (s->f); + int depth = DefaultDepthOfScreen (screen); + + /* Create a pixmap as large as the glyph string. */ + pixmap = XCreatePixmap (s->display, s->window, + s->background_width, + s->height, depth); + + /* Don't clip in the following because we're working on the + pixmap. */ + XSetClipMask (s->display, s->gc, None); + + /* Fill the pixmap with the background color/stipple. */ + if (s->stippled_p) + { + /* Fill background with a stipple pattern. */ + XSetFillStyle (s->display, s->gc, FillOpaqueStippled); + XFillRectangle (s->display, pixmap, s->gc, + 0, 0, s->background_width, s->height); + XSetFillStyle (s->display, s->gc, FillSolid); + } + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground | GCBackground, + &xgcv); + XSetForeground (s->display, s->gc, xgcv.background); + XFillRectangle (s->display, pixmap, s->gc, + 0, 0, s->background_width, s->height); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + else +#endif + /* Implementation idea: Is it possible to construct a mask? + We could look at the color at the margins of the image, and + say that this color is probably the background color of the + image. */ + x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height); + + s->background_filled_p = 1; + } + + /* Draw the foreground. */ + if (pixmap != 0) + { + x_draw_image_foreground_1 (s, pixmap); + x_set_glyph_string_clipping (s); + mac_copy_area (s->display, pixmap, s->window, s->gc, + 0, 0, s->background_width, s->height, s->x, s->y); + XFreePixmap (s->display, pixmap); + } + else + x_draw_image_foreground (s); + + /* If we must draw a relief around the image, do it. */ + if (s->img->relief + || s->hl == DRAW_IMAGE_RAISED + || s->hl == DRAW_IMAGE_SUNKEN) + x_draw_image_relief (s); +} + + +/* Draw stretch glyph string S. */ + +static void +x_draw_stretch_glyph_string (s) + struct glyph_string *s; +{ + xassert (s->first_glyph->type == STRETCH_GLYPH); + s->stippled_p = s->face->stipple != 0; + + if (s->hl == DRAW_CURSOR + && !x_stretch_cursor_p) + { + /* If `x-stretch-block-cursor' is nil, don't draw a block cursor + as wide as the stretch glyph. */ + int width = min (CANON_X_UNIT (s->f), s->background_width); + + /* Draw cursor. */ + x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height); + + /* Clear rest using the GC of the original non-cursor face. */ + if (width < s->background_width) + { + GC gc = s->face->gc; + int x = s->x + width, y = s->y; + int w = s->background_width - width, h = s->height; + Rect r; + + x_get_glyph_string_clip_rect (s, &r); + mac_set_clip_rectangle (s->display, s->window, &r); + +#if 0 /* MAC_TODO: stipple */ + if (s->face->stipple) + { + /* Fill background with a stipple pattern. */ + XSetFillStyle (s->display, gc, FillOpaqueStippled); + XFillRectangle (s->display, s->window, gc, x, y, w, h); + XSetFillStyle (s->display, gc, FillSolid); + } + else +#endif + { + XGCValues xgcv; + XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv); + XSetForeground (s->display, gc, xgcv.background); + XFillRectangle (s->display, s->window, gc, x, y, w, h); + XSetForeground (s->display, gc, xgcv.foreground); + } + } + } + else + x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width, + s->height); + + s->background_filled_p = 1; +} + + +/* Draw glyph string S. */ + +static void +x_draw_glyph_string (s) + struct glyph_string *s; +{ + /* If S draws into the background of its successor, draw the + background of the successor first so that S can draw into it. + This makes S->next use XDrawString instead of XDrawImageString. */ + if (s->next && s->right_overhang && !s->for_overlaps_p) + { + xassert (s->next->img == NULL); + x_set_glyph_string_gc (s->next); + x_set_glyph_string_clipping (s->next); + x_draw_glyph_string_background (s->next, 1); + } + + /* Set up S->gc, set clipping and draw S. */ + x_set_glyph_string_gc (s); + x_set_glyph_string_clipping (s); + + switch (s->first_glyph->type) + { + case IMAGE_GLYPH: + x_draw_image_glyph_string (s); + break; + + case STRETCH_GLYPH: + x_draw_stretch_glyph_string (s); + break; + + case CHAR_GLYPH: + if (s->for_overlaps_p) + s->background_filled_p = 1; + else + x_draw_glyph_string_background (s, 0); + x_draw_glyph_string_foreground (s); + break; + + case COMPOSITE_GLYPH: + if (s->for_overlaps_p || s->gidx > 0) + s->background_filled_p = 1; + else + x_draw_glyph_string_background (s, 1); + x_draw_composite_glyph_string_foreground (s); + break; + + default: + abort (); + } + + if (!s->for_overlaps_p) + { + /* Draw underline. */ + if (s->face->underline_p) + { + unsigned long h = 1; + unsigned long dy = s->height - h; + + if (s->face->underline_defaulted_p) + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->underline_color); + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + + /* Draw overline. */ + if (s->face->overline_p) + { + unsigned long dy = 0, h = 1; + + if (s->face->overline_color_defaulted_p) + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->overline_color); + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + + /* Draw strike-through. */ + if (s->face->strike_through_p) + { + unsigned long h = 1; + unsigned long dy = (s->height - h) / 2; + + if (s->face->strike_through_color_defaulted_p) + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->strike_through_color); + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + + /* Draw relief. */ + if (s->face->box != FACE_NO_BOX) + x_draw_glyph_string_box (s); + } + + /* Reset clipping. */ + mac_reset_clipping (s->display, s->window); +} + + +static int x_fill_composite_glyph_string P_ ((struct glyph_string *, + struct face **, int)); + + +/* Fill glyph string S with composition components specified by S->cmp. + + FACES is an array of faces for all components of this composition. + S->gidx is the index of the first component for S. + OVERLAPS_P non-zero means S should draw the foreground only, and + use its physical height for clipping. + + Value is the index of a component not in S. */ + +static int +x_fill_composite_glyph_string (s, faces, overlaps_p) + struct glyph_string *s; + struct face **faces; + int overlaps_p; +{ + int i; + + xassert (s); + + s->for_overlaps_p = overlaps_p; + + s->face = faces[s->gidx]; + s->font = s->face->font; + s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); + + /* For all glyphs of this composition, starting at the offset + S->gidx, until we reach the end of the definition or encounter a + glyph that requires the different face, add it to S. */ + ++s->nchars; + for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i) + ++s->nchars; + + /* All glyph strings for the same composition has the same width, + i.e. the width set for the first component of the composition. */ + + s->width = s->first_glyph->pixel_width; + + /* If the specified font could not be loaded, use the frame's + default font, but record the fact that we couldn't load it in + the glyph string so that we can draw rectangles for the + characters of the glyph string. */ + if (s->font == NULL) + { + s->font_not_found_p = 1; + s->font = FRAME_FONT (s->f); + } + + /* Adjust base line for subscript/superscript text. */ + s->ybase += s->first_glyph->voffset; + + xassert (s->face && s->face->gc); + + /* This glyph string must always be drawn with 16-bit functions. */ + s->two_byte_p = 1; + + return s->gidx + s->nchars; +} + + +/* Fill glyph string S from a sequence of character glyphs. + + FACE_ID is the face id of the string. START is the index of the + first glyph to consider, END is the index of the last + 1. + OVERLAPS_P non-zero means S should draw the foreground only, and + use its physical height for clipping. + + Value is the index of the first glyph not in S. */ + +static int +x_fill_glyph_string (s, face_id, start, end, overlaps_p) + struct glyph_string *s; + int face_id; + int start, end, overlaps_p; +{ + struct glyph *glyph, *last; + int voffset; + int glyph_not_available_p; + + xassert (s->f == XFRAME (s->w->frame)); + xassert (s->nchars == 0); + xassert (start >= 0 && end > start); + + s->for_overlaps_p = overlaps_p, + glyph = s->row->glyphs[s->area] + start; + last = s->row->glyphs[s->area] + end; + voffset = glyph->voffset; + + glyph_not_available_p = glyph->glyph_not_available_p; + + while (glyph < last + && glyph->type == CHAR_GLYPH + && glyph->voffset == voffset + /* Same face id implies same font, nowadays. */ + && glyph->face_id == face_id + && glyph->glyph_not_available_p == glyph_not_available_p) + { + int two_byte_p; + + s->face = x_get_glyph_face_and_encoding (s->f, glyph, + s->char2b + s->nchars, + &two_byte_p); + s->two_byte_p = two_byte_p; + ++s->nchars; + xassert (s->nchars <= end - start); + s->width += glyph->pixel_width; + ++glyph; + } + + s->font = s->face->font; + s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); + + /* If the specified font could not be loaded, use the frame's font, + but record the fact that we couldn't load it in + S->font_not_found_p so that we can draw rectangles for the + characters of the glyph string. */ + if (s->font == NULL || glyph_not_available_p) + { + s->font_not_found_p = 1; + s->font = FRAME_FONT (s->f); + } + + /* Adjust base line for subscript/superscript text. */ + s->ybase += voffset; + + xassert (s->face && s->face->gc); + return glyph - s->row->glyphs[s->area]; +} + + +/* Fill glyph string S from image glyph S->first_glyph. */ + +static void +x_fill_image_glyph_string (s) + struct glyph_string *s; +{ + xassert (s->first_glyph->type == IMAGE_GLYPH); + s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id); + xassert (s->img); + s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + s->font = s->face->font; + s->width = s->first_glyph->pixel_width; + + /* Adjust base line for subscript/superscript text. */ + s->ybase += s->first_glyph->voffset; +} + + +/* Fill glyph string S from a sequence of stretch glyphs. + + ROW is the glyph row in which the glyphs are found, AREA is the + area within the row. START is the index of the first glyph to + consider, END is the index of the last + 1. + + Value is the index of the first glyph not in S. */ + +static int +x_fill_stretch_glyph_string (s, row, area, start, end) + struct glyph_string *s; + struct glyph_row *row; + enum glyph_row_area area; + int start, end; +{ + struct glyph *glyph, *last; + int voffset, face_id; + + xassert (s->first_glyph->type == STRETCH_GLYPH); + + glyph = s->row->glyphs[s->area] + start; + last = s->row->glyphs[s->area] + end; + face_id = glyph->face_id; + s->face = FACE_FROM_ID (s->f, face_id); + s->font = s->face->font; + s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); + s->width = glyph->pixel_width; + voffset = glyph->voffset; + + for (++glyph; + (glyph < last + && glyph->type == STRETCH_GLYPH + && glyph->voffset == voffset + && glyph->face_id == face_id); + ++glyph) + s->width += glyph->pixel_width; + + /* Adjust base line for subscript/superscript text. */ + s->ybase += voffset; + + xassert (s->face && s->face->gc); + return glyph - s->row->glyphs[s->area]; +} + + +/* Initialize glyph string S. CHAR2B is a suitably allocated vector + of XChar2b structures for S; it can't be allocated in + x_init_glyph_string because it must be allocated via `alloca'. W + is the window on which S is drawn. ROW and AREA are the glyph row + and area within the row from which S is constructed. START is the + index of the first glyph structure covered by S. HL is a + face-override for drawing S. */ + +static void +x_init_glyph_string (s, char2b, w, row, area, start, hl) + struct glyph_string *s; + XChar2b *char2b; + struct window *w; + struct glyph_row *row; + enum glyph_row_area area; + int start; + enum draw_glyphs_face hl; +{ + bzero (s, sizeof *s); + s->w = w; + s->f = XFRAME (w->frame); + s->display = FRAME_MAC_DISPLAY (s->f); + s->window = FRAME_MAC_WINDOW (s->f); + s->char2b = char2b; + s->hl = hl; + s->row = row; + s->area = area; + s->first_glyph = row->glyphs[area] + start; + s->height = row->height; + s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + + /* Display the internal border below the tool-bar window. */ + if (s->w == XWINDOW (s->f->tool_bar_window)) + s->y -= s->f->output_data.mac->internal_border_width; + + s->ybase = s->y + row->ascent; +} + + +/* Set background width of glyph string S. START is the index of the + first glyph following S. LAST_X is the right-most x-position + 1 + in the drawing area. */ + +static INLINE void +x_set_glyph_string_background_width (s, start, last_x) + struct glyph_string *s; + int start; + int last_x; +{ + /* If the face of this glyph string has to be drawn to the end of + the drawing area, set S->extends_to_end_of_line_p. */ + struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID); + + if (start == s->row->used[s->area] + && s->hl == DRAW_NORMAL_TEXT + && ((s->area == TEXT_AREA && s->row->fill_line_p) + || s->face->background != default_face->background + || s->face->stipple != default_face->stipple)) + s->extends_to_end_of_line_p = 1; + + /* If S extends its face to the end of the line, set its + background_width to the distance to the right edge of the drawing + area. */ + if (s->extends_to_end_of_line_p) + s->background_width = last_x - s->x + 1; + else + s->background_width = s->width; +} + + +/* Add a glyph string for a stretch glyph to the list of strings + between HEAD and TAIL. START is the index of the stretch glyph in + row area AREA of glyph row ROW. END is the index of the last glyph + in that glyph row area. X is the current output position assigned + to the new glyph string constructed. HL overrides that face of the + glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X + is the right-most x-position of the drawing area. */ + +/* SunOS 4 bundled cc, barfed on continuations in the arg lists here + and below -- keep them on one line. */ +#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \ + do \ + { \ + s = (struct glyph_string *) alloca (sizeof *s); \ + x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \ + START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \ + x_append_glyph_string (&HEAD, &TAIL, s); \ + s->x = (X); \ + } \ + while (0) + + +/* Add a glyph string for an image glyph to the list of strings + between HEAD and TAIL. START is the index of the image glyph in + row area AREA of glyph row ROW. END is the index of the last glyph + in that glyph row area. X is the current output position assigned + to the new glyph string constructed. HL overrides that face of the + glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X + is the right-most x-position of the drawing area. */ + +#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \ + do \ + { \ + s = (struct glyph_string *) alloca (sizeof *s); \ + x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \ + x_fill_image_glyph_string (s); \ + x_append_glyph_string (&HEAD, &TAIL, s); \ + ++START; \ + s->x = (X); \ + } \ + while (0) + + +/* Add a glyph string for a sequence of character glyphs to the list + of strings between HEAD and TAIL. START is the index of the first + glyph in row area AREA of glyph row ROW that is part of the new + glyph string. END is the index of the last glyph in that glyph row + area. X is the current output position assigned to the new glyph + string constructed. HL overrides that face of the glyph; e.g. it + is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the + right-most x-position of the drawing area. */ + +#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \ + do \ + { \ + int c, face_id; \ + XChar2b *char2b; \ + \ + c = (ROW)->glyphs[AREA][START].u.ch; \ + face_id = (ROW)->glyphs[AREA][START].face_id; \ + \ + s = (struct glyph_string *) alloca (sizeof *s); \ + char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \ + x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \ + x_append_glyph_string (&HEAD, &TAIL, s); \ + s->x = (X); \ + START = x_fill_glyph_string (s, face_id, START, END, \ + OVERLAPS_P); \ + } \ + while (0) + + +/* Add a glyph string for a composite sequence to the list of strings + between HEAD and TAIL. START is the index of the first glyph in + row area AREA of glyph row ROW that is part of the new glyph + string. END is the index of the last glyph in that glyph row area. + X is the current output position assigned to the new glyph string + constructed. HL overrides that face of the glyph; e.g. it is + DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most + x-position of the drawing area. */ + +#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \ + do { \ + int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \ + int face_id = (ROW)->glyphs[AREA][START].face_id; \ + struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \ + struct composition *cmp = composition_table[cmp_id]; \ + int glyph_len = cmp->glyph_len; \ + XChar2b *char2b; \ + struct face **faces; \ + struct glyph_string *first_s = NULL; \ + int n; \ + \ + base_face = base_face->ascii_face; \ + char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \ + faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \ + /* At first, fill in `char2b' and `faces'. */ \ + for (n = 0; n < glyph_len; n++) \ + { \ + int c = COMPOSITION_GLYPH (cmp, n); \ + int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \ + faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \ + x_get_char_face_and_encoding (XFRAME (w->frame), c, \ + this_face_id, char2b + n, 1); \ + } \ + \ + /* Make glyph_strings for each glyph sequence that is drawable by \ + the same face, and append them to HEAD/TAIL. */ \ + for (n = 0; n < cmp->glyph_len;) \ + { \ + s = (struct glyph_string *) alloca (sizeof *s); \ + x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \ + x_append_glyph_string (&(HEAD), &(TAIL), s); \ + s->cmp = cmp; \ + s->gidx = n; \ + s->x = (X); \ + \ + if (n == 0) \ + first_s = s; \ + \ + n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \ + } \ + \ + ++START; \ + s = first_s; \ + } while (0) + + +/* Build a list of glyph strings between HEAD and TAIL for the glyphs + of AREA of glyph row ROW on window W between indices START and END. + HL overrides the face for drawing glyph strings, e.g. it is + DRAW_CURSOR to draw a cursor. X and LAST_X are start and end + x-positions of the drawing area. + + This is an ugly monster macro construct because we must use alloca + to allocate glyph strings (because x_draw_glyphs can be called + asynchronously). */ + +#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \ + do \ + { \ + HEAD = TAIL = NULL; \ + while (START < END) \ + { \ + struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \ + switch (first_glyph->type) \ + { \ + case CHAR_GLYPH: \ + BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \ + TAIL, HL, X, LAST_X, \ + OVERLAPS_P); \ + break; \ + \ + case COMPOSITE_GLYPH: \ + BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \ + HEAD, TAIL, HL, X, LAST_X,\ + OVERLAPS_P); \ + break; \ + \ + case STRETCH_GLYPH: \ + BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \ + HEAD, TAIL, HL, X, LAST_X); \ + break; \ + \ + case IMAGE_GLYPH: \ + BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \ + TAIL, HL, X, LAST_X); \ + break; \ + \ + default: \ + abort (); \ + } \ + \ + x_set_glyph_string_background_width (s, START, LAST_X); \ + (X) += s->width; \ + } \ + } \ + while (0) + + +/* Draw glyphs between START and END in AREA of ROW on window W, + starting at x-position X. X is relative to AREA in W. HL is a + face-override with the following meaning: + + DRAW_NORMAL_TEXT draw normally + DRAW_CURSOR draw in cursor face + DRAW_MOUSE_FACE draw in mouse face. + DRAW_INVERSE_VIDEO draw in mode line face + DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it + DRAW_IMAGE_RAISED draw an image with a raised relief around it + + If REAL_START is non-null, return in *REAL_START the real starting + position for display. This can be different from START in case + overlapping glyphs must be displayed. If REAL_END is non-null, + return in *REAL_END the real end position for display. This can be + different from END in case overlapping glyphs must be displayed. + + If OVERLAPS_P is non-zero, draw only the foreground of characters + and clip to the physical height of ROW. + + Value is the x-position reached, relative to AREA of W. */ + +static int +x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end, + overlaps_p) + struct window *w; + int x; + struct glyph_row *row; + enum glyph_row_area area; + int start, end; + enum draw_glyphs_face hl; + int *real_start, *real_end; + int overlaps_p; +{ + struct glyph_string *head, *tail; + struct glyph_string *s; + int last_x, area_width; + int x_reached; + int i, j; + + /* Let's rather be paranoid than getting a SEGV. */ + start = max (0, start); + end = min (end, row->used[area]); + if (real_start) + *real_start = start; + if (real_end) + *real_end = end; + + /* Translate X to frame coordinates. Set last_x to the right + end of the drawing area. */ + if (row->full_width_p) + { + /* X is relative to the left edge of W, without scroll bars + or flag areas. */ + struct frame *f = XFRAME (w->frame); + /* int width = FRAME_FLAGS_AREA_WIDTH (f); */ + int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f); + + x += window_left_x; + area_width = XFASTINT (w->width) * CANON_X_UNIT (f); + last_x = window_left_x + area_width; + + if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + { + int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f); + if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) + last_x += width; + else + x -= width; + } + + x += FRAME_INTERNAL_BORDER_WIDTH (f); + last_x -= FRAME_INTERNAL_BORDER_WIDTH (f); + } + else + { + x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x); + area_width = window_box_width (w, area); + last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width); + } + + /* Build a doubly-linked list of glyph_string structures between + head and tail from what we have to draw. Note that the macro + BUILD_GLYPH_STRINGS will modify its start parameter. That's + the reason we use a separate variable `i'. */ + i = start; + BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x, + overlaps_p); + if (tail) + x_reached = tail->x + tail->background_width; + else + x_reached = x; + + /* If there are any glyphs with lbearing < 0 or rbearing > width in + the row, redraw some glyphs in front or following the glyph + strings built above. */ + if (!overlaps_p && row->contains_overlapping_glyphs_p) + { + int dummy_x = 0; + struct glyph_string *h, *t; + + /* Compute overhangs for all glyph strings. */ + for (s = head; s; s = s->next) + x_compute_glyph_string_overhangs (s); + + /* Prepend glyph strings for glyphs in front of the first glyph + string that are overwritten because of the first glyph + string's left overhang. The background of all strings + prepended must be drawn because the first glyph string + draws over it. */ + i = x_left_overwritten (head); + if (i >= 0) + { + j = i; + BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t, + DRAW_NORMAL_TEXT, dummy_x, last_x, + overlaps_p); + start = i; + if (real_start) + *real_start = start; + x_compute_overhangs_and_x (t, head->x, 1); + x_prepend_glyph_string_lists (&head, &tail, h, t); + } + + /* Prepend glyph strings for glyphs in front of the first glyph + string that overwrite that glyph string because of their + right overhang. For these strings, only the foreground must + be drawn, because it draws over the glyph string at `head'. + The background must not be drawn because this would overwrite + right overhangs of preceding glyphs for which no glyph + strings exist. */ + i = x_left_overwriting (head); + if (i >= 0) + { + BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t, + DRAW_NORMAL_TEXT, dummy_x, last_x, + overlaps_p); + for (s = h; s; s = s->next) + s->background_filled_p = 1; + if (real_start) + *real_start = i; + x_compute_overhangs_and_x (t, head->x, 1); + x_prepend_glyph_string_lists (&head, &tail, h, t); + } + + /* Append glyphs strings for glyphs following the last glyph + string tail that are overwritten by tail. The background of + these strings has to be drawn because tail's foreground draws + over it. */ + i = x_right_overwritten (tail); + if (i >= 0) + { + BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t, + DRAW_NORMAL_TEXT, x, last_x, + overlaps_p); + x_compute_overhangs_and_x (h, tail->x + tail->width, 0); + x_append_glyph_string_lists (&head, &tail, h, t); + if (real_end) + *real_end = i; + } + + /* Append glyph strings for glyphs following the last glyph + string tail that overwrite tail. The foreground of such + glyphs has to be drawn because it writes into the background + of tail. The background must not be drawn because it could + paint over the foreground of following glyphs. */ + i = x_right_overwriting (tail); + if (i >= 0) + { + BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t, + DRAW_NORMAL_TEXT, x, last_x, + overlaps_p); + for (s = h; s; s = s->next) + s->background_filled_p = 1; + x_compute_overhangs_and_x (h, tail->x + tail->width, 0); + x_append_glyph_string_lists (&head, &tail, h, t); + if (real_end) + *real_end = i; + } + } + + /* Draw all strings. */ + for (s = head; s; s = s->next) + x_draw_glyph_string (s); + + /* Value is the x-position up to which drawn, relative to AREA of W. + This doesn't include parts drawn because of overhangs. */ + x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached); + if (!row->full_width_p) + { + if (area > LEFT_MARGIN_AREA) + x_reached -= window_box_width (w, LEFT_MARGIN_AREA); + if (area > TEXT_AREA) + x_reached -= window_box_width (w, TEXT_AREA); + } + return x_reached; +} + + +/* Fix the display of area AREA of overlapping row ROW in window W. */ + +void +x_fix_overlapping_area (w, row, area) + struct window *w; + struct glyph_row *row; + enum glyph_row_area area; +{ + int i, x; + + BLOCK_INPUT; + + if (area == LEFT_MARGIN_AREA) + x = 0; + else if (area == TEXT_AREA) + x = row->x + window_box_width (w, LEFT_MARGIN_AREA); + else + x = (window_box_width (w, LEFT_MARGIN_AREA) + + window_box_width (w, TEXT_AREA)); + + for (i = 0; i < row->used[area];) + { + if (row->glyphs[area][i].overlaps_vertically_p) + { + int start = i, start_x = x; + + do + { + x += row->glyphs[area][i].pixel_width; + ++i; + } + while (i < row->used[area] + && row->glyphs[area][i].overlaps_vertically_p); + + x_draw_glyphs (w, start_x, row, area, start, i, + (row->inverse_p + ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT), + NULL, NULL, 1); + } + else + { + x += row->glyphs[area][i].pixel_width; + ++i; + } + } + + UNBLOCK_INPUT; +} + + +/* Output LEN glyphs starting at START at the nominal cursor position. + Advance the nominal cursor over the text. The global variable + updated_window contains the window being updated, updated_row is + the glyph row being updated, and updated_area is the area of that + row being updated. */ + +void +x_write_glyphs (start, len) + struct glyph *start; + int len; +{ + int x, hpos, real_start, real_end; + + xassert (updated_window && updated_row); + BLOCK_INPUT; + + /* Write glyphs. */ + + hpos = start - updated_row->glyphs[updated_area]; + x = x_draw_glyphs (updated_window, output_cursor.x, + updated_row, updated_area, + hpos, hpos + len, + (updated_row->inverse_p + ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT), + &real_start, &real_end, 0); + + /* If we drew over the cursor, note that it is not visible any more. */ + note_overwritten_text_cursor (updated_window, real_start, + real_end - real_start); + + UNBLOCK_INPUT; + + /* Advance the output cursor. */ + output_cursor.hpos += len; + output_cursor.x = x; +} + + +/* Insert LEN glyphs from START at the nominal cursor position. */ + +void +x_insert_glyphs (start, len) + struct glyph *start; + register int len; +{ + struct frame *f; + struct window *w; + int line_height, shift_by_width, shifted_region_width; + struct glyph_row *row; + struct glyph *glyph; + int frame_x, frame_y, hpos, real_start, real_end; + + xassert (updated_window && updated_row); + BLOCK_INPUT; + w = updated_window; + f = XFRAME (WINDOW_FRAME (w)); + + /* Get the height of the line we are in. */ + row = updated_row; + line_height = row->height; + + /* Get the width of the glyphs to insert. */ + shift_by_width = 0; + for (glyph = start; glyph < start + len; ++glyph) + shift_by_width += glyph->pixel_width; + + /* Get the width of the region to shift right. */ + shifted_region_width = (window_box_width (w, updated_area) + - output_cursor.x + - shift_by_width); + + /* Shift right. */ + frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x); + frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y); + + mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + f->output_data.mac->normal_gc, + frame_x, frame_y, + shifted_region_width, line_height, + frame_x + shift_by_width, frame_y); + + /* Write the glyphs. */ + hpos = start - row->glyphs[updated_area]; + x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len, + DRAW_NORMAL_TEXT, &real_start, &real_end, 0); + note_overwritten_text_cursor (w, real_start, real_end - real_start); + + /* Advance the output cursor. */ + output_cursor.hpos += len; + output_cursor.x += shift_by_width; + UNBLOCK_INPUT; +} + + +/* Delete N glyphs at the nominal cursor position. Not implemented + for X frames. */ + +void +x_delete_glyphs (n) + register int n; +{ + abort (); +} + + +/* Erase the current text line from the nominal cursor position + (inclusive) to pixel column TO_X (exclusive). The idea is that + everything from TO_X onward is already erased. + + TO_X is a pixel position relative to updated_area of + updated_window. TO_X == -1 means clear to the end of this area. */ + +void +x_clear_end_of_line (to_x) + int to_x; +{ + struct frame *f; + struct window *w = updated_window; + int max_x, min_y, max_y; + int from_x, from_y, to_y; + + xassert (updated_window && updated_row); + f = XFRAME (w->frame); + + if (updated_row->full_width_p) + { + max_x = XFASTINT (w->width) * CANON_X_UNIT (f); + if (FRAME_HAS_VERTICAL_SCROLL_BARS (f) + && !w->pseudo_window_p) + max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f); + } + else + max_x = window_box_width (w, updated_area); + max_y = window_text_bottom_y (w); + + /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end + of window. For TO_X > 0, truncate to end of drawing area. */ + if (to_x == 0) + return; + else if (to_x < 0) + to_x = max_x; + else + to_x = min (to_x, max_x); + + to_y = min (max_y, output_cursor.y + updated_row->height); + + /* Notice if the cursor will be cleared by this operation. */ + if (!updated_row->full_width_p) + note_overwritten_text_cursor (w, output_cursor.hpos, -1); + + from_x = output_cursor.x; + + /* Translate to frame coordinates. */ + if (updated_row->full_width_p) + { + from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x); + to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x); + } + else + { + from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x); + to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x); + } + + min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); + from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y)); + to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y); + + /* Prevent inadvertently clearing to end of the X window. */ + if (to_x > from_x && to_y > from_y) + { + BLOCK_INPUT; + XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + from_x, from_y, to_x - from_x, to_y - from_y, + 0); + UNBLOCK_INPUT; + } +} + + +/* Clear entire frame. If updating_frame is non-null, clear that + frame. Otherwise clear the selected frame. */ + +void +x_clear_frame () +{ + struct frame *f; + + if (updating_frame) + f = updating_frame; + else + f = SELECTED_FRAME (); + + /* Clearing the frame will erase any cursor, so mark them all as no + longer visible. */ + mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); + output_cursor.hpos = output_cursor.vpos = 0; + output_cursor.x = -1; + + /* We don't set the output cursor here because there will always + follow an explicit cursor_to. */ + BLOCK_INPUT; + XClearWindow (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); + +#if 0 /* Clearing frame on Mac OS clears scroll bars. */ + /* We have to clear the scroll bars, too. If we have changed + colors or something like that, then they should be notified. */ + x_scroll_bar_clear (f); +#endif + + XFlush (FRAME_MAC_DISPLAY (f)); + UNBLOCK_INPUT; +} + + + +/* Invert the middle quarter of the frame for .15 sec. */ + +/* We use the select system call to do the waiting, so we have to make + sure it's available. If it isn't, we just won't do visual bells. */ + +#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) + +/* Subtract the `struct timeval' values X and Y, storing the result in + *RESULT. Return 1 if the difference is negative, otherwise 0. */ + +static int +timeval_subtract (result, x, y) + struct timeval *result, x, y; +{ + /* Perform the carry for the later subtraction by updating y. This + is safer because on some systems the tv_sec member is unsigned. */ + if (x.tv_usec < y.tv_usec) + { + int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; + y.tv_usec -= 1000000 * nsec; + y.tv_sec += nsec; + } + + if (x.tv_usec - y.tv_usec > 1000000) + { + int nsec = (y.tv_usec - x.tv_usec) / 1000000; + y.tv_usec += 1000000 * nsec; + y.tv_sec -= nsec; + } + + /* Compute the time remaining to wait. tv_usec is certainly + positive. */ + result->tv_sec = x.tv_sec - y.tv_sec; + result->tv_usec = x.tv_usec - y.tv_usec; + + /* Return indication of whether the result should be considered + negative. */ + return x.tv_sec < y.tv_sec; +} + +void +XTflash (f) + struct frame *f; +{ + BLOCK_INPUT; + + FlashMenuBar (0); + + { + struct timeval wakeup; + + EMACS_GET_TIME (wakeup); + + /* Compute time to wait until, propagating carry from usecs. */ + wakeup.tv_usec += 150000; + wakeup.tv_sec += (wakeup.tv_usec / 1000000); + wakeup.tv_usec %= 1000000; + + /* Keep waiting until past the time wakeup. */ + while (1) + { + struct timeval timeout; + + EMACS_GET_TIME (timeout); + + /* In effect, timeout = wakeup - timeout. + Break if result would be negative. */ + if (timeval_subtract (&timeout, wakeup, timeout)) + break; + + /* Try to wait that long--but we might wake up sooner. */ + select (0, NULL, NULL, NULL, &timeout); + } + } + + FlashMenuBar (0); + + UNBLOCK_INPUT; +} + +#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */ + + +/* Make audible bell. */ + +void +XTring_bell () +{ + struct frame *f = SELECTED_FRAME (); + +#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) + if (visible_bell) + XTflash (f); + else +#endif + { + BLOCK_INPUT; + SysBeep (1); + XFlush (FRAME_MAC_DISPLAY (f)); + UNBLOCK_INPUT; + } +} + + + +/* Specify how many text lines, from the top of the window, + should be affected by insert-lines and delete-lines operations. + This, and those operations, are used only within an update + that is bounded by calls to x_update_begin and x_update_end. */ + +void +XTset_terminal_window (n) + register int n; +{ + /* This function intentionally left blank. */ +} + + + +/*********************************************************************** + Line Dance + ***********************************************************************/ + +/* Perform an insert-lines or delete-lines operation, inserting N + lines or deleting -N lines at vertical position VPOS. */ + +void +x_ins_del_lines (vpos, n) + int vpos, n; +{ + abort (); +} + + +/* Scroll part of the display as described by RUN. */ + +void +x_scroll_run (w, run) + struct window *w; + struct run *run; +{ + struct frame *f = XFRAME (w->frame); + int x, y, width, height, from_y, to_y, bottom_y; + + /* Get frame-relative bounding box of the text display area of W, + without mode lines. Include in this box the flags areas to the + left and right of W. */ + window_box (w, -1, &x, &y, &width, &height); + width += FRAME_X_FLAGS_AREA_WIDTH (f); + x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f); + + from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); + to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y); + bottom_y = y + height; + + if (to_y < from_y) + { + /* Scrolling up. Make sure we don't copy part of the mode + line at the bottom. */ + if (from_y + run->height > bottom_y) + height = bottom_y - from_y; + else + height = run->height; + } + else + { + /* Scolling down. Make sure we don't copy over the mode line. + at the bottom. */ + if (to_y + run->height > bottom_y) + height = bottom_y - to_y; + else + height = run->height; + } + + BLOCK_INPUT; + + /* Cursor off. Will be switched on again in x_update_window_end. */ + updated_window = w; + x_clear_cursor (w); + + mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + f->output_data.mac->normal_gc, + x, from_y, + width, height, + x, to_y); + + UNBLOCK_INPUT; +} + + + +/*********************************************************************** + Exposure Events + ***********************************************************************/ + +/* Redisplay an exposed area of frame F. X and Y are the upper-left + corner of the exposed rectangle. W and H are width and height of + the exposed area. All are pixel values. W or H zero means redraw + the entire frame. */ + +static void +expose_frame (f, x, y, w, h) + struct frame *f; + int x, y, w, h; +{ + Rect r; + + TRACE ((stderr, "expose_frame ")); + + /* No need to redraw if frame will be redrawn soon. */ + if (FRAME_GARBAGED_P (f)) + { + TRACE ((stderr, " garbaged\n")); + return; + } + + /* MAC_TODO: this is a kludge, but if scroll bars are not activated + or deactivated here, for unknown reasons, activated scroll bars + are shown in deactivated frames in some instances. */ + if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame) + activate_scroll_bars (f); + else + deactivate_scroll_bars (f); + + /* If basic faces haven't been realized yet, there is no point in + trying to redraw anything. This can happen when we get an expose + event while Emacs is starting, e.g. by moving another window. */ + if (FRAME_FACE_CACHE (f) == NULL + || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL) + { + TRACE ((stderr, " no faces\n")); + return; + } + + if (w == 0 || h == 0) + { + r.left = r.top = 0; + r.right = CANON_X_UNIT (f) * f->width; + r.bottom = CANON_Y_UNIT (f) * f->height; + } + else + { + r.left = x; + r.top = y; + r.right = x + w; + r.bottom = y + h; + } + + TRACE ((stderr, "(%d, %d, %d, %d)\n", r.left, r.top, r.right, r.bottom)); + expose_window_tree (XWINDOW (f->root_window), &r); + + if (WINDOWP (f->tool_bar_window)) + { + struct window *w = XWINDOW (f->tool_bar_window); + Rect window_rect; + Rect intersection_rect; + int window_x, window_y, window_width, window_height; + + + window_box (w, -1, &window_x, &window_y, &window_width, &window_height); + window_rect.left = window_x; + window_rect.top = window_y; + window_rect.right = window_x + window_width; + window_rect.bottom = window_y + window_height; + + if (x_intersect_rectangles (&r, &window_rect, &intersection_rect)) + expose_window (w, &intersection_rect); + } + +#ifndef USE_X_TOOLKIT + if (WINDOWP (f->menu_bar_window)) + { + struct window *w = XWINDOW (f->menu_bar_window); + Rect window_rect; + Rect intersection_rect; + int window_x, window_y, window_width, window_height; + + + window_box (w, -1, &window_x, &window_y, &window_width, &window_height); + window_rect.left = window_x; + window_rect.top = window_y; + window_rect.right = window_x + window_width; + window_rect.bottom = window_y + window_height; + + if (x_intersect_rectangles (&r, &window_rect, &intersection_rect)) + expose_window (w, &intersection_rect); + } +#endif /* not USE_X_TOOLKIT */ +} + + +/* Redraw (parts) of all windows in the window tree rooted at W that + intersect R. R contains frame pixel coordinates. */ + +static void +expose_window_tree (w, r) + struct window *w; + Rect *r; +{ + while (w) + { + if (!NILP (w->hchild)) + expose_window_tree (XWINDOW (w->hchild), r); + else if (!NILP (w->vchild)) + expose_window_tree (XWINDOW (w->vchild), r); + else + { + Rect window_rect; + Rect intersection_rect; + struct frame *f = XFRAME (w->frame); + int window_x, window_y, window_width, window_height; + + /* Frame-relative pixel rectangle of W. */ + window_box (w, -1, &window_x, &window_y, &window_width, + &window_height); + window_rect.left + = (window_x + - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) + - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_Y_UNIT (f)); + window_rect.top = window_y; + window_rect.right = window_rect.left + + (window_width + + FRAME_X_FLAGS_AREA_WIDTH (f) + + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)); + window_rect.bottom = window_rect.top + + window_height + CURRENT_MODE_LINE_HEIGHT (w); + + if (x_intersect_rectangles (r, &window_rect, &intersection_rect)) + expose_window (w, &intersection_rect); + } + + w = NILP (w->next) ? 0 : XWINDOW (w->next); + } +} + + +/* Redraw the part of glyph row area AREA of glyph row ROW on window W + which intersects rectangle R. R is in window-relative coordinates. */ + +static void +expose_area (w, row, r, area) + struct window *w; + struct glyph_row *row; + Rect *r; + enum glyph_row_area area; +{ + int x; + struct glyph *first = row->glyphs[area]; + struct glyph *end = row->glyphs[area] + row->used[area]; + struct glyph *last; + int first_x; + + /* Set x to the window-relative start position for drawing glyphs of + AREA. The first glyph of the text area can be partially visible. + The first glyphs of other areas cannot. */ + if (area == LEFT_MARGIN_AREA) + x = 0; + else if (area == TEXT_AREA) + x = row->x + window_box_width (w, LEFT_MARGIN_AREA); + else + x = (window_box_width (w, LEFT_MARGIN_AREA) + + window_box_width (w, TEXT_AREA)); + + if (area == TEXT_AREA && row->fill_line_p) + /* If row extends face to end of line write the whole line. */ + x_draw_glyphs (w, x, row, area, + 0, row->used[area], + row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT, + NULL, NULL, 0); + else + { + /* Find the first glyph that must be redrawn. */ + while (first < end + && x + first->pixel_width < r->left) + { + x += first->pixel_width; + ++first; + } + + /* Find the last one. */ + last = first; + first_x = x; + while (last < end + && x < r->right) + { + x += last->pixel_width; + ++last; + } + + /* Repaint. */ + if (last > first) + x_draw_glyphs (w, first_x, row, area, + first - row->glyphs[area], + last - row->glyphs[area], + row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT, + NULL, NULL, 0); + } +} + + +/* Redraw the parts of the glyph row ROW on window W intersecting + rectangle R. R is in window-relative coordinates. */ + +static void +expose_line (w, row, r) + struct window *w; + struct glyph_row *row; + Rect *r; +{ + xassert (row->enabled_p); + + if (row->mode_line_p || w->pseudo_window_p) + x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA], + row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT, + NULL, NULL, 0); + else + { + if (row->used[LEFT_MARGIN_AREA]) + expose_area (w, row, r, LEFT_MARGIN_AREA); + if (row->used[TEXT_AREA]) + expose_area (w, row, r, TEXT_AREA); + if (row->used[RIGHT_MARGIN_AREA]) + expose_area (w, row, r, RIGHT_MARGIN_AREA); + x_draw_row_bitmaps (w, row); + } +} + + +/* Return non-zero if W's cursor intersects rectangle R. */ + +static int +x_phys_cursor_in_rect_p (w, r) + struct window *w; + Rect *r; +{ + Rect cr, result; + struct glyph *cursor_glyph; + + cursor_glyph = get_phys_cursor_glyph (w); + if (cursor_glyph) + { + cr.left = w->phys_cursor.x; + cr.top = w->phys_cursor.y; + cr.right = cr.left + cursor_glyph->pixel_width; + cr.bottom = cr.top + w->phys_cursor_height; + return x_intersect_rectangles (&cr, r, &result); + } + else + return 0; +} + + +/* Redraw a rectangle of window W. R is a rectangle in window + relative coordinates. Call this function with input blocked. */ + +static void +expose_window (w, r) + struct window *w; + Rect *r; +{ + struct glyph_row *row; + int y; + int yb = window_text_bottom_y (w); + int cursor_cleared_p; + + /* If window is not yet fully initialized, do nothing. This can + happen when toolkit scroll bars are used and a window is split. + Reconfiguring the scroll bar will generate an expose for a newly + created window. */ + if (w->current_matrix == NULL) + return; + + TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n", + r->left, r->top, r->right, r->bottom)); + + /* Convert to window coordinates. */ + r->left = FRAME_TO_WINDOW_PIXEL_X (w, r->left); + r->top = FRAME_TO_WINDOW_PIXEL_Y (w, r->top); + r->right = FRAME_TO_WINDOW_PIXEL_X (w, r->right); + r->bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r->bottom); + + /* Turn off the cursor. */ + if (!w->pseudo_window_p + && x_phys_cursor_in_rect_p (w, r)) + { + x_clear_cursor (w); + cursor_cleared_p = 1; + } + else + cursor_cleared_p = 0; + + /* Find the first row intersecting the rectangle R. */ + row = w->current_matrix->rows; + y = 0; + while (row->enabled_p + && y < yb + && y + row->height < r->top) + { + y += row->height; + ++row; + } + + /* Display the text in the rectangle, one text line at a time. */ + while (row->enabled_p + && y < yb + && y < r->bottom) + { + expose_line (w, row, r); + y += row->height; + ++row; + } + + /* Display the mode line if there is one. */ + if (WINDOW_WANTS_MODELINE_P (w) + && (row = MATRIX_MODE_LINE_ROW (w->current_matrix), + row->enabled_p) + && row->y < r->bottom) + expose_line (w, row, r); + + if (!w->pseudo_window_p) + { + /* Draw border between windows. */ + x_draw_vertical_border (w); + + /* Turn the cursor on again. */ + if (cursor_cleared_p) + x_update_window_cursor (w, 1); + } + + /* Display scroll bar for this window. */ + if (!NILP (w->vertical_scroll_bar)) + { + ControlHandle ch + = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (w->vertical_scroll_bar)); + + Draw1Control (ch); + } +} + + +/* Determine the intersection of two rectangles R1 and R2. Return + the intersection in *RESULT. Value is non-zero if RESULT is not + empty. */ + +static int +x_intersect_rectangles (r1, r2, result) + Rect *r1, *r2, *result; +{ + Rect *left, *right; + Rect *upper, *lower; + int intersection_p = 0; + + /* Rerrange so that R1 is the left-most rectangle. */ + if (r1->left < r2->left) + left = r1, right = r2; + else + left = r2, right = r1; + + /* X0 of the intersection is right.x0, if this is inside R1, + otherwise there is no intersection. */ + if (right->left <= left->right) + { + result->left = right->left; + + /* The right end of the intersection is the minimum of the + the right ends of left and right. */ + result->right = min (left->right, right->right); + + /* Same game for Y. */ + if (r1->top < r2->top) + upper = r1, lower = r2; + else + upper = r2, lower = r1; + + /* The upper end of the intersection is lower.y0, if this is inside + of upper. Otherwise, there is no intersection. */ + if (lower->top <= upper->bottom) + { + result->top = lower->top; + + /* The lower end of the intersection is the minimum of the lower + ends of upper and lower. */ + result->bottom = min (lower->bottom, upper->bottom); + intersection_p = 1; + } + } + + return intersection_p; +} + + + + + +static void +frame_highlight (f) + struct frame *f; +{ + x_update_cursor (f, 1); +} + +static void +frame_unhighlight (f) + struct frame *f; +{ + x_update_cursor (f, 1); +} + +/* The focus has changed. Update the frames as necessary to reflect + the new situation. Note that we can't change the selected frame + here, because the Lisp code we are interrupting might become confused. + Each event gets marked with the frame in which it occurred, so the + Lisp code can tell when the switch took place by examining the events. */ + +static void +x_new_focus_frame (dpyinfo, frame) + struct x_display_info *dpyinfo; + struct frame *frame; +{ + struct frame *old_focus = dpyinfo->x_focus_frame; + + if (frame != dpyinfo->x_focus_frame) + { + /* Set this before calling other routines, so that they see + the correct value of x_focus_frame. */ + dpyinfo->x_focus_frame = frame; + + if (old_focus && old_focus->auto_lower) + x_lower_frame (old_focus); + +#if 0 + selected_frame = frame; + XSETFRAME (XWINDOW (selected_frame->selected_window)->frame, + selected_frame); + Fselect_window (selected_frame->selected_window); + choose_minibuf_frame (); +#endif /* ! 0 */ + + if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise) + pending_autoraise_frame = dpyinfo->x_focus_frame; + else + pending_autoraise_frame = 0; + } + + x_frame_rehighlight (dpyinfo); +} + +/* Handle an event saying the mouse has moved out of an Emacs frame. */ + +static void +x_mouse_leave (dpyinfo) + struct x_display_info *dpyinfo; +{ + x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame); +} + +/* The focus has changed, or we have redirected a frame's focus to + another frame (this happens when a frame uses a surrogate + mini-buffer frame). Shift the highlight as appropriate. + + The FRAME argument doesn't necessarily have anything to do with which + frame is being highlighted or un-highlighted; we only use it to find + the appropriate X display info. */ + +void +XTframe_rehighlight (frame) + struct frame *frame; +{ + x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame)); +} + +static void +x_frame_rehighlight (dpyinfo) + struct x_display_info *dpyinfo; +{ + struct frame *old_highlight = dpyinfo->x_highlight_frame; + + if (dpyinfo->x_focus_frame) + { + dpyinfo->x_highlight_frame + = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))) + ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)) + : dpyinfo->x_focus_frame); + if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame)) + { + FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil; + dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame; + } + } + else + dpyinfo->x_highlight_frame = 0; + + if (dpyinfo->x_highlight_frame != old_highlight) + { + if (old_highlight) + frame_unhighlight (old_highlight); + if (dpyinfo->x_highlight_frame) + frame_highlight (dpyinfo->x_highlight_frame); + } +} + + + +/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */ + +#if 0 +/* Initialize mode_switch_bit and modifier_meaning. */ +static void +x_find_modifier_meanings (dpyinfo) + struct x_display_info *dpyinfo; +{ + int min_code, max_code; + KeySym *syms; + int syms_per_code; + XModifierKeymap *mods; + + dpyinfo->meta_mod_mask = 0; + dpyinfo->shift_lock_mask = 0; + dpyinfo->alt_mod_mask = 0; + dpyinfo->super_mod_mask = 0; + dpyinfo->hyper_mod_mask = 0; + +#ifdef HAVE_X11R4 + XDisplayKeycodes (dpyinfo->display, &min_code, &max_code); +#else + min_code = dpyinfo->display->min_keycode; + max_code = dpyinfo->display->max_keycode; +#endif + + syms = XGetKeyboardMapping (dpyinfo->display, + min_code, max_code - min_code + 1, + &syms_per_code); + mods = XGetModifierMapping (dpyinfo->display); + + /* Scan the modifier table to see which modifier bits the Meta and + Alt keysyms are on. */ + { + int row, col; /* The row and column in the modifier table. */ + + for (row = 3; row < 8; row++) + for (col = 0; col < mods->max_keypermod; col++) + { + KeyCode code + = mods->modifiermap[(row * mods->max_keypermod) + col]; + + /* Zeroes are used for filler. Skip them. */ + if (code == 0) + continue; + + /* Are any of this keycode's keysyms a meta key? */ + { + int code_col; + + for (code_col = 0; code_col < syms_per_code; code_col++) + { + int sym = syms[((code - min_code) * syms_per_code) + code_col]; + + switch (sym) + { + case XK_Meta_L: + case XK_Meta_R: + dpyinfo->meta_mod_mask |= (1 << row); + break; + + case XK_Alt_L: + case XK_Alt_R: + dpyinfo->alt_mod_mask |= (1 << row); + break; + + case XK_Hyper_L: + case XK_Hyper_R: + dpyinfo->hyper_mod_mask |= (1 << row); + break; + + case XK_Super_L: + case XK_Super_R: + dpyinfo->super_mod_mask |= (1 << row); + break; + + case XK_Shift_Lock: + /* Ignore this if it's not on the lock modifier. */ + if ((1 << row) == LockMask) + dpyinfo->shift_lock_mask = LockMask; + break; + } + } + } + } + } + + /* If we couldn't find any meta keys, accept any alt keys as meta keys. */ + if (! dpyinfo->meta_mod_mask) + { + dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask; + dpyinfo->alt_mod_mask = 0; + } + + /* If some keys are both alt and meta, + make them just meta, not alt. */ + if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask) + { + dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask; + } + + XFree ((char *) syms); + XFreeModifiermap (mods); +} + +#endif + +/* Convert between the modifier bits X uses and the modifier bits + Emacs uses. */ + +static unsigned int +x_mac_to_emacs_modifiers (dpyinfo, state) + struct x_display_info *dpyinfo; + unsigned short state; +{ + return (((state & shiftKey) ? shift_modifier : 0) + | ((state & controlKey) ? ctrl_modifier : 0) + | ((state & cmdKey) ? meta_modifier : 0) + | ((state & optionKey) ? alt_modifier : 0)); +} + +#if 0 +static unsigned short +x_emacs_to_x_modifiers (dpyinfo, state) + struct x_display_info *dpyinfo; + unsigned int state; +{ + return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0) + | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0) + | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0) + | ((state & shift_modifier) ? ShiftMask : 0) + | ((state & ctrl_modifier) ? ControlMask : 0) + | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0)); +} +#endif + +/* Convert a keysym to its name. */ + +char * +x_get_keysym_name (keysym) + int keysym; +{ + char *value; + + BLOCK_INPUT; +#if 0 + value = XKeysymToString (keysym); +#else + value = 0; +#endif + UNBLOCK_INPUT; + + return value; +} + + + +/* Mouse clicks and mouse movement. Rah. */ + +/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph + co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the + glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do + not force the value into range. */ + +void +pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip) + FRAME_PTR f; + register int pix_x, pix_y; + register int *x, *y; + Rect *bounds; + int noclip; +{ + /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down + even for negative values. */ + if (pix_x < 0) + pix_x -= FONT_WIDTH ((f)->output_data.mac->font) - 1; + if (pix_y < 0) + pix_y -= (f)->output_data.mac->line_height - 1; + + pix_x = PIXEL_TO_CHAR_COL (f, pix_x); + pix_y = PIXEL_TO_CHAR_ROW (f, pix_y); + + if (bounds) + { + bounds->left = CHAR_TO_PIXEL_COL (f, pix_x); + bounds->top = CHAR_TO_PIXEL_ROW (f, pix_y); + bounds->right = bounds->left + FONT_WIDTH (f->output_data.mac->font); + bounds->bottom = bounds->top + f->output_data.mac->line_height; + } + + if (!noclip) + { + if (pix_x < 0) + pix_x = 0; + else if (pix_x > FRAME_WINDOW_WIDTH (f)) + pix_x = FRAME_WINDOW_WIDTH (f); + + if (pix_y < 0) + pix_y = 0; + else if (pix_y > f->height) + pix_y = f->height; + } + + *x = pix_x; + *y = pix_y; +} + + +/* Given HPOS/VPOS in the current matrix of W, return corresponding + frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we + can't tell the positions because W's display is not up to date, + return 0. */ + +static int +glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y) + struct window *w; + int hpos, vpos; + int *frame_x, *frame_y; +{ + int success_p; + + xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w); + xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h); + + if (display_completed) + { + struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos); + struct glyph *glyph = row->glyphs[TEXT_AREA]; + struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]); + + *frame_y = row->y; + *frame_x = row->x; + while (glyph < end) + { + *frame_x += glyph->pixel_width; + ++glyph; + } + + success_p = 1; + } + else + { + *frame_y = *frame_x = 0; + success_p = 0; + } + + *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y); + *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x); + return success_p; +} + + +/* Prepare a mouse-event in *RESULT for placement in the input queue. + + If the event is a button press, then note that we have grabbed + the mouse. */ + +static Lisp_Object +construct_mouse_click (result, event, f) + struct input_event *result; + EventRecord *event; + struct frame *f; +{ + Point mouseLoc; + + result->kind = mouse_click; + result->code = 0; /* only one mouse button */ + result->timestamp = event->when; + result->modifiers = event->what == mouseDown ? down_modifier : up_modifier; + + mouseLoc = event->where; + SetPort (FRAME_MAC_WINDOW (f)); + GlobalToLocal (&mouseLoc); + XSETINT (result->x, mouseLoc.h); + XSETINT (result->y, mouseLoc.v); + + XSETFRAME (result->frame_or_window, f); + + result->arg = Qnil; + return Qnil; +} + + +/* Function to report a mouse movement to the mainstream Emacs code. + The input handler calls this. + + We have received a mouse movement event, which is given in *event. + If the mouse is over a different glyph than it was last time, tell + the mainstream emacs code by setting mouse_moved. If not, ask for + another motion event, so we can check again the next time it moves. */ + +static Point last_mouse_motion_position; +static Lisp_Object last_mouse_motion_frame; + +static void +note_mouse_movement (frame, pos) + FRAME_PTR frame; + Point *pos; +{ + last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */ + last_mouse_motion_position = *pos; + XSETFRAME (last_mouse_motion_frame, frame); + + if (!PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)) + { + frame->mouse_moved = 1; + last_mouse_scroll_bar = Qnil; + note_mouse_highlight (frame, -1, -1); + } + /* Has the mouse moved off the glyph it was on at the last sighting? */ + else if (pos->h < last_mouse_glyph.left + || pos->h >= last_mouse_glyph.right + || pos->v < last_mouse_glyph.top + || pos->v >= last_mouse_glyph.bottom) + { + frame->mouse_moved = 1; + last_mouse_scroll_bar = Qnil; + note_mouse_highlight (frame, pos->h, pos->v); + } +} + +/* This is used for debugging, to turn off note_mouse_highlight. */ + +int disable_mouse_highlight; + + + +/************************************************************************ + Mouse Face + ************************************************************************/ + +/* Find the glyph under window-relative coordinates X/Y in window W. + Consider only glyphs from buffer text, i.e. no glyphs from overlay + strings. Return in *HPOS and *VPOS the row and column number of + the glyph found. Return in *AREA the glyph area containing X. + Value is a pointer to the glyph found or null if X/Y is not on + text, or we can't tell because W's current matrix is not up to + date. */ + +static struct glyph * +x_y_to_hpos_vpos (w, x, y, hpos, vpos, area) + struct window *w; + int x, y; + int *hpos, *vpos, *area; +{ + struct glyph *glyph, *end; + struct glyph_row *row = NULL; + int x0, i, left_area_width; + + /* Find row containing Y. Give up if some row is not enabled. */ + for (i = 0; i < w->current_matrix->nrows; ++i) + { + row = MATRIX_ROW (w->current_matrix, i); + if (!row->enabled_p) + return NULL; + if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row)) + break; + } + + *vpos = i; + *hpos = 0; + + /* Give up if Y is not in the window. */ + if (i == w->current_matrix->nrows) + return NULL; + + /* Get the glyph area containing X. */ + if (w->pseudo_window_p) + { + *area = TEXT_AREA; + x0 = 0; + } + else + { + left_area_width = window_box_width (w, LEFT_MARGIN_AREA); + if (x < left_area_width) + { + *area = LEFT_MARGIN_AREA; + x0 = 0; + } + else if (x < left_area_width + window_box_width (w, TEXT_AREA)) + { + *area = TEXT_AREA; + x0 = row->x + left_area_width; + } + else + { + *area = RIGHT_MARGIN_AREA; + x0 = left_area_width + window_box_width (w, TEXT_AREA); + } + } + + /* Find glyph containing X. */ + glyph = row->glyphs[*area]; + end = glyph + row->used[*area]; + while (glyph < end) + { + if (x < x0 + glyph->pixel_width) + { + if (w->pseudo_window_p) + break; + else if (BUFFERP (glyph->object)) + break; + } + + x0 += glyph->pixel_width; + ++glyph; + } + + if (glyph == end) + return NULL; + + *hpos = glyph - row->glyphs[*area]; + return glyph; +} + + +/* Convert frame-relative x/y to coordinates relative to window W. + Takes pseudo-windows into account. */ + +static void +frame_to_window_pixel_xy (w, x, y) + struct window *w; + int *x, *y; +{ + if (w->pseudo_window_p) + { + /* A pseudo-window is always full-width, and starts at the + left edge of the frame, plus a frame border. */ + struct frame *f = XFRAME (w->frame); + *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f); + *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y); + } + else + { + *x = FRAME_TO_WINDOW_PIXEL_X (w, *x); + *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y); + } +} + + +/* Take proper action when mouse has moved to the mode or top line of + window W, x-position X. MODE_LINE_P non-zero means mouse is on the + mode line. X is relative to the start of the text display area of + W, so the width of bitmap areas and scroll bars must be subtracted + to get a position relative to the start of the mode line. */ + +static void +note_mode_line_highlight (w, x, mode_line_p) + struct window *w; + int x, mode_line_p; +{ + struct frame *f = XFRAME (w->frame); + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + Cursor cursor = dpyinfo->vertical_scroll_bar_cursor; + struct glyph_row *row; + + if (mode_line_p) + row = MATRIX_MODE_LINE_ROW (w->current_matrix); + else + row = MATRIX_HEADER_LINE_ROW (w->current_matrix); + + if (row->enabled_p) + { + struct glyph *glyph, *end; + Lisp_Object help, map; + int x0; + + /* Find the glyph under X. */ + glyph = row->glyphs[TEXT_AREA]; + end = glyph + row->used[TEXT_AREA]; + x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f) + + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)); + while (glyph < end + && x >= x0 + glyph->pixel_width) + { + x0 += glyph->pixel_width; + ++glyph; + } + + if (glyph < end + && STRINGP (glyph->object) + && XSTRING (glyph->object)->intervals + && glyph->charpos >= 0 + && glyph->charpos < XSTRING (glyph->object)->size) + { + /* If we're on a string with `help-echo' text property, + arrange for the help to be displayed. This is done by + setting the global variable help_echo to the help string. */ + help = Fget_text_property (make_number (glyph->charpos), + Qhelp_echo, glyph->object); + if (!NILP (help)) + { + help_echo = help; + XSETWINDOW (help_echo_window, w); + help_echo_object = glyph->object; + help_echo_pos = glyph->charpos; + } + + /* Change the mouse pointer according to what is under X/Y. */ + map = Fget_text_property (make_number (glyph->charpos), + Qlocal_map, glyph->object); + if (!NILP (Fkeymapp (map))) + cursor = f->output_data.mac->nontext_cursor; + else + { + map = Fget_text_property (make_number (glyph->charpos), + Qkeymap, glyph->object); + if (!NILP (Fkeymapp (map))) + cursor = f->output_data.mac->nontext_cursor; + } + } + } + +#if 0 /* MAC_TODO: mouse cursor */ + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor); +#endif +} + + +/* Take proper action when the mouse has moved to position X, Y on + frame F as regards highlighting characters that have mouse-face + properties. Also de-highlighting chars where the mouse was before. + X and Y can be negative or out of range. */ + +static void +note_mouse_highlight (f, x, y) + struct frame *f; + int x, y; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + int portion; + Lisp_Object window; + struct window *w; + + /* When a menu is active, don't highlight because this looks odd. */ +#ifdef USE_X_TOOLKIT + if (popup_activated ()) + return; +#endif + + if (disable_mouse_highlight + || !f->glyphs_initialized_p) + return; + + dpyinfo->mouse_face_mouse_x = x; + dpyinfo->mouse_face_mouse_y = y; + dpyinfo->mouse_face_mouse_frame = f; + + if (dpyinfo->mouse_face_defer) + return; + + if (gc_in_progress) + { + dpyinfo->mouse_face_deferred_gc = 1; + return; + } + + /* Which window is that in? */ + window = window_from_coordinates (f, x, y, &portion, 1); + + /* If we were displaying active text in another window, clear that. */ + if (! EQ (window, dpyinfo->mouse_face_window)) + clear_mouse_face (dpyinfo); + + /* Not on a window -> return. */ + if (!WINDOWP (window)) + return; + + /* Convert to window-relative pixel coordinates. */ + w = XWINDOW (window); + frame_to_window_pixel_xy (w, &x, &y); + + /* Handle tool-bar window differently since it doesn't display a + buffer. */ + if (EQ (window, f->tool_bar_window)) + { + note_tool_bar_highlight (f, x, y); + return; + } + + if (portion == 1 || portion == 3) + { + /* Mouse is on the mode or top line. */ + note_mode_line_highlight (w, x, portion == 1); + return; + } +#if 0 /* MAC_TODO: mouse cursor */ + else + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + f->output_data.x->text_cursor); +#endif + + /* Are we in a window whose display is up to date? + And verify the buffer's text has not changed. */ + if (/* Within text portion of the window. */ + portion == 0 + && EQ (w->window_end_valid, w->buffer) + && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer)) + && (XFASTINT (w->last_overlay_modified) + == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer)))) + { + int hpos, vpos, pos, i, area; + struct glyph *glyph; + + /* Find the glyph under X/Y. */ + glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area); + + /* Clear mouse face if X/Y not over text. */ + if (glyph == NULL + || area != TEXT_AREA + || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p) + { + clear_mouse_face (dpyinfo); + return; + } + + pos = glyph->charpos; + xassert (w->pseudo_window_p || BUFFERP (glyph->object)); + + /* Check for mouse-face and help-echo. */ + { + Lisp_Object mouse_face, overlay, position; + Lisp_Object *overlay_vec; + int len, noverlays; + struct buffer *obuf; + int obegv, ozv; + + /* If we get an out-of-range value, return now; avoid an error. */ + if (pos > BUF_Z (XBUFFER (w->buffer))) + return; + + /* Make the window's buffer temporarily current for + overlays_at and compute_char_face. */ + obuf = current_buffer; + current_buffer = XBUFFER (w->buffer); + obegv = BEGV; + ozv = ZV; + BEGV = BEG; + ZV = Z; + + /* Is this char mouse-active or does it have help-echo? */ + XSETINT (position, pos); + + /* Put all the overlays we want in a vector in overlay_vec. + Store the length in len. If there are more than 10, make + enough space for all, and try again. */ + len = 10; + overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL); + if (noverlays > len) + { + len = noverlays; + overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL); + } + + /* Sort overlays into increasing priority order. */ + noverlays = sort_overlays (overlay_vec, noverlays, w); + + /* Check mouse-face highlighting. */ + if (! (EQ (window, dpyinfo->mouse_face_window) + && vpos >= dpyinfo->mouse_face_beg_row + && vpos <= dpyinfo->mouse_face_end_row + && (vpos > dpyinfo->mouse_face_beg_row + || hpos >= dpyinfo->mouse_face_beg_col) + && (vpos < dpyinfo->mouse_face_end_row + || hpos < dpyinfo->mouse_face_end_col + || dpyinfo->mouse_face_past_end))) + { + /* Clear the display of the old active region, if any. */ + clear_mouse_face (dpyinfo); + + /* Find the highest priority overlay that has a mouse-face prop. */ + overlay = Qnil; + for (i = noverlays - 1; i >= 0; --i) + { + mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); + if (!NILP (mouse_face)) + { + overlay = overlay_vec[i]; + break; + } + } + + /* If no overlay applies, get a text property. */ + if (NILP (overlay)) + mouse_face = Fget_text_property (position, Qmouse_face, w->buffer); + + /* Handle the overlay case. */ + if (! NILP (overlay)) + { + /* Find the range of text around this char that + should be active. */ + Lisp_Object before, after; + int ignore; + + before = Foverlay_start (overlay); + after = Foverlay_end (overlay); + /* Record this as the current active region. */ + fast_find_position (w, XFASTINT (before), + &dpyinfo->mouse_face_beg_col, + &dpyinfo->mouse_face_beg_row, + &dpyinfo->mouse_face_beg_x, + &dpyinfo->mouse_face_beg_y); + dpyinfo->mouse_face_past_end + = !fast_find_position (w, XFASTINT (after), + &dpyinfo->mouse_face_end_col, + &dpyinfo->mouse_face_end_row, + &dpyinfo->mouse_face_end_x, + &dpyinfo->mouse_face_end_y); + dpyinfo->mouse_face_window = window; + dpyinfo->mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1); + + /* Display it as active. */ + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + } + /* Handle the text property case. */ + else if (! NILP (mouse_face)) + { + /* Find the range of text around this char that + should be active. */ + Lisp_Object before, after, beginning, end; + int ignore; + + beginning = Fmarker_position (w->start); + XSETINT (end, (BUF_Z (XBUFFER (w->buffer)) + - XFASTINT (w->window_end_pos))); + before + = Fprevious_single_property_change (make_number (pos + 1), + Qmouse_face, + w->buffer, beginning); + after + = Fnext_single_property_change (position, Qmouse_face, + w->buffer, end); + /* Record this as the current active region. */ + fast_find_position (w, XFASTINT (before), + &dpyinfo->mouse_face_beg_col, + &dpyinfo->mouse_face_beg_row, + &dpyinfo->mouse_face_beg_x, + &dpyinfo->mouse_face_beg_y); + dpyinfo->mouse_face_past_end + = !fast_find_position (w, XFASTINT (after), + &dpyinfo->mouse_face_end_col, + &dpyinfo->mouse_face_end_row, + &dpyinfo->mouse_face_end_x, + &dpyinfo->mouse_face_end_y); + dpyinfo->mouse_face_window = window; + dpyinfo->mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1); + + /* Display it as active. */ + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + } + } + + /* Look for a `help-echo' property. */ + { + Lisp_Object help, overlay; + + /* Check overlays first. */ + help = Qnil; + for (i = noverlays - 1; i >= 0 && NILP (help); --i) + { + overlay = overlay_vec[i]; + help = Foverlay_get (overlay, Qhelp_echo); + } + + if (!NILP (help)) + { + help_echo = help; + help_echo_window = window; + help_echo_object = overlay; + help_echo_pos = pos; + } + else + { + /* Try text properties. */ + if ((STRINGP (glyph->object) + && glyph->charpos >= 0 + && glyph->charpos < XSTRING (glyph->object)->size) + || (BUFFERP (glyph->object) + && glyph->charpos >= BEGV + && glyph->charpos < ZV)) + help = Fget_text_property (make_number (glyph->charpos), + Qhelp_echo, glyph->object); + + if (!NILP (help)) + { + help_echo = help; + help_echo_window = window; + help_echo_object = glyph->object; + help_echo_pos = glyph->charpos; + } + } + } + + BEGV = obegv; + ZV = ozv; + current_buffer = obuf; + } + } +} + +static void +redo_mouse_highlight () +{ + if (!NILP (last_mouse_motion_frame) + && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame))) + note_mouse_highlight (XFRAME (last_mouse_motion_frame), + last_mouse_motion_position.h, + last_mouse_motion_position.v); +} + + + +/*********************************************************************** + Tool-bars + ***********************************************************************/ + +static int x_tool_bar_item P_ ((struct frame *, int, int, + struct glyph **, int *, int *, int *)); + +/* Tool-bar item index of the item on which a mouse button was pressed + or -1. */ + +static int last_tool_bar_item; + + +/* Get information about the tool-bar item at position X/Y on frame F. + Return in *GLYPH a pointer to the glyph of the tool-bar item in + the current matrix of the tool-bar window of F, or NULL if not + on a tool-bar item. Return in *PROP_IDX the index of the tool-bar + item in F->current_tool_bar_items. Value is + + -1 if X/Y is not on a tool-bar item + 0 if X/Y is on the same item that was highlighted before. + 1 otherwise. */ + +static int +x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx) + struct frame *f; + int x, y; + struct glyph **glyph; + int *hpos, *vpos, *prop_idx; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + struct window *w = XWINDOW (f->tool_bar_window); + int area; + + /* Find the glyph under X/Y. */ + *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area); + if (*glyph == NULL) + return -1; + + /* Get the start of this tool-bar item's properties in + f->current_tool_bar_items. */ + if (!tool_bar_item_info (f, *glyph, prop_idx)) + return -1; + + /* Is mouse on the highlighted item? */ + if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window) + && *vpos >= dpyinfo->mouse_face_beg_row + && *vpos <= dpyinfo->mouse_face_end_row + && (*vpos > dpyinfo->mouse_face_beg_row + || *hpos >= dpyinfo->mouse_face_beg_col) + && (*vpos < dpyinfo->mouse_face_end_row + || *hpos < dpyinfo->mouse_face_end_col + || dpyinfo->mouse_face_past_end)) + return 0; + + return 1; +} + + +/* Handle mouse button event on the tool-bar of frame F, at + frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress + or ButtonRelase. */ + +static void +x_handle_tool_bar_click (f, button_event) + struct frame *f; + EventRecord *button_event; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + struct window *w = XWINDOW (f->tool_bar_window); + int hpos, vpos, prop_idx; + struct glyph *glyph; + Lisp_Object enabled_p; + int x = button_event->where.h; + int y = button_event->where.v; + + /* If not on the highlighted tool-bar item, return. */ + frame_to_window_pixel_xy (w, &x, &y); + if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0) + return; + + /* If item is disabled, do nothing. */ + enabled_p = (XVECTOR (f->current_tool_bar_items) + ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]); + if (NILP (enabled_p)) + return; + + if (button_event->what == mouseDown) + { + /* Show item in pressed state. */ + show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN); + dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN; + last_tool_bar_item = prop_idx; + } + else + { + Lisp_Object key, frame; + struct input_event event; + + /* Show item in released state. */ + show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED); + dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED; + + key = (XVECTOR (f->current_tool_bar_items) + ->contents[prop_idx + TOOL_BAR_ITEM_KEY]); + + XSETFRAME (frame, f); + event.kind = TOOL_BAR_EVENT; + event.frame_or_window = frame; + event.arg = frame; + kbd_buffer_store_event (&event); + + event.kind = TOOL_BAR_EVENT; + event.frame_or_window = frame; + event.arg = key; + event.modifiers = x_mac_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), + button_event->modifiers); + kbd_buffer_store_event (&event); + last_tool_bar_item = -1; + } +} + + +/* Possibly highlight a tool-bar item on frame F when mouse moves to + tool-bar window-relative coordinates X/Y. Called from + note_mouse_highlight. */ + +static void +note_tool_bar_highlight (f, x, y) + struct frame *f; + int x, y; +{ + Lisp_Object window = f->tool_bar_window; + struct window *w = XWINDOW (window); + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + int hpos, vpos; + struct glyph *glyph; + struct glyph_row *row; + int i; + Lisp_Object enabled_p; + int prop_idx; + enum draw_glyphs_face draw = DRAW_IMAGE_RAISED; + int mouse_down_p, rc; + + /* Function note_mouse_highlight is called with negative x(y + values when mouse moves outside of the frame. */ + if (x <= 0 || y <= 0) + { + clear_mouse_face (dpyinfo); + return; + } + + rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx); + if (rc < 0) + { + /* Not on tool-bar item. */ + clear_mouse_face (dpyinfo); + return; + } + else if (rc == 0) + /* On same tool-bar item as before. */ + goto set_help_echo; + + clear_mouse_face (dpyinfo); + + /* Mouse is down, but on different tool-bar item? */ + mouse_down_p = (dpyinfo->grabbed + && f == last_mouse_frame + && FRAME_LIVE_P (f)); + if (mouse_down_p + && last_tool_bar_item != prop_idx) + return; + + dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT; + draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; + + /* If tool-bar item is not enabled, don't highlight it. */ + enabled_p = (XVECTOR (f->current_tool_bar_items) + ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]); + if (!NILP (enabled_p)) + { + /* Compute the x-position of the glyph. In front and past the + image is a space. We include this is the highlighted area. */ + row = MATRIX_ROW (w->current_matrix, vpos); + for (i = x = 0; i < hpos; ++i) + x += row->glyphs[TEXT_AREA][i].pixel_width; + + /* Record this as the current active region. */ + dpyinfo->mouse_face_beg_col = hpos; + dpyinfo->mouse_face_beg_row = vpos; + dpyinfo->mouse_face_beg_x = x; + dpyinfo->mouse_face_beg_y = row->y; + dpyinfo->mouse_face_past_end = 0; + + dpyinfo->mouse_face_end_col = hpos + 1; + dpyinfo->mouse_face_end_row = vpos; + dpyinfo->mouse_face_end_x = x + glyph->pixel_width; + dpyinfo->mouse_face_end_y = row->y; + dpyinfo->mouse_face_window = window; + dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID; + + /* Display it as active. */ + show_mouse_face (dpyinfo, draw); + dpyinfo->mouse_face_image_state = draw; + } + + set_help_echo: + + /* Set help_echo to a help string.to display for this tool-bar item. + XTread_socket does the rest. */ + help_echo_object = help_echo_window = Qnil; + help_echo_pos = -1; + help_echo = (XVECTOR (f->current_tool_bar_items) + ->contents[prop_idx + TOOL_BAR_ITEM_HELP]); + if (NILP (help_echo)) + help_echo = (XVECTOR (f->current_tool_bar_items) + ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]); +} + + + +/* Find the glyph matrix position of buffer position POS in window W. + *HPOS, *VPOS, *X, and *Y are set to the positions found. W's + current glyphs must be up to date. If POS is above window start + return (0, 0, 0, 0). If POS is after end of W, return end of + last line in W. */ + +static int +fast_find_position (w, pos, hpos, vpos, x, y) + struct window *w; + int pos; + int *hpos, *vpos, *x, *y; +{ + int i; + int lastcol; + int maybe_next_line_p = 0; + int line_start_position; + int yb = window_text_bottom_y (w); + struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0); + struct glyph_row *best_row = row; + int row_vpos = 0, best_row_vpos = 0; + int current_x; + + while (row->y < yb) + { + if (row->used[TEXT_AREA]) + line_start_position = row->glyphs[TEXT_AREA]->charpos; + else + line_start_position = 0; + + if (line_start_position > pos) + break; + /* If the position sought is the end of the buffer, + don't include the blank lines at the bottom of the window. */ + else if (line_start_position == pos + && pos == BUF_ZV (XBUFFER (w->buffer))) + { + maybe_next_line_p = 1; + break; + } + else if (line_start_position > 0) + { + best_row = row; + best_row_vpos = row_vpos; + } + + if (row->y + row->height >= yb) + break; + + ++row; + ++row_vpos; + } + + /* Find the right column within BEST_ROW. */ + lastcol = 0; + current_x = best_row->x; + for (i = 0; i < best_row->used[TEXT_AREA]; i++) + { + struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i; + int charpos; + + charpos = glyph->charpos; + if (charpos == pos) + { + *hpos = i; + *vpos = best_row_vpos; + *x = current_x; + *y = best_row->y; + return 1; + } + else if (charpos > pos) + break; + else if (charpos > 0) + lastcol = i; + + current_x += glyph->pixel_width; + } + + /* If we're looking for the end of the buffer, + and we didn't find it in the line we scanned, + use the start of the following line. */ + if (maybe_next_line_p) + { + ++best_row; + ++best_row_vpos; + lastcol = 0; + current_x = best_row->x; + } + + *vpos = best_row_vpos; + *hpos = lastcol + 1; + *x = current_x; + *y = best_row->y; + return 0; +} + + +/* Display the active region described by mouse_face_* + in its mouse-face if HL > 0, in its normal face if HL = 0. */ + +static void +show_mouse_face (dpyinfo, draw) + struct mac_display_info *dpyinfo; + enum draw_glyphs_face draw; +{ + struct window *w = XWINDOW (dpyinfo->mouse_face_window); + struct frame *f = XFRAME (WINDOW_FRAME (w)); + int i; + int cursor_off_p = 0; + struct cursor_pos saved_cursor; + + saved_cursor = output_cursor; + + /* If window is in the process of being destroyed, don't bother + to do anything. */ + if (w->current_matrix == NULL) + goto set_x_cursor; + + /* Recognize when we are called to operate on rows that don't exist + anymore. This can happen when a window is split. */ + if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows) + goto set_x_cursor; + + set_output_cursor (&w->phys_cursor); + + /* Note that mouse_face_beg_row etc. are window relative. */ + for (i = dpyinfo->mouse_face_beg_row; + i <= dpyinfo->mouse_face_end_row; + i++) + { + int start_hpos, end_hpos, start_x; + struct glyph_row *row = MATRIX_ROW (w->current_matrix, i); + + /* Don't do anything if row doesn't have valid contents. */ + if (!row->enabled_p) + continue; + + /* For all but the first row, the highlight starts at column 0. */ + if (i == dpyinfo->mouse_face_beg_row) + { + start_hpos = dpyinfo->mouse_face_beg_col; + start_x = dpyinfo->mouse_face_beg_x; + } + else + { + start_hpos = 0; + start_x = 0; + } + + if (i == dpyinfo->mouse_face_end_row) + end_hpos = dpyinfo->mouse_face_end_col; + else + end_hpos = row->used[TEXT_AREA]; + + /* If the cursor's in the text we are about to rewrite, turn the + cursor off. */ + if (!w->pseudo_window_p + && i == output_cursor.vpos + && output_cursor.hpos >= start_hpos - 1 + && output_cursor.hpos <= end_hpos) + { + x_update_window_cursor (w, 0); + cursor_off_p = 1; + } + + if (end_hpos > start_hpos) + { + row->mouse_face_p = draw == DRAW_MOUSE_FACE; + x_draw_glyphs (w, start_x, row, TEXT_AREA, + start_hpos, end_hpos, draw, NULL, NULL, 0); + } + } + + /* If we turned the cursor off, turn it back on. */ + if (cursor_off_p) + x_display_cursor (w, 1, + output_cursor.hpos, output_cursor.vpos, + output_cursor.x, output_cursor.y); + + output_cursor = saved_cursor; + + set_x_cursor: +#if 0 /* MAC_TODO: mouse cursor */ + /* Change the mouse cursor. */ + if (draw == DRAW_NORMAL_TEXT) + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + f->output_data.x->text_cursor); + else if (draw == DRAW_MOUSE_FACE) + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + f->output_data.x->cross_cursor); + else + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + f->output_data.x->nontext_cursor); +#endif + ; +} + +/* Clear out the mouse-highlighted active region. + Redraw it un-highlighted first. */ + +void +clear_mouse_face (dpyinfo) + struct mac_display_info *dpyinfo; +{ + if (tip_frame) + return; + + if (! NILP (dpyinfo->mouse_face_window)) + show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); + + dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; + dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; + dpyinfo->mouse_face_window = Qnil; +} + + +/* Clear any mouse-face on window W. This function is part of the + redisplay interface, and is called from try_window_id and similar + functions to ensure the mouse-highlight is off. */ + +void +x_clear_mouse_face (w) + struct window *w; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame)); + Lisp_Object window; + + XSETWINDOW (window, w); + if (EQ (window, dpyinfo->mouse_face_window)) + clear_mouse_face (dpyinfo); +} + + +/* Just discard the mouse face information for frame F, if any. + This is used when the size of F is changed. */ + +static void +cancel_mouse_face (f) + FRAME_PTR f; +{ + Lisp_Object window; + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + window = dpyinfo->mouse_face_window; + if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f) + { + dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; + dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; + dpyinfo->mouse_face_window = Qnil; + } +} + +static struct scroll_bar *x_window_to_scroll_bar (); +static void x_scroll_bar_report_motion (); + +/* Return the current position of the mouse. + *fp should be a frame which indicates which display to ask about. + + If the mouse movement started in a scroll bar, set *fp, *bar_window, + and *part to the frame, window, and scroll bar part that the mouse + is over. Set *x and *y to the portion and whole of the mouse's + position on the scroll bar. + + If the mouse movement started elsewhere, set *fp to the frame the + mouse is on, *bar_window to nil, and *x and *y to the character cell + the mouse is over. + + Set *time to the server time-stamp for the time at which the mouse + was at this position. + + Don't store anything if we don't have a valid set of values to report. + + This clears the mouse_moved flag, so we can wait for the next mouse + movement. */ + +void +XTmouse_position (fp, insist, bar_window, part, x, y, time) + FRAME_PTR *fp; + int insist; + Lisp_Object *bar_window; + enum scroll_bar_part *part; + Lisp_Object *x, *y; + unsigned long *time; +{ + Point mouse_pos; + int ignore1, ignore2; + WindowPtr wp = FrontWindow (); + struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; + Lisp_Object frame, tail; + + BLOCK_INPUT; + + if (! NILP (last_mouse_scroll_bar) && insist == 0) + x_scroll_bar_report_motion (fp, bar_window, part, x, y, time); + else + { + /* Clear the mouse-moved flag for every frame on this display. */ + FOR_EACH_FRAME (tail, frame) + XFRAME (frame)->mouse_moved = 0; + + last_mouse_scroll_bar = Qnil; + + SetPort (wp); + GetMouse (&mouse_pos); + + pixel_to_glyph_coords (f, mouse_pos.h, mouse_pos.v, &ignore1, &ignore2, + &last_mouse_glyph, insist); + + *bar_window = Qnil; + *part = scroll_bar_handle; + *fp = f; + XSETINT (*x, mouse_pos.h); + XSETINT (*y, mouse_pos.v); + *time = last_mouse_movement_time; + } + + UNBLOCK_INPUT; +} + + +/************************************************************************ + Scroll bars, general + ************************************************************************/ + +/* Create a scroll bar and return the scroll bar vector for it. W is + the Emacs window on which to create the scroll bar. TOP, LEFT, + WIDTH and HEIGHT are.the pixel coordinates and dimensions of the + scroll bar. */ + +static struct scroll_bar * +x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height) + struct window *w; + int top, left, width, height, disp_top, disp_height; +{ + struct frame *f = XFRAME (w->frame); + struct scroll_bar *bar + = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil)); + Rect r; + ControlHandle ch; + + BLOCK_INPUT; + + r.left = left; + r.top = disp_top; + r.right = left + width; + r.bottom = disp_top + disp_height; + + ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", 1, 0, 0, 0, scrollBarProc, + 0L); + SET_SCROLL_BAR_CONTROL_HANDLE (bar, ch); + SetControlReference (ch, (long) bar); + + XSETWINDOW (bar->window, w); + XSETINT (bar->top, top); + XSETINT (bar->left, left); + XSETINT (bar->width, width); + XSETINT (bar->height, height); + XSETINT (bar->start, 0); + XSETINT (bar->end, 0); + bar->dragging = Qnil; + + /* Add bar to its frame's list of scroll bars. */ + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (FRAME_SCROLL_BARS (f), bar); + if (!NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + + UNBLOCK_INPUT; + return bar; +} + + +/* Draw BAR's handle in the proper position. + + If the handle is already drawn from START to END, don't bother + redrawing it, unless REBUILD is non-zero; in that case, always + redraw it. (REBUILD is handy for drawing the handle after expose + events.) + + Normally, we want to constrain the start and end of the handle to + fit inside its rectangle, but if the user is dragging the scroll + bar handle, we want to let them drag it down all the way, so that + the bar's top is as far down as it goes; otherwise, there's no way + to move to the very end of the buffer. */ + +static void +x_scroll_bar_set_handle (bar, start, end, rebuild) + struct scroll_bar *bar; + int start, end; + int rebuild; +{ + int dragging = ! NILP (bar->dragging); + ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar); + FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + + /* If the display is already accurate, do nothing. */ + if (! rebuild + && start == XINT (bar->start) + && end == XINT (bar->end)) + return; + + BLOCK_INPUT; + + { + int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width)); + int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height)); + int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); + + /* Make sure the values are reasonable, and try to preserve + the distance between start and end. */ + { + int length = end - start; + + if (start < 0) + start = 0; + else if (start > top_range) + start = top_range; + end = start + length; + + if (end < start) + end = start; + else if (end > top_range && ! dragging) + end = top_range; + } + + /* Store the adjusted setting in the scroll bar. */ + XSETINT (bar->start, start); + XSETINT (bar->end, end); + + /* Clip the end position, just for display. */ + if (end > top_range) + end = top_range; + + /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels + below top positions, to make sure the handle is always at least + that many pixels tall. */ + end += VERTICAL_SCROLL_BAR_MIN_HANDLE; + + SetControlMinimum (ch, 0); + /* Don't inadvertently activate deactivated scroll bars */ + if (GetControlMaximum (ch) != -1) + SetControlMaximum (ch, + VERTICAL_SCROLL_BAR_TOP_RANGE (f, + XINT (bar->height)) + - 1); + SetControlValue (ch, start); +#if 0 /* MAC_TODO: detect Appearance Manager 1.1 before use. */ + SetControlViewSize (ch, end); +#endif + } + + UNBLOCK_INPUT; +} + + +/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to + nil. */ + +static void +x_scroll_bar_remove (bar) + struct scroll_bar *bar; +{ + FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + + BLOCK_INPUT; + + /* Destroy the Mac scroll bar control */ + DisposeControl (SCROLL_BAR_CONTROL_HANDLE (bar)); + + /* Disassociate this scroll bar from its window. */ + XWINDOW (bar->window)->vertical_scroll_bar = Qnil; + + UNBLOCK_INPUT; +} + + +/* Set the handle of the vertical scroll bar for WINDOW to indicate + that we are displaying PORTION characters out of a total of WHOLE + characters, starting at POSITION. If WINDOW has no scroll bar, + create one. */ + +static void +XTset_vertical_scroll_bar (w, portion, whole, position) + struct window *w; + int portion, whole, position; +{ + struct frame *f = XFRAME (w->frame); + struct scroll_bar *bar; + int top, height, left, sb_left, width, sb_width, disp_top, disp_height; + int window_x, window_y, window_width, window_height; + + /* Get window dimensions. */ + window_box (w, -1, &window_x, &window_y, &window_width, &window_height); + top = window_y; + width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f); + height = window_height; + + /* Compute the left edge of the scroll bar area. */ + if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) + left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f); + else + left = XFASTINT (w->left); + left *= CANON_X_UNIT (f); + left += FRAME_INTERNAL_BORDER_WIDTH (f); + + /* Compute the width of the scroll bar which might be less than + the width of the area reserved for the scroll bar. */ + if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0) + sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f); + else + sb_width = width; + + /* Compute the left edge of the scroll bar. */ + if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) + sb_left = left + width - sb_width - (width - sb_width) / 2; + else + sb_left = left + (width - sb_width) / 2; + + /* Adjustments according to Inside Macintosh to make it look nice */ + disp_top = top; + disp_height = height; + if (disp_top == 0) + { + disp_top = -1; + disp_height++; + } + else if (disp_top == PIXEL_HEIGHT (f) - 16) + { + disp_top++; + disp_height--; + } + + if (sb_left + sb_width == PIXEL_WIDTH (f)) + sb_left++; + + /* Does the scroll bar exist yet? */ + if (NILP (w->vertical_scroll_bar)) + { + BLOCK_INPUT; + XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + left, top, width, height, 0); + UNBLOCK_INPUT; + bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top, + disp_height); + XSETVECTOR (w->vertical_scroll_bar, bar); + } + else + { + /* It may just need to be moved and resized. */ + ControlHandle ch; + + bar = XSCROLL_BAR (w->vertical_scroll_bar); + ch = SCROLL_BAR_CONTROL_HANDLE (bar); + + BLOCK_INPUT; + + /* If already correctly positioned, do nothing. */ + if (XINT (bar->left) == sb_left + && XINT (bar->top) == top + && XINT (bar->width) == sb_width + && XINT (bar->height) == height) + Draw1Control (ch); + else + { + if (sb_left + sb_width >= PIXEL_WIDTH (f)) + XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + sb_left - 1, top, 1, height, 0); + + HideControl (ch); + MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top); + SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, + disp_height); + ShowControl (ch); + + /* Remember new settings. */ + XSETINT (bar->left, sb_left); + XSETINT (bar->top, top); + XSETINT (bar->width, sb_width); + XSETINT (bar->height, height); + } + + UNBLOCK_INPUT; + } + + /* Set the scroll bar's current state, unless we're currently being + dragged. */ + if (NILP (bar->dragging)) + { + int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height); + + if (whole == 0) + x_scroll_bar_set_handle (bar, 0, top_range, 0); + else + { + int start = ((double) position * top_range) / whole; + int end = ((double) (position + portion) * top_range) / whole; + x_scroll_bar_set_handle (bar, start, end, 0); + } + } +} + + +/* The following three hooks are used when we're doing a thorough + redisplay of the frame. We don't explicitly know which scroll bars + are going to be deleted, because keeping track of when windows go + away is a real pain - "Can you say set-window-configuration, boys + and girls?" Instead, we just assert at the beginning of redisplay + that *all* scroll bars are to be removed, and then save a scroll bar + from the fiery pit when we actually redisplay its window. */ + +/* Arrange for all scroll bars on FRAME to be removed at the next call + to `*judge_scroll_bars_hook'. A scroll bar may be spared if + `*redeem_scroll_bar_hook' is applied to its window before the judgment. */ + +static void +XTcondemn_scroll_bars (frame) + FRAME_PTR frame; +{ + /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */ + while (! NILP (FRAME_SCROLL_BARS (frame))) + { + Lisp_Object bar; + bar = FRAME_SCROLL_BARS (frame); + FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next; + XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame); + XSCROLL_BAR (bar)->prev = Qnil; + if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) + XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar; + FRAME_CONDEMNED_SCROLL_BARS (frame) = bar; + } +} + +/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle. + Note that WINDOW isn't necessarily condemned at all. */ +static void +XTredeem_scroll_bar (window) + struct window *window; +{ + struct scroll_bar *bar; + + /* We can't redeem this window's scroll bar if it doesn't have one. */ + if (NILP (window->vertical_scroll_bar)) + abort (); + + bar = XSCROLL_BAR (window->vertical_scroll_bar); + + /* Unlink it from the condemned list. */ + { + FRAME_PTR f = XFRAME (WINDOW_FRAME (window)); + + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar)) + /* It's not condemned. Everything's fine. */ + return; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + window->vertical_scroll_bar)) + FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next; + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + abort (); + } + else + XSCROLL_BAR (bar->prev)->next = bar->next; + + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSETVECTOR (FRAME_SCROLL_BARS (f), bar); + if (! NILP (bar->next)) + XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); + } +} + +/* Remove all scroll bars on FRAME that haven't been saved since the + last call to `*condemn_scroll_bars_hook'. */ + +static void +XTjudge_scroll_bars (f) + FRAME_PTR f; +{ + Lisp_Object bar, next; + + bar = FRAME_CONDEMNED_SCROLL_BARS (f); + + /* Clear out the condemned list now so we won't try to process any + more events on the hapless scroll bars. */ + FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil; + + for (; ! NILP (bar); bar = next) + { + struct scroll_bar *b = XSCROLL_BAR (bar); + + x_scroll_bar_remove (b); + + next = b->next; + b->next = b->prev = Qnil; + } + + /* Now there should be no references to the condemned scroll bars, + and they should get garbage-collected. */ +} + + +static void +activate_scroll_bars (frame) + FRAME_PTR frame; +{ + Lisp_Object bar; + ControlHandle ch; + + bar = FRAME_SCROLL_BARS (frame); + while (! NILP (bar)) + { + ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar)); + SetControlMaximum (ch, + VERTICAL_SCROLL_BAR_TOP_RANGE (frame, + XINT (XSCROLL_BAR (bar) + ->height)) - 1); + + bar = XSCROLL_BAR (bar)->next; + } +} + + +static void +deactivate_scroll_bars (frame) + FRAME_PTR frame; +{ + Lisp_Object bar; + ControlHandle ch; + + bar = FRAME_SCROLL_BARS (frame); + while (! NILP (bar)) + { + ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar)); + SetControlMaximum (ch, XINT (-1)); + + bar = XSCROLL_BAR (bar)->next; + } +} + +/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind + is set to something other than no_event, it is enqueued. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ + +static void +x_scroll_bar_handle_click (bar, part_code, er, bufp) + struct scroll_bar *bar; + int part_code; + EventRecord *er; + struct input_event *bufp; +{ + if (! GC_WINDOWP (bar->window)) + abort (); + + bufp->kind = scroll_bar_click; + bufp->frame_or_window = bar->window; + bufp->arg = Qnil; + + bar->dragging = Qnil; + + switch (part_code) + { + case kControlUpButtonPart: + bufp->part = scroll_bar_up_arrow; + break; + case kControlDownButtonPart: + bufp->part = scroll_bar_down_arrow; + break; + case kControlPageUpPart: + bufp->part = scroll_bar_above_handle; + break; + case kControlPageDownPart: + bufp->part = scroll_bar_below_handle; + break; + case kControlIndicatorPart: + if (er->what == mouseDown) + bar->dragging = make_number (0); + XSETVECTOR (last_mouse_scroll_bar, bar); + bufp->part = scroll_bar_handle; + break; + } +} + + +/* Handle some mouse motion while someone is dragging the scroll bar. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ + +static void +x_scroll_bar_note_movement (bar, y_pos, t) + struct scroll_bar *bar; + int y_pos; + Time t; +{ + FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame); + + last_mouse_movement_time = t; + + f->mouse_moved = 1; + XSETVECTOR (last_mouse_scroll_bar, bar); + + /* If we're dragging the bar, display it. */ + if (! GC_NILP (bar->dragging)) + { + /* Where should the handle be now? */ + int new_start = y_pos - 24; + + if (new_start != XINT (bar->start)) + { + int new_end = new_start + (XINT (bar->end) - XINT (bar->start)); + + x_scroll_bar_set_handle (bar, new_start, new_end, 0); + } + } +} + + +/* Return information to the user about the current position of the + mouse on the scroll bar. */ + +static void +x_scroll_bar_report_motion (fp, bar_window, part, x, y, time) + FRAME_PTR *fp; + Lisp_Object *bar_window; + enum scroll_bar_part *part; + Lisp_Object *x, *y; + unsigned long *time; +{ + struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar); + WindowPtr wp = FrontWindow (); + Point mouse_pos; + struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; + int win_y, top_range; + + SetPort (wp); + GetMouse (&mouse_pos); + + win_y = mouse_pos.v - XINT (bar->top); + top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); + + win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER; + + win_y -= 24; + + if (! NILP (bar->dragging)) + win_y -= XINT (bar->dragging); + + if (win_y < 0) + win_y = 0; + if (win_y > top_range) + win_y = top_range; + + *fp = f; + *bar_window = bar->window; + + if (! NILP (bar->dragging)) + *part = scroll_bar_handle; + else if (win_y < XINT (bar->start)) + *part = scroll_bar_above_handle; + else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE) + *part = scroll_bar_handle; + else + *part = scroll_bar_below_handle; + + XSETINT (*x, win_y); + XSETINT (*y, top_range); + + f->mouse_moved = 0; + last_mouse_scroll_bar = Qnil; + + *time = last_mouse_movement_time; +} + +/*********************************************************************** + Text Cursor + ***********************************************************************/ + +/* Note if the text cursor of window W has been overwritten by a + drawing operation that outputs N glyphs starting at HPOS in the + line given by output_cursor.vpos. N < 0 means all the rest of the + line after HPOS has been written. */ + +static void +note_overwritten_text_cursor (w, hpos, n) + struct window *w; + int hpos, n; +{ + if (updated_area == TEXT_AREA + && output_cursor.vpos == w->phys_cursor.vpos + && hpos <= w->phys_cursor.hpos + && (n < 0 + || hpos + n > w->phys_cursor.hpos)) + w->phys_cursor_on_p = 0; +} + + +/* Set clipping for output in glyph row ROW. W is the window in which + we operate. GC is the graphics context to set clipping in. + WHOLE_LINE_P non-zero means include the areas used for truncation + mark display and alike in the clipping rectangle. + + ROW may be a text row or, e.g., a mode line. Text rows must be + clipped to the interior of the window dedicated to text display, + mode lines must be clipped to the whole window. */ + +static void +x_clip_to_row (w, row, gc, whole_line_p) + struct window *w; + struct glyph_row *row; + GC gc; + int whole_line_p; +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + Rect clip_rect; + int window_x, window_y, window_width, window_height; + + window_box (w, -1, &window_x, &window_y, &window_width, &window_height); + + clip_rect.left = WINDOW_TO_FRAME_PIXEL_X (w, 0); + clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + clip_rect.top = max (clip_rect.top, window_y); + clip_rect.right = clip_rect.left + window_width; + clip_rect.bottom = clip_rect.top + row->visible_height; + + /* If clipping to the whole line, including trunc marks, extend + the rectangle to the left and increase its width. */ + if (whole_line_p) + { + clip_rect.left -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f); + clip_rect.right += FRAME_X_FLAGS_AREA_WIDTH (f); + } + + mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), &clip_rect); +} + + +/* Draw a hollow box cursor on window W in glyph row ROW. */ + +static void +x_draw_hollow_cursor (w, row) + struct window *w; + struct glyph_row *row; +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + Display *dpy = FRAME_MAC_DISPLAY (f); + int x, y, wd, h; + XGCValues xgcv; + struct glyph *cursor_glyph; + GC gc; + + /* Compute frame-relative coordinates from window-relative + coordinates. */ + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) + + row->ascent - w->phys_cursor_ascent); + h = row->height - 1; + + /* Get the glyph the cursor is on. If we can't tell because + the current matrix is invalid or such, give up. */ + cursor_glyph = get_phys_cursor_glyph (w); + if (cursor_glyph == NULL) + return; + + /* Compute the width of the rectangle to draw. If on a stretch + glyph, and `x-stretch-block-cursor' is nil, don't draw a + rectangle as wide as the glyph, but use a canonical character + width instead. */ + wd = cursor_glyph->pixel_width - 1; + if (cursor_glyph->type == STRETCH_GLYPH + && !x_stretch_cursor_p) + wd = min (CANON_X_UNIT (f), wd); + + /* The foreground of cursor_gc is typically the same as the normal + background color, which can cause the cursor box to be invisible. */ + xgcv.foreground = f->output_data.mac->cursor_pixel; + if (dpyinfo->scratch_cursor_gc) + XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv); + else + dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f), + GCForeground, &xgcv); + gc = dpyinfo->scratch_cursor_gc; + + /* Set clipping, draw the rectangle, and reset clipping again. */ + x_clip_to_row (w, row, gc, 0); + mac_draw_rectangle (dpy, FRAME_MAC_WINDOW (f), gc, x, y, wd, h); + mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f)); +} + + +/* Draw a bar cursor on window W in glyph row ROW. + + Implementation note: One would like to draw a bar cursor with an + angle equal to the one given by the font property XA_ITALIC_ANGLE. + Unfortunately, I didn't find a font yet that has this property set. + --gerd. */ + +static void +x_draw_bar_cursor (w, row, width) + struct window *w; + struct glyph_row *row; + int width; +{ + /* If cursor hpos is out of bounds, don't draw garbage. This can + happen in mini-buffer windows when switching between echo area + glyphs and mini-buffer. */ + if (w->phys_cursor.hpos < row->used[TEXT_AREA]) + { + struct frame *f = XFRAME (w->frame); + struct glyph *cursor_glyph; + GC gc; + int x; + unsigned long mask; + XGCValues xgcv; + Display *dpy; + Window window; + + cursor_glyph = get_phys_cursor_glyph (w); + if (cursor_glyph == NULL) + return; + + xgcv.background = f->output_data.mac->cursor_pixel; + xgcv.foreground = f->output_data.mac->cursor_pixel; + mask = GCForeground | GCBackground; + dpy = FRAME_MAC_DISPLAY (f); + window = FRAME_MAC_WINDOW (f); + gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc; + + if (gc) + XChangeGC (dpy, gc, mask, &xgcv); + else + { + gc = XCreateGC (dpy, window, mask, &xgcv); + FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc; + } + + if (width < 0) + width = f->output_data.mac->cursor_width; + + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + x_clip_to_row (w, row, gc, 0); + XFillRectangle (dpy, window, gc, + x, + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), + min (cursor_glyph->pixel_width, width), + row->height); + mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f)); + } +} + + +/* Clear the cursor of window W to background color, and mark the + cursor as not shown. This is used when the text where the cursor + is is about to be rewritten. */ + +static void +x_clear_cursor (w) + struct window *w; +{ + if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p) + x_update_window_cursor (w, 0); +} + + +/* Draw the cursor glyph of window W in glyph row ROW. See the + comment of x_draw_glyphs for the meaning of HL. */ + +static void +x_draw_phys_cursor_glyph (w, row, hl) + struct window *w; + struct glyph_row *row; + enum draw_glyphs_face hl; +{ + /* If cursor hpos is out of bounds, don't draw garbage. This can + happen in mini-buffer windows when switching between echo area + glyphs and mini-buffer. */ + if (w->phys_cursor.hpos < row->used[TEXT_AREA]) + { + x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, + w->phys_cursor.hpos, w->phys_cursor.hpos + 1, + hl, 0, 0, 0); + + /* When we erase the cursor, and ROW is overlapped by other + rows, make sure that these overlapping parts of other rows + are redrawn. */ + if (hl == DRAW_NORMAL_TEXT && row->overlapped_p) + { + if (row > w->current_matrix->rows + && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1)) + x_fix_overlapping_area (w, row - 1, TEXT_AREA); + + if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w) + && MATRIX_ROW_OVERLAPS_PRED_P (row + 1)) + x_fix_overlapping_area (w, row + 1, TEXT_AREA); + } + } +} + + +/* Erase the image of a cursor of window W from the screen. */ + +static void +x_erase_phys_cursor (w) + struct window *w; +{ + struct frame *f = XFRAME (w->frame); + struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + int hpos = w->phys_cursor.hpos; + int vpos = w->phys_cursor.vpos; + int mouse_face_here_p = 0; + struct glyph_matrix *active_glyphs = w->current_matrix; + struct glyph_row *cursor_row; + struct glyph *cursor_glyph; + enum draw_glyphs_face hl; + + /* No cursor displayed or row invalidated => nothing to do on the + screen. */ + if (w->phys_cursor_type == NO_CURSOR) + goto mark_cursor_off; + + /* VPOS >= active_glyphs->nrows means that window has been resized. + Don't bother to erase the cursor. */ + if (vpos >= active_glyphs->nrows) + goto mark_cursor_off; + + /* If row containing cursor is marked invalid, there is nothing we + can do. */ + cursor_row = MATRIX_ROW (active_glyphs, vpos); + if (!cursor_row->enabled_p) + goto mark_cursor_off; + + /* This can happen when the new row is shorter than the old one. + In this case, either x_draw_glyphs or clear_end_of_line + should have cleared the cursor. Note that we wouldn't be + able to erase the cursor in this case because we don't have a + cursor glyph at hand. */ + if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA]) + goto mark_cursor_off; + + /* If the cursor is in the mouse face area, redisplay that when + we clear the cursor. */ + if (! NILP (dpyinfo->mouse_face_window) + && w == XWINDOW (dpyinfo->mouse_face_window) + && (vpos > dpyinfo->mouse_face_beg_row + || (vpos == dpyinfo->mouse_face_beg_row + && hpos >= dpyinfo->mouse_face_beg_col)) + && (vpos < dpyinfo->mouse_face_end_row + || (vpos == dpyinfo->mouse_face_end_row + && hpos < dpyinfo->mouse_face_end_col)) + /* Don't redraw the cursor's spot in mouse face if it is at the + end of a line (on a newline). The cursor appears there, but + mouse highlighting does not. */ + && cursor_row->used[TEXT_AREA] > hpos) + mouse_face_here_p = 1; + + /* Maybe clear the display under the cursor. */ + if (w->phys_cursor_type == HOLLOW_BOX_CURSOR) + { + int x; + int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); + + cursor_glyph = get_phys_cursor_glyph (w); + if (cursor_glyph == NULL) + goto mark_cursor_off; + + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), + + XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + x, + WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + cursor_row->y)), + cursor_glyph->pixel_width, + cursor_row->visible_height, + 0); + } + + /* Erase the cursor by redrawing the character underneath it. */ + if (mouse_face_here_p) + hl = DRAW_MOUSE_FACE; + else if (cursor_row->inverse_p) + hl = DRAW_INVERSE_VIDEO; + else + hl = DRAW_NORMAL_TEXT; + x_draw_phys_cursor_glyph (w, cursor_row, hl); + + mark_cursor_off: + w->phys_cursor_on_p = 0; + w->phys_cursor_type = NO_CURSOR; +} + + +/* Display or clear cursor of window W. If ON is zero, clear the + cursor. If it is non-zero, display the cursor. If ON is nonzero, + where to put the cursor is specified by HPOS, VPOS, X and Y. */ + +void +x_display_and_set_cursor (w, on, hpos, vpos, x, y) + struct window *w; + int on, hpos, vpos, x, y; +{ + struct frame *f = XFRAME (w->frame); + int new_cursor_type; + int new_cursor_width; + struct glyph_matrix *current_glyphs; + struct glyph_row *glyph_row; + struct glyph *glyph; + + /* This is pointless on invisible frames, and dangerous on garbaged + windows and frames; in the latter case, the frame or window may + be in the midst of changing its size, and x and y may be off the + window. */ + if (! FRAME_VISIBLE_P (f) + || FRAME_GARBAGED_P (f) + || vpos >= w->current_matrix->nrows + || hpos >= w->current_matrix->matrix_w) + return; + + /* If cursor is off and we want it off, return quickly. */ + if (!on && !w->phys_cursor_on_p) + return; + + current_glyphs = w->current_matrix; + glyph_row = MATRIX_ROW (current_glyphs, vpos); + glyph = glyph_row->glyphs[TEXT_AREA] + hpos; + + /* If cursor row is not enabled, we don't really know where to + display the cursor. */ + if (!glyph_row->enabled_p) + { + w->phys_cursor_on_p = 0; + return; + } + + xassert (interrupt_input_blocked); + + /* Set new_cursor_type to the cursor we want to be displayed. In a + mini-buffer window, we want the cursor only to appear if we are + reading input from this window. For the selected window, we want + the cursor type given by the frame parameter. If explicitly + marked off, draw no cursor. In all other cases, we want a hollow + box cursor. */ + new_cursor_width = -1; + if (cursor_in_echo_area + && FRAME_HAS_MINIBUF_P (f) + && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)) + { + if (w == XWINDOW (echo_area_window)) + new_cursor_type = FRAME_DESIRED_CURSOR (f); + else + new_cursor_type = HOLLOW_BOX_CURSOR; + } + else + { + if (w != XWINDOW (selected_window) + || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame) + { + extern int cursor_in_non_selected_windows; + + if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows) + new_cursor_type = NO_CURSOR; + else + new_cursor_type = HOLLOW_BOX_CURSOR; + } + else if (w->cursor_off_p) + new_cursor_type = NO_CURSOR; + else + { + struct buffer *b = XBUFFER (w->buffer); + + if (EQ (b->cursor_type, Qt)) + new_cursor_type = FRAME_DESIRED_CURSOR (f); + else + new_cursor_type = x_specified_cursor_type (b->cursor_type, + &new_cursor_width); + } + } + + /* If cursor is currently being shown and we don't want it to be or + it is in the wrong place, or the cursor type is not what we want, + erase it. */ + if (w->phys_cursor_on_p + && (!on + || w->phys_cursor.x != x + || w->phys_cursor.y != y + || new_cursor_type != w->phys_cursor_type)) + x_erase_phys_cursor (w); + + /* If the cursor is now invisible and we want it to be visible, + display it. */ + if (on && !w->phys_cursor_on_p) + { + w->phys_cursor_ascent = glyph_row->ascent; + w->phys_cursor_height = glyph_row->height; + + /* Set phys_cursor_.* before x_draw_.* is called because some + of them may need the information. */ + w->phys_cursor.x = x; + w->phys_cursor.y = glyph_row->y; + w->phys_cursor.hpos = hpos; + w->phys_cursor.vpos = vpos; + w->phys_cursor_type = new_cursor_type; + w->phys_cursor_on_p = 1; + + switch (new_cursor_type) + { + case HOLLOW_BOX_CURSOR: + x_draw_hollow_cursor (w, glyph_row); + break; + + case FILLED_BOX_CURSOR: + x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + break; + + case BAR_CURSOR: + x_draw_bar_cursor (w, glyph_row, new_cursor_width); + break; + + case NO_CURSOR: + break; + + default: + abort (); + } + +#ifdef HAVE_X_I18N + if (w == XWINDOW (f->selected_window)) + if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition)) + xic_set_preeditarea (w, x, y); +#endif + } + +#ifndef XFlush + if (updating_frame != f) + XFlush (FRAME_X_DISPLAY (f)); +#endif +} + + +/* Display the cursor on window W, or clear it. X and Y are window + relative pixel coordinates. HPOS and VPOS are glyph matrix + positions. If W is not the selected window, display a hollow + cursor. ON non-zero means display the cursor at X, Y which + correspond to HPOS, VPOS, otherwise it is cleared. */ + +void +x_display_cursor (w, on, hpos, vpos, x, y) + struct window *w; + int on, hpos, vpos, x, y; +{ + BLOCK_INPUT; + x_display_and_set_cursor (w, on, hpos, vpos, x, y); + UNBLOCK_INPUT; +} + + +/* Display the cursor on window W, or clear it, according to ON_P. + Don't change the cursor's position. */ + +void +x_update_cursor (f, on_p) + struct frame *f; +{ + x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p); +} + + +/* Call x_update_window_cursor with parameter ON_P on all leaf windows + in the window tree rooted at W. */ + +static void +x_update_cursor_in_window_tree (w, on_p) + struct window *w; + int on_p; +{ + while (w) + { + if (!NILP (w->hchild)) + x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p); + else if (!NILP (w->vchild)) + x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p); + else + x_update_window_cursor (w, on_p); + + w = NILP (w->next) ? 0 : XWINDOW (w->next); + } +} + + +/* Switch the display of W's cursor on or off, according to the value + of ON. */ + +static void +x_update_window_cursor (w, on) + struct window *w; + int on; +{ + /* Don't update cursor in windows whose frame is in the process + of being deleted. */ + if (w->current_matrix) + { + BLOCK_INPUT; + x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos, + w->phys_cursor.x, w->phys_cursor.y); + UNBLOCK_INPUT; + } +} + + +#if 0 /* MAC_TODO: no icon and X error handling (?) */ +/* Icons. */ + +/* Refresh bitmap kitchen sink icon for frame F + when we get an expose event for it. */ + +void +refreshicon (f) + struct frame *f; +{ + /* Normally, the window manager handles this function. */ +} + +/* Make the x-window of frame F use the gnu icon bitmap. */ + +int +x_bitmap_icon (f, file) + struct frame *f; + Lisp_Object file; +{ + int bitmap_id; + + if (FRAME_X_WINDOW (f) == 0) + return 1; + + /* Free up our existing icon bitmap if any. */ + if (f->output_data.x->icon_bitmap > 0) + x_destroy_bitmap (f, f->output_data.x->icon_bitmap); + f->output_data.x->icon_bitmap = 0; + + if (STRINGP (file)) + bitmap_id = x_create_bitmap_from_file (f, file); + else + { + /* Create the GNU bitmap if necessary. */ + if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0) + FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id + = x_create_bitmap_from_data (f, gnu_bits, + gnu_width, gnu_height); + + /* The first time we create the GNU bitmap, + this increments the ref-count one extra time. + As a result, the GNU bitmap is never freed. + That way, we don't have to worry about allocating it again. */ + x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id); + + bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id; + } + + x_wm_set_icon_pixmap (f, bitmap_id); + f->output_data.x->icon_bitmap = bitmap_id; + + return 0; +} + + +/* Make the x-window of frame F use a rectangle with text. + Use ICON_NAME as the text. */ + +int +x_text_icon (f, icon_name) + struct frame *f; + char *icon_name; +{ + if (FRAME_X_WINDOW (f) == 0) + return 1; + +#ifdef HAVE_X11R4 + { + XTextProperty text; + text.value = (unsigned char *) icon_name; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen (icon_name); +#ifdef USE_X_TOOLKIT + XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget), + &text); +#else /* not USE_X_TOOLKIT */ + XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text); +#endif /* not USE_X_TOOLKIT */ + } +#else /* not HAVE_X11R4 */ + XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name); +#endif /* not HAVE_X11R4 */ + + if (f->output_data.x->icon_bitmap > 0) + x_destroy_bitmap (f, f->output_data.x->icon_bitmap); + f->output_data.x->icon_bitmap = 0; + x_wm_set_icon_pixmap (f, 0); + + return 0; +} + +#define X_ERROR_MESSAGE_SIZE 200 + +/* If non-nil, this should be a string. + It means catch X errors and store the error message in this string. */ + +static Lisp_Object x_error_message_string; + +/* An X error handler which stores the error message in + x_error_message_string. This is called from x_error_handler if + x_catch_errors is in effect. */ + +static void +x_error_catcher (display, error) + Display *display; + XErrorEvent *error; +{ + XGetErrorText (display, error->error_code, + XSTRING (x_error_message_string)->data, + X_ERROR_MESSAGE_SIZE); +} + +/* Begin trapping X errors for display DPY. Actually we trap X errors + for all displays, but DPY should be the display you are actually + operating on. + + After calling this function, X protocol errors no longer cause + Emacs to exit; instead, they are recorded in the string + stored in x_error_message_string. + + Calling x_check_errors signals an Emacs error if an X error has + occurred since the last call to x_catch_errors or x_check_errors. + + Calling x_uncatch_errors resumes the normal error handling. */ + +void x_check_errors (); +static Lisp_Object x_catch_errors_unwind (); + +int +x_catch_errors (dpy) + Display *dpy; +{ + int count = specpdl_ptr - specpdl; + + /* Make sure any errors from previous requests have been dealt with. */ + XSync (dpy, False); + + record_unwind_protect (x_catch_errors_unwind, x_error_message_string); + + x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE); + XSTRING (x_error_message_string)->data[0] = 0; + + return count; +} + +/* Unbind the binding that we made to check for X errors. */ + +static Lisp_Object +x_catch_errors_unwind (old_val) + Lisp_Object old_val; +{ + x_error_message_string = old_val; + return Qnil; +} + +/* If any X protocol errors have arrived since the last call to + x_catch_errors or x_check_errors, signal an Emacs error using + sprintf (a buffer, FORMAT, the x error message text) as the text. */ + +void +x_check_errors (dpy, format) + Display *dpy; + char *format; +{ + /* Make sure to catch any errors incurred so far. */ + XSync (dpy, False); + + if (XSTRING (x_error_message_string)->data[0]) + error (format, XSTRING (x_error_message_string)->data); +} + +/* Nonzero if we had any X protocol errors + since we did x_catch_errors on DPY. */ + +int +x_had_errors_p (dpy) + Display *dpy; +{ + /* Make sure to catch any errors incurred so far. */ + XSync (dpy, False); + + return XSTRING (x_error_message_string)->data[0] != 0; +} + +/* Forget about any errors we have had, since we did x_catch_errors on DPY. */ + +void +x_clear_errors (dpy) + Display *dpy; +{ + XSTRING (x_error_message_string)->data[0] = 0; +} + +/* Stop catching X protocol errors and let them make Emacs die. + DPY should be the display that was passed to x_catch_errors. + COUNT should be the value that was returned by + the corresponding call to x_catch_errors. */ + +void +x_uncatch_errors (dpy, count) + Display *dpy; + int count; +{ + unbind_to (count, Qnil); +} + +#if 0 +static unsigned int x_wire_count; +x_trace_wire () +{ + fprintf (stderr, "Lib call: %d\n", ++x_wire_count); +} +#endif /* ! 0 */ + + +/* Handle SIGPIPE, which can happen when the connection to a server + simply goes away. SIGPIPE is handled by x_connection_signal. + Don't need to do anything, because the write which caused the + SIGPIPE will fail, causing Xlib to invoke the X IO error handler, + which will do the appropriate cleanup for us. */ + +static SIGTYPE +x_connection_signal (signalnum) /* If we don't have an argument, */ + int signalnum; /* some compilers complain in signal calls. */ +{ +#ifdef USG + /* USG systems forget handlers when they are used; + must reestablish each time */ + signal (signalnum, x_connection_signal); +#endif /* USG */ +} + +/* Handling X errors. */ + +/* Handle the loss of connection to display DISPLAY. */ + +static SIGTYPE +x_connection_closed (display, error_message) + Display *display; + char *error_message; +{ + struct x_display_info *dpyinfo = x_display_info_for_display (display); + Lisp_Object frame, tail; + + /* Indicate that this display is dead. */ + +#if 0 /* Closing the display caused a bus error on OpenWindows. */ +#ifdef USE_X_TOOLKIT + XtCloseDisplay (display); +#endif +#endif + + if (dpyinfo) + dpyinfo->display = 0; + + /* First delete frames whose mini-buffers are on frames + that are on the dead display. */ + FOR_EACH_FRAME (tail, frame) + { + Lisp_Object minibuf_frame; + minibuf_frame + = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame)))); + if (FRAME_X_P (XFRAME (frame)) + && FRAME_X_P (XFRAME (minibuf_frame)) + && ! EQ (frame, minibuf_frame) + && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo) + Fdelete_frame (frame, Qt); + } + + /* Now delete all remaining frames on the dead display. + We are now sure none of these is used as the mini-buffer + for another frame that we need to delete. */ + FOR_EACH_FRAME (tail, frame) + if (FRAME_X_P (XFRAME (frame)) + && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo) + { + /* Set this to t so that Fdelete_frame won't get confused + trying to find a replacement. */ + FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt; + Fdelete_frame (frame, Qt); + } + + if (dpyinfo) + x_delete_display (dpyinfo); + + if (x_display_list == 0) + { + fprintf (stderr, "%s\n", error_message); + shut_down_emacs (0, 0, Qnil); + exit (70); + } + + /* Ordinary stack unwind doesn't deal with these. */ +#ifdef SIGIO + sigunblock (sigmask (SIGIO)); +#endif + sigunblock (sigmask (SIGALRM)); + TOTALLY_UNBLOCK_INPUT; + + clear_waiting_for_input (); + error ("%s", error_message); +} + +/* This is the usual handler for X protocol errors. + It kills all frames on the display that we got the error for. + If that was the only one, it prints an error message and kills Emacs. */ + +static void +x_error_quitter (display, error) + Display *display; + XErrorEvent *error; +{ + char buf[256], buf1[356]; + + /* Note that there is no real way portable across R3/R4 to get the + original error handler. */ + + XGetErrorText (display, error->error_code, buf, sizeof (buf)); + sprintf (buf1, "X protocol error: %s on protocol request %d", + buf, error->request_code); + x_connection_closed (display, buf1); +} + +/* This is the first-level handler for X protocol errors. + It calls x_error_quitter or x_error_catcher. */ + +static int +x_error_handler (display, error) + Display *display; + XErrorEvent *error; +{ + if (! NILP (x_error_message_string)) + x_error_catcher (display, error); + else + x_error_quitter (display, error); + return 0; +} + +/* This is the handler for X IO errors, always. + It kills all frames on the display that we lost touch with. + If that was the only one, it prints an error message and kills Emacs. */ + +static int +x_io_error_quitter (display) + Display *display; +{ + char buf[256]; + + sprintf (buf, "Connection lost to X server `%s'", DisplayString (display)); + x_connection_closed (display, buf); + return 0; +} +#endif + +/* Changing the font of the frame. */ + +/* Give frame F the font named FONTNAME as its default font, and + return the full name of that font. FONTNAME may be a wildcard + pattern; in that case, we choose some font that fits the pattern. + The return value shows which font we chose. */ + +Lisp_Object +x_new_font (f, fontname) + struct frame *f; + register char *fontname; +{ + struct font_info *fontp + = FS_LOAD_FONT (f, 0, fontname, -1); + + if (!fontp) + return Qnil; + + f->output_data.mac->font = (XFontStruct *) (fontp->font); + f->output_data.mac->baseline_offset = fontp->baseline_offset; + f->output_data.mac->fontset = -1; + + /* Compute the scroll bar width in character columns. */ + if (f->scroll_bar_pixel_width > 0) + { + int wid = FONT_WIDTH (f->output_data.mac->font); + f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid; + } + else + { + int wid = FONT_WIDTH (f->output_data.mac->font); + f->scroll_bar_cols = (14 + wid - 1) / wid; + } + + /* Now make the frame display the given font. */ + if (FRAME_MAC_WINDOW (f) != 0) + { + XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->normal_gc, + f->output_data.mac->font); + XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->reverse_gc, + f->output_data.mac->font); + XSetFont (FRAME_MAC_DISPLAY (f), f->output_data.mac->cursor_gc, + f->output_data.mac->font); + + frame_update_line_height (f); + x_set_window_size (f, 0, f->width, f->height); + } + else + /* If we are setting a new frame's font for the first time, there + are no faces yet, so this font's height is the line height. */ + f->output_data.mac->line_height = FONT_HEIGHT (f->output_data.mac->font); + + return build_string (fontp->full_name); +} + +/* Give frame F the fontset named FONTSETNAME as its default font, and + return the full name of that fontset. FONTSETNAME may be a + wildcard pattern; in that case, we choose some fontset that fits + the pattern. The return value shows which fontset we chose. */ + +Lisp_Object +x_new_fontset (f, fontsetname) + struct frame *f; + char *fontsetname; +{ + int fontset = fs_query_fontset (build_string (fontsetname), 0); + Lisp_Object result; + + if (fontset < 0) + return Qnil; + + if (f->output_data.mac->fontset == fontset) + /* This fontset is already set in frame F. There's nothing more + to do. */ + return fontset_name (fontset); + + result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data)); + + if (!STRINGP (result)) + /* Can't load ASCII font. */ + return Qnil; + + /* Since x_new_font doesn't update any fontset information, do it + now. */ + f->output_data.mac->fontset = fontset; + +#ifdef HAVE_X_I18N + if (FRAME_XIC (f) + && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea))) + xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data); +#endif + + return build_string (fontsetname); +} + +#if 0 /* MAC_TODO: inline input methods for Mac */ + +/*********************************************************************** + X Input Methods + ***********************************************************************/ + +#ifdef HAVE_X_I18N + +#ifdef HAVE_X11R6 + +/* XIM destroy callback function, which is called whenever the + connection to input method XIM dies. CLIENT_DATA contains a + pointer to the x_display_info structure corresponding to XIM. */ + +static void +xim_destroy_callback (xim, client_data, call_data) + XIM xim; + XPointer client_data; + XPointer call_data; +{ + struct x_display_info *dpyinfo = (struct x_display_info *) client_data; + Lisp_Object frame, tail; + + BLOCK_INPUT; + + /* No need to call XDestroyIC.. */ + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_X_DISPLAY_INFO (f) == dpyinfo) + { + FRAME_XIC (f) = NULL; + if (FRAME_XIC_FONTSET (f)) + { + XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f)); + FRAME_XIC_FONTSET (f) = NULL; + } + } + } + + /* No need to call XCloseIM. */ + dpyinfo->xim = NULL; + XFree (dpyinfo->xim_styles); + UNBLOCK_INPUT; +} + +#endif /* HAVE_X11R6 */ + +/* Open the connection to the XIM server on display DPYINFO. + RESOURCE_NAME is the resource name Emacs uses. */ + +static void +xim_open_dpy (dpyinfo, resource_name) + struct x_display_info *dpyinfo; + char *resource_name; +{ +#ifdef USE_XIM + XIM xim; + + xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS); + dpyinfo->xim = xim; + + if (xim) + { +#ifdef HAVE_X11R6 + XIMCallback destroy; +#endif + + /* Get supported styles and XIM values. */ + XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL); + +#ifdef HAVE_X11R6 + destroy.callback = xim_destroy_callback; + destroy.client_data = (XPointer)dpyinfo; + /* This isn't prptotyped in OSF 5.0. */ + XSetIMValues (xim, XNDestroyCallback, &destroy, NULL); +#endif + } + +#else /* not USE_XIM */ + dpyinfo->xim = NULL; +#endif /* not USE_XIM */ +} + + +#ifdef HAVE_X11R6_XIM + +struct xim_inst_t +{ + struct x_display_info *dpyinfo; + char *resource_name; +}; + +/* XIM instantiate callback function, which is called whenever an XIM + server is available. DISPLAY is teh display of the XIM. + CLIENT_DATA contains a pointer to an xim_inst_t structure created + when the callback was registered. */ + +static void +xim_instantiate_callback (display, client_data, call_data) + Display *display; + XPointer client_data; + XPointer call_data; +{ + struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data; + struct x_display_info *dpyinfo = xim_inst->dpyinfo; + + /* We don't support multiple XIM connections. */ + if (dpyinfo->xim) + return; + + xim_open_dpy (dpyinfo, xim_inst->resource_name); + + /* Create XIC for the existing frames on the same display, as long + as they have no XIC. */ + if (dpyinfo->xim && dpyinfo->reference_count > 0) + { + Lisp_Object tail, frame; + + BLOCK_INPUT; + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + + if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo) + if (FRAME_XIC (f) == NULL) + { + create_frame_xic (f); + if (FRAME_XIC_STYLE (f) & XIMStatusArea) + xic_set_statusarea (f); + if (FRAME_XIC_STYLE (f) & XIMPreeditPosition) + { + struct window *w = XWINDOW (f->selected_window); + xic_set_preeditarea (w, w->cursor.x, w->cursor.y); + } + } + } + + UNBLOCK_INPUT; + } +} + +#endif /* HAVE_X11R6_XIM */ + + +/* Open a connection to the XIM server on display DPYINFO. + RESOURCE_NAME is the resource name for Emacs. On X11R5, open the + connection only at the first time. On X11R6, open the connection + in the XIM instantiate callback function. */ + +static void +xim_initialize (dpyinfo, resource_name) + struct x_display_info *dpyinfo; + char *resource_name; +{ +#ifdef USE_XIM +#ifdef HAVE_X11R6_XIM + struct xim_inst_t *xim_inst; + int len; + + dpyinfo->xim = NULL; + xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t)); + xim_inst->dpyinfo = dpyinfo; + len = strlen (resource_name); + xim_inst->resource_name = (char *) xmalloc (len + 1); + bcopy (resource_name, xim_inst->resource_name, len + 1); + XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb, + resource_name, EMACS_CLASS, + xim_instantiate_callback, + /* Fixme: This is XPointer in + XFree86 but (XPointer *) on + Tru64, at least. */ + (XPointer) xim_inst); +#else /* not HAVE_X11R6_XIM */ + dpyinfo->xim = NULL; + xim_open_dpy (dpyinfo, resource_name); +#endif /* not HAVE_X11R6_XIM */ + +#else /* not USE_XIM */ + dpyinfo->xim = NULL; +#endif /* not USE_XIM */ +} + + +/* Close the connection to the XIM server on display DPYINFO. */ + +static void +xim_close_dpy (dpyinfo) + struct x_display_info *dpyinfo; +{ +#ifdef USE_XIM +#ifdef HAVE_X11R6_XIM + XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb, + NULL, EMACS_CLASS, + xim_instantiate_callback, NULL); +#endif /* not HAVE_X11R6_XIM */ + XCloseIM (dpyinfo->xim); + dpyinfo->xim = NULL; + XFree (dpyinfo->xim_styles); +#endif /* USE_XIM */ +} + +#endif /* not HAVE_X11R6_XIM */ + +#endif + +/* Calculate the absolute position in frame F + from its current recorded position values and gravity. */ + +static void +x_calc_absolute_position (f) + struct frame *f; +{ + Point pt; + int flags = f->output_data.mac->size_hint_flags; + + pt.h = pt.v = 0; + + /* Find the position of the outside upper-left corner of + the inner window, with respect to the outer window. */ + if (f->output_data.mac->parent_desc != FRAME_MAC_DISPLAY_INFO (f)->root_window) + { + GrafPtr savePort; + GetPort (&savePort); + SetPort (FRAME_MAC_WINDOW (f)); + SetPt(&pt, FRAME_MAC_WINDOW (f)->portRect.left, FRAME_MAC_WINDOW (f)->portRect.top); + LocalToGlobal (&pt); + SetPort (savePort); + } + + /* Treat negative positions as relative to the leftmost bottommost + position that fits on the screen. */ + if (flags & XNegative) + f->output_data.mac->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width + - 2 * f->output_data.mac->border_width - pt.h + - PIXEL_WIDTH (f) + + f->output_data.mac->left_pos); + /* NTEMACS_TODO: Subtract menubar height? */ + if (flags & YNegative) + f->output_data.mac->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height + - 2 * f->output_data.mac->border_width - pt.v + - PIXEL_HEIGHT (f) + + f->output_data.mac->top_pos); + /* The left_pos and top_pos + are now relative to the top and left screen edges, + so the flags should correspond. */ + f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative); +} + +/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position, + to really change the position, and 0 when calling from + x_make_frame_visible (in that case, XOFF and YOFF are the current + position values). It is -1 when calling from x_set_frame_parameters, + which means, do adjust for borders but don't change the gravity. */ + +void +x_set_offset (f, xoff, yoff, change_gravity) + struct frame *f; + register int xoff, yoff; + int change_gravity; +{ + if (change_gravity > 0) + { + f->output_data.mac->top_pos = yoff; + f->output_data.mac->left_pos = xoff; + f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative); + if (xoff < 0) + f->output_data.mac->size_hint_flags |= XNegative; + if (yoff < 0) + f->output_data.mac->size_hint_flags |= YNegative; + f->output_data.mac->win_gravity = NorthWestGravity; + } + x_calc_absolute_position (f); + + BLOCK_INPUT; + x_wm_set_size_hint (f, (long) 0, 0); + + MoveWindow (f->output_data.mac->mWP, xoff + 6, yoff + 42, false); + + UNBLOCK_INPUT; +} + +/* Call this to change the size of frame F's x-window. + If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity + for this size change and subsequent size changes. + Otherwise we leave the window gravity unchanged. */ + +void +x_set_window_size (f, change_gravity, cols, rows) + struct frame *f; + int change_gravity; + int cols, rows; +{ + int pixelwidth, pixelheight; + + check_frame_size (f, &rows, &cols); + f->output_data.mac->vertical_scroll_bar_extra + = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f) + ? 0 + : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0 + ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f) + : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font))); + f->output_data.mac->flags_areas_extra + = FRAME_FLAGS_AREA_WIDTH (f); + pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols); + pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows); + + f->output_data.mac->win_gravity = NorthWestGravity; + x_wm_set_size_hint (f, (long) 0, 0); + + SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0); + + /* Now, strictly speaking, we can't be sure that this is accurate, + but the window manager will get around to dealing with the size + change request eventually, and we'll hear how it went when the + ConfigureNotify event gets here. + + We could just not bother storing any of this information here, + and let the ConfigureNotify event set everything up, but that + might be kind of confusing to the Lisp code, since size changes + wouldn't be reported in the frame parameters until some random + point in the future when the ConfigureNotify event arrives. + + We pass 1 for DELAY since we can't run Lisp code inside of + a BLOCK_INPUT. */ + change_frame_size (f, rows, cols, 0, 1, 0); + PIXEL_WIDTH (f) = pixelwidth; + PIXEL_HEIGHT (f) = pixelheight; + + /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to + receive in the ConfigureNotify event; if we get what we asked + for, then the event won't cause the screen to become garbaged, so + we have to make sure to do it here. */ + SET_FRAME_GARBAGED (f); + + XFlush (FRAME_X_DISPLAY (f)); + + /* If cursor was outside the new size, mark it as off. */ + mark_window_cursors_off (XWINDOW (f->root_window)); + + /* Clear out any recollection of where the mouse highlighting was, + since it might be in a place that's outside the new frame size. + Actually checking whether it is outside is a pain in the neck, + so don't try--just let the highlighting be done afresh with new size. */ + cancel_mouse_face (f); +} + +/* Mouse warping. */ + +void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y); + +void +x_set_mouse_position (f, x, y) + struct frame *f; + int x, y; +{ + int pix_x, pix_y; + + pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.mac->font) / 2; + pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.mac->line_height / 2; + + if (pix_x < 0) pix_x = 0; + if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f); + + if (pix_y < 0) pix_y = 0; + if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f); + + x_set_mouse_pixel_position (f, pix_x, pix_y); +} + +/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */ + +void +x_set_mouse_pixel_position (f, pix_x, pix_y) + struct frame *f; + int pix_x, pix_y; +{ +#if 0 /* MAC_TODO: CursorDeviceMoveTo is non-Carbon */ + BLOCK_INPUT; + + XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f), + 0, 0, 0, 0, pix_x, pix_y); + UNBLOCK_INPUT; +#endif +} + +/* focus shifting, raising and lowering. */ + +static void +x_focus_on_frame (f) + struct frame *f; +{ +#if 0 /* This proves to be unpleasant. */ + x_raise_frame (f); +#endif +#if 0 + /* I don't think that the ICCCM allows programs to do things like this + without the interaction of the window manager. Whatever you end up + doing with this code, do it to x_unfocus_frame too. */ + XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + RevertToPointerRoot, CurrentTime); +#endif /* ! 0 */ +} + +static void +x_unfocus_frame (f) + struct frame *f; +{ +#if 0 + /* Look at the remarks in x_focus_on_frame. */ + if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f) + XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot, + RevertToPointerRoot, CurrentTime); +#endif /* ! 0 */ +} + +/* Raise frame F. */ + +void +x_raise_frame (f) + struct frame *f; +{ + if (f->async_visible) + SelectWindow (FRAME_MAC_WINDOW (f)); +} + +/* Lower frame F. */ + +void +x_lower_frame (f) + struct frame *f; +{ + if (f->async_visible) + SendBehind (FRAME_MAC_WINDOW (f), nil); +} + +void +XTframe_raise_lower (f, raise_flag) + FRAME_PTR f; + int raise_flag; +{ + if (raise_flag) + x_raise_frame (f); + else + x_lower_frame (f); +} + +/* Change of visibility. */ + +/* This tries to wait until the frame is really visible. + However, if the window manager asks the user where to position + the frame, this will return before the user finishes doing that. + The frame will not actually be visible at that time, + but it will become visible later when the window manager + finishes with it. */ + +void +x_make_frame_visible (f) + struct frame *f; +{ + Lisp_Object type; + int original_top, original_left; + + BLOCK_INPUT; + + if (! FRAME_VISIBLE_P (f)) + { + /* We test FRAME_GARBAGED_P here to make sure we don't + call x_set_offset a second time + if we get to x_make_frame_visible a second time + before the window gets really visible. */ + if (! FRAME_ICONIFIED_P (f) + && ! f->output_data.mac->asked_for_visible) + x_set_offset (f, f->output_data.mac->left_pos, + f->output_data.mac->top_pos, 0); + + f->output_data.mac->asked_for_visible = 1; + + ShowWindow (FRAME_MAC_WINDOW (f)); + } + + XFlush (FRAME_MAC_DISPLAY (f)); + + /* Synchronize to ensure Emacs knows the frame is visible + before we do anything else. We do this loop with input not blocked + so that incoming events are handled. */ + { + Lisp_Object frame; + int count; + + /* This must come after we set COUNT. */ + UNBLOCK_INPUT; + + XSETFRAME (frame, f); + + /* Wait until the frame is visible. Process X events until a + MapNotify event has been seen, or until we think we won't get a + MapNotify at all.. */ + for (count = input_signal_count + 10; + input_signal_count < count && !FRAME_VISIBLE_P (f);) + { + /* Force processing of queued events. */ + x_sync (f); + + /* Machines that do polling rather than SIGIO have been + observed to go into a busy-wait here. So we'll fake an + alarm signal to let the handler know that there's something + to be read. We used to raise a real alarm, but it seems + that the handler isn't always enabled here. This is + probably a bug. */ + if (input_polling_used ()) + { + /* It could be confusing if a real alarm arrives while + processing the fake one. Turn it off and let the + handler reset it. */ + extern void poll_for_input_1 P_ ((void)); + int old_poll_suppress_count = poll_suppress_count; + poll_suppress_count = 1; + poll_for_input_1 (); + poll_suppress_count = old_poll_suppress_count; + } + + /* See if a MapNotify event has been processed. */ + FRAME_SAMPLE_VISIBILITY (f); + } + } +} + +/* Change from mapped state to withdrawn state. */ + +/* Make the frame visible (mapped and not iconified). */ + +void +x_make_frame_invisible (f) + struct frame *f; +{ + /* Don't keep the highlight on an invisible frame. */ + if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f) + FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0; + + BLOCK_INPUT; + + HideWindow (FRAME_MAC_WINDOW (f)); + + /* We can't distinguish this from iconification + just by the event that we get from the server. + So we can't win using the usual strategy of letting + FRAME_SAMPLE_VISIBILITY set this. So do it by hand, + and synchronize with the server to make sure we agree. */ + f->visible = 0; + FRAME_ICONIFIED_P (f) = 0; + f->async_visible = 0; + f->async_iconified = 0; + + UNBLOCK_INPUT; +} + +/* Change window state from mapped to iconified. */ + +void +x_iconify_frame (f) + struct frame *f; +{ +#if 0 /* MAC_TODO: really no iconify on Mac */ + int result; + Lisp_Object type; + + /* Don't keep the highlight on an invisible frame. */ + if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f) + FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0; + + if (f->async_iconified) + return; + + BLOCK_INPUT; + + FRAME_SAMPLE_VISIBILITY (f); + + type = x_icon_type (f); + if (!NILP (type)) + x_bitmap_icon (f, type); + +#ifdef USE_X_TOOLKIT + + if (! FRAME_VISIBLE_P (f)) + { + if (! EQ (Vx_no_window_manager, Qt)) + x_wm_set_window_state (f, IconicState); + /* This was XtPopup, but that did nothing for an iconified frame. */ + XtMapWidget (f->output_data.x->widget); + /* The server won't give us any event to indicate + that an invisible frame was changed to an icon, + so we have to record it here. */ + f->iconified = 1; + f->visible = 1; + f->async_iconified = 1; + f->async_visible = 0; + UNBLOCK_INPUT; + return; + } + + result = XIconifyWindow (FRAME_X_DISPLAY (f), + XtWindow (f->output_data.x->widget), + DefaultScreen (FRAME_X_DISPLAY (f))); + UNBLOCK_INPUT; + + if (!result) + error ("Can't notify window manager of iconification"); + + f->async_iconified = 1; + f->async_visible = 0; + + + BLOCK_INPUT; + XFlush (FRAME_X_DISPLAY (f)); + UNBLOCK_INPUT; +#else /* not USE_X_TOOLKIT */ + + /* Make sure the X server knows where the window should be positioned, + in case the user deiconifies with the window manager. */ + if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f)) + x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0); + + /* Since we don't know which revision of X we're running, we'll use both + the X11R3 and X11R4 techniques. I don't know if this is a good idea. */ + + /* X11R4: send a ClientMessage to the window manager using the + WM_CHANGE_STATE type. */ + { + XEvent message; + + message.xclient.window = FRAME_X_WINDOW (f); + message.xclient.type = ClientMessage; + message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state; + message.xclient.format = 32; + message.xclient.data.l[0] = IconicState; + + if (! XSendEvent (FRAME_X_DISPLAY (f), + DefaultRootWindow (FRAME_X_DISPLAY (f)), + False, + SubstructureRedirectMask | SubstructureNotifyMask, + &message)) + { + UNBLOCK_INPUT_RESIGNAL; + error ("Can't notify window manager of iconification"); + } + } + + /* X11R3: set the initial_state field of the window manager hints to + IconicState. */ + x_wm_set_window_state (f, IconicState); + + if (!FRAME_VISIBLE_P (f)) + { + /* If the frame was withdrawn, before, we must map it. */ + XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); + } + + f->async_iconified = 1; + f->async_visible = 0; + + XFlush (FRAME_X_DISPLAY (f)); + UNBLOCK_INPUT; +#endif /* not USE_X_TOOLKIT */ +#endif +} + +/* Destroy the X window of frame F. */ + +void +x_destroy_window (f) + struct frame *f; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + BLOCK_INPUT; + + DisposeWindow (FRAME_MAC_WINDOW (f)); + + free_frame_menubar (f); + free_frame_faces (f); + + xfree (f->output_data.mac); + f->output_data.mac = 0; + if (f == dpyinfo->x_focus_frame) + dpyinfo->x_focus_frame = 0; + if (f == dpyinfo->x_focus_event_frame) + dpyinfo->x_focus_event_frame = 0; + if (f == dpyinfo->x_highlight_frame) + dpyinfo->x_highlight_frame = 0; + + dpyinfo->reference_count--; + + if (f == dpyinfo->mouse_face_mouse_frame) + { + dpyinfo->mouse_face_beg_row + = dpyinfo->mouse_face_beg_col = -1; + dpyinfo->mouse_face_end_row + = dpyinfo->mouse_face_end_col = -1; + dpyinfo->mouse_face_window = Qnil; + dpyinfo->mouse_face_deferred_gc = 0; + dpyinfo->mouse_face_mouse_frame = 0; + } + + UNBLOCK_INPUT; +} + +/* Setting window manager hints. */ + +/* Set the normal size hints for the window manager, for frame F. + FLAGS is the flags word to use--or 0 meaning preserve the flags + that the window now has. + If USER_POSITION is nonzero, we set the USPosition + flag (this is useful when FLAGS is 0). */ + +void +x_wm_set_size_hint (f, flags, user_position) + struct frame *f; + long flags; + int user_position; +{ +#if 0 /* MAC_TODO: connect this to the Appearance Manager */ + XSizeHints size_hints; + +#ifdef USE_X_TOOLKIT + Arg al[2]; + int ac = 0; + Dimension widget_width, widget_height; + Window window = XtWindow (f->output_data.x->widget); +#else /* not USE_X_TOOLKIT */ + Window window = FRAME_X_WINDOW (f); +#endif /* not USE_X_TOOLKIT */ + + /* Setting PMaxSize caused various problems. */ + size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */; + + size_hints.x = f->output_data.x->left_pos; + size_hints.y = f->output_data.x->top_pos; + +#ifdef USE_X_TOOLKIT + XtSetArg (al[ac], XtNwidth, &widget_width); ac++; + XtSetArg (al[ac], XtNheight, &widget_height); ac++; + XtGetValues (f->output_data.x->widget, al, ac); + size_hints.height = widget_height; + size_hints.width = widget_width; +#else /* not USE_X_TOOLKIT */ + size_hints.height = PIXEL_HEIGHT (f); + size_hints.width = PIXEL_WIDTH (f); +#endif /* not USE_X_TOOLKIT */ + + size_hints.width_inc = FONT_WIDTH (f->output_data.x->font); + size_hints.height_inc = f->output_data.x->line_height; + size_hints.max_width + = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0); + size_hints.max_height + = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0); + + /* Calculate the base and minimum sizes. + + (When we use the X toolkit, we don't do it here. + Instead we copy the values that the widgets are using, below.) */ +#ifndef USE_X_TOOLKIT + { + int base_width, base_height; + int min_rows = 0, min_cols = 0; + + base_width = CHAR_TO_PIXEL_WIDTH (f, 0); + base_height = CHAR_TO_PIXEL_HEIGHT (f, 0); + + check_frame_size (f, &min_rows, &min_cols); + + /* The window manager uses the base width hints to calculate the + current number of rows and columns in the frame while + resizing; min_width and min_height aren't useful for this + purpose, since they might not give the dimensions for a + zero-row, zero-column frame. + + We use the base_width and base_height members if we have + them; otherwise, we set the min_width and min_height members + to the size for a zero x zero frame. */ + +#ifdef HAVE_X11R4 + size_hints.flags |= PBaseSize; + size_hints.base_width = base_width; + size_hints.base_height = base_height; + size_hints.min_width = base_width + min_cols * size_hints.width_inc; + size_hints.min_height = base_height + min_rows * size_hints.height_inc; +#else + size_hints.min_width = base_width; + size_hints.min_height = base_height; +#endif + } + + /* If we don't need the old flags, we don't need the old hint at all. */ + if (flags) + { + size_hints.flags |= flags; + goto no_read; + } +#endif /* not USE_X_TOOLKIT */ + + { + XSizeHints hints; /* Sometimes I hate X Windows... */ + long supplied_return; + int value; + +#ifdef HAVE_X11R4 + value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints, + &supplied_return); +#else + value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints); +#endif + +#ifdef USE_X_TOOLKIT + size_hints.base_height = hints.base_height; + size_hints.base_width = hints.base_width; + size_hints.min_height = hints.min_height; + size_hints.min_width = hints.min_width; +#endif + + if (flags) + size_hints.flags |= flags; + else + { + if (value == 0) + hints.flags = 0; + if (hints.flags & PSize) + size_hints.flags |= PSize; + if (hints.flags & PPosition) + size_hints.flags |= PPosition; + if (hints.flags & USPosition) + size_hints.flags |= USPosition; + if (hints.flags & USSize) + size_hints.flags |= USSize; + } + } + +#ifndef USE_X_TOOLKIT + no_read: +#endif + +#ifdef PWinGravity + size_hints.win_gravity = f->output_data.x->win_gravity; + size_hints.flags |= PWinGravity; + + if (user_position) + { + size_hints.flags &= ~ PPosition; + size_hints.flags |= USPosition; + } +#endif /* PWinGravity */ + +#ifdef HAVE_X11R4 + XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints); +#else + XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints); +#endif +#endif /* MACTODO */ +} + +#if 0 /* MACTODO: hide application instead of iconify? */ +/* Used for IconicState or NormalState */ + +void +x_wm_set_window_state (f, state) + struct frame *f; + int state; +{ +#ifdef USE_X_TOOLKIT + Arg al[1]; + + XtSetArg (al[0], XtNinitialState, state); + XtSetValues (f->output_data.x->widget, al, 1); +#else /* not USE_X_TOOLKIT */ + Window window = FRAME_X_WINDOW (f); + + f->output_data.x->wm_hints.flags |= StateHint; + f->output_data.x->wm_hints.initial_state = state; + + XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints); +#endif /* not USE_X_TOOLKIT */ +} + +void +x_wm_set_icon_pixmap (f, pixmap_id) + struct frame *f; + int pixmap_id; +{ + Pixmap icon_pixmap; + +#ifndef USE_X_TOOLKIT + Window window = FRAME_X_WINDOW (f); +#endif + + if (pixmap_id > 0) + { + icon_pixmap = x_bitmap_pixmap (f, pixmap_id); + f->output_data.x->wm_hints.icon_pixmap = icon_pixmap; + } + else + { + /* It seems there is no way to turn off use of an icon pixmap. + The following line does it, only if no icon has yet been created, + for some window managers. But with mwm it crashes. + Some people say it should clear the IconPixmapHint bit in this case, + but that doesn't work, and the X consortium said it isn't the + right thing at all. Since there is no way to win, + best to explicitly give up. */ +#if 0 + f->output_data.x->wm_hints.icon_pixmap = None; +#else + return; +#endif + } + +#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */ + + { + Arg al[1]; + XtSetArg (al[0], XtNiconPixmap, icon_pixmap); + XtSetValues (f->output_data.x->widget, al, 1); + } + +#else /* not USE_X_TOOLKIT */ + + f->output_data.x->wm_hints.flags |= IconPixmapHint; + XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints); + +#endif /* not USE_X_TOOLKIT */ +} + +#endif + +void +x_wm_set_icon_position (f, icon_x, icon_y) + struct frame *f; + int icon_x, icon_y; +{ +#if 0 /* MAC_TODO: no icons on Mac */ +#ifdef USE_X_TOOLKIT + Window window = XtWindow (f->output_data.x->widget); +#else + Window window = FRAME_X_WINDOW (f); +#endif + + f->output_data.x->wm_hints.flags |= IconPositionHint; + f->output_data.x->wm_hints.icon_x = icon_x; + f->output_data.x->wm_hints.icon_y = icon_y; + + XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints); +#endif +} + + +/*********************************************************************** + Fonts + ***********************************************************************/ + +/* Return a pointer to struct font_info of font FONT_IDX of frame F. */ + +struct font_info * +x_get_font_info (f, font_idx) + FRAME_PTR f; + int font_idx; +{ + return (FRAME_MAC_FONT_TABLE (f) + font_idx); +} + +/* the global font name table */ +char **font_name_table = NULL; +int font_name_table_size = 0; +int font_name_count = 0; + +/* compare two strings ignoring case */ +static int +stricmp (const char *s, const char *t) +{ + for ( ; tolower (*s) == tolower (*t); s++, t++) + if (*s == '\0') + return 0; + return tolower (*s) - tolower (*t); +} + +/* compare two strings ignoring case and handling wildcard */ +static int +wildstrieq (char *s1, char *s2) +{ + if (strcmp (s1, "*") == 0 || strcmp (s2, "*") == 0) + return true; + + return stricmp (s1, s2) == 0; +} + +/* Assume parameter 1 is fully qualified, no wildcards. */ +static int +mac_font_pattern_match (fontname, pattern) + char * fontname; + char * pattern; +{ + char *regex = (char *) alloca (strlen (pattern) * 2); + char *font_name_copy = (char *) alloca (strlen (fontname) + 1); + char *ptr; + + /* Copy fontname so we can modify it during comparison. */ + strcpy (font_name_copy, fontname); + + ptr = regex; + *ptr++ = '^'; + + /* Turn pattern into a regexp and do a regexp match. */ + for (; *pattern; pattern++) + { + if (*pattern == '?') + *ptr++ = '.'; + else if (*pattern == '*') + { + *ptr++ = '.'; + *ptr++ = '*'; + } + else + *ptr++ = *pattern; + } + *ptr = '$'; + *(ptr + 1) = '\0'; + + return (fast_c_string_match_ignore_case (build_string (regex), + font_name_copy) >= 0); +} + +/* Two font specs are considered to match if their foundry, family, + weight, slant, and charset match. */ +static int +mac_font_match (char *mf, char *xf) +{ + char m_foundry[50], m_family[50], m_weight[20], m_slant[2], m_charset[20]; + char x_foundry[50], x_family[50], x_weight[20], x_slant[2], x_charset[20]; + + if (sscanf (mf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s", + m_foundry, m_family, m_weight, m_slant, m_charset) != 5) + return mac_font_pattern_match (mf, xf); + + if (sscanf (xf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s", + x_foundry, x_family, x_weight, x_slant, x_charset) != 5) + return mac_font_pattern_match (mf, xf); + + return (wildstrieq (m_foundry, x_foundry) + && wildstrieq (m_family, x_family) + && wildstrieq (m_weight, x_weight) + && wildstrieq (m_slant, x_slant) + && wildstrieq (m_charset, x_charset)) + || mac_font_pattern_match (mf, xf); +} + + +static char * +mac_to_x_fontname (char *name, int size, Style style, short scriptcode) +{ + char foundry[32], family[32], cs[32]; + char xf[255], *result, *p; + + if (sscanf (name, "%31[^-]-%31[^-]-%31s", foundry, family, cs) != 3) + { + strcpy(foundry, "Apple"); + strcpy(family, name); + + switch (scriptcode) + { + case smTradChinese: + strcpy(cs, "big5-0"); + break; + case smSimpChinese: + strcpy(cs, "gb2312-0"); + break; + case smJapanese: + strcpy(cs, "jisx0208.1983-sjis"); + break; + case smKorean: + strcpy(cs, "ksc5601-0"); + break; + default: + strcpy(cs, "mac-roman"); + break; + } + } + + sprintf(xf, "-%s-%s-%s-%c-normal--%d-%d-75-75-m-%d-%s", + foundry, family, style & bold ? "bold" : "medium", + style & italic ? 'i' : 'r', size, size * 10, size * 10, cs); + + result = (char *) xmalloc (strlen (xf) + 1); + strcpy (result, xf); + for (p = result; *p; p++) + *p = tolower(*p); + return result; +} + + +/* Convert an X font spec to the corresponding mac font name, which + can then be passed to GetFNum after conversion to a Pascal string. + For ordinary Mac fonts, this should just be their names, like + "monaco", "Taipei", etc. Fonts converted from the GNU intlfonts + collection contain their charset designation in their names, like + "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both types of font + names are handled accordingly. */ +static void +x_font_name_to_mac_font_name (char *xf, char *mf) +{ + char foundry[32], family[32], weight[20], slant[2], cs[32]; + + strcpy (mf, ""); + + if (sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s", + foundry, family, weight, slant, cs) != 5 && + sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s", + foundry, family, weight, slant, cs) != 5) + return; + + if (strcmp (cs, "big5-0") == 0 || strcmp (cs, "gb2312-0") == 0 + || strcmp (cs, "jisx0208.1983-sjis") == 0 + || strcmp (cs, "ksc5601-0") == 0 || strcmp (cs, "mac-roman") == 0) + strcpy(mf, family); + else + sprintf(mf, "%s-%s-%s", foundry, family, cs); +} + + +/* Sets up the table font_name_table to contain the list of all + monospace fonts in the system the first time the table is used so + that the Resource Manager need not be accessed every time this + information is needed. */ + +static void +init_font_name_table () +{ + GrafPtr port; + SInt16 fontnum, old_fontnum; + int num_mac_fonts = CountResources('FOND'); + int i, j; + Handle font_handle, font_handle_2; + short id, scriptcode; + ResType type; + Str32 name; + struct FontAssoc *fat; + struct AsscEntry *assc_entry; + + GetPort (&port); /* save the current font number used */ + old_fontnum = port->txFont; + + for (i = 1; i <= num_mac_fonts; i++) /* loop to get all available fonts */ + { + font_handle = GetIndResource ('FOND', i); + if (!font_handle) + continue; + + GetResInfo (font_handle, &id, &type, name); + GetFNum (name, &fontnum); + p2cstr (name); + if (fontnum == 0) + continue; + + TextFont (fontnum); + scriptcode = FontToScript (fontnum); + do + { + HLock (font_handle); + + if (GetResourceSizeOnDisk (font_handle) >= sizeof (struct FamRec)) + { + fat = (struct FontAssoc *) (*font_handle + + sizeof (struct FamRec)); + assc_entry = (struct AsscEntry *) (*font_handle + + sizeof (struct FamRec) + + sizeof (struct FontAssoc)); + + for (j = 0; j <= fat->numAssoc; j++, assc_entry++) + { + if (font_name_table_size == 0) + { + font_name_table_size = 16; + font_name_table = (char **) + xmalloc (font_name_table_size * sizeof (char *)); + } + else if (font_name_count >= font_name_table_size) + { + font_name_table_size += 16; + font_name_table = (char **) + xrealloc (font_name_table, + font_name_table_size * sizeof (char *)); + } + font_name_table[font_name_count++] + = mac_to_x_fontname (name, + assc_entry->fontSize, + assc_entry->fontStyle, + scriptcode); + } + } + + HUnlock (font_handle); + font_handle_2 = GetNextFOND (font_handle); + ReleaseResource (font_handle); + font_handle = font_handle_2; + } + while (ResError () == noErr && font_handle); + } + + TextFont (old_fontnum); +} + + +/* Return a list of at most MAXNAMES font specs matching the one in + PATTERN. Note that each '*' in the PATTERN matches exactly one + field of the font spec, unlike X in which an '*' in a font spec can + match a number of fields. The result is in the Mac implementation + all fonts must be specified by a font spec with all 13 fields + (although many of these can be "*'s"). */ + +Lisp_Object +x_list_fonts (struct frame *f, + Lisp_Object pattern, + int size, + int maxnames) +{ + char *ptnstr; + Lisp_Object newlist = Qnil; + int n_fonts = 0; + int i; + + if (font_name_table == NULL) /* Initialize when first used. */ + init_font_name_table (); + + ptnstr = XSTRING (pattern)->data; + + /* Scan and matching bitmap fonts. */ + for (i = 0; i < font_name_count; i++) + { + if (mac_font_pattern_match (font_name_table[i], ptnstr)) + { + newlist = Fcons (build_string (font_name_table[i]), newlist); + + n_fonts++; + if (n_fonts >= maxnames) + break; + } + } + + /* MAC_TODO: add code for matching outline fonts here */ + + return newlist; +} + + +#if GLYPH_DEBUG + +/* Check that FONT is valid on frame F. It is if it can be found in + F's font table. */ + +static void +x_check_font (f, font) + struct frame *f; + XFontStruct *font; +{ + int i; + struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + + xassert (font != NULL); + + for (i = 0; i < dpyinfo->n_fonts; i++) + if (dpyinfo->font_table[i].name + && font == dpyinfo->font_table[i].font) + break; + + xassert (i < dpyinfo->n_fonts); +} + +#endif /* GLYPH_DEBUG != 0 */ + + +/* Set *W to the minimum width, *H to the minimum font height of FONT. + Note: There are (broken) X fonts out there with invalid XFontStruct + min_bounds contents. For example, handa@etl.go.jp reports that + "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts + have font->min_bounds.width == 0. */ + +static INLINE void +x_font_min_bounds (font, w, h) + MacFontStruct *font; + int *w, *h; +{ + *h = FONT_HEIGHT (font); + *w = font->min_bounds.width; + + /* Try to handle the case where FONT->min_bounds has invalid + contents. Since the only font known to have invalid min_bounds + is fixed-width, use max_bounds if min_bounds seems to be invalid. */ + if (*w <= 0) + *w = font->max_bounds.width; +} + + +/* Compute the smallest character width and smallest font height over + all fonts available on frame F. Set the members smallest_char_width + and smallest_font_height in F's x_display_info structure to + the values computed. Value is non-zero if smallest_font_height or + smallest_char_width become smaller than they were before. */ + +static int +x_compute_min_glyph_bounds (f) + struct frame *f; +{ + int i; + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + MacFontStruct *font; + int old_width = dpyinfo->smallest_char_width; + int old_height = dpyinfo->smallest_font_height; + + dpyinfo->smallest_font_height = 100000; + dpyinfo->smallest_char_width = 100000; + + for (i = 0; i < dpyinfo->n_fonts; ++i) + if (dpyinfo->font_table[i].name) + { + struct font_info *fontp = dpyinfo->font_table + i; + int w, h; + + font = (MacFontStruct *) fontp->font; + xassert (font != (MacFontStruct *) ~0); + x_font_min_bounds (font, &w, &h); + + dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h); + dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w); + } + + xassert (dpyinfo->smallest_char_width > 0 + && dpyinfo->smallest_font_height > 0); + + return (dpyinfo->n_fonts == 1 + || dpyinfo->smallest_char_width < old_width + || dpyinfo->smallest_font_height < old_height); +} + + +/* Determine whether given string is a fully-specified XLFD: all 14 + fields are present, none is '*'. */ + +static int +is_fully_specified_xlfd (char *p) +{ + int i; + char *q; + + if (*p != '-') + return 0; + + for (i = 0; i < 13; i++) + { + q = strchr (p + 1, '-'); + if (q == NULL) + return 0; + if (q - p == 2 && *(p + 1) == '*') + return 0; + p = q; + } + + if (strchr (p + 1, '-') != NULL) + return 0; + + if (*(p + 1) == '*' && *(p + 2) == '\0') + return 0; + + return 1; +} + + +const int kDefaultFontSize = 9; + + +/* MacLoadQueryFont creates and returns an internal representation for + a font in a MacFontStruct struct (similar in function to + XLoadQueryFont in X). There is really no concept corresponding to + "loading" a font on the Mac. But we check its existence and find + the font number and all other information for it and store them in + the returned MacFontStruct. */ + +static MacFontStruct * +XLoadQueryFont (Display *dpy, char *fontname) +{ + int i, size, is_two_byte_font, char_width; + char *name; + GrafPtr port; + SInt16 old_fontnum, old_fontsize; + Style old_fontface; + Str32 mfontname; + SInt16 fontnum; + Style fontface = normal; + MacFontStruct *font; + FontInfo the_fontinfo; + char s_weight[7], c_slant; + + if (is_fully_specified_xlfd (fontname)) + name = fontname; + else + { + for (i = 0; i < font_name_count; i++) + if (mac_font_pattern_match (font_name_table[i], fontname)) + break; + + if (i >= font_name_count) + return NULL; + + name = font_name_table[i]; + } + + GetPort (&port); /* save the current font number used */ + old_fontnum = port->txFont; + old_fontsize = port->txSize; + old_fontface = port->txFace; + + if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%d-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &size) != 1) + size = kDefaultFontSize; + + if (sscanf (name, "-%*[^-]-%*[^-]-%6[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", s_weight) == 1) + if (strcmp (s_weight, "bold") == 0) + fontface |= bold; + + if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &c_slant) == 1) + if (c_slant == 'i') + fontface |= italic; + + x_font_name_to_mac_font_name (name, mfontname); + c2pstr (mfontname); + GetFNum (mfontname, &fontnum); + if (fontnum == 0) + return NULL; + + font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct)); + + font->fontname = (char *) xmalloc (strlen (name) + 1); + bcopy (name, font->fontname, strlen (name) + 1); + + font->mac_fontnum = fontnum; + font->mac_fontsize = size; + font->mac_fontface = fontface; + font->mac_scriptcode = FontToScript (fontnum); + + is_two_byte_font = font->mac_scriptcode == smJapanese || + font->mac_scriptcode == smTradChinese || + font->mac_scriptcode == smSimpChinese || + font->mac_scriptcode == smKorean; + + TextFont (fontnum); + TextSize (size); + TextFace (fontface); + + GetFontInfo (&the_fontinfo); + + font->ascent = the_fontinfo.ascent; + font->descent = the_fontinfo.descent; + + font->min_byte1 = 0; + if (is_two_byte_font) + font->max_byte1 = 1; + else + font->max_byte1 = 0; + font->min_char_or_byte2 = 0x20; + font->max_char_or_byte2 = 0xff; + + if (is_two_byte_font) + { + /* Use the width of an "ideographic space" of that font because + the_fontinfo.widMax returns the wrong width for some fonts. */ + switch (font->mac_scriptcode) + { + case smJapanese: + char_width = StringWidth("\p\x81\x40"); + break; + case smTradChinese: + char_width = StringWidth("\p\xa1\x40"); + break; + case smSimpChinese: + char_width = StringWidth("\p\xa1\xa1"); + break; + case smKorean: + char_width = StringWidth("\p\xa1\xa1"); + break; + } + } + else + /* Do this instead of use the_fontinfo.widMax, which incorrectly + returns 15 for 12-point Monaco! */ + char_width = CharWidth ('m'); + + font->max_bounds.rbearing = char_width; + font->max_bounds.lbearing = 0; + font->max_bounds.width = char_width; + font->max_bounds.ascent = the_fontinfo.ascent; + font->max_bounds.descent = the_fontinfo.descent; + + font->min_bounds = font->max_bounds; + + if (is_two_byte_font || CharWidth ('m') == CharWidth ('i')) + font->per_char = NULL; + else + { + font->per_char = (XCharStruct *) + xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1)); + { + int c; + + for (c = 0x20; c <= 0xff; c++) + { + font->per_char[c - 0x20] = font->max_bounds; + font->per_char[c - 0x20].width = CharWidth (c); + } + } + } + + TextFont (old_fontnum); /* restore previous font number, size and face */ + TextSize (old_fontsize); + TextFace (old_fontface); + + return font; +} + + +/* Load font named FONTNAME of the size SIZE for frame F, and return a + pointer to the structure font_info while allocating it dynamically. + If SIZE is 0, load any size of font. + If loading is failed, return NULL. */ + +struct font_info * +x_load_font (f, fontname, size) + struct frame *f; + register char *fontname; + int size; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + Lisp_Object font_names; + + /* Get a list of all the fonts that match this name. Once we + have a list of matching fonts, we compare them against the fonts + we already have by comparing names. */ + font_names = x_list_fonts (f, build_string (fontname), size, 1); + + if (!NILP (font_names)) + { + Lisp_Object tail; + int i; + + for (i = 0; i < dpyinfo->n_fonts; i++) + for (tail = font_names; CONSP (tail); tail = XCDR (tail)) + if (dpyinfo->font_table[i].name + && (!strcmp (dpyinfo->font_table[i].name, + XSTRING (XCAR (tail))->data) + || !strcmp (dpyinfo->font_table[i].full_name, + XSTRING (XCAR (tail))->data))) + return (dpyinfo->font_table + i); + } + + /* Load the font and add it to the table. */ + { + char *full_name; + struct MacFontStruct *font; + struct font_info *fontp; + unsigned long value; + int i; + + /* If we have found fonts by x_list_font, load one of them. If + not, we still try to load a font by the name given as FONTNAME + because XListFonts (called in x_list_font) of some X server has + a bug of not finding a font even if the font surely exists and + is loadable by XLoadQueryFont. */ + if (size > 0 && !NILP (font_names)) + fontname = (char *) XSTRING (XCAR (font_names))->data; + + font = (MacFontStruct *) XLoadQueryFont (FRAME_MAC_DISPLAY (f), fontname); + if (!font) + return NULL; + + /* Find a free slot in the font table. */ + for (i = 0; i < dpyinfo->n_fonts; ++i) + if (dpyinfo->font_table[i].name == NULL) + break; + + /* If no free slot found, maybe enlarge the font table. */ + if (i == dpyinfo->n_fonts + && dpyinfo->n_fonts == dpyinfo->font_table_size) + { + int sz; + dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size); + sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table; + dpyinfo->font_table + = (struct font_info *) xrealloc (dpyinfo->font_table, sz); + } + + fontp = dpyinfo->font_table + i; + if (i == dpyinfo->n_fonts) + ++dpyinfo->n_fonts; + + /* Now fill in the slots of *FONTP. */ + BLOCK_INPUT; + fontp->font = font; + fontp->font_idx = i; + fontp->name = (char *) xmalloc (strlen (font->fontname) + 1); + bcopy (font->fontname, fontp->name, strlen (font->fontname) + 1); + + fontp->full_name = fontp->name; + + fontp->size = font->max_bounds.width; + fontp->height = FONT_HEIGHT (font); + { + /* For some font, ascent and descent in max_bounds field is + larger than the above value. */ + int max_height = font->max_bounds.ascent + font->max_bounds.descent; + if (max_height > fontp->height) + fontp->height = max_height; + } + + /* The slot `encoding' specifies how to map a character + code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to + the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or + (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, + 2:0xA020..0xFF7F). For the moment, we don't know which charset + uses this font. So, we set information in fontp->encoding[1] + which is never used by any charset. If mapping can't be + decided, set FONT_ENCODING_NOT_DECIDED. */ + if (font->mac_scriptcode == smJapanese) + fontp->encoding[1] = 4; + else + { + fontp->encoding[1] + = (font->max_byte1 == 0 + /* 1-byte font */ + ? (font->min_char_or_byte2 < 0x80 + ? (font->max_char_or_byte2 < 0x80 + ? 0 /* 0x20..0x7F */ + : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */ + : 1) /* 0xA0..0xFF */ + /* 2-byte font */ + : (font->min_byte1 < 0x80 + ? (font->max_byte1 < 0x80 + ? (font->min_char_or_byte2 < 0x80 + ? (font->max_char_or_byte2 < 0x80 + ? 0 /* 0x2020..0x7F7F */ + : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */ + : 3) /* 0x20A0..0x7FFF */ + : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */ + : (font->min_char_or_byte2 < 0x80 + ? (font->max_char_or_byte2 < 0x80 + ? 2 /* 0xA020..0xFF7F */ + : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */ + : 1))); /* 0xA0A0..0xFFFF */ + } + +#if 0 /* MAC_TODO: fill these out with more reasonably values */ + fontp->baseline_offset + = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value) + ? (long) value : 0); + fontp->relative_compose + = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value) + ? (long) value : 0); + fontp->default_ascent + = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value) + ? (long) value : 0); +#else + fontp->baseline_offset = 0; + fontp->relative_compose = 0; + fontp->default_ascent = 0; +#endif + + /* Set global flag fonts_changed_p to non-zero if the font loaded + has a character with a smaller width than any other character + before, or if the font loaded has a smalle>r height than any + other font loaded before. If this happens, it will make a + glyph matrix reallocation necessary. */ + fonts_changed_p = x_compute_min_glyph_bounds (f); + UNBLOCK_INPUT; + return fontp; + } +} + + +/* Return a pointer to struct font_info of a font named FONTNAME for + frame F. If no such font is loaded, return NULL. */ + +struct font_info * +x_query_font (f, fontname) + struct frame *f; + register char *fontname; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + int i; + + for (i = 0; i < dpyinfo->n_fonts; i++) + if (dpyinfo->font_table[i].name + && (!strcmp (dpyinfo->font_table[i].name, fontname) + || !strcmp (dpyinfo->font_table[i].full_name, fontname))) + return (dpyinfo->font_table + i); + return NULL; +} + + +/* Find a CCL program for a font specified by FONTP, and set the member + `encoder' of the structure. */ + +void +x_find_ccl_program (fontp) + struct font_info *fontp; +{ + Lisp_Object list, elt; + + for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list)) + { + elt = XCAR (list); + if (CONSP (elt) + && STRINGP (XCAR (elt)) + && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name) + >= 0)) + break; + } + if (! NILP (list)) + { + struct ccl_program *ccl + = (struct ccl_program *) xmalloc (sizeof (struct ccl_program)); + + if (setup_ccl_program (ccl, XCDR (elt)) < 0) + xfree (ccl); + else + fontp->font_encoder = ccl; + } +} + + + +/*********************************************************************** + Initialization + ***********************************************************************/ + +#ifdef USE_X_TOOLKIT +static XrmOptionDescRec emacs_options[] = { + {"-geometry", ".geometry", XrmoptionSepArg, NULL}, + {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"}, + + {"-internal-border-width", "*EmacsScreen.internalBorderWidth", + XrmoptionSepArg, NULL}, + {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL}, + + {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, + {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, + {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, + {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, + {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, + {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL}, + {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL} +}; +#endif /* USE_X_TOOLKIT */ + +static int x_initialized; + +#ifdef MULTI_KBOARD +/* Test whether two display-name strings agree up to the dot that separates + the screen number from the server number. */ +static int +same_x_server (name1, name2) + char *name1, *name2; +{ + int seen_colon = 0; + unsigned char *system_name = XSTRING (Vsystem_name)->data; + int system_name_length = strlen (system_name); + int length_until_period = 0; + + while (system_name[length_until_period] != 0 + && system_name[length_until_period] != '.') + length_until_period++; + + /* Treat `unix' like an empty host name. */ + if (! strncmp (name1, "unix:", 5)) + name1 += 4; + if (! strncmp (name2, "unix:", 5)) + name2 += 4; + /* Treat this host's name like an empty host name. */ + if (! strncmp (name1, system_name, system_name_length) + && name1[system_name_length] == ':') + name1 += system_name_length; + if (! strncmp (name2, system_name, system_name_length) + && name2[system_name_length] == ':') + name2 += system_name_length; + /* Treat this host's domainless name like an empty host name. */ + if (! strncmp (name1, system_name, length_until_period) + && name1[length_until_period] == ':') + name1 += length_until_period; + if (! strncmp (name2, system_name, length_until_period) + && name2[length_until_period] == ':') + name2 += length_until_period; + + for (; *name1 != '\0' && *name1 == *name2; name1++, name2++) + { + if (*name1 == ':') + seen_colon++; + if (seen_colon && *name1 == '.') + return 1; + } + return (seen_colon + && (*name1 == '.' || *name1 == '\0') + && (*name2 == '.' || *name2 == '\0')); +} +#endif + +struct mac_display_info * +x_term_init (display_name, xrm_option, resource_name) + Lisp_Object display_name; + char *xrm_option; + char *resource_name; +{ + if (!x_initialized) + { + x_initialize (); + x_initialized = 1; + } + + return &one_mac_display_info; +} + +/* Set up use of X before we make the first connection. */ + +static struct redisplay_interface x_redisplay_interface = +{ + x_produce_glyphs, + x_write_glyphs, + x_insert_glyphs, + x_clear_end_of_line, + x_scroll_run, + x_after_update_window_line, + x_update_window_begin, + x_update_window_end, + XTcursor_to, + x_flush, + x_clear_mouse_face, + x_get_glyph_overhangs, + x_fix_overlapping_area +}; + + +/* The Mac Event loop code */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __MWERKS__ +#include +#endif + +#define M_APPLE 128 +#define I_ABOUT 1 + +#define WINDOW_RESOURCE 128 +#define TERM_WINDOW_RESOURCE 129 + +#define DEFAULT_NUM_COLS 80 + +#define MIN_DOC_SIZE 64 +#define MAX_DOC_SIZE 32767 + +/* sleep time for WaitNextEvent */ +#define WNE_SLEEP_AT_SUSPEND 10 +#define WNE_SLEEP_AT_RESUME 1 + +/* true when cannot handle any Mac OS events */ +static int handling_window_update = 0; + +/* the flag appl_is_suspended is used both for determining the sleep + time to be passed to WaitNextEvent and whether the cursor should be + drawn when updating the display. The cursor is turned off when + Emacs is suspended. Redrawing it is unnecessary and what needs to + be done depends on whether the cursor lies inside or outside the + redraw region. So we might as well skip drawing it when Emacs is + suspended. */ +static Boolean app_is_suspended = false; +static long app_sleep_time = WNE_SLEEP_AT_RESUME; + +#define EXTRA_STACK_ALLOC (256 * 1024) + +#define ARGV_STRING_LIST_ID 129 +#define ABOUT_ALERT_ID 128 + +Boolean terminate_flag = false; + +/* true if using command key as meta key */ +Lisp_Object Vmac_command_key_is_meta; + +/* convert input from Mac keyboard (assumed to be in Mac Roman coding) + to this text encoding */ +int mac_keyboard_text_encoding; +int current_mac_keyboard_text_encoding = kTextEncodingMacRoman; + +/* Set in term/mac-win.el to indicate that event loop can now generate + drag and drop events. */ +Lisp_Object Vmac_ready_for_drag_n_drop; + +Lisp_Object drag_and_drop_file_list; + +Point saved_menu_event_location; + +/* Apple Events */ +static void init_required_apple_events(void); +static pascal OSErr do_ae_open_application(const AppleEvent *, AppleEvent *, long); +static pascal OSErr do_ae_print_documents(const AppleEvent *, AppleEvent *, long); +static pascal OSErr do_ae_open_documents(AppleEvent *, AppleEvent *, long); +static pascal OSErr do_ae_quit_application(AppleEvent *, AppleEvent *, long); + +extern void init_emacs_passwd_dir (); +extern int emacs_main (int, char **, char **); +extern void check_alarm (); + +extern void initialize_applescript(); +extern void terminate_applescript(); + + +static void +do_get_menus (void) +{ + Handle menubar_handle; + MenuHandle menu_handle; + + menubar_handle = GetNewMBar (128); + if(menubar_handle == NULL) + abort (); + SetMenuBar (menubar_handle); + DrawMenuBar (); + + menu_handle = GetMenuHandle (M_APPLE); + if(menu_handle != NULL) + AppendResMenu (menu_handle,'DRVR'); + else + abort (); +} + + +static void +do_init_managers (void) +{ + InitGraf (&qd.thePort); + InitFonts (); + FlushEvents (everyEvent, 0); + InitWindows (); + InitMenus (); + TEInit (); + InitDialogs (NULL); + InitCursor (); + + /* set up some extra stack space for use by emacs */ + SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC)); + + /* MaxApplZone must be called for AppleScript to execute more + complicated scripts */ + MaxApplZone (); + MoreMasters (); +} + + +static void +do_window_update (WindowPtr win) +{ + struct mac_output *mwp = (mac_output *) GetWRefCon (win); + struct frame *f = mwp->mFP; + + if (f) + { + if (f->async_visible == 0) + { + f->async_visible = 1; + f->async_iconified = 0; + SET_FRAME_GARBAGED (f); + + /* An update event is equivalent to MapNotify on X, so report + visibility changes properly. */ + if (! NILP(Vframe_list) && ! NILP (XCDR (Vframe_list))) + /* Force a redisplay sooner or later to update the + frame titles in case this is the second frame. */ + record_asynch_buffer_change (); + } + else + { + BeginUpdate (win); + handling_window_update = 1; + + expose_frame (f, 0, 0, 0, 0); + + handling_window_update = 0; + EndUpdate (win); + } + } +} + +static void +do_window_activate (WindowPtr win) +{ + mac_output *mwp = (mac_output *) GetWRefCon (win); + struct frame *f = mwp->mFP; + + if (f) + { + x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f); + activate_scroll_bars (f); + } +} + +static void +do_window_deactivate (WindowPtr win) +{ + mac_output *mwp = (mac_output *) GetWRefCon (win); + struct frame *f = mwp->mFP; + + if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame) + { + x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0); + deactivate_scroll_bars (f); + } +} + +static void +do_app_resume () +{ + mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ()); + struct frame *f = mwp->mFP; + + if (f) + { + x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f); + activate_scroll_bars (f); + } + + app_is_suspended = false; + app_sleep_time = WNE_SLEEP_AT_RESUME; +} + +static void +do_app_suspend () +{ + mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ()); + struct frame *f = mwp->mFP; + + if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame) + { + x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0); + deactivate_scroll_bars (f); + } + + app_is_suspended = true; + app_sleep_time = WNE_SLEEP_AT_SUSPEND; +} + + +static void +do_mouse_moved (Point mouse_pos) +{ + WindowPtr wp = FrontWindow (); + struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; + + SetPort (wp); + GlobalToLocal (&mouse_pos); + + note_mouse_movement (f, &mouse_pos); +} + + +static void +do_os_event (EventRecord *erp) +{ + switch((erp->message >> 24) & 0x000000FF) + { + case suspendResumeMessage: + if((erp->message & resumeFlag) == 1) + do_app_resume (); + else + do_app_suspend (); + break; + + case mouseMovedMessage: + do_mouse_moved (erp->where); + break; + } +} + +static void +do_events (EventRecord *erp) +{ + switch (erp->what) + { + case updateEvt: + do_window_update ((WindowPtr) erp->message); + break; + + case osEvt: + do_os_event (erp); + break; + + case activateEvt: + if ((erp->modifiers & activeFlag) != 0) + do_window_activate ((WindowPtr) erp->message); + else + do_window_deactivate ((WindowPtr) erp->message); + break; + } +} + +static void +do_apple_menu (SInt16 menu_item) +{ + Str255 item_name; + SInt16 da_driver_refnum; + + if (menu_item == I_ABOUT) + NoteAlert (ABOUT_ALERT_ID, NULL); + else + { + GetMenuItemText (GetMenuHandle (M_APPLE), menu_item, item_name); + da_driver_refnum = OpenDeskAcc (item_name); + } +} + +void +do_menu_choice (SInt32 menu_choice) +{ + SInt16 menu_id, menu_item; + + menu_id = HiWord (menu_choice); + menu_item = LoWord (menu_choice); + + if (menu_id == 0) + return; + + switch (menu_id) + { + case M_APPLE: + do_apple_menu (menu_item); + break; + + default: + { + WindowPtr wp = FrontWindow (); + struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; + MenuHandle menu = GetMenuHandle (menu_id); + if (menu) + { + UInt32 refcon; + + GetMenuItemRefCon (menu, menu_item, &refcon); + menubar_selection_callback (f, refcon); + } + } + } + + HiliteMenu (0); +} + + +/* Handle drags in size box. Based on code contributed by Ben + Mesander and IM - Window Manager A. */ + +static void +do_grow_window (WindowPtr w, EventRecord *e) +{ + long grow_size; + Rect limit_rect; + int rows, columns; + mac_output *mwp = (mac_output *) GetWRefCon (w); + struct frame *f = mwp->mFP; + + SetRect(&limit_rect, MIN_DOC_SIZE, MIN_DOC_SIZE, MAX_DOC_SIZE, MAX_DOC_SIZE); + + grow_size = GrowWindow (w, e->where, &limit_rect); + + /* see if it really changed size */ + if (grow_size != 0) + { + rows = PIXEL_TO_CHAR_HEIGHT (f, HiWord (grow_size)); + columns = PIXEL_TO_CHAR_WIDTH (f, LoWord (grow_size)); + + x_set_window_size (f, 0, columns, rows); + } +} + + +/* Handle clicks in zoom box. Calculation of "standard state" based + on code in IM - Window Manager A and code contributed by Ben + Mesander. The standard state of an Emacs window is 80-characters + wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */ + +static void +do_zoom_window (WindowPtr w, int zoom_in_or_out) +{ + GrafPtr save_port; + Rect zoom_rect, port_rect; + Point top_left; + int w_title_height, columns, rows, width, height, dummy, x, y; + mac_output *mwp = (mac_output *) GetWRefCon (w); + struct frame *f = mwp->mFP; + + GetPort (&save_port); + SetPort (w); + EraseRect (&(w->portRect)); /* erase to avoid flicker */ + if (zoom_in_or_out == inZoomOut) + { + SetPt(&top_left, w->portRect.left, w->portRect.top); + LocalToGlobal (&top_left); + + /* calculate height of window's title bar */ + w_title_height = top_left.v - 1 + - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight(); + + /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */ + zoom_rect = qd.screenBits.bounds; + zoom_rect.top += w_title_height; + InsetRect (&zoom_rect, 8, 4); /* not too tight */ + + zoom_rect.right = zoom_rect.left + + CHAR_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS); + + (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState = zoom_rect; + } + + ZoomWindow (w, zoom_in_or_out, w == FrontWindow()); + + /* retrieve window size and update application values */ + port_rect = w->portRect; + rows = PIXEL_TO_CHAR_HEIGHT (f, port_rect.bottom - port_rect.top); + columns = PIXEL_TO_CHAR_WIDTH (f, port_rect.right - port_rect.left); + x_set_window_size (mwp->mFP, 0, columns, rows); + + SetPort (save_port); +} + + +/* Intialize AppleEvent dispatcher table for the required events. */ +void +init_required_apple_events () +{ + OSErr err; + long result; + + /* Make sure we have apple events before starting. */ + err = Gestalt (gestaltAppleEventsAttr, &result); + if (err != noErr) + abort (); + + if (!(result & (1 << gestaltAppleEventsPresent))) + abort (); + + err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, + NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_open_application), + 0L, false); + if (err != noErr) + abort (); + + err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, + NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_open_documents), + 0L, false); + if (err != noErr) + abort (); + + err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, + NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_print_documents), + 0L, false); + if (err != noErr) + abort (); + + err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, + NewAEEventHandlerProc ((AEEventHandlerProcPtr) do_ae_quit_application), + 0L, false); + if (err != noErr) + abort (); +} + + +/* Open Application Apple Event */ +static pascal OSErr +do_ae_open_application(const AppleEvent *pae, AppleEvent *preply, long prefcon) +{ + return noErr; +} + + +/* Defined in mac.c. */ +extern int +path_from_vol_dir_name (char *, int, short, long, char *); + + +/* Called when we receive an AppleEvent with an ID of + "kAEOpenDocuments". This routine gets the direct parameter, + extracts the FSSpecs in it, and puts their names on a list. */ +static pascal OSErr +do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon) +{ + OSErr err, err2; + AEDesc the_desc; + AEKeyword keyword; + DescType actual_type; + Size actual_size; + + err = AEGetParamDesc (message, keyDirectObject, typeAEList, &the_desc); + if (err != noErr) + goto descriptor_error_exit; + + /* Check to see that we got all of the required parameters from the + event descriptor. For an 'odoc' event this should just be the + file list. */ + err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard, + &actual_type, (Ptr) &keyword, + sizeof (keyword), &actual_size); + /* No error means that we found some unused parameters. + errAEDescNotFound means that there are no more parameters. If we + get an error code other than that, flag it. */ + if ((err == noErr) || (err != errAEDescNotFound)) + { + err = errAEEventNotHandled; + goto error_exit; + } + err = noErr; + + /* Got all the parameters we need. Now, go through the direct + object list and parse it up. */ + { + long num_files_to_open; + + err = AECountItems (&the_desc, &num_files_to_open); + if (err == noErr) + { + int i; + + /* AE file list is one based so just use that for indexing here. */ + for (i = 1; (err == noErr) && (i <= num_files_to_open); i++) { + FSSpec fs; + Str255 path_name, unix_path_name; + + err = AEGetNthPtr(&the_desc, i, typeFSS, &keyword, &actual_type, + (Ptr) &fs, sizeof (fs), &actual_size); + if (err != noErr) break; + + if (path_from_vol_dir_name (path_name, 255, fs.vRefNum, fs.parID, + fs.name) && + mac_to_unix_pathname (path_name, unix_path_name, 255)) + drag_and_drop_file_list = Fcons (build_string (unix_path_name), + drag_and_drop_file_list); + } + } + } + +error_exit: + /* Nuke the coerced file list in any case */ + err2 = AEDisposeDesc(&the_desc); + +descriptor_error_exit: + /* InvalRect(&(gFrontMacWindowP->mWP->portRect)); */ + return err; +} + + +/* Print Document Apple Event */ +static pascal OSErr +do_ae_print_documents (const AppleEvent *pAE, AppleEvent *reply, long refcon) +{ + return errAEEventNotHandled; +} + + +static pascal OSErr +do_ae_quit_application (AppleEvent* message, AppleEvent *reply, long refcon) +{ + /* FixMe: Do we need an unwind-protect or something here? And what + do we do about unsaved files. Currently just forces quit rather + than doing recursive callback to get user input. */ + + terminate_flag = true; + + /* Fkill_emacs doesn't return. We have to return. (TI) */ + return noErr; +} + + +#if __profile__ +void +profiler_exit_proc () +{ + ProfilerDump ("\pEmacs.prof"); + ProfilerTerm (); +} +#endif + +/* These few functions implement Emacs as a normal Mac application + (almost): set up the the heap and the Toolbox, handle necessary + system events plus a few simple menu events. They also set up + Emacs's access to functions defined in the rest of this file. + Emacs uses function hooks to perform all its terminal I/O. A + complete list of these functions appear in termhooks.h. For what + they do, read the comments there and see also w32term.c and + xterm.c. What's noticeably missing here is the event loop, which + is normally present in most Mac application. After performing the + necessary Mac initializations, main passes off control to + emacs_main (corresponding to main in emacs.c). Emacs_main calls + mac_read_socket (defined further below) to read input. This is + where WaitNextEvent is called to process Mac events. This is also + where check_alarm in sysdep.c is called to simulate alarm signals. + This makes the cursor jump back to its correct position after + briefly jumping to that of the matching parenthesis, print useful + hints and prompts in the minibuffer after the user stops typing for + a wait, etc. */ + +#undef main +int +main (void) +{ +#if __profile__ /* is the profiler on? */ + if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200)) + exit(1); +#endif + +#if __MWERKS__ + /* set creator and type for files created by MSL */ + _fcreator = 'EMAx'; + _ftype = 'TEXT'; +#endif + + do_init_managers (); + + do_get_menus (); + + init_emacs_passwd_dir (); + + init_environ (); + + initialize_applescript (); + + init_required_apple_events (); + + { + char **argv; + int argc = 0; + + /* set up argv array from STR# resource */ + get_string_list (&argv, ARGV_STRING_LIST_ID); + while (argv[argc]) + argc++; + + /* free up AppleScript resources on exit */ + atexit (terminate_applescript); + +#if __profile__ /* is the profiler on? */ + atexit (profiler_exit_proc); +#endif + + /* 3rd param "envp" never used in emacs_main */ + (void) emacs_main (argc, argv, 0); + } + + /* Never reached - real exit in Fkill_emacs */ + return 0; +} + + +/* Table for translating Mac keycode to X keysym values. Contributed + by Sudhir Shenoy. */ +static unsigned char keycode_to_xkeysym_table[] = { +/* 0x00 - 0x3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x40 */ + 0, '\xae' /* kp. */, 0, '\xaa' /* kp* */, + 0, '\xab' /* kp+ */, 0, '\x7f' /* kp_clr */, + 0, 0, 0, '\xaf' /* kp/ */, + '\x8d' /* kp_ent */, 0, '\xad' /* kp- */, 0, +/* 0x50 */ + 0, '\xbd' /* kp= */, '\xb0' /* kp0 */, '\xb1' /* kp1 */, + '\xb2' /* kp2 */, '\xb3' /* kp3 */, '\xb4' /* kp4 */, '\xb5' /* kp5 */, + '\xb6' /* kp6 */, '\xb7' /* kp7 */, 0, '\xb8' /* kp8 */, + '\xb9' /* kp9 */, 0, 0, 0, +/* 0x60 */ + '\xc2' /* F5 */, '\xc3' /* F6 */, '\xc4' /* F7 */, '\xc0' /* F3 */, + '\xc5' /* F8 */, '\xc6' /* F9 */, 0, '\xc8' /* F11 */, + 0, '\xca' /* F13 */, 0, '\xcb' /* F14 */, + 0, '\xc7' /* F10 */, 0, '\xc9' /* F12 */, +/* 0x70 */ + 0, '\xcc' /* F15 */, '\x9e' /* ins */, '\x95' /* home */, + '\x9a' /* pgup */, '\x9f' /* del */, '\xc1' /* F4 */, '\x9c' /* end */, + '\xbf' /* F2 */, '\x9b' /* pgdown */, '\xbe' /* F1 */, '\x51' /* left */, + '\x53' /* right */, '\x54' /* down */, '\x52' /* up */, 0 +}; + +static int +keycode_to_xkeysym (int keyCode, int *xKeySym) +{ + *xKeySym = keycode_to_xkeysym_table [keyCode & 0x7f]; + return *xKeySym != 0; +} + +/* Emacs calls this whenever it wants to read an input event from the + user. */ +int +XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) +{ + int count = 0; + EventRecord er; + int the_modifiers; + EventMask event_mask; + + if (interrupt_input_blocked) + { + interrupt_input_pending = 1; + return -1; + } + + interrupt_input_pending = 0; + BLOCK_INPUT; + + /* So people can tell when we have read the available input. */ + input_signal_count++; + + if (numchars <= 0) + abort (); + + /* Don't poll for events to process (specifically updateEvt) if + window update currently already in progress. A call to redisplay + (in do_window_update) can be preempted by another call to + redisplay, causing blank regions to be left on the screen and the + cursor to be left at strange places. */ + if (handling_window_update) + { + UNBLOCK_INPUT; + return 0; + } + + if (terminate_flag) + Fkill_emacs (make_number (1)); + + /* It is necessary to set this (additional) argument slot of an + event to nil because keyboard.c protects incompletely processed + event from being garbage collected by placing them in the + kbd_buffer_gcpro vector. */ + bufp->arg = Qnil; + + event_mask = everyEvent; + if (NILP (Vmac_ready_for_drag_n_drop)) + event_mask -= highLevelEventMask; + + if (WaitNextEvent (event_mask, &er, (expected ? app_sleep_time : 0L), NULL)) + switch (er.what) + { + case mouseDown: + case mouseUp: + { + WindowPtr window_ptr = FrontWindow (); + SInt16 part_code; + + if (mouse_tracking_in_progress == mouse_tracking_scroll_bar + && er.what == mouseUp) + { + struct mac_output *mwp = (mac_output *) GetWRefCon (window_ptr); + Point mouse_loc = er.where; + + /* Convert to local coordinates of new window. */ + SetPort (window_ptr); + GlobalToLocal (&mouse_loc); + + bufp->code = 0; /* only one mouse button */ + bufp->kind = scroll_bar_click; + bufp->frame_or_window = tracked_scroll_bar->window; + bufp->part = scroll_bar_handle; + bufp->modifiers = up_modifier; + bufp->timestamp = er.when * (1000 / 60); + /* ticks to milliseconds */ + + XSETINT (bufp->x, tracked_scroll_bar->left + 2); + XSETINT (bufp->y, mouse_loc.v - 24); + tracked_scroll_bar->dragging = Qnil; + mouse_tracking_in_progress = mouse_tracking_none; + tracked_scroll_bar = NULL; + count++; + break; + } + + part_code = FindWindow (er.where, &window_ptr); + + switch (part_code) + { + case inMenuBar: + { + struct frame *f = ((mac_output *) + GetWRefCon (FrontWindow ()))->mFP; + saved_menu_event_location = er.where; + bufp->kind = menu_bar_activate_event; + XSETFRAME (bufp->frame_or_window, f); + count++; + } + break; + + case inContent: + if (window_ptr != FrontWindow ()) + SelectWindow (window_ptr); + else + { + int control_part_code; + ControlHandle ch; + struct mac_output *mwp = (mac_output *) + GetWRefCon (window_ptr); + Point mouse_loc = er.where; + + /* convert to local coordinates of new window */ + SetPort (window_ptr); + GlobalToLocal (&mouse_loc); + control_part_code = FindControl (mouse_loc, window_ptr, &ch); + + bufp->code = 0; /* only one mouse button */ + XSETINT (bufp->x, mouse_loc.h); + XSETINT (bufp->y, mouse_loc.v); + bufp->timestamp = er.when * (1000 / 60); + /* ticks to milliseconds */ + + if (control_part_code != 0) + { + struct scroll_bar *bar = (struct scroll_bar *) + GetControlReference (ch); + x_scroll_bar_handle_click (bar, control_part_code, &er, + bufp); + if (er.what == mouseDown + && control_part_code == kControlIndicatorPart) + { + mouse_tracking_in_progress = mouse_tracking_scroll_bar; + tracked_scroll_bar = bar; + } + else + { + mouse_tracking_in_progress = mouse_tracking_none; + tracked_scroll_bar = NULL; + } + } + else + { + bufp->kind = mouse_click; + XSETFRAME (bufp->frame_or_window, mwp->mFP); + if (er.what == mouseDown) + mouse_tracking_in_progress = mouse_tracking_mouse_movement; + else + mouse_tracking_in_progress = mouse_tracking_none; + } + + switch (er.what) + { + case mouseDown: + bufp->modifiers = down_modifier; + break; + case mouseUp: + bufp->modifiers = up_modifier; + break; + } + + count++; + } + break; + + case inDrag: + DragWindow (window_ptr, er.where, &qd.screenBits.bounds); + break; + + case inGoAway: + if (TrackGoAway (window_ptr, er.where)) + { + bufp->kind = delete_window_event; + XSETFRAME (bufp->frame_or_window, + ((mac_output *) GetWRefCon (window_ptr))->mFP); + count++; + } + break; + + /* window resize handling added --ben */ + case inGrow: + do_grow_window(window_ptr, &er); + break; + + /* window zoom handling added --ben */ + case inZoomIn: + case inZoomOut: + if (TrackBox (window_ptr, er.where, part_code)) + do_zoom_window (window_ptr, part_code); + break; + + default: + break; + } + } + break; + + case updateEvt: + case osEvt: + case activateEvt: + do_events (&er); + break; + + case keyDown: + case autoKey: + { + int keycode = (er.message & keyCodeMask) >> 8; + int xkeysym; + + ObscureCursor (); + + if (keycode == 0x33) /* delete key (charCode translated to 0x8) */ + { + bufp->code = 0x7f; + bufp->kind = ascii_keystroke; + } + else if (keycode_to_xkeysym (keycode, &xkeysym)) + { + bufp->code = 0xff00 | xkeysym; + bufp->kind = non_ascii_keystroke; + } + else + { + if (er.modifiers + & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey)) + { + /* This code comes from Keyboard Resource, Appendix + C of IM - Text. This is necessary since shift is + ignored in KCHR table translation when option or + command is pressed. */ + int new_modifiers = er.modifiers & 0xf600; + /* mask off option and command */ + int new_keycode = keycode | new_modifiers; + Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache); + unsigned long some_state = 0; + bufp->code = KeyTranslate (kchr_ptr, new_keycode, + &some_state) & 0xff; + } + else + bufp->code = er.message & charCodeMask; + bufp->kind = ascii_keystroke; + } + } + + /* If variable mac-convert-keyboard-input-to-latin-1 is non-nil, + convert non-ASCII characters typed at the Mac keyboard + (presumed to be in the Mac Roman encoding) to iso-latin-1 + encoding before they are passed to Emacs. This enables the + Mac keyboard to be used to enter non-ASCII iso-latin-1 + characters directly. */ + if (mac_keyboard_text_encoding != kTextEncodingMacRoman + && bufp->kind == ascii_keystroke && bufp->code >= 128) + { + static TECObjectRef converter = NULL; + OSStatus the_err = noErr; + OSStatus convert_status = noErr; + + if (converter == NULL) + { + the_err = TECCreateConverter (&converter, + kTextEncodingMacRoman, + mac_keyboard_text_encoding); + current_mac_keyboard_text_encoding = mac_keyboard_text_encoding; + } + else if (mac_keyboard_text_encoding != current_mac_keyboard_text_encoding) + { + /* Free the converter for the current encoding before + creating a new one. */ + TECDisposeConverter (converter); + the_err = TECCreateConverter (&converter, + kTextEncodingMacRoman, + mac_keyboard_text_encoding); + current_mac_keyboard_text_encoding = mac_keyboard_text_encoding; + } + + if (the_err == noErr) + { + unsigned char ch = bufp->code; + ByteCount actual_input_length, actual_output_length; + unsigned char outch; + + convert_status = TECConvertText (converter, &ch, 1, + &actual_input_length, + &outch, 1, + &actual_output_length); + if (convert_status == noErr + && actual_input_length == 1 + && actual_output_length == 1) + bufp->code = outch; + } + } + + the_modifiers = 0; + if (er.modifiers & shiftKey) + the_modifiers |= shift_modifier; + if (er.modifiers & controlKey) + the_modifiers |= ctrl_modifier; + /* use option or command key as meta depending on value of + mac-command-key-is-meta */ + if (er.modifiers + & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey)) + the_modifiers |= meta_modifier; + bufp->modifiers = the_modifiers; + + { + mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ()); + XSETFRAME (bufp->frame_or_window, mwp->mFP); + } + + bufp->timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ + + count++; + break; + + case kHighLevelEvent: + drag_and_drop_file_list = Qnil; + + AEProcessAppleEvent(&er); + + /* Build a drag_n_drop type event as is done in + constuct_drag_n_drop in w32term.c. */ + if (!NILP (drag_and_drop_file_list)) + { + struct frame *f; + WindowPtr wp; + Lisp_Object frame; + + wp = FrontWindow (); + if (!wp) + f = NULL; + else + f = ((mac_output *) GetWRefCon (wp))->mFP; + + bufp->kind = drag_n_drop; + bufp->code = 0; + bufp->timestamp = er.when * (1000 / 60); + /* ticks to milliseconds */ + bufp->modifiers = 0; + + XSETINT (bufp->x, 0); + XSETINT (bufp->y, 0); + + XSETFRAME (frame, f); + bufp->frame_or_window = Fcons (frame, drag_and_drop_file_list); + + /* Regardless of whether Emacs was suspended or in the + foreground, ask it to redraw its entire screen. + Otherwise parts of the screen can be left in an + inconsistent state. */ + if (wp) + InvalRect (&(wp->portRect)); + + count++; + } + + default: + break; + } + + /* If the focus was just given to an autoraising frame, + raise it now. */ + /* ??? This ought to be able to handle more than one such frame. */ + if (pending_autoraise_frame) + { + x_raise_frame (pending_autoraise_frame); + pending_autoraise_frame = 0; + } + + check_alarm (); /* simulate the handling of a SIGALRM */ + + { + static Point old_mouse_pos = { -1, -1 }; + + if (app_is_suspended) + { + old_mouse_pos.h = -1; + old_mouse_pos.v = -1; + } + else + { + Point mouse_pos; + WindowPtr wp = FrontWindow (); + struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; + Lisp_Object bar; + struct scroll_bar *sb; + + SetPort (wp); + GetMouse (&mouse_pos); + + if (!EqualPt (mouse_pos, old_mouse_pos)) + { + if (mouse_tracking_in_progress == mouse_tracking_scroll_bar + && tracked_scroll_bar) + x_scroll_bar_note_movement (tracked_scroll_bar, + mouse_pos.v + - XINT (tracked_scroll_bar->top), + TickCount() * (1000 / 60)); + else + note_mouse_movement (f, &mouse_pos); + + old_mouse_pos = mouse_pos; + } + } + } + + UNBLOCK_INPUT; + + return count; +} + + +/* Need to override CodeWarrior's input function so no conversion is + done on newlines Otherwise compiled functions in .elc files will be + read incorrectly. Defined in ...:MSL C:MSL + Common:Source:buffer_io.c. */ +#ifdef __MWERKS__ +void +__convert_to_newlines (unsigned char * p, size_t * n) +{ +#pragma unused(p,n) +} + +void +__convert_from_newlines (unsigned char * p, size_t * n) +{ +#pragma unused(p,n) +} +#endif + + +/* Initialize the struct pointed to by MW to represent a new COLS x + ROWS Macintosh window, using font with name FONTNAME and size + FONTSIZE. */ +void +NewMacWindow (FRAME_PTR fp) +{ + mac_output *mwp; + static int making_terminal_window = 1; + + mwp = fp->output_data.mac; + + if (making_terminal_window) + { + if (!(mwp->mWP = GetNewCWindow (TERM_WINDOW_RESOURCE, NULL, + (WindowPtr) -1))) + abort (); + making_terminal_window = 0; + } + else + if (!(mwp->mWP = GetNewCWindow (WINDOW_RESOURCE, NULL, (WindowPtr) -1))) + abort (); + + + SetWRefCon (mwp->mWP, (long) mwp); + /* so that update events can find this mac_output struct */ + mwp->mFP = fp; /* point back to emacs frame */ + + SetPort (mwp->mWP); + + mwp->fontset = -1; + + SizeWindow (mwp->mWP, mwp->pixel_width, mwp->pixel_height, false); + ShowWindow (mwp->mWP); + +} + + +void make_mac_frame (struct frame *f) +{ + FRAME_CAN_HAVE_SCROLL_BARS (f) = 1; + FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right; + + NewMacWindow(f); + f->output_data.mac->background_pixel = 0xffffff; + f->output_data.mac->foreground_pixel = 0; + + f->output_data.mac->cursor_pixel = 0; + f->output_data.mac->border_pixel = 0x00ff00; + f->output_data.mac->mouse_pixel = 0xff00ff; + f->output_data.mac->cursor_foreground_pixel = 0x0000ff; + + f->output_data.mac->desired_cursor = FILLED_BOX_CURSOR; + + f->output_data.mac->fontset = -1; + f->output_data.mac->scroll_bar_foreground_pixel = -1; + f->output_data.mac->scroll_bar_background_pixel = -1; + f->output_data.mac->left_pos = 4; + f->output_data.mac->top_pos = 4; + f->output_data.mac->border_width = 0; + f->output_data.mac->explicit_parent = 0; + + f->output_data.mac->internal_border_width = 0; + + f->output_method = output_mac; + + f->auto_raise = 1; + f->auto_lower = 1; + + f->new_width = 0; + f->new_height = 0; +} + +void make_mac_terminal_frame (struct frame *f) +{ + Lisp_Object frame; + + XSETFRAME (frame, f); + + f->output_method = output_mac; + f->output_data.mac = (struct mac_output *) + xmalloc (sizeof (struct mac_output)); + bzero (f->output_data.mac, sizeof (struct mac_output)); + f->output_data.mac->fontset = -1; + f->output_data.mac->scroll_bar_foreground_pixel = -1; + f->output_data.mac->scroll_bar_background_pixel = -1; + + XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f); + + f->width = 96; + f->height = 4; + + make_mac_frame (f); + + Fmodify_frame_parameters (frame, + Fcons (Fcons (Qfont, + build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil)); + Fmodify_frame_parameters (frame, + Fcons (Fcons (Qforeground_color, + build_string ("black")), Qnil)); + Fmodify_frame_parameters (frame, + Fcons (Fcons (Qbackground_color, + build_string ("white")), Qnil)); +} + +void +mac_initialize_display_info () +{ + struct mac_display_info *dpyinfo = &one_mac_display_info; + GDHandle main_device_handle; + + bzero (dpyinfo, sizeof (*dpyinfo)); + + /* Put it on x_display_name_list. */ + x_display_name_list = Fcons (Fcons (build_string ("Mac"), Qnil), + x_display_name_list); + dpyinfo->name_list_element = XCAR (x_display_name_list); + + main_device_handle = LMGetMainDevice(); + + dpyinfo->reference_count = 0; + dpyinfo->resx = 75.0; + dpyinfo->resy = 75.0; + dpyinfo->n_planes = 1; + dpyinfo->n_cbits = 16; + dpyinfo->height = (**main_device_handle).gdRect.bottom; + dpyinfo->width = (**main_device_handle).gdRect.right; + dpyinfo->grabbed = 0; + dpyinfo->root_window = NULL; + + dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; + dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; + dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID; + dpyinfo->mouse_face_window = Qnil; + +} + +void +x_initialize () +{ + rif = &x_redisplay_interface; + + clear_frame_hook = x_clear_frame; + ins_del_lines_hook = x_ins_del_lines; + change_line_highlight_hook = x_change_line_highlight; + delete_glyphs_hook = x_delete_glyphs; + ring_bell_hook = XTring_bell; + reset_terminal_modes_hook = XTreset_terminal_modes; + set_terminal_modes_hook = XTset_terminal_modes; + update_begin_hook = x_update_begin; + update_end_hook = x_update_end; + set_terminal_window_hook = XTset_terminal_window; + read_socket_hook = XTread_socket; + frame_up_to_date_hook = XTframe_up_to_date; + reassert_line_highlight_hook = XTreassert_line_highlight; + mouse_position_hook = XTmouse_position; + frame_rehighlight_hook = XTframe_rehighlight; + frame_raise_lower_hook = XTframe_raise_lower; + + set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar; + condemn_scroll_bars_hook = XTcondemn_scroll_bars; + redeem_scroll_bar_hook = XTredeem_scroll_bar; + judge_scroll_bars_hook = XTjudge_scroll_bars; + + estimate_mode_line_height_hook = x_estimate_mode_line_height; + + scroll_region_ok = 1; /* we'll scroll partial frames */ + char_ins_del_ok = 0; /* just as fast to write the line */ + line_ins_del_ok = 1; /* we'll just blt 'em */ + fast_clear_end_of_line = 1; /* X does this well */ + memory_below_frame = 0; /* we don't remember what scrolls + off the bottom */ + baud_rate = 19200; + + x_noop_count = 0; + last_tool_bar_item = -1; + any_help_event_p = 0; + + /* Try to use interrupt input; if we can't, then start polling. */ + Fset_input_mode (Qt, Qnil, Qt, Qnil); + +#ifdef USE_X_TOOLKIT + XtToolkitInitialize (); + Xt_app_con = XtCreateApplicationContext (); + XtAppSetFallbackResources (Xt_app_con, Xt_default_resources); + + /* Install an asynchronous timer that processes Xt timeout events + every 0.1s. This is necessary because some widget sets use + timeouts internally, for example the LessTif menu bar, or the + Xaw3d scroll bar. When Xt timouts aren't processed, these + widgets don't behave normally. */ + { + EMACS_TIME interval; + EMACS_SET_SECS_USECS (interval, 0, 100000); + start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0); + } +#endif + +#if USE_TOOLKIT_SCROLL_BARS + xaw3d_arrow_scroll = False; + xaw3d_pick_top = True; +#endif + +#if 0 + /* Note that there is no real way portable across R3/R4 to get the + original error handler. */ + XSetErrorHandler (x_error_handler); + XSetIOErrorHandler (x_io_error_quitter); + + /* Disable Window Change signals; they are handled by X events. */ +#ifdef SIGWINCH + signal (SIGWINCH, SIG_DFL); +#endif /* ! defined (SIGWINCH) */ + + signal (SIGPIPE, x_connection_signal); +#endif + + mac_initialize_display_info (); +} + + +void +syms_of_macterm () +{ +#if 0 + staticpro (&x_error_message_string); + x_error_message_string = Qnil; +#endif + + staticpro (&x_display_name_list); + x_display_name_list = Qnil; + + staticpro (&last_mouse_scroll_bar); + last_mouse_scroll_bar = Qnil; + + staticpro (&Qvendor_specific_keysyms); + Qvendor_specific_keysyms = intern ("vendor-specific-keysyms"); + + staticpro (&last_mouse_press_frame); + last_mouse_press_frame = Qnil; + + help_echo = Qnil; + staticpro (&help_echo); + help_echo_object = Qnil; + staticpro (&help_echo_object); + help_echo_window = Qnil; + staticpro (&help_echo_window); + previous_help_echo = Qnil; + staticpro (&previous_help_echo); + help_echo_pos = -1; + + DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p, + "*Non-nil means draw block cursor as wide as the glyph under it.\n\ +For example, if a block cursor is over a tab, it will be drawn as\n\ +wide as that tab on the display."); + x_stretch_cursor_p = 0; + + DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p, + "If not nil, Emacs uses toolkit scroll bars."); +#if USE_TOOLKIT_SCROLL_BARS + x_toolkit_scroll_bars_p = 1; +#else + x_toolkit_scroll_bars_p = 0; +#endif + + staticpro (&last_mouse_motion_frame); + last_mouse_motion_frame = Qnil; + + DEFVAR_LISP ("mac-command-key-is-meta", &Vmac_command_key_is_meta, + "Non-nil means that the command key is used as the Emacs meta key.\n\ +Otherwise the option key is used."); + Vmac_command_key_is_meta = Qt; + + DEFVAR_LISP ("mac-ready-for-drag-n-drop", &Vmac_ready_for_drag_n_drop, + "Non-nil indicates that the Mac event loop can now generate drag and\n\ +drop events. Set in term/mac-win.el."); + Vmac_ready_for_drag_n_drop = Qnil; + + DEFVAR_INT ("mac-keyboard-text-encoding", &mac_keyboard_text_encoding, + "One of the Text Encoding Base constant values defined in the\n\ +Basic Text Constants section of Inside Macintosh - Text Encoding\n\ +Conversion Manager. Its value determines the encoding characters\n\ +typed at the Mac keyboard (presumed to be in the MacRoman encoding)\n\ +will convert into. E.g., if it is set to kTextEncodingMacRoman (0),\n\ +its default value, no conversion takes place. If it is set to\n\ +kTextEncodingISOLatin1 (0x201) or kTextEncodingISOLatin2 (0x202),\n\ +characters typed on Mac keyboard are first converted into the\n\ +ISO Latin-1 or ISO Latin-2 encoding, respectively before being\n\ +passed to Emacs. Together with Emacs's set-keyboard-coding-system\n\ +command, this enables the Mac keyboard to be used to enter non-ASCII\n\ +characters directly."); + mac_keyboard_text_encoding = kTextEncodingMacRoman; +} diff --git a/src/ChangeLog b/src/ChangeLog index eaedd49679f..04736e027bf 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,73 @@ +2000-10-23 Andrew Choi + + * dispextern.h [macintosh]: Include macgui.h instead of macterm.h. + + * dispnew.c [macintosh]: Include macterm.h. + (init_display) [macintosh]: initialization for window system. + + * emacs.c (main) [macintosh]: Call syms_of_textprop, + syms_of_macfns, syms_of_ccl, syms_of_fontset, syms_of_xterm, + syms_of_search, x_term_init, and init_keyboard before calling + init_window_once. Also, call syms_of_xmenu. + + * fontset.c (syms_of_fontset) [macintosh]: Set ASCII font of + default fontset to Monaco. + + * frame.c [macintosh]: Include macterm.h. Remove declarations of + NewMacWindow and DisposeMacWindow. + (make_terminal_frame) [macintosh]: Call make_mac_terminal_frame + instead of calling NewMacWindow and setting fields of + f->output_data.mac directly. Call init_frame_faces. + (Fdelete_frame) [macintosh]: Remove unused code. + (Fmodify_frame_parameters) [macintosh]: Call + x_set_frame_parameters instead of mac_set_frame_parameters. + + * frame.h [macintosh]: Define menu_bar_lines field in struct + frame. Define FRAME_EXTERNAL_MENU_BAR macro. + + * keyboard.c [macintosh]: Include macterm.h. + (kbd_buffer_get_event) [macintosh]: Generate delete_window_event + and menu_bar_activate_event type events as for X and NT. + (make_lispy_event) [macintosh]: Construct lisp events of type + MENU_BAR_EVENT as for X and NT. + + * sysdep.c [macintosh]: Remove declaration for sys_signal. + Include stdlib.h. Remove definition of Vx_bitmap_file_path. + (sys_subshell) [macintosh]: Remove definition entirely. + (init_sys_modes) [macintosh]: Do not initialize Vwindow_system and + Vwindow_system_version here. Remove initialization of + Vx_bitmap_file_path. + (read_input_waiting): Correct the number of parameters passed to + read_socket_hook. + Move all Macintosh functions to mac/mac.c. + + * term.c [macintosh]: Include macterm.h. + + * window.c [macintosh]: Include macterm.h. + + * xdisp.c [macintosh]: Include macterm.h. Declare + set_frame_menubar and pending_menu_activation. + (echo_area_display) [macintosh]: Do not return if terminal frame + is the selected frame. + (update_menu_bar) [macintosh]: Check FRAME_EXTERNAL_MENU_BAR (f). + Allow only the selected frame to set menu bar. + (redisplay_window) [macintosh]: Obtain menu bar to redisplay by + calling FRAME_EXTERNAL_MENU_BAR (f). + (display_menu_bar) [macintosh]: Check FRAME_MAC_P (f). + + * xfaces.c [macintosh]: Include macterm.h. Define x_display_info + and check_x. Declare XCreateGC. Define x_create_gc and + x_free_gc. Initialize font_sort_order. + (x_face_list_fonts) [macintosh]: Use the same code as WINDOWSNT, + but call x_list_fonts instead of w32_list_fonts. + (Finternal_face_x_get_resource) [macintosh]: Do not call + display_x_get_resource. + (prepare_face_for_display) [macintosh]: Set xgcv.font. + (realize_x_face) [macintosh]: Load the font if it is specified in + ATTRS. + (syms_of_xfaces) [macintosh]: Initialize Vscalable_fonts_allowed + to Qt. + 2000-10-22 Stefan Monnier * keymap.c (fix_submap_inheritance): Don't do anything if parent_entry diff --git a/src/dispextern.h b/src/dispextern.h index 795387b9978..15ff0227dba 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -40,7 +40,7 @@ Boston, MA 02111-1307, USA. */ #endif #ifdef macintosh -#include "macterm.h" +#include "macgui.h" #endif /* Structure forward declarations. Some are here because function diff --git a/src/dispnew.c b/src/dispnew.c index be01f6756e2..14e4d968760 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -60,6 +60,10 @@ Boston, MA 02111-1307, USA. */ #include "w32term.h" #endif /* HAVE_NTGUI */ +#ifdef macintosh +#include "macterm.h" +#endif /* macintosh */ + /* Include systime.h after xterm.h to avoid double inclusion of time.h. */ #include "systime.h" @@ -6087,6 +6091,16 @@ init_display () } #endif /* HAVE_NTGUI */ +#ifdef macintosh + if (!inhibit_window_system) + { + Vwindow_system = intern ("mac"); + Vwindow_system_version = make_number (1); + adjust_frame_glyphs_initially (); + return; + } +#endif /* macintosh */ + /* If no window system has been specified, try to use the terminal. */ if (! isatty (0)) { diff --git a/src/emacs.c b/src/emacs.c index 9c2645f361f..92f70206d72 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1110,6 +1110,25 @@ main (argc, argv, envp) CANNOT_DUMP is defined. */ syms_of_keyboard (); +#ifdef macintosh + /* init_window_once calls make_terminal_frame which on Mac OS creates + a full-fledge output_mac type frame. This does not work correctly + before syms_of_textprop, syms_of_macfns, syms_of_ccl, + syms_of_fontset, syms_of_xterm, syms_of_search, x_term_init, and + init_keyboard have already been called. */ + syms_of_textprop (); + syms_of_macfns (); + syms_of_ccl (); + syms_of_fontset (); + syms_of_macterm (); + syms_of_macmenu (); + syms_of_data (); + syms_of_search (); + + x_term_init (); + init_keyboard (); +#endif + init_window_once (); /* Init the window system */ init_fileio_once (); /* Must precede any path manipulation. */ } @@ -1306,7 +1325,10 @@ main (argc, argv, envp) /* The basic levels of Lisp must come first */ /* And data must come first of all for the sake of symbols like error-message */ +#ifndef macintosh + /* Called before init_window_once for Mac OS. */ syms_of_data (); +#endif syms_of_alloc (); syms_of_lread (); syms_of_print (); @@ -1322,7 +1344,10 @@ main (argc, argv, envp) syms_of_casetab (); syms_of_callproc (); syms_of_category (); +#ifndef macintosh + /* Called before init_window_once for Mac OS. */ syms_of_ccl (); +#endif syms_of_charset (); syms_of_cmds (); #ifndef NO_DIR_LIBRARY @@ -1345,7 +1370,10 @@ main (argc, argv, envp) syms_of_minibuf (); syms_of_mocklisp (); syms_of_process (); +#ifndef macintosh + /* Called before init_window_once for Mac OS. */ syms_of_search (); +#endif syms_of_frame (); syms_of_syntax (); syms_of_term (); @@ -1353,8 +1381,10 @@ main (argc, argv, envp) #ifdef HAVE_SOUND syms_of_sound (); #endif - +#ifndef macintosh + /* Called before init_window_once for Mac OS. */ syms_of_textprop (); +#endif syms_of_composite (); #ifdef VMS syms_of_vmsproc (); @@ -1374,8 +1404,10 @@ main (argc, argv, envp) #endif /* HAVE_X_WINDOWS */ #ifndef HAVE_NTGUI +#ifndef macintosh syms_of_xmenu (); #endif +#endif #ifdef HAVE_NTGUI syms_of_w32term (); @@ -1411,7 +1443,10 @@ main (argc, argv, envp) #endif /* VMS */ init_display (); /* Determine terminal type. init_sys_modes uses results */ } +#ifndef macintosh + /* Called before init_window_once for Mac OS. */ init_keyboard (); /* This too must precede init_sys_modes */ +#endif #ifdef VMS init_vmsproc (); /* And this too. */ #endif /* VMS */ diff --git a/src/fontset.c b/src/fontset.c index 7b8f5ce73c9..56f782a2638 100644 --- a/src/fontset.c +++ b/src/fontset.c @@ -1397,9 +1397,15 @@ syms_of_fontset () FONTSET_ID (Vdefault_fontset) = make_number (0); FONTSET_NAME (Vdefault_fontset) = build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"); +#ifdef macintosh + FONTSET_ASCII (Vdefault_fontset) + = Fcons (make_number (0), + build_string ("-apple-monaco-medium-r-*--*-120-*-*-*-*-mac-roman")); +#else FONTSET_ASCII (Vdefault_fontset) = Fcons (make_number (0), build_string ("-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1")); +#endif AREF (Vfontset_table, 0) = Vdefault_fontset; next_fontset_id = 1; diff --git a/src/frame.c b/src/frame.c index b4afa56803b..403261ed326 100644 --- a/src/frame.c +++ b/src/frame.c @@ -29,6 +29,9 @@ Boston, MA 02111-1307, USA. */ #ifdef WINDOWSNT #include "w32term.h" #endif +#ifdef macintosh +#include "macterm.h" +#endif #include "buffer.h" /* These help us bind and responding to switch-frame events. */ #include "commands.h" @@ -45,11 +48,6 @@ Boston, MA 02111-1307, USA. */ #include "dosfns.h" #endif -#ifdef macintosh -extern struct mac_output *NewMacWindow (); -extern void DisposeMacWindow (struct mac_output *); -#endif - /* Evaluate this expression to rebuild the section of syms_of_frame that initializes and staticpros the symbols declared below. Note that Emacs 18 has a bug that keeps C-x C-e from being able to @@ -582,25 +580,15 @@ make_terminal_frame () f->output_method = output_termcap; #else #ifdef macintosh - f->output_data.mac = NewMacWindow(f); - f->output_data.mac->background_pixel = 0xffffff; - f->output_data.mac->foreground_pixel = 0; - f->output_data.mac->n_param_faces = 0; - f->output_data.mac->n_computed_faces = 0; - f->output_data.mac->size_computed_faces = 0; - f->output_method = output_mac; - f->auto_raise = 1; - f->auto_lower = 1; - init_frame_faces (f); -#else /* !macintosh */ + make_mac_terminal_frame (f); +#else f->output_data.x = &tty_display; -#endif /* !macintosh */ +#endif /* macintosh */ #endif /* MSDOS */ -#ifndef macintosh if (!noninteractive) init_frame_faces (f); -#endif + return f; } @@ -1288,14 +1276,6 @@ but if the second optional argument FORCE is non-nil, you may do so.") x_destroy_window (f); #endif -/* Done by x_destroy_window above already */ -#if 0 -#ifdef macintosh - if (FRAME_MAC_P (f)) - DisposeMacWindow (f->output_data.mac); -#endif -#endif - f->output_data.nothing = 0; /* If we've deleted the last_nonminibuf_frame, then try to find @@ -2229,11 +2209,6 @@ enabled such bindings for that variable with `make-variable-frame-local'.") IT_set_frame_parameters (f, alist); else #endif -#ifdef macintosh - if (FRAME_MAC_P (f)) - mac_set_frame_parameters (f, alist); - else -#endif { int length = XINT (Flength (alist)); diff --git a/src/frame.h b/src/frame.h index 01ba8f8f5cf..a8c759fe407 100644 --- a/src/frame.h +++ b/src/frame.h @@ -259,7 +259,7 @@ struct frame /* Number of lines of menu bar. */ int menu_bar_lines; -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) /* Nonzero means using a menu bar that comes from the X toolkit. */ int external_menu_bar; #endif @@ -442,7 +442,7 @@ typedef struct frame *FRAME_PTR; /* Nonzero if this frame should display a menu bar in a way that does not use any text lines. */ -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) #define FRAME_EXTERNAL_MENU_BAR(f) (f)->external_menu_bar #else #define FRAME_EXTERNAL_MENU_BAR(f) 0 diff --git a/src/keyboard.c b/src/keyboard.c index e4aac125a61..4e08cc5c3d6 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -70,6 +70,10 @@ Boston, MA 02111-1307, USA. */ #include "w32term.h" #endif /* HAVE_NTGUI */ +#ifdef macintosh +#include "macterm.h" +#endif + /* Include systime.h after xterm.h to avoid double inclusion of time.h. */ #include "systime.h" @@ -93,7 +97,7 @@ extern int input_fd; #ifdef HAVE_WINDOW_SYSTEM /* Make all keyboard buffers much bigger when using X windows. */ #ifdef macintosh -/* But not too big (local data > 32K error) if on macintosh */ +/* But not too big (local data > 32K error) if on macintosh. */ #define KBD_BUFFER_SIZE 512 #else #define KBD_BUFFER_SIZE 4096 @@ -3474,7 +3478,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu) abort (); #endif } -#if defined (HAVE_X11) || defined (HAVE_NTGUI) +#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (macintosh) else if (event->kind == delete_window_event) { /* Make an event (delete-frame (FRAME)). */ @@ -3482,6 +3486,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu) obj = Fcons (Qdelete_frame, Fcons (obj, Qnil)); kbd_fetch_ptr = event + 1; } +#endif +#if defined (HAVE_X11) || defined (HAVE_NTGUI) else if (event->kind == iconify_event) { /* Make an event (iconify-frame (FRAME)). */ @@ -3503,7 +3509,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu) XSETBUFFER (obj, current_buffer); kbd_fetch_ptr = event + 1; } -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) else if (event->kind == menu_bar_activate_event) { kbd_fetch_ptr = event + 1; @@ -5093,7 +5099,7 @@ make_lispy_event (event) } #endif /* HAVE_MOUSE */ -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) case MENU_BAR_EVENT: if (EQ (event->arg, event->frame_or_window)) /* This is the prefix key. We translate this to diff --git a/src/sysdep.c b/src/sysdep.c index d53b7d93db2..3b336f6bf7f 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -31,21 +31,15 @@ Boston, MA 02111-1307, USA. */ #undef NULL #ifdef macintosh -#ifdef __MRC__ -__sigfun sys_signal (int signal, __sigfun signal_func); -#elif __MWERKS__ -__signal_func_ptr sys_signal (int signal, __signal_func_ptr signal_func); -#else -You lose!!! -#endif +/* It is essential to include stdlib.h so that this file picks up + the correct definitions of rand, srand, and RAND_MAX. + Otherwise random numbers will not work correctly. */ +#include + #ifndef subprocesses /* Nonzero means delete a process right away if it exits (process.c). */ static int delete_exited_processes; #endif -#ifndef HAVE_X_WINDOWS -/* Search path for bitmap files (xfns.c). */ -Lisp_Object Vx_bitmap_file_path; -#endif #endif /* macintosh */ #define min(x,y) ((x) > (y) ? (y) : (x)) @@ -751,12 +745,10 @@ sys_suspend () /* Fork a subshell. */ +#ifndef macintosh void sys_subshell () { -#ifdef macintosh - error ("Can't spawn subshell"); -#else #ifndef VMS #ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */ int st; @@ -873,8 +865,8 @@ sys_subshell () restore_signal_handlers (saved_handlers); synch_process_alive = 0; #endif /* !VMS */ -#endif /* !macintosh */ } +#endif /* !macintosh */ static void save_signal_handlers (saved_handlers) @@ -1285,23 +1277,13 @@ init_sys_modes () struct emacs_tty tty; #ifdef macintosh - Vwindow_system = intern ("mac"); - Vwindow_system_version = make_number (1); - -/* cus-start.el complains if delete-exited-processes and x-bitmap-file-path not defined */ +/* cus-start.el complains if delete-exited-processes is not defined */ #ifndef subprocesses DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes, "*Non-nil means delete processes immediately when they exit.\n\ nil means don't delete them until `list-processes' is run."); delete_exited_processes = 0; #endif - -#ifndef HAVE_X_WINDOWS - DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path, - "List of directories to search for bitmap files for X."); - Vx_bitmap_file_path = decode_env_path ((char *) 0, "."); -#endif - #endif /* not macintosh */ #ifdef VMS @@ -2651,7 +2633,7 @@ read_input_waiting () read_alarm_should_throw = 0; if (! setjmp (read_alarm_throw)) - nread = (*read_socket_hook) (0, buf, 256, 1); + nread = (*read_socket_hook) (0, buf, 256, 1, 0); else nread = -1; @@ -5306,1542 +5288,4 @@ strsignal (code) return signame; } #endif /* HAVE_STRSIGNAL */ - -/* All the Macintosh stuffs go here */ - -#ifdef macintosh - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Convert a Mac pathname to Unix form. A Mac full pathname is one - that does not begin with a ':' and contains at least one ':'. A Mac - full pathname causes an '/' to be prepended to the Unix pathname. - The algorithm for the rest of the pathname is as follows: - For each segment between two ':', - if it is non-null, copy as is and then add a '/' at the end, - otherwise, insert a "../" into the Unix pathname. - Returns 1 if successful; 0 if fails. */ - -int -Mac2UnixPathname (const char *mfn, char *ufn, int ufnbuflen) -{ - const char *p, *q, *pe; - - strcpy (ufn, ""); - - if (*mfn == '\0') - return 1; - - p = strchr (mfn, ':'); - if (p != 0 && p != mfn) /* full pathname */ - strcat (ufn, "/"); - - p = mfn; - if (*p == ':') - p++; - - pe = mfn + strlen (mfn); - while (p < pe) - { - q = strchr (p, ':'); - if (q) - { - if (q == p) - { /* two consecutive ':' */ - if (strlen (ufn) + 3 >= ufnbuflen) - return 0; - strcat (ufn, "../"); - } - else - { - if (strlen (ufn) + (q - p) + 1 >= ufnbuflen) - return 0; - strncat (ufn, p, q - p); - strcat (ufn, "/"); - } - p = q + 1; - } - else - { - if (strlen (ufn) + (pe - p) >= ufnbuflen) - return 0; - strncat (ufn, p, pe - p); /* no separator for last one */ - p = pe; - } - } - - return 1; -} - -extern char *GetTempDirName (); - -/* Convert a Unix pathname to Mac form. Approximately reverse of the - above in algorithm. */ -int -Unix2MacPathname (const char *ufn, char *mfn, int mfnbuflen) -{ - const char *p, *q, *pe; - char expandedPathname[MAXPATHLEN+1]; - - strcpy (mfn, ""); - - if (*ufn == '\0') - return 1; - - p = ufn; - - /* Check for and handle volume names. Last comparison: strangely - somewhere `/.emacs' is passed. A temporary fix for now. */ - if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0) - { - if (strlen (p) + 1 > mfnbuflen) - return 0; - strcpy (mfn, p+1); - strcat (mfn, ":"); - return 1; - } - - if (strncmp (p, "~emacs/", 7) == 0) - { /* expand to emacs dir found by InitEmacsPasswdDir */ - struct passwd *pw = getpwnam ("emacs"); - p += 7; - if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN) - return 0; - strcpy (expandedPathname, pw->pw_dir); - strcat (expandedPathname, p); - p = expandedPathname; - /* Now p points to the pathname with emacs dir prefix. */ - } - else if (strncmp (p, "/tmp/", 5) == 0) - { - char *t = GetTempDirName (); - p += 5; - if (strlen (t) + strlen (p) > MAXPATHLEN) - return 0; - strcpy (expandedPathname, t); - strcat (expandedPathname, p); - p = expandedPathname; - /* Now p points to the pathname with emacs dir prefix. */ - } - else if (*p != '/') /* relative pathname */ - strcat (mfn, ":"); - - if (*p == '/') - p++; - - pe = p + strlen (p); - while (p < pe) - { - q = strchr (p, '/'); - if (q) - { - if (q - p == 2 && *p == '.' && *(p+1) == '.') - { - if (strlen (mfn) + 1 >= mfnbuflen) - return 0; - strcat (mfn, ":"); - } - else - { - if (strlen (mfn) + (q - p) + 1 >= mfnbuflen) - return 0; - strncat (mfn, p, q - p); - strcat (mfn, ":"); - } - p = q + 1; - } - else - { - if (strlen (mfn) + (pe - p) >= mfnbuflen) - return 0; - strncat (mfn, p, pe - p); - p = pe; - } - } - - return 1; -} - -/* The following functions with "sys_" prefix are stubs to Unix - functions that have already been implemented by CW or MPW. The - calls to them in Emacs source course are #define'd to call the sys_ - versions by the header files s-mac.h. In these stubs pathnames are - converted between their Unix and Mac forms. */ -/* Unix Epoch is Jan 1, 1970 while Mac Epoch is Jan 1, 1904: 66 years - + 17 leap days */ -#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60) - -/* CW Epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not a leap - year! */ -#define CW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60) - -/* Define our own stat function for both MrC and CW. The reason for - doing this: "stat" is both the name of a struct and function name: - we can't #define stat to something else to - redirect Emacs's calls to our own version that converts Unix style - filenames to Mac style filename because all sorts of compilation - errors will be generated if stat is #define'd to be something else. */ - -int -stat (const char *path, struct stat *buf) -{ - char MacPathname[MAXPATHLEN+1]; - CInfoPBRec cipb; - - if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0) - return -1; - - c2pstr (MacPathname); - cipb.hFileInfo.ioNamePtr = MacPathname; - cipb.hFileInfo.ioVRefNum = 0; - cipb.hFileInfo.ioDirID = 0; - cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */ - - errno = PBGetCatInfo (&cipb, false); - if (errno == -43) /* -43: fnfErr defined in Errors.h */ - errno = ENOENT; - if (errno != noErr) - return -1; - - if (cipb.hFileInfo.ioFlAttrib & 0x10) - { /* bit 4 = 1 for directories */ - buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC; - if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */ - buf->st_mode |= S_IWRITE; - buf->st_ino = cipb.dirInfo.ioDrDirID; - buf->st_dev = cipb.dirInfo.ioVRefNum; - buf->st_size = cipb.dirInfo.ioDrNmFls; /* size of dir = number of files and dirs */ - buf->st_atime = buf->st_mtime = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF; - buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF; - } - else - { - buf->st_mode = S_IFREG | S_IREAD; - if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */ - buf->st_mode |= S_IWRITE; - if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL') - buf->st_mode |= S_IEXEC; - buf->st_ino = cipb.hFileInfo.ioDirID; - buf->st_dev = cipb.hFileInfo.ioVRefNum; - buf->st_size = cipb.hFileInfo.ioFlLgLen; - buf->st_atime = buf->st_mtime = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF; - buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF; - } - buf->st_nlink = 1; - buf->st_uid = getuid (); - buf->st_gid = getgid (); - buf->st_rdev = 0; - - return 0; -} - -#if __MRC__ - -/* CW defines fstat in stat.mac.c while MPW does not provide this - function. Without the information of how to get from a file - descriptor in MPW StdCLib to a Mac OS file spec, it should be hard - to implement this function. Fortunately, there is only one place - where this function is called in our configuration: in fileio.c, - where only the st_dev and st_ino fields are used to determine - whether two fildes point to different i-nodes to prevent copying - a file onto itself equal. What we have here probably needs - improvement. */ -int -fstat (int fildes, struct stat *buf) -{ - buf->st_dev = 0; - buf->st_ino = fildes; - return 0; /* success */ -} - -#endif /* __MRC__ */ - -/* From Think Reference code example */ -int -mkdir (const char *dirname, int mode) -{ -#pragma unused (mode) - - HFileParam hfpb; - char MacPathname[MAXPATHLEN+1]; - - if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0) - return -1; - - c2pstr (MacPathname); - hfpb.ioNamePtr = MacPathname; - hfpb.ioVRefNum = 0; /*ignored unless name is invalid */ - hfpb.ioDirID = 0; /*parent is the root */ - - /* Just return the Mac OSErr code for now. */ - errno = PBDirCreate ((HParmBlkPtr) &hfpb, false); - return errno == noErr ? 0 : -1; -} - -int -rmdir (const char *dirname) -{ - HFileParam hfpb; - char MacPathname[MAXPATHLEN+1]; - - if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0) - return -1; - - c2pstr (MacPathname); - hfpb.ioNamePtr = MacPathname; - hfpb.ioVRefNum = 0; /*ignored unless name is invalid */ - hfpb.ioDirID = 0; /*parent is the root */ - - errno = PBHDelete ((HParmBlkPtr) &hfpb, false); - return errno == noErr ? 0 : -1; -} - -#ifdef __MRC__ - -/* No implementation yet. */ -int -execvp (const char *path, ...) -{ - return -1; -} - -#endif /* __MRC__ */ - -int -utime (const char *path, const struct utimbuf *times) -{ - char MacPathname[MAXPATHLEN+1]; - CInfoPBRec cipb; - - if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0) - return -1; - - c2pstr (MacPathname); - cipb.hFileInfo.ioNamePtr = MacPathname; - cipb.hFileInfo.ioVRefNum = 0; - cipb.hFileInfo.ioDirID = 0; - /* Set to 0 to get information about specific dir or file. */ - cipb.hFileInfo.ioFDirIndex = 0; - - errno = PBGetCatInfo (&cipb, false); - if (errno != noErr) - return -1; - - if (cipb.hFileInfo.ioFlAttrib & 0x10) - { /* bit 4 = 1 for directories */ - if (times) - cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF; - else - GetDateTime (&cipb.dirInfo.ioDrMdDat); - } - else - { - if (times) - cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF; - else - GetDateTime (&cipb.hFileInfo.ioFlMdDat); - } - - errno = PBSetCatInfo (&cipb, false); - return errno == noErr ? 0 : -1; -} - -#define F_OK 0 -#define X_OK 1 -#define W_OK 2 - -/* Like stat, but test for access mode in hfpb.ioFlAttrib. */ -int -access (const char *path, int mode) -{ - char MacPathname[MAXPATHLEN+1]; - CInfoPBRec cipb; - - if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0) - return -1; - - c2pstr (MacPathname); - cipb.hFileInfo.ioNamePtr = MacPathname; - cipb.hFileInfo.ioVRefNum = 0; - cipb.hFileInfo.ioDirID = 0; - cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */ - - errno = PBGetCatInfo (&cipb, false); - if (errno != noErr) - return -1; - - if (mode == F_OK) /* got this far, file exists */ - return 0; - - if (mode & X_OK) - if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */ - return 0; - else - { - if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL') - return 0; - else - return -1; - } - - if (mode & W_OK) - return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0; /* don't allow if lock bit on */ - - return -1; -} - -#define DEV_NULL_FD 0x10000 - -#undef open -int -sys_open (const char *path, int oflag) -{ - char MacPathname[MAXPATHLEN+1]; - - if (strcmp (path, "/dev/null") == 0) - return DEV_NULL_FD; /* some bogus fd to be ignored in write */ - - if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0) - return -1; - else - return open (MacPathname, oflag); -} - -#undef creat -int -sys_creat (const char *path, mode_t mode) -{ - char MacPathname[MAXPATHLEN+1]; - - if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0) - return -1; - else - return creat (MacPathname, mode); -} - -#undef unlink -int -sys_unlink (const char *path) -{ - char MacPathname[MAXPATHLEN+1]; - - if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0) - return -1; - else - return unlink (MacPathname); -} - -#undef read -int -sys_read (int fildes, char *buf, int count) -{ - if (fildes == 0) - { /* if stdin, call (non-echoing) "getch" in console.h */ - if (MacKeyPending ()) - { /* don't wait for a key if none has been pressed */ - *buf = MacGetChar (); - return 1; - } - else - return 0; - } - else - return read (fildes, buf, count); -} - -#undef write -int -sys_write (int fildes, char *buf, int count) -{ - if (fildes == DEV_NULL_FD) - return count; - else - return write (fildes, buf, count); -} - -#undef rename -int -sys_rename (const char * old_name, const char * new_name) -{ - char MacOldName[MAXPATHLEN+1], MacNewName[MAXPATHLEN+1]; - - if (strcmp (old_name, new_name) == 0) - return 0; - - if (Unix2MacPathname (old_name, MacOldName, MAXPATHLEN+1) == 0) - return 1; - - if (Unix2MacPathname (new_name, MacNewName, MAXPATHLEN+1) == 0) - return 1; - - return rename (MacOldName, MacNewName); -} - -#undef fopen -extern FILE *fopen (const char *name, const char *mode); -FILE -sys_fopen (const char *name, const char *mode) -{ - char MacPathname[MAXPATHLEN+1]; - - if (Unix2MacPathname (name, MacPathname, MAXPATHLEN+1) == 0) - return 0; - else - return fopen (MacPathname, mode); -} - -#include - -long targetTicks = 0; - -#ifdef __MRC__ -__sigfun alarm_signal_func = (__sigfun) 0; -#elif __MWERKS__ -__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0; -#else -You lose!!! -#endif - -/* These functions simulate SIG_ALRM. The stub for function signal - stores the signal handler function in alarm_signal_func if a - SIG_ALRM is encountered. CheckAlarm is called in mac_read_socket, - which emacs calls periodically. A pending alarm is represented by - a non-zero targetTicks value. CheckAlarm calls the handler - function pointed to by alarm_signal_func if one has been set up and - an alarm is pending. */ -void -CheckAlarm () -{ - if (targetTicks && TickCount () > targetTicks) - { - targetTicks = 0; - if (alarm_signal_func) - (*alarm_signal_func)(SIGALRM); - } -} - -/* Called in sys_select to wait for an alarm signal to arrive. */ -int -pause () -{ - unsigned long finalTick; - - if (!targetTicks) /* no alarm pending */ - return -1; - - while (TickCount () <= targetTicks) - Delay (1UL, &finalTick); /* wait for 1/60 second before trying again */ - - targetTicks = 0; - if (alarm_signal_func) - (*alarm_signal_func)(SIGALRM); - - return 0; -} - -int -alarm (int seconds) -{ - long remaining = targetTicks ? (TickCount () - targetTicks) / 60 : 0; - - targetTicks = seconds ? TickCount () + 60 * seconds : 0; - - return (remaining < 0) ? 0 : (unsigned int) remaining; -} - -#undef signal -#ifdef __MRC__ -extern __sigfun signal (int signal, __sigfun signal_func); -__sigfun -sys_signal (int signal_num, __sigfun signal_func) -#elif __MWERKS__ -extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func); -__signal_func_ptr -sys_signal (int signal_num, __signal_func_ptr signal_func) -#else - You lose!!! -#endif -{ - if (signal_num != SIGALRM) - return signal (signal_num, signal_func); - else - { -#ifdef __MRC__ - __sigfun old_signal_func; -#elif __MWERKS__ - __signal_func_ptr old_signal_func; -#else - You lose!!! -#endif - old_signal_func = alarm_signal_func; - alarm_signal_func = signal_func; - return old_signal_func; - } -} - -/* The time functions adjust time values according to the difference - between the Unix and CW epoches. */ - -#undef gmtime -extern struct tm *gmtime (const time_t *); -struct tm -sys_gmtime (const time_t *timer) -{ - time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF; - - return gmtime (&unixTime); -} - -#undef localtime -extern struct tm *localtime (const time_t *); -struct tm * -sys_localtime (const time_t *timer) -{ - time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF; - - return localtime (&unixTime); -} - -#undef ctime -extern char *ctime (const time_t *); -char * -sys_ctime (const time_t *timer) -{ - time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF; - - return ctime (&unixTime); -} - -#undef time -extern time_t time (time_t *); -time_t -sys_time (time_t *timer) -{ - time_t macTime = time (NULL) - CW_UNIX_EPOCH_DIFF; - - if (timer) - *timer = macTime; - - return macTime; -} - -/* no subprocesses, empty wait */ -int -wait (int pid) -{ - return 0; -} - -void -croak (char *badfunc) -{ - printf ("%s not yet implemented\r\n", badfunc); - exit (1); -} - -char * -index (const char * str, int chr) -{ - return strchr (str, chr); -} - -char *e[] = { 0 }; -char **environ = &e[0]; - -char * -mktemp (char *template) -{ - int len, k; - static seqnum = 0; - - len = strlen (template); - k = len - 1; - while (k >= 0 && template[k] == 'X') - k--; - - k++; /* make k index of first 'X' */ - - if (k < len) - { - /* Zero filled, number of digits equal to the number of X's. */ - sprintf (&template[k], "%0*d", len-k, seqnum++); - - return template; - } - else - return 0; -} - -/* Emulate getpwuid, getpwnam and others. */ - -#define PASSWD_FIELD_SIZE 256 - -static char myPasswdName[PASSWD_FIELD_SIZE]; -static char myPasswdDir[MAXPATHLEN+1]; - -static struct passwd myPasswd = -{ - myPasswdName, - myPasswdDir, -}; - -/* Initialized by main () in macterm.c to pathname of emacs directory. */ -char emacsPasswdDir[MAXPATHLEN+1]; - -void -InitEmacsPasswdDir () -{ - int found = false; - - if (getwd (emacsPasswdDir) && getwd (myPasswdDir)) - { - /* Need pathname of first ancestor that begins with `emacs' since - Mac emacs application is somewhere in the emacs-20.3 tree. */ - int len = strlen (emacsPasswdDir); - /* J points to the "/" following the directory name being compared. */ - int j = len - 1; - int i = j - 1; - while (i >= 0 && !found) - { - while (i >= 0 && emacsPasswdDir[i] != '/') - i--; - if (emacsPasswdDir[i] == '/' && i+5 < len) - found = (strncmp (&(emacsPasswdDir[i+1]), "emacs", 5) == 0); - if (found) - emacsPasswdDir[j+1] = '\0'; - else - { - j = i; - i = j - 1; - } - } - } - - if (!found) - { /* setting to "/" probably won't work, - but set it to something anyway. */ - strcpy (emacsPasswdDir, "/"); - strcpy (myPasswdDir, "/"); - } -} - -static struct passwd emacsPasswd = -{ - "emacs", - emacsPasswdDir, -}; - -static int myPasswdInited = 0; - -static void -InitMyPasswd () -{ - char **ownerName; - - /* Note: myPasswdDir initialized in InitEmacsPasswdDir to directory - where Emacs was started. */ - - ownerName = (char **) GetResource ('STR ',-16096); - if (ownerName) - { - HLock (ownerName); - BlockMove ((unsigned char *) *ownerName, - (unsigned char *) myPasswdName, *ownerName[0] + 1); - HUnlock (ownerName); - p2cstr ((unsigned char *) myPasswdName); - } - else - myPasswdName[0] = 0; -} - -struct passwd * -getpwuid (uid_t uid) -{ - if (!myPasswdInited) - { - InitMyPasswd (); - myPasswdInited = 1; - } - - return &myPasswd; -} - -struct passwd * -getpwnam (const char *name) -{ - if (strcmp (name, "emacs") == 0) - return &emacsPasswd; - - if (!myPasswdInited) - { - InitMyPasswd (); - myPasswdInited = 1; - } - - return &myPasswd; -} - -/* The functions fork, kill, sigsetmask, sigblock, request_sigio, - setpgrp, setpriority, and unrequest_sigio are defined to be empty - as in msdos.c. */ - -int -fork () -{ - return -1; -} - -int -kill (int x, int y) -{ - return -1; -} - -int -sigsetmask (int x) -{ - return 0; -} - -int -sigblock (int mask) -{ - return 0; -} - -void -request_sigio (void) -{ -} - -int -setpgrp () -{ - return 0; -} - -void -unrequest_sigio (void) -{ -} - -/* djgpp does not implement pipe either. */ -int -pipe (int _fildes[2]) -{ - errno = EACCES; - return -1; -} - -/* Hard and symbolic links. */ -int -symlink (const char *name1, const char *name2) -{ - errno = ENOENT; - return -1; -} - -int -link (const char *name1, const char *name2) -{ - errno = ENOENT; - return -1; -} - -int -lstat (const char *path, struct stat *sb) -{ - return stat (path, sb); -} - -int -readlink (const char *path, char *buf, int bufsiz) -{ - errno = ENOENT; - return -1; -} - -mode_t -umask (mode_t numask) -{ - static mode_t mask = 022; - mode_t oldmask = mask; - mask = numask; - return oldmask; -} - -int -chmod (const char *path, mode_t mode) -{ - /* say it always succeed for now */ - return 0; -} - -int -dup (int oldd) -{ -#ifdef __MRC__ - return fcntl (oldd, F_DUPFD, 0); -#elif __MWERKS__ - /* current implementation of fcntl in fcntl.mac.c simply returns old - descriptor */ - return fcntl (oldd, F_DUPFD); -#else -You lose!!! -#endif -} - -/* This is from the original sysdep.c. Emulate BSD dup2. First close - newd if it already exists. Then, attempt to dup oldd. If not - successful, call dup2 recursively until we are, then close the - unsuccessful ones. */ -int -dup2 (int oldd, int newd) -{ - int fd, ret; - - close (newd); - - fd = dup (oldd); - if (fd == -1) - return -1; - if (fd == newd) - return newd; - ret = dup2 (oldd, newd); - close (fd); - return ret; -} - -/* let it fail for now */ -char * -sbrk (int incr) -{ - return (char *) -1; -} - -int -fsync (int fd) -{ - return 0; -} - -int -ioctl (int d, int request, void *argp) -{ - return -1; -} - -#ifdef __MRC__ -int -isatty (int fildes) -{ - if (fildes >=0 && fildes <= 2) - return 1; - else - return 0; -} - -int -getgid () -{ - return 100; -} - -int -getegid () -{ - return 100; -} - -int -getuid () -{ - return 200; -} - -int -geteuid () -{ - return 200; -} - -unsigned int -sleep (unsigned int seconds) -{ - unsigned long finalTick; - - Delay (seconds * 60UL, &finalTick); - return (0); -} -#endif /* __MRC__ */ - -#ifdef __MWERKS__ -#undef getpid -int -getpid () -{ - return 9999; -} -#endif /* __MWERKS__ */ - -/* Return the path to the directory in which Emacs can create - temporary files. The MacOS "temporary items" directory cannot be - used because it removes the file written by a process when it - exits. In that sense it's more like "/dev/null" than "/tmp" (but - again not exactly). And of course Emacs needs to read back the - files written by its subprocesses. So here we write the files to a - directory "Emacs" in the Preferences Folder. This directory is - created if it does not exist. */ -static char * -GetTempDirName () -{ - static char *TempDirName = NULL; - short vRefNum; - long dirID; - OSErr err; - Str255 dirName, fullPath; - CInfoPBRec cpb; - char unixDirName[MAXPATHLEN+1]; - DIR *dir; - - /* Cache directory name with pointer TempDirName. - Look for it only the first time. */ - if (!TempDirName) - { - err = FindFolder (kOnSystemDisk, kPreferencesFolderType, - kCreateFolder, &vRefNum, &dirID); - if (err != noErr) - return NULL; - - *fullPath = '\0'; - cpb.dirInfo.ioNamePtr = dirName; - cpb.dirInfo.ioDrParID = dirID; - - /* Standard ref num to full path name loop */ - do { - cpb.dirInfo.ioVRefNum = vRefNum; - cpb.dirInfo.ioFDirIndex = -1; - cpb.dirInfo.ioDrDirID = cpb.dirInfo.ioDrParID; - - err = PBGetCatInfo (&cpb, false); - - p2cstr (dirName); - strcat (dirName, ":"); - if (strlen (fullPath) + strlen (dirName) <= MAXPATHLEN) - { - strcat (dirName, fullPath); - strcpy (fullPath, dirName); - } - else - return NULL; - } - while (cpb.dirInfo.ioDrDirID != fsRtDirID && err == noErr); - - if (strlen (fullPath) + 6 <= MAXPATHLEN) - strcat (fullPath, "Emacs:"); - else - return NULL; - - if (Mac2UnixPathname (fullPath, unixDirName, MAXPATHLEN+1) == 0) - return NULL; - - dir = opendir (unixDirName); /* check whether temp directory exists */ - if (dir) - closedir (dir); - else if (mkdir (unixDirName, 0700) != 0) /* create it if not */ - return NULL; - - TempDirName = (char *) xmalloc (strlen (unixDirName) + 1); - strcpy (TempDirName, unixDirName); - } - - return TempDirName; -} - -char * -getenv (const char * name) -{ - if (strcmp (name, "TERM") == 0) - return "vt100"; - else if (strcmp (name, "TERMCAP") == 0) - /* for debugging purpose when code was still outputting to dumb terminal */ - return "d0|vt100|vt100-am|vt100am|dec vt100:do=[do]:co#100:li#32:cl=[cl]:sf=[sf]:km:\ -:le=[le]:bs:am:cm=[cm-%d,%d]:nd=[nd]:up=[up]:ce=[ce]:cd=[cd]:so=[so]:se=[se]:\ -:us=[us]:ue=[ue]:md=[md]:mr=[mr]:mb=[mb]:me=[me]:is=[is]:\ -:rf=/usr/share/lib/tabset/vt100:rs=[rs]:ks=[ks]:ke=[ke]:\ -:ku=\\036:kd=\\037:kr=\\035:kl=\\034:kb=[kb]:ho=[ho]:k1=[k1]:k2=[k2]:k3=[k3]:k4=[k4]:\ -:pt:sr=[sr]:vt#3:xn:sc=[sc]:rc=[rc]:cs=[cs-%d,%d]"; - else if (strcmp (name, "TMPDIR") == 0) - return GetTempDirName (); - else - return (NULL); -} - -#ifdef __MRC__ -#include - -int -uname (struct utsname *name) -{ - char **systemName; - systemName = GetString (-16413); /* IM - Resource Manager Reference */ - if (systemName) - { - BlockMove (*systemName, name->nodename, (*systemName)[0]+1); - p2cstr (name->nodename); - } - else - return -1; -} -#endif - -#include -#include - -/* Event class of HLE sent to subprocess. */ -const OSType kEmacsSubprocessSend = 'ESND'; -/* Event class of HLE sent back from subprocess. */ -const OSType kEmacsSubprocessReply = 'ERPY'; - -char * -mystrchr (char *s, char c) -{ - while (*s && *s != c) - { - if (*s == '\\') - s++; - s++; - } - - if (*s) - { - *s = '\0'; - return s; - } - else - return NULL; -} - -char * -mystrtok (char *s) -{ - while (*s) - s++; - - return s + 1; -} - -void -mystrcpy (char *to, char *from) -{ - while (*from) - { - if (*from == '\\') - from++; - *to++ = *from++; - } - *to = '\0'; -} - -/* Start a Mac subprocess. Arguments for it is passed in argv (null - terminated). The process should run with the default directory - "workdir", read input from "infn", and write output and error to - "outfn" and "errfn", resp. The Process Manager call - LaunchApplication is used to start the subprocess. We use high - level events as the mechanism to pass arguments to the subprocess - and to make Emacs wait for the subprocess to terminate and pass - back a result code. The bulk of the code here packs the arguments - into one message to be passed together with the high level event. - Emacs also sometimes starts a subprocess using a shell to perform - wildcard filename expansion. Since we don't really have a shell on - the Mac, this case is detected and the starting of the shell is - by-passed. We really need to add code here to do filename - expansion to support such functionality. */ -int -run_mac_command (argv, workdir, infn, outfn, errfn) - unsigned char **argv; - const char *workdir; - const char *infn, *outfn, errfn; -{ - char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1]; - char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1]; - int paramlen, argc, newargc, j, retries; - char **newargv, *param, *p; - OSErr iErr; - FSSpec spec; - LaunchParamBlockRec lpbr; - EventRecord sendEvent, replyEvent; - RgnHandle cursorRegionHdl; - TargetID targ; - unsigned long refCon, len; - - if (Unix2MacPathname (workdir, macworkdir, MAXPATHLEN+1) == 0) - return -1; - if (Unix2MacPathname (infn, macinfn, MAXPATHLEN+1) == 0) - return -1; - if (Unix2MacPathname (outfn, macoutfn, MAXPATHLEN+1) == 0) - return -1; - if (Unix2MacPathname (errfn, macerrfn, MAXPATHLEN+1) == 0) - return -1; - - paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn) + strlen (macerrfn) + 4; - /* count nulls at end of strings */ - - argc = 0; - while (argv[argc]) - argc++; - - if (argc == 0) - return -1; - - /* If a subprocess is invoked with a shell, we receive 3 arguments of the form: - "/sh" "-c" "/ " */ - j = strlen (argv[0]); - if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0 && argc == 3 && strcmp (argv[1], "-c") == 0) - { - char *command, *t, tempmacpathname[MAXPATHLEN+1]; - - /* The arguments for the command in argv[2] are separated by - spaces. Count them and put the count in newargc. */ - command = (char *) alloca (strlen (argv[2])+2); - strcpy (command, argv[2]); - if (command[strlen (command) - 1] != ' ') - strcat (command, " "); - - t = command; - newargc = 0; - t = mystrchr (t, ' '); - while (t) - { - newargc++; - t = mystrchr (t+1, ' '); - } - - newargv = (char **) alloca (sizeof (char *) * newargc); - - t = command; - for (j = 0; j < newargc; j++) - { - newargv[j] = (char *) alloca (strlen (t) + 1); - mystrcpy (newargv[j], t); - - t = mystrtok (t); - paramlen += strlen (newargv[j]) + 1; - } - - if (strncmp (newargv[0], "~emacs/", 7) == 0) - { - if (Unix2MacPathname (newargv[0], tempmacpathname, MAXPATHLEN+1) == 0) - return -1; - } - else - { /* sometimes Emacs call "sh" without a path for the command */ -#if 0 - char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1); - strcpy (t, "~emacs/"); - strcat (t, newargv[0]); -#endif - Lisp_Object path; - openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, 1); - - if (NILP (path)) - return -1; - if (Unix2MacPathname (XSTRING (path)->data, tempmacpathname, MAXPATHLEN+1) == 0) - return -1; - } - strcpy (macappname, tempmacpathname); - } - else - { - if (Unix2MacPathname (argv[0], macappname, MAXPATHLEN+1) == 0) - return -1; - - newargv = (char **) alloca (sizeof (char *) * argc); - newargc = argc; - for (j = 1; j < argc; j++) - { - if (strncmp (argv[j], "~emacs/", 7) == 0) - { - char *t = strchr (argv[j], ' '); - if (t) - { - char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1]; - strncpy (tempcmdname, argv[j], t-argv[j]); - tempcmdname[t-argv[j]] = '\0'; - if (Unix2MacPathname (tempcmdname, tempmaccmdname, MAXPATHLEN+1) == 0) - return -1; - newargv[j] = (char *) alloca (strlen (tempmaccmdname) + strlen (t) + 1); - strcpy (newargv[j], tempmaccmdname); - strcat (newargv[j], t); - } - else - { - char tempmaccmdname[MAXPATHLEN+1]; - if (Unix2MacPathname (argv[j], tempmaccmdname, MAXPATHLEN+1) == 0) - return -1; - newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1); - strcpy (newargv[j], tempmaccmdname); - } - } - else - newargv[j] = argv[j]; - paramlen += strlen (newargv[j]) + 1; - } - } - - /* After expanding all the arguments, we now know the length of the parameter block to be - sent to the subprocess as a message attached to the HLE. */ - param = (char *) xmalloc (paramlen + 1); - if (!param) - return -1; - - p = param; - *p++ = newargc; /* first byte of message contains number of arguments for command */ - strcpy (p, macworkdir); - p += strlen (macworkdir); - *p++ = '\0'; /* null terminate strings sent so it's possible to use strcpy over there */ - strcpy (p, macinfn); - p += strlen (macinfn); - *p++ = '\0'; - strcpy (p, macoutfn); - p += strlen (macoutfn); - *p++ = '\0'; - strcpy (p, macerrfn); - p += strlen (macerrfn); - *p++ = '\0'; - for (j = 1; j < newargc; j++) { - strcpy (p, newargv[j]); - p += strlen (newargv[j]); - *p++ = '\0'; - } - - c2pstr (macappname); - - iErr = FSMakeFSSpec (0, 0, macappname, &spec); - - if (iErr != noErr) { - xfree (param); - return -1; - } - - lpbr.launchBlockID = extendedBlock; - lpbr.launchEPBLength = extendedBlockLen; - lpbr.launchControlFlags = launchContinue + launchNoFileFlags; - lpbr.launchAppSpec = &spec; - lpbr.launchAppParameters = NULL; - - iErr = LaunchApplication (&lpbr); /* call the subprocess */ - if (iErr != noErr) - { - xfree (param); - return -1; - } - - sendEvent.what = kHighLevelEvent; - sendEvent.message = kEmacsSubprocessSend; /* Event ID stored in "where" unused */ - - retries = 3; - do { /* OS may think current subprocess has terminated if previous one terminated recently */ - iErr = PostHighLevelEvent (&sendEvent, &lpbr.launchProcessSN, 0, param, paramlen + 1, receiverIDisPSN); - } - while (iErr == sessClosedErr && retries-- > 0); - - if (iErr != noErr) { - xfree (param); - return -1; - } - - cursorRegionHdl = NewRgn (); - - /* Wait for the subprocess to finish, when it will send us a ERPY high level event */ - while (1) - if (WaitNextEvent (highLevelEventMask, &replyEvent, 180, cursorRegionHdl) && replyEvent.message == kEmacsSubprocessReply) - break; - - /* The return code is sent through the refCon */ - iErr = AcceptHighLevelEvent (&targ, &refCon, NULL, &len); - if (iErr != noErr) { - DisposeHandle ((Handle) cursorRegionHdl); - xfree (param); - return -1; - } - - DisposeHandle ((Handle) cursorRegionHdl); - xfree (param); - - return refCon; -} - -DIR * -opendir (const char *dirname) -{ - char MacPathname[MAXPATHLEN+1]; - DIR *dirp; - CInfoPBRec cipb; - int len; - - dirp = (DIR *) xmalloc (sizeof (DIR)); - if (!dirp) - return 0; - - /* Handle special case when dirname is "/": sets up for readir to - get all mount volumes. */ - if (strcmp (dirname, "/") == 0) { - dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */ - dirp->current_index = 1; /* index for first volume */ - return dirp; - } - - /* Handle typical cases: not accessing all mounted volumes. */ - if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0) - return 0; - - /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */ - len = strlen (MacPathname); - if (MacPathname[len - 1] != ':' && len < MAXPATHLEN) - strcat (MacPathname, ":"); - - c2pstr (MacPathname); - cipb.hFileInfo.ioNamePtr = MacPathname; /* using full pathname so vRefNum and dirID ignored */ - cipb.hFileInfo.ioVRefNum = 0; - cipb.hFileInfo.ioDirID = 0; - cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */ - - errno = PBGetCatInfo (&cipb, false); - if (errno != noErr) { - errno = ENOENT; - return 0; - } - - if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */ - return 0; /* not a directory */ - - dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */ - dirp->getting_volumes = 0; - dirp->current_index = 1; /* index for first file/directory */ - - return dirp; -} - -int -closedir (DIR *dp) -{ - xfree (dp); - return 0; -} - -struct dirent * -readdir (DIR *dp) -{ - HParamBlockRec HPBlock; - CInfoPBRec cipb; - static struct dirent s_dirent; - static Str255 s_name; - int done; - - /* Handle the root directory containing the mounted volumes. Call - PBHGetVInfo specifying an index to obtain the info for a volume. - PBHGetVInfo returns an error when it receives an index beyond the - last volume, at which time we should return a nil dirent struct - pointer. */ - if (dp->getting_volumes) { - HPBlock.volumeParam.ioNamePtr = s_name; - HPBlock.volumeParam.ioVRefNum = 0; - HPBlock.volumeParam.ioVolIndex = dp->current_index; - - errno = PBHGetVInfo (&HPBlock, false); - if (errno != noErr) { - errno = ENOENT; - return 0; - } - - p2cstr (s_name); - strcat (s_name, "/"); /* need "/" for stat to work correctly */ - - dp->current_index++; - - s_dirent.d_ino = cipb.dirInfo.ioDrDirID; - s_dirent.d_name = s_name; - - return &s_dirent; - } - else { - cipb.hFileInfo.ioVRefNum = 0; - cipb.hFileInfo.ioNamePtr = s_name; /* location to receive filename returned */ - - /* return only visible files */ - done = false; - while (!done) { - cipb.hFileInfo.ioDirID = dp->dir_id; /* directory ID found by opendir */ - cipb.hFileInfo.ioFDirIndex = dp->current_index; - - errno = PBGetCatInfo (&cipb, false); - if (errno != noErr) { - errno = ENOENT; - return 0; - } - - /* insist on an visibile entry */ - if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */ - done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible); - else - done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible); - - dp->current_index++; - } - - p2cstr (s_name); - - s_dirent.d_ino = cipb.dirInfo.ioDrDirID; /* value unimportant: non-zero for valid file */ - s_dirent.d_name = s_name; - - return &s_dirent; - } -} - -char * -getwd (char *path) -{ - char MacPathname[MAXPATHLEN+1]; - Str255 directoryName; - OSErr errno; - CInfoPBRec cipb; - - MacPathname[0] = '\0'; - directoryName[0] = '\0'; - cipb.dirInfo.ioDrParID = 0; - cipb.dirInfo.ioNamePtr = directoryName; /* empty string = default directory */ - - do { - cipb.dirInfo.ioVRefNum = 0; - cipb.dirInfo.ioFDirIndex = -1; - cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID; /* go up to parent each time */ - - errno = PBGetCatInfo (&cipb, false); - if (errno != noErr) { - errno = ENOENT; - return 0; - } - - p2cstr (directoryName); - strcat (directoryName, ":"); - strcat (directoryName, MacPathname); /* attach to front since going up directory tree */ - strcpy (MacPathname, directoryName); - } while (cipb.dirInfo.ioDrDirID != fsRtDirID); /* until volume's root directory */ - - if (Mac2UnixPathname (MacPathname, path, MAXPATHLEN+1) == 0) - return 0; - else - return path; -} -#endif /* macintosh */ diff --git a/src/term.c b/src/term.c index e704f0db0bb..c33d0553a1a 100644 --- a/src/term.c +++ b/src/term.c @@ -51,6 +51,9 @@ extern int tgetnum P_ ((char *id)); #ifdef HAVE_X_WINDOWS #include "xterm.h" #endif +#ifdef macintosh +#include "macterm.h" +#endif static void turn_on_face P_ ((struct frame *, int face_id)); static void turn_off_face P_ ((struct frame *, int face_id)); diff --git a/src/window.c b/src/window.c index 215ceea847f..ee7a10f9806 100644 --- a/src/window.c +++ b/src/window.c @@ -42,6 +42,9 @@ Boston, MA 02111-1307, USA. */ #ifdef MSDOS #include "msdos.h" #endif +#ifdef macintosh +#include "macterm.h" +#endif #ifndef max #define max(a, b) ((a) < (b) ? (b) : (a)) diff --git a/src/xdisp.c b/src/xdisp.c index 12574dd5d07..97791fb5e21 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -194,13 +194,16 @@ Boston, MA 02111-1307, USA. */ #ifdef WINDOWSNT #include "w32term.h" #endif +#ifdef macintosh +#include "macterm.h" +#endif #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #define INFINITY 10000000 -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) extern void set_frame_menubar P_ ((struct frame *f, int, int)); extern int pending_menu_activation; #endif @@ -767,7 +770,7 @@ window_text_bottom_y (w) { struct frame *f = XFRAME (w->frame); int height = XFASTINT (w->height) * CANON_Y_UNIT (f); - + if (WINDOW_WANTS_MODELINE_P (w)) height -= CURRENT_MODE_LINE_HEIGHT (w); return height; @@ -6392,6 +6395,8 @@ echo_area_display (update_frame_p) if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p) return 0; +/* The terminal frame is used as the first Emacs frame on the Mac OS. */ +#ifndef macintosh #ifdef HAVE_WINDOW_SYSTEM /* When Emacs starts, selected_frame may be a visible terminal frame, even if we run under a window system. If we let this @@ -6400,6 +6405,7 @@ echo_area_display (update_frame_p) && !NILP (Vwindow_system)) return 0; #endif /* HAVE_WINDOW_SYSTEM */ +#endif /* Redraw garbaged frames. */ if (frame_garbaged) @@ -6732,7 +6738,7 @@ update_menu_bar (f, save_match_data) if (FRAME_WINDOW_P (f) ? -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) FRAME_EXTERNAL_MENU_BAR (f) #else FRAME_MENU_BAR_LINES (f) > 0 @@ -6779,8 +6785,14 @@ update_menu_bar (f, save_match_data) FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); /* Redisplay the menu bar in case we changed it. */ -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) - if (FRAME_WINDOW_P (f)) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) + if (FRAME_WINDOW_P (f) +#if defined (macintosh) + /* All frames on Mac OS share the same menubar. So only the + selected frame should be allowed to set it. */ + && f == SELECTED_FRAME () +#endif + ) set_frame_menubar (f, 0, 0); else /* On a terminal screen, the menu bar is an ordinary screen @@ -9666,7 +9678,7 @@ redisplay_window (window, just_this_one_p) if (FRAME_WINDOW_P (f)) { -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh) redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f); #else redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0; @@ -12113,6 +12125,10 @@ display_menu_bar (w) if (FRAME_X_P (f)) return; #endif +#ifdef macintosh + if (FRAME_MAC_P (f)) + return; +#endif #ifdef USE_X_TOOLKIT xassert (!FRAME_WINDOW_P (f)); diff --git a/src/xfaces.c b/src/xfaces.c index f12ec242e7f..b0c5dc01258 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -218,6 +218,33 @@ Boston, MA 02111-1307, USA. */ #define FONT_WIDTH FONT_MAX_WIDTH #endif /* WINDOWSNT */ +#ifdef macintosh +#include "macterm.h" +#define x_display_info mac_display_info +#define check_x check_mac + +extern XGCValues *XCreateGC (void *, WindowPtr, unsigned long, XGCValues *); + +static INLINE GC +x_create_gc (f, mask, xgcv) + struct frame *f; + unsigned long mask; + XGCValues *xgcv; +{ + GC gc; + gc = XCreateGC (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), mask, xgcv); + return gc; +} + +static INLINE void +x_free_gc (f, gc) + struct frame *f; + GC gc; +{ + XFreeGC (FRAME_MAC_DISPLAY (f), gc); +} +#endif + #include "buffer.h" #include "dispextern.h" #include "blockinput.h" @@ -1304,7 +1331,6 @@ defined_color (f, color_name, color_def, alloc) #endif #ifdef macintosh else if (FRAME_MAC_P (f)) - /* FIXME: mac_defined_color doesn't exist! */ return mac_defined_color (f, color_name, color_def, alloc); #endif else @@ -1800,8 +1826,11 @@ static struct frame *font_frame; font height, then for weight, then for slant.' This variable can be set via set-face-font-sort-order. */ +#ifdef macintosh +static int font_sort_order[4] = { XLFD_SWIDTH, XLFD_POINT_SIZE, XLFD_WEIGHT, XLFD_SLANT }; +#else static int font_sort_order[4]; - +#endif /* Look up FONT.fields[FIELD_INDEX] in TABLE which has DIM entries. TABLE must be sorted by TABLE[i]->name in ascending order. Value @@ -2242,7 +2271,7 @@ x_face_list_fonts (f, pattern, fonts, nfonts, try_alternatives_p, names = XListFonts (dpy, pattern, nfonts, &n); UNBLOCK_INPUT; #endif /* HAVE_X_WINDOWS */ -#ifdef WINDOWSNT +#if defined (WINDOWSNT) || defined (macintosh) /* NTEMACS_TODO : currently this uses w32_list_fonts, but it may be better to do it the other way around. */ Lisp_Object lfonts; @@ -2255,7 +2284,11 @@ x_face_list_fonts (f, pattern, fonts, nfonts, try_alternatives_p, /* Get the list of fonts matching PATTERN. */ BLOCK_INPUT; +#ifdef WINDOWSNT lfonts = w32_list_fonts (f, lpattern, 0, nfonts); +#else /* macintosh */ + lfonts = x_list_fonts (f, lpattern, 0, nfonts); +#endif UNBLOCK_INPUT; /* Count fonts returned */ @@ -2273,7 +2306,7 @@ x_face_list_fonts (f, pattern, fonts, nfonts, try_alternatives_p, names[i] = XSTRING (XCAR (tem))->data; tem = XCDR (tem); } -#endif /* WINDOWSNT */ +#endif /* defined (WINDOWSNT) || defined (macintosh) */ if (names) { @@ -4121,6 +4154,7 @@ DEFUN ("internal-face-x-get-resource", Finternal_face_x_get_resource, { Lisp_Object value = Qnil; #ifndef WINDOWSNT +#ifndef macintosh CHECK_STRING (resource, 0); CHECK_STRING (class, 1); CHECK_LIVE_FRAME (frame, 2); @@ -4128,6 +4162,7 @@ DEFUN ("internal-face-x-get-resource", Finternal_face_x_get_resource, value = display_x_get_resource (FRAME_X_DISPLAY_INFO (XFRAME (frame)), resource, class, Qnil, Qnil); UNBLOCK_INPUT; +#endif /* not macintosh */ #endif /* not WINDOWSNT */ return value; } @@ -4872,6 +4907,9 @@ prepare_face_for_display (f, face) #endif #ifdef WINDOWSNT xgcv.font = face->font; +#endif +#ifdef macintosh + xgcv.font = face->font; #endif mask |= GCFont; } @@ -6181,6 +6219,18 @@ realize_x_face (cache, attrs, c, base_face) fontset = default_face->fontset; face->fontset = make_fontset_for_ascii_face (f, fontset); face->font = NULL; /* to force realize_face to load font */ + +#ifdef macintosh + /* Load the font if it is specified in ATTRS. This fixes + changing frame font on the Mac. */ + if (STRINGP (attrs[LFACE_FONT_INDEX])) + { + struct font_info *font_info = + FS_LOAD_FONT (f, 0, XSTRING (attrs[LFACE_FONT_INDEX])->data, -1); + if (font_info) + face->font = font_info->font; + } +#endif } /* Load colors, and set remaining attributes. */ @@ -7037,7 +7087,7 @@ A value of nil means don't allow any scalable fonts.\n\ A value of t means allow any scalable font.\n\ Otherwise, value must be a list of regular expressions. A font may be\n\ scaled if its name matches a regular expression in the list."); -#ifdef WINDOWSNT +#if defined (WINDOWSNT) || defined (macintosh) /* Windows uses mainly truetype fonts, so disallowing scalable fonts by default limits the fonts available severely. */ Vscalable_fonts_allowed = Qt;