|
1 <?xml version="1.0"?> |
|
2 |
|
3 <!-- This Source Code Form is subject to the terms of the Mozilla Public |
|
4 - License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> |
|
6 |
|
7 <?xml-stylesheet href="chrome://global/skin" type="text/css"?> |
|
8 |
|
9 <window id="NativeMenuWindow" |
|
10 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" |
|
11 xmlns:html="http://www.w3.org/1999/xhtml" |
|
12 width="600" |
|
13 height="600" |
|
14 title="Native Mouse Event Test" |
|
15 orient="vertical"> |
|
16 <script type="application/javascript" |
|
17 src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" /> |
|
18 |
|
19 <box height="200" id="box"/> |
|
20 <menupopup id="popup" width="250" height="50"/> |
|
21 <panel id="panel" width="250" height="50" noautohide="true"/> |
|
22 |
|
23 <script type="application/javascript"><![CDATA[ |
|
24 |
|
25 function ok(condition, message) { |
|
26 window.opener.wrappedJSObject.SimpleTest.ok(condition, message); |
|
27 } |
|
28 |
|
29 function is(a, b, message) { |
|
30 window.opener.wrappedJSObject.SimpleTest.is(a, b, message); |
|
31 } |
|
32 |
|
33 function todo(condition, message) { |
|
34 window.opener.wrappedJSObject.SimpleTest.todo(condition, message); |
|
35 } |
|
36 |
|
37 function todo_is(a, b, message) { |
|
38 window.opener.wrappedJSObject.SimpleTest.todo_is(a, b, message); |
|
39 } |
|
40 |
|
41 function onTestsFinished() { |
|
42 clearTimeout(gAfterLoopExecution); |
|
43 observe(window, eventMonitor, false); |
|
44 observe(gRightWindow, eventMonitor, false); |
|
45 observe(gPopup, eventMonitor, false); |
|
46 gRightWindow.close(); |
|
47 var openerSimpleTest = window.opener.wrappedJSObject.SimpleTest; |
|
48 window.close(); |
|
49 openerSimpleTest.finish(); |
|
50 } |
|
51 |
|
52 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; |
|
53 const xulWin = 'data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?><?xml-stylesheet href="chrome://global/skin" type="text/css"?><window xmlns="' + XUL_NS + '"/>'; |
|
54 |
|
55 const NSLeftMouseDown = 1, |
|
56 NSLeftMouseUp = 2, |
|
57 NSRightMouseDown = 3, |
|
58 NSRightMouseUp = 4, |
|
59 NSMouseMoved = 5, |
|
60 NSLeftMouseDragged = 6, |
|
61 NSRightMouseDragged = 7, |
|
62 NSMouseEntered = 8, |
|
63 NSMouseExited = 9, |
|
64 NSKeyDown = 10, |
|
65 NSKeyUp = 11, |
|
66 NSFlagsChanged = 12, |
|
67 NSAppKitDefined = 13, |
|
68 NSSystemDefined = 14, |
|
69 NSApplicationDefined = 15, |
|
70 NSPeriodic = 16, |
|
71 NSCursorUpdate = 17, |
|
72 NSScrollWheel = 22, |
|
73 NSTabletPoint = 23, |
|
74 NSTabletProximity = 24, |
|
75 NSOtherMouseDown = 25, |
|
76 NSOtherMouseUp = 26, |
|
77 NSOtherMouseDragged = 27, |
|
78 NSEventTypeGesture = 29, |
|
79 NSEventTypeMagnify = 30, |
|
80 NSEventTypeSwipe = 31, |
|
81 NSEventTypeRotate = 18, |
|
82 NSEventTypeBeginGesture = 19, |
|
83 NSEventTypeEndGesture = 20; |
|
84 |
|
85 const NSAlphaShiftKeyMask = 1 << 16, |
|
86 NSShiftKeyMask = 1 << 17, |
|
87 NSControlKeyMask = 1 << 18, |
|
88 NSAlternateKeyMask = 1 << 19, |
|
89 NSCommandKeyMask = 1 << 20, |
|
90 NSNumericPadKeyMask = 1 << 21, |
|
91 NSHelpKeyMask = 1 << 22, |
|
92 NSFunctionKeyMask = 1 << 23; |
|
93 |
|
94 const gDebug = false; |
|
95 |
|
96 function printDebug(msg) { if (gDebug) dump(msg); } |
|
97 |
|
98 var gExpectedEvents = []; |
|
99 var gRightWindow = null, gPopup = null; |
|
100 var gCurrentMouseX = 0, gCurrentMouseY = 0; |
|
101 var gAfterLoopExecution = 0; |
|
102 |
|
103 function testMouse(x, y, msg, elem, win, exp, flags, callback) { |
|
104 clearExpectedEvents(); |
|
105 var syntheticEvent = null; |
|
106 exp.forEach(function (expEv) { |
|
107 expEv.screenX = x; |
|
108 expEv.screenY = y; |
|
109 if (expEv.synthetic) { |
|
110 is(syntheticEvent, null, |
|
111 "Can't handle two synthetic events in a single testMouse call"); |
|
112 syntheticEvent = expEv; |
|
113 } |
|
114 gExpectedEvents.push(expEv); |
|
115 }); |
|
116 printDebug("sending event: " + x + ", " + y + " (" + msg + ")\n"); |
|
117 gCurrentMouseX = x; |
|
118 gCurrentMouseY = y; |
|
119 var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor). |
|
120 getInterface(Components.interfaces.nsIDOMWindowUtils); |
|
121 var callbackFunc = function() { |
|
122 clearExpectedEvents(); |
|
123 callback(); |
|
124 } |
|
125 if (syntheticEvent) { |
|
126 // Set up this listener before we sendNativeMouseEvent, just |
|
127 // in case that synchronously calls us. |
|
128 eventListenOnce(syntheticEvent.target, syntheticEvent.type, |
|
129 // Trigger callbackFunc async, so we're not assuming |
|
130 // anything about how our listener gets ordered with |
|
131 // others. |
|
132 function () { SimpleTest.executeSoon(callbackFunc) }); |
|
133 } |
|
134 utils.sendNativeMouseEvent(x, y, msg, flags || 0, elem); |
|
135 if (!syntheticEvent) { |
|
136 gAfterLoopExecution = setTimeout(callbackFunc, 0); |
|
137 } |
|
138 } |
|
139 |
|
140 function eventListenOnce(elem, name, callback) { |
|
141 elem.addEventListener(name, function(e) { |
|
142 elem.removeEventListener(name, arguments.callee, false); |
|
143 callback(e); |
|
144 }, false); |
|
145 } |
|
146 |
|
147 function focusAndThen(win, callback) { |
|
148 eventListenOnce(win, "focus", callback); |
|
149 printDebug("focusing a window\n"); |
|
150 win.focus(); |
|
151 } |
|
152 |
|
153 function eventToString(e) { |
|
154 return JSON.stringify({ |
|
155 type: e.type, target: e.target.nodeName, screenX: e.screenX, screenY: e.screenY |
|
156 }); |
|
157 } |
|
158 |
|
159 function clearExpectedEvents() { |
|
160 while (gExpectedEvents.length > 0) { |
|
161 var expectedEvent = gExpectedEvents.shift(); |
|
162 var errFun = expectedEvent.shouldFireButDoesnt ? todo : ok; |
|
163 errFun(false, "Didn't receive expected event: " + eventToString(expectedEvent)); |
|
164 } |
|
165 } |
|
166 |
|
167 var gEventNum = 0; |
|
168 |
|
169 function eventMonitor(e) { |
|
170 printDebug("got event: " + eventToString(e) + "\n"); |
|
171 processEvent(e); |
|
172 } |
|
173 |
|
174 function processEvent(e) { |
|
175 if (e.screenX != gCurrentMouseX || e.screenY != gCurrentMouseY) { |
|
176 todo(false, "Oh no! Received a stray event from a confused tracking area. Aborting test."); |
|
177 onTestsFinished(); |
|
178 return; |
|
179 } |
|
180 var expectedEvent = gExpectedEvents.shift(); |
|
181 if (!expectedEvent) { |
|
182 ok(false, "received event I didn't expect: " + eventToString(e)); |
|
183 return; |
|
184 } |
|
185 if (e.type != expectedEvent.type) { |
|
186 // Didn't get expectedEvent. |
|
187 var errFun = expectedEvent.shouldFireButDoesnt ? todo : ok; |
|
188 errFun(false, "Didn't receive expected event: " + eventToString(expectedEvent)); |
|
189 return processEvent(e); |
|
190 } |
|
191 gEventNum++; |
|
192 is(e.screenX, expectedEvent.screenX, gEventNum + " | wrong X coord for event " + eventToString(e)); |
|
193 is(e.screenY, expectedEvent.screenY, gEventNum + " | wrong Y coord for event " + eventToString(e)); |
|
194 is(e.target, expectedEvent.target, gEventNum + " | wrong target for event " + eventToString(e)); |
|
195 if (expectedEvent.firesButShouldnt) { |
|
196 todo(false, gEventNum + " | Got an event that should not have fired: " + eventToString(e)); |
|
197 } |
|
198 } |
|
199 |
|
200 function observe(elem, fun, add) { |
|
201 var addOrRemove = add ? "addEventListener" : "removeEventListener"; |
|
202 elem[addOrRemove]("mousemove", fun, false); |
|
203 elem[addOrRemove]("mouseover", fun, false); |
|
204 elem[addOrRemove]("mouseout", fun, false); |
|
205 elem[addOrRemove]("mousedown", fun, false); |
|
206 elem[addOrRemove]("mouseup", fun, false); |
|
207 elem[addOrRemove]("click", fun, false); |
|
208 } |
|
209 |
|
210 function start() { |
|
211 window.resizeTo(200, 200); |
|
212 window.moveTo(50, 50); |
|
213 gRightWindow = open(xulWin, '', 'chrome,screenX=300,screenY=50,width=200,height=200'); |
|
214 eventListenOnce(gRightWindow, "focus", function () { |
|
215 focusAndThen(window, runTests); |
|
216 }); |
|
217 gPopup = document.getElementById("popup"); |
|
218 } |
|
219 |
|
220 function runTests() { |
|
221 observe(window, eventMonitor, true); |
|
222 observe(gRightWindow, eventMonitor, true); |
|
223 var left = window, right = gRightWindow; |
|
224 var leftElem = document.getElementById("box"); |
|
225 var rightElem = gRightWindow.document.documentElement; |
|
226 var panel = document.getElementById("panel"); |
|
227 var tooltip = (function createTooltipInRightWindow() { |
|
228 var _tooltip = right.document.createElementNS(XUL_NS, "tooltip"); |
|
229 _tooltip.setAttribute("id", "tip"); |
|
230 _tooltip.setAttribute("width", "80"); |
|
231 _tooltip.setAttribute("height", "20"); |
|
232 right.document.documentElement.appendChild(_tooltip); |
|
233 return _tooltip; |
|
234 })(); |
|
235 var tests = [ |
|
236 |
|
237 // Part 1: Disallow click-through |
|
238 |
|
239 function blockClickThrough(callback) { |
|
240 document.documentElement.setAttribute("clickthrough", "never"); |
|
241 gRightWindow.document.documentElement.setAttribute("clickthrough", "never"); |
|
242 callback(); |
|
243 }, |
|
244 // Enter the left window, which is focused. |
|
245 [150, 150, NSMouseMoved, null, left, [ |
|
246 { type: "mouseover", target: leftElem }, |
|
247 { type: "mousemove", target: leftElem } |
|
248 ]], |
|
249 // Test that moving inside the window fires mousemove events. |
|
250 [170, 150, NSMouseMoved, null, left, [ |
|
251 { type: "mousemove", target: leftElem }, |
|
252 ]], |
|
253 // Leaving the window should fire a mouseout event... |
|
254 [170, 20, NSMouseMoved, null, left, [ |
|
255 { type: "mouseout", target: leftElem }, |
|
256 ]], |
|
257 // ... and entering a mouseover event. |
|
258 [170, 120, NSMouseMoved, null, left, [ |
|
259 { type: "mouseover", target: leftElem }, |
|
260 { type: "mousemove", target: leftElem }, |
|
261 ]], |
|
262 // Move over the right window, which is inactive. |
|
263 // Inactive windows shouldn't respond to mousemove events when clickthrough="never", |
|
264 // so we should only get a mouseout event, no mouseover event. |
|
265 [400, 150, NSMouseMoved, null, right, [ |
|
266 { type: "mouseout", target: leftElem }, |
|
267 ]], |
|
268 // Left-clicking while holding Cmd and middle clicking should work even |
|
269 // on inactive windows, but without making them active. |
|
270 [400, 150, NSLeftMouseDown, null, right, [ |
|
271 { type: "mousedown", target: rightElem }, |
|
272 ], NSCommandKeyMask], |
|
273 [400, 150, NSLeftMouseUp, null, right, [ |
|
274 { type: "mouseup", target: rightElem }, |
|
275 { type: "click", target: rightElem }, |
|
276 ], NSCommandKeyMask], |
|
277 [400, 150, NSOtherMouseDown, null, right, [ |
|
278 { type: "mousedown", target: rightElem }, |
|
279 ]], |
|
280 [400, 150, NSOtherMouseUp, null, right, [ |
|
281 { type: "mouseup", target: rightElem }, |
|
282 { type: "click", target: rightElem }, |
|
283 ]], |
|
284 // Clicking an inactive window should make it active and fire a mouseover |
|
285 // event. |
|
286 [400, 150, NSLeftMouseDown, null, right, [ |
|
287 { type: "mouseover", target: rightElem, synthetic: true }, |
|
288 ]], |
|
289 [400, 150, NSLeftMouseUp, null, right, [ |
|
290 ]], |
|
291 // Now it's focused, so we should get a mousedown event when clicking. |
|
292 [400, 150, NSLeftMouseDown, null, right, [ |
|
293 { type: "mousedown", target: rightElem }, |
|
294 ]], |
|
295 // Let's drag to the right without letting the button go. |
|
296 [410, 150, NSLeftMouseDragged, null, right, [ |
|
297 { type: "mousemove", target: rightElem }, |
|
298 ]], |
|
299 // Let go of the mouse. |
|
300 [410, 150, NSLeftMouseUp, null, right, [ |
|
301 { type: "mouseup", target: rightElem }, |
|
302 { type: "click", target: rightElem }, |
|
303 ]], |
|
304 // Move the mouse back over the left window, which is inactive. |
|
305 [150, 170, NSMouseMoved, null, left, [ |
|
306 { type: "mouseout", target: rightElem }, |
|
307 ]], |
|
308 // Now we're being sneaky. The left window is inactive, but *right*-clicks to it |
|
309 // should still get through. Test that. |
|
310 // Ideally we'd be bracketing that event with over and out events, too, but it |
|
311 // probably doesn't matter too much. |
|
312 [150, 170, NSRightMouseDown, null, left, [ |
|
313 { type: "mouseover", target: leftElem, shouldFireButDoesnt: true }, |
|
314 { type: "mousedown", target: leftElem }, |
|
315 { type: "mouseout", target: leftElem, shouldFireButDoesnt: true }, |
|
316 ]], |
|
317 // Let go of the mouse. |
|
318 [150, 170, NSRightMouseUp, null, left, [ |
|
319 { type: "mouseover", target: leftElem, shouldFireButDoesnt: true }, |
|
320 { type: "mouseup", target: leftElem }, |
|
321 { type: "click", target: leftElem }, |
|
322 { type: "mouseout", target: leftElem, shouldFireButDoesnt: true }, |
|
323 ]], |
|
324 // Right clicking hasn't focused it, so the window is still inactive. |
|
325 // Let's focus it; this time without the mouse, for variaton's sake. |
|
326 // Still, mouseout and mouseover events should fire. |
|
327 function raiseLeftWindow(callback) { |
|
328 clearExpectedEvents(); |
|
329 gExpectedEvents.push({ screenX: 150, screenY: 170, type: "mouseover", target: leftElem }); |
|
330 // We have to be a bit careful here. The synthetic mouse event may |
|
331 // not fire for a bit after we focus the left window. |
|
332 eventListenOnce(leftElem, "mouseover", function() { |
|
333 // Trigger callback async, so we're not assuming |
|
334 // anything about how our listener gets ordered with others. |
|
335 SimpleTest.executeSoon(callback); |
|
336 }); |
|
337 printDebug("focusing left window"); |
|
338 left.focus(); |
|
339 }, |
|
340 // It's active, so it should respond to mousemove events now. |
|
341 [150, 170, NSMouseMoved, null, left, [ |
|
342 { type: "mousemove", target: leftElem }, |
|
343 ]], |
|
344 // This was boring... let's introduce a popup. It will overlap both the left |
|
345 // and the right window. |
|
346 function openPopupInLeftWindow(callback) { |
|
347 eventListenOnce(gPopup, "popupshown", callback); |
|
348 gPopup.openPopupAtScreen(150, 50, true); |
|
349 }, |
|
350 // Move the mouse over the popup. |
|
351 [200, 80, NSMouseMoved, gPopup, left, [ |
|
352 { type: "mouseout", target: leftElem }, |
|
353 { type: "mouseover", target: gPopup }, |
|
354 { type: "mousemove", target: gPopup }, |
|
355 ]], |
|
356 // Move the mouse back over the left window outside the popup. |
|
357 [160, 170, NSMouseMoved, null, left, [ |
|
358 { type: "mouseout", target: gPopup }, |
|
359 { type: "mouseover", target: leftElem }, |
|
360 { type: "mousemove", target: leftElem }, |
|
361 ]], |
|
362 // Back over the popup... |
|
363 [190, 80, NSMouseMoved, gPopup, left, [ |
|
364 { type: "mouseout", target: leftElem }, |
|
365 { type: "mouseover", target: gPopup }, |
|
366 { type: "mousemove", target: gPopup }, |
|
367 ]], |
|
368 // ...and over into the right window. |
|
369 // It's inactive, so it shouldn't get mouseover events yet. |
|
370 [400, 170, NSMouseMoved, null, right, [ |
|
371 { type: "mouseout", target: gPopup }, |
|
372 ]], |
|
373 // Again, no mouse events please, even though a popup is open. (bug 425556) |
|
374 [400, 180, NSMouseMoved, null, right, [ |
|
375 ]], |
|
376 // Activate the right window with a click. |
|
377 // This will close the popup and make the mouse enter the right window. |
|
378 [400, 180, NSLeftMouseDown, null, right, [ |
|
379 { type: "mouseover", target: rightElem, synthetic: true }, |
|
380 ]], |
|
381 [400, 180, NSLeftMouseUp, null, right, [ |
|
382 ]], |
|
383 function verifyPopupClosed2(callback) { |
|
384 is(gPopup.popupBoxObject.popupState, "closed", "popup should have closed when clicking"); |
|
385 callback(); |
|
386 }, |
|
387 // Now the right window is active; click it again, just for fun. |
|
388 [400, 180, NSLeftMouseDown, null, right, [ |
|
389 { type: "mousedown", target: rightElem }, |
|
390 ]], |
|
391 [400, 180, NSLeftMouseUp, null, right, [ |
|
392 { type: "mouseup", target: rightElem }, |
|
393 { type: "click", target: rightElem }, |
|
394 ]], |
|
395 |
|
396 // Time for our next trick: a tooltip! |
|
397 // Install the tooltip, but don't show it yet. |
|
398 function setTooltip(callback) { |
|
399 rightElem.setAttribute("tooltip", "tip"); |
|
400 gExpectedEvents.push({ screenX: 410, screenY: 180, type: "mousemove", target: rightElem }); |
|
401 eventListenOnce(rightElem, "popupshown", callback); |
|
402 gCurrentMouseX = 410; |
|
403 gCurrentMouseY = 180; |
|
404 var utils = right.QueryInterface(Components.interfaces.nsIInterfaceRequestor). |
|
405 getInterface(Components.interfaces.nsIDOMWindowUtils); |
|
406 utils.sendNativeMouseEvent(410, 180, NSMouseMoved, 0, null); |
|
407 }, |
|
408 // Now the tooltip is visible. |
|
409 // Move the mouse a little to the right. |
|
410 [411, 180, NSMouseMoved, null, right, [ |
|
411 { type: "mousemove", target: rightElem }, |
|
412 ]], |
|
413 // Move another pixel. |
|
414 [412, 180, NSMouseMoved, null, right, [ |
|
415 { type: "mousemove", target: rightElem }, |
|
416 ]], |
|
417 // Move up and click to make the tooltip go away. |
|
418 [412, 80, NSMouseMoved, null, right, [ |
|
419 { type: "mousemove", target: rightElem }, |
|
420 ]], |
|
421 [412, 80, NSLeftMouseDown, null, right, [ |
|
422 { type: "mousedown", target: rightElem }, |
|
423 ]], |
|
424 [412, 80, NSLeftMouseUp, null, right, [ |
|
425 { type: "mouseup", target: rightElem }, |
|
426 { type: "click", target: rightElem }, |
|
427 ]], |
|
428 // OK, next round. Open a panel in the left window, which is inactive. |
|
429 function openPanel(callback) { |
|
430 eventListenOnce(panel, "popupshown", callback); |
|
431 panel.openPopupAtScreen(150, 150, false); |
|
432 }, |
|
433 // The panel is parented, so it will be z-ordered over its parent but |
|
434 // under the active window. |
|
435 // Now we move the mouse over the part where the panel rect intersects the |
|
436 // right window's rect. Since the panel is under the window, all the events |
|
437 // should target the right window. |
|
438 [390, 170, NSMouseMoved, null, right, [ |
|
439 { type: "mousemove", target: rightElem }, |
|
440 ]], |
|
441 [390, 171, NSMouseMoved, null, right, [ |
|
442 { type: "mousemove", target: rightElem }, |
|
443 ]], |
|
444 [391, 171, NSMouseMoved, null, right, [ |
|
445 { type: "mousemove", target: rightElem }, |
|
446 ]], |
|
447 // Now move off the right window, so that the mouse is directly over the |
|
448 // panel. |
|
449 [260, 170, NSMouseMoved, panel, left, [ |
|
450 { type: "mouseout", target: rightElem }, |
|
451 ]], |
|
452 [260, 171, NSMouseMoved, panel, left, [ |
|
453 ]], |
|
454 [261, 171, NSMouseMoved, panel, left, [ |
|
455 ]], |
|
456 // Let's be evil and click it. |
|
457 [261, 171, NSLeftMouseDown, panel, left, [ |
|
458 ]], |
|
459 [261, 171, NSLeftMouseUp, panel, left, [ |
|
460 ]], |
|
461 // This didn't focus the window, unfortunately, so let's do it ourselves. |
|
462 function raiseLeftWindowTakeTwo(callback) { |
|
463 focusAndThen(left, callback); |
|
464 }, |
|
465 // Now mouse events should get through to the panel (which is now over the |
|
466 // right window). |
|
467 [387, 170, NSMouseMoved, panel, left, [ |
|
468 { type: "mouseover", target: panel }, |
|
469 { type: "mousemove", target: panel }, |
|
470 ]], |
|
471 [387, 171, NSMouseMoved, panel, left, [ |
|
472 { type: "mousemove", target: panel }, |
|
473 ]], |
|
474 [388, 171, NSMouseMoved, panel, left, [ |
|
475 { type: "mousemove", target: panel }, |
|
476 ]], |
|
477 // Click the panel. |
|
478 [388, 171, NSLeftMouseDown, panel, left, [ |
|
479 { type: "mousedown", target: panel } |
|
480 ]], |
|
481 [388, 171, NSLeftMouseUp, panel, left, [ |
|
482 { type: "mouseup", target: panel }, |
|
483 { type: "click", target: panel }, |
|
484 ]], |
|
485 |
|
486 // Last test for this part: Hit testing in the Canyon of Nowhere - |
|
487 // the pixel row directly south of the panel, over the left window. |
|
488 // Before bug 515003 we wrongly thought the mouse wasn't over any window. |
|
489 [173, 200, NSMouseMoved, null, left, [ |
|
490 { type: "mouseout", target: panel }, |
|
491 { type: "mouseover", target: leftElem }, |
|
492 { type: "mousemove", target: leftElem }, |
|
493 ]], |
|
494 [173, 201, NSMouseMoved, null, left, [ |
|
495 { type: "mousemove", target: leftElem }, |
|
496 ]], |
|
497 |
|
498 // Part 2: Allow click-through |
|
499 |
|
500 function hideThatPanel(callback) { |
|
501 eventListenOnce(panel, "popuphidden", callback); |
|
502 panel.hidePopup(); |
|
503 }, |
|
504 function unblockClickThrough(callback) { |
|
505 document.documentElement.removeAttribute("clickthrough"); |
|
506 gRightWindow.document.documentElement.removeAttribute("clickthrough"); |
|
507 callback(); |
|
508 }, |
|
509 // Enter the left window, which is focused. |
|
510 [150, 150, NSMouseMoved, null, left, [ |
|
511 { type: "mousemove", target: leftElem } |
|
512 ]], |
|
513 // Test that moving inside the window fires mousemove events. |
|
514 [170, 150, NSMouseMoved, null, left, [ |
|
515 { type: "mousemove", target: leftElem }, |
|
516 ]], |
|
517 // Leaving the window should fire a mouseout event... |
|
518 [170, 20, NSMouseMoved, null, left, [ |
|
519 { type: "mouseout", target: leftElem }, |
|
520 ]], |
|
521 // ... and entering a mouseover event. |
|
522 [170, 120, NSMouseMoved, null, left, [ |
|
523 { type: "mouseover", target: leftElem }, |
|
524 { type: "mousemove", target: leftElem }, |
|
525 ]], |
|
526 // Move over the right window, which is inactive but still accepts |
|
527 // mouse events. |
|
528 [400, 150, NSMouseMoved, null, right, [ |
|
529 { type: "mouseout", target: leftElem }, |
|
530 { type: "mouseover", target: rightElem }, |
|
531 { type: "mousemove", target: rightElem }, |
|
532 ]], |
|
533 // Left-clicking while holding Cmd and middle clicking should work |
|
534 // on inactive windows, but without making them active. |
|
535 [400, 150, NSLeftMouseDown, null, right, [ |
|
536 { type: "mousedown", target: rightElem }, |
|
537 ], NSCommandKeyMask], |
|
538 [400, 150, NSLeftMouseUp, null, right, [ |
|
539 { type: "mouseup", target: rightElem }, |
|
540 { type: "click", target: rightElem }, |
|
541 ], NSCommandKeyMask], |
|
542 [400, 150, NSOtherMouseDown, null, right, [ |
|
543 { type: "mousedown", target: rightElem }, |
|
544 ]], |
|
545 [400, 150, NSOtherMouseUp, null, right, [ |
|
546 { type: "mouseup", target: rightElem }, |
|
547 { type: "click", target: rightElem }, |
|
548 ]], |
|
549 // Clicking an inactive window should make it active |
|
550 [400, 150, NSLeftMouseDown, null, right, [ |
|
551 { type: "mousedown", target: rightElem }, |
|
552 ]], |
|
553 [400, 150, NSLeftMouseUp, null, right, [ |
|
554 { type: "mouseup", target: rightElem }, |
|
555 { type: "click", target: rightElem }, |
|
556 ]], |
|
557 // Now it's focused. |
|
558 [401, 150, NSLeftMouseDown, null, right, [ |
|
559 { type: "mousedown", target: rightElem }, |
|
560 ]], |
|
561 // Let's drag to the right without letting the button go. |
|
562 [410, 150, NSLeftMouseDragged, null, right, [ |
|
563 { type: "mousemove", target: rightElem }, |
|
564 ]], |
|
565 // Let go of the mouse. |
|
566 [410, 150, NSLeftMouseUp, null, right, [ |
|
567 { type: "mouseup", target: rightElem }, |
|
568 { type: "click", target: rightElem }, |
|
569 ]], |
|
570 // Move the mouse back over the left window, which is inactive. |
|
571 [150, 170, NSMouseMoved, null, left, [ |
|
572 { type: "mouseout", target: rightElem }, |
|
573 { type: "mouseover", target: leftElem }, |
|
574 { type: "mousemove", target: leftElem }, |
|
575 ]], |
|
576 // Right-click it. |
|
577 [150, 170, NSRightMouseDown, null, left, [ |
|
578 { type: "mousedown", target: leftElem }, |
|
579 ]], |
|
580 // Let go of the mouse. |
|
581 [150, 170, NSRightMouseUp, null, left, [ |
|
582 { type: "mouseup", target: leftElem }, |
|
583 { type: "click", target: leftElem }, |
|
584 ]], |
|
585 // Right clicking hasn't focused it, so the window is still inactive. |
|
586 // Let's focus it; this time without the mouse, for variaton's sake. |
|
587 function raiseLeftWindow(callback) { |
|
588 clearExpectedEvents(); |
|
589 focusAndThen(left, function () { SimpleTest.executeSoon(callback); }); |
|
590 }, |
|
591 // It's active and should still respond to mousemove events. |
|
592 [150, 170, NSMouseMoved, null, left, [ |
|
593 { type: "mousemove", target: leftElem }, |
|
594 ]], |
|
595 |
|
596 // This was boring... let's introduce a popup. It will overlap both the left |
|
597 // and the right window. |
|
598 function openPopupInLeftWindow(callback) { |
|
599 eventListenOnce(gPopup, "popupshown", callback); |
|
600 gPopup.openPopupAtScreen(150, 50, true); |
|
601 }, |
|
602 // Move the mouse over the popup. |
|
603 [200, 80, NSMouseMoved, gPopup, left, [ |
|
604 { type: "mouseout", target: leftElem }, |
|
605 { type: "mouseover", target: gPopup }, |
|
606 { type: "mousemove", target: gPopup }, |
|
607 ]], |
|
608 // Move the mouse back over the left window outside the popup. |
|
609 [160, 170, NSMouseMoved, null, left, [ |
|
610 { type: "mouseout", target: gPopup }, |
|
611 { type: "mouseover", target: leftElem }, |
|
612 { type: "mousemove", target: leftElem }, |
|
613 ]], |
|
614 // Back over the popup... |
|
615 [190, 80, NSMouseMoved, gPopup, left, [ |
|
616 { type: "mouseout", target: leftElem }, |
|
617 { type: "mouseover", target: gPopup }, |
|
618 { type: "mousemove", target: gPopup }, |
|
619 ]], |
|
620 // ...and over into the right window. |
|
621 [400, 170, NSMouseMoved, null, right, [ |
|
622 { type: "mouseout", target: gPopup }, |
|
623 { type: "mouseover", target: rightElem }, |
|
624 { type: "mousemove", target: rightElem }, |
|
625 ]], |
|
626 [400, 180, NSMouseMoved, null, right, [ |
|
627 { type: "mousemove", target: rightElem }, |
|
628 ]], |
|
629 // Activate the right window with a click. |
|
630 [400, 180, NSLeftMouseDown, null, right, [ |
|
631 { type: "mousedown", target: rightElem }, |
|
632 ]], |
|
633 [400, 180, NSLeftMouseUp, null, right, [ |
|
634 { type: "mouseup", target: rightElem }, |
|
635 { type: "click", target: rightElem }, |
|
636 ]], |
|
637 function verifyPopupClosed2(callback) { |
|
638 is(gPopup.popupBoxObject.popupState, "closed", "popup should have closed when clicking"); |
|
639 callback(); |
|
640 }, |
|
641 // Now the right window is active; click it again, just for fun. |
|
642 [400, 180, NSLeftMouseDown, null, right, [ |
|
643 { type: "mousedown", target: rightElem }, |
|
644 ]], |
|
645 [400, 180, NSLeftMouseUp, null, right, [ |
|
646 { type: "mouseup", target: rightElem }, |
|
647 { type: "click", target: rightElem }, |
|
648 ]], |
|
649 |
|
650 // Time for our next trick: a tooltip! |
|
651 // Install the tooltip, but don't show it yet. |
|
652 function setTooltip2(callback) { |
|
653 rightElem.setAttribute("tooltip", "tip"); |
|
654 gExpectedEvents.push({ screenX: 410, screenY: 180, type: "mousemove", target: rightElem }); |
|
655 eventListenOnce(rightElem, "popupshown", callback); |
|
656 gCurrentMouseX = 410; |
|
657 gCurrentMouseY = 180; |
|
658 var utils = right.QueryInterface(Components.interfaces.nsIInterfaceRequestor). |
|
659 getInterface(Components.interfaces.nsIDOMWindowUtils); |
|
660 utils.sendNativeMouseEvent(410, 180, NSMouseMoved, 0, null); |
|
661 }, |
|
662 // Now the tooltip is visible. |
|
663 // Move the mouse a little to the right. |
|
664 [411, 180, NSMouseMoved, null, right, [ |
|
665 { type: "mousemove", target: rightElem }, |
|
666 ]], |
|
667 // Move another pixel. |
|
668 [412, 180, NSMouseMoved, null, right, [ |
|
669 { type: "mousemove", target: rightElem }, |
|
670 ]], |
|
671 // Move up and click to make the tooltip go away. |
|
672 [412, 80, NSMouseMoved, null, right, [ |
|
673 { type: "mousemove", target: rightElem }, |
|
674 ]], |
|
675 [412, 80, NSLeftMouseDown, null, right, [ |
|
676 { type: "mousedown", target: rightElem }, |
|
677 ]], |
|
678 [412, 80, NSLeftMouseUp, null, right, [ |
|
679 { type: "mouseup", target: rightElem }, |
|
680 { type: "click", target: rightElem }, |
|
681 ]], |
|
682 // OK, next round. Open a panel in the left window, which is inactive. |
|
683 function openPanel2(callback) { |
|
684 eventListenOnce(panel, "popupshown", callback); |
|
685 panel.openPopupAtScreen(150, 150, false); |
|
686 }, |
|
687 // The panel is parented, so it will be z-ordered over its parent but |
|
688 // under the active window. |
|
689 // Now we move the mouse over the part where the panel rect intersects the |
|
690 // right window's rect. Since the panel is under the window, all the events |
|
691 // should target the right window. |
|
692 [390, 170, NSMouseMoved, null, right, [ |
|
693 { type: "mousemove", target: rightElem }, |
|
694 ]], |
|
695 [390, 171, NSMouseMoved, null, right, [ |
|
696 { type: "mousemove", target: rightElem }, |
|
697 ]], |
|
698 [391, 171, NSMouseMoved, null, right, [ |
|
699 { type: "mousemove", target: rightElem }, |
|
700 ]], |
|
701 // Now move off the right window, so that the mouse is directly over the |
|
702 // panel. |
|
703 [260, 170, NSMouseMoved, panel, left, [ |
|
704 { type: "mouseout", target: rightElem }, |
|
705 { type: "mouseover", target: panel }, |
|
706 { type: "mousemove", target: panel }, |
|
707 ]], |
|
708 [260, 171, NSMouseMoved, panel, left, [ |
|
709 { type: "mousemove", target: panel }, |
|
710 ]], |
|
711 [261, 171, NSMouseMoved, panel, left, [ |
|
712 { type: "mousemove", target: panel }, |
|
713 ]], |
|
714 // Let's be evil and click it. |
|
715 [261, 171, NSLeftMouseDown, panel, left, [ |
|
716 { type: "mousedown", target: panel }, |
|
717 ]], |
|
718 [261, 171, NSLeftMouseUp, panel, left, [ |
|
719 { type: "mouseup", target: panel }, |
|
720 { type: "click", target: panel }, |
|
721 ]], |
|
722 // This didn't focus the window, unfortunately, so let's do it ourselves. |
|
723 function raiseLeftWindowTakeTwo(callback) { |
|
724 focusAndThen(left, callback); |
|
725 }, |
|
726 [387, 170, NSMouseMoved, panel, left, [ |
|
727 { type: "mousemove", target: panel }, |
|
728 ]], |
|
729 [387, 171, NSMouseMoved, panel, left, [ |
|
730 { type: "mousemove", target: panel }, |
|
731 ]], |
|
732 [388, 171, NSMouseMoved, panel, left, [ |
|
733 { type: "mousemove", target: panel }, |
|
734 ]], |
|
735 // Click the panel. |
|
736 [388, 171, NSLeftMouseDown, panel, left, [ |
|
737 { type: "mousedown", target: panel } |
|
738 ]], |
|
739 [388, 171, NSLeftMouseUp, panel, left, [ |
|
740 { type: "mouseup", target: panel }, |
|
741 { type: "click", target: panel }, |
|
742 ]], |
|
743 |
|
744 // Last test for today: Hit testing in the Canyon of Nowhere - |
|
745 // the pixel row directly south of the panel, over the left window. |
|
746 // Before bug 515003 we wrongly thought the mouse wasn't over any window. |
|
747 [173, 200, NSMouseMoved, null, left, [ |
|
748 { type: "mouseout", target: panel }, |
|
749 { type: "mouseover", target: leftElem }, |
|
750 { type: "mousemove", target: leftElem }, |
|
751 ]], |
|
752 [173, 201, NSMouseMoved, null, left, [ |
|
753 { type: "mousemove", target: leftElem }, |
|
754 ]], |
|
755 ]; |
|
756 function runNextTest() { |
|
757 if (!tests.length) |
|
758 return onTestsFinished(); |
|
759 |
|
760 var test = tests.shift(); |
|
761 if (typeof test == "function") |
|
762 return test(runNextTest); |
|
763 |
|
764 var [x, y, msg, elem, win, exp, flags] = test; |
|
765 testMouse(x, y, msg, elem, win, exp, flags, runNextTest); |
|
766 } |
|
767 runNextTest(); |
|
768 } |
|
769 |
|
770 SimpleTest.waitForFocus(start); |
|
771 |
|
772 ]]></script> |
|
773 </window> |