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'));
15 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
16 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
17 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
18 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
19 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
20 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
21 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
22 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255
25 function base64_8(str, index) {
27 (base64Values[str.charCodeAt(index)]) +
28 (base64Values[str.charCodeAt(index+1)] << 6);
32 function base64_16(str, index) {
34 (base64Values[str.charCodeAt(index)]) +
35 (base64Values[str.charCodeAt(index+1)] << 6) +
36 (base64Values[str.charCodeAt(index+2)] << 12);
40 function base64_16s(str, index) {
41 var v = base64_16(str, index);
48 function base64_24(str, index) {
50 (base64Values[str.charCodeAt(index)]) +
51 (base64Values[str.charCodeAt(index+1)] << 6) +
52 (base64Values[str.charCodeAt(index+2)] << 12) +
53 (base64Values[str.charCodeAt(index+3)] << 18);
57 function base64_32(str, index) {
59 (base64Values[str.charCodeAt(index)]) +
60 (base64Values[str.charCodeAt(index+1)] << 6) +
61 (base64Values[str.charCodeAt(index+2)] << 12) +
62 (base64Values[str.charCodeAt(index+3)] << 18) +
63 (base64Values[str.charCodeAt(index+4)] << 24) +
64 (base64Values[str.charCodeAt(index+5)] << 30);
70 try { return new XMLHttpRequest(); } catch(e) {}
71 try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
72 try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
73 try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
74 try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
79 /* This resizes the window so the *inner* size is the specified size */
80 function resizeBrowserWindow(window, w, h) {
81 var innerW = window.innerWidth;
82 var innerH = window.innerHeight;
84 var outerW = window.outerWidth;
85 var outerH = window.outerHeight;
87 window.resizeTo(w + outerW - innerW,
91 function resizeCanvas(canvas, w, h)
93 /* Canvas resize clears the data, so we need to save it first */
94 var tmpCanvas = canvas.ownerDocument.createElement("canvas");
95 tmpCanvas.width = canvas.width;
96 tmpCanvas.height = canvas.height;
97 var tmpContext = tmpCanvas.getContext("2d");
98 tmpContext.globalCompositeOperation = "copy";
99 tmpContext.drawImage(canvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
104 var context = canvas.getContext("2d");
106 context.globalCompositeOperation = "copy";
107 context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
110 var useToplevelWindows = false;
111 var toplevelWindows = [];
112 var grab = new Object();
114 grab.ownerEvents = false;
115 grab.implicit = false;
116 var localGrab = null;
121 var lastTimeStamp = 0;
122 var realWindowWithMouse = 0;
123 var windowWithMouse = 0;
125 var stackingOrder = [];
126 var outstandingCommands = new Array();
127 var inputSocket = null;
131 var GDK_CROSSING_NORMAL = 0;
132 var GDK_CROSSING_GRAB = 1;
133 var GDK_CROSSING_UNGRAB = 2;
136 var GDK_SHIFT_MASK = 1 << 0;
137 var GDK_LOCK_MASK = 1 << 1;
138 var GDK_CONTROL_MASK = 1 << 2;
139 var GDK_MOD1_MASK = 1 << 3;
140 var GDK_MOD2_MASK = 1 << 4;
141 var GDK_MOD3_MASK = 1 << 5;
142 var GDK_MOD4_MASK = 1 << 6;
143 var GDK_MOD5_MASK = 1 << 7;
144 var GDK_BUTTON1_MASK = 1 << 8;
145 var GDK_BUTTON2_MASK = 1 << 9;
146 var GDK_BUTTON3_MASK = 1 << 10;
147 var GDK_BUTTON4_MASK = 1 << 11;
148 var GDK_BUTTON5_MASK = 1 << 12;
149 var GDK_SUPER_MASK = 1 << 26;
150 var GDK_HYPER_MASK = 1 << 27;
151 var GDK_META_MASK = 1 << 28;
152 var GDK_RELEASE_MASK = 1 << 30;
154 function getButtonMask (button) {
156 return GDK_BUTTON1_MASK;
158 return GDK_BUTTON2_MASK;
160 return GDK_BUTTON3_MASK;
162 return GDK_BUTTON4_MASK;
164 return GDK_BUTTON5_MASK;
168 function flushSurface(surface)
170 var commands = surface.drawQueue;
172 var context = surface.canvas.getContext("2d");
173 context.globalCompositeOperation = "source-over";
175 for (i = 0; i < commands.length; i++) {
176 var cmd = commands[i];
178 case 'i': // put image data surface
179 context.globalCompositeOperation = "source-over";
180 context.drawImage(cmd.img, cmd.x, cmd.y);
183 case 'b': // copy rects
191 for (var j = 0; j < cmd.rects.length; j++) {
192 var rect = cmd.rects[j];
193 context.rect(rect.x, rect.y, rect.w, rect.h);
197 maxx = rect.x + rect.w;
198 maxy = rect.y + rect.h;
204 if (rect.x + rect.w > maxx)
205 maxx = rect.x + rect.w;
206 if (rect.y + rect.h > maxy)
207 maxy = rect.y + rect.h;
211 context.globalCompositeOperation = "copy";
212 context.drawImage(context.canvas,
213 minx - cmd.dx, miny - cmd.dy, maxx - minx, maxy - miny,
214 minx, miny, maxx - minx, maxy - miny);
219 alert("Unknown drawing op " + cmd.op);
224 function ensureSurfaceInDocument(surface, doc)
226 if (surface.document != doc) {
227 var oldCanvas = surface.canvas;
228 var canvas = doc.importNode(oldCanvas, false);
229 doc.body.appendChild(canvas);
230 canvas.surface = surface;
231 oldCanvas.parentNode.removeChild(oldCanvas);
233 surface.canvas = canvas;
234 if (surface.toplevelElement == oldCanvas)
235 surface.toplevelElement = canvas;
236 surface.document = doc;
240 var windowGeometryTimeout = null;
242 function updateBrowserWindowGeometry(win) {
246 var surface = win.surface;
248 var innerW = win.innerWidth;
249 var innerH = win.innerHeight;
253 if (frameSizeX > 0) {
254 x = win.screenX + frameSizeX;
255 y = win.screenY + frameSizeY;
258 if (x != surface.x || y != surface.y ||
259 innerW != surface.width || innerH != surface.height) {
260 var oldX = surface.x;
261 var oldY = surface.y;
264 if (surface.width != innerW || surface.height != innerH)
265 resizeCanvas(surface.canvas, innerW, innerH);
266 surface.width = innerW;
267 surface.height = innerH;
268 sendInput ("w", [surface.id, surface.x, surface.y, surface.width, surface.height]);
269 for (id in surfaces) {
270 var childSurface = surfaces[id];
271 var transientToplevel = getTransientToplevel(childSurface);
272 if (transientToplevel != null && transientToplevel == surface) {
273 childSurface.x += surface.x - oldX;
274 childSurface.y += surface.y - oldY;
275 sendInput ("w", [childSurface.id, childSurface.x, childSurface.y, childSurface.width, childSurface.height]);
281 function browserWindowClosed(win) {
282 var surface = win.surface;
284 sendInput ("W", [surface.id]);
285 for (id in surfaces) {
286 var childSurface = surfaces[id];
287 var transientToplevel = getTransientToplevel(childSurface);
288 if (transientToplevel != null && transientToplevel == surface) {
289 sendInput ("W", [childSurface.id]);
294 function registerWindow(win)
296 toplevelWindows.push(win);
297 win.onresize = function(ev) { updateBrowserWindowGeometry(ev.target); };
298 if (!windowGeometryTimeout)
299 windowGeometryTimeout = setInterval(function () { toplevelWindows.forEach(updateBrowserWindowGeometry); }, 2000);
300 win.onunload = function(ev) { browserWindowClosed(ev.target.defaultView); };
303 function unregisterWindow(win)
305 var i = toplevelWindows.indexOf(win);
307 toplevelWindows.splice(i, 1);
309 if (windowGeometryTimeout && toplevelWindows.length == 0) {
310 clearInterval(windowGeometryTimeout);
311 windowGeometryTimeout = null;
315 function getTransientToplevel(surface)
317 while (surface.transientParent != 0) {
318 surface = surfaces[surface.transientParent];
319 if (surface && surface.window)
325 function getStyle(el, styleProp)
327 if (el.currentStyle) {
328 return el.currentStyle[styleProp];
329 } else if (window.getComputedStyle) {
330 var win = el.ownerDocument.defaultView;
331 return win.getComputedStyle(el, null).getPropertyValue(styleProp);
336 function parseOffset(value)
338 var px = value.indexOf("px");
340 return parseInt(value.slice(0,px));
344 function getFrameOffset(surface) {
347 var el = surface.canvas;
348 while (el != null && el != surface.frame) {
352 /* For some reason the border is not includes in the offsets.. */
353 x += parseOffset(getStyle(el, "border-left-width"));
354 y += parseOffset(getStyle(el, "border-top-width"));
356 el = el.offsetParent;
359 /* Also include frame border as per above */
360 x += parseOffset(getStyle(el, "border-left-width"));
361 y += parseOffset(getStyle(el, "border-top-width"));
366 var positionIndex = 0;
367 function cmdCreateSurface(id, x, y, width, height, isTemp)
369 var surface = { id: id, x: x, y:y, width: width, height: height, isTemp: isTemp };
370 surface.positioned = isTemp;
371 surface.drawQueue = [];
372 surface.transientParent = 0;
373 surface.visible = false;
374 surface.window = null;
375 surface.document = document;
376 surface.frame = null;
378 var canvas = document.createElement("canvas");
379 canvas.width = width;
380 canvas.height = height;
381 canvas.surface = surface;
382 surface.canvas = canvas;
385 if (useToplevelWindows || isTemp) {
386 toplevelElement = canvas;
387 document.body.appendChild(canvas);
389 var frame = document.createElement("div");
390 frame.frameFor = surface;
391 frame.className = "frame-window";
392 surface.frame = frame;
394 var button = document.createElement("center");
395 var X = document.createTextNode("X");
396 button.appendChild(X);
397 button.className = "frame-close";
398 frame.appendChild(button);
400 var contents = document.createElement("div");
401 contents.className = "frame-contents";
402 frame.appendChild(contents);
404 canvas.style["display"] = "block";
405 contents.appendChild(canvas);
407 toplevelElement = frame;
408 document.body.appendChild(frame);
410 surface.x = 100 + positionIndex * 10;
411 surface.y = 100 + positionIndex * 10;
412 positionIndex = (positionIndex + 1) % 20;
413 sendInput ("w", [surface.id, surface.x, surface.y, surface.width, surface.height]);
416 surface.toplevelElement = toplevelElement;
417 toplevelElement.style["position"] = "absolute";
418 /* This positioning isn't strictly right for apps in another topwindow,
419 * but that will be fixed up when showing. */
420 toplevelElement.style["left"] = surface.x + "px";
421 toplevelElement.style["top"] = surface.y + "px";
422 toplevelElement.style["display"] = "inline";
424 /* We hide the frame with visibility rather than display none
425 * so getFrameOffset still works with hidden windows. */
426 toplevelElement.style["visibility"] = "hidden";
428 surfaces[id] = surface;
429 stackingOrder.push(surface);
432 function cmdShowSurface(id)
434 var surface = surfaces[id];
438 surface.visible = true;
440 var xOffset = surface.x;
441 var yOffset = surface.y;
443 if (useToplevelWindows) {
445 if (!surface.isTemp) {
447 'width='+surface.width+',height='+surface.height+
448 ',location=no,menubar=no,scrollbars=no,toolbar=no';
449 if (surface.positioned)
451 ',left='+surface.x+',top='+surface.y+',screenX='+surface.x+',screenY='+surface.y;
452 var win = window.open('','_blank', options);
453 win.surface = surface;
457 doc.write("<body></body>");
460 surface.window = win;
464 var transientToplevel = getTransientToplevel(surface);
465 if (transientToplevel) {
466 doc = transientToplevel.window.document;
467 xOffset = surface.x - transientToplevel.x;
468 yOffset = surface.y - transientToplevel.y;
472 ensureSurfaceInDocument(surface, doc);
475 var offset = getFrameOffset(surface);
481 surface.toplevelElement.style["left"] = xOffset + "px";
482 surface.toplevelElement.style["top"] = yOffset + "px";
483 surface.toplevelElement.style["visibility"] = "visible";
488 updateBrowserWindowGeometry(surface.window);
491 function cmdHideSurface(id)
493 var surface = surfaces[id];
495 if (!surface.visible)
497 surface.visible = false;
499 var element = surface.toplevelElement;
501 element.style["visibility"] = "hidden";
503 // Import the canvas into the main document
504 ensureSurfaceInDocument(surface, document);
506 if (surface.window) {
507 unregisterWindow(surface.window);
508 surface.window.close();
509 surface.window = null;
513 function cmdSetTransientFor(id, parentId)
515 var surface = surfaces[id];
517 if (surface.transientParent == parentId)
520 surface.transientParent = parentId;
521 if (surface.visible && surface.isTemp) {
522 alert("TODO: move temps between transient parents when visible");
526 function restackWindows() {
527 for (var i = 0; i < stackingOrder.length; i++) {
528 var surface = stackingOrder[i];
529 surface.toplevelElement.style.zIndex = i;
533 function moveToTopHelper(surface) {
534 var i = stackingOrder.indexOf(surface);
535 stackingOrder.splice(i, 1);
536 stackingOrder.push(surface);
538 for (var cid in surfaces) {
539 var child = surfaces[cid];
540 if (child.transientParent == surface.id)
541 moveToTopHelper(child);
545 function moveToTop(surface) {
546 moveToTopHelper(surface);
551 function cmdDeleteSurface(id)
553 var surface = surfaces[id];
554 var i = stackingOrder.indexOf(surface);
556 stackingOrder.splice(i, 1);
557 var canvas = surface.canvas;
558 canvas.parentNode.removeChild(canvas);
559 var frame = surface.frame;
561 frame.parentNode.removeChild(frame);
565 function cmdMoveSurface(id, x, y)
567 var surface = surfaces[id];
568 surface.positioned = true;
572 if (surface.visible) {
573 if (surface.window) {
574 /* TODO: This moves the outer frame position, we really want the inner position.
575 * However this isn't *strictly* invalid, as any WM could have done whatever it
576 * wanted with the positioning of the window.
578 surface.window.moveTo(surface.x, surface.y);
580 var xOffset = surface.x;
581 var yOffset = surface.y;
583 var transientToplevel = getTransientToplevel(surface);
584 if (transientToplevel) {
585 xOffset = surface.x - transientToplevel.x;
586 yOffset = surface.y - transientToplevel.y;
589 var element = surface.canvas;
591 element = surface.frame;
592 var offset = getFrameOffset(surface);
597 element.style["left"] = xOffset + "px";
598 element.style["top"] = yOffset + "px";
603 function cmdResizeSurface(id, w, h)
605 var surface = surfaces[id];
610 /* Flush any outstanding draw ops before changing size */
611 flushSurface(surface);
613 resizeCanvas(surface.canvas, w, h);
615 if (surface.window) {
616 resizeBrowserWindow(surface.window, w, h);
620 function cmdFlushSurface(id)
622 flushSurface(surfaces[id]);
625 function cmdGrabPointer(id, ownerEvents)
627 doGrab(id, ownerEvents, false);
631 function cmdUngrabPointer()
638 function handleCommands(cmdObj)
640 var cmd = cmdObj.data;
643 while (i < cmd.length) {
644 var command = cmd[i++];
645 lastSerial = base64_32(cmd, i);
648 case 's': // create new surface
649 var id = base64_16(cmd, i);
651 var x = base64_16s(cmd, i);
653 var y = base64_16s(cmd, i);
655 var w = base64_16(cmd, i);
657 var h = base64_16(cmd, i);
659 var isTemp = cmd[i] == '1';
661 cmdCreateSurface(id, x, y, w, h, isTemp);
664 case 'S': // Show a surface
665 var id = base64_16(cmd, i);
670 case 'H': // Hide a surface
671 var id = base64_16(cmd, i);
676 case 'p': // Set transient parent
677 var id = base64_16(cmd, i);
679 var parentId = base64_16(cmd, i);
681 cmdSetTransientFor(id, parentId);
684 case 'd': // Delete surface
685 var id = base64_16(cmd, i);
687 cmdDeleteSurface(id);
690 case 'm': // Move a surface
691 var id = base64_16(cmd, i);
693 var x = base64_16(cmd, i);
695 var y = base64_16(cmd, i);
697 cmdMoveSurface(id, x, y);
700 case 'r': // Resize a surface
701 var id = base64_16(cmd, i);
703 var w = base64_16(cmd, i);
705 var h = base64_16(cmd, i);
707 cmdResizeSurface(id, w, h);
710 case 'i': // Put image data surface
711 var q = new Object();
713 q.id = base64_16(cmd, i);
715 q.x = base64_16(cmd, i);
717 q.y = base64_16(cmd, i);
719 var size = base64_32(cmd, i);
721 var url = cmd.slice(i, i + size);
725 surfaces[q.id].drawQueue.push(q);
726 if (!q.img.complete) {
728 q.img.onload = function() { handleOutstanding(); };
733 case 'b': // Copy rects
734 var q = new Object();
736 q.id = base64_16(cmd, i);
739 var nrects = base64_16(cmd, i);
743 for (var r = 0; r < nrects; r++) {
744 var rect = new Object();
745 rect.x = base64_16(cmd, i);
747 rect.y = base64_16(cmd, i);
749 rect.w = base64_16(cmd, i);
751 rect.h = base64_16(cmd, i);
756 q.dx = base64_16s(cmd, i);
758 q.dy = base64_16s(cmd, i);
760 surfaces[q.id].drawQueue.push(q);
763 case 'f': // Flush surface
764 var id = base64_16(cmd, i);
771 var id = base64_16(cmd, i);
773 var ownerEvents = cmd[i++] == '1';
775 cmdGrabPointer(id, ownerEvents);
782 alert("Unknown op " + command);
788 function handleOutstanding()
790 while (outstandingCommands.length > 0) {
791 var cmd = outstandingCommands.shift();
792 if (!handleCommands(cmd)) {
793 outstandingCommands.unshift(cmd);
799 function handleLoad(event)
802 cmdObj.data = event.target.responseText;
805 outstandingCommands.push(cmdObj);
806 if (outstandingCommands.length == 1) {
811 function getSurfaceId(ev) {
812 var surface = ev.target.surface;
813 if (surface != undefined)
818 function sendInput(cmd, args)
820 if (inputSocket != null) {
821 inputSocket.send(cmd + ([lastSerial, lastTimeStamp].concat(args)).join(","));
825 function getPositionsFromAbsCoord(absX, absY, relativeId) {
832 if (relativeId != 0) {
833 var surface = surfaces[relativeId];
834 res.winX = res.winX - surface.x;
835 res.winY = res.winY - surface.y;
841 function getPositionsFromEvent(ev, relativeId) {
843 if (useToplevelWindows) {
850 var res = getPositionsFromAbsCoord(absX, absY, relativeId);
858 function getEffectiveEventTarget (id) {
859 if (grab.window != null) {
860 if (!grab.ownerEvents)
868 function updateForEvent(ev) {
869 lastTimeStamp = ev.timeStamp;
870 if (ev.target.surface && ev.target.surface.window) {
871 var win = ev.target.surface.window;
872 if (ev.screenX != undefined && ev.clientX != undefined) {
873 var newFrameSizeX = ev.screenX - ev.clientX - win.screenX;
874 var newFrameSizeY = ev.screenY - ev.clientY - win.screenY;
875 if (newFrameSizeX != frameSizeX || newFrameSizeY != frameSizeY) {
876 frameSizeX = newFrameSizeX;
877 frameSizeY = newFrameSizeY;
878 toplevelWindows.forEach(updateBrowserWindowGeometry);
881 updateBrowserWindowGeometry(win);
885 function onMouseMove (ev) {
888 var dx = ev.pageX - localGrab.lastX;
889 var dy = ev.pageY - localGrab.lastY;
890 var surface = localGrab.frame.frameFor;
893 var offset = getFrameOffset(surface);
894 localGrab.frame.style["left"] = (surface.x - offset.x) + "px";
895 localGrab.frame.style["top"] = (surface.y - offset.y) + "px";
896 sendInput ("w", [surface.id, surface.x, surface.y, surface.width, surface.height]);
897 localGrab.lastX = ev.pageX;
898 localGrab.lastY = ev.pageY;
901 var id = getSurfaceId(ev);
902 id = getEffectiveEventTarget (id);
903 var pos = getPositionsFromEvent(ev, id);
904 sendInput ("m", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
907 function onMouseOver (ev) {
911 var id = getSurfaceId(ev);
912 realWindowWithMouse = id;
913 id = getEffectiveEventTarget (id);
914 var pos = getPositionsFromEvent(ev, id);
915 windowWithMouse = id;
916 if (windowWithMouse != 0) {
917 sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
921 function onMouseOut (ev) {
925 var id = getSurfaceId(ev);
927 id = getEffectiveEventTarget (id);
928 var pos = getPositionsFromEvent(ev, id);
931 sendInput ("l", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
933 realWindowWithMouse = 0;
937 function doGrab(id, ownerEvents, implicit) {
940 if (windowWithMouse != id) {
941 if (windowWithMouse != 0) {
942 pos = getPositionsFromAbsCoord(lastX, lastY, windowWithMouse);
943 sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]);
945 pos = getPositionsFromAbsCoord(lastX, lastY, id);
946 sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]);
947 windowWithMouse = id;
951 grab.ownerEvents = ownerEvents;
952 grab.implicit = implicit;
955 function doUngrab() {
957 if (realWindowWithMouse != windowWithMouse) {
958 if (windowWithMouse != 0) {
959 pos = getPositionsFromAbsCoord(lastX, lastY, windowWithMouse);
960 sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]);
962 if (realWindowWithMouse != 0) {
963 pos = getPositionsFromAbsCoord(lastX, lastY, realWindowWithMouse);
964 sendInput ("e", [realWindowWithMouse, realWindowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]);
966 windowWithMouse = realWindowWithMouse;
971 function onMouseDown (ev) {
973 var button = ev.button + 1;
974 lastState = lastState | getButtonMask (button);
975 var id = getSurfaceId(ev);
976 id = getEffectiveEventTarget (id);
978 if (id == 0 && ev.target.frameFor) { /* mouse click on frame */
979 localGrab = new Object();
980 localGrab.frame = ev.target;
981 localGrab.lastX = ev.pageX;
982 localGrab.lastY = ev.pageY;
983 moveToTop(localGrab.frame.frameFor);
987 var pos = getPositionsFromEvent(ev, id);
988 if (grab.window == null)
989 doGrab (id, false, true);
990 sendInput ("b", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]);
993 function onMouseUp (ev) {
995 var button = ev.button + 1;
996 lastState = lastState & ~getButtonMask (button);
997 var evId = getSurfaceId(ev);
998 id = getEffectiveEventTarget (evId);
999 var pos = getPositionsFromEvent(ev, id);
1003 realWindowWithMouse = evId;
1004 if (windowWithMouse != id) {
1005 if (windowWithMouse != 0) {
1006 sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
1008 windowWithMouse = id;
1009 if (windowWithMouse != 0) {
1010 sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
1016 sendInput ("B", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]);
1018 if (grab.window != null && grab.implicit)
1019 doUngrab(ev.timeStamp);
1022 var lastKeyDown = 0;
1023 function onKeyDown (ev) {
1027 var keyCode = ev.keyCode;
1028 if (keyCode != lastKeyDown) {
1029 sendInput ("k", [keyCode]);
1030 lastKeyDown = keyCode;
1034 function onKeyUp (ev) {
1038 var keyCode = ev.keyCode;
1039 sendInput ("K", [keyCode]);
1043 function cancelEvent(ev)
1045 ev = ev ? ev : window.event;
1046 if (ev.stopPropagation)
1047 ev.stopPropagation();
1048 if (ev.preventDefault)
1049 ev.preventDefault();
1050 ev.cancelBubble = true;
1052 ev.returnValue = false;
1056 function onMouseWheel(ev)
1061 ev = ev ? ev : window.event;
1063 var id = getSurfaceId(ev);
1064 var pos = getPositionsFromEvent(ev, id);
1066 var offset = ev.detail ? ev.detail : ev.wheelDelta;
1070 sendInput ("s", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, dir]);
1072 return cancelEvent(ev);
1075 function setupDocument(document)
1077 document.oncontextmenu = function () { return false; };
1078 document.onmousemove = onMouseMove;
1079 document.onmouseover = onMouseOver;
1080 document.onmouseout = onMouseOut;
1081 document.onmousedown = onMouseDown;
1082 document.onmouseup = onMouseUp;
1083 document.onkeydown = onKeyDown;
1084 document.onkeyup = onKeyUp;
1086 if (document.addEventListener) {
1087 document.addEventListener('DOMMouseScroll', onMouseWheel, false);
1088 document.addEventListener('mousewheel', onMouseWheel, false);
1089 } else if (document.attachEvent) {
1090 element.attachEvent("onmousewheel", onMouseWheel);
1096 var url = window.location.toString();
1097 var query_string = url.split("?");
1098 if (query_string.length > 1) {
1099 var params = query_string[1].split("&");
1100 if (params[0].indexOf("toplevel") != -1)
1101 useToplevelWindows = true;
1103 var xhr = createXHR();
1105 if (typeof xhr.multipart == 'undefined') {
1106 alert("Sorry, this example only works in browsers that support multipart.");
1110 xhr.multipart = true;
1111 xhr.open("GET", "/output", true);
1112 xhr.onload = handleLoad;
1116 if ("WebSocket" in window) {
1117 var loc = window.location.toString().replace("http:", "ws:");
1118 loc = loc.substr(0, loc.lastIndexOf('/')) + "/input";
1119 var ws = new WebSocket(loc, "broadway");
1120 ws.onopen = function() {
1123 if (useToplevelWindows) {
1124 w = window.screen.width;
1125 h = window.screen.height;
1127 w = window.innerWidth;
1128 h = window.innerHeight;
1129 window.onresize = function(ev) {
1131 w = window.innerWidth;
1132 h = window.innerHeight;
1133 sendInput ("d", [w, h]);
1136 sendInput ("d", [w, h]);
1138 ws.onclose = function() {
1142 alert("WebSocket not supported, input will not work!");
1144 setupDocument(document);
1145 window.onunload = function (ev) {
1146 for (var i = 0; i < toplevelWindows.length; i++)
1147 toplevelWindows[i].close();