/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsBaseWidget.h" #include "nsIAppShell.h" #include "nsIDeviceContext.h" #include "nsCOMPtr.h" #include "nsIMenuListener.h" #include "nsIEnumerator.h" #include "nsGfxCIID.h" #include "nsWidgetsCID.h" #ifndef LOG_ADDREF_RELEASE NS_IMPL_ISUPPORTS(nsBaseWidget, nsCOMTypeInfo::GetIID()) #else extern "C" { void __log_addref(void* p, int oldrc, int newrc); void __log_release(void* p, int oldrc, int newrc); } NS_IMPL_QUERY_INTERFACE(nsBaseWidget, nsCOMTypeInfo::GetIID()) nsrefcnt nsBaseWidget::AddRef(void) { NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); __log_addref((void*) this, mRefCnt, mRefCnt + 1); return ++mRefCnt; } nsrefcnt nsBaseWidget::Release(void) { __log_release((void*) this, mRefCnt, mRefCnt - 1); NS_PRECONDITION(0 != mRefCnt, "dup release"); if (--mRefCnt == 0) { NS_DELETEXPCOM(this); return 0; } return mRefCnt; } #endif NS_IMPL_ADDREF(nsBaseWidget::Enumerator); NS_IMPL_RELEASE(nsBaseWidget::Enumerator); NS_IMETHODIMP nsBaseWidget::Enumerator::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (NULL == aInstancePtr) return NS_ERROR_NULL_POINTER; if (aIID.Equals(nsCOMTypeInfo::GetIID()) || aIID.Equals(nsCOMTypeInfo::GetIID()) || aIID.Equals(nsCOMTypeInfo::GetIID())) { *aInstancePtr = (void*) this; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } //------------------------------------------------------------------------- // // nsBaseWidget constructor // //------------------------------------------------------------------------- nsBaseWidget::nsBaseWidget() : mBounds(0,0,0,0) { NS_NewISupportsArray(getter_AddRefs(mChildren)); mEventCallback = nsnull; mToolkit = nsnull; mAppShell = nsnull; mMouseListener = nsnull; mEventListener = nsnull; mMenuListener = nsnull; mClientData = nsnull; mContext = nsnull; mCursor = eCursor_standard; mBorderStyle = eBorderStyle_none; mVScrollbar = nsnull; NS_INIT_REFCNT(); } //------------------------------------------------------------------------- // // nsBaseWidget destructor // //------------------------------------------------------------------------- nsBaseWidget::~nsBaseWidget() { NS_IF_RELEASE(mMenuListener); NS_IF_RELEASE(mVScrollbar); } //------------------------------------------------------------------------- // // Basic create. // //------------------------------------------------------------------------- void nsBaseWidget::BaseCreate(nsIWidget *aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsIToolkit *aToolkit, nsWidgetInitData *aInitData) { if (nsnull == mToolkit) { if (nsnull != aToolkit) { mToolkit = (nsIToolkit*)aToolkit; NS_ADDREF(mToolkit); } else { if (nsnull != aParent) { mToolkit = (nsIToolkit*)(aParent->GetToolkit()); // the call AddRef's, we don't have to } // it's some top level window with no toolkit passed in. // Create a default toolkit with the current thread else { static NS_DEFINE_IID(kToolkitCID, NS_TOOLKIT_CID); static NS_DEFINE_IID(kToolkitIID, NS_ITOOLKIT_IID); nsresult res; res = nsComponentManager::CreateInstance(kToolkitCID, nsnull, kToolkitIID, (void **)&mToolkit); if (NS_OK != res) NS_ASSERTION(PR_FALSE, "Can not create a toolkit in nsBaseWidget::Create"); if (mToolkit) mToolkit->Init(PR_GetCurrentThread()); } } } mAppShell = aAppShell; NS_IF_ADDREF(mAppShell); // save the event callback function mEventCallback = aHandleEventFunction; // keep a reference to the device context if (aContext) { mContext = aContext; NS_ADDREF(mContext); } else { nsresult res; static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); res = nsComponentManager::CreateInstance(kDeviceContextCID, nsnull, kDeviceContextIID, (void **)&mContext); if (NS_OK == res) mContext->Init(nsnull); } if (nsnull != aInitData) { PreCreateWidget(aInitData); } if (aParent) { aParent->AddChild(this); } } NS_IMETHODIMP nsBaseWidget::CaptureMouse(PRBool aCapture) { return NS_OK; } //------------------------------------------------------------------------- // // Accessor functions to get/set the client data // //------------------------------------------------------------------------- NS_IMETHODIMP nsBaseWidget::GetClientData(void*& aClientData) { aClientData = mClientData; return NS_OK; } NS_IMETHODIMP nsBaseWidget::SetClientData(void* aClientData) { mClientData = aClientData; return NS_OK; } //------------------------------------------------------------------------- // // Close this nsBaseWidget // //------------------------------------------------------------------------- NS_METHOD nsBaseWidget::Destroy() { // disconnect from the parent nsIWidget *parent = GetParent(); if (parent) { parent->RemoveChild(this); NS_RELEASE(parent); } NS_IF_RELEASE(mVScrollbar); // disconnect listeners. NS_IF_RELEASE(mMouseListener); NS_IF_RELEASE(mEventListener); NS_IF_RELEASE(mMenuListener); return NS_OK; } //------------------------------------------------------------------------- // // Get this nsBaseWidget parent // //------------------------------------------------------------------------- nsIWidget* nsBaseWidget::GetParent(void) { return nsnull; } //------------------------------------------------------------------------- // // Get this nsBaseWidget's list of children // //------------------------------------------------------------------------- nsIEnumerator* nsBaseWidget::GetChildren() { nsIEnumerator* children = nsnull; PRUint32 itemCount = 0; mChildren->Count(&itemCount); if ( itemCount ) { children = new Enumerator(*this); NS_IF_ADDREF(children); } return children; } //------------------------------------------------------------------------- // // Add a child to the list of children // //------------------------------------------------------------------------- void nsBaseWidget::AddChild(nsIWidget* aChild) { mChildren->AppendElement(aChild); } //------------------------------------------------------------------------- // // Remove a child from the list of children // //------------------------------------------------------------------------- void nsBaseWidget::RemoveChild(nsIWidget* aChild) { mChildren->RemoveElement(aChild); } //------------------------------------------------------------------------- // // Get the foreground color // //------------------------------------------------------------------------- nscolor nsBaseWidget::GetForegroundColor(void) { return mForeground; } //------------------------------------------------------------------------- // // Set the foreground color // //------------------------------------------------------------------------- NS_METHOD nsBaseWidget::SetForegroundColor(const nscolor &aColor) { mForeground = aColor; return NS_OK; } //------------------------------------------------------------------------- // // Get the background color // //------------------------------------------------------------------------- nscolor nsBaseWidget::GetBackgroundColor(void) { return mBackground; } //------------------------------------------------------------------------- // // Set the background color // //------------------------------------------------------------------------- NS_METHOD nsBaseWidget::SetBackgroundColor(const nscolor &aColor) { mBackground = aColor; return NS_OK; } //------------------------------------------------------------------------- // // Get this component cursor // //------------------------------------------------------------------------- nsCursor nsBaseWidget::GetCursor() { return mCursor; } NS_METHOD nsBaseWidget::SetCursor(nsCursor aCursor) { mCursor = aCursor; return NS_OK; } //------------------------------------------------------------------------- // // Create a rendering context from this nsBaseWidget // //------------------------------------------------------------------------- nsIRenderingContext* nsBaseWidget::GetRenderingContext() { nsIRenderingContext *renderingCtx = NULL; nsresult res; static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID); static NS_DEFINE_IID(kRenderingContextIID, NS_IRENDERING_CONTEXT_IID); res = nsComponentManager::CreateInstance(kRenderingContextCID, nsnull, kRenderingContextIID, (void **)&renderingCtx); if (NS_OK == res) renderingCtx->Init(mContext, this); NS_ASSERTION(NULL != renderingCtx, "Null rendering context"); return renderingCtx; } //------------------------------------------------------------------------- // // Return the toolkit this widget was created on // //------------------------------------------------------------------------- nsIToolkit* nsBaseWidget::GetToolkit() { NS_IF_ADDREF(mToolkit); return mToolkit; } //------------------------------------------------------------------------- // // Return the used device context // //------------------------------------------------------------------------- nsIDeviceContext* nsBaseWidget::GetDeviceContext() { NS_IF_ADDREF(mContext); return mContext; } //------------------------------------------------------------------------- // // Return the App Shell // //------------------------------------------------------------------------- nsIAppShell *nsBaseWidget::GetAppShell() { NS_IF_ADDREF(mAppShell); return mAppShell; } //------------------------------------------------------------------------- // // Destroy the window // //------------------------------------------------------------------------- void nsBaseWidget::OnDestroy() { // release references to device context, toolkit, and app shell NS_IF_RELEASE(mContext); NS_IF_RELEASE(mToolkit); NS_IF_RELEASE(mAppShell); } //------------------------------------------------------------------------- // // Constructor // //------------------------------------------------------------------------- nsBaseWidget::Enumerator::Enumerator(nsBaseWidget & inParent) : mParent(inParent), mCurrentPosition(0) { NS_INIT_REFCNT(); } //------------------------------------------------------------------------- // // Destructor // //------------------------------------------------------------------------- nsBaseWidget::Enumerator::~Enumerator() { } //enumerator interfaces NS_IMETHODIMP nsBaseWidget::Enumerator::Next() { PRUint32 itemCount = 0; mParent.mChildren->Count(&itemCount); if (mCurrentPosition < itemCount - 1 ) mCurrentPosition ++; else return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsBaseWidget::Enumerator::Prev() { if (mCurrentPosition > 0 ) mCurrentPosition --; else return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsBaseWidget::Enumerator::CurrentItem(nsISupports **aItem) { if (!aItem) return NS_ERROR_NULL_POINTER; PRUint32 itemCount = 0; mParent.mChildren->Count(&itemCount); if ( mCurrentPosition < itemCount ) { nsISupports* widget = mParent.mChildren->ElementAt(mCurrentPosition); // NS_IF_ADDREF(widget); already addref'd in nsSupportsArray::ElementAt() *aItem = widget; } else return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsBaseWidget::Enumerator::First() { PRUint32 itemCount = 0; mParent.mChildren->Count(&itemCount); if ( itemCount ) { mCurrentPosition = 0; return NS_OK; } else return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsBaseWidget::Enumerator::Last() { PRUint32 itemCount = 0; mParent.mChildren->Count(&itemCount); if ( itemCount ) { mCurrentPosition = itemCount - 1; return NS_OK; } else return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsBaseWidget::Enumerator::IsDone() { PRUint32 itemCount = 0; mParent.mChildren->Count(&itemCount); if ((mCurrentPosition == itemCount-1) || (itemCount == 0) ){ //empty lists always return done return NS_OK; } else { return NS_COMFALSE; } return NS_OK; } NS_METHOD nsBaseWidget::SetWindowType(nsWindowType aWindowType) { mWindowType = aWindowType; return NS_OK; } NS_METHOD nsBaseWidget::SetBorderStyle(nsBorderStyle aBorderStyle) { mBorderStyle = aBorderStyle; return NS_OK; } NS_METHOD nsBaseWidget::SetTitle(const nsString& aTitle) { return NS_OK; } /** * Processes a mouse pressed event * **/ NS_METHOD nsBaseWidget::AddMouseListener(nsIMouseListener * aListener) { NS_PRECONDITION(mMouseListener == nsnull, "Null mouse listener"); NS_IF_RELEASE(mMouseListener); NS_ADDREF(aListener); mMouseListener = aListener; return NS_OK; } /** * Processes a mouse pressed event * **/ NS_METHOD nsBaseWidget::AddEventListener(nsIEventListener * aListener) { NS_PRECONDITION(mEventListener == nsnull, "Null mouse listener"); NS_IF_RELEASE(mEventListener); NS_ADDREF(aListener); mEventListener = aListener; return NS_OK; } /** * Add a menu listener * This interface should only be called by the menu services manager * This will AddRef() the menu listener * This will Release() a previously set menu listener * **/ NS_METHOD nsBaseWidget::AddMenuListener(nsIMenuListener * aListener) { NS_IF_RELEASE(mMenuListener); NS_IF_ADDREF(aListener); mMenuListener = aListener; return NS_OK; } /** * If the implementation of nsWindow supports borders this method MUST be overridden * **/ NS_METHOD nsBaseWidget::GetClientBounds(nsRect &aRect) { return GetBounds(aRect); } /** * If the implementation of nsWindow supports borders this method MUST be overridden * **/ NS_METHOD nsBaseWidget::GetBounds(nsRect &aRect) { aRect = mBounds; return NS_OK; } /** * If the implementation of nsWindow supports borders this method MUST be overridden * **/ NS_METHOD nsBaseWidget::GetBoundsAppUnits(nsRect &aRect, float aAppUnits) { aRect = mBounds; // Convert to twips aRect.x = nscoord((PRFloat64)aRect.x * aAppUnits); aRect.y = nscoord((PRFloat64)aRect.y * aAppUnits); aRect.width = nscoord((PRFloat64)aRect.width * aAppUnits); aRect.height = nscoord((PRFloat64)aRect.height * aAppUnits); return NS_OK; } /** * * **/ NS_METHOD nsBaseWidget::SetBounds(const nsRect &aRect) { mBounds = aRect; return NS_OK; } /** * Calculates the border width and height * **/ NS_METHOD nsBaseWidget::GetBorderSize(PRInt32 &aWidth, PRInt32 &aHeight) { nsRect rectWin; nsRect rect; GetBounds(rectWin); GetClientBounds(rect); aWidth = (rectWin.width - rect.width) / 2; aHeight = (rectWin.height - rect.height) / 2; return NS_OK; } /** * Calculates the border width and height * **/ void nsBaseWidget::DrawScaledRect(nsIRenderingContext& aRenderingContext, const nsRect & aRect, float aScale, float aAppUnits) { nsRect rect = aRect; float x = (float)rect.x; float y = (float)rect.y; float w = (float)rect.width; float h = (float)rect.height; float twoAppUnits = aAppUnits * 2.0f; for (int i=0;iGetCanonicalPixelScale(scale); context->GetDevUnitsToAppUnits(appUnits); GetBoundsAppUnits(rect, appUnits); aRenderingContext.SetColor(NS_RGB(0,0,0)); DrawScaledRect(aRenderingContext, rect, scale, appUnits); NS_RELEASE(context); return NS_OK; } NS_METHOD nsBaseWidget::SetVerticalScrollbar(nsIWidget * aWidget) { NS_IF_RELEASE(mVScrollbar); mVScrollbar = aWidget; NS_IF_ADDREF(mVScrollbar); return NS_OK; } NS_METHOD nsBaseWidget::EnableFileDrop(PRBool aEnable) { return NS_OK; } NS_METHOD nsBaseWidget::SetModal(void) { return NS_ERROR_FAILURE; } #ifdef DEBUG // // Convert a GUI event message code to a string. // Makes it a lot easier to debug events. // // See gtk/nsWidget.cpp and windows/nsWindow.cpp // for a DebugPrintEvent() function that uses // this. // nsAutoString nsBaseWidget::GuiEventToString(nsGUIEvent & aEvent) { nsString eventName = "UNKNOWN"; #define _ASSIGN_eventName(_value,_name)\ case _value: eventName = _name ; break switch(aEvent.message) { _ASSIGN_eventName(NS_BLUR_CONTENT,"NS_BLUR_CONTENT"); _ASSIGN_eventName(NS_CONTROL_CHANGE,"NS_CONTROL_CHANGE"); _ASSIGN_eventName(NS_CREATE,"NS_CREATE"); _ASSIGN_eventName(NS_DESTROY,"NS_DESTROY"); _ASSIGN_eventName(NS_DRAGDROP_GESTURE,"NS_DRAGDROP_GESTURE"); _ASSIGN_eventName(NS_DRAGDROP_DROP,"NS_DRAGDROP_DROP"); _ASSIGN_eventName(NS_DRAGDROP_ENTER,"NS_DRAGDROP_ENTER"); _ASSIGN_eventName(NS_DRAGDROP_EXIT,"NS_DRAGDROP_EXIT"); _ASSIGN_eventName(NS_DRAGDROP_OVER,"NS_DRAGDROP_OVER"); _ASSIGN_eventName(NS_FOCUS_CONTENT,"NS_FOCUS_CONTENT"); _ASSIGN_eventName(NS_FORM_SELECTED,"NS_FORM_SELECTED"); _ASSIGN_eventName(NS_FORM_CHANGE,"NS_FORM_CHANGE"); _ASSIGN_eventName(NS_FORM_RESET,"NS_FORM_RESET"); _ASSIGN_eventName(NS_FORM_SUBMIT,"NS_FORM_SUBMIT"); _ASSIGN_eventName(NS_GOTFOCUS,"NS_GOTFOCUS"); _ASSIGN_eventName(NS_IMAGE_ABORT,"NS_IMAGE_ABORT"); _ASSIGN_eventName(NS_IMAGE_ERROR,"NS_IMAGE_ERROR"); _ASSIGN_eventName(NS_IMAGE_LOAD,"NS_IMAGE_LOAD"); _ASSIGN_eventName(NS_KEY_DOWN,"NS_KEY_DOWN"); _ASSIGN_eventName(NS_KEY_PRESS,"NS_KEY_PRESS"); _ASSIGN_eventName(NS_KEY_UP,"NS_KEY_UP"); _ASSIGN_eventName(NS_LOSTFOCUS,"NS_LOSTFOCUS"); _ASSIGN_eventName(NS_MENU_SELECTED,"NS_MENU_SELECTED"); _ASSIGN_eventName(NS_MOUSE_ENTER,"NS_MOUSE_ENTER"); _ASSIGN_eventName(NS_MOUSE_EXIT,"NS_MOUSE_EXIT"); _ASSIGN_eventName(NS_MOUSE_LEFT_BUTTON_DOWN,"NS_MOUSE_LEFT_BUTTON_DOWN"); _ASSIGN_eventName(NS_MOUSE_LEFT_BUTTON_UP,"NS_MOUSE_LEFT_BUTTON_UP"); _ASSIGN_eventName(NS_MOUSE_LEFT_CLICK,"NS_MOUSE_LEFT_CLICK"); _ASSIGN_eventName(NS_MOUSE_LEFT_DOUBLECLICK,"NS_MOUSE_LEFT_DOUBLECLICK"); _ASSIGN_eventName(NS_MOUSE_MIDDLE_BUTTON_DOWN,"NS_MOUSE_MIDDLE_BUTTON_DOWN"); _ASSIGN_eventName(NS_MOUSE_MIDDLE_BUTTON_UP,"NS_MOUSE_MIDDLE_BUTTON_UP"); _ASSIGN_eventName(NS_MOUSE_MIDDLE_CLICK,"NS_MOUSE_MIDDLE_CLICK"); _ASSIGN_eventName(NS_MOUSE_MIDDLE_DOUBLECLICK,"NS_MOUSE_MIDDLE_DOUBLECLICK"); _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE"); _ASSIGN_eventName(NS_MOUSE_RIGHT_BUTTON_DOWN,"NS_MOUSE_RIGHT_BUTTON_DOWN"); _ASSIGN_eventName(NS_MOUSE_RIGHT_BUTTON_UP,"NS_MOUSE_RIGHT_BUTTON_UP"); _ASSIGN_eventName(NS_MOUSE_RIGHT_CLICK,"NS_MOUSE_RIGHT_CLICK"); _ASSIGN_eventName(NS_MOUSE_RIGHT_DOUBLECLICK,"NS_MOUSE_RIGHT_DOUBLECLICK"); _ASSIGN_eventName(NS_MOVE,"NS_MOVE"); _ASSIGN_eventName(NS_PAGE_LOAD,"NS_PAGE_LOAD"); _ASSIGN_eventName(NS_PAGE_UNLOAD,"NS_PAGE_UNLOAD"); _ASSIGN_eventName(NS_PAINT,"NS_PAINT"); _ASSIGN_eventName(NS_MENU_CREATE,"NS_MENU_CREATE"); _ASSIGN_eventName(NS_MENU_DESTROY,"NS_MENU_DESTROY"); _ASSIGN_eventName(NS_MENU_ACTION, "NS_MENU_ACTION"); _ASSIGN_eventName(NS_SCROLLBAR_LINE_NEXT,"NS_SCROLLBAR_LINE_NEXT"); _ASSIGN_eventName(NS_SCROLLBAR_LINE_PREV,"NS_SCROLLBAR_LINE_PREV"); _ASSIGN_eventName(NS_SCROLLBAR_PAGE_NEXT,"NS_SCROLLBAR_PAGE_NEXT"); _ASSIGN_eventName(NS_SCROLLBAR_PAGE_PREV,"NS_SCROLLBAR_PAGE_PREV"); _ASSIGN_eventName(NS_SCROLLBAR_POS,"NS_SCROLLBAR_POS"); _ASSIGN_eventName(NS_SIZE,"NS_SIZE"); #undef _ASSIGN_eventName default: { char buf[32]; sprintf(buf,"UNKNOWN: %d",aEvent.message); eventName = buf; } break; } return nsAutoString(eventName); } #endif