(Qfont_spec, Qfont_entity, Qfont_object): Extern them.
[bpt/emacs.git] / src / mactoolbox.c
index 6b4d220..45a8613 100644 (file)
@@ -118,10 +118,8 @@ extern Lisp_Object Qhi_command;
 static TSMDocumentID tsm_document_id;
 extern Lisp_Object Qtext_input;
 extern Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
-extern Lisp_Object Vmac_ts_active_input_overlay;
+extern Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
 extern Lisp_Object Qbefore_string;
-extern Lisp_Object Vmac_ts_script_language_on_focus;
-extern Lisp_Object saved_ts_script_language_on_focus;
 #endif
 
 static int mac_event_to_emacs_modifiers P_ ((EventRef));
@@ -136,6 +134,14 @@ extern OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
                                                        EventRef, UInt32,
                                                        const EventParamName *,
                                                        const EventParamType *));
+extern int fast_find_position P_ ((struct window *, int, int *, int *,
+                                  int *, int *, Lisp_Object));
+extern struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
+                                          int *, int *, int *, int *, int *));
+extern void mac_ax_selected_text_range P_ ((struct frame *, CFRange *));
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
+extern unsigned int mac_ax_number_of_characters P_ ((struct frame *));
+#endif
 
 #if USE_MAC_TSM
 extern OSStatus mac_restore_keyboard_input_source P_ ((void));
@@ -376,6 +382,10 @@ mac_handle_mouse_event (next_handler, event, data)
 }
 
 #if USE_MAC_TSM
+extern void mac_get_selected_range P_ ((struct window *, CFRange *));
+extern int mac_store_buffer_text_to_unicode_chars P_ ((struct buffer *,
+                                                      int, int, UniChar *));
+
 static pascal OSStatus
 mac_handle_text_input_event (next_handler, event, data)
      EventHandlerCallRef next_handler;
@@ -514,42 +524,268 @@ mac_handle_text_input_event (next_handler, event, data)
 
     case kEventTextInputOffsetToPos:
       {
+       long byte_offset;
        struct frame *f;
        struct window *w;
        Point p;
 
-       if (!OVERLAYP (Vmac_ts_active_input_overlay))
+       err = GetEventParameter (event, kEventParamTextInputSendTextOffset,
+                                typeLongInteger, NULL, sizeof (long), NULL,
+                                &byte_offset);
+       if (err != noErr)
          break;
 
-       /* Strictly speaking, this is not always correct because
-          previous events may change some states about display.  */
-       if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
+       if (STRINGP (Vmac_ts_active_input_buf)
+           && SBYTES (Vmac_ts_active_input_buf) != 0)
+         {
+           if (!OVERLAYP (Vmac_ts_active_input_overlay))
+             break;
+
+           /* Strictly speaking, this is not always correct because
+              previous events may change some states about display.  */
+           if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
+             {
+               /* Active input area is displayed around the current point.  */
+               f = SELECTED_FRAME ();
+               w = XWINDOW (f->selected_window);
+             }
+           else if (WINDOWP (echo_area_window))
+             {
+               /* Active input area is displayed in the echo area.  */
+               w = XWINDOW (echo_area_window);
+               f = WINDOW_XFRAME (w);
+             }
+           else
+             break;
+
+           p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
+                  + WINDOW_LEFT_FRINGE_WIDTH (w)
+                  + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
+           p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
+                  + FONT_BASE (FRAME_FONT (f))
+                  + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
+         }
+       else
          {
-           /* Active input area is displayed around the current point.  */
-           f = SELECTED_FRAME ();
+#ifndef MAC_OSX
+           break;
+#else  /* MAC_OSX */
+           CFRange sel_range;
+           int charpos;
+           int hpos, vpos, x, y;
+           struct glyph_row *row;
+           struct glyph *glyph;
+           XFontStruct *font;
+
+           f = mac_focus_frame (&one_mac_display_info);
            w = XWINDOW (f->selected_window);
+           mac_get_selected_range (w, &sel_range);
+           charpos = (BUF_BEGV (XBUFFER (w->buffer)) + sel_range.location
+                      + byte_offset / (long) sizeof (UniChar));
+
+           if (!fast_find_position (w, charpos, &hpos, &vpos, &x, &y, Qnil))
+             {
+               result = errOffsetInvalid;
+               break;
+             }
+
+           row = MATRIX_ROW (w->current_matrix, vpos);
+           glyph = row->glyphs[TEXT_AREA] + hpos;
+           if (glyph->type != CHAR_GLYPH || glyph->glyph_not_available_p)
+             break;
+
+           p.h = (WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x)
+                  + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
+           p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, y)
+                  + row->visible_height
+                  + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
+
+           font = FACE_FROM_ID (f, glyph->face_id)->font;
+           if (font)
+             {
+               Fixed point_size = Long2Fix (font->mac_fontsize);
+               short height = row->visible_height;
+               short ascent = row->ascent;
+
+               SetEventParameter (event,
+                                  kEventParamTextInputReplyPointSize,
+                                  typeFixed, sizeof (Fixed), &point_size);
+               SetEventParameter (event,
+                                  kEventParamTextInputReplyLineHeight,
+                                  typeShortInteger, sizeof (short), &height);
+               SetEventParameter (event,
+                                  kEventParamTextInputReplyLineAscent,
+                                  typeShortInteger, sizeof (short), &ascent);
+               if (font->mac_fontnum != -1)
+                 {
+                   OSStatus err1;
+                   FMFont fm_font;
+                   FMFontStyle style;
+
+                   err1 = FMGetFontFromFontFamilyInstance (font->mac_fontnum,
+                                                           font->mac_fontface,
+                                                           &fm_font, &style);
+                   if (err1 == noErr)
+                     SetEventParameter (event, kEventParamTextInputReplyFMFont,
+                                        typeUInt32, sizeof (UInt32), &fm_font);
+                   else
+                     {
+                       long qd_font = font->mac_fontnum;
+
+                       SetEventParameter (event, kEventParamTextInputReplyFont,
+                                          typeLongInteger, sizeof (long),
+                                          &qd_font);
+                     }
+                 }
+               else if (font->mac_style)
+                 {
+                   OSStatus err1;
+                   ATSUFontID font_id;
+
+                   err1 = ATSUGetAttribute (font->mac_style, kATSUFontTag,
+                                            sizeof (ATSUFontID), &font_id,
+                                            NULL);
+                   if (err1 == noErr)
+                     SetEventParameter (event, kEventParamTextInputReplyFMFont,
+                                        typeUInt32, sizeof (UInt32), &font_id);
+                 }
+               else
+                 abort ();
+             }
+#endif /* MAC_OSX */
          }
