]> code.delx.au - gnu-emacs/blobdiff - src/macfns.c
*** empty log message ***
[gnu-emacs] / src / macfns.c
index 18697c59a491ff7250e39cfdb227ff6c745479ad..88f975a65c88f6cf9ab972a3302b3c34acd0edec 100644 (file)
@@ -1,5 +1,5 @@
 /* Graphical user interface functions for Mac OS.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -42,7 +42,6 @@ Boston, MA 02111-1307, USA.  */
 #include "epaths.h"
 #include "termhooks.h"
 #include "coding.h"
-#include "ccl.h"
 #include "systime.h"
 
 /* #include "bitmaps/gray.xbm" */
@@ -59,17 +58,6 @@ static unsigned char gray_bits[] = {
 
 #include <stdlib.h>
 #include <string.h>
-#ifndef MAC_OSX
-#include <alloca.h>
-#endif
-
-#ifdef MAC_OSX
-#include <QuickTime/QuickTime.h>
-#else /* not MAC_OSX */
-#include <Windows.h>
-#include <Gestalt.h>
-#include <TextUtils.h>
-#endif /* not MAC_OSX */
 
 /*extern void free_frame_menubar ();
 extern double atof ();
@@ -172,21 +160,6 @@ extern Lisp_Object Vwindow_system_version;
 
 extern int mac_initialized;
 
-/* Functions in macterm.c.  */
-extern void x_set_window_size (struct frame *, int, int, int);
-extern void x_make_frame_visible (struct frame *);
-extern struct mac_display_info *mac_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 *);
-extern void mac_initialize ();
-extern Pixmap XCreatePixmap (Display *, WindowPtr, unsigned int, unsigned int, unsigned int);
-extern Pixmap XCreatePixmapFromBitmapData (Display *, WindowPtr, char *, unsigned int, unsigned int, unsigned long, unsigned long, unsigned int);
-extern void XFreePixmap (Display *, Pixmap);
-extern void XSetForeground (Display *, GC, unsigned long);
-extern void mac_draw_line_to_pixmap (Display *, Pixmap, GC, int, int, int, int);
-
 
 /* compare two strings ignoring case */
 
@@ -339,6 +312,9 @@ static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
                                                             Lisp_Object,
                                                             char *, char *,
                                                             int));
+
+extern void mac_get_window_bounds P_ ((struct frame *, Rect *, Rect *));
+
 /* 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.  */
@@ -348,31 +324,15 @@ x_real_positions (f, xptr, yptr)
      FRAME_PTR f;
      int *xptr, *yptr;
 {
-  Point pt;
-  GrafPtr oldport;
+  Rect inner, outer;
 
-#ifdef TARGET_API_MAC_CARBON
-  {
-    Rect r;
+  mac_get_window_bounds (f, &inner, &outer);
 
-    GetWindowPortBounds (f->output_data.mac->mWP, &r);
-    SetPt (&pt, r.left, r.top);
-  }
-#else /* not TARGET_API_MAC_CARBON */
-  SetPt (&pt,
-        f->output_data.mac->mWP->portRect.left,
-        f->output_data.mac->mWP->portRect.top);
-#endif /* not TARGET_API_MAC_CARBON */
-  GetPort (&oldport);
-  LocalToGlobal (&pt);
-  SetPort (oldport);
-
-  /* MAC has no frame pixel diff.  */
-  f->x_pixels_diff = 0;
-  f->y_pixels_diff = 0;
-
-  *xptr = pt.h;
-  *yptr = pt.v;
+  f->x_pixels_diff = inner.left - outer.left;
+  f->y_pixels_diff = inner.top - outer.top;
+
+  *xptr = outer.left;
+  *yptr = outer.top;
 }
 
 \f
