Back to index

lightning-sunbird  0.9+nobinonly
nsDOMUIEvent.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Steve Clark (buster@netscape.com)
00024  *   Ilya Konstantinov (mozilla-code@future.shiny.co.il)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsDOMUIEvent.h"
00042 #include "nsIPresShell.h"
00043 #include "nsIInterfaceRequestorUtils.h"
00044 #include "nsIDOMWindowInternal.h"
00045 #include "nsIDOMNode.h"
00046 #include "nsIContent.h"
00047 #include "nsContentUtils.h"
00048 #include "nsIViewManager.h"
00049 #include "nsIScrollableView.h"
00050 #include "nsIWidget.h"
00051 #include "nsIPresShell.h"
00052 #include "nsIEventStateManager.h"
00053 #include "nsIFrame.h"
00054 
00055 nsDOMUIEvent::nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent)
00056   : nsDOMEvent(aPresContext, aEvent ?
00057                NS_STATIC_CAST(nsEvent *, aEvent) :
00058                NS_STATIC_CAST(nsEvent *, new nsUIEvent(PR_FALSE, 0, 0)))
00059 {
00060   if (aEvent) {
00061     mEventIsInternal = PR_FALSE;
00062   }
00063   else {
00064     mEventIsInternal = PR_TRUE;
00065     mEvent->time = PR_Now();
00066   }
00067   
00068   // Fill mDetail and mView according to the mEvent (widget-generated
00069   // event) we've got
00070   switch(mEvent->eventStructType)
00071   {
00072     case NS_UI_EVENT:
00073     {
00074       nsUIEvent *event = NS_STATIC_CAST(nsUIEvent*, mEvent);
00075       mDetail = event->detail;
00076       break;
00077     }
00078 
00079     case NS_SCROLLPORT_EVENT:
00080     {
00081       nsScrollPortEvent* scrollEvent = NS_STATIC_CAST(nsScrollPortEvent*, mEvent);
00082       mDetail = (PRInt32)scrollEvent->orient;
00083       break;
00084     }
00085 
00086     default:
00087       mDetail = 0;
00088       break;
00089   }
00090 
00091   mView = nsnull;
00092   if (mPresContext)
00093   {
00094     nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
00095     if (container)
00096     {
00097        nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(container);
00098        if (window)
00099           mView = do_QueryInterface(window);
00100     }
00101   }
00102 }
00103 
00104 NS_IMPL_ADDREF_INHERITED(nsDOMUIEvent, nsDOMEvent)
00105 NS_IMPL_RELEASE_INHERITED(nsDOMUIEvent, nsDOMEvent)
00106 
00107 NS_INTERFACE_MAP_BEGIN(nsDOMUIEvent)
00108   NS_INTERFACE_MAP_ENTRY(nsIDOMUIEvent)
00109   NS_INTERFACE_MAP_ENTRY(nsIDOMNSUIEvent)
00110   NS_INTERFACE_MAP_ENTRY(nsIPrivateCompositionEvent)
00111   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(UIEvent)
00112 NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
00113 
00114 nsPoint nsDOMUIEvent::GetScreenPoint() {
00115   if (!mEvent || 
00116        // XXXldb Why not NS_MOUSE_SCROLL_EVENT?
00117        (mEvent->eventStructType != NS_MOUSE_EVENT &&
00118         mEvent->eventStructType != NS_POPUP_EVENT &&
00119         !NS_IS_DRAG_EVENT(mEvent))) {
00120     return nsPoint(0, 0);
00121   }
00122 
00123   if (!((nsGUIEvent*)mEvent)->widget ) {
00124     return mEvent->refPoint;
00125   }
00126     
00127   nsRect bounds(mEvent->refPoint, nsSize(1, 1));
00128   nsRect offset;
00129   ((nsGUIEvent*)mEvent)->widget->WidgetToScreen ( bounds, offset );
00130   return offset.TopLeft();
00131 }
00132 
00133 nsPoint nsDOMUIEvent::GetClientPoint() {
00134   if (!mEvent || 
00135        // XXXldb Why not NS_MOUSE_SCROLL_EVENT?
00136        (mEvent->eventStructType != NS_MOUSE_EVENT &&
00137         mEvent->eventStructType != NS_POPUP_EVENT &&
00138         !NS_IS_DRAG_EVENT(mEvent)) ||
00139       !mPresContext) {
00140     return nsPoint(0, 0);
00141   }
00142 
00143   //My god, man, there *must* be a better way to do this.
00144   nsCOMPtr<nsIWidget> docWidget;
00145   nsIPresShell *presShell = mPresContext->GetPresShell();
00146   if (presShell) {
00147     nsIViewManager* vm = presShell->GetViewManager();
00148     if (vm) {
00149       vm->GetWidget(getter_AddRefs(docWidget));
00150     }
00151   }
00152 
00153   nsPoint pt = mEvent->refPoint;
00154 
00155   nsCOMPtr<nsIWidget> eventWidget = ((nsGUIEvent*)mEvent)->widget;
00156   if (!eventWidget || !docWidget) {
00157     return mEvent->point;
00158   }
00159   
00160   // BUG 296004 (see also BUG 242833)
00161   //
00162   // For document events we want to return a point relative to the local view manager,
00163   // (docWidget) not to the generating widget (eventWidget). However, for global events
00164   // we want to leave them relative to the generating widget.
00165   //
00166   // To determine which we are, we use the fact that currently for the latter case our
00167   // docWidget and eventWidget won't be linked together in the widget hierarchy. That
00168   // means that the coordinate space transform which follows wouldn't have worked
00169   // anyway... actually what we want is for all users of this and refPoint to agree
00170   // gracefully on what coordinate system to use, but that's a more involved change.
00171   
00172   nsCOMPtr<nsIWidget> eventParent = eventWidget;
00173   for (;;) {
00174     nsCOMPtr<nsIWidget> t = dont_AddRef(eventParent->GetParent());
00175     if (!t)
00176       break;
00177     eventParent = t;
00178   }
00179 
00180   nsCOMPtr<nsIWidget> docParent = docWidget;
00181   for (;;) {
00182     nsCOMPtr<nsIWidget> t = dont_AddRef(docParent->GetParent());
00183     if (!t)
00184       break;
00185     docParent = t;
00186   }
00187 
00188   if (docParent != eventParent)
00189     return pt;
00190   
00191   while (eventWidget && docWidget != eventWidget) {
00192     nsWindowType windowType;
00193     eventWidget->GetWindowType(windowType);
00194     if (windowType == eWindowType_popup)
00195       break;
00196 
00197     nsRect bounds;
00198     eventWidget->GetBounds(bounds);
00199     pt += bounds.TopLeft();
00200     eventWidget = dont_AddRef(eventWidget->GetParent());
00201   }
00202   
00203   if (eventWidget != docWidget) {
00204     // docWidget wasn't on the chain from the event widget to the root
00205     // of the widget tree (or the nearest popup). OK, so now pt is
00206     // relative to eventWidget; to get it relative to docWidget, we
00207     // need to subtract docWidget's offset from eventWidget.
00208     while (docWidget && docWidget != eventWidget) {
00209       nsWindowType windowType;
00210       docWidget->GetWindowType(windowType);
00211       if (windowType == eWindowType_popup) {
00212         // oh dear. the doc and the event were in different popups?
00213         // That shouldn't happen.
00214         NS_NOTREACHED("doc widget and event widget are in different popups. That's dumb.");
00215         break;
00216       }
00217       
00218       nsRect bounds;
00219       docWidget->GetBounds(bounds);
00220       pt -= bounds.TopLeft();
00221       docWidget = dont_AddRef(docWidget->GetParent());
00222     }
00223   }
00224   
00225   return pt;
00226 }
00227 
00228 NS_IMETHODIMP
00229 nsDOMUIEvent::GetView(nsIDOMAbstractView** aView)
00230 {
00231   *aView = mView;
00232   NS_IF_ADDREF(*aView);
00233   return NS_OK;
00234 }
00235 
00236 NS_IMETHODIMP
00237 nsDOMUIEvent::GetDetail(PRInt32* aDetail)
00238 {
00239   *aDetail = mDetail;
00240   return NS_OK;
00241 }
00242 
00243 NS_IMETHODIMP
00244 nsDOMUIEvent::InitUIEvent(const nsAString & typeArg, PRBool canBubbleArg, PRBool cancelableArg, nsIDOMAbstractView *viewArg, PRInt32 detailArg)
00245 {
00246   nsresult rv = nsDOMEvent::InitEvent(typeArg, canBubbleArg, cancelableArg);
00247   NS_ENSURE_SUCCESS(rv, rv);
00248   
00249   mDetail = detailArg;
00250   mView = viewArg;
00251 
00252   return NS_OK;
00253 }
00254 
00255 // ---- nsDOMNSUIEvent implementation -------------------
00256 
00257 NS_IMETHODIMP
00258 nsDOMUIEvent::GetPageX(PRInt32* aPageX)
00259 {
00260   NS_ENSURE_ARG_POINTER(aPageX);
00261   nsresult ret = NS_OK;
00262   PRInt32 scrollX = 0;
00263   nsIScrollableView* view = nsnull;
00264   float p2t, t2p;
00265 
00266   GetScrollInfo(&view, &p2t, &t2p);
00267   if(view) {
00268     nscoord xPos, yPos;
00269     ret = view->GetScrollPosition(xPos, yPos);
00270     scrollX = NSTwipsToIntPixels(xPos, t2p);
00271   }
00272 
00273   if (NS_SUCCEEDED(ret)) {
00274     *aPageX = GetClientPoint().x + scrollX;
00275   }
00276 
00277   return ret;
00278 }
00279 
00280 NS_IMETHODIMP
00281 nsDOMUIEvent::GetPageY(PRInt32* aPageY)
00282 {
00283   NS_ENSURE_ARG_POINTER(aPageY);
00284   nsresult ret = NS_OK;
00285   PRInt32 scrollY = 0;
00286   nsIScrollableView* view = nsnull;
00287   float p2t, t2p;
00288 
00289   GetScrollInfo(&view, &p2t, &t2p);
00290   if(view) {
00291     nscoord xPos, yPos;
00292     ret = view->GetScrollPosition(xPos, yPos);
00293     scrollY = NSTwipsToIntPixels(yPos, t2p);
00294   }
00295 
00296   if (NS_SUCCEEDED(ret)) {
00297     *aPageY = GetClientPoint().y + scrollY;
00298   }
00299 
00300   return ret;
00301 }
00302 
00303 NS_IMETHODIMP
00304 nsDOMUIEvent::GetWhich(PRUint32* aWhich)
00305 {
00306   NS_ENSURE_ARG_POINTER(aWhich);
00307   // Usually we never reach here, as this is reimplemented for mouse and keyboard events.
00308   *aWhich = 0;
00309   return NS_OK;
00310 }
00311 
00312 NS_IMETHODIMP
00313 nsDOMUIEvent::GetRangeParent(nsIDOMNode** aRangeParent)
00314 {
00315   NS_ENSURE_ARG_POINTER(aRangeParent);
00316   nsIFrame* targetFrame = nsnull;
00317 
00318   if (mPresContext) {
00319     mPresContext->EventStateManager()->GetEventTarget(&targetFrame);
00320   }
00321 
00322   *aRangeParent = nsnull;
00323 
00324   if (targetFrame) {
00325     nsCOMPtr<nsIContent> parent;
00326     PRInt32 offset, endOffset;
00327     PRBool beginOfContent;
00328     if (NS_SUCCEEDED(targetFrame->GetContentAndOffsetsFromPoint(mPresContext, 
00329                                               mEvent->point,
00330                                               getter_AddRefs(parent),
00331                                               offset,
00332                                               endOffset,
00333                                               beginOfContent))) {
00334       if (parent) {
00335         return CallQueryInterface(parent, aRangeParent);
00336       }
00337     }
00338   }
00339 
00340   return NS_OK;
00341 }
00342 
00343 NS_IMETHODIMP
00344 nsDOMUIEvent::GetRangeOffset(PRInt32* aRangeOffset)
00345 {
00346   NS_ENSURE_ARG_POINTER(aRangeOffset);
00347   nsIFrame* targetFrame = nsnull;
00348 
00349   if (mPresContext) {
00350     mPresContext->EventStateManager()->GetEventTarget(&targetFrame);
00351   }
00352 
00353   if (targetFrame) {
00354     nsIContent* parent = nsnull;
00355     PRInt32 endOffset;
00356     PRBool beginOfContent;
00357     if (NS_SUCCEEDED(targetFrame->GetContentAndOffsetsFromPoint(mPresContext, 
00358                                               mEvent->point,
00359                                               &parent,
00360                                               *aRangeOffset,
00361                                               endOffset,
00362                                               beginOfContent))) {
00363       NS_IF_RELEASE(parent);
00364       return NS_OK;
00365     }
00366   }
00367   *aRangeOffset = 0;
00368   return NS_OK;
00369 }
00370 
00371 NS_IMETHODIMP
00372 nsDOMUIEvent::GetCancelBubble(PRBool* aCancelBubble)
00373 {
00374   NS_ENSURE_ARG_POINTER(aCancelBubble);
00375   if (mEvent->flags & NS_EVENT_FLAG_BUBBLE || mEvent->flags & NS_EVENT_FLAG_INIT) {
00376     *aCancelBubble = (mEvent->flags &= NS_EVENT_FLAG_STOP_DISPATCH) ? PR_TRUE : PR_FALSE;
00377   }
00378   else {
00379     *aCancelBubble = PR_FALSE;
00380   }
00381   return NS_OK;
00382 }
00383 
00384 NS_IMETHODIMP
00385 nsDOMUIEvent::SetCancelBubble(PRBool aCancelBubble)
00386 {
00387   if (mEvent->flags & NS_EVENT_FLAG_BUBBLE || mEvent->flags & NS_EVENT_FLAG_INIT) {
00388     if (aCancelBubble) {
00389       mEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
00390     }
00391     else {
00392       mEvent->flags &= ~NS_EVENT_FLAG_STOP_DISPATCH;
00393     }
00394   }
00395   return NS_OK;
00396 }
00397 
00398 NS_IMETHODIMP
00399 nsDOMUIEvent::GetLayerX(PRInt32* aLayerX)
00400 {
00401   NS_ENSURE_ARG_POINTER(aLayerX);
00402   if (!mEvent || (mEvent->eventStructType != NS_MOUSE_EVENT) ||
00403       !mPresContext) {
00404     *aLayerX = 0;
00405     return NS_OK;
00406   }
00407 
00408   float t2p;
00409   t2p = mPresContext->TwipsToPixels();
00410   *aLayerX = NSTwipsToIntPixels(mEvent->point.x, t2p);
00411   return NS_OK;
00412 }
00413 
00414 NS_IMETHODIMP
00415 nsDOMUIEvent::GetLayerY(PRInt32* aLayerY)
00416 {
00417   NS_ENSURE_ARG_POINTER(aLayerY);
00418   if (!mEvent || (mEvent->eventStructType != NS_MOUSE_EVENT) ||
00419       !mPresContext) {
00420     *aLayerY = 0;
00421     return NS_OK;
00422   }
00423 
00424   float t2p;
00425   t2p = mPresContext->TwipsToPixels();
00426   *aLayerY = NSTwipsToIntPixels(mEvent->point.y, t2p);
00427   return NS_OK;
00428 }
00429 
00430 NS_IMETHODIMP
00431 nsDOMUIEvent::GetIsChar(PRBool* aIsChar)
00432 {
00433   switch(mEvent->eventStructType)
00434   {
00435     case NS_KEY_EVENT:
00436       *aIsChar = ((nsKeyEvent*)mEvent)->isChar;
00437       return NS_OK;
00438     case NS_TEXT_EVENT:
00439       *aIsChar = ((nsTextEvent*)mEvent)->isChar;
00440       return NS_OK;
00441     default:
00442       *aIsChar = PR_FALSE;
00443       return NS_OK;
00444   }
00445 }
00446 
00447 NS_IMETHODIMP
00448 nsDOMUIEvent::GetPreventDefault(PRBool* aReturn)
00449 {
00450   NS_ENSURE_ARG_POINTER(aReturn);
00451   *aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
00452 
00453   return NS_OK;
00454 }
00455 
00456 nsresult
00457 nsDOMUIEvent::GetScrollInfo(nsIScrollableView** aScrollableView,
00458                             float* aP2T, float* aT2P)
00459 {
00460   NS_ENSURE_ARG_POINTER(aScrollableView);
00461   NS_ENSURE_ARG_POINTER(aP2T);
00462   NS_ENSURE_ARG_POINTER(aT2P);
00463   if (!mPresContext) {
00464     *aScrollableView = nsnull;
00465     return NS_ERROR_FAILURE;
00466   }
00467 
00468   *aP2T = mPresContext->PixelsToTwips();
00469   *aT2P = mPresContext->TwipsToPixels();
00470 
00471   nsIPresShell *presShell = mPresContext->GetPresShell();
00472   if (presShell) {
00473     nsIViewManager* vm = presShell->GetViewManager();
00474     if(vm) {
00475       return vm->GetRootScrollableView(aScrollableView);
00476     }
00477   }
00478   return NS_OK;
00479 }
00480 
00481 NS_METHOD nsDOMUIEvent::GetCompositionReply(nsTextEventReply** aReply)
00482 {
00483   if((mEvent->eventStructType == NS_RECONVERSION_EVENT) ||
00484      (mEvent->message == NS_COMPOSITION_START) ||
00485      (mEvent->message == NS_COMPOSITION_QUERY))
00486   {
00487     *aReply = &(NS_STATIC_CAST(nsCompositionEvent*, mEvent)->theReply);
00488     return NS_OK;
00489   }
00490   *aReply = nsnull;
00491   return NS_ERROR_FAILURE;
00492 }
00493 
00494 NS_METHOD
00495 nsDOMUIEvent::GetReconversionReply(nsReconversionEventReply** aReply)
00496 {
00497   if (mEvent->eventStructType == NS_RECONVERSION_EVENT)
00498   {
00499     *aReply = &(NS_STATIC_CAST(nsReconversionEvent*, mEvent)->theReply);
00500     return NS_OK;
00501   }
00502   *aReply = nsnull;
00503   return NS_ERROR_FAILURE;
00504 }
00505 
00506 NS_METHOD
00507 nsDOMUIEvent::GetQueryCaretRectReply(nsQueryCaretRectEventReply** aReply)
00508 {
00509   if (mEvent->eventStructType == NS_QUERYCARETRECT_EVENT)
00510   {
00511     *aReply = &(NS_STATIC_CAST(nsQueryCaretRectEvent*, mEvent)->theReply);
00512     return NS_OK;
00513   }
00514   *aReply = nsnull;
00515   return NS_ERROR_FAILURE;
00516 }
00517 
00518 nsresult NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult,
00519                           nsPresContext* aPresContext,
00520                           nsGUIEvent *aEvent) 
00521 {
00522   nsDOMUIEvent* it = new nsDOMUIEvent(aPresContext, aEvent);
00523   if (nsnull == it) {
00524     return NS_ERROR_OUT_OF_MEMORY;
00525   }
00526 
00527   return CallQueryInterface(it, aInstancePtrResult);
00528 }