OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "chrome/browser/renderer_host/render_widget_host_view_mac.h" | 5 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" |
6 | 6 |
7 #include "base/histogram.h" | 7 #include "base/histogram.h" |
8 #include "base/sys_string_conversions.h" | 8 #include "base/sys_string_conversions.h" |
9 #include "chrome/browser/browser_trial.h" | 9 #include "chrome/browser/browser_trial.h" |
10 #import "chrome/browser/cocoa/rwhvm_editcommand_helper.h" | 10 #import "chrome/browser/cocoa/rwhvm_editcommand_helper.h" |
11 #include "chrome/browser/renderer_host/backing_store.h" | 11 #include "chrome/browser/renderer_host/backing_store.h" |
12 #include "chrome/browser/renderer_host/render_process_host.h" | 12 #include "chrome/browser/renderer_host/render_process_host.h" |
13 #include "chrome/browser/renderer_host/render_widget_host.h" | 13 #include "chrome/browser/renderer_host/render_widget_host.h" |
14 #include "chrome/common/native_web_keyboard_event.h" | 14 #include "chrome/common/native_web_keyboard_event.h" |
15 #include "skia/ext/platform_canvas.h" | 15 #include "skia/ext/platform_canvas.h" |
16 #import "third_party/mozilla/include/ToolTip.h" | |
17 #include "webkit/api/public/mac/WebInputEventFactory.h" | 16 #include "webkit/api/public/mac/WebInputEventFactory.h" |
18 #include "webkit/api/public/WebInputEvent.h" | 17 #include "webkit/api/public/WebInputEvent.h" |
19 #include "webkit/glue/webmenurunner_mac.h" | 18 #include "webkit/glue/webmenurunner_mac.h" |
20 | 19 |
21 using WebKit::WebInputEventFactory; | 20 using WebKit::WebInputEventFactory; |
22 using WebKit::WebMouseEvent; | 21 using WebKit::WebMouseEvent; |
23 using WebKit::WebMouseWheelEvent; | 22 using WebKit::WebMouseWheelEvent; |
24 | 23 |
25 @interface RenderWidgetHostViewCocoa (Private) | 24 @interface RenderWidgetHostViewCocoa (Private) |
26 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; | 25 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 | 100 |
102 void RenderWidgetHostViewMac::WasHidden() { | 101 void RenderWidgetHostViewMac::WasHidden() { |
103 if (is_hidden_) | 102 if (is_hidden_) |
104 return; | 103 return; |
105 | 104 |
106 // If we receive any more paint messages while we are hidden, we want to | 105 // If we receive any more paint messages while we are hidden, we want to |
107 // ignore them so we don't re-allocate the backing store. We will paint | 106 // ignore them so we don't re-allocate the backing store. We will paint |
108 // everything again when we become selected again. | 107 // everything again when we become selected again. |
109 is_hidden_ = true; | 108 is_hidden_ = true; |
110 | 109 |
111 // We can't have tooltips floating around after the tools they're tipping | |
112 // about are hidden, can we? | |
113 tooltip_.reset(NULL); | |
114 tooltip_text_.clear(); | |
115 | |
116 // If we have a renderer, then inform it that we are being hidden so it can | 110 // If we have a renderer, then inform it that we are being hidden so it can |
117 // reduce its resource utilization. | 111 // reduce its resource utilization. |
118 render_widget_host_->WasHidden(); | 112 render_widget_host_->WasHidden(); |
119 } | 113 } |
120 | 114 |
121 void RenderWidgetHostViewMac::SetSize(const gfx::Size& size) { | 115 void RenderWidgetHostViewMac::SetSize(const gfx::Size& size) { |
122 if (is_hidden_) | 116 if (is_hidden_) |
123 return; | 117 return; |
124 | 118 |
125 // TODO(avi): the TabContents object uses this method to size the newly | 119 // TODO(avi): the TabContents object uses this method to size the newly |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 // We get this call just before |render_widget_host_| deletes | 254 // We get this call just before |render_widget_host_| deletes |
261 // itself. But we are owned by |cocoa_view_|, which may be retained | 255 // itself. But we are owned by |cocoa_view_|, which may be retained |
262 // by some other code. Examples are TabContentsViewMac's | 256 // by some other code. Examples are TabContentsViewMac's |
263 // |latent_focus_view_| and TabWindowController's | 257 // |latent_focus_view_| and TabWindowController's |
264 // |cachedContentView_|. | 258 // |cachedContentView_|. |
265 render_widget_host_ = NULL; | 259 render_widget_host_ = NULL; |
266 } | 260 } |
267 | 261 |
268 // Called from the renderer to tell us what the tooltip text should be. It | 262 // Called from the renderer to tell us what the tooltip text should be. It |
269 // calls us frequently so we need to cache the value to prevent doing a lot | 263 // calls us frequently so we need to cache the value to prevent doing a lot |
270 // of repeat work. We cannot simply use [-NSView setToolTip:] because NSView | 264 // of repeat work. |
271 // can't handle the case where the tooltip text changes while the mouse is | |
272 // still inside the view. Since the page elements that get tooltips are all | |
273 // contained within this view (and are unknown to the NSView system), we | |
274 // are forced to implement our own tooltips with child windows. | |
275 // TODO(pinkerton): Do we want these tooltips to time out after a certain time? | |
276 // Gecko does this automatically in the back-end, hence the ToolTip class not | |
277 // needing that functionality. We can either modify ToolTip or add this | |
278 // functionality here with a timer. | |
279 // TODO(pinkerton): This code really needs to live at a higher level because | |
280 // right now it allows multiple views in multiple tabs to each be displaying | |
281 // a tooltip simultaneously (http://crbug.com/14178). | |
282 void RenderWidgetHostViewMac::SetTooltipText(const std::wstring& tooltip_text) { | 265 void RenderWidgetHostViewMac::SetTooltipText(const std::wstring& tooltip_text) { |
283 if (tooltip_text != tooltip_text_ && [[cocoa_view_ window] isKeyWindow]) { | 266 if (tooltip_text != tooltip_text_ && [[cocoa_view_ window] isKeyWindow]) { |
284 tooltip_text_ = tooltip_text; | 267 tooltip_text_ = tooltip_text; |
285 | 268 |
286 // Clamp the tooltip length to kMaxTooltipLength. It's a DOS issue on | 269 // Clamp the tooltip length to kMaxTooltipLength. It's a DOS issue on |
287 // Windows; we're just trying to be polite. Don't persist the trimmed | 270 // Windows; we're just trying to be polite. Don't persist the trimmed |
288 // string, as then the comparison above will always fail and we'll try to | 271 // string, as then the comparison above will always fail and we'll try to |
289 // set it again every single time the mouse moves. | 272 // set it again every single time the mouse moves. |
290 std::wstring display_text = tooltip_text_; | 273 std::wstring display_text = tooltip_text_; |
291 if (tooltip_text_.length() > kMaxTooltipLength) | 274 if (tooltip_text_.length() > kMaxTooltipLength) |
292 display_text = tooltip_text_.substr(0, kMaxTooltipLength); | 275 display_text = tooltip_text_.substr(0, kMaxTooltipLength); |
293 | 276 |
294 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); | 277 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); |
295 if ([tooltip_nsstring length] == 0) { | 278 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; |
296 tooltip_.reset(NULL); // The dtor closes the tooltip. | |
297 } else { | |
298 // Get the current mouse location in the window's coordinate system and | |
299 // use that as the point for displaying the tooltip. | |
300 if (!tooltip_.get()) | |
301 tooltip_.reset([[ToolTip alloc] init]); | |
302 NSPoint event_point = | |
303 [[cocoa_view_ window] mouseLocationOutsideOfEventStream]; | |
304 [tooltip_ showToolTipAtPoint:event_point | |
305 withString:tooltip_nsstring | |
306 overWindow:[cocoa_view_ window]]; | |
307 } | |
308 } | 279 } |
309 } | 280 } |
310 | 281 |
311 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( | 282 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( |
312 const gfx::Size& size) { | 283 const gfx::Size& size) { |
313 return new BackingStore(render_widget_host_, size); | 284 return new BackingStore(render_widget_host_, size); |
314 } | 285 } |
315 | 286 |
316 // Display a popup menu for WebKit using Cocoa widgets. | 287 // Display a popup menu for WebKit using Cocoa widgets. |
317 void RenderWidgetHostViewMac::ShowPopupWithItems( | 288 void RenderWidgetHostViewMac::ShowPopupWithItems( |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 &RenderWidgetHostViewMac::ShutdownHost)); | 331 &RenderWidgetHostViewMac::ShutdownHost)); |
361 } | 332 } |
362 } | 333 } |
363 | 334 |
364 void RenderWidgetHostViewMac::ShutdownHost() { | 335 void RenderWidgetHostViewMac::ShutdownHost() { |
365 shutdown_factory_.RevokeAll(); | 336 shutdown_factory_.RevokeAll(); |
366 render_widget_host_->Shutdown(); | 337 render_widget_host_->Shutdown(); |
367 // Do not touch any members at this point, |this| has been deleted. | 338 // Do not touch any members at this point, |this| has been deleted. |
368 } | 339 } |
369 | 340 |
| 341 |
| 342 |
| 343 // RenderWidgetHostViewCocoa --------------------------------------------------- |
| 344 |
370 @implementation RenderWidgetHostViewCocoa | 345 @implementation RenderWidgetHostViewCocoa |
371 | 346 |
372 // Tons of stuff goes here, where we grab events going on in Cocoaland and send | 347 // Tons of stuff goes here, where we grab events going on in Cocoaland and send |
373 // them into the C++ system. TODO(avi): all that jazz | 348 // them into the C++ system. TODO(avi): all that jazz |
374 | 349 |
375 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { | 350 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { |
376 self = [super initWithFrame:NSZeroRect]; | 351 self = [super initWithFrame:NSZeroRect]; |
377 if (self != nil) { | 352 if (self != nil) { |
378 editCommand_helper_.reset(new RWHVMEditCommandHelper); | 353 editCommand_helper_.reset(new RWHVMEditCommandHelper); |
379 editCommand_helper_->AddEditingSelectorsToClass([self class]); | 354 editCommand_helper_->AddEditingSelectorsToClass([self class]); |
380 | 355 |
381 renderWidgetHostView_ = r; | 356 renderWidgetHostView_ = r; |
382 canBeKeyView_ = YES; | 357 canBeKeyView_ = YES; |
383 closeOnDeactivate_ = NO; | 358 closeOnDeactivate_ = NO; |
384 } | 359 } |
385 return self; | 360 return self; |
386 } | 361 } |
387 | 362 |
388 - (void)dealloc { | 363 - (void)dealloc { |
389 delete renderWidgetHostView_; | 364 delete renderWidgetHostView_; |
| 365 [toolTip_ release]; |
390 | 366 |
391 [super dealloc]; | 367 [super dealloc]; |
392 } | 368 } |
393 | 369 |
394 - (void)setCanBeKeyView:(BOOL)can { | 370 - (void)setCanBeKeyView:(BOOL)can { |
395 canBeKeyView_ = can; | 371 canBeKeyView_ = can; |
396 } | 372 } |
397 | 373 |
398 - (void)setCloseOnDeactivate:(BOOL)b { | 374 - (void)setCloseOnDeactivate:(BOOL)b { |
399 closeOnDeactivate_ = b; | 375 closeOnDeactivate_ = b; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
563 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { | 539 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { |
564 SEL action = [item action]; | 540 SEL action = [item action]; |
565 | 541 |
566 return editCommand_helper_->IsMenuItemEnabled(action, self); | 542 return editCommand_helper_->IsMenuItemEnabled(action, self); |
567 } | 543 } |
568 | 544 |
569 - (RenderWidgetHostViewMac*)renderWidgetHostViewMac { | 545 - (RenderWidgetHostViewMac*)renderWidgetHostViewMac { |
570 return renderWidgetHostView_; | 546 return renderWidgetHostView_; |
571 } | 547 } |
572 | 548 |
| 549 |
| 550 // Below is the nasty tooltip stuff -- copied from WebKit's WebHTMLView.mm |
| 551 // with minor modifications for code style and commenting. |
| 552 // |
| 553 // The 'public' interface is -setToolTipAtMousePoint:. This differs from |
| 554 // -setToolTip: in that the updated tooltip takes effect immediately, |
| 555 // without the user's having to move the mouse out of and back into the view. |
| 556 // |
| 557 // Unfortunately, doing this requires sending fake mouseEnter/Exit events to |
| 558 // the view, which in turn requires overriding some internal tracking-rect |
| 559 // methods (to keep track of its owner & userdata, which need to be filled out |
| 560 // in the fake events.) --snej 7/6/09 |
| 561 |
| 562 |
| 563 /* |
| 564 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. |
| 565 * (C) 2006, 2007 Graham Dennis (graham.dennis@gmail.com) |
| 566 * |
| 567 * Redistribution and use in source and binary forms, with or without |
| 568 * modification, are permitted provided that the following conditions |
| 569 * are met: |
| 570 * |
| 571 * 1. Redistributions of source code must retain the above copyright |
| 572 * notice, this list of conditions and the following disclaimer. |
| 573 * 2. Redistributions in binary form must reproduce the above copyright |
| 574 * notice, this list of conditions and the following disclaimer in the |
| 575 * documentation and/or other materials provided with the distribution. |
| 576 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| 577 * its contributors may be used to endorse or promote products derived |
| 578 * from this software without specific prior written permission. |
| 579 * |
| 580 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 581 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 582 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 583 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 584 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 585 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 586 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 587 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 588 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 589 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 590 */ |
| 591 |
| 592 // Any non-zero value will do, but using something recognizable might help us |
| 593 // debug some day. |
| 594 static const NSTrackingRectTag kTrackingRectTag = 0xBADFACE; |
| 595 |
| 596 // Override of a public NSView method, replacing the inherited functionality. |
| 597 // See above for rationale. |
| 598 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect |
| 599 owner:(id)owner |
| 600 userData:(void *)data |
| 601 assumeInside:(BOOL)assumeInside { |
| 602 DCHECK(trackingRectOwner_ == nil); |
| 603 trackingRectOwner_ = owner; |
| 604 trackingRectUserData_ = data; |
| 605 return kTrackingRectTag; |
| 606 } |
| 607 |
| 608 // Override of (apparently) a private NSView method(!) See above for rationale. |
| 609 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect |
| 610 owner:(id)owner |
| 611 userData:(void *)data |
| 612 assumeInside:(BOOL)assumeInside |
| 613 useTrackingNum:(int)tag { |
| 614 DCHECK(tag == 0 || tag == kTrackingRectTag); |
| 615 DCHECK(trackingRectOwner_ == nil); |
| 616 trackingRectOwner_ = owner; |
| 617 trackingRectUserData_ = data; |
| 618 return kTrackingRectTag; |
| 619 } |
| 620 |
| 621 // Override of (apparently) a private NSView method(!) See above for rationale. |
| 622 - (void)_addTrackingRects:(NSRect *)rects |
| 623 owner:(id)owner |
| 624 userDataList:(void **)userDataList |
| 625 assumeInsideList:(BOOL *)assumeInsideList |
| 626 trackingNums:(NSTrackingRectTag *)trackingNums |
| 627 count:(int)count { |
| 628 DCHECK(count == 1); |
| 629 DCHECK(trackingNums[0] == 0 || trackingNums[0] == kTrackingRectTag); |
| 630 DCHECK(trackingRectOwner_ == nil); |
| 631 trackingRectOwner_ = owner; |
| 632 trackingRectUserData_ = userDataList[0]; |
| 633 trackingNums[0] = kTrackingRectTag; |
| 634 } |
| 635 |
| 636 // Override of a public NSView method, replacing the inherited functionality. |
| 637 // See above for rationale. |
| 638 - (void)removeTrackingRect:(NSTrackingRectTag)tag { |
| 639 if (tag == 0) |
| 640 return; |
| 641 |
| 642 if (tag == kTrackingRectTag) { |
| 643 trackingRectOwner_ = nil; |
| 644 return; |
| 645 } |
| 646 |
| 647 if (tag == lastToolTipTag_) { |
| 648 [super removeTrackingRect:tag]; |
| 649 lastToolTipTag_ = 0; |
| 650 return; |
| 651 } |
| 652 |
| 653 // If any other tracking rect is being removed, we don't know how it was |
| 654 // created and it's possible there's a leak involved (see Radar 3500217). |
| 655 NOTREACHED(); |
| 656 } |
| 657 |
| 658 // Override of (apparently) a private NSView method(!) |
| 659 - (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count { |
| 660 for (int i = 0; i < count; ++i) { |
| 661 int tag = tags[i]; |
| 662 if (tag == 0) |
| 663 continue; |
| 664 DCHECK(tag == kTrackingRectTag); |
| 665 trackingRectOwner_ = nil; |
| 666 } |
| 667 } |
| 668 |
| 669 // Sends a fake NSMouseExited event to the view for its current tracking rect. |
| 670 - (void)_sendToolTipMouseExited { |
| 671 // Nothing matters except window, trackingNumber, and userData. |
| 672 int windowNumber = [[self window] windowNumber]; |
| 673 NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited |
| 674 location:NSMakePoint(0, 0) |
| 675 modifierFlags:0 |
| 676 timestamp:0 |
| 677 windowNumber:windowNumber |
| 678 context:NULL |
| 679 eventNumber:0 |
| 680 trackingNumber:kTrackingRectTag |
| 681 userData:trackingRectUserData_]; |
| 682 [trackingRectOwner_ mouseExited:fakeEvent]; |
| 683 } |
| 684 |
| 685 // Sends a fake NSMouseEntered event to the view for its current tracking rect. |
| 686 - (void)_sendToolTipMouseEntered { |
| 687 // Nothing matters except window, trackingNumber, and userData. |
| 688 int windowNumber = [[self window] windowNumber]; |
| 689 NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered |
| 690 location:NSMakePoint(0, 0) |
| 691 modifierFlags:0 |
| 692 timestamp:0 |
| 693 windowNumber:windowNumber |
| 694 context:NULL |
| 695 eventNumber:0 |
| 696 trackingNumber:kTrackingRectTag |
| 697 userData:trackingRectUserData_]; |
| 698 [trackingRectOwner_ mouseEntered:fakeEvent]; |
| 699 } |
| 700 |
| 701 // Sets the view's current tooltip, to be displayed at the current mouse |
| 702 // location. (This does not make the tooltip appear -- as usual, it only |
| 703 // appears after a delay.) Pass null to remove the tooltip. |
| 704 - (void)setToolTipAtMousePoint:(NSString *)string { |
| 705 NSString *toolTip = [string length] == 0 ? nil : string; |
| 706 NSString *oldToolTip = toolTip_; |
| 707 if ((toolTip == nil || oldToolTip == nil) ? toolTip == oldToolTip |
| 708 : [toolTip isEqualToString:oldToolTip]) { |
| 709 return; |
| 710 } |
| 711 if (oldToolTip) { |
| 712 [self _sendToolTipMouseExited]; |
| 713 [oldToolTip release]; |
| 714 } |
| 715 toolTip_ = [toolTip copy]; |
| 716 if (toolTip) { |
| 717 // See radar 3500217 for why we remove all tooltips |
| 718 // rather than just the single one we created. |
| 719 [self removeAllToolTips]; |
| 720 NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000); |
| 721 lastToolTipTag_ = [self addToolTipRect:wideOpenRect |
| 722 owner:self |
| 723 userData:NULL]; |
| 724 [self _sendToolTipMouseEntered]; |
| 725 } |
| 726 } |
| 727 |
| 728 // NSView calls this to get the text when displaying the tooltip. |
| 729 - (NSString *)view:(NSView *)view |
| 730 stringForToolTip:(NSToolTipTag)tag |
| 731 point:(NSPoint)point |
| 732 userData:(void *)data { |
| 733 return [[toolTip_ copy] autorelease]; |
| 734 } |
| 735 |
573 @end | 736 @end |
574 | 737 |
OLD | NEW |