-       else if (WINDOWP (echo_area_window))
+
+       err = SetEventParameter (event, kEventParamTextInputReplyPoint,
+                                typeQDPoint, sizeof (Point), &p);
+       if (err == noErr)
+         result = noErr;
+      }
+      break;
+
+#ifdef MAC_OSX
+    case kEventTextInputPosToOffset:
+      {
+       Point point;
+       Boolean leading_edge_p = true;
+       struct frame *f;
+       int x, y;
+       Lisp_Object window;
+       enum window_part part;
+       long region_class = kTSMOutsideOfBody, byte_offset = 0;
+
+       err = GetEventParameter (event, kEventParamTextInputSendCurrentPoint,
+                                typeQDPoint, NULL, sizeof (Point), NULL,
+                                &point);
+       if (err != noErr)
+         break;
+
+       GetEventParameter (event, kEventParamTextInputReplyLeadingEdge,
+                          typeBoolean, NULL, sizeof (Boolean), NULL,
+                          &leading_edge_p);
+
+       f = mac_focus_frame (&one_mac_display_info);
+       x = point.h - (f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
+       y = point.v - (f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
+       window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
+       if (WINDOWP (window) && EQ (window, f->selected_window))
          {
-           /* Active input area is displayed in the echo area.  */
-           w = XWINDOW (echo_area_window);
-           f = WINDOW_XFRAME (w);
+           struct window *w;
+           struct buffer *b;
+
+           /* Convert to window-relative pixel coordinates.  */
+           w = XWINDOW (window);
+           frame_to_window_pixel_xy (w, &x, &y);
+
+           /* Are we in a window whose display is up to date?
+              And verify the buffer's text has not changed.  */
+           b = XBUFFER (w->buffer);
+           if (part == ON_TEXT
+               && EQ (w->window_end_valid, w->buffer)
+               && XINT (w->last_modified) == BUF_MODIFF (b)
+               && XINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
+             {
+               int hpos, vpos, area;
+               struct glyph *glyph;
+
+               /* Find the glyph under X/Y.  */
+               glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, 0, 0, &area);
+
+               if (glyph != NULL && area == TEXT_AREA)
+                 {
+                   byte_offset = ((glyph->charpos - BUF_BEGV (b))
+                                  * sizeof (UniChar));
+                   region_class = kTSMInsideOfBody;
+                 }
+             }
          }
-       else
+
+       err = SetEventParameter (event, kEventParamTextInputReplyRegionClass,
+                                typeLongInteger, sizeof (long),
+                                &region_class);
+       if (err == noErr)
+         err = SetEventParameter (event, kEventParamTextInputReplyTextOffset,
+                                  typeLongInteger, sizeof (long),
+                                  &byte_offset);
+       if (err == noErr)
+         result = noErr;
+      }
+      break;
+
+    case kEventTextInputGetSelectedText:
+      {
+       struct frame *f = mac_focus_frame (&one_mac_display_info);
+       struct window *w = XWINDOW (f->selected_window);
+       struct buffer *b = XBUFFER (w->buffer);
+       CFRange sel_range;
+       int start, end;
+       UniChar *characters, c;
+
+       if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
+         /* Don't try to get buffer contents as the gap might be
+            being altered. */
          break;
 
-       p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
-              + WINDOW_LEFT_FRINGE_WIDTH (w)
-              + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
-       p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
-              + FONT_BASE (FRAME_FONT (f))
-              + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
-       err = SetEventParameter (event, kEventParamTextInputReplyPoint,
-                                typeQDPoint, sizeof (typeQDPoint), &p);
+       mac_get_selected_range (w, &sel_range);
+       if (sel_range.length == 0)
+         {
+           Boolean leading_edge_p;
+
+           err = GetEventParameter (event,
+                                    kEventParamTextInputReplyLeadingEdge,
+                                    typeBoolean, NULL, sizeof (Boolean), NULL,
+                                    &leading_edge_p);
+           if (err != noErr)
+             break;
+
+           start = BUF_BEGV (b) + sel_range.location;
+           if (!leading_edge_p)
+             start--;
+           end = start + 1;
+           characters = &c;
+
+           if (start < BUF_BEGV (b) || end > BUF_ZV (b))
+             break;
+         }
+       else
+         {
+           start = BUF_BEGV (b) + sel_range.location;
+           end = start + sel_range.length;
+           characters = xmalloc (sel_range.length * sizeof (UniChar));
+         }
+
+       if (mac_store_buffer_text_to_unicode_chars (b, start, end, characters))
+         err = SetEventParameter (event, kEventParamTextInputReplyText,
+                                  typeUnicodeText,
+                                  sel_range.length * sizeof (UniChar),
+                                  characters);
+       if (characters != &c)
+         xfree (characters);
+
        if (err == noErr)
          result = noErr;
       }
       break;
+#endif /* MAC_OSX */
 
     default:
       abort ();
@@ -561,6 +797,86 @@ mac_handle_text_input_event (next_handler, event, data)
                                              names, types);
   return result;
 }
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
+static pascal OSStatus
+mac_handle_document_access_event (next_handler, event, data)
+     EventHandlerCallRef next_handler;
+     EventRef event;
+     void *data;
+{
+  OSStatus err, result;
+  struct frame *f = mac_focus_frame (&one_mac_display_info);
+
+  result = CallNextEventHandler (next_handler, event);
+  if (result != eventNotHandledErr)
+    return result;
+
+  switch (GetEventKind (event))
+    {
+    case kEventTSMDocumentAccessGetLength:
+      {
+       CFIndex count = mac_ax_number_of_characters (f);
+
+       err = SetEventParameter (event, kEventParamTSMDocAccessCharacterCount,
+                                typeCFIndex, sizeof (CFIndex), &count);
+       if (err == noErr)
+         result = noErr;
+      }
+      break;
+
+    case kEventTSMDocumentAccessGetSelectedRange:
+      {
+       CFRange sel_range;
+
+       mac_ax_selected_text_range (f, &sel_range);
+       err = SetEventParameter (event,
+                                kEventParamTSMDocAccessReplyCharacterRange,
+                                typeCFRange, sizeof (CFRange), &sel_range);
+       if (err == noErr)
+         result = noErr;
+      }
+      break;
+
+    case kEventTSMDocumentAccessGetCharacters:
+      {
+       struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
+       CFRange range;
+       Ptr characters;
+       int start, end;
+
+       if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
+         /* Don't try to get buffer contents as the gap might be
+            being altered. */
+         break;
+
+       err = GetEventParameter (event,
+                                kEventParamTSMDocAccessSendCharacterRange,
+                                typeCFRange, NULL, sizeof (CFRange), NULL,
+                                &range);
+       if (err == noErr)
+         err = GetEventParameter (event,
+                                  kEventParamTSMDocAccessSendCharactersPtr,
+                                  typePtr, NULL, sizeof (Ptr), NULL,
+                                  &characters);
+       if (err != noErr)
+         break;
+
+       start = BUF_BEGV (b) + range.location;
+       end = start + range.length;
+       if (mac_store_buffer_text_to_unicode_chars (b, start, end,
+                                                   (UniChar *) characters))
+         result = noErr;
+      }
+      break;
+
+    default:
+      abort ();
+    }
+
+  return result;
+}
+#endif
 #endif
 
 OSStatus