@@ -1961,8 +1921,8 @@ x_set_name (f, name, explicit)
   if (FRAME_MAC_WINDOW (f))
     {
       if (STRING_MULTIBYTE (name))
-#if 0 /* MAC_TODO: encoding title string */
-       name = ENCODE_SYSTEM (name);
+#if TARGET_API_MAC_CARBON
+       name = ENCODE_UTF_8 (name);
 #else
         return;
 #endif
@@ -1970,6 +1930,14 @@ x_set_name (f, name, explicit)
       BLOCK_INPUT;
 
       {
+#if TARGET_API_MAC_CARBON
+       CFStringRef windowTitle =
+         CFStringCreateWithCString (NULL, SDATA (name),
+                                    kCFStringEncodingUTF8);
+
+       SetWindowTitleWithCFString (FRAME_MAC_WINDOW (f), windowTitle);
+       CFRelease (windowTitle);
+#else
        Str255 windowTitle;
        if (strlen (SDATA (name)) < 255)
          {
@@ -1977,6 +1945,7 @@ x_set_name (f, name, explicit)
            c2pstr (windowTitle);
            SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
          }
+#endif
       }
 
       UNBLOCK_INPUT;
@@ -2035,8 +2004,8 @@ x_set_title (f, name, old_name)
   if (FRAME_MAC_WINDOW (f))
     {
       if (STRING_MULTIBYTE (name))
-#if 0 /* MAC_TODO: encoding title string */
-       name = ENCODE_SYSTEM (name);
+#if TARGET_API_MAC_CARBON
+       name = ENCODE_UTF_8 (name);
 #else
         return;
 #endif
@@ -2044,6 +2013,14 @@ x_set_title (f, name, old_name)
       BLOCK_INPUT;
 
       {
+#if TARGET_API_MAC_CARBON
+       CFStringRef windowTitle =
+         CFStringCreateWithCString (NULL, SDATA (name),
+                                    kCFStringEncodingUTF8);
+
+       SetWindowTitleWithCFString (FRAME_MAC_WINDOW (f), windowTitle);
+       CFRelease (windowTitle);
+#else
        Str255 windowTitle;
        if (strlen (SDATA (name)) < 255)
          {
@@ -2051,6 +2028,7 @@ x_set_title (f, name, old_name)
            c2pstr (windowTitle);
            SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
          }
+#endif
       }
 
       UNBLOCK_INPUT;
@@ -2595,8 +2573,6 @@ This function is an internal primitive--use `make-frame' instead.  */)
   f->output_data.mac = (struct mac_output *) xmalloc (sizeof (struct mac_output));
   bzero (f->output_data.mac, sizeof (struct mac_output));
   FRAME_FONTSET (f) = -1;
-  f->output_data.mac->scroll_bar_foreground_pixel = -1;
-  f->output_data.mac->scroll_bar_background_pixel = -1;
   record_unwind_protect (unwind_create_frame, frame);
 
   f->icon_name
@@ -2613,7 +2589,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
 
   if (!NILP (parent))
     {
-      f->output_data.mac->parent_desc = (Window) parent;
+      f->output_data.mac->parent_desc = (Window) XFASTINT (parent);
       f->output_data.mac->explicit_parent = 1;
     }
   else
@@ -2723,7 +2699,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
 
   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),
+  x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
                        "toolBar", "ToolBar", RES_TYPE_NUMBER);
   x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
                       "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
@@ -2732,25 +2708,32 @@ This function is an internal primitive--use `make-frame' instead.  */)
 
   f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
 
-  /* MAC_TODO: specify 1 below when toolbars are implemented.  */
-  window_prompting = x_figure_window_size (f, parms, 0);
+#if TARGET_API_MAC_CARBON
+  f->output_data.mac->text_cursor = kThemeIBeamCursor;
+  f->output_data.mac->nontext_cursor = kThemeArrowCursor;
+  f->output_data.mac->modeline_cursor = kThemeArrowCursor;
+  f->output_data.mac->hand_cursor = kThemePointingHandCursor;
+  f->output_data.mac->hourglass_cursor = kThemeWatchCursor;
+  f->output_data.mac->horizontal_drag_cursor = kThemeResizeLeftRightCursor;
+#else
+  f->output_data.mac->text_cursor = GetCursor (iBeamCursor);
+  f->output_data.mac->nontext_cursor = &arrow_cursor;
+  f->output_data.mac->modeline_cursor = &arrow_cursor;
+  f->output_data.mac->hand_cursor = &arrow_cursor;
+  f->output_data.mac->hourglass_cursor = GetCursor (watchCursor);
+  f->output_data.mac->horizontal_drag_cursor = &arrow_cursor;
+#endif
+
+  /* Compute the size of the window.  */
+  window_prompting = x_figure_window_size (f, parms, 1);
 
   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. */
-  FRAME_LINES (f) += 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.  */
@@ -2769,7 +2752,8 @@ This function is an internal primitive--use `make-frame' instead.  */)
   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);
+                      "scrollBarWidth", "ScrollBarWidth",
+                      RES_TYPE_NUMBER);
 
   /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
      Change will not be effected unless different from the current
@@ -2777,13 +2761,10 @@ This function is an internal primitive--use `make-frame' instead.  */)
   width = FRAME_COLS (f);
   height = FRAME_LINES (f);
 
-  FRAME_LINES (f) = 0;
   SET_FRAME_COLS (f, 0);
+  FRAME_LINES (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
@@ -2963,8 +2944,8 @@ If omitted or nil, that stands for the selected frame's display.  */)
 {
   struct mac_display_info *dpyinfo = check_x_display_info (display);
 
-  /* MAC_TODO: check whether this is right */
-  return make_number (dpyinfo->n_planes >= 8 ? 256 : 1 << dpyinfo->n_planes - 1);
+  /* We force 24+ bit depths to 24-bit to prevent an overflow.  */
+  return make_number (1 << min (dpyinfo->n_planes, 24));
 }
 
 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
@@ -3005,17 +2986,20 @@ If omitted or nil, that stands for the selected frame's display.  */)
   (display)
      Lisp_Object display;
 {
-  int mac_major_version, mac_minor_version;
+  int mac_major_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;
+  mac_major_version = (response >> 8) & 0xff;
+  /* convert BCD to int */
+  mac_major_version -= (mac_major_version >> 4) * 6;
 
   return Fcons (make_number (mac_major_version),
-               Fcons (make_number (mac_minor_version), Qnil));
+               Fcons (make_number ((response >> 4) & 0xf),
+                      Fcons (make_number (response & 0xf),
+                             Qnil)));
 }
 
 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
@@ -3040,11 +3024,8 @@ If omitted or nil, that stands for the selected frame's 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));
+  return make_number ((int) (dpyinfo->height * 25.4 / dpyinfo->resy));
 }
 
 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
@@ -3058,11 +3039,8 @@ If omitted or nil, that stands for the selected frame's 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));
+  return make_number ((int) (dpyinfo->width * 25.4 / dpyinfo->resx));
 }
 
 DEFUN ("x-display-backing-store", Fx_display_backing_store,
@@ -3610,9 +3588,11 @@ hide_hourglass ()
  ***********************************************************************/
 
 static Lisp_Object x_create_tip_frame P_ ((struct mac_display_info *,
-                                          Lisp_Object));
+                                          Lisp_Object, Lisp_Object));
+static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
+                               Lisp_Object, int, int, int *, int *));
 
