OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <QuartzCore/QuartzCore.h> | 5 #include <QuartzCore/QuartzCore.h> |
6 | 6 |
7 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" | 7 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" |
8 | 8 |
9 #include "app/app_switches.h" | 9 #include "app/app_switches.h" |
10 #include "app/surface/io_surface_support_mac.h" | 10 #include "app/surface/io_surface_support_mac.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey; | 56 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey; |
57 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey; | 57 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey; |
58 return modifiers; | 58 return modifiers; |
59 } | 59 } |
60 | 60 |
61 @interface RenderWidgetHostViewCocoa (Private) | 61 @interface RenderWidgetHostViewCocoa (Private) |
62 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; | 62 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; |
63 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; | 63 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; |
64 - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; | 64 - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; |
65 - (void)cancelChildPopups; | 65 - (void)cancelChildPopups; |
| 66 - (void)checkForPluginImeCancellation; |
66 @end | 67 @end |
67 | 68 |
68 // This API was published since 10.6. Provide the declaration so it can be | 69 // This API was published since 10.6. Provide the declaration so it can be |
69 // // called below when building with the 10.5 SDK. | 70 // // called below when building with the 10.5 SDK. |
70 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 | 71 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 |
71 @class NSTextInputContext; | 72 @class NSTextInputContext; |
72 @interface NSResponder (AppKitDetails) | 73 @interface NSResponder (AppKitDetails) |
73 - (NSTextInputContext *)inputContext; | 74 - (NSTextInputContext *)inputContext; |
74 @end | 75 @end |
75 #endif | 76 #endif |
76 | 77 |
77 namespace { | 78 namespace { |
78 | 79 |
79 // Maximum number of characters we allow in a tooltip. | 80 // Maximum number of characters we allow in a tooltip. |
80 const size_t kMaxTooltipLength = 1024; | 81 const size_t kMaxTooltipLength = 1024; |
81 | 82 |
82 // TODO(suzhe): Upstream this function. | 83 // TODO(suzhe): Upstream this function. |
83 WebKit::WebColor WebColorFromNSColor(NSColor *color) { | 84 WebKit::WebColor WebColorFromNSColor(NSColor *color) { |
84 CGFloat r, g, b, a; | 85 CGFloat r, g, b, a; |
85 [color getRed:&r green:&g blue:&b alpha:&a]; | 86 [color getRed:&r green:&g blue:&b alpha:&a]; |
86 | 87 |
87 return | 88 return |
88 std::max(0, std::min(static_cast<int>(lroundf(255.0f * a)), 255)) << 24 | | 89 std::max(0, std::min(static_cast<int>(lroundf(255.0f * a)), 255)) << 24 | |
89 std::max(0, std::min(static_cast<int>(lroundf(255.0f * r)), 255)) << 16 | | 90 std::max(0, std::min(static_cast<int>(lroundf(255.0f * r)), 255)) << 16 | |
90 std::max(0, std::min(static_cast<int>(lroundf(255.0f * g)), 255)) << 8 | | 91 std::max(0, std::min(static_cast<int>(lroundf(255.0f * g)), 255)) << 8 | |
91 std::max(0, std::min(static_cast<int>(lroundf(255.0f * b)), 255)); | 92 std::max(0, std::min(static_cast<int>(lroundf(255.0f * b)), 255)); |
92 } | 93 } |
93 | 94 |
94 // Extract underline information from an attributed string. | 95 // Extract underline information from an attributed string. Mostly copied from |
95 // Mostly copied from third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.m
m | 96 // third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm |
96 void ExtractUnderlines( | 97 void ExtractUnderlines( |
97 NSAttributedString* string, | 98 NSAttributedString* string, |
98 std::vector<WebKit::WebCompositionUnderline>* underlines) { | 99 std::vector<WebKit::WebCompositionUnderline>* underlines) { |
99 int length = [[string string] length]; | 100 int length = [[string string] length]; |
100 int i = 0; | 101 int i = 0; |
101 while (i < length) { | 102 while (i < length) { |
102 NSRange range; | 103 NSRange range; |
103 NSDictionary* attrs = [string attributesAtIndex:i | 104 NSDictionary* attrs = [string attributesAtIndex:i |
104 longestEffectiveRange:&range | 105 longestEffectiveRange:&range |
105 inRange:NSMakeRange(i, length - i)]; | 106 inRange:NSMakeRange(i, length - i)]; |
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 | 875 |
875 void RenderWidgetHostViewMac::KillSelf() { | 876 void RenderWidgetHostViewMac::KillSelf() { |
876 if (shutdown_factory_.empty()) { | 877 if (shutdown_factory_.empty()) { |
877 [cocoa_view_ setHidden:YES]; | 878 [cocoa_view_ setHidden:YES]; |
878 MessageLoop::current()->PostTask(FROM_HERE, | 879 MessageLoop::current()->PostTask(FROM_HERE, |
879 shutdown_factory_.NewRunnableMethod( | 880 shutdown_factory_.NewRunnableMethod( |
880 &RenderWidgetHostViewMac::ShutdownHost)); | 881 &RenderWidgetHostViewMac::ShutdownHost)); |
881 } | 882 } |
882 } | 883 } |
883 | 884 |
884 void RenderWidgetHostViewMac::SetPluginImeEnabled(bool enabled, int plugin_id) { | 885 void RenderWidgetHostViewMac::PluginFocusChanged(bool focused, int plugin_id) { |
885 [cocoa_view_ setPluginImeEnabled:(enabled ? YES : NO) forPlugin:plugin_id]; | 886 [cocoa_view_ pluginFocusChanged:(focused ? YES : NO) forPlugin:plugin_id]; |
| 887 } |
| 888 |
| 889 void RenderWidgetHostViewMac::StartPluginIme() { |
| 890 [cocoa_view_ setPluginImeActive:YES]; |
886 } | 891 } |
887 | 892 |
888 bool RenderWidgetHostViewMac::PostProcessEventForPluginIme( | 893 bool RenderWidgetHostViewMac::PostProcessEventForPluginIme( |
889 const NativeWebKeyboardEvent& event) { | 894 const NativeWebKeyboardEvent& event) { |
890 // Check WebInputEvent type since multiple types of events can be sent into | 895 // Check WebInputEvent type since multiple types of events can be sent into |
891 // WebKit for the same OS event (e.g., RawKeyDown and Char), so filtering is | 896 // WebKit for the same OS event (e.g., RawKeyDown and Char), so filtering is |
892 // necessary to avoid double processing. | 897 // necessary to avoid double processing. |
893 // Also check the native type, since NSFlagsChanged is considered a key event | 898 // Also check the native type, since NSFlagsChanged is considered a key event |
894 // for WebKit purposes, but isn't considered a key event by the OS. | 899 // for WebKit purposes, but isn't considered a key event by the OS. |
895 if (event.type == WebInputEvent::RawKeyDown && | 900 if (event.type == WebInputEvent::RawKeyDown && |
896 [event.os_event type] == NSKeyDown) | 901 [event.os_event type] == NSKeyDown) |
897 return [cocoa_view_ postProcessEventForPluginIme:event.os_event]; | 902 return [cocoa_view_ postProcessEventForPluginIme:event.os_event]; |
898 return false; | 903 return false; |
899 } | 904 } |
900 | 905 |
901 void RenderWidgetHostViewMac::PluginImeCompositionConfirmed( | 906 void RenderWidgetHostViewMac::PluginImeCompositionCompleted( |
902 const string16& text, int plugin_id) { | 907 const string16& text, int plugin_id) { |
903 if (render_widget_host_) { | 908 if (render_widget_host_) { |
904 render_widget_host_->Send(new ViewMsg_PluginImeCompositionConfirmed( | 909 render_widget_host_->Send(new ViewMsg_PluginImeCompositionCompleted( |
905 render_widget_host_->routing_id(), text, plugin_id)); | 910 render_widget_host_->routing_id(), text, plugin_id)); |
906 } | 911 } |
907 } | 912 } |
908 | 913 |
909 gfx::PluginWindowHandle | 914 gfx::PluginWindowHandle |
910 RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque, | 915 RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque, |
911 bool root) { | 916 bool root) { |
912 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 917 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
913 | 918 |
914 // |render_widget_host_| is set to NULL when |RWHVMac::Destroy()| has | 919 // |render_widget_host_| is set to NULL when |RWHVMac::Destroy()| has |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1251 | 1256 |
1252 NSRect bounds = [enclosing_window frame]; | 1257 NSRect bounds = [enclosing_window frame]; |
1253 return FlipNSRectToRectScreen(bounds); | 1258 return FlipNSRectToRectScreen(bounds); |
1254 } | 1259 } |
1255 | 1260 |
1256 void RenderWidgetHostViewMac::SetActive(bool active) { | 1261 void RenderWidgetHostViewMac::SetActive(bool active) { |
1257 if (render_widget_host_) | 1262 if (render_widget_host_) |
1258 render_widget_host_->SetActive(active); | 1263 render_widget_host_->SetActive(active); |
1259 if (HasFocus()) | 1264 if (HasFocus()) |
1260 SetTextInputActive(active); | 1265 SetTextInputActive(active); |
| 1266 if (!active) |
| 1267 [cocoa_view_ setPluginImeActive:NO]; |
1261 } | 1268 } |
1262 | 1269 |
1263 void RenderWidgetHostViewMac::SetWindowVisibility(bool visible) { | 1270 void RenderWidgetHostViewMac::SetWindowVisibility(bool visible) { |
1264 if (render_widget_host_) { | 1271 if (render_widget_host_) { |
1265 render_widget_host_->Send(new ViewMsg_SetWindowVisibility( | 1272 render_widget_host_->Send(new ViewMsg_SetWindowVisibility( |
1266 render_widget_host_->routing_id(), visible)); | 1273 render_widget_host_->routing_id(), visible)); |
1267 } | 1274 } |
1268 } | 1275 } |
1269 | 1276 |
1270 void RenderWidgetHostViewMac::WindowFrameChanged() { | 1277 void RenderWidgetHostViewMac::WindowFrameChanged() { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1324 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { | 1331 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { |
1325 self = [super initWithFrame:NSZeroRect]; | 1332 self = [super initWithFrame:NSZeroRect]; |
1326 if (self) { | 1333 if (self) { |
1327 editCommand_helper_.reset(new RWHVMEditCommandHelper); | 1334 editCommand_helper_.reset(new RWHVMEditCommandHelper); |
1328 editCommand_helper_->AddEditingSelectorsToClass([self class]); | 1335 editCommand_helper_->AddEditingSelectorsToClass([self class]); |
1329 | 1336 |
1330 renderWidgetHostView_.reset(r); | 1337 renderWidgetHostView_.reset(r); |
1331 canBeKeyView_ = YES; | 1338 canBeKeyView_ = YES; |
1332 takesFocusOnlyOnMouseDown_ = NO; | 1339 takesFocusOnlyOnMouseDown_ = NO; |
1333 closeOnDeactivate_ = NO; | 1340 closeOnDeactivate_ = NO; |
1334 pluginImeIdentifier_ = -1; | 1341 focusedPluginIdentifier_ = -1; |
1335 } | 1342 } |
1336 return self; | 1343 return self; |
1337 } | 1344 } |
1338 | 1345 |
1339 - (void)setCanBeKeyView:(BOOL)can { | 1346 - (void)setCanBeKeyView:(BOOL)can { |
1340 canBeKeyView_ = can; | 1347 canBeKeyView_ = can; |
1341 } | 1348 } |
1342 | 1349 |
1343 - (void)setTakesFocusOnlyOnMouseDown:(BOOL)b { | 1350 - (void)setTakesFocusOnlyOnMouseDown:(BOOL)b { |
1344 takesFocusOnlyOnMouseDown_ = b; | 1351 takesFocusOnlyOnMouseDown_ = b; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1480 | 1487 |
1481 // These variables might be set when handling the keyboard event. | 1488 // These variables might be set when handling the keyboard event. |
1482 // Clear them here so that we can know whether they have changed afterwards. | 1489 // Clear them here so that we can know whether they have changed afterwards. |
1483 textToBeInserted_.clear(); | 1490 textToBeInserted_.clear(); |
1484 markedText_.clear(); | 1491 markedText_.clear(); |
1485 underlines_.clear(); | 1492 underlines_.clear(); |
1486 unmarkTextCalled_ = NO; | 1493 unmarkTextCalled_ = NO; |
1487 hasEditCommands_ = NO; | 1494 hasEditCommands_ = NO; |
1488 editCommands_.clear(); | 1495 editCommands_.clear(); |
1489 | 1496 |
| 1497 // Before doing anything with a key down, check to see if plugin IME has been |
| 1498 // cancelled, since the plugin host needs to be informed of that before |
| 1499 // receiving the keydown. |
| 1500 if ([theEvent type] == NSKeyDown) |
| 1501 [self checkForPluginImeCancellation]; |
| 1502 |
1490 // Sends key down events to input method first, then we can decide what should | 1503 // Sends key down events to input method first, then we can decide what should |
1491 // be done according to input method's feedback. | 1504 // be done according to input method's feedback. |
1492 // If a plugin is active, bypass this step since events are forwarded directly | 1505 // If a plugin is active, bypass this step since events are forwarded directly |
1493 // to the plugin IME. | 1506 // to the plugin IME. |
1494 if (pluginImeIdentifier_ == -1) | 1507 if (focusedPluginIdentifier_ == -1) |
1495 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | 1508 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; |
1496 | 1509 |
1497 handlingKeyDown_ = NO; | 1510 handlingKeyDown_ = NO; |
1498 | 1511 |
1499 // Indicates if we should send the key event and corresponding editor commands | 1512 // Indicates if we should send the key event and corresponding editor commands |
1500 // after processing the input method result. | 1513 // after processing the input method result. |
1501 BOOL delayEventUntilAfterImeCompostion = NO; | 1514 BOOL delayEventUntilAfterImeCompostion = NO; |
1502 | 1515 |
1503 // To emulate Windows, over-write |event.windowsKeyCode| to VK_PROCESSKEY | 1516 // To emulate Windows, over-write |event.windowsKeyCode| to VK_PROCESSKEY |
1504 // while an input method is composing or inserting a text. | 1517 // while an input method is composing or inserting a text. |
(...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2392 } | 2405 } |
2393 | 2406 |
2394 - (NSInteger)conversationIdentifier { | 2407 - (NSInteger)conversationIdentifier { |
2395 return reinterpret_cast<NSInteger>(self); | 2408 return reinterpret_cast<NSInteger>(self); |
2396 } | 2409 } |
2397 | 2410 |
2398 // Each RenderWidgetHostViewCocoa has its own input context, but we return | 2411 // Each RenderWidgetHostViewCocoa has its own input context, but we return |
2399 // nil when the caret is in non-editable content or password box to avoid | 2412 // nil when the caret is in non-editable content or password box to avoid |
2400 // making input methods do their work. | 2413 // making input methods do their work. |
2401 - (NSTextInputContext *)inputContext { | 2414 - (NSTextInputContext *)inputContext { |
2402 if (pluginImeIdentifier_ != -1) | 2415 if (focusedPluginIdentifier_ != -1) |
2403 return [[ComplexTextInputPanel sharedComplexTextInputPanel] inputContext]; | 2416 return [[ComplexTextInputPanel sharedComplexTextInputPanel] inputContext]; |
2404 | 2417 |
2405 switch(renderWidgetHostView_->text_input_type_) { | 2418 switch(renderWidgetHostView_->text_input_type_) { |
2406 case WebKit::WebTextInputTypeNone: | 2419 case WebKit::WebTextInputTypeNone: |
2407 case WebKit::WebTextInputTypePassword: | 2420 case WebKit::WebTextInputTypePassword: |
2408 return nil; | 2421 return nil; |
2409 default: | 2422 default: |
2410 return [super inputContext]; | 2423 return [super inputContext]; |
2411 } | 2424 } |
2412 } | 2425 } |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2625 - (void)confirmComposition { | 2638 - (void)confirmComposition { |
2626 if (!hasMarkedText_) | 2639 if (!hasMarkedText_) |
2627 return; | 2640 return; |
2628 | 2641 |
2629 if (renderWidgetHostView_->render_widget_host_) | 2642 if (renderWidgetHostView_->render_widget_host_) |
2630 renderWidgetHostView_->render_widget_host_->ImeConfirmComposition(); | 2643 renderWidgetHostView_->render_widget_host_->ImeConfirmComposition(); |
2631 | 2644 |
2632 [self cancelComposition]; | 2645 [self cancelComposition]; |
2633 } | 2646 } |
2634 | 2647 |
2635 - (void)setPluginImeEnabled:(BOOL)enabled forPlugin:(int)pluginId { | 2648 - (void)setPluginImeActive:(BOOL)active { |
2636 if ((enabled && pluginId == pluginImeIdentifier_) || | 2649 if (active == pluginImeActive_) |
2637 (!enabled && pluginId != pluginImeIdentifier_)) | |
2638 return; | 2650 return; |
2639 | 2651 |
2640 // If IME was already active then either it is being cancelled, or the plugin | 2652 pluginImeActive_ = active; |
2641 // changed; either way the current input needs to be cleared. | 2653 if (!active) { |
2642 if (pluginImeIdentifier_ != -1) | 2654 [[ComplexTextInputPanel sharedComplexTextInputPanel] cancelComposition]; |
2643 [[ComplexTextInputPanel sharedComplexTextInputPanel] cancelInput]; | 2655 renderWidgetHostView_->PluginImeCompositionCompleted( |
| 2656 string16(), focusedPluginIdentifier_); |
| 2657 } |
| 2658 } |
2644 | 2659 |
2645 pluginImeIdentifier_ = enabled ? pluginId : -1; | 2660 - (void)pluginFocusChanged:(BOOL)focused forPlugin:(int)pluginId { |
| 2661 if (focused) |
| 2662 focusedPluginIdentifier_ = pluginId; |
| 2663 else if (focusedPluginIdentifier_ == pluginId) |
| 2664 focusedPluginIdentifier_ = -1; |
| 2665 |
| 2666 // Whenever plugin focus changes, plugin IME resets. |
| 2667 [self setPluginImeActive:NO]; |
2646 } | 2668 } |
2647 | 2669 |
2648 - (BOOL)postProcessEventForPluginIme:(NSEvent*)event { | 2670 - (BOOL)postProcessEventForPluginIme:(NSEvent*)event { |
2649 if (pluginImeIdentifier_ == -1) | 2671 if (!pluginImeActive_) |
2650 return false; | |
2651 | |
2652 // ComplexTextInputPanel only works on 10.6+. | |
2653 static BOOL sImeSupported = NO; | |
2654 static BOOL sHaveCheckedSupport = NO; | |
2655 if (!sHaveCheckedSupport) { | |
2656 int32 major, minor, bugfix; | |
2657 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); | |
2658 sImeSupported = major > 10 || (major == 10 && minor > 5); | |
2659 sHaveCheckedSupport = YES; | |
2660 } | |
2661 if (!sImeSupported) | |
2662 return false; | 2672 return false; |
2663 | 2673 |
2664 ComplexTextInputPanel* inputPanel = | 2674 ComplexTextInputPanel* inputPanel = |
2665 [ComplexTextInputPanel sharedComplexTextInputPanel]; | 2675 [ComplexTextInputPanel sharedComplexTextInputPanel]; |
2666 NSString* composited_string = nil; | 2676 NSString* composited_string = nil; |
2667 BOOL handled = [inputPanel interpretKeyEvent:event | 2677 BOOL handled = [inputPanel interpretKeyEvent:event |
2668 string:&composited_string]; | 2678 string:&composited_string]; |
2669 if (composited_string) { | 2679 if (composited_string) { |
2670 renderWidgetHostView_->PluginImeCompositionConfirmed( | 2680 renderWidgetHostView_->PluginImeCompositionCompleted( |
2671 base::SysNSStringToUTF16(composited_string), pluginImeIdentifier_); | 2681 base::SysNSStringToUTF16(composited_string), focusedPluginIdentifier_); |
| 2682 pluginImeActive_ = NO; |
2672 } | 2683 } |
2673 return handled; | 2684 return handled; |
2674 } | 2685 } |
2675 | 2686 |
| 2687 - (void)checkForPluginImeCancellation { |
| 2688 if (pluginImeActive_ && |
| 2689 ![[ComplexTextInputPanel sharedComplexTextInputPanel] inComposition]) { |
| 2690 renderWidgetHostView_->PluginImeCompositionCompleted( |
| 2691 string16(), focusedPluginIdentifier_); |
| 2692 pluginImeActive_ = NO; |
| 2693 } |
| 2694 } |
| 2695 |
2676 - (ViewID)viewID { | 2696 - (ViewID)viewID { |
2677 return VIEW_ID_TAB_CONTAINER_FOCUS_VIEW; | 2697 return VIEW_ID_TAB_CONTAINER_FOCUS_VIEW; |
2678 } | 2698 } |
2679 | 2699 |
2680 // Overriding a NSResponder method to support application services. | 2700 // Overriding a NSResponder method to support application services. |
2681 | 2701 |
2682 - (id)validRequestorForSendType:(NSString*)sendType | 2702 - (id)validRequestorForSendType:(NSString*)sendType |
2683 returnType:(NSString*)returnType { | 2703 returnType:(NSString*)returnType { |
2684 id requestor = nil; | 2704 id requestor = nil; |
2685 BOOL sendTypeIsString = [sendType isEqual:NSStringPboardType]; | 2705 BOOL sendTypeIsString = [sendType isEqual:NSStringPboardType]; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2725 if (!string) return NO; | 2745 if (!string) return NO; |
2726 | 2746 |
2727 // If the user is currently using an IME, confirm the IME input, | 2747 // If the user is currently using an IME, confirm the IME input, |
2728 // and then insert the text from the service, the same as TextEdit and Safari. | 2748 // and then insert the text from the service, the same as TextEdit and Safari. |
2729 [self confirmComposition]; | 2749 [self confirmComposition]; |
2730 [self insertText:string]; | 2750 [self insertText:string]; |
2731 return YES; | 2751 return YES; |
2732 } | 2752 } |
2733 | 2753 |
2734 @end | 2754 @end |
OLD | NEW |