@@ -606,16 +922,35 @@ install_application_handler ()
 #if USE_MAC_TSM
   if (err == noErr)
     {
-      static const EventTypeSpec spec[] =
+      static const EventTypeSpec specs[] =
        {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
         {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
-        {kEventClassTextInput, kEventTextInputOffsetToPos}};
+        {kEventClassTextInput, kEventTextInputOffsetToPos},
+#ifdef MAC_OSX
+        {kEventClassTextInput, kEventTextInputPosToOffset},
+        {kEventClassTextInput, kEventTextInputGetSelectedText}
+#endif
+       };
 
       err = InstallApplicationEventHandler (NewEventHandlerUPP
                                            (mac_handle_text_input_event),
-                                           GetEventTypeCount (spec),
-                                           spec, NULL, NULL);
+                                           GetEventTypeCount (specs),
+                                           specs, NULL, NULL);
+    }
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
+  if (err == noErr)
+    {
+      static const EventTypeSpec specs[] =
+       {{kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength},
+        {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange},
+        {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters}};
+
+      err = InstallApplicationEventHandler (mac_handle_document_access_event,
+                                           GetEventTypeCount (specs),
+                                           specs, NULL, NULL);
     }
+#endif
 #endif
 
   if (err == noErr)
@@ -3009,8 +3344,8 @@ mac_event_to_emacs_modifiers (EventRef eventRef)
   GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
                    sizeof (UInt32), NULL, &mods);
   class = GetEventClass (eventRef);