-/* The frame of a currently visible tooltip, or null.  */
+/* The frame of a currently visible tooltip.  */
 
 Lisp_Object tip_frame;
 
@@ -3627,15 +3607,42 @@ Window tip_window;
 
 Lisp_Object last_show_tip_args;
 
+/* Maximum size for tooltips; a cons (COLUMNS . ROWS).  */
+
+Lisp_Object Vx_max_tooltip_size;
+
+
+static Lisp_Object
+unwind_create_tip_frame (frame)
+     Lisp_Object frame;
+{
+  Lisp_Object deleted;
+
+  deleted = unwind_create_frame (frame);
+  if (EQ (deleted, Qt))
+    {
+      tip_window = NULL;
+      tip_frame = Qnil;
+    }
+
+  return deleted;
+}
+
+
 /* Create a frame for a tooltip on the display described by DPYINFO.
-   PARMS is a list of frame parameters.  Value is the frame.  */
+   PARMS is a list of frame parameters.  TEXT is the string to
+   display in the tip frame.  Value is the frame.
+
+   Note that functions called here, esp. x_default_parameter can
+   signal errors, for instance when a specified color name is
+   undefined.  We have to make sure that we're in a consistent state
+   when this happens.  */
 
 static Lisp_Object
-x_create_tip_frame (dpyinfo, parms)
+x_create_tip_frame (dpyinfo, parms, text)
      struct mac_display_info *dpyinfo;
