1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 tw=80 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla's Element Optimizeing extension.
18 * The Initial Developer of the Original Code is the Mozilla Foundation.
19 * Portions created by the Initial Developer are Copyright (C) 2006
20 * the Initial Developer. All Rights Reserved.
23 * Oleg Romashin <romaxa@gmail.com> (original author)
24 * Brad Lassey <blassey@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsCURILoader.h"
41 #include "nsICategoryManager.h"
42 #include "nsIDOMAbstractView.h"
43 #include "nsIDOMDocument.h"
44 #include "nsIDOMDocumentView.h"
45 #include "nsIDOMHTMLElement.h"
46 #include "nsIDOMHTMLIFrameElement.h"
47 #include "nsIDOMNSDocument.h"
48 #include "nsIDOMNSElement.h"
49 #include "nsIDOMNSHTMLElement.h"
50 #include "nsIDOMNode.h"
51 #include "nsIDOMNodeList.h"
52 #include "nsIDOMWindow.h"
53 #include "nsIDOMWindowCollection.h"
54 #include "nsIDocument.h"
55 #include "nsIGenericFactory.h"
56 #include "nsIObserver.h"
58 #include "nsIPresShell.h"
59 #include "nsIStyleSheetService.h"
60 #include "nsIWebProgress.h"
61 #include "nsIWebProgressListener.h"
62 #include "nsIWindowWatcher.h"
63 #include "nsNetUtil.h"
65 #include "nsStringGlue.h"
66 #include "nsWeakReference.h"
67 #include "nsIWebBrowser.h"
68 #include "nsIObserverService.h"
69 #include "nsIDOMEventTarget.h"
70 #include "nsPIDOMWindow.h"
71 #include "nsIDOMWindow.h"
73 #include "nsIDOM3EventTarget.h"
74 #include "nsIDOMKeyListener.h"
75 #include "nsIDOMCompositionListener.h"
76 #include "nsIDOMTextListener.h"
77 #include "nsIDOMMouseMotionListener.h"
78 #include "nsIDOMMouseListener.h"
79 #include "nsIDOMMouseEvent.h"
81 #include "nsGUIEvent.h"
82 #include "nsIViewManager.h"
84 const int MIN_INT
=((int) (1 << (sizeof(int) * 8 - 1)));
86 static int g_lastX
=MIN_INT
;
87 static int g_lastY
=MIN_INT
;
88 static PRBool g_panning
= PR_FALSE
;
89 static PRBool g_is_scrollable
= PR_FALSE
;
92 #define NS_FRAME_HAS_RELATIVE_SIZE 0x01000000
93 #define NS_FRAME_HAS_OPTIMIZEDVIEW 0x02000000
95 // TODO auto reload nsWidgetUtils in C.
96 class nsWidgetUtils
: public nsIObserver
,
97 public nsIDOMMouseMotionListener
,
98 public nsIDOMMouseListener
,
99 public nsSupportsWeakReference
103 virtual ~nsWidgetUtils();
105 nsresult
GetDOMWindowByNode(nsIDOMNode
*aNode
, nsIDOMWindow
* *aDOMWindow
);
107 void RemoveWindowListeners(nsIDOMWindow
*aDOMWin
);
108 void GetChromeEventHandler(nsIDOMWindow
*aDOMWin
, nsIDOMEventTarget
**aChromeTarget
);
109 void AttachWindowListeners(nsIDOMWindow
*aDOMWin
);
111 // nsIDOMMouseMotionListener
112 NS_IMETHOD
MouseMove(nsIDOMEvent
* aDOMEvent
);
113 NS_IMETHOD
DragMove(nsIDOMEvent
* aMouseEvent
);
114 NS_IMETHOD
HandleEvent(nsIDOMEvent
* aDOMEvent
);
116 // nsIDOMMouseListener
117 NS_IMETHOD
MouseDown(nsIDOMEvent
* aDOMEvent
);
118 NS_IMETHOD
MouseUp(nsIDOMEvent
* aDOMEvent
);
119 NS_IMETHOD
MouseClick(nsIDOMEvent
* aDOMEvent
);
120 NS_IMETHOD
MouseDblClick(nsIDOMEvent
* aDOMEvent
);
121 NS_IMETHOD
MouseOver(nsIDOMEvent
* aDOMEvent
);
122 NS_IMETHOD
MouseOut(nsIDOMEvent
* aDOMEvent
);
126 nsCOMPtr
<nsIWidget
> mWidget
;
127 nsCOMPtr
<nsIViewManager
> mViewManager
;
128 nsCOMPtr
<nsIDOMWindow
> mWindow
;
129 nsCOMPtr
<nsIDOMNode
> mNode
;
132 nsWidgetUtils::nsWidgetUtils()
138 nsWidgetUtils::Init()
141 nsCOMPtr
<nsIObserverService
> obsSvc
=
142 do_GetService("@mozilla.org/observer-service;1");
143 NS_ENSURE_STATE(obsSvc
);
145 rv
= obsSvc
->AddObserver(this, "domwindowopened", PR_FALSE
);
146 NS_ENSURE_SUCCESS(rv
, rv
);
147 rv
= obsSvc
->AddObserver(this, "domwindowclosed", PR_FALSE
);
148 NS_ENSURE_SUCCESS(rv
, rv
);
152 nsWidgetUtils::HandleEvent(nsIDOMEvent
* aDOMEvent
)
158 IsXULNode(nsIDOMNode
*aNode
, PRUint32
*aType
= 0)
160 PRBool retval
= PR_FALSE
;
161 if (!aNode
) return retval
;
164 aNode
->GetNodeName(sorigNode
);
165 if (sorigNode
.EqualsLiteral("#document"))
167 retval
= StringBeginsWith(sorigNode
, NS_LITERAL_STRING("xul:"));
169 if (!aType
) return retval
;
171 if (sorigNode
.EqualsLiteral("xul:thumb")
172 || sorigNode
.EqualsLiteral("xul:vbox")
173 || sorigNode
.EqualsLiteral("xul:spacer"))
174 *aType
= PR_FALSE
; // Magic
175 else if (sorigNode
.EqualsLiteral("xul:slider"))
177 else if (sorigNode
.EqualsLiteral("xul:scrollbarbutton"))
184 nsWidgetUtils::GetDOMWindowByNode(nsIDOMNode
*aNode
, nsIDOMWindow
* *aDOMWindow
)
187 nsCOMPtr
<nsIDOMDocument
> nodeDoc
;
188 rv
= aNode
->GetOwnerDocument(getter_AddRefs(nodeDoc
));
189 NS_ENSURE_SUCCESS(rv
, rv
);
190 nsCOMPtr
<nsIDOMDocumentView
> docView
= do_QueryInterface(nodeDoc
, &rv
);
191 NS_ENSURE_SUCCESS(rv
, rv
);
192 nsCOMPtr
<nsIDOMAbstractView
> absView
;
193 NS_ENSURE_SUCCESS(rv
, rv
);
194 rv
= docView
->GetDefaultView(getter_AddRefs(absView
));
195 NS_ENSURE_SUCCESS(rv
, rv
);
196 nsCOMPtr
<nsIDOMWindow
> window
= do_QueryInterface(absView
, &rv
);
197 NS_ENSURE_SUCCESS(rv
, rv
);
198 *aDOMWindow
= window
;
199 NS_IF_ADDREF(*aDOMWindow
);
204 nsWidgetUtils::MouseDown(nsIDOMEvent
* aDOMEvent
)
206 g_is_scrollable
= PR_FALSE
;
207 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent
;
208 mouseEvent
= do_QueryInterface(aDOMEvent
);
212 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenX(&g_lastX
);
213 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenY(&g_lastY
);
215 nsCOMPtr
<nsIDOMEventTarget
> eventTarget
;
216 aDOMEvent
->GetTarget(getter_AddRefs(eventTarget
));
219 mNode
= do_QueryInterface(eventTarget
);
223 PRBool isXul
= IsXULNode(mNode
, &type
);
224 if (isXul
) return NS_OK
;
225 g_is_scrollable
= PR_TRUE
;
227 GetDOMWindowByNode(mNode
, getter_AddRefs(mWindow
));
230 nsCOMPtr
<nsIDocument
> doc
;
231 nsCOMPtr
<nsIDOMDocument
> domDoc
;
232 mWindow
->GetDocument(getter_AddRefs(domDoc
));
233 doc
= do_QueryInterface(domDoc
);
234 if (!doc
) return NS_OK
;
235 // the only case where there could be more shells in printpreview
236 nsIPresShell
*shell
= doc
->GetPrimaryShell();
237 NS_ENSURE_TRUE(shell
, NS_ERROR_FAILURE
);
238 mViewManager
= shell
->GetViewManager();
239 NS_ENSURE_TRUE(mViewManager
, NS_ERROR_FAILURE
);
240 mViewManager
->GetWidget(getter_AddRefs(mWidget
));
241 // Return TRUE from your signal handler to mark the event as consumed.
242 // PRBool return_val = PR_FALSE;
243 if (g_is_scrollable
) {
244 aDOMEvent
->StopPropagation();
245 aDOMEvent
->PreventDefault();
251 nsWidgetUtils::MouseUp(nsIDOMEvent
* aDOMEvent
)
253 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent
;
254 mouseEvent
= do_QueryInterface(aDOMEvent
);
257 // Return TRUE from your signal handler to mark the event as consumed.
260 g_is_scrollable
= PR_FALSE
;
266 nsWidgetUtils::MouseMove(nsIDOMEvent
* aDOMEvent
)
268 if (!g_is_scrollable
) return NS_OK
;
270 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent
= do_QueryInterface(aDOMEvent
);
274 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenX(&x
);
275 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenY(&y
);
277 int dx
= g_lastX
- x
;
278 int dy
= g_lastY
- y
;
279 if(g_lastX
== MIN_INT
|| g_lastY
== MIN_INT
)
283 mWindow->ScrollBy(dx, dy);
288 nsEventStatus statusX
;
289 nsMouseScrollEvent
scrollEventX(PR_TRUE
, NS_MOUSE_SCROLL
, mWidget
);
290 scrollEventX
.delta
= dx
;
291 scrollEventX
.scrollFlags
= nsMouseScrollEvent::kIsHorizontal
| nsMouseScrollEvent::kIsPixels
;
292 mViewManager
->DispatchEvent(&scrollEventX
, &statusX
);
293 if(statusX
!= nsEventStatus_eIgnore
){
297 nsEventStatus statusY
;
298 nsMouseScrollEvent
scrollEventY(PR_TRUE
, NS_MOUSE_SCROLL
, mWidget
);
299 scrollEventY
.delta
= dy
;
300 scrollEventY
.scrollFlags
= nsMouseScrollEvent::kIsVertical
| nsMouseScrollEvent::kIsPixels
;
301 mViewManager
->DispatchEvent(&scrollEventY
, &statusY
);
302 if(statusY
!= nsEventStatus_eIgnore
){
310 nsWidgetUtils::MouseClick(nsIDOMEvent
* aDOMEvent
)
316 nsWidgetUtils::MouseDblClick(nsIDOMEvent
* aDOMEvent
)
322 nsWidgetUtils::MouseOver(nsIDOMEvent
* aDOMEvent
)
328 nsWidgetUtils::MouseOut(nsIDOMEvent
* aDOMEvent
)
335 nsWidgetUtils::DragMove(nsIDOMEvent
* aDOMEvent
)
341 nsWidgetUtils::GetChromeEventHandler(nsIDOMWindow
*aDOMWin
,
342 nsIDOMEventTarget
**aChromeTarget
)
344 nsCOMPtr
<nsPIDOMWindow
> privateDOMWindow(do_QueryInterface(aDOMWin
));
345 nsPIDOMEventTarget
* chromeEventHandler
= nsnull
;
346 if (privateDOMWindow
) {
347 chromeEventHandler
= privateDOMWindow
->GetChromeEventHandler();
350 nsCOMPtr
<nsIDOMEventTarget
> target(do_QueryInterface(chromeEventHandler
));
352 *aChromeTarget
= target
;
353 NS_IF_ADDREF(*aChromeTarget
);
357 nsWidgetUtils::RemoveWindowListeners(nsIDOMWindow
*aDOMWin
)
360 nsCOMPtr
<nsIDOMEventTarget
> chromeEventHandler
;
361 GetChromeEventHandler(aDOMWin
, getter_AddRefs(chromeEventHandler
));
362 if (!chromeEventHandler
) {
366 // Use capturing, otherwise the normal find next will get activated when ours should
367 nsCOMPtr
<nsPIDOMEventTarget
> piTarget(do_QueryInterface(chromeEventHandler
));
369 // Remove DOM Text listener for IME text events
370 rv
= piTarget
->RemoveEventListenerByIID(static_cast<nsIDOMMouseListener
*>(this),
371 NS_GET_IID(nsIDOMMouseListener
));
373 NS_WARNING("Failed to add Mouse Motion listener\n");
376 rv
= piTarget
->RemoveEventListenerByIID(static_cast<nsIDOMMouseMotionListener
*>(this),
377 NS_GET_IID(nsIDOMMouseMotionListener
));
379 NS_WARNING("Failed to add Mouse Motion listener\n");
385 nsWidgetUtils::AttachWindowListeners(nsIDOMWindow
*aDOMWin
)
388 nsCOMPtr
<nsIDOMEventTarget
> chromeEventHandler
;
389 GetChromeEventHandler(aDOMWin
, getter_AddRefs(chromeEventHandler
));
390 if (!chromeEventHandler
) {
394 // Use capturing, otherwise the normal find next will get activated when ours should
395 nsCOMPtr
<nsPIDOMEventTarget
> piTarget(do_QueryInterface(chromeEventHandler
));
397 // Attach menu listeners, this will help us ignore keystrokes meant for menus
398 rv
= piTarget
->AddEventListenerByIID(static_cast<nsIDOMMouseListener
*>(this),
399 NS_GET_IID(nsIDOMMouseListener
));
401 NS_WARNING("Failed to add Mouse Motion listener\n");
404 rv
= piTarget
->AddEventListenerByIID(static_cast<nsIDOMMouseMotionListener
*>(this),
405 NS_GET_IID(nsIDOMMouseMotionListener
));
407 NS_WARNING("Failed to add Mouse Motion listener\n");
412 nsWidgetUtils::~nsWidgetUtils()
416 NS_IMPL_ISUPPORTS4(nsWidgetUtils
, nsIObserver
, nsIDOMMouseMotionListener
, nsIDOMMouseListener
, nsISupportsWeakReference
)
419 nsWidgetUtils::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*aData
)
422 if (!strcmp(aTopic
,"domwindowopened"))
424 nsCOMPtr
<nsIDOMWindow
> chromeWindow
= do_QueryInterface(aSubject
);
426 AttachWindowListeners(chromeWindow
);
430 if (!strcmp(aTopic
,"domwindowclosed"))
432 nsCOMPtr
<nsIDOMWindow
> chromeWindow
= do_QueryInterface(aSubject
);
433 RemoveWindowListeners(chromeWindow
);
440 //------------------------------------------------------------------------------
441 // XPCOM REGISTRATION BELOW
442 //------------------------------------------------------------------------------
444 #define WidgetUtils_CID \
445 { 0x0ced17b6, 0x96ed, 0x4030, \
446 {0xa1, 0x34, 0x77, 0xcb, 0x66, 0x10, 0xa8, 0xf6} }
448 #define WidgetUtils_ContractID "@mozilla.org/extensions/widgetutils;1"
450 static NS_METHOD
WidgetUtilsRegistration(nsIComponentManager
*aCompMgr
,
452 const char *registryLocation
,
453 const char *componentType
,
454 const nsModuleComponentInfo
*info
)
458 nsCOMPtr
<nsIServiceManager
> servman
= do_QueryInterface((nsISupports
*)aCompMgr
, &rv
);
462 nsCOMPtr
<nsICategoryManager
> catman
;
463 servman
->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID
,
464 NS_GET_IID(nsICategoryManager
),
465 getter_AddRefs(catman
));
470 char* previous
= nsnull
;
471 rv
= catman
->AddCategoryEntry("app-startup",
473 WidgetUtils_ContractID
,
478 nsMemory::Free(previous
);
483 static NS_METHOD
WidgetUtilsUnregistration(nsIComponentManager
*aCompMgr
,
485 const char *registryLocation
,
486 const nsModuleComponentInfo
*info
)
490 nsCOMPtr
<nsIServiceManager
> servman
= do_QueryInterface((nsISupports
*)aCompMgr
, &rv
);
494 nsCOMPtr
<nsICategoryManager
> catman
;
495 servman
->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID
,
496 NS_GET_IID(nsICategoryManager
),
497 getter_AddRefs(catman
));
502 rv
= catman
->DeleteCategoryEntry("app-startup",
509 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWidgetUtils
)
511 static const nsModuleComponentInfo components
[] =
513 { "nsWidgetUtilsService",
515 WidgetUtils_ContractID
,
516 nsWidgetUtilsConstructor
,
517 WidgetUtilsRegistration
,
518 WidgetUtilsUnregistration
522 NS_IMPL_NSGETMODULE(nsWidgetUtilsModule
, components
)