/widget/src/cocoa/nsChildView.mm
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
- /* -*- Mode: objc; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Josh Aas <josh@mozilla.com>
- * Mark Mentovai <mark@moxienet.com>
- * H?kan Waara <hwaara@gmail.com>
- * Stuart Morgan <stuart.morgan@alumni.case.edu>
- * Mats Palmgren <mats.palmgren@bredband.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- #include <unistd.h>
-
- #include "nsChildView.h"
- #include "nsCocoaWindow.h"
- #include "nsObjCExceptions.h"
- #include "nsCOMPtr.h"
- #include "nsToolkit.h"
- #include "nsCRT.h"
- #include "nsplugindefs.h"
- #include "nsIPrefService.h"
- #include "nsIPrefBranch.h"
- #include "nsIFontMetrics.h"
- #include "nsIDeviceContext.h"
- #include "nsIRegion.h"
- #include "nsIRollupListener.h"
- #include "nsIScrollableView.h"
- #include "nsIViewManager.h"
- #include "nsIInterfaceRequestor.h"
- #include "nsIServiceManager.h"
- #include "nsILocalFile.h"
- #include "nsILocalFileMac.h"
- #include "nsGfxCIID.h"
- #include "nsIMenuRollup.h"
- #include "nsDragService.h"
- #include "nsCursorManager.h"
- #include "nsWindowMap.h"
- #include "nsCocoaUtils.h"
- #include "nsMenuBarX.h"
- #include "gfxContext.h"
- #include "gfxQuartzSurface.h"
- #include <dlfcn.h>
- #undef DEBUG_IME
- #undef DEBUG_UPDATE
- #undef INVALIDATE_DEBUGGING // flash areas as they are invalidated
- #ifdef MOZ_LOGGING
- #define FORCE_PR_LOG
- #endif
- #include "prlog.h"
- #ifdef PR_LOGGING
- PRLogModuleInfo* sCocoaLog = nsnull;
- #endif
- // npapi.h defines NPEventType_AdjustCursorEvent but we don't want to include npapi.h here.
- // We need to send this in the "what" field for certain native plugin events. WebKit does
- // this as well.
- #define adjustCursorEvent 33
- extern "C" {
- CG_EXTERN void CGContextResetCTM(CGContextRef);
- CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
- CG_EXTERN void CGContextResetClip(CGContextRef);
- }
- #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
- struct __TISInputSource;
- typedef __TISInputSource* TISInputSourceRef;
- #endif
- TISInputSourceRef (*Leopard_TISCopyCurrentKeyboardLayoutInputSource)() = NULL;
- void* (*Leopard_TISGetInputSourceProperty)(TISInputSourceRef inputSource, CFStringRef propertyKey) = NULL;
- CFArrayRef (*Leopard_TISCreateInputSourceList)(CFDictionaryRef properties, Boolean includeAllInstalled) = NULL;
- CFStringRef kOurTISPropertyUnicodeKeyLayoutData = NULL;
- CFStringRef kOurTISPropertyInputSourceID = NULL;
- extern PRBool gCocoaWindowMethodsSwizzled; // Defined in nsCocoaWindow.mm
- extern nsISupportsArray *gDraggedTransferables;
- PRBool nsTSMManager::sIsIMEEnabled = PR_TRUE;
- PRBool nsTSMManager::sIsRomanKeyboardsOnly = PR_FALSE;
- PRBool nsTSMManager::sIgnoreCommit = PR_FALSE;
- NSView<mozView>* nsTSMManager::sComposingView = nsnull;
- TSMDocumentID nsTSMManager::sDocumentID = nsnull;
- NSString* nsTSMManager::sComposingString = nsnull;
- static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
- static NSView* sLastViewEntered = nil;
- #ifdef INVALIDATE_DEBUGGING
- static void blinkRect(Rect* r);
- static void blinkRgn(RgnHandle rgn);
- #endif
- nsIRollupListener * gRollupListener = nsnull;
- nsIWidget * gRollupWidget = nsnull;
- @interface ChildView(Private)
- // sets up our view, attaching it to its owning gecko view
- - (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild;
- // sends gecko an ime composition event
- - (nsRect) sendCompositionEvent:(PRInt32)aEventType;
- // sends gecko an ime text event
- - (void) sendTextEvent:(PRUnichar*) aBuffer
- attributedString:(NSAttributedString*) aString
- selectedRange:(NSRange)selRange
- markedRange:(NSRange)markRange
- doCommit:(BOOL)doCommit;
- // do generic gecko event setup with a generic cocoa event. accepts nil inEvent.
- - (void) convertGenericCocoaEvent:(NSEvent*)inEvent toGeckoEvent:(nsInputEvent*)outGeckoEvent;
- // set up a gecko mouse event based on a cocoa mouse event
- - (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent toGeckoEvent:(nsInputEvent*)outGeckoEvent;
- // set up a gecko key event based on a cocoa key event
- - (void) convertCocoaKeyEvent:(NSEvent*)aKeyEvent toGeckoEvent:(nsKeyEvent*)outGeckoEvent;
- - (NSMenu*)contextMenu;
- - (TopLevelWindowData*)ensureWindowData;
- - (void)setIsPluginView:(BOOL)aIsPlugin;
- - (BOOL)isPluginView;
- - (BOOL)childViewHasPlugin;
- - (BOOL)isRectObscuredBySubview:(NSRect)inRect;
- - (void)processPendingRedraws;
- - (PRBool)processKeyDownEvent:(NSEvent*)theEvent keyEquiv:(BOOL)isKeyEquiv;
- - (BOOL)ensureCorrectMouseEventTarget:(NSEvent *)anEvent;
- - (void)maybeInitContextMenuTracking;
- + (NSEvent*)makeNewCocoaEventWithType:(NSEventType)type fromEvent:(NSEvent*)theEvent;
- #if USE_CLICK_HOLD_CONTEXTMENU
- // called on a timer two seconds after a mouse down to see if we should display
- // a context menu (click-hold)
- - (void)clickHoldCallback:(id)inEvent;
- #endif
- #ifdef ACCESSIBILITY
- - (id<mozAccessible>)accessible;
- #endif
- @end
- #pragma mark -
- /* Convenience routines to go from a gecko rect to cocoa NSRects and back
- *
- * Gecko rects (nsRect) contain an origin (x,y) in a coordinate
- * system with (0,0) in the top-left of the screen. Cocoa rects
- * (NSRect) contain an origin (x,y) in a coordinate system with
- * (0,0) in the bottom-left of the screen. Both nsRect and NSRect
- * contain width/height info, with no difference in their use.
- * If a Cocoa rect is from a flipped view, there is no need to
- * convert coordinate systems.
- */
- static inline void
- GeckoRectToNSRect(const nsRect & inGeckoRect, NSRect & outCocoaRect)
- {
- outCocoaRect.origin.x = inGeckoRect.x;
- outCocoaRect.origin.y = inGeckoRect.y;
- outCocoaRect.size.width = inGeckoRect.width;
- outCocoaRect.size.height = inGeckoRect.height;
- }
- static inline void
- NSRectToGeckoRect(const NSRect & inCocoaRect, nsRect & outGeckoRect)
- {
- outGeckoRect.x = static_cast<nscoord>(inCocoaRect.origin.x);
- outGeckoRect.y = static_cast<nscoord>(inCocoaRect.origin.y);
- outGeckoRect.width = static_cast<nscoord>(inCocoaRect.size.width);
- outGeckoRect.height = static_cast<nscoord>(inCocoaRect.size.height);
- }
- static inline void
- ConvertGeckoRectToMacRect(const nsRect& aRect, Rect& outMacRect)
- {
- outMacRect.left = aRect.x;
- outMacRect.top = aRect.y;
- outMacRect.right = aRect.x + aRect.width;
- outMacRect.bottom = aRect.y + aRect.height;
- }
- // Flips a screen coordinate from a point in the cocoa coordinate system (bottom-left rect) to a point
- // that is a "flipped" cocoa coordinate system (starts in the top-left).
- static inline void
- FlipCocoaScreenCoordinate (NSPoint &inPoint)
- {
- inPoint.y = nsCocoaUtils::FlippedScreenY(inPoint.y);
- }
-
- static PRUint32
- UnderlineAttributeToTextRangeType(PRUint32 aUnderlineStyle, NSRange selRange)
- {
- #ifdef DEBUG_IME
- NSLog(@"****in underlineAttributeToTextRangeType = %d", aUnderlineStyle);
- #endif
- // For more info on the underline attribute, please see:
- // http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/AttributedStrings/Tasks/AccessingAttrs.html
- // We are not clear where the define for value 2 is right now.
- // To see this value in japanese ime, type 'aaaaaaaaa' and hit space to make the
- // ime send you some part of text in 1 (NSSingleUnderlineStyle) and some part in 2.
- // ftang will ask apple for more details
- //
- // it probably means show 1-pixel thickness underline vs 2-pixel thickness
-
- PRUint32 attr;
- if (selRange.length == 0) {
- switch (aUnderlineStyle) {
- case 1:
- attr = NS_TEXTRANGE_RAWINPUT;
- break;
- case 2:
- default:
- attr = NS_TEXTRANGE_SELECTEDRAWTEXT;
- break;
- }
- }
- else {
- switch (aUnderlineStyle) {
- case 1:
- attr = NS_TEXTRANGE_CONVERTEDTEXT;
- break;
- case 2:
- default:
- attr = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
- break;
- }
- }
- return attr;
- }
- static PRUint32
- CountRanges(NSAttributedString *aString)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
- // Iterate through aString for the NSUnderlineStyleAttributeName and count the
- // different segments adjusting limitRange as we go.
- PRUint32 count = 0;
- NSRange effectiveRange;
- NSRange limitRange = NSMakeRange(0, [aString length]);
- while (limitRange.length > 0) {
- [aString attribute:NSUnderlineStyleAttributeName
- atIndex:limitRange.location
- longestEffectiveRange:&effectiveRange
- inRange:limitRange];
- limitRange = NSMakeRange(NSMaxRange(effectiveRange),
- NSMaxRange(limitRange) - NSMaxRange(effectiveRange));
- count++;
- }
- return count;
- NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
- }
- static void
- ConvertAttributeToGeckoRange(NSAttributedString *aString, NSRange markRange, NSRange selRange, PRUint32 inCount, nsTextRange* aRanges)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
- // Convert the Cocoa range into the nsTextRange Array used in Gecko.
- // Iterate through the attributed string and map the underline attribute to Gecko IME textrange attributes.
- // We may need to change the code here if we change the implementation of validAttributesForMarkedText.
- PRUint32 i = 0;
- NSRange effectiveRange;
- NSRange limitRange = NSMakeRange(0, [aString length]);
- while ((limitRange.length > 0) && (i < inCount)) {
- id attributeValue = [aString attribute:NSUnderlineStyleAttributeName
- atIndex:limitRange.location
- longestEffectiveRange:&effectiveRange
- inRange:limitRange];
- aRanges[i].mStartOffset = effectiveRange.location;
- aRanges[i].mEndOffset = NSMaxRange(effectiveRange);
- aRanges[i].mRangeType = UnderlineAttributeToTextRangeType([attributeValue intValue], selRange);
- limitRange = NSMakeRange(NSMaxRange(effectiveRange),
- NSMaxRange(limitRange) - NSMaxRange(effectiveRange));
- i++;
- }
- // Get current caret position.
- // Caret is indicator of insertion point, so mEndOffset = 0.
- aRanges[i].mStartOffset = selRange.location + selRange.length;
- aRanges[i].mEndOffset = 0;
- aRanges[i].mRangeType = NS_TEXTRANGE_CARETPOSITION;
- NS_OBJC_END_TRY_ABORT_BLOCK;
- }
- static void
- FillTextRangeInTextEvent(nsTextEvent *aTextEvent, NSAttributedString* aString, NSRange markRange, NSRange selRange)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
- // Count the number of segments in the attributed string and add one more count for sending current caret position to Gecko.
- // Allocate the right size of nsTextRange and draw caret at right position.
- // Convert the attributed string into an array of nsTextRange and get current caret position by calling above functions.
- PRUint32 count = CountRanges(aString) + 1;
- aTextEvent->rangeArray = new nsTextRange[count];
- if (aTextEvent->rangeArray) {
- aTextEvent->rangeCount = count;
- ConvertAttributeToGeckoRange(aString, markRange, selRange, aTextEvent->rangeCount, aTextEvent->rangeArray);
- }
- NS_OBJC_END_TRY_ABORT_BLOCK;
- }
- #pragma mark -
- nsChildView::nsChildView() : nsBaseWidget()
- , mView(nsnull)
- , mParentView(nsnull)
- , mParentWidget(nsnull)
- , mVisible(PR_FALSE)
- , mDrawing(PR_FALSE)
- , mLiveResizeInProgress(PR_FALSE)
- , mIsPluginView(PR_FALSE)
- , mPluginDrawing(PR_FALSE)
- , mPluginIsCG(PR_FALSE)
- , mInSetFocus(PR_FALSE)
- {
- #ifdef PR_LOGGING
- if (!sCocoaLog) {
- sCocoaLog = PR_NewLogModule("nsCocoaWidgets");
- CFIndex idx;
- KLGetKeyboardLayoutCount(&idx);
- PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("Keyboard layout configuration:"));
- for (CFIndex i = 0; i < idx; ++i) {
- KeyboardLayoutRef curKL;
- if (KLGetKeyboardLayoutAtIndex(i, &curKL) == noErr) {
- CFStringRef name;
- if (KLGetKeyboardLayoutProperty(curKL, kKLName, (const void**)&name) == noErr) {
- int idn;
- KLGetKeyboardLayoutProperty(curKL, kKLIdentifier, (const void**)&idn);
- int kind;
- KLGetKeyboardLayoutProperty(curKL, kKLKind, (const void**)&kind);
- char buf[256];
- CFStringGetCString(name, buf, 256, kCFStringEncodingASCII);
- PR_LOG(sCocoaLog, PR_LOG_ALWAYS, (" %d,%s,%d\n", idn, buf, kind));
- }
- }
- }
- }
- #endif
- SetBackgroundColor(NS_RGB(255, 255, 255));
- SetForegroundColor(NS_RGB(0, 0, 0));
- if (nsToolkit::OnLeopardOrLater() && !Leopard_TISCopyCurrentKeyboardLayoutInputSource) {
- // This libary would already be open for LMGetKbdType (and probably other
- // symbols), so merely using RTLD_DEFAULT in dlsym would be sufficient,
- // but man dlsym says: "all mach-o images in the process (except ...) are
- // searched in the order they were loaded. This can be a costly search
- // and should be avoided."
- void* hitoolboxHandle = dlopen("/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox", RTLD_LAZY);
- if (hitoolboxHandle) {
- *(void **)(&Leopard_TISCopyCurrentKeyboardLayoutInputSource) = dlsym(hitoolboxHandle, "TISCopyCurrentKeyboardLayoutInputSource");
- *(void **)(&Leopard_TISGetInputSourceProperty) = dlsym(hitoolboxHandle, "TISGetInputSourceProperty");
- *(void **)(&Leopard_TISCreateInputSourceList) = dlsym(hitoolboxHandle, "TISCreateInputSourceList");
- kOurTISPropertyUnicodeKeyLayoutData = *static_cast<CFStringRef*>(dlsym(hitoolboxHandle, "kTISPropertyUnicodeKeyLayoutData"));
- kOurTISPropertyInputSourceID = *static_cast<CFStringRef*>(dlsym(hitoolboxHandle, "kTISPropertyInputSourceID"));
- }
- }
- }
- nsChildView::~nsChildView()
- {
- // notify the children that we're gone
- for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
- nsChildView* childView = static_cast<nsChildView*>(kid);
- childView->mParentWidget = nsnull;
- }
- NS_WARN_IF_FALSE(mOnDestroyCalled, "nsChildView object destroyed without calling Destroy()");
- // An nsChildView object that was in use can be destroyed without Destroy()
- // ever being called on it. So we also need to do a quick, safe cleanup
- // here (it's too late to just call Destroy(), which can cause crashes).
- // It's particularly important to make sure widgetDestroyed is called on our
- // mView -- this method NULLs mView's mGeckoChild, and NULL checks on
- // mGeckoChild are used throughout the ChildView class to tell if it's safe
- // to use a ChildView object.
- [mView widgetDestroyed]; // Safe if mView is nil.
- mParentWidget = nil;
- TearDownView(); // Safe if called twice.
- }
- NS_IMPL_ISUPPORTS_INHERITED2(nsChildView, nsBaseWidget, nsIPluginWidget, nsIKBStateControl)
- // Utility method for implementing both Create(nsIWidget ...)
- // and Create(nsNativeWidget...)
- nsresult nsChildView::StandardCreate(nsIWidget *aParent,
- const nsRect &aRect,
- EVENT_CALLBACK aHandleEventFunction,
- nsIDeviceContext *aContext,
- nsIAppShell *aAppShell,
- nsIToolkit *aToolkit,
- nsWidgetInitData *aInitData,
- nsNativeWidget aNativeParent)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- // See NSWindow (MethodSwizzling) in nsCocoaWindow.mm.
- if (!gCocoaWindowMethodsSwizzled) {
- nsToolkit::SwizzleMethods([NSWindow class], @selector(sendEvent:),
- @selector(nsCocoaWindow_NSWindow_sendEvent:));
- gCocoaWindowMethodsSwizzled = PR_TRUE;
- }
- mBounds = aRect;
- BaseCreate(aParent, aRect, aHandleEventFunction,
- aContext, aAppShell, aToolkit, aInitData);
- // inherit things from the parent view and create our parallel
- // NSView in the Cocoa display system
- mParentView = nil;
- if (aParent) {
- SetBackgroundColor(aParent->GetBackgroundColor());
- SetForegroundColor(aParent->GetForegroundColor());
- // inherit the top-level window. NS_NATIVE_WIDGET is always a NSView
- // regardless of if we're asking a window or a view (for compatibility
- // with windows).
- mParentView = (NSView*)aParent->GetNativeData(NS_NATIVE_WIDGET);
- mParentWidget = aParent;
- }
- else
- mParentView = reinterpret_cast<NSView*>(aNativeParent);
-
- // create our parallel NSView and hook it up to our parent. Recall
- // that NS_NATIVE_WIDGET is the NSView.
- NSRect r;
- GeckoRectToNSRect(mBounds, r);
- mView = [CreateCocoaView(r) retain];
- if (!mView) return NS_ERROR_FAILURE;
-
- #if DEBUG
- // if our parent is a popup window, we're most certainly coming from a <select> list dropdown which
- // we handle in a different way than other platforms. It's ok that we don't have a parent
- // view because we bailed before even creating the cocoa widgetry and as a result, we
- // don't need to assert. However, if that's not the case, we definitely want to assert
- // to show views aren't getting correctly parented.
- if (aParent) {
- nsWindowType windowType;
- aParent->GetWindowType(windowType);
- if (windowType != eWindowType_popup)
- NS_ASSERTION(mParentView && mView, "couldn't hook up new NSView in hierarchy");
- }
- else {
- NS_ASSERTION(mParentView && mView, "couldn't hook up new NSView in hierarchy");
- }
- #endif
- // If this view was created in a Gecko view hierarchy, the initial state
- // is hidden. If the view is attached only to a native NSView but has
- // no Gecko parent (as in embedding), the initial state is visible.
- if (mParentWidget)
- [mView setHidden:YES];
- else
- mVisible = PR_TRUE;
- // Hook it up in the NSView hierarchy.
- if (mParentView) {
- NSWindow* window = [mParentView window];
- if (!window &&
- [mParentView respondsToSelector:@selector(nativeWindow)])
- window = [mParentView nativeWindow];
- [mView setNativeWindow:window];
- [mParentView addSubview:mView];
- }
- // if this is a ChildView, make sure that our per-window data
- // is set up
- if ([mView isKindOfClass:[ChildView class]])
- [(ChildView*)mView ensureWindowData];
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- // Creates the appropriate child view. Override to create something other than
- // our |ChildView| object. Autoreleases, so caller must retain.
- NSView*
- nsChildView::CreateCocoaView(NSRect inFrame)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
- return [[[ChildView alloc] initWithFrame:inFrame geckoChild:this] autorelease];
- NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
- }
- void nsChildView::TearDownView()
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
- if (!mView)
- return;
- NSWindow* win = [mView window];
- NSResponder* responder = [win firstResponder];
-
- // We're being unhooked from the view hierarchy, don't leave our view
- // or a child view as the window first responder.
- if (responder && [responder isKindOfClass:[NSView class]] &&
- [(NSView*)responder isDescendantOf:mView]) {
- [win makeFirstResponder:[mView superview]];
- }
- // If mView is win's contentView, win (mView's NSWindow) "owns" mView --
- // win has retained mView, and will detach it from the view hierarchy and
- // release it when necessary (when win is itself destroyed (in a call to
- // [win dealloc])). So all we need to do here is call [mView release] (to
- // match the call to [mView retain] in nsChildView::StandardCreate()).
- // Also calling [mView removeFromSuperviewWithoutNeedingDisplay] causes
- // mView to be released again and dealloced, while remaining win's
- // contentView. So if we do that here, win will (for a short while) have
- // an invalid contentView (for the consequences see bmo bugs 381087 and
- // 374260).
- if ([mView isEqual:[win contentView]]) {
- [mView release];
- } else {
- // Stop NSView hierarchy being changed during [ChildView drawRect:]
- [mView performSelectorOnMainThread:@selector(delayedTearDown) withObject:nil waitUntilDone:false];
- }
- mView = nil;
- NS_OBJC_END_TRY_ABORT_BLOCK;
- }
- // create a nsChildView
- NS_IMETHODIMP nsChildView::Create(nsIWidget *aParent,
- const nsRect &aRect,
- EVENT_CALLBACK aHandleEventFunction,
- nsIDeviceContext *aContext,
- nsIAppShell *aAppShell,
- nsIToolkit *aToolkit,
- nsWidgetInitData *aInitData)
- {
- return(StandardCreate(aParent, aRect, aHandleEventFunction, aContext,
- aAppShell, aToolkit, aInitData, nsnull));
- }
- // Creates a main nsChildView using a native widget (an NSView)
- NS_IMETHODIMP nsChildView::Create(nsNativeWidget aNativeParent,
- const nsRect &aRect,
- EVENT_CALLBACK aHandleEventFunction,
- nsIDeviceContext *aContext,
- nsIAppShell *aAppShell,
- nsIToolkit *aToolkit,
- nsWidgetInitData *aInitData)
- {
- // what we're passed in |aNativeParent| is an NSView.
- return(StandardCreate(nsnull, aRect, aHandleEventFunction, aContext,
- aAppShell, aToolkit, aInitData, aNativeParent));
- }
- NS_IMETHODIMP nsChildView::Destroy()
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (mOnDestroyCalled)
- return NS_OK;
- mOnDestroyCalled = PR_TRUE;
- [mView widgetDestroyed];
- nsBaseWidget::OnDestroy();
- nsBaseWidget::Destroy();
- ReportDestroyEvent();
- mParentWidget = nil;
- TearDownView();
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- #pragma mark -
- #if 0
- static void PrintViewHierarchy(NSView *view)
- {
- while (view) {
- NSLog(@" view is %x, frame %@", view, NSStringFromRect([view frame]));
- view = [view superview];
- }
- }
- #endif
- // Return native data according to aDataType
- void* nsChildView::GetNativeData(PRUint32 aDataType)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL;
- void* retVal = nsnull;
- switch (aDataType)
- {
- case NS_NATIVE_WIDGET:
- case NS_NATIVE_DISPLAY:
- retVal = (void*)mView;
- break;
- case NS_NATIVE_WINDOW:
- retVal = [mView nativeWindow];
- break;
- case NS_NATIVE_GRAPHIC:
- NS_ASSERTION(0, "Requesting NS_NATIVE_GRAPHIC on a Mac OS X child view!");
- retVal = nsnull;
- break;
- case NS_NATIVE_OFFSETX:
- retVal = 0;
- break;
- case NS_NATIVE_OFFSETY:
- retVal = 0;
- break;
- case NS_NATIVE_PLUGIN_PORT:
- #ifndef NP_NO_QUICKDRAW
- case NS_NATIVE_PLUGIN_PORT_QD:
- {
- mPluginIsCG = PR_FALSE;
- mIsPluginView = PR_TRUE;
- if ([mView isKindOfClass:[ChildView class]])
- [(ChildView*)mView setIsPluginView:YES];
- NSWindow* window = [mView nativeWindow];
- if (window) {
- WindowRef topLevelWindow = (WindowRef)[window windowRef];
- if (topLevelWindow) {
- mPluginPort.qdPort.port = ::GetWindowPort(topLevelWindow);
- NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
- NSRect frame = [[window contentView] frame];
- viewOrigin.y = frame.size.height - viewOrigin.y;
-
- // need to convert view's origin to window coordinates.
- // then, encode as "SetOrigin" ready values.
- mPluginPort.qdPort.portx = (PRInt32)-viewOrigin.x;
- mPluginPort.qdPort.porty = (PRInt32)-viewOrigin.y;
- }
- }
- retVal = (void*)&mPluginPort;
- break;
- }
- #endif
- case NS_NATIVE_PLUGIN_PORT_CG:
- {
- mPluginIsCG = PR_TRUE;
- mIsPluginView = PR_TRUE;
- if ([mView isKindOfClass:[ChildView class]])
- [(ChildView*)mView setIsPluginView:YES];
- mPluginPort.cgPort.context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- NSWindow* window = [mView nativeWindow];
- if (window) {
- WindowRef topLevelWindow = (WindowRef)[window windowRef];
- mPluginPort.cgPort.window = topLevelWindow;
- }
- retVal = (void*)&mPluginPort;
- break;
- }
- }
- return retVal;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
- }
- #pragma mark -
- NS_IMETHODIMP nsChildView::GetHasTransparentBackground(PRBool& aTransparent)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- aTransparent = ![mView isOpaque];
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- // This is called by nsContainerFrame on the root widget for all window types
- // except popup windows (when nsCocoaWindow::SetHasTransparentBackground is used instead).
- NS_IMETHODIMP nsChildView::SetHasTransparentBackground(PRBool aTransparent)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- BOOL currentTransparency = ![[mView nativeWindow] isOpaque];
- if (aTransparent != currentTransparency) {
- // Find out if this is a window we created by seeing if the delegate is WindowDelegate. If it is,
- // tell the nsCocoaWindow to set its background to transparent.
- id windowDelegate = [[mView nativeWindow] delegate];
- if (windowDelegate && [windowDelegate isKindOfClass:[WindowDelegate class]]) {
- nsCocoaWindow *widget = [(WindowDelegate *)windowDelegate geckoWidget];
- if (widget) {
- widget->MakeBackgroundTransparent(aTransparent);
- [(ChildView*)mView setTransparent:aTransparent];
- }
- }
- }
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- NS_IMETHODIMP nsChildView::IsVisible(PRBool& outState)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (!mVisible) {
- outState = mVisible;
- }
- else {
- // mVisible does not accurately reflect the state of a hidden tabbed view
- // so verify that the view has a window as well
- outState = ([mView window] != nil);
- // now check native widget hierarchy visibility
- if (outState && NSIsEmptyRect([mView visibleRect])) {
- outState = PR_FALSE;
- }
- }
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- void nsChildView::HidePlugin()
- {
- NS_ASSERTION(mIsPluginView, "HidePlugin called on non-plugin view");
- if (mPluginInstanceOwner && !mPluginIsCG) {
- nsPluginWindow* window;
- mPluginInstanceOwner->GetWindow(window);
- nsCOMPtr<nsIPluginInstance> instance;
- mPluginInstanceOwner->GetInstance(*getter_AddRefs(instance));
- if (window && instance) {
- window->clipRect.top = 0;
- window->clipRect.left = 0;
- window->clipRect.bottom = 0;
- window->clipRect.right = 0;
- instance->SetWindow(window);
- }
- }
- }
- static void HideChildPluginViews(NSView* aView)
- {
- NSArray* subviews = [aView subviews];
- for (unsigned int i = 0; i < [subviews count]; ++i) {
- NSView* view = [subviews objectAtIndex: i];
- if (![view isKindOfClass:[ChildView class]])
- continue;
- ChildView* childview = static_cast<ChildView*>(view);
- if ([childview isPluginView]) {
- nsChildView* widget = static_cast<nsChildView*>([childview widget]);
- if (widget) {
- widget->HidePlugin();
- }
- } else {
- HideChildPluginViews(view);
- }
- }
- }
- // Hide or show this component
- NS_IMETHODIMP nsChildView::Show(PRBool aState)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (aState != mVisible) {
- [mView setHidden:!aState];
- mVisible = aState;
- if (!mVisible)
- HideChildPluginViews(mView);
- }
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- nsIWidget*
- nsChildView::GetParent(void)
- {
- return mParentWidget;
- }
- nsIWidget*
- nsChildView::GetTopLevelWidget()
- {
- nsIWidget* current = this;
- for (nsIWidget* parent = GetParent(); parent ; parent = parent->GetParent())
- current = parent;
- return current;
- }
- NS_IMETHODIMP nsChildView::ModalEventFilter(PRBool aRealEvent, void *aEvent,
- PRBool *aForWindow)
- {
- if (aForWindow)
- *aForWindow = PR_FALSE;
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP nsChildView::Enable(PRBool aState)
- {
- return NS_OK;
- }
- NS_IMETHODIMP nsChildView::IsEnabled(PRBool *aState)
- {
- // unimplemented
- if (aState)
- *aState = PR_TRUE;
- return NS_OK;
- }
- NS_IMETHODIMP nsChildView::SetFocus(PRBool aRaise)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- // Don't do anything if SetFocus() has been called reentrantly on the same
- // object. Sometimes calls to nsChildView::DispatchEvent() can get
- // temporarily stuck, causing calls to [ChildView sendFocusEvent:] and
- // SetFocus() to be reentered. These reentrant calls are probably the
- // result of one or more bugs, and doing things on a reentrant call can
- // cause problems: For example if mView is already the first responder and
- // we send it an NS_GOTFOCUS event (see below), this causes the Mochitests
- // to get stuck in the toolkit/content/tests/widgets/test_popup_button.xul
- // test.
- if (mInSetFocus)
- return NS_OK;
- mInSetFocus = PR_TRUE;
- NSWindow* window = [mView window];
- if (window) {
- nsAutoRetainCocoaObject kungFuDeathGrip(mView);
- // For reasons that aren't yet clear, focus changes within a window (as
- // opposed to those between windows or between apps) should only trigger
- // NS_LOSTFOCUS and NS_GOTFOCUS events (sent to Gecko) in the context of
- // a call to nsChildView::SetFocus() (or nsCocoaWindow::SetFocus(), which
- // in any case re-routes to nsChildView::SetFocus()). If we send these
- // events on every intra-window focus change (on every call to
- // [ChildView becomeFirstResponder:] or [ChildView resignFirstResponder:]),
- // the result will be strange focus bugs (like bmo bugs 399471, 403232,
- // 404433 and 408266).
- NSResponder* firstResponder = [window firstResponder];
- if ([mView isEqual:firstResponder]) {
- // Sometimes SetFocus() is called on an nsChildView object that's
- // already focused. In principle this shouldn't happen, and in any
- // case we shouldn't have to dispatch any events. But if we don't, we
- // sometimes get text-input cursors blinking in more than one text
- // field, or still blinking when the browser is no longer active. For
- // reasons that aren't at all clear, this problem can be avoided by
- // always sending an NS_GOTFOCUS message here.
- if ([mView isKindOfClass:[ChildView class]])
- [(ChildView *)mView sendFocusEvent:NS_GOTFOCUS];
- } else {
- // Retain and release firstResponder around the call to
- // makeFirstResponder.
- [firstResponder retain];
- if ([window makeFirstResponder:mView]) {
- if ([firstResponder isKindOfClass:[ChildView class]])
- [(ChildView *)firstResponder sendFocusEvent:NS_LOSTFOCUS];
- if ([mView isKindOfClass:[ChildView class]])
- [(ChildView *)mView sendFocusEvent:NS_GOTFOCUS];
- }
- [firstResponder release];
- }
- }
- mInSetFocus = PR_FALSE;
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- // Set the colormap of the window
- NS_IMETHODIMP nsChildView::SetColorMap(nsColorMap *aColorMap)
- {
- return NS_OK;
- }
- NS_IMETHODIMP nsChildView::SetMenuBar(nsIMenuBar * aMenuBar)
- {
- return NS_ERROR_FAILURE; // subviews don't have menu bars
- }
- NS_IMETHODIMP nsChildView::ShowMenuBar(PRBool aShow)
- {
- return NS_ERROR_FAILURE; // subviews don't have menu bars
- }
- // Override to set the cursor on the mac
- NS_IMETHODIMP nsChildView::SetCursor(nsCursor aCursor)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- nsBaseWidget::SetCursor(aCursor);
- [[nsCursorManager sharedInstance] setCursor: aCursor];
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- // implement to fix "hidden virtual function" warning
- NS_IMETHODIMP nsChildView::SetCursor(imgIContainer* aCursor,
- PRUint32 aHotspotX, PRUint32 aHotspotY)
- {
- return nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY);
- }
- #pragma mark -
- // Get this component dimension
- NS_IMETHODIMP nsChildView::GetBounds(nsRect &aRect)
- {
- aRect = mBounds;
- return NS_OK;
- }
- NS_IMETHODIMP nsChildView::SetBounds(const nsRect &aRect)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- nsresult rv = Inherited::SetBounds(aRect);
- if (NS_SUCCEEDED(rv)) {
- NSRect r;
- GeckoRectToNSRect(aRect, r);
- [mView setFrame:r];
- }
- return rv;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- NS_IMETHODIMP nsChildView::ConstrainPosition(PRBool aAllowSlop,
- PRInt32 *aX, PRInt32 *aY)
- {
- return NS_OK;
- }
- // Move this component, aX and aY are in the parent widget coordinate system
- NS_IMETHODIMP nsChildView::Move(PRInt32 aX, PRInt32 aY)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (!mView || (mBounds.x == aX && mBounds.y == aY))
- return NS_OK;
- mBounds.x = aX;
- mBounds.y = aY;
- NSRect r;
- GeckoRectToNSRect(mBounds, r);
- [mView setFrame:r];
- if (mVisible)
- [mView setNeedsDisplay:YES];
- ReportMoveEvent();
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- NS_IMETHODIMP nsChildView::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (!mView || (mBounds.width == aWidth && mBounds.height == aHeight))
- return NS_OK;
- mBounds.width = aWidth;
- mBounds.height = aHeight;
- NSRect r;
- GeckoRectToNSRect(mBounds, r);
- [mView setFrame:r];
- if (mVisible && aRepaint)
- [mView setNeedsDisplay:YES];
- ReportSizeEvent();
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- NS_IMETHODIMP nsChildView::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- BOOL isMoving = (mBounds.x != aX || mBounds.y != aY);
- BOOL isResizing = (mBounds.width != aWidth || mBounds.height != aHeight);
- if (!mView || (!isMoving && !isResizing))
- return NS_OK;
- if (isMoving) {
- mBounds.x = aX;
- mBounds.y = aY;
- }
- if (isResizing) {
- mBounds.width = aWidth;
- mBounds.height = aHeight;
- }
- NSRect r;
- GeckoRectToNSRect(mBounds, r);
- [mView setFrame:r];
- if (mVisible && aRepaint)
- [mView setNeedsDisplay:YES];
- if (isMoving) {
- ReportMoveEvent();
- if (mOnDestroyCalled)
- return NS_OK;
- }
- if (isResizing)
- ReportSizeEvent();
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- NS_METHOD nsChildView::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight)
- {
- return NS_ERROR_FAILURE; // nobody call this anywhere in the code
- }
- NS_METHOD nsChildView::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
- {
- return NS_ERROR_FAILURE; // nobody call this anywhere in the code
- }
- NS_IMETHODIMP nsChildView::BeginResizingChildren(void)
- {
- return NS_OK;
- }
- NS_IMETHODIMP nsChildView::EndResizingChildren(void)
- {
- return NS_OK;
- }
- NS_IMETHODIMP nsChildView::GetPluginClipRect(nsRect& outClipRect, nsPoint& outOrigin, PRBool& outWidgetVisible)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- NS_ASSERTION(mIsPluginView, "GetPluginClipRect must only be called on a plugin widget");
- if (!mIsPluginView) return NS_ERROR_FAILURE;
-
- NSWindow* window = [mView nativeWindow];
- if (!window) return NS_ERROR_FAILURE;
-
- NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
- NSRect frame = [[window contentView] frame];
- viewOrigin.y = frame.size.height - viewOrigin.y;
-
- // set up the clipping region for plugins.
- NSRect visibleBounds = [mView visibleRect];
- NSPoint clipOrigin = [mView convertPoint:visibleBounds.origin toView:nil];
-
- // Convert from cocoa to QuickDraw coordinates
- clipOrigin.y = frame.size.height - clipOrigin.y;
-
- outClipRect.x = (nscoord)clipOrigin.x;
- outClipRect.y = (nscoord)clipOrigin.y;
-
-
- PRBool isVisible;
- IsVisible(isVisible);
- if (isVisible && [mView window] != nil) {
- outClipRect.width = (nscoord)visibleBounds.size.width;
- outClipRect.height = (nscoord)visibleBounds.size.height;
- outWidgetVisible = PR_TRUE;
- }
- else {
- outClipRect.width = 0;
- outClipRect.height = 0;
- outWidgetVisible = PR_FALSE;
- }
- // need to convert view's origin to window coordinates.
- // then, encode as "SetOrigin" ready values.
- outOrigin.x = (nscoord)-viewOrigin.x;
- outOrigin.y = (nscoord)-viewOrigin.y;
-
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- NS_IMETHODIMP nsChildView::StartDrawPlugin()
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- NS_ASSERTION(mIsPluginView, "StartDrawPlugin must only be called on a plugin widget");
- if (!mIsPluginView) return NS_ERROR_FAILURE;
- // Prevent reentrant "drawing" (or in fact reentrant handling of any plugin
- // event). Doing this for both CoreGraphics and QuickDraw plugins restores
- // the 1.8-branch behavior wrt reentrancy, and fixes (or works around) bugs
- // caused by plugins depending on the old behavior -- e.g. bmo bug 409615.
- if (mPluginDrawing)
- return NS_ERROR_FAILURE;
- NSWindow* window = [mView nativeWindow];
- if (!window)
- return NS_ERROR_FAILURE;
-
- // It appears that the WindowRef from which we get the plugin port undergoes the
- // traditional BeginUpdate/EndUpdate cycle, which, if you recall, sets the visible
- // region to the intersection of the visible region and the update region. Since
- // we don't know here if we're being drawn inside a BeginUpdate/EndUpdate pair
- // (which seem to occur in [NSWindow display]), and we don't want to have the burden
- // of correctly doing Carbon invalidates of the plugin rect, we manually set the
- // visible region to be the entire port every time. It is necessary to set up our
- // window's port even for CoreGraphics plugins, because they may still use Carbon
- // internally (see bug #420527 for details).
- CGrafPtr port = ::GetWindowPort(WindowRef([window windowRef]));
- if (!mPluginIsCG)
- port = mPluginPort.qdPort.port;
- RgnHandle pluginRegion = ::NewRgn();
- if (pluginRegion) {
- PRBool portChanged = (port != CGrafPtr(GetQDGlobalsThePort()));
- CGrafPtr oldPort;
- GDHandle oldDevice;
- if (portChanged) {
- ::GetGWorld(&oldPort, &oldDevice);
- ::SetGWorld(port, ::IsPortOffscreen(port) ? nsnull : ::GetMainDevice());
- }
- ::SetOrigin(0, 0);
-
- nsRect clipRect; // this is in native window coordinates
- nsPoint origin;
- PRBool visible;
- GetPluginClipRect(clipRect, origin, visible);
-
- // XXX if we're not visible, set an empty clip region?
- Rect pluginRect;
- ConvertGeckoRectToMacRect(clipRect, pluginRect);
-
- ::RectRgn(pluginRegion, &pluginRect);
- ::SetPortVisibleRegion(port, pluginRegion);
- ::SetPortClipRegion(port, pluginRegion);
-
- // now set up the origin for the plugin
- ::SetOrigin(origin.x, origin.y);
-
- ::DisposeRgn(pluginRegion);
- if (portChanged)
- ::SetGWorld(oldPort, oldDevice);
- }
- mPluginDrawing = PR_TRUE;
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- NS_IMETHODIMP nsChildView::EndDrawPlugin()
- {
- NS_ASSERTION(mIsPluginView, "EndDrawPlugin must only be called on a plugin widget");
- if (!mIsPluginView) return NS_ERROR_FAILURE;
- mPluginDrawing = PR_FALSE;
- return NS_OK;
- }
- NS_IMETHODIMP nsChildView::SetPluginInstanceOwner(nsIPluginInstanceOwner* aInstanceOwner)
- {
- mPluginInstanceOwner = aInstanceOwner;
- return NS_OK;
- }
- void nsChildView::LiveResizeStarted()
- {
- // XXX todo. Use this to disable Java async redraw during resize
- mLiveResizeInProgress = PR_TRUE;
- }
- void nsChildView::LiveResizeEnded()
- {
- mLiveResizeInProgress = PR_FALSE;
- }
- static NSString* ToNSString(const nsAString& aString)
- {
- return [NSString stringWithCharacters:aString.BeginReading()
- length:aString.Length()];
- }
- struct KeyboardLayoutOverride {
- PRInt32 mKeyboardLayout;
- PRBool mOverrideEnabled;
- };
- static KeyboardLayoutOverride gOverrideKeyboardLayout;
- static const PRUint32 sModifierFlagMap[][2] = {
- { nsIWidget::CAPS_LOCK, NSAlphaShiftKeyMask },
- { nsIWidget::SHIFT_L, NSShiftKeyMask },
- { nsIWidget::CTRL_L, NSControlKeyMask },
- { nsIWidget::ALT_L, NSAlternateKeyMask },
- { nsIWidget::COMMAND, NSCommandKeyMask },
- { nsIWidget::NUMERIC_KEY_PAD, NSNumericPadKeyMask },
- { nsIWidget::HELP, NSHelpKeyMask },
- { nsIWidget::FUNCTION, NSFunctionKeyMask }
- };
- nsresult nsChildView::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
- PRInt32 aNativeKeyCode,
- PRUint32 aModifierFlags,
- const nsAString& aCharacters,
- const nsAString& aUnmodifiedCharacters)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
- PRUint32 modifierFlags = 0;
- for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierFlagMap); ++i) {
- if (aModifierFlags & sModifierFlagMap[i][0]) {
- modifierFlags |= sModifierFlagMap[i][1];
- }
- }
- int windowNumber = [[mView window] windowNumber];
- NSEvent* downEvent = [NSEvent keyEventWithType:NSKeyDown
- location:NSMakePoint(0,0)
- modifierFlags:modifierFlags
- timestamp:0
- windowNumber:windowNumber
- context:[NSGraphicsContext currentContext]
- characters:ToNSString(aCharacters)
- charactersIgnoringModifiers:ToNSString(aUnmodifiedCharacters)
- isARepeat:NO
- keyCode:aNativeKeyCode];
- NSEvent* upEvent = [ChildView makeNewCocoaEventWithType:NSKeyUp
- fromEvent:downEvent];
- if (downEvent && upEvent) {
- KeyboardLayoutOverride currentLayout = gOverrideKeyboardLayout;
- gOverrideKeyboardLayout.mKeyboardLayout = aNativeKeyboardLayout;
- gOverrideKeyboardLayout.mOverrideEnabled = PR_TRUE;
- [NSApp sendEvent:downEvent];
- [NSApp sendEvent:upEvent];
- // processKeyDownEvent and keyUp block exceptions so we're sure to
- // reach here to restore gOverrideKeyboardLayout
- gOverrideKeyboardLayout = currentLayout;
- }
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- #pragma mark -
- #ifdef INVALIDATE_DEBUGGING
- static Boolean KeyDown(const UInt8 theKey)
- {
- KeyMap map;
- GetKeys(map);
- return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
- }
- static Boolean caps_lock()
- {
- return KeyDown(0x39);
- }
- static void blinkRect(Rect* r)
- {
- StRegionFromPool oldClip;
- if (oldClip != NULL)
- ::GetClip(oldClip);
- ::ClipRect(r);
- ::InvertRect(r);
- UInt32 end = ::TickCount() + 5;
- while (::TickCount() < end) ;
- ::InvertRect(r);
- if (oldClip != NULL)
- ::SetClip(oldClip);
- }
- static void blinkRgn(RgnHandle rgn)
- {
- StRegionFromPool oldClip;
- if (oldClip != NULL)
- ::GetClip(oldClip);
- ::SetClip(rgn);
- ::InvertRgn(rgn);
- UInt32 end = ::TickCount() + 5;
- while (::TickCount() < end) ;
- ::InvertRgn(rgn);
- if (oldClip != NULL)
- ::SetClip(oldClip);
- }
- #endif
- // Invalidate this component's visible area
- NS_IMETHODIMP nsChildView::Invalidate(PRBool aIsSynchronous)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (!mView || !mVisible)
- return NS_OK;
- if (aIsSynchronous) {
- [mView display];
- }
- else if ([NSView focusView]) {
- // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
- // don't lose it.
- [mView setNeedsPendingDisplay];
- }
- else {
- [mView setNeedsDisplay:YES];
- }
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- // Invalidate this component's visible area
- NS_IMETHODIMP nsChildView::Invalidate(const nsRect &aRect, PRBool aIsSynchronous)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (!mView || !mVisible)
- return NS_OK;
- NSRect r;
- GeckoRectToNSRect(aRect, r);
-
- if (aIsSynchronous) {
- [mView displayRect:r];
- }
- else if ([NSView focusView]) {
- // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
- // don't lose it.
- [mView setNeedsPendingDisplayInRect:r];
- }
- else {
- [mView setNeedsDisplayInRect:r];
- }
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- // Validate the widget
- NS_IMETHODIMP nsChildView::Validate()
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- [mView setNeedsDisplay:NO];
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- // Invalidate this component's visible area
- NS_IMETHODIMP nsChildView::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchronous)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- if (!mView || !mVisible)
- return NS_OK;
- // FIXME rewrite to use a Cocoa region when nsIRegion isn't a QD Region
- NSRect r;
- nsRect bounds;
- nsIRegion* region = const_cast<nsIRegion*>(aRegion); // ugh. this method should be const
- region->GetBoundingBox(&bounds.x, &bounds.y, &bounds.width, &bounds.height);
- GeckoRectToNSRect(bounds, r);
-
- if (aIsSynchronous)
- [mView displayRect:r];
- else
- [mView setNeedsDisplayInRect:r];
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- inline PRUint16 COLOR8TOCOLOR16(PRUint8 color8)
- {
- // return (color8 == 0xFF ? 0xFFFF : (color8 << 8));
- return (color8 << 8) | color8; /* (color8 * 257) == (color8 * 0x0101) */
- }
- // Dummy impl, meant to be overridden
- PRBool
- nsChildView::OnPaint(nsPaintEvent &event)
- {
- return PR_TRUE;
- }
- // this is handled for us by UpdateWidget
- NS_IMETHODIMP nsChildView::Update()
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- // Update means "Flush any pending changes right now." It does *not* mean
- // repaint the world. :) -- dwh
- [mView displayIfNeeded];
- return NS_OK;
- NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
- }
- #pragma mark -
- // Scroll the bits of a view and its children
- // FIXME: I'm sure the invalidating can be optimized, just no time now.
- NS_IMETHODIMP nsChildView::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
- {
- NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
- BOOL viewWasDirty = NO;
- if (mVisible) {
- viewWasDirty = [mView needsDisplay];
- NSSize scrollVector = {aDx,aDy};
- [mView scrollRect: [mView visibleRect] by:scrollVector];
- }
-
- // Scroll the children (even if the widget is not visible)
- for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
- // We use resize rather than move since it gives us control
- // over repainting. We can scroll like a bat out of hell
- // by not wasting time invalidating the widgets, since it's
- // completely unnecessary to do so.
- nsRect bounds;
- kid->GetBounds(bounds);
- kid->Resize(bounds.x + aDx, bounds.y + aDy, bounds.width, bounds.height, PR_FALSE);
- }
- if (mOnDestroyCalled)
- return NS_OK;
- if (mVisible) {
- if (viewWasDirty) {
- [mView setNeedsDisplay:YES];
- }
- else {
- NSRect frame = [mView visibleRect];
- NSRect horizInvalid = frame;
- NSRect vertInvalid = frame;
-
- if (aDx != 0) {
- horizInvalid.size.width = abs(aDx);
- if (aDx < 0)
- horizInvalid.origin.x = frame.origin.x + frame.size.width + aDx;
- [mView setNeedsDisplayInRect: horizInvalid];
- }
- if (aDy != 0) {
- vertInvalid.size.height = abs(aDy);
- if (aDy < 0)
- vertInvalid.origin.y = frame.origin.y + frame.size.height + aDy;
- [mView setNeedsDisplayInRect: vertInvalid];
- }
- // We also need to check for any ChildViews which overlap this widget
- // but are not descendent widgets. If there are any, we need to
- // invalidate the area of this view that these ChildViews will have been
- // blitted into, since these widgets aren't supposed to scroll with
- // this widget.
- // To do this, start at the root Gecko NSView, and walk down along
- // our ancestor view chain, looking at all the subviews in each level
- // of the hierarchy. If we find a non-ancestor view that overlaps
- // this view, invalidate the area around it.
- // We need to convert all rects to a common ancestor view to intersect
- // them, since a view's frame is in the coordinate space of its parent.
- // Use mParentView as the frame of reference.
- NSRect selfFrame = [mParentView convertRect:[mView frame] fromView:[mView superview]];
- NSView* view = mParentView;
- BOOL selfLevel = NO;
- while (!selfLevel) {
- NSView* nextAncestorView = nil;
- NSArray* subviews = [view subviews];
- for (unsigned int i = 0; i < [subviews count]; ++i) {
- NSView* subView = [subviews objectAtIndex: i];
- if (subView == mView)
- selfLevel = YES;
- else if ([mView isDescendantOf:subView])
- nextAncestorView = subView;
- else {
- NSRect intersectArea = NSIntersectionRect([mParentView convertRect:[subView frame] fromView:[subView superview]], selfFrame);
- if (!NSIsEmptyRect(intersectArea)) {
- NSPoint origin = [mView convertPoint:intersectAr…
Large files files are truncated, but you can click here to view the full file