-     Lisp_Object parms;
+     Lisp_Object parms, text;
 {
-#if 0 /* MAC_TODO : Mac version */
   struct frame *f;
   Lisp_Object frame, tem;
   Lisp_Object name;
@@ -3644,8 +3651,11 @@ x_create_tip_frame (dpyinfo, parms)
   int count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3;
   struct kboard *kb;
+  int face_change_count_before = face_change_count;
+  Lisp_Object buffer;
+  struct buffer *old_buffer;
 
-  check_x ();
+  check_mac ();
 
   /* Use this general default value to start with until we know if
      this frame has a specified name.  */
@@ -3658,7 +3668,7 @@ x_create_tip_frame (dpyinfo, parms)
 #endif
 
   /* Get the name of the frame to use for resource lookup.  */
-  name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
+  name = mac_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
   if (!STRINGP (name)
       && !EQ (name, Qunbound)
       && !NILP (name))
@@ -3667,31 +3677,50 @@ x_create_tip_frame (dpyinfo, parms)
 
   frame = Qnil;
   GCPRO3 (parms, name, frame);
-  tip_frame = f = make_frame (1);
+  f = make_frame (1);
   XSETFRAME (frame, f);
+
+  buffer = Fget_buffer_create (build_string (" *tip*"));
+  Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer, Qnil);
+  old_buffer = current_buffer;
+  set_buffer_internal_1 (XBUFFER (buffer));
+  current_buffer->truncate_lines = Qnil;
+  specbind (Qinhibit_read_only, Qt);
+  specbind (Qinhibit_modification_hooks, Qt);
+  Ferase_buffer ();
+  Finsert (1, &text);
+  set_buffer_internal_1 (old_buffer);
+
   FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
+  record_unwind_protect (unwind_create_tip_frame, frame);
 
-  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
-  FRAME_FONTSET (f) = -1;
+  /* By setting the output method, we're essentially saying that
+     the frame is live, as per FRAME_LIVE_P.  If we get a signal
+     from this point on, x_destroy_window might screw up reference
+     counts etc.  */
+  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));
+
+  FRAME_FONTSET (f)  = -1;
   f->icon_name = Qnil;
 
+#if 0 /* GLYPH_DEBUG TODO: image support.  */
+  image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
+  dpyinfo_refcount = dpyinfo->reference_count;
+#endif /* GLYPH_DEBUG */
 #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;
+  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->x_id_name);
+      f->name = build_string (dpyinfo->mac_id_name);
       f->explicit_name = 0;
     }
   else
@@ -3702,12 +3731,12 @@ x_create_tip_frame (dpyinfo, parms)
       specbind (Qx_resource_name, name);
     }
 
-  /* Extract the window parameters from the supplied values
-     that are needed to determine window geometry.  */
+  /* 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);
+    font = mac_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
 
     BLOCK_INPUT;
     /* First, try whatever font the caller has specified.  */
@@ -3721,22 +3750,16 @@ x_create_tip_frame (dpyinfo, parms)
       }
 
     /* 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");
+      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, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
+      font = x_new_font (f, "-*-monaco-*-12-*-mac-roman");
+    if (! STRINGP (font))
+      font = x_new_font (f, "-*-courier-*-10-*-mac-roman");
     UNBLOCK_INPUT;
     if (! STRINGP (font))
-      font = build_string ("fixed");
+      error ("Cannot find any usable font");
 
     x_default_parameter (f, parms, Qfont, font,
                         "font", "Font", RES_TYPE_STRING);
@@ -3752,7 +3775,7 @@ x_create_tip_frame (dpyinfo, parms)
     {
       Lisp_Object value;
 
-      value = w32_get_arg (parms, Qinternal_border_width,
+      value = mac_get_arg (parms, Qinternal_border_width,
                         "internalBorder", "internalBorder", RES_TYPE_NUMBER);
       if (! EQ (value, Qunbound))
        parms = Fcons (Fcons (Qinternal_border_width, value),
@@ -3783,34 +3806,28 @@ x_create_tip_frame (dpyinfo, parms)
      happen.  */
   init_frame_faces (f);
 
-  f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
+  f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
 
   window_prompting = x_figure_window_size (f, parms, 0);
 
   {
-    XSetWindowAttributes attrs;
-    unsigned long mask;
+    Rect r;
 
     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);
+    SetRect (&r, 0, 0, 1, 1);
+    if (CreateNewWindow (kHelpWindowClass,
+#ifdef MAC_OS_X_VERSION_10_2
+                        kWindowIgnoreClicksAttribute |
+#endif
+                        kWindowNoActivatesAttribute,
+                        &r, &tip_window) == noErr)
+      {
+       FRAME_MAC_WINDOW (f) = tip_window;
+       SetWRefCon (tip_window, (long) f->output_data.mac);
+       /* so that update events can find this mac_output struct */
+       f->output_data.mac->mFP = f;
+       ShowWindow (tip_window);
+      }
     UNBLOCK_INPUT;
   }
 
@@ -3828,8 +3845,8 @@ x_create_tip_frame (dpyinfo, parms)
      FRAME_LINES (f).  */
   width = FRAME_COLS (f);
   height = FRAME_LINES (f);