-  if (!NILP (Vmac_emulate_three_button_mouse) &&
-      (class == kEventClassMouse || class == kEventClassCommand))
+  if (!NILP (Vmac_emulate_three_button_mouse)
+      && (class == kEventClassMouse || class == kEventClassCommand))
     {
       mods &= ~(optionKey | cmdKey);
     }
@@ -3560,6 +3895,9 @@ XTread_socket (sd, expected, hold_quit)
                  OSStatus err;
                  HIViewRef ch;
 
+                 if (FrontNonFloatingWindow () != window_ptr)
+                   SelectWindow (window_ptr);
+
                  err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
                                                    eventRef, &ch);
                  /* This doesn't work on Mac OS X 10.2.  */
@@ -4248,7 +4586,6 @@ x_activate_menubar (f)
 {
   SInt32 menu_choice;
   SInt16 menu_id, menu_item;
-  extern Point saved_menu_event_location;
 
   set_frame_menubar (f, 0, 1);
   BLOCK_INPUT;
@@ -5704,6 +6041,75 @@ static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
 static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
 static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
 
+static OSErr
+create_apple_event_from_drag_ref (drag, num_types, types, result)
+     DragRef drag;
+     UInt32 num_types;
+     const FlavorType *types;
+     AppleEvent *result;
+{
+  OSErr err;
+  UInt16 num_items;
+  AppleEvent items;
+  long index;
+  char *buf = NULL;
+
+  err = CountDragItems (drag, &num_items);
+  if (err != noErr)
+    return err;
+  err = AECreateList (NULL, 0, false, &items);
+  if (err != noErr)
+    return err;
+
+  for (index = 1; index <= num_items; index++)
+    {
+      ItemReference item;
+      DescType desc_type = typeNull;
+      Size size;
+
+      err = GetDragItemReferenceNumber (drag, index, &item);
+      if (err == noErr)
+       {
+         int i;
+
+         for (i = 0; i < num_types; i++)
+           {
+             err = GetFlavorDataSize (drag, item, types[i], &size);
+             if (err == noErr)
+               {
+                 buf = xrealloc (buf, size);
+                 err = GetFlavorData (drag, item, types[i], buf, &size, 0);
+               }
+             if (err == noErr)
+               {
+                 desc_type = types[i];
+                 break;
+               }
+           }
+       }
+      err = AEPutPtr (&items, index, desc_type,
+                     desc_type != typeNull ? buf : NULL,
+                     desc_type != typeNull ? size : 0);
+      if (err != noErr)
+       break;
+    }
+  if (buf)
+    xfree (buf);
+
+  if (err == noErr)
+    {
+      err = create_apple_event (0, 0, result); /* Dummy class and ID.  */
+      if (err == noErr)
+       err = AEPutParamDesc (result, keyDirectObject, &items);
+      if (err != noErr)
+       AEDisposeDesc (result);
+    }
+
+  AEDisposeDesc (&items);
+
+  return err;
+}
+
 static void
 mac_store_drag_event (window, mouse_pos, modifiers, desc)
      WindowRef window;