PageRenderTime 70ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/widget/src/cocoa/nsChildView.mm

https://bitbucket.org/mkato/mozilla-1.9.0-win64
Objective C++ | 6236 lines | 4337 code | 1171 blank | 728 comment | 628 complexity | e15973147b4c5196df4c65f4aeea1434 MD5 | raw file
Possible License(s): LGPL-3.0, MIT, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /* -*- Mode: objc; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License
  6. * Version 1.1 (the "License"); you may not use this file except in
  7. * compliance with the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is mozilla.org code.
  16. *
  17. * The Initial Developer of the Original Code is
  18. * Netscape Communications Corporation.
  19. * Portions created by the Initial Developer are Copyright (C) 1998
  20. * the Initial Developer. All Rights Reserved.
  21. *
  22. * Contributor(s):
  23. * Josh Aas <josh@mozilla.com>
  24. * Mark Mentovai <mark@moxienet.com>
  25. * H?kan Waara <hwaara@gmail.com>
  26. * Stuart Morgan <stuart.morgan@alumni.case.edu>
  27. * Mats Palmgren <mats.palmgren@bredband.net>
  28. *
  29. * Alternatively, the contents of this file may be used under the terms of
  30. * either the GNU General Public License Version 2 or later (the "GPL"), or
  31. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  32. * in which case the provisions of the GPL or the LGPL are applicable instead
  33. * of those above. If you wish to allow use of your version of this file only
  34. * under the terms of either the GPL or the LGPL, and not to allow others to
  35. * use your version of this file under the terms of the MPL, indicate your
  36. * decision by deleting the provisions above and replace them with the notice
  37. * and other provisions required by the GPL or the LGPL. If you do not delete
  38. * the provisions above, a recipient may use your version of this file under
  39. * the terms of any one of the MPL, the GPL or the LGPL.
  40. *
  41. * ***** END LICENSE BLOCK ***** */
  42. #include <unistd.h>
  43. #include "nsChildView.h"
  44. #include "nsCocoaWindow.h"
  45. #include "nsObjCExceptions.h"
  46. #include "nsCOMPtr.h"
  47. #include "nsToolkit.h"
  48. #include "nsCRT.h"
  49. #include "nsplugindefs.h"
  50. #include "nsIPrefService.h"
  51. #include "nsIPrefBranch.h"
  52. #include "nsIFontMetrics.h"
  53. #include "nsIDeviceContext.h"
  54. #include "nsIRegion.h"
  55. #include "nsIRollupListener.h"
  56. #include "nsIScrollableView.h"
  57. #include "nsIViewManager.h"
  58. #include "nsIInterfaceRequestor.h"
  59. #include "nsIServiceManager.h"
  60. #include "nsILocalFile.h"
  61. #include "nsILocalFileMac.h"
  62. #include "nsGfxCIID.h"
  63. #include "nsIMenuRollup.h"
  64. #include "nsDragService.h"
  65. #include "nsCursorManager.h"
  66. #include "nsWindowMap.h"
  67. #include "nsCocoaUtils.h"
  68. #include "nsMenuBarX.h"
  69. #include "gfxContext.h"
  70. #include "gfxQuartzSurface.h"
  71. #include <dlfcn.h>
  72. #undef DEBUG_IME
  73. #undef DEBUG_UPDATE
  74. #undef INVALIDATE_DEBUGGING // flash areas as they are invalidated
  75. #ifdef MOZ_LOGGING
  76. #define FORCE_PR_LOG
  77. #endif
  78. #include "prlog.h"
  79. #ifdef PR_LOGGING
  80. PRLogModuleInfo* sCocoaLog = nsnull;
  81. #endif
  82. // npapi.h defines NPEventType_AdjustCursorEvent but we don't want to include npapi.h here.
  83. // We need to send this in the "what" field for certain native plugin events. WebKit does
  84. // this as well.
  85. #define adjustCursorEvent 33
  86. extern "C" {
  87. CG_EXTERN void CGContextResetCTM(CGContextRef);
  88. CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
  89. CG_EXTERN void CGContextResetClip(CGContextRef);
  90. }
  91. #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
  92. struct __TISInputSource;
  93. typedef __TISInputSource* TISInputSourceRef;
  94. #endif
  95. TISInputSourceRef (*Leopard_TISCopyCurrentKeyboardLayoutInputSource)() = NULL;
  96. void* (*Leopard_TISGetInputSourceProperty)(TISInputSourceRef inputSource, CFStringRef propertyKey) = NULL;
  97. CFArrayRef (*Leopard_TISCreateInputSourceList)(CFDictionaryRef properties, Boolean includeAllInstalled) = NULL;
  98. CFStringRef kOurTISPropertyUnicodeKeyLayoutData = NULL;
  99. CFStringRef kOurTISPropertyInputSourceID = NULL;
  100. extern PRBool gCocoaWindowMethodsSwizzled; // Defined in nsCocoaWindow.mm
  101. extern nsISupportsArray *gDraggedTransferables;
  102. PRBool nsTSMManager::sIsIMEEnabled = PR_TRUE;
  103. PRBool nsTSMManager::sIsRomanKeyboardsOnly = PR_FALSE;
  104. PRBool nsTSMManager::sIgnoreCommit = PR_FALSE;
  105. NSView<mozView>* nsTSMManager::sComposingView = nsnull;
  106. TSMDocumentID nsTSMManager::sDocumentID = nsnull;
  107. NSString* nsTSMManager::sComposingString = nsnull;
  108. static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
  109. static NSView* sLastViewEntered = nil;
  110. #ifdef INVALIDATE_DEBUGGING
  111. static void blinkRect(Rect* r);
  112. static void blinkRgn(RgnHandle rgn);
  113. #endif
  114. nsIRollupListener * gRollupListener = nsnull;
  115. nsIWidget * gRollupWidget = nsnull;
  116. @interface ChildView(Private)
  117. // sets up our view, attaching it to its owning gecko view
  118. - (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild;
  119. // sends gecko an ime composition event
  120. - (nsRect) sendCompositionEvent:(PRInt32)aEventType;
  121. // sends gecko an ime text event
  122. - (void) sendTextEvent:(PRUnichar*) aBuffer
  123. attributedString:(NSAttributedString*) aString
  124. selectedRange:(NSRange)selRange
  125. markedRange:(NSRange)markRange
  126. doCommit:(BOOL)doCommit;
  127. // do generic gecko event setup with a generic cocoa event. accepts nil inEvent.
  128. - (void) convertGenericCocoaEvent:(NSEvent*)inEvent toGeckoEvent:(nsInputEvent*)outGeckoEvent;
  129. // set up a gecko mouse event based on a cocoa mouse event
  130. - (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent toGeckoEvent:(nsInputEvent*)outGeckoEvent;
  131. // set up a gecko key event based on a cocoa key event
  132. - (void) convertCocoaKeyEvent:(NSEvent*)aKeyEvent toGeckoEvent:(nsKeyEvent*)outGeckoEvent;
  133. - (NSMenu*)contextMenu;
  134. - (TopLevelWindowData*)ensureWindowData;
  135. - (void)setIsPluginView:(BOOL)aIsPlugin;
  136. - (BOOL)isPluginView;
  137. - (BOOL)childViewHasPlugin;
  138. - (BOOL)isRectObscuredBySubview:(NSRect)inRect;
  139. - (void)processPendingRedraws;
  140. - (PRBool)processKeyDownEvent:(NSEvent*)theEvent keyEquiv:(BOOL)isKeyEquiv;
  141. - (BOOL)ensureCorrectMouseEventTarget:(NSEvent *)anEvent;
  142. - (void)maybeInitContextMenuTracking;
  143. + (NSEvent*)makeNewCocoaEventWithType:(NSEventType)type fromEvent:(NSEvent*)theEvent;
  144. #if USE_CLICK_HOLD_CONTEXTMENU
  145. // called on a timer two seconds after a mouse down to see if we should display
  146. // a context menu (click-hold)
  147. - (void)clickHoldCallback:(id)inEvent;
  148. #endif
  149. #ifdef ACCESSIBILITY
  150. - (id<mozAccessible>)accessible;
  151. #endif
  152. @end
  153. #pragma mark -
  154. /* Convenience routines to go from a gecko rect to cocoa NSRects and back
  155. *
  156. * Gecko rects (nsRect) contain an origin (x,y) in a coordinate
  157. * system with (0,0) in the top-left of the screen. Cocoa rects
  158. * (NSRect) contain an origin (x,y) in a coordinate system with
  159. * (0,0) in the bottom-left of the screen. Both nsRect and NSRect
  160. * contain width/height info, with no difference in their use.
  161. * If a Cocoa rect is from a flipped view, there is no need to
  162. * convert coordinate systems.
  163. */
  164. static inline void
  165. GeckoRectToNSRect(const nsRect & inGeckoRect, NSRect & outCocoaRect)
  166. {
  167. outCocoaRect.origin.x = inGeckoRect.x;
  168. outCocoaRect.origin.y = inGeckoRect.y;
  169. outCocoaRect.size.width = inGeckoRect.width;
  170. outCocoaRect.size.height = inGeckoRect.height;
  171. }
  172. static inline void
  173. NSRectToGeckoRect(const NSRect & inCocoaRect, nsRect & outGeckoRect)
  174. {
  175. outGeckoRect.x = static_cast<nscoord>(inCocoaRect.origin.x);
  176. outGeckoRect.y = static_cast<nscoord>(inCocoaRect.origin.y);
  177. outGeckoRect.width = static_cast<nscoord>(inCocoaRect.size.width);
  178. outGeckoRect.height = static_cast<nscoord>(inCocoaRect.size.height);
  179. }
  180. static inline void
  181. ConvertGeckoRectToMacRect(const nsRect& aRect, Rect& outMacRect)
  182. {
  183. outMacRect.left = aRect.x;
  184. outMacRect.top = aRect.y;
  185. outMacRect.right = aRect.x + aRect.width;
  186. outMacRect.bottom = aRect.y + aRect.height;
  187. }
  188. // Flips a screen coordinate from a point in the cocoa coordinate system (bottom-left rect) to a point
  189. // that is a "flipped" cocoa coordinate system (starts in the top-left).
  190. static inline void
  191. FlipCocoaScreenCoordinate (NSPoint &inPoint)
  192. {
  193. inPoint.y = nsCocoaUtils::FlippedScreenY(inPoint.y);
  194. }
  195. static PRUint32
  196. UnderlineAttributeToTextRangeType(PRUint32 aUnderlineStyle, NSRange selRange)
  197. {
  198. #ifdef DEBUG_IME
  199. NSLog(@"****in underlineAttributeToTextRangeType = %d", aUnderlineStyle);
  200. #endif
  201. // For more info on the underline attribute, please see:
  202. // http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/AttributedStrings/Tasks/AccessingAttrs.html
  203. // We are not clear where the define for value 2 is right now.
  204. // To see this value in japanese ime, type 'aaaaaaaaa' and hit space to make the
  205. // ime send you some part of text in 1 (NSSingleUnderlineStyle) and some part in 2.
  206. // ftang will ask apple for more details
  207. //
  208. // it probably means show 1-pixel thickness underline vs 2-pixel thickness
  209. PRUint32 attr;
  210. if (selRange.length == 0) {
  211. switch (aUnderlineStyle) {
  212. case 1:
  213. attr = NS_TEXTRANGE_RAWINPUT;
  214. break;
  215. case 2:
  216. default:
  217. attr = NS_TEXTRANGE_SELECTEDRAWTEXT;
  218. break;
  219. }
  220. }
  221. else {
  222. switch (aUnderlineStyle) {
  223. case 1:
  224. attr = NS_TEXTRANGE_CONVERTEDTEXT;
  225. break;
  226. case 2:
  227. default:
  228. attr = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
  229. break;
  230. }
  231. }
  232. return attr;
  233. }
  234. static PRUint32
  235. CountRanges(NSAttributedString *aString)
  236. {
  237. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
  238. // Iterate through aString for the NSUnderlineStyleAttributeName and count the
  239. // different segments adjusting limitRange as we go.
  240. PRUint32 count = 0;
  241. NSRange effectiveRange;
  242. NSRange limitRange = NSMakeRange(0, [aString length]);
  243. while (limitRange.length > 0) {
  244. [aString attribute:NSUnderlineStyleAttributeName
  245. atIndex:limitRange.location
  246. longestEffectiveRange:&effectiveRange
  247. inRange:limitRange];
  248. limitRange = NSMakeRange(NSMaxRange(effectiveRange),
  249. NSMaxRange(limitRange) - NSMaxRange(effectiveRange));
  250. count++;
  251. }
  252. return count;
  253. NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
  254. }
  255. static void
  256. ConvertAttributeToGeckoRange(NSAttributedString *aString, NSRange markRange, NSRange selRange, PRUint32 inCount, nsTextRange* aRanges)
  257. {
  258. NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
  259. // Convert the Cocoa range into the nsTextRange Array used in Gecko.
  260. // Iterate through the attributed string and map the underline attribute to Gecko IME textrange attributes.
  261. // We may need to change the code here if we change the implementation of validAttributesForMarkedText.
  262. PRUint32 i = 0;
  263. NSRange effectiveRange;
  264. NSRange limitRange = NSMakeRange(0, [aString length]);
  265. while ((limitRange.length > 0) && (i < inCount)) {
  266. id attributeValue = [aString attribute:NSUnderlineStyleAttributeName
  267. atIndex:limitRange.location
  268. longestEffectiveRange:&effectiveRange
  269. inRange:limitRange];
  270. aRanges[i].mStartOffset = effectiveRange.location;
  271. aRanges[i].mEndOffset = NSMaxRange(effectiveRange);
  272. aRanges[i].mRangeType = UnderlineAttributeToTextRangeType([attributeValue intValue], selRange);
  273. limitRange = NSMakeRange(NSMaxRange(effectiveRange),
  274. NSMaxRange(limitRange) - NSMaxRange(effectiveRange));
  275. i++;
  276. }
  277. // Get current caret position.
  278. // Caret is indicator of insertion point, so mEndOffset = 0.
  279. aRanges[i].mStartOffset = selRange.location + selRange.length;
  280. aRanges[i].mEndOffset = 0;
  281. aRanges[i].mRangeType = NS_TEXTRANGE_CARETPOSITION;
  282. NS_OBJC_END_TRY_ABORT_BLOCK;
  283. }
  284. static void
  285. FillTextRangeInTextEvent(nsTextEvent *aTextEvent, NSAttributedString* aString, NSRange markRange, NSRange selRange)
  286. {
  287. NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
  288. // Count the number of segments in the attributed string and add one more count for sending current caret position to Gecko.
  289. // Allocate the right size of nsTextRange and draw caret at right position.
  290. // Convert the attributed string into an array of nsTextRange and get current caret position by calling above functions.
  291. PRUint32 count = CountRanges(aString) + 1;
  292. aTextEvent->rangeArray = new nsTextRange[count];
  293. if (aTextEvent->rangeArray) {
  294. aTextEvent->rangeCount = count;
  295. ConvertAttributeToGeckoRange(aString, markRange, selRange, aTextEvent->rangeCount, aTextEvent->rangeArray);
  296. }
  297. NS_OBJC_END_TRY_ABORT_BLOCK;
  298. }
  299. #pragma mark -
  300. nsChildView::nsChildView() : nsBaseWidget()
  301. , mView(nsnull)
  302. , mParentView(nsnull)
  303. , mParentWidget(nsnull)
  304. , mVisible(PR_FALSE)
  305. , mDrawing(PR_FALSE)
  306. , mLiveResizeInProgress(PR_FALSE)
  307. , mIsPluginView(PR_FALSE)
  308. , mPluginDrawing(PR_FALSE)
  309. , mPluginIsCG(PR_FALSE)
  310. , mInSetFocus(PR_FALSE)
  311. {
  312. #ifdef PR_LOGGING
  313. if (!sCocoaLog) {
  314. sCocoaLog = PR_NewLogModule("nsCocoaWidgets");
  315. CFIndex idx;
  316. KLGetKeyboardLayoutCount(&idx);
  317. PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("Keyboard layout configuration:"));
  318. for (CFIndex i = 0; i < idx; ++i) {
  319. KeyboardLayoutRef curKL;
  320. if (KLGetKeyboardLayoutAtIndex(i, &curKL) == noErr) {
  321. CFStringRef name;
  322. if (KLGetKeyboardLayoutProperty(curKL, kKLName, (const void**)&name) == noErr) {
  323. int idn;
  324. KLGetKeyboardLayoutProperty(curKL, kKLIdentifier, (const void**)&idn);
  325. int kind;
  326. KLGetKeyboardLayoutProperty(curKL, kKLKind, (const void**)&kind);
  327. char buf[256];
  328. CFStringGetCString(name, buf, 256, kCFStringEncodingASCII);
  329. PR_LOG(sCocoaLog, PR_LOG_ALWAYS, (" %d,%s,%d\n", idn, buf, kind));
  330. }
  331. }
  332. }
  333. }
  334. #endif
  335. SetBackgroundColor(NS_RGB(255, 255, 255));
  336. SetForegroundColor(NS_RGB(0, 0, 0));
  337. if (nsToolkit::OnLeopardOrLater() && !Leopard_TISCopyCurrentKeyboardLayoutInputSource) {
  338. // This libary would already be open for LMGetKbdType (and probably other
  339. // symbols), so merely using RTLD_DEFAULT in dlsym would be sufficient,
  340. // but man dlsym says: "all mach-o images in the process (except ...) are
  341. // searched in the order they were loaded. This can be a costly search
  342. // and should be avoided."
  343. void* hitoolboxHandle = dlopen("/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox", RTLD_LAZY);
  344. if (hitoolboxHandle) {
  345. *(void **)(&Leopard_TISCopyCurrentKeyboardLayoutInputSource) = dlsym(hitoolboxHandle, "TISCopyCurrentKeyboardLayoutInputSource");
  346. *(void **)(&Leopard_TISGetInputSourceProperty) = dlsym(hitoolboxHandle, "TISGetInputSourceProperty");
  347. *(void **)(&Leopard_TISCreateInputSourceList) = dlsym(hitoolboxHandle, "TISCreateInputSourceList");
  348. kOurTISPropertyUnicodeKeyLayoutData = *static_cast<CFStringRef*>(dlsym(hitoolboxHandle, "kTISPropertyUnicodeKeyLayoutData"));
  349. kOurTISPropertyInputSourceID = *static_cast<CFStringRef*>(dlsym(hitoolboxHandle, "kTISPropertyInputSourceID"));
  350. }
  351. }
  352. }
  353. nsChildView::~nsChildView()
  354. {
  355. // notify the children that we're gone
  356. for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
  357. nsChildView* childView = static_cast<nsChildView*>(kid);
  358. childView->mParentWidget = nsnull;
  359. }
  360. NS_WARN_IF_FALSE(mOnDestroyCalled, "nsChildView object destroyed without calling Destroy()");
  361. // An nsChildView object that was in use can be destroyed without Destroy()
  362. // ever being called on it. So we also need to do a quick, safe cleanup
  363. // here (it's too late to just call Destroy(), which can cause crashes).
  364. // It's particularly important to make sure widgetDestroyed is called on our
  365. // mView -- this method NULLs mView's mGeckoChild, and NULL checks on
  366. // mGeckoChild are used throughout the ChildView class to tell if it's safe
  367. // to use a ChildView object.
  368. [mView widgetDestroyed]; // Safe if mView is nil.
  369. mParentWidget = nil;
  370. TearDownView(); // Safe if called twice.
  371. }
  372. NS_IMPL_ISUPPORTS_INHERITED2(nsChildView, nsBaseWidget, nsIPluginWidget, nsIKBStateControl)
  373. // Utility method for implementing both Create(nsIWidget ...)
  374. // and Create(nsNativeWidget...)
  375. nsresult nsChildView::StandardCreate(nsIWidget *aParent,
  376. const nsRect &aRect,
  377. EVENT_CALLBACK aHandleEventFunction,
  378. nsIDeviceContext *aContext,
  379. nsIAppShell *aAppShell,
  380. nsIToolkit *aToolkit,
  381. nsWidgetInitData *aInitData,
  382. nsNativeWidget aNativeParent)
  383. {
  384. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  385. // See NSWindow (MethodSwizzling) in nsCocoaWindow.mm.
  386. if (!gCocoaWindowMethodsSwizzled) {
  387. nsToolkit::SwizzleMethods([NSWindow class], @selector(sendEvent:),
  388. @selector(nsCocoaWindow_NSWindow_sendEvent:));
  389. gCocoaWindowMethodsSwizzled = PR_TRUE;
  390. }
  391. mBounds = aRect;
  392. BaseCreate(aParent, aRect, aHandleEventFunction,
  393. aContext, aAppShell, aToolkit, aInitData);
  394. // inherit things from the parent view and create our parallel
  395. // NSView in the Cocoa display system
  396. mParentView = nil;
  397. if (aParent) {
  398. SetBackgroundColor(aParent->GetBackgroundColor());
  399. SetForegroundColor(aParent->GetForegroundColor());
  400. // inherit the top-level window. NS_NATIVE_WIDGET is always a NSView
  401. // regardless of if we're asking a window or a view (for compatibility
  402. // with windows).
  403. mParentView = (NSView*)aParent->GetNativeData(NS_NATIVE_WIDGET);
  404. mParentWidget = aParent;
  405. }
  406. else
  407. mParentView = reinterpret_cast<NSView*>(aNativeParent);
  408. // create our parallel NSView and hook it up to our parent. Recall
  409. // that NS_NATIVE_WIDGET is the NSView.
  410. NSRect r;
  411. GeckoRectToNSRect(mBounds, r);
  412. mView = [CreateCocoaView(r) retain];
  413. if (!mView) return NS_ERROR_FAILURE;
  414. #if DEBUG
  415. // if our parent is a popup window, we're most certainly coming from a <select> list dropdown which
  416. // we handle in a different way than other platforms. It's ok that we don't have a parent
  417. // view because we bailed before even creating the cocoa widgetry and as a result, we
  418. // don't need to assert. However, if that's not the case, we definitely want to assert
  419. // to show views aren't getting correctly parented.
  420. if (aParent) {
  421. nsWindowType windowType;
  422. aParent->GetWindowType(windowType);
  423. if (windowType != eWindowType_popup)
  424. NS_ASSERTION(mParentView && mView, "couldn't hook up new NSView in hierarchy");
  425. }
  426. else {
  427. NS_ASSERTION(mParentView && mView, "couldn't hook up new NSView in hierarchy");
  428. }
  429. #endif
  430. // If this view was created in a Gecko view hierarchy, the initial state
  431. // is hidden. If the view is attached only to a native NSView but has
  432. // no Gecko parent (as in embedding), the initial state is visible.
  433. if (mParentWidget)
  434. [mView setHidden:YES];
  435. else
  436. mVisible = PR_TRUE;
  437. // Hook it up in the NSView hierarchy.
  438. if (mParentView) {
  439. NSWindow* window = [mParentView window];
  440. if (!window &&
  441. [mParentView respondsToSelector:@selector(nativeWindow)])
  442. window = [mParentView nativeWindow];
  443. [mView setNativeWindow:window];
  444. [mParentView addSubview:mView];
  445. }
  446. // if this is a ChildView, make sure that our per-window data
  447. // is set up
  448. if ([mView isKindOfClass:[ChildView class]])
  449. [(ChildView*)mView ensureWindowData];
  450. return NS_OK;
  451. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  452. }
  453. // Creates the appropriate child view. Override to create something other than
  454. // our |ChildView| object. Autoreleases, so caller must retain.
  455. NSView*
  456. nsChildView::CreateCocoaView(NSRect inFrame)
  457. {
  458. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
  459. return [[[ChildView alloc] initWithFrame:inFrame geckoChild:this] autorelease];
  460. NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
  461. }
  462. void nsChildView::TearDownView()
  463. {
  464. NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
  465. if (!mView)
  466. return;
  467. NSWindow* win = [mView window];
  468. NSResponder* responder = [win firstResponder];
  469. // We're being unhooked from the view hierarchy, don't leave our view
  470. // or a child view as the window first responder.
  471. if (responder && [responder isKindOfClass:[NSView class]] &&
  472. [(NSView*)responder isDescendantOf:mView]) {
  473. [win makeFirstResponder:[mView superview]];
  474. }
  475. // If mView is win's contentView, win (mView's NSWindow) "owns" mView --
  476. // win has retained mView, and will detach it from the view hierarchy and
  477. // release it when necessary (when win is itself destroyed (in a call to
  478. // [win dealloc])). So all we need to do here is call [mView release] (to
  479. // match the call to [mView retain] in nsChildView::StandardCreate()).
  480. // Also calling [mView removeFromSuperviewWithoutNeedingDisplay] causes
  481. // mView to be released again and dealloced, while remaining win's
  482. // contentView. So if we do that here, win will (for a short while) have
  483. // an invalid contentView (for the consequences see bmo bugs 381087 and
  484. // 374260).
  485. if ([mView isEqual:[win contentView]]) {
  486. [mView release];
  487. } else {
  488. // Stop NSView hierarchy being changed during [ChildView drawRect:]
  489. [mView performSelectorOnMainThread:@selector(delayedTearDown) withObject:nil waitUntilDone:false];
  490. }
  491. mView = nil;
  492. NS_OBJC_END_TRY_ABORT_BLOCK;
  493. }
  494. // create a nsChildView
  495. NS_IMETHODIMP nsChildView::Create(nsIWidget *aParent,
  496. const nsRect &aRect,
  497. EVENT_CALLBACK aHandleEventFunction,
  498. nsIDeviceContext *aContext,
  499. nsIAppShell *aAppShell,
  500. nsIToolkit *aToolkit,
  501. nsWidgetInitData *aInitData)
  502. {
  503. return(StandardCreate(aParent, aRect, aHandleEventFunction, aContext,
  504. aAppShell, aToolkit, aInitData, nsnull));
  505. }
  506. // Creates a main nsChildView using a native widget (an NSView)
  507. NS_IMETHODIMP nsChildView::Create(nsNativeWidget aNativeParent,
  508. const nsRect &aRect,
  509. EVENT_CALLBACK aHandleEventFunction,
  510. nsIDeviceContext *aContext,
  511. nsIAppShell *aAppShell,
  512. nsIToolkit *aToolkit,
  513. nsWidgetInitData *aInitData)
  514. {
  515. // what we're passed in |aNativeParent| is an NSView.
  516. return(StandardCreate(nsnull, aRect, aHandleEventFunction, aContext,
  517. aAppShell, aToolkit, aInitData, aNativeParent));
  518. }
  519. NS_IMETHODIMP nsChildView::Destroy()
  520. {
  521. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  522. if (mOnDestroyCalled)
  523. return NS_OK;
  524. mOnDestroyCalled = PR_TRUE;
  525. [mView widgetDestroyed];
  526. nsBaseWidget::OnDestroy();
  527. nsBaseWidget::Destroy();
  528. ReportDestroyEvent();
  529. mParentWidget = nil;
  530. TearDownView();
  531. return NS_OK;
  532. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  533. }
  534. #pragma mark -
  535. #if 0
  536. static void PrintViewHierarchy(NSView *view)
  537. {
  538. while (view) {
  539. NSLog(@" view is %x, frame %@", view, NSStringFromRect([view frame]));
  540. view = [view superview];
  541. }
  542. }
  543. #endif
  544. // Return native data according to aDataType
  545. void* nsChildView::GetNativeData(PRUint32 aDataType)
  546. {
  547. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL;
  548. void* retVal = nsnull;
  549. switch (aDataType)
  550. {
  551. case NS_NATIVE_WIDGET:
  552. case NS_NATIVE_DISPLAY:
  553. retVal = (void*)mView;
  554. break;
  555. case NS_NATIVE_WINDOW:
  556. retVal = [mView nativeWindow];
  557. break;
  558. case NS_NATIVE_GRAPHIC:
  559. NS_ASSERTION(0, "Requesting NS_NATIVE_GRAPHIC on a Mac OS X child view!");
  560. retVal = nsnull;
  561. break;
  562. case NS_NATIVE_OFFSETX:
  563. retVal = 0;
  564. break;
  565. case NS_NATIVE_OFFSETY:
  566. retVal = 0;
  567. break;
  568. case NS_NATIVE_PLUGIN_PORT:
  569. #ifndef NP_NO_QUICKDRAW
  570. case NS_NATIVE_PLUGIN_PORT_QD:
  571. {
  572. mPluginIsCG = PR_FALSE;
  573. mIsPluginView = PR_TRUE;
  574. if ([mView isKindOfClass:[ChildView class]])
  575. [(ChildView*)mView setIsPluginView:YES];
  576. NSWindow* window = [mView nativeWindow];
  577. if (window) {
  578. WindowRef topLevelWindow = (WindowRef)[window windowRef];
  579. if (topLevelWindow) {
  580. mPluginPort.qdPort.port = ::GetWindowPort(topLevelWindow);
  581. NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
  582. NSRect frame = [[window contentView] frame];
  583. viewOrigin.y = frame.size.height - viewOrigin.y;
  584. // need to convert view's origin to window coordinates.
  585. // then, encode as "SetOrigin" ready values.
  586. mPluginPort.qdPort.portx = (PRInt32)-viewOrigin.x;
  587. mPluginPort.qdPort.porty = (PRInt32)-viewOrigin.y;
  588. }
  589. }
  590. retVal = (void*)&mPluginPort;
  591. break;
  592. }
  593. #endif
  594. case NS_NATIVE_PLUGIN_PORT_CG:
  595. {
  596. mPluginIsCG = PR_TRUE;
  597. mIsPluginView = PR_TRUE;
  598. if ([mView isKindOfClass:[ChildView class]])
  599. [(ChildView*)mView setIsPluginView:YES];
  600. mPluginPort.cgPort.context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
  601. NSWindow* window = [mView nativeWindow];
  602. if (window) {
  603. WindowRef topLevelWindow = (WindowRef)[window windowRef];
  604. mPluginPort.cgPort.window = topLevelWindow;
  605. }
  606. retVal = (void*)&mPluginPort;
  607. break;
  608. }
  609. }
  610. return retVal;
  611. NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
  612. }
  613. #pragma mark -
  614. NS_IMETHODIMP nsChildView::GetHasTransparentBackground(PRBool& aTransparent)
  615. {
  616. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  617. aTransparent = ![mView isOpaque];
  618. return NS_OK;
  619. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  620. }
  621. // This is called by nsContainerFrame on the root widget for all window types
  622. // except popup windows (when nsCocoaWindow::SetHasTransparentBackground is used instead).
  623. NS_IMETHODIMP nsChildView::SetHasTransparentBackground(PRBool aTransparent)
  624. {
  625. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  626. BOOL currentTransparency = ![[mView nativeWindow] isOpaque];
  627. if (aTransparent != currentTransparency) {
  628. // Find out if this is a window we created by seeing if the delegate is WindowDelegate. If it is,
  629. // tell the nsCocoaWindow to set its background to transparent.
  630. id windowDelegate = [[mView nativeWindow] delegate];
  631. if (windowDelegate && [windowDelegate isKindOfClass:[WindowDelegate class]]) {
  632. nsCocoaWindow *widget = [(WindowDelegate *)windowDelegate geckoWidget];
  633. if (widget) {
  634. widget->MakeBackgroundTransparent(aTransparent);
  635. [(ChildView*)mView setTransparent:aTransparent];
  636. }
  637. }
  638. }
  639. return NS_OK;
  640. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  641. }
  642. NS_IMETHODIMP nsChildView::IsVisible(PRBool& outState)
  643. {
  644. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  645. if (!mVisible) {
  646. outState = mVisible;
  647. }
  648. else {
  649. // mVisible does not accurately reflect the state of a hidden tabbed view
  650. // so verify that the view has a window as well
  651. outState = ([mView window] != nil);
  652. // now check native widget hierarchy visibility
  653. if (outState && NSIsEmptyRect([mView visibleRect])) {
  654. outState = PR_FALSE;
  655. }
  656. }
  657. return NS_OK;
  658. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  659. }
  660. void nsChildView::HidePlugin()
  661. {
  662. NS_ASSERTION(mIsPluginView, "HidePlugin called on non-plugin view");
  663. if (mPluginInstanceOwner && !mPluginIsCG) {
  664. nsPluginWindow* window;
  665. mPluginInstanceOwner->GetWindow(window);
  666. nsCOMPtr<nsIPluginInstance> instance;
  667. mPluginInstanceOwner->GetInstance(*getter_AddRefs(instance));
  668. if (window && instance) {
  669. window->clipRect.top = 0;
  670. window->clipRect.left = 0;
  671. window->clipRect.bottom = 0;
  672. window->clipRect.right = 0;
  673. instance->SetWindow(window);
  674. }
  675. }
  676. }
  677. static void HideChildPluginViews(NSView* aView)
  678. {
  679. NSArray* subviews = [aView subviews];
  680. for (unsigned int i = 0; i < [subviews count]; ++i) {
  681. NSView* view = [subviews objectAtIndex: i];
  682. if (![view isKindOfClass:[ChildView class]])
  683. continue;
  684. ChildView* childview = static_cast<ChildView*>(view);
  685. if ([childview isPluginView]) {
  686. nsChildView* widget = static_cast<nsChildView*>([childview widget]);
  687. if (widget) {
  688. widget->HidePlugin();
  689. }
  690. } else {
  691. HideChildPluginViews(view);
  692. }
  693. }
  694. }
  695. // Hide or show this component
  696. NS_IMETHODIMP nsChildView::Show(PRBool aState)
  697. {
  698. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  699. if (aState != mVisible) {
  700. [mView setHidden:!aState];
  701. mVisible = aState;
  702. if (!mVisible)
  703. HideChildPluginViews(mView);
  704. }
  705. return NS_OK;
  706. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  707. }
  708. nsIWidget*
  709. nsChildView::GetParent(void)
  710. {
  711. return mParentWidget;
  712. }
  713. nsIWidget*
  714. nsChildView::GetTopLevelWidget()
  715. {
  716. nsIWidget* current = this;
  717. for (nsIWidget* parent = GetParent(); parent ; parent = parent->GetParent())
  718. current = parent;
  719. return current;
  720. }
  721. NS_IMETHODIMP nsChildView::ModalEventFilter(PRBool aRealEvent, void *aEvent,
  722. PRBool *aForWindow)
  723. {
  724. if (aForWindow)
  725. *aForWindow = PR_FALSE;
  726. return NS_ERROR_NOT_IMPLEMENTED;
  727. }
  728. NS_IMETHODIMP nsChildView::Enable(PRBool aState)
  729. {
  730. return NS_OK;
  731. }
  732. NS_IMETHODIMP nsChildView::IsEnabled(PRBool *aState)
  733. {
  734. // unimplemented
  735. if (aState)
  736. *aState = PR_TRUE;
  737. return NS_OK;
  738. }
  739. NS_IMETHODIMP nsChildView::SetFocus(PRBool aRaise)
  740. {
  741. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  742. // Don't do anything if SetFocus() has been called reentrantly on the same
  743. // object. Sometimes calls to nsChildView::DispatchEvent() can get
  744. // temporarily stuck, causing calls to [ChildView sendFocusEvent:] and
  745. // SetFocus() to be reentered. These reentrant calls are probably the
  746. // result of one or more bugs, and doing things on a reentrant call can
  747. // cause problems: For example if mView is already the first responder and
  748. // we send it an NS_GOTFOCUS event (see below), this causes the Mochitests
  749. // to get stuck in the toolkit/content/tests/widgets/test_popup_button.xul
  750. // test.
  751. if (mInSetFocus)
  752. return NS_OK;
  753. mInSetFocus = PR_TRUE;
  754. NSWindow* window = [mView window];
  755. if (window) {
  756. nsAutoRetainCocoaObject kungFuDeathGrip(mView);
  757. // For reasons that aren't yet clear, focus changes within a window (as
  758. // opposed to those between windows or between apps) should only trigger
  759. // NS_LOSTFOCUS and NS_GOTFOCUS events (sent to Gecko) in the context of
  760. // a call to nsChildView::SetFocus() (or nsCocoaWindow::SetFocus(), which
  761. // in any case re-routes to nsChildView::SetFocus()). If we send these
  762. // events on every intra-window focus change (on every call to
  763. // [ChildView becomeFirstResponder:] or [ChildView resignFirstResponder:]),
  764. // the result will be strange focus bugs (like bmo bugs 399471, 403232,
  765. // 404433 and 408266).
  766. NSResponder* firstResponder = [window firstResponder];
  767. if ([mView isEqual:firstResponder]) {
  768. // Sometimes SetFocus() is called on an nsChildView object that's
  769. // already focused. In principle this shouldn't happen, and in any
  770. // case we shouldn't have to dispatch any events. But if we don't, we
  771. // sometimes get text-input cursors blinking in more than one text
  772. // field, or still blinking when the browser is no longer active. For
  773. // reasons that aren't at all clear, this problem can be avoided by
  774. // always sending an NS_GOTFOCUS message here.
  775. if ([mView isKindOfClass:[ChildView class]])
  776. [(ChildView *)mView sendFocusEvent:NS_GOTFOCUS];
  777. } else {
  778. // Retain and release firstResponder around the call to
  779. // makeFirstResponder.
  780. [firstResponder retain];
  781. if ([window makeFirstResponder:mView]) {
  782. if ([firstResponder isKindOfClass:[ChildView class]])
  783. [(ChildView *)firstResponder sendFocusEvent:NS_LOSTFOCUS];
  784. if ([mView isKindOfClass:[ChildView class]])
  785. [(ChildView *)mView sendFocusEvent:NS_GOTFOCUS];
  786. }
  787. [firstResponder release];
  788. }
  789. }
  790. mInSetFocus = PR_FALSE;
  791. return NS_OK;
  792. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  793. }
  794. // Set the colormap of the window
  795. NS_IMETHODIMP nsChildView::SetColorMap(nsColorMap *aColorMap)
  796. {
  797. return NS_OK;
  798. }
  799. NS_IMETHODIMP nsChildView::SetMenuBar(nsIMenuBar * aMenuBar)
  800. {
  801. return NS_ERROR_FAILURE; // subviews don't have menu bars
  802. }
  803. NS_IMETHODIMP nsChildView::ShowMenuBar(PRBool aShow)
  804. {
  805. return NS_ERROR_FAILURE; // subviews don't have menu bars
  806. }
  807. // Override to set the cursor on the mac
  808. NS_IMETHODIMP nsChildView::SetCursor(nsCursor aCursor)
  809. {
  810. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  811. nsBaseWidget::SetCursor(aCursor);
  812. [[nsCursorManager sharedInstance] setCursor: aCursor];
  813. return NS_OK;
  814. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  815. }
  816. // implement to fix "hidden virtual function" warning
  817. NS_IMETHODIMP nsChildView::SetCursor(imgIContainer* aCursor,
  818. PRUint32 aHotspotX, PRUint32 aHotspotY)
  819. {
  820. return nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY);
  821. }
  822. #pragma mark -
  823. // Get this component dimension
  824. NS_IMETHODIMP nsChildView::GetBounds(nsRect &aRect)
  825. {
  826. aRect = mBounds;
  827. return NS_OK;
  828. }
  829. NS_IMETHODIMP nsChildView::SetBounds(const nsRect &aRect)
  830. {
  831. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  832. nsresult rv = Inherited::SetBounds(aRect);
  833. if (NS_SUCCEEDED(rv)) {
  834. NSRect r;
  835. GeckoRectToNSRect(aRect, r);
  836. [mView setFrame:r];
  837. }
  838. return rv;
  839. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  840. }
  841. NS_IMETHODIMP nsChildView::ConstrainPosition(PRBool aAllowSlop,
  842. PRInt32 *aX, PRInt32 *aY)
  843. {
  844. return NS_OK;
  845. }
  846. // Move this component, aX and aY are in the parent widget coordinate system
  847. NS_IMETHODIMP nsChildView::Move(PRInt32 aX, PRInt32 aY)
  848. {
  849. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  850. if (!mView || (mBounds.x == aX && mBounds.y == aY))
  851. return NS_OK;
  852. mBounds.x = aX;
  853. mBounds.y = aY;
  854. NSRect r;
  855. GeckoRectToNSRect(mBounds, r);
  856. [mView setFrame:r];
  857. if (mVisible)
  858. [mView setNeedsDisplay:YES];
  859. ReportMoveEvent();
  860. return NS_OK;
  861. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  862. }
  863. NS_IMETHODIMP nsChildView::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
  864. {
  865. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  866. if (!mView || (mBounds.width == aWidth && mBounds.height == aHeight))
  867. return NS_OK;
  868. mBounds.width = aWidth;
  869. mBounds.height = aHeight;
  870. NSRect r;
  871. GeckoRectToNSRect(mBounds, r);
  872. [mView setFrame:r];
  873. if (mVisible && aRepaint)
  874. [mView setNeedsDisplay:YES];
  875. ReportSizeEvent();
  876. return NS_OK;
  877. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  878. }
  879. NS_IMETHODIMP nsChildView::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
  880. {
  881. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  882. BOOL isMoving = (mBounds.x != aX || mBounds.y != aY);
  883. BOOL isResizing = (mBounds.width != aWidth || mBounds.height != aHeight);
  884. if (!mView || (!isMoving && !isResizing))
  885. return NS_OK;
  886. if (isMoving) {
  887. mBounds.x = aX;
  888. mBounds.y = aY;
  889. }
  890. if (isResizing) {
  891. mBounds.width = aWidth;
  892. mBounds.height = aHeight;
  893. }
  894. NSRect r;
  895. GeckoRectToNSRect(mBounds, r);
  896. [mView setFrame:r];
  897. if (mVisible && aRepaint)
  898. [mView setNeedsDisplay:YES];
  899. if (isMoving) {
  900. ReportMoveEvent();
  901. if (mOnDestroyCalled)
  902. return NS_OK;
  903. }
  904. if (isResizing)
  905. ReportSizeEvent();
  906. return NS_OK;
  907. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  908. }
  909. NS_METHOD nsChildView::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight)
  910. {
  911. return NS_ERROR_FAILURE; // nobody call this anywhere in the code
  912. }
  913. NS_METHOD nsChildView::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
  914. {
  915. return NS_ERROR_FAILURE; // nobody call this anywhere in the code
  916. }
  917. NS_IMETHODIMP nsChildView::BeginResizingChildren(void)
  918. {
  919. return NS_OK;
  920. }
  921. NS_IMETHODIMP nsChildView::EndResizingChildren(void)
  922. {
  923. return NS_OK;
  924. }
  925. NS_IMETHODIMP nsChildView::GetPluginClipRect(nsRect& outClipRect, nsPoint& outOrigin, PRBool& outWidgetVisible)
  926. {
  927. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  928. NS_ASSERTION(mIsPluginView, "GetPluginClipRect must only be called on a plugin widget");
  929. if (!mIsPluginView) return NS_ERROR_FAILURE;
  930. NSWindow* window = [mView nativeWindow];
  931. if (!window) return NS_ERROR_FAILURE;
  932. NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
  933. NSRect frame = [[window contentView] frame];
  934. viewOrigin.y = frame.size.height - viewOrigin.y;
  935. // set up the clipping region for plugins.
  936. NSRect visibleBounds = [mView visibleRect];
  937. NSPoint clipOrigin = [mView convertPoint:visibleBounds.origin toView:nil];
  938. // Convert from cocoa to QuickDraw coordinates
  939. clipOrigin.y = frame.size.height - clipOrigin.y;
  940. outClipRect.x = (nscoord)clipOrigin.x;
  941. outClipRect.y = (nscoord)clipOrigin.y;
  942. PRBool isVisible;
  943. IsVisible(isVisible);
  944. if (isVisible && [mView window] != nil) {
  945. outClipRect.width = (nscoord)visibleBounds.size.width;
  946. outClipRect.height = (nscoord)visibleBounds.size.height;
  947. outWidgetVisible = PR_TRUE;
  948. }
  949. else {
  950. outClipRect.width = 0;
  951. outClipRect.height = 0;
  952. outWidgetVisible = PR_FALSE;
  953. }
  954. // need to convert view's origin to window coordinates.
  955. // then, encode as "SetOrigin" ready values.
  956. outOrigin.x = (nscoord)-viewOrigin.x;
  957. outOrigin.y = (nscoord)-viewOrigin.y;
  958. return NS_OK;
  959. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  960. }
  961. NS_IMETHODIMP nsChildView::StartDrawPlugin()
  962. {
  963. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  964. NS_ASSERTION(mIsPluginView, "StartDrawPlugin must only be called on a plugin widget");
  965. if (!mIsPluginView) return NS_ERROR_FAILURE;
  966. // Prevent reentrant "drawing" (or in fact reentrant handling of any plugin
  967. // event). Doing this for both CoreGraphics and QuickDraw plugins restores
  968. // the 1.8-branch behavior wrt reentrancy, and fixes (or works around) bugs
  969. // caused by plugins depending on the old behavior -- e.g. bmo bug 409615.
  970. if (mPluginDrawing)
  971. return NS_ERROR_FAILURE;
  972. NSWindow* window = [mView nativeWindow];
  973. if (!window)
  974. return NS_ERROR_FAILURE;
  975. // It appears that the WindowRef from which we get the plugin port undergoes the
  976. // traditional BeginUpdate/EndUpdate cycle, which, if you recall, sets the visible
  977. // region to the intersection of the visible region and the update region. Since
  978. // we don't know here if we're being drawn inside a BeginUpdate/EndUpdate pair
  979. // (which seem to occur in [NSWindow display]), and we don't want to have the burden
  980. // of correctly doing Carbon invalidates of the plugin rect, we manually set the
  981. // visible region to be the entire port every time. It is necessary to set up our
  982. // window's port even for CoreGraphics plugins, because they may still use Carbon
  983. // internally (see bug #420527 for details).
  984. CGrafPtr port = ::GetWindowPort(WindowRef([window windowRef]));
  985. if (!mPluginIsCG)
  986. port = mPluginPort.qdPort.port;
  987. RgnHandle pluginRegion = ::NewRgn();
  988. if (pluginRegion) {
  989. PRBool portChanged = (port != CGrafPtr(GetQDGlobalsThePort()));
  990. CGrafPtr oldPort;
  991. GDHandle oldDevice;
  992. if (portChanged) {
  993. ::GetGWorld(&oldPort, &oldDevice);
  994. ::SetGWorld(port, ::IsPortOffscreen(port) ? nsnull : ::GetMainDevice());
  995. }
  996. ::SetOrigin(0, 0);
  997. nsRect clipRect; // this is in native window coordinates
  998. nsPoint origin;
  999. PRBool visible;
  1000. GetPluginClipRect(clipRect, origin, visible);
  1001. // XXX if we're not visible, set an empty clip region?
  1002. Rect pluginRect;
  1003. ConvertGeckoRectToMacRect(clipRect, pluginRect);
  1004. ::RectRgn(pluginRegion, &pluginRect);
  1005. ::SetPortVisibleRegion(port, pluginRegion);
  1006. ::SetPortClipRegion(port, pluginRegion);
  1007. // now set up the origin for the plugin
  1008. ::SetOrigin(origin.x, origin.y);
  1009. ::DisposeRgn(pluginRegion);
  1010. if (portChanged)
  1011. ::SetGWorld(oldPort, oldDevice);
  1012. }
  1013. mPluginDrawing = PR_TRUE;
  1014. return NS_OK;
  1015. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  1016. }
  1017. NS_IMETHODIMP nsChildView::EndDrawPlugin()
  1018. {
  1019. NS_ASSERTION(mIsPluginView, "EndDrawPlugin must only be called on a plugin widget");
  1020. if (!mIsPluginView) return NS_ERROR_FAILURE;
  1021. mPluginDrawing = PR_FALSE;
  1022. return NS_OK;
  1023. }
  1024. NS_IMETHODIMP nsChildView::SetPluginInstanceOwner(nsIPluginInstanceOwner* aInstanceOwner)
  1025. {
  1026. mPluginInstanceOwner = aInstanceOwner;
  1027. return NS_OK;
  1028. }
  1029. void nsChildView::LiveResizeStarted()
  1030. {
  1031. // XXX todo. Use this to disable Java async redraw during resize
  1032. mLiveResizeInProgress = PR_TRUE;
  1033. }
  1034. void nsChildView::LiveResizeEnded()
  1035. {
  1036. mLiveResizeInProgress = PR_FALSE;
  1037. }
  1038. static NSString* ToNSString(const nsAString& aString)
  1039. {
  1040. return [NSString stringWithCharacters:aString.BeginReading()
  1041. length:aString.Length()];
  1042. }
  1043. struct KeyboardLayoutOverride {
  1044. PRInt32 mKeyboardLayout;
  1045. PRBool mOverrideEnabled;
  1046. };
  1047. static KeyboardLayoutOverride gOverrideKeyboardLayout;
  1048. static const PRUint32 sModifierFlagMap[][2] = {
  1049. { nsIWidget::CAPS_LOCK, NSAlphaShiftKeyMask },
  1050. { nsIWidget::SHIFT_L, NSShiftKeyMask },
  1051. { nsIWidget::CTRL_L, NSControlKeyMask },
  1052. { nsIWidget::ALT_L, NSAlternateKeyMask },
  1053. { nsIWidget::COMMAND, NSCommandKeyMask },
  1054. { nsIWidget::NUMERIC_KEY_PAD, NSNumericPadKeyMask },
  1055. { nsIWidget::HELP, NSHelpKeyMask },
  1056. { nsIWidget::FUNCTION, NSFunctionKeyMask }
  1057. };
  1058. nsresult nsChildView::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
  1059. PRInt32 aNativeKeyCode,
  1060. PRUint32 aModifierFlags,
  1061. const nsAString& aCharacters,
  1062. const nsAString& aUnmodifiedCharacters)
  1063. {
  1064. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  1065. PRUint32 modifierFlags = 0;
  1066. for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierFlagMap); ++i) {
  1067. if (aModifierFlags & sModifierFlagMap[i][0]) {
  1068. modifierFlags |= sModifierFlagMap[i][1];
  1069. }
  1070. }
  1071. int windowNumber = [[mView window] windowNumber];
  1072. NSEvent* downEvent = [NSEvent keyEventWithType:NSKeyDown
  1073. location:NSMakePoint(0,0)
  1074. modifierFlags:modifierFlags
  1075. timestamp:0
  1076. windowNumber:windowNumber
  1077. context:[NSGraphicsContext currentContext]
  1078. characters:ToNSString(aCharacters)
  1079. charactersIgnoringModifiers:ToNSString(aUnmodifiedCharacters)
  1080. isARepeat:NO
  1081. keyCode:aNativeKeyCode];
  1082. NSEvent* upEvent = [ChildView makeNewCocoaEventWithType:NSKeyUp
  1083. fromEvent:downEvent];
  1084. if (downEvent && upEvent) {
  1085. KeyboardLayoutOverride currentLayout = gOverrideKeyboardLayout;
  1086. gOverrideKeyboardLayout.mKeyboardLayout = aNativeKeyboardLayout;
  1087. gOverrideKeyboardLayout.mOverrideEnabled = PR_TRUE;
  1088. [NSApp sendEvent:downEvent];
  1089. [NSApp sendEvent:upEvent];
  1090. // processKeyDownEvent and keyUp block exceptions so we're sure to
  1091. // reach here to restore gOverrideKeyboardLayout
  1092. gOverrideKeyboardLayout = currentLayout;
  1093. }
  1094. return NS_OK;
  1095. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  1096. }
  1097. #pragma mark -
  1098. #ifdef INVALIDATE_DEBUGGING
  1099. static Boolean KeyDown(const UInt8 theKey)
  1100. {
  1101. KeyMap map;
  1102. GetKeys(map);
  1103. return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
  1104. }
  1105. static Boolean caps_lock()
  1106. {
  1107. return KeyDown(0x39);
  1108. }
  1109. static void blinkRect(Rect* r)
  1110. {
  1111. StRegionFromPool oldClip;
  1112. if (oldClip != NULL)
  1113. ::GetClip(oldClip);
  1114. ::ClipRect(r);
  1115. ::InvertRect(r);
  1116. UInt32 end = ::TickCount() + 5;
  1117. while (::TickCount() < end) ;
  1118. ::InvertRect(r);
  1119. if (oldClip != NULL)
  1120. ::SetClip(oldClip);
  1121. }
  1122. static void blinkRgn(RgnHandle rgn)
  1123. {
  1124. StRegionFromPool oldClip;
  1125. if (oldClip != NULL)
  1126. ::GetClip(oldClip);
  1127. ::SetClip(rgn);
  1128. ::InvertRgn(rgn);
  1129. UInt32 end = ::TickCount() + 5;
  1130. while (::TickCount() < end) ;
  1131. ::InvertRgn(rgn);
  1132. if (oldClip != NULL)
  1133. ::SetClip(oldClip);
  1134. }
  1135. #endif
  1136. // Invalidate this component's visible area
  1137. NS_IMETHODIMP nsChildView::Invalidate(PRBool aIsSynchronous)
  1138. {
  1139. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  1140. if (!mView || !mVisible)
  1141. return NS_OK;
  1142. if (aIsSynchronous) {
  1143. [mView display];
  1144. }
  1145. else if ([NSView focusView]) {
  1146. // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
  1147. // don't lose it.
  1148. [mView setNeedsPendingDisplay];
  1149. }
  1150. else {
  1151. [mView setNeedsDisplay:YES];
  1152. }
  1153. return NS_OK;
  1154. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  1155. }
  1156. // Invalidate this component's visible area
  1157. NS_IMETHODIMP nsChildView::Invalidate(const nsRect &aRect, PRBool aIsSynchronous)
  1158. {
  1159. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  1160. if (!mView || !mVisible)
  1161. return NS_OK;
  1162. NSRect r;
  1163. GeckoRectToNSRect(aRect, r);
  1164. if (aIsSynchronous) {
  1165. [mView displayRect:r];
  1166. }
  1167. else if ([NSView focusView]) {
  1168. // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
  1169. // don't lose it.
  1170. [mView setNeedsPendingDisplayInRect:r];
  1171. }
  1172. else {
  1173. [mView setNeedsDisplayInRect:r];
  1174. }
  1175. return NS_OK;
  1176. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  1177. }
  1178. // Validate the widget
  1179. NS_IMETHODIMP nsChildView::Validate()
  1180. {
  1181. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  1182. [mView setNeedsDisplay:NO];
  1183. return NS_OK;
  1184. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  1185. }
  1186. // Invalidate this component's visible area
  1187. NS_IMETHODIMP nsChildView::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchronous)
  1188. {
  1189. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  1190. if (!mView || !mVisible)
  1191. return NS_OK;
  1192. // FIXME rewrite to use a Cocoa region when nsIRegion isn't a QD Region
  1193. NSRect r;
  1194. nsRect bounds;
  1195. nsIRegion* region = const_cast<nsIRegion*>(aRegion); // ugh. this method should be const
  1196. region->GetBoundingBox(&bounds.x, &bounds.y, &bounds.width, &bounds.height);
  1197. GeckoRectToNSRect(bounds, r);
  1198. if (aIsSynchronous)
  1199. [mView displayRect:r];
  1200. else
  1201. [mView setNeedsDisplayInRect:r];
  1202. return NS_OK;
  1203. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  1204. }
  1205. inline PRUint16 COLOR8TOCOLOR16(PRUint8 color8)
  1206. {
  1207. // return (color8 == 0xFF ? 0xFFFF : (color8 << 8));
  1208. return (color8 << 8) | color8; /* (color8 * 257) == (color8 * 0x0101) */
  1209. }
  1210. // Dummy impl, meant to be overridden
  1211. PRBool
  1212. nsChildView::OnPaint(nsPaintEvent &event)
  1213. {
  1214. return PR_TRUE;
  1215. }
  1216. // this is handled for us by UpdateWidget
  1217. NS_IMETHODIMP nsChildView::Update()
  1218. {
  1219. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  1220. // Update means "Flush any pending changes right now." It does *not* mean
  1221. // repaint the world. :) -- dwh
  1222. [mView displayIfNeeded];
  1223. return NS_OK;
  1224. NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
  1225. }
  1226. #pragma mark -
  1227. // Scroll the bits of a view and its children
  1228. // FIXME: I'm sure the invalidating can be optimized, just no time now.
  1229. NS_IMETHODIMP nsChildView::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
  1230. {
  1231. NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
  1232. BOOL viewWasDirty = NO;
  1233. if (mVisible) {
  1234. viewWasDirty = [mView needsDisplay];
  1235. NSSize scrollVector = {aDx,aDy};
  1236. [mView scrollRect: [mView visibleRect] by:scrollVector];
  1237. }
  1238. // Scroll the children (even if the widget is not visible)
  1239. for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
  1240. // We use resize rather than move since it gives us control
  1241. // over repainting. We can scroll like a bat out of hell
  1242. // by not wasting time invalidating the widgets, since it's
  1243. // completely unnecessary to do so.
  1244. nsRect bounds;
  1245. kid->GetBounds(bounds);
  1246. kid->Resize(bounds.x + aDx, bounds.y + aDy, bounds.width, bounds.height, PR_FALSE);
  1247. }
  1248. if (mOnDestroyCalled)
  1249. return NS_OK;
  1250. if (mVisible) {
  1251. if (viewWasDirty) {
  1252. [mView setNeedsDisplay:YES];
  1253. }
  1254. else {
  1255. NSRect frame = [mView visibleRect];
  1256. NSRect horizInvalid = frame;
  1257. NSRect vertInvalid = frame;
  1258. if (aDx != 0) {
  1259. horizInvalid.size.width = abs(aDx);
  1260. if (aDx < 0)
  1261. horizInvalid.origin.x = frame.origin.x + frame.size.width + aDx;
  1262. [mView setNeedsDisplayInRect: horizInvalid];
  1263. }
  1264. if (aDy != 0) {
  1265. vertInvalid.size.height = abs(aDy);
  1266. if (aDy < 0)
  1267. vertInvalid.origin.y = frame.origin.y + frame.size.height + aDy;
  1268. [mView setNeedsDisplayInRect: vertInvalid];
  1269. }
  1270. // We also need to check for any ChildViews which overlap this widget
  1271. // but are not descendent widgets. If there are any, we need to
  1272. // invalidate the area of this view that these ChildViews will have been
  1273. // blitted into, since these widgets aren't supposed to scroll with
  1274. // this widget.
  1275. // To do this, start at the root Gecko NSView, and walk down along
  1276. // our ancestor view chain, looking at all the subviews in each level
  1277. // of the hierarchy. If we find a non-ancestor view that overlaps
  1278. // this view, invalidate the area around it.
  1279. // We need to convert all rects to a common ancestor view to intersect
  1280. // them, since a view's frame is in the coordinate space of its parent.
  1281. // Use mParentView as the frame of reference.
  1282. NSRect selfFrame = [mParentView convertRect:[mView frame] fromView:[mView superview]];
  1283. NSView* view = mParentView;
  1284. BOOL selfLevel = NO;
  1285. while (!selfLevel) {
  1286. NSView* nextAncestorView = nil;
  1287. NSArray* subviews = [view subviews];
  1288. for (unsigned int i = 0; i < [subviews count]; ++i) {
  1289. NSView* subView = [subviews objectAtIndex: i];
  1290. if (subView == mView)
  1291. selfLevel = YES;
  1292. else if ([mView isDescendantOf:subView])
  1293. nextAncestorView = subView;
  1294. else {
  1295. NSRect intersectArea = NSIntersectionRect([mParentView convertRect:[subView frame] fromView:[subView superview]], selfFrame);
  1296. if (!NSIsEmptyRect(intersectArea)) {
  1297. NSPoint origin = [mView convertPoint:intersectAr

Large files files are truncated, but you can click here to view the full file