-  FRAME_LINES (f) = 0;
   SET_FRAME_COLS (f, 0);
+  FRAME_LINES (f) = 0;
   change_frame_size (f, height, width, 1, 0, 0);
 
   /* Add `tooltip' frame parameter's default value. */
@@ -3837,6 +3854,26 @@ x_create_tip_frame (dpyinfo, parms)
     Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
                                            Qnil));
 
+  /* Set up faces after all frame parameters are known.  This call
+     also merges in face attributes specified for new frames.
+
+     Frame parameters may be changed if .Xdefaults contains
+     specifications for the default font.  For example, if there is an
+     `Emacs.default.attributeBackground: pink', the `background-color'
+     attribute of the frame get's set, which let's the internal border
+     of the tooltip frame appear in pink.  Prevent this.  */
+  {
+    Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
+
+    /* Set tip_frame here, so that */
+    tip_frame = frame;
+    call1 (Qface_set_after_frame_default, frame);
+
+    if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
+      Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
+                                             Qnil));
+  }
+
   f->no_split = 1;
 
   UNGCPRO;
@@ -3848,17 +3885,80 @@ x_create_tip_frame (dpyinfo, parms)
 
   /* Now that the frame is official, it counts as a reference to
      its display.  */
-  FRAME_W32_DISPLAY_INFO (f)->reference_count++;
+  FRAME_MAC_DISPLAY_INFO (f)->reference_count++;
+
+  /* Setting attributes of faces of the tooltip frame from resources
+     and similar will increment face_change_count, which leads to the
+     clearing of all current matrices.  Since this isn't necessary
+     here, avoid it by resetting face_change_count to the value it
+     had before we created the tip frame.  */
+  face_change_count = face_change_count_before;
 
+  /* Discard the unwind_protect.  */
   return unbind_to (count, frame);
-#endif /* MAC_TODO */
-  return Qnil;
+}
+
+
+/* Compute where to display tip frame F.  PARMS is the list of frame
+   parameters for F.  DX and DY are specified offsets from the current
+   location of the mouse.  WIDTH and HEIGHT are the width and height
+   of the tooltip.  Return coordinates relative to the root window of
+   the display in *ROOT_X, and *ROOT_Y.  */
+
+static void
+compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
+     struct frame *f;
+     Lisp_Object parms, dx, dy;
+     int width, height;
+     int *root_x, *root_y;
+{
+  Lisp_Object left, top;
+
+  /* User-specified position?  */
+  left = Fcdr (Fassq (Qleft, parms));
+  top  = Fcdr (Fassq (Qtop, parms));
+
+  /* Move the tooltip window where the mouse pointer is.  Resize and
+     show it.  */
+  if (!INTEGERP (left) || !INTEGERP (top))
+    {
+      Point mouse_pos;
+
+      BLOCK_INPUT;
+      GetMouse (&mouse_pos);
+      LocalToGlobal (&mouse_pos);
+      *root_x = mouse_pos.h;
+      *root_y = mouse_pos.v;
+      UNBLOCK_INPUT;
+    }
+
+  if (INTEGERP (top))
+    *root_y = XINT (top);
+  else if (*root_y + XINT (dy) - height < 0)
+    *root_y -= XINT (dy);
+  else
+    {
+      *root_y -= height;
+      *root_y += XINT (dy);
+    }
+
+  if (INTEGERP (left))
+    *root_x = XINT (left);
+  else if (*root_x + XINT (dx) + width <= FRAME_MAC_DISPLAY_INFO (f)->width)
+    /* It fits to the right of the pointer.  */
+    *root_x += XINT (dx);
+  else if (width + XINT (dx) <= *root_x)
+    /* It fits to the left of the pointer.  */
+    *root_x -= width + XINT (dx);
+  else
+    /* Put it left-justified on the screen -- it ought to fit that way.  */
+    *root_x = 0;
 }
 
 
 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
