1 /* Helper functions for debugging */
5 logDiv = document.createElement('div');
6 document.body.appendChild(logDiv);
7 logDiv.style["position"] = "absolute";
8 logDiv.style["right"] = "0px";
10 logDiv.appendChild(document.createTextNode(str));
11 logDiv.appendChild(document.createElement('br'));
14 function getStackTrace()
17 var isCallstackPopulated = false;
21 if (e.stack) { // Firefox
22 var lines = e.stack.split("\n");
23 for (var i=0, len=lines.length; i<len; i++) {
24 if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
25 callstack.push(lines[i]);
28 // Remove call to getStackTrace()
30 isCallstackPopulated = true;
31 } else if (window.opera && e.message) { // Opera
32 var lines = e.message.split("\n");
33 for (var i=0, len=lines.length; i<len; i++) {
34 if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
36 // Append next line also since it has the file info
38 entry += " at " + lines[i+1];
41 callstack.push(entry);
44 // Remove call to getStackTrace()
46 isCallstackPopulated = true;
49 if (!isCallstackPopulated) { //IE and Safari
50 var currentFunction = arguments.callee.caller;
51 while (currentFunction) {
52 var fn = currentFunction.toString();
53 var fname = fn.substring(fn.indexOf("function") + 8, fn.indexOf("(")) || "anonymous";
54 callstack.push(fname);
55 currentFunction = currentFunction.caller;
61 function logStackTrace(len) {
62 var callstack = getStackTrace();
63 var end = callstack.length;
65 end = Math.min(len + 1, end);
66 for (var i = 1; i < end; i++)
71 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
72 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
73 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
74 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
75 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
76 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
77 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
78 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255
81 function base64_8(str, index) {
83 (base64Values[str.charCodeAt(index)]) +
84 (base64Values[str.charCodeAt(index+1)] << 6);
88 function base64_16(str, index) {
90 (base64Values[str.charCodeAt(index)]) +
91 (base64Values[str.charCodeAt(index+1)] << 6) +
92 (base64Values[str.charCodeAt(index+2)] << 12);
96 function base64_16s(str, index) {
97 var v = base64_16(str, index);
104 function base64_24(str, index) {
106 (base64Values[str.charCodeAt(index)]) +
107 (base64Values[str.charCodeAt(index+1)] << 6) +
108 (base64Values[str.charCodeAt(index+2)] << 12) +
109 (base64Values[str.charCodeAt(index+3)] << 18);
113 function base64_32(str, index) {
115 (base64Values[str.charCodeAt(index)]) +
116 (base64Values[str.charCodeAt(index+1)] << 6) +
117 (base64Values[str.charCodeAt(index+2)] << 12) +
118 (base64Values[str.charCodeAt(index+3)] << 18) +
119 (base64Values[str.charCodeAt(index+4)] << 24) +
120 (base64Values[str.charCodeAt(index+5)] << 30);
126 try { return new XMLHttpRequest(); } catch(e) {}
127 try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
128 try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
129 try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
130 try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
135 /* This resizes the window so the *inner* size is the specified size */
136 function resizeBrowserWindow(window, w, h) {
137 var innerW = window.innerWidth;
138 var innerH = window.innerHeight;
140 var outerW = window.outerWidth;
141 var outerH = window.outerHeight;
143 window.resizeTo(w + outerW - innerW,
144 h + outerH - innerH);
147 function resizeCanvas(canvas, w, h)
149 /* Canvas resize clears the data, so we need to save it first */
150 var tmpCanvas = canvas.ownerDocument.createElement("canvas");
151 tmpCanvas.width = canvas.width;
152 tmpCanvas.height = canvas.height;
153 var tmpContext = tmpCanvas.getContext("2d");
154 tmpContext.globalCompositeOperation = "copy";
155 tmpContext.drawImage(canvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
160 var context = canvas.getContext("2d");
162 context.globalCompositeOperation = "copy";
163 context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
166 var useToplevelWindows = false;
167 var toplevelWindows = [];
168 var grab = new Object();
170 grab.ownerEvents = false;
171 grab.implicit = false;
172 var localGrab = null;
177 var lastTimeStamp = 0;
178 var realWindowWithMouse = 0;
179 var windowWithMouse = 0;
181 var stackingOrder = [];
182 var outstandingCommands = new Array();
183 var inputSocket = null;
185 var GDK_CROSSING_NORMAL = 0;
186 var GDK_CROSSING_GRAB = 1;
187 var GDK_CROSSING_UNGRAB = 2;
190 var GDK_SHIFT_MASK = 1 << 0;
191 var GDK_LOCK_MASK = 1 << 1;
192 var GDK_CONTROL_MASK = 1 << 2;
193 var GDK_MOD1_MASK = 1 << 3;
194 var GDK_MOD2_MASK = 1 << 4;
195 var GDK_MOD3_MASK = 1 << 5;
196 var GDK_MOD4_MASK = 1 << 6;
197 var GDK_MOD5_MASK = 1 << 7;
198 var GDK_BUTTON1_MASK = 1 << 8;
199 var GDK_BUTTON2_MASK = 1 << 9;
200 var GDK_BUTTON3_MASK = 1 << 10;
201 var GDK_BUTTON4_MASK = 1 << 11;
202 var GDK_BUTTON5_MASK = 1 << 12;
203 var GDK_SUPER_MASK = 1 << 26;
204 var GDK_HYPER_MASK = 1 << 27;
205 var GDK_META_MASK = 1 << 28;
206 var GDK_RELEASE_MASK = 1 << 30;
208 function getButtonMask (button) {
210 return GDK_BUTTON1_MASK;
212 return GDK_BUTTON2_MASK;
214 return GDK_BUTTON3_MASK;
216 return GDK_BUTTON4_MASK;
218 return GDK_BUTTON5_MASK;
222 function flushSurface(surface)
224 var commands = surface.drawQueue;
226 var context = surface.canvas.getContext("2d");
227 context.globalCompositeOperation = "source-over";
229 for (i = 0; i < commands.length; i++) {
230 var cmd = commands[i];
232 case 'i': // put image data surface
233 context.globalCompositeOperation = "source-over";
234 context.drawImage(cmd.img, cmd.x, cmd.y);
237 case 'b': // copy rects
245 for (var j = 0; j < cmd.rects.length; j++) {
246 var rect = cmd.rects[j];
247 context.rect(rect.x, rect.y, rect.w, rect.h);
251 maxx = rect.x + rect.w;
252 maxy = rect.y + rect.h;
258 if (rect.x + rect.w > maxx)
259 maxx = rect.x + rect.w;
260 if (rect.y + rect.h > maxy)
261 maxy = rect.y + rect.h;
265 context.globalCompositeOperation = "copy";
266 context.drawImage(context.canvas,
267 minx - cmd.dx, miny - cmd.dy, maxx - minx, maxy - miny,
268 minx, miny, maxx - minx, maxy - miny);
273 alert("Unknown drawing op " + cmd.op);
278 function ensureSurfaceInDocument(surface, doc)
280 if (surface.document != doc) {
281 var oldCanvas = surface.canvas;
282 var canvas = doc.importNode(oldCanvas, false);
283 doc.body.appendChild(canvas);
284 canvas.surface = surface;
285 oldCanvas.parentNode.removeChild(oldCanvas);
287 surface.canvas = canvas;
288 if (surface.toplevelElement == oldCanvas)
289 surface.toplevelElement = canvas;
290 surface.document = doc;
294 function sendConfigureNotify(surface)
296 sendInput("w", [surface.id, surface.x, surface.y, surface.width, surface.height]);
299 var windowGeometryTimeout = null;
301 function updateBrowserWindowGeometry(win, alwaysSendConfigure) {
305 var surface = win.surface;
307 var innerW = win.innerWidth;
308 var innerH = win.innerHeight;
313 if (win.mozInnerScreenX != undefined) {
314 x = win.mozInnerScreenX;
315 y = win.mozInnerScreenY;
316 } else if (win.screenTop != undefined) {
320 alert("No implementation to get window position");
323 if (alwaysSendConfigure || x != surface.x || y != surface.y ||
324 innerW != surface.width || innerH != surface.height) {
325 var oldX = surface.x;
326 var oldY = surface.y;
329 if (surface.width != innerW || surface.height != innerH)
330 resizeCanvas(surface.canvas, innerW, innerH);
331 surface.width = innerW;
332 surface.height = innerH;
333 sendConfigureNotify(surface);
334 for (id in surfaces) {
335 var childSurface = surfaces[id];
336 var transientToplevel = getTransientToplevel(childSurface);
337 if (transientToplevel != null && transientToplevel == surface) {
338 childSurface.x += surface.x - oldX;
339 childSurface.y += surface.y - oldY;
340 sendConfigureNotify(childSurface);
346 function browserWindowClosed(win) {
347 var surface = win.surface;
349 sendInput ("W", [surface.id]);
350 for (id in surfaces) {
351 var childSurface = surfaces[id];
352 var transientToplevel = getTransientToplevel(childSurface);
353 if (transientToplevel != null && transientToplevel == surface) {
354 sendInput ("W", [childSurface.id]);
359 function registerWindow(win)
361 toplevelWindows.push(win);
362 win.onresize = function(ev) { updateBrowserWindowGeometry(ev.target, false); };
363 if (!windowGeometryTimeout)
364 windowGeometryTimeout = setInterval(function () {
365 for (var i = 0; i < toplevelWindows.length; i++)
366 toplevelWindows[i].updateBrowserWindowGeometry(toplevelWindows[i], false);
368 win.onunload = function(ev) { browserWindowClosed(ev.target.defaultView); };
371 function unregisterWindow(win)
373 var i = toplevelWindows.indexOf(win);
375 toplevelWindows.splice(i, 1);
377 if (windowGeometryTimeout && toplevelWindows.length == 0) {
378 clearInterval(windowGeometryTimeout);
379 windowGeometryTimeout = null;
383 function getTransientToplevel(surface)
385 while (surface && surface.transientParent != 0) {
386 surface = surfaces[surface.transientParent];
387 if (surface && surface.window)
393 function getStyle(el, styleProp)
395 if (el.currentStyle) {
396 return el.currentStyle[styleProp];
397 } else if (window.getComputedStyle) {
398 var win = el.ownerDocument.defaultView;
399 return win.getComputedStyle(el, null).getPropertyValue(styleProp);
404 function parseOffset(value)
406 var px = value.indexOf("px");
408 return parseInt(value.slice(0,px));
412 function getFrameOffset(surface) {
415 var el = surface.canvas;
416 while (el != null && el != surface.frame) {
420 /* For some reason the border is not includes in the offsets.. */
421 x += parseOffset(getStyle(el, "border-left-width"));
422 y += parseOffset(getStyle(el, "border-top-width"));
424 el = el.offsetParent;
427 /* Also include frame border as per above */
428 x += parseOffset(getStyle(el, "border-left-width"));
429 y += parseOffset(getStyle(el, "border-top-width"));
434 var positionIndex = 0;
435 function cmdCreateSurface(id, x, y, width, height, isTemp)
437 var surface = { id: id, x: x, y:y, width: width, height: height, isTemp: isTemp };
438 surface.positioned = isTemp;
439 surface.drawQueue = [];
440 surface.transientParent = 0;
441 surface.visible = false;
442 surface.window = null;
443 surface.document = document;
444 surface.frame = null;
446 var canvas = document.createElement("canvas");
447 canvas.width = width;
448 canvas.height = height;
449 canvas.surface = surface;
450 surface.canvas = canvas;
453 if (useToplevelWindows || isTemp) {
454 toplevelElement = canvas;
455 document.body.appendChild(canvas);
457 var frame = document.createElement("div");
458 frame.frameFor = surface;
459 frame.className = "frame-window";
460 surface.frame = frame;
462 var button = document.createElement("center");
463 var X = document.createTextNode("X");
464 button.appendChild(X);
465 button.className = "frame-close";
466 frame.appendChild(button);
468 var contents = document.createElement("div");
469 contents.className = "frame-contents";
470 frame.appendChild(contents);
472 canvas.style["display"] = "block";
473 contents.appendChild(canvas);
475 toplevelElement = frame;
476 document.body.appendChild(frame);
478 surface.x = 100 + positionIndex * 10;
479 surface.y = 100 + positionIndex * 10;
480 positionIndex = (positionIndex + 1) % 20;
483 surface.toplevelElement = toplevelElement;
484 toplevelElement.style["position"] = "absolute";
485 /* This positioning isn't strictly right for apps in another topwindow,
486 * but that will be fixed up when showing. */
487 toplevelElement.style["left"] = surface.x + "px";
488 toplevelElement.style["top"] = surface.y + "px";
489 toplevelElement.style["display"] = "inline";
491 /* We hide the frame with visibility rather than display none
492 * so getFrameOffset still works with hidden windows. */
493 toplevelElement.style["visibility"] = "hidden";
495 surfaces[id] = surface;
496 stackingOrder.push(surface);
498 sendConfigureNotify(surface);
501 function cmdShowSurface(id)
503 var surface = surfaces[id];
507 surface.visible = true;
509 var xOffset = surface.x;
510 var yOffset = surface.y;
512 if (useToplevelWindows) {
514 if (!surface.isTemp) {
516 'width='+surface.width+',height='+surface.height+
517 ',location=no,menubar=no,scrollbars=no,toolbar=no';
518 if (surface.positioned)
520 ',left='+surface.x+',top='+surface.y+',screenX='+surface.x+',screenY='+surface.y;
521 var win = window.open('','_blank', options);
522 win.surface = surface;
526 doc.write("<body></body>");
529 surface.window = win;
533 var transientToplevel = getTransientToplevel(surface);
534 if (transientToplevel) {
535 doc = transientToplevel.window.document;
536 xOffset = surface.x - transientToplevel.x;
537 yOffset = surface.y - transientToplevel.y;
541 ensureSurfaceInDocument(surface, doc);
544 var offset = getFrameOffset(surface);
550 surface.toplevelElement.style["left"] = xOffset + "px";
551 surface.toplevelElement.style["top"] = yOffset + "px";
552 surface.toplevelElement.style["visibility"] = "visible";
557 updateBrowserWindowGeometry(surface.window, false);
560 function cmdHideSurface(id)
562 var surface = surfaces[id];
564 if (!surface.visible)
566 surface.visible = false;
568 var element = surface.toplevelElement;
570 element.style["visibility"] = "hidden";
572 // Import the canvas into the main document
573 ensureSurfaceInDocument(surface, document);
575 if (surface.window) {
576 unregisterWindow(surface.window);
577 surface.window.close();
578 surface.window = null;
582 function cmdSetTransientFor(id, parentId)
584 var surface = surfaces[id];
586 if (surface.transientParent == parentId)
589 surface.transientParent = parentId;
590 if (parentId != 0 && surfaces[parentId]) {
591 moveToHelper(surface, stackingOrder.indexOf(surfaces[parentId])+1);
594 if (surface.visible) {
599 function restackWindows() {
600 for (var i = 0; i < stackingOrder.length; i++) {
601 var surface = stackingOrder[i];
602 surface.toplevelElement.style.zIndex = i;
606 function moveToHelper(surface, position) {
607 var i = stackingOrder.indexOf(surface);
608 stackingOrder.splice(i, 1);
609 if (position != undefined)
610 stackingOrder.splice(position, 0, surface);
612 stackingOrder.push(surface);
614 for (var cid in surfaces) {
615 var child = surfaces[cid];
616 if (child.transientParent == surface.id)
617 moveToHelper(child, stackingOrder.indexOf(surface) + 1);
621 function moveToTop(surface) {
622 moveToHelper(surface);
627 function cmdDeleteSurface(id)
629 var surface = surfaces[id];
630 var i = stackingOrder.indexOf(surface);
632 stackingOrder.splice(i, 1);
633 var canvas = surface.canvas;
634 canvas.parentNode.removeChild(canvas);
635 var frame = surface.frame;
637 frame.parentNode.removeChild(frame);
641 function cmdMoveSurface(id, x, y)
643 var surface = surfaces[id];
644 surface.positioned = true;
648 if (surface.visible) {
649 if (surface.window) {
650 /* TODO: This moves the outer frame position, we really want the inner position.
651 * However this isn't *strictly* invalid, as any WM could have done whatever it
652 * wanted with the positioning of the window.
654 surface.window.moveTo(surface.x, surface.y);
656 var xOffset = surface.x;
657 var yOffset = surface.y;
659 var transientToplevel = getTransientToplevel(surface);
660 if (transientToplevel) {
661 xOffset = surface.x - transientToplevel.x;
662 yOffset = surface.y - transientToplevel.y;
665 var element = surface.canvas;
667 element = surface.frame;
668 var offset = getFrameOffset(surface);
673 element.style["left"] = xOffset + "px";
674 element.style["top"] = yOffset + "px";
678 if (surface.window) {
679 updateBrowserWindowGeometry(surface.window, true);
681 sendConfigureNotify(surface);
685 function cmdResizeSurface(id, w, h)
687 var surface = surfaces[id];
692 /* Flush any outstanding draw ops before changing size */
693 flushSurface(surface);
695 resizeCanvas(surface.canvas, w, h);
697 if (surface.window) {
698 resizeBrowserWindow(surface.window, w, h);
699 updateBrowserWindowGeometry(surface.window, true);
701 sendConfigureNotify(surface);
705 function cmdFlushSurface(id)
707 flushSurface(surfaces[id]);
710 function cmdGrabPointer(id, ownerEvents)
712 doGrab(id, ownerEvents, false);
716 function cmdUngrabPointer()
723 function handleCommands(cmdObj)
725 var cmd = cmdObj.data;
728 while (i < cmd.length) {
729 var id, x, y, w, h, q;
730 var command = cmd[i++];
731 lastSerial = base64_32(cmd, i);
734 case 's': // create new surface
735 id = base64_16(cmd, i);
737 x = base64_16s(cmd, i);
739 y = base64_16s(cmd, i);
741 w = base64_16(cmd, i);
743 h = base64_16(cmd, i);
745 var isTemp = cmd[i] == '1';
747 cmdCreateSurface(id, x, y, w, h, isTemp);
750 case 'S': // Show a surface
751 id = base64_16(cmd, i);
756 case 'H': // Hide a surface
757 id = base64_16(cmd, i);
762 case 'p': // Set transient parent
763 id = base64_16(cmd, i);
765 var parentId = base64_16(cmd, i);
767 cmdSetTransientFor(id, parentId);
770 case 'd': // Delete surface
771 id = base64_16(cmd, i);
773 cmdDeleteSurface(id);
776 case 'm': // Move a surface
777 id = base64_16(cmd, i);
779 x = base64_16(cmd, i);
781 y = base64_16(cmd, i);
783 cmdMoveSurface(id, x, y);
786 case 'r': // Resize a surface
787 id = base64_16(cmd, i);
789 w = base64_16(cmd, i);
791 h = base64_16(cmd, i);
793 cmdResizeSurface(id, w, h);
796 case 'i': // Put image data surface
799 q.id = base64_16(cmd, i);
801 q.x = base64_16(cmd, i);
803 q.y = base64_16(cmd, i);
805 var size = base64_32(cmd, i);
807 var url = cmd.slice(i, i + size);
811 surfaces[q.id].drawQueue.push(q);
812 if (!q.img.complete) {
814 q.img.onload = function() { handleOutstanding(); };
819 case 'b': // Copy rects
822 q.id = base64_16(cmd, i);
825 var nrects = base64_16(cmd, i);
829 for (var r = 0; r < nrects; r++) {
830 var rect = new Object();
831 rect.x = base64_16(cmd, i);
833 rect.y = base64_16(cmd, i);
835 rect.w = base64_16(cmd, i);
837 rect.h = base64_16(cmd, i);
842 q.dx = base64_16s(cmd, i);
844 q.dy = base64_16s(cmd, i);
846 surfaces[q.id].drawQueue.push(q);
849 case 'f': // Flush surface
850 id = base64_16(cmd, i);
857 id = base64_16(cmd, i);
859 var ownerEvents = cmd[i++] == '1';
861 cmdGrabPointer(id, ownerEvents);
868 alert("Unknown op " + command);
874 function handleOutstanding()
876 while (outstandingCommands.length > 0) {
877 var cmd = outstandingCommands.shift();
878 if (!handleCommands(cmd)) {
879 outstandingCommands.unshift(cmd);
885 function handleLoad(event)
888 cmdObj.data = event.target.responseText;
891 outstandingCommands.push(cmdObj);
892 if (outstandingCommands.length == 1) {
897 function getSurfaceId(ev) {
898 var surface = ev.target.surface;
899 if (surface != undefined)
904 function sendInput(cmd, args)
906 if (inputSocket != null) {
907 inputSocket.send(cmd + ([lastSerial, lastTimeStamp].concat(args)).join(","));
911 function getPositionsFromAbsCoord(absX, absY, relativeId) {
918 if (relativeId != 0) {
919 var surface = surfaces[relativeId];
920 res.winX = res.winX - surface.x;
921 res.winY = res.winY - surface.y;
927 function getPositionsFromEvent(ev, relativeId) {
929 if (useToplevelWindows) {
936 var res = getPositionsFromAbsCoord(absX, absY, relativeId);
944 function getEffectiveEventTarget (id) {
945 if (grab.window != null) {
946 if (!grab.ownerEvents)
954 function updateForEvent(ev) {
955 lastTimeStamp = ev.timeStamp;
956 if (ev.target.surface && ev.target.surface.window) {
957 var win = ev.target.surface.window;
958 updateBrowserWindowGeometry(win, false);
962 function onMouseMove (ev) {
965 var dx = ev.pageX - localGrab.lastX;
966 var dy = ev.pageY - localGrab.lastY;
967 var surface = localGrab.frame.frameFor;
970 var offset = getFrameOffset(surface);
971 localGrab.frame.style["left"] = (surface.x - offset.x) + "px";
972 localGrab.frame.style["top"] = (surface.y - offset.y) + "px";
973 sendConfigureNotify(surface);
974 localGrab.lastX = ev.pageX;
975 localGrab.lastY = ev.pageY;
978 var id = getSurfaceId(ev);
979 id = getEffectiveEventTarget (id);
980 var pos = getPositionsFromEvent(ev, id);
981 sendInput ("m", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
984 function onMouseOver (ev) {
988 var id = getSurfaceId(ev);
989 realWindowWithMouse = id;
990 id = getEffectiveEventTarget (id);
991 var pos = getPositionsFromEvent(ev, id);
992 windowWithMouse = id;
993 if (windowWithMouse != 0) {
994 sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
998 function onMouseOut (ev) {
1002 var id = getSurfaceId(ev);
1004 id = getEffectiveEventTarget (id);
1005 var pos = getPositionsFromEvent(ev, id);
1008 sendInput ("l", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
1010 realWindowWithMouse = 0;
1011 windowWithMouse = 0;
1014 function doGrab(id, ownerEvents, implicit) {
1017 if (windowWithMouse != id) {
1018 if (windowWithMouse != 0) {
1019 pos = getPositionsFromAbsCoord(lastX, lastY, windowWithMouse);
1020 sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]);
1022 pos = getPositionsFromAbsCoord(lastX, lastY, id);
1023 sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]);
1024 windowWithMouse = id;
1028 grab.ownerEvents = ownerEvents;
1029 grab.implicit = implicit;
1032 function doUngrab() {
1034 if (realWindowWithMouse != windowWithMouse) {
1035 if (windowWithMouse != 0) {
1036 pos = getPositionsFromAbsCoord(lastX, lastY, windowWithMouse);
1037 sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]);
1039 if (realWindowWithMouse != 0) {
1040 pos = getPositionsFromAbsCoord(lastX, lastY, realWindowWithMouse);
1041 sendInput ("e", [realWindowWithMouse, realWindowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]);
1043 windowWithMouse = realWindowWithMouse;
1048 function onMouseDown (ev) {
1050 var button = ev.button + 1;
1051 lastState = lastState | getButtonMask (button);
1052 var id = getSurfaceId(ev);
1053 id = getEffectiveEventTarget (id);
1055 if (id == 0 && ev.target.frameFor) { /* mouse click on frame */
1056 localGrab = new Object();
1057 localGrab.frame = ev.target;
1058 localGrab.lastX = ev.pageX;
1059 localGrab.lastY = ev.pageY;
1060 moveToTop(localGrab.frame.frameFor);
1064 var pos = getPositionsFromEvent(ev, id);
1065 if (grab.window == null)
1066 doGrab (id, false, true);
1067 sendInput ("b", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]);
1070 function onMouseUp (ev) {
1072 var button = ev.button + 1;
1073 lastState = lastState & ~getButtonMask (button);
1074 var evId = getSurfaceId(ev);
1075 id = getEffectiveEventTarget (evId);
1076 var pos = getPositionsFromEvent(ev, id);
1080 realWindowWithMouse = evId;
1081 if (windowWithMouse != id) {
1082 if (windowWithMouse != 0) {
1083 sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
1085 windowWithMouse = id;
1086 if (windowWithMouse != 0) {
1087 sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
1093 sendInput ("B", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]);
1095 if (grab.window != null && grab.implicit)
1096 doUngrab(ev.timeStamp);
1099 var lastKeyDown = 0;
1100 function onKeyDown (ev) {
1104 var keyCode = ev.keyCode;
1105 if (keyCode != lastKeyDown) {
1106 sendInput ("k", [keyCode]);
1107 lastKeyDown = keyCode;
1111 function onKeyUp (ev) {
1115 var keyCode = ev.keyCode;
1116 sendInput ("K", [keyCode]);
1120 function cancelEvent(ev)
1122 ev = ev ? ev : window.event;
1123 if (ev.stopPropagation)
1124 ev.stopPropagation();
1125 if (ev.preventDefault)
1126 ev.preventDefault();
1127 ev.cancelBubble = true;
1129 ev.returnValue = false;
1133 function onMouseWheel(ev)
1138 ev = ev ? ev : window.event;
1140 var id = getSurfaceId(ev);
1141 var pos = getPositionsFromEvent(ev, id);
1143 var offset = ev.detail ? ev.detail : ev.wheelDelta;
1147 sendInput ("s", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, dir]);
1149 return cancelEvent(ev);
1152 function setupDocument(document)
1154 document.oncontextmenu = function () { return false; };
1155 document.onmousemove = onMouseMove;
1156 document.onmouseover = onMouseOver;
1157 document.onmouseout = onMouseOut;
1158 document.onmousedown = onMouseDown;
1159 document.onmouseup = onMouseUp;
1160 document.onkeydown = onKeyDown;
1161 document.onkeyup = onKeyUp;
1163 if (document.addEventListener) {
1164 document.addEventListener('DOMMouseScroll', onMouseWheel, false);
1165 document.addEventListener('mousewheel', onMouseWheel, false);
1166 } else if (document.attachEvent) {
1167 element.attachEvent("onmousewheel", onMouseWheel);
1173 var url = window.location.toString();
1174 var query_string = url.split("?");
1175 if (query_string.length > 1) {
1176 var params = query_string[1].split("&");
1177 if (params[0].indexOf("toplevel") != -1)
1178 useToplevelWindows = true;
1180 var xhr = createXHR();
1182 if (typeof xhr.multipart == 'undefined') {
1183 alert("Sorry, this example only works in browsers that support multipart.");
1187 xhr.multipart = true;
1188 xhr.open("GET", "/output", true);
1189 xhr.onload = handleLoad;
1193 if ("WebSocket" in window) {
1194 var loc = window.location.toString().replace("http:", "ws:");
1195 loc = loc.substr(0, loc.lastIndexOf('/')) + "/input";
1196 var ws = new WebSocket(loc, "broadway");
1197 ws.onopen = function() {
1200 if (useToplevelWindows) {
1201 w = window.screen.width;
1202 h = window.screen.height;
1204 w = window.innerWidth;
1205 h = window.innerHeight;
1206 window.onresize = function(ev) {
1208 w = window.innerWidth;
1209 h = window.innerHeight;
1210 sendInput ("d", [w, h]);
1213 sendInput ("d", [w, h]);
1215 ws.onclose = function() {
1219 alert("WebSocket not supported, input will not work!");
1221 setupDocument(document);
1222 window.onunload = function (ev) {
1223 for (var i = 0; i < toplevelWindows.length; i++)
1224 toplevelWindows[i].close();