-       doc : /* Show STRING in a "tooltip" window on frame FRAME.
-A tooltip window is a small window displaying a string.
+       doc: /* Show STRING in a "tooltip" window on frame FRAME.
+A tooltip window is a small window displaying a string.
 
 FRAME nil or omitted means use the selected frame.
 
@@ -3874,19 +3974,19 @@ displayed at the mouse position, with offset DX added (default is 5 if
 DX isn't specified).  Likewise for the y-position; if a `top' frame
 parameter is specified, it determines the y-position of the tooltip
 window, otherwise it is displayed at the mouse position, with offset
-DY added (default is 10).  */)
-  (string, frame, parms, timeout, dx, dy)
+DY added (default is -10).
+
+A tooltip's maximum size is specified by `x-max-tooltip-size'.
+Text larger than the specified size is clipped.  */)
+     (string, frame, parms, timeout, dx, dy)
      Lisp_Object string, frame, parms, timeout, dx, dy;
 {
   struct frame *f;
   struct window *w;
-  Window root, child;
-  Lisp_Object buffer, top, left;
+  int root_x, root_y;
   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_INDEX ();
@@ -3935,13 +4035,11 @@ DY added (default is 10).  */)
              call1 (Qcancel_timer, timer);
            }
 
-#if 0 /* MAC_TODO : Mac specifics */
          BLOCK_INPUT;
-         compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
-         XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                      root_x, root_y - FRAME_PIXEL_HEIGHT (f));
+         compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
+                         FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
+         MoveWindow (FRAME_MAC_WINDOW (f), root_x, root_y, false);
          UNBLOCK_INPUT;
-#endif /* MAC_TODO */
          goto start_timer;
        }
     }
@@ -3968,26 +4066,36 @@ DY added (default is 10).  */)
 
   /* 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);
+  frame = x_create_tip_frame (FRAME_MAC_DISPLAY_INFO (f), parms, string);
   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.  */
+  /* Set up the frame's root window.  */
   w = XWINDOW (FRAME_ROOT_WINDOW (f));
   w->left_col = w->top_line = make_number (0);
-  w->total_cols = make_number (80);
-  w->total_lines = make_number (40);
+
+  if (CONSP (Vx_max_tooltip_size)
+      && INTEGERP (XCAR (Vx_max_tooltip_size))
+      && XINT (XCAR (Vx_max_tooltip_size)) > 0
+      && INTEGERP (XCDR (Vx_max_tooltip_size))
+      && XINT (XCDR (Vx_max_tooltip_size)) > 0)
+    {
+      w->total_cols = XCAR (Vx_max_tooltip_size);
+      w->total_lines = XCDR (Vx_max_tooltip_size);
+    }
+  else
+    {
+      w->total_cols = make_number (80);
+      w->total_lines = make_number (40);
+    }
+
+  FRAME_TOTAL_COLS (f) = XINT (w->total_cols);
   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, Qnil);
   old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (buffer));
-  Ferase_buffer ();
-  Finsert (1, &string);
+  set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
+  current_buffer->truncate_lines = Qnil;
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
@@ -4008,7 +4116,7 @@ DY added (default is 10).  */)
       /* 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
+      /* There's a glyph at the end of rows that is used to place
         the cursor there.  Don't include the width of this glyph.  */
       if (row->used[TEXT_AREA])
        {
@@ -4029,17 +4137,13 @@ DY added (default is 10).  */)
 
   /* Move the tooltip window where the mouse pointer is.  Resize and
      show it.  */
-#if 0 /* TODO : Mac specifics */
-  compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
+  compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
 
   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));
+  MoveWindow (FRAME_MAC_WINDOW (f), root_x, root_y, false);
+  SizeWindow (FRAME_MAC_WINDOW (f), width, height, true);
+  BringToFront (FRAME_MAC_WINDOW (f));
   UNBLOCK_INPUT;
-#endif /* MAC_TODO */
 
   /* Draw into the window.  */
   w->must_be_updated_p = 1;
@@ -4061,8 +4165,8 @@ DY added (default is 10).  */)
 
 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
        doc: /* Hide the current tooltip window, if there is any.
-Value is t is tooltip was open, nil otherwise.  */)
-  ()
+Value is t if tooltip was open, nil otherwise.  */)
+     ()
 {
   int count;
   Lisp_Object deleted, frame, timer;
@@ -4096,19 +4200,27 @@ Value is t is tooltip was open, nil otherwise.  */)
 
 
 \f
+#ifdef TARGET_API_MAC_CARBON
 /***********************************************************************
                        File selection dialog
  ***********************************************************************/
 
-#if 0 /* MAC_TODO: can standard file dialog */
+/**
+   There is a relatively standard way to do this using applescript to run
+   a (choose file) method.  However, this doesn't do "the right thing"
+   by working only if the find-file occurred during a menu or toolbar
+   click.  So we must do the file dialog by hand, using the navigation
+   manager.  This also has more flexibility in determining the default
+   directory and whether or not we are going to choose a file.
+ **/
+
 extern Lisp_Object Qfile_name_history;
 
 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
        doc: /* Read file name, prompting with PROMPT in directory DIR.
 Use a file selection dialog.
 Select DEFAULT-FILENAME in the dialog's file selection box, if
-specified.  Don't let the user enter a file name in the file
-selection dialog's entry field, if MUSTMATCH is non-nil.  */)
+specified.  Ensure that file exists if MUSTMATCH is non-nil.  */)
   (prompt, dir, default_filename, mustmatch)
      Lisp_Object prompt, dir, default_filename, mustmatch;
 {
@@ -4116,9 +4228,8 @@ selection dialog's entry field, if MUSTMATCH is non-nil.  */)
   Lisp_Object file = Qnil;
   int count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
-  char filename[MAX_PATH + 1];
-  char init_dir[MAX_PATH + 1];
-  int use_dialog_p = 1;
+  char filename[1001];
+  int default_filter_index = 1; /* 1: All Files, 2: Directories only  */
 
   GCPRO5 (prompt, dir, default_filename, mustmatch, file);
   CHECK_STRING (prompt);
@@ -4127,87 +4238,148 @@ selection dialog's entry field, if MUSTMATCH is non-nil.  */)
   /* 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, SDATA (dir), MAX_PATH);
-  init_dir[MAX_PATH] = '\0';
-  unixtodos_filename (init_dir);
-
-  if (STRINGP (default_filename))
-    {
-      char *file_name_only;
-      char *full_path_name = SDATA (default_filename);
 
-      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;
-        }
+  {
+    OSStatus status;
+    NavDialogCreationOptions options;
+    NavDialogRef dialogRef;
+    NavTypeListHandle fileTypes = NULL;
+    NavUserAction userAction;
+    CFStringRef message=NULL, client=NULL, saveName = NULL;
+    
+    BLOCK_INPUT;
+    /* No need for a callback function because we are modal */
+    NavGetDefaultDialogCreationOptions(&options);
+    options.modality = kWindowModalityAppModal;
+    options.location.h = options.location.v = -1;
+    options.optionFlags = kNavDefaultNavDlogOptions;
+    options.optionFlags |= kNavAllFilesInPopup;  /* All files allowed */
+    options.optionFlags |= kNavSelectAllReadableItem;
+    if (!NILP(prompt))
+      {
+       message = CFStringCreateWithCStringNoCopy(NULL, SDATA(prompt),
+                                                 kCFStringEncodingUTF8, 
+                                                 kCFAllocatorNull);
+       options.message = message;
+      }
+    /* Don't set the application, let it use default.
+    client = CFStringCreateWithCStringNoCopy(NULL, "Emacs", 
+                                            kCFStringEncodingMacRoman, NULL);
+    options.clientName = client;
+    */
+
+    /* Do Dired hack copied from w32fns.c */ 
+    if (!NILP(prompt) && strncmp (SDATA(prompt), "Dired", 5) == 0)
+      status = NavCreateChooseFolderDialog(&options, NULL, NULL, NULL,
+                                          &dialogRef);
+    else if (NILP (mustmatch)) 
+      { 
+       /* This is a save dialog */
+       if (!NILP(default_filename))
+         {
+           saveName = CFStringCreateWithCString(NULL, SDATA(default_filename),
+                                                kCFStringEncodingUTF8);
+           options.saveFileName = saveName;
+           options.optionFlags |= kNavSelectDefaultLocation;
+         }
+       /* MAC_TODO: Find a better way to determine if this is a save
+          or load dialog than comparing dir with default_filename */
+       if (EQ(dir, default_filename)) 
+         {
+           status = NavCreateChooseFileDialog(&options, fileTypes,
+                                              NULL, NULL, NULL, NULL, 
+                                              &dialogRef);
+         }
+       else {
+         status = NavCreatePutFileDialog(&options, 
+                                         'TEXT', kNavGenericSignature,
+                                         NULL, NULL, &dialogRef);
+       }
+      }
+    else
+      {
+       /* This is an open dialog*/
+       status = NavCreateChooseFileDialog(&options, fileTypes,
+                                          NULL, NULL, NULL, NULL, 
+                                          &dialogRef);
+      }
+    
+    /* Set the default location and continue*/
+    if (status == noErr) {
+      if (!NILP(dir)) {
+       FSRef defLoc;
+       AEDesc defLocAed;
+       status = FSPathMakeRef(SDATA(dir), &defLoc, NULL);
+       if (status == noErr) 
+         {
+           AECreateDesc(typeFSRef, &defLoc, sizeof(FSRef), &defLocAed);
+           NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed);
+         }
+       AEDisposeDesc(&defLocAed);
+      }
 
-      strncpy (filename, file_name_only, MAX_PATH);
-      filename[MAX_PATH] = '\0';
+      status = NavDialogRun(dialogRef);
     }
-  else
-    filename[0] = '\0';
 
-  if (use_dialog_p)
-    {
-      OPENFILENAME file_details;
-      char *filename_file;
+    if (saveName) CFRelease(saveName);
+    if (client) CFRelease(client);
+    if (message) CFRelease(message);
 
-      /* 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 = SDATA (prompt);
-      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);
+    if (status == noErr) {
+      userAction = NavDialogGetUserAction(dialogRef);
+      switch (userAction)
+       {
+       case kNavUserActionNone:
+       case kNavUserActionCancel:
+         break;                /* Treat cancel like C-g */
+       case kNavUserActionOpen:
+       case kNavUserActionChoose:
+       case kNavUserActionSaveAs:
+         {
+           NavReplyRecord reply;
+           AEDesc aed;
+           FSRef fsRef;
+           status = NavDialogGetReply(dialogRef, &reply);
+           AECoerceDesc(&reply.selection, typeFSRef, &aed);
+           AEGetDescData(&aed, (void *) &fsRef, sizeof (FSRef));
+           FSRefMakePath(&fsRef, (UInt8 *) filename, 1000);
+           AEDisposeDesc(&aed);
+           if (reply.saveFileName)
+             {
+               /* If it was a saved file, we need to add the file name */
+               int len = strlen(filename);
+               if (len && filename[len-1] != '/')
+                 filename[len++] = '/';
+               CFStringGetCString(reply.saveFileName, filename+len, 
+                                  1000-len, kCFStringEncodingUTF8);
+             }
+           file = DECODE_FILE(build_string (filename));
+           NavDisposeReply(&reply);
+         }
+         break;
+       }
+      NavDialogDispose(dialogRef);
     }
-  /* 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);
+    else {
+      /* Fall back on minibuffer if there was a problem */
+      file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
+                              dir, mustmatch, dir, Qfile_name_history,
+                              default_filename, Qnil);
+    }
+    UNBLOCK_INPUT;
+  }
 
   UNGCPRO;
-
+  
   /* Make "Cancel" equivalent to C-g.  */
   if (NILP (file))
     Fsignal (Qquit, Qnil);
-
+  
   return unbind_to (count, file);
 }
-#endif /* MAC_TODO */
 
 
+#endif
 \f
 /***********************************************************************
                            Initialization
@@ -4264,7 +4436,8 @@ syms_of_macfns ()
   staticpro (&Qsuppress_icon);
   Qundefined_color = intern ("undefined-color");
   staticpro (&Qundefined_color);
-  /* This is the end of symbol initialization.  */
+  Qcancel_timer = intern ("cancel-timer");
+  staticpro (&Qcancel_timer);
 
   Qhyper = intern ("hyper");
   staticpro (&Qhyper);
@@ -4280,6 +4453,7 @@ syms_of_macfns ()
   staticpro (&Qcontrol);
   Qshift = intern ("shift");
   staticpro (&Qshift);
+  /* This is the end of symbol initialization.  */
 
   /* Text property `display' should be nonsticky by default.  */
   Vtext_property_default_nonsticky
@@ -4329,6 +4503,11 @@ or when you set the mouse color.  */);
               doc: /* A string indicating the foreground color of the cursor box.  */);
   Vx_cursor_fore_pixel = Qnil;
 
+  DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
+    doc: /* Maximum size for tooltips.  Value is a pair (COLUMNS . ROWS).
+Text larger than this is clipped.  */);
+  Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
+
   DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
               doc: /* Non-nil if no window manager is in use.
 Emacs doesn't try to figure this out; this is always nil
@@ -4401,7 +4580,10 @@ Chinese, Japanese, and Korean.  */);
   tip_frame = Qnil;
   staticpro (&tip_frame);
 
-#if 0 /* MAC_TODO */
+  last_show_tip_args = Qnil;
+  staticpro (&last_show_tip_args);
+
+#if TARGET_API_MAC_CARBON
   defsubr (&Sx_file_dialog);
 #endif
 }