mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 19:00:08 +00:00
1365e93fad
This mode makes each toplevel window get its own browser window, with popup windows using the browser window of their transient parent. Its not idea, as you can't get rid of all browser chrome by default, and it means popups (like menus) can't extend outside the toplevels. But, it is kinda cool.
843 lines
21 KiB
JavaScript
843 lines
21 KiB
JavaScript
/* Helper functions for debugging */
|
|
var logDiv = null;
|
|
function log(str) {
|
|
if (!logDiv) {
|
|
logDiv = document.createElement('div');
|
|
document.body.appendChild(logDiv);
|
|
logDiv.style["position"] = "absolute";
|
|
logDiv.style["right"] = "0px";
|
|
}
|
|
logDiv.appendChild(document.createTextNode(str));
|
|
logDiv.appendChild(document.createElement('br'));
|
|
}
|
|
|
|
var base64Values = [
|
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
|
255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
|
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
|
|
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
|
|
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255
|
|
]
|
|
|
|
function base64_8(str, index) {
|
|
var v =
|
|
(base64Values[str.charCodeAt(index)]) +
|
|
(base64Values[str.charCodeAt(index+1)] << 6);
|
|
return v;
|
|
}
|
|
|
|
function base64_16(str, index) {
|
|
var v =
|
|
(base64Values[str.charCodeAt(index)]) +
|
|
(base64Values[str.charCodeAt(index+1)] << 6) +
|
|
(base64Values[str.charCodeAt(index+2)] << 12);
|
|
return v;
|
|
}
|
|
|
|
function base64_16s(str, index) {
|
|
var v = base64_16(str, index);
|
|
if (v > 32767)
|
|
return v - 65536;
|
|
else
|
|
return v;
|
|
}
|
|
|
|
function base64_24(str, index) {
|
|
var v =
|
|
(base64Values[str.charCodeAt(index)]) +
|
|
(base64Values[str.charCodeAt(index+1)] << 6) +
|
|
(base64Values[str.charCodeAt(index+2)] << 12) +
|
|
(base64Values[str.charCodeAt(index+3)] << 18);
|
|
return v;
|
|
}
|
|
|
|
function base64_32(str, index) {
|
|
var v =
|
|
(base64Values[str.charCodeAt(index)]) +
|
|
(base64Values[str.charCodeAt(index+1)] << 6) +
|
|
(base64Values[str.charCodeAt(index+2)] << 12) +
|
|
(base64Values[str.charCodeAt(index+3)] << 18) +
|
|
(base64Values[str.charCodeAt(index+4)] << 24) +
|
|
(base64Values[str.charCodeAt(index+5)] << 30);
|
|
return v;
|
|
}
|
|
|
|
function createXHR()
|
|
{
|
|
try { return new XMLHttpRequest(); } catch(e) {}
|
|
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
|
|
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
|
|
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
|
|
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
|
|
|
|
return null;
|
|
}
|
|
|
|
/* This resizes the window so the *inner* size is the specified size */
|
|
function resizeBrowserWindow(window, w, h) {
|
|
var innerW = window.innerWidth;
|
|
var innerH = window.innerHeight;
|
|
|
|
var outerW = window.outerWidth;
|
|
var outerH = window.outerHeight;
|
|
|
|
window.resizeTo(w + outerW - innerW,
|
|
h + outerH - innerH);
|
|
}
|
|
|
|
var useToplevelWindows = false;
|
|
var grab = new Object();
|
|
grab.window = null;
|
|
grab.ownerEvents = false;
|
|
grab.implicit = false;
|
|
var lastSerial = 0;
|
|
var lastX = 0;
|
|
var lastY = 0;
|
|
var lastState;
|
|
var lastTimeStamp = 0;
|
|
var realWindowWithMouse = 0;
|
|
var windowWithMouse = 0;
|
|
var surfaces = {};
|
|
var outstandingCommands = new Array();
|
|
var inputSocket = null;
|
|
|
|
var GDK_CROSSING_NORMAL = 0;
|
|
var GDK_CROSSING_GRAB = 1;
|
|
var GDK_CROSSING_UNGRAB = 2;
|
|
|
|
// GdkModifierType
|
|
var GDK_SHIFT_MASK = 1 << 0;
|
|
var GDK_LOCK_MASK = 1 << 1;
|
|
var GDK_CONTROL_MASK = 1 << 2;
|
|
var GDK_MOD1_MASK = 1 << 3;
|
|
var GDK_MOD2_MASK = 1 << 4;
|
|
var GDK_MOD3_MASK = 1 << 5;
|
|
var GDK_MOD4_MASK = 1 << 6;
|
|
var GDK_MOD5_MASK = 1 << 7;
|
|
var GDK_BUTTON1_MASK = 1 << 8;
|
|
var GDK_BUTTON2_MASK = 1 << 9;
|
|
var GDK_BUTTON3_MASK = 1 << 10;
|
|
var GDK_BUTTON4_MASK = 1 << 11;
|
|
var GDK_BUTTON5_MASK = 1 << 12;
|
|
var GDK_SUPER_MASK = 1 << 26;
|
|
var GDK_HYPER_MASK = 1 << 27;
|
|
var GDK_META_MASK = 1 << 28;
|
|
var GDK_RELEASE_MASK = 1 << 30;
|
|
|
|
function getButtonMask (button) {
|
|
if (button == 1)
|
|
return GDK_BUTTON1_MASK;
|
|
if (button == 2)
|
|
return GDK_BUTTON2_MASK;
|
|
if (button == 3)
|
|
return GDK_BUTTON3_MASK;
|
|
if (button == 4)
|
|
return GDK_BUTTON4_MASK;
|
|
if (button == 5)
|
|
return GDK_BUTTON5_MASK;
|
|
return 0;
|
|
}
|
|
|
|
function flushSurface(surface)
|
|
{
|
|
var commands = surface.drawQueue;
|
|
surface.queue = [];
|
|
var context = surface.context;
|
|
var i = 0;
|
|
for (i = 0; i < commands.length; i++) {
|
|
var cmd = commands[i];
|
|
switch (cmd.op) {
|
|
case 'i': // put image data surface
|
|
context.globalCompositeOperation = "source-over";
|
|
context.drawImage(cmd.img, cmd.x, cmd.y);
|
|
break;
|
|
|
|
case 'b': // copy rects
|
|
context.save();
|
|
context.beginPath();
|
|
|
|
var minx;
|
|
var miny;
|
|
var maxx;
|
|
var maxy;
|
|
for (var j = 0; j < cmd.rects.length; j++) {
|
|
var rect = cmd.rects[j];
|
|
context.rect(rect.x, rect.y, rect.w, rect.h);
|
|
if (j == 0) {
|
|
minx = rect.x;
|
|
miny = rect.y;
|
|
maxx = rect.x + rect.w;
|
|
maxy = rect.y + rect.h;
|
|
} else {
|
|
if (rect.x < minx)
|
|
minx = rect.x;
|
|
if (rect.y < miny)
|
|
miny = rect.y;
|
|
if (rect.x + rect.w > maxx)
|
|
maxx = rect.x + rect.w;
|
|
if (rect.y + rect.h > maxy)
|
|
maxy = rect.y + rect.h;
|
|
}
|
|
}
|
|
context.clip();
|
|
context.globalCompositeOperation = "copy";
|
|
context.drawImage(context.canvas,
|
|
minx - cmd.dx, miny - cmd.dy, maxx - minx, maxy - miny,
|
|
minx, miny, maxx - minx, maxy - miny);
|
|
context.restore();
|
|
break;
|
|
|
|
default:
|
|
alert("Unknown drawing op " + cmd.op);
|
|
}
|
|
}
|
|
}
|
|
|
|
function ensureSurfaceInDocument(surface, doc)
|
|
{
|
|
if (surface.document != doc) {
|
|
var oldCanvas = surface.canvas;
|
|
var canvas = doc.importNode(oldCanvas, false);
|
|
doc.body.appendChild(canvas);
|
|
canvas.surface = surface;
|
|
oldCanvas.parentNode.removeChild(oldCanvas);
|
|
|
|
surface.canvas = canvas;
|
|
surface.document = doc;
|
|
|
|
var context = canvas.getContext("2d");
|
|
context.globalCompositeOperation = "source-over";
|
|
surface.context = context;
|
|
}
|
|
}
|
|
|
|
function getTransientToplevel(surface)
|
|
{
|
|
while (surface.transientParent != 0) {
|
|
surface = surfaces[surface.transientParent];
|
|
if (surface.window)
|
|
return surface;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function cmdCreateSurface(id, x, y, width, height, isTemp)
|
|
{
|
|
var surface = { id: id, x: x, y:y, width: width, height: height, isTemp: isTemp };
|
|
surface.drawQueue = [];
|
|
surface.transientParent = 0;
|
|
surface.visible = false;
|
|
surface.window = null;
|
|
surface.document = document;
|
|
|
|
var canvas = document.createElement("canvas");
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
canvas.surface = surface;
|
|
canvas.style["position"] = "absolute";
|
|
canvas.style["left"] = "0px";
|
|
canvas.style["top"] = "0px";
|
|
canvas.style["display"] = "none";
|
|
document.body.appendChild(canvas);
|
|
surface.canvas = canvas;
|
|
|
|
var context = canvas.getContext("2d");
|
|
context.globalCompositeOperation = "source-over";
|
|
surface.context = context;
|
|
|
|
surfaces[id] = surface;
|
|
}
|
|
|
|
function cmdShowSurface(id)
|
|
{
|
|
var surface = surfaces[id];
|
|
|
|
if (surface.visible)
|
|
return;
|
|
surface.visible = true;
|
|
|
|
var xOffset = surface.x;
|
|
var yOffset = surface.y;
|
|
|
|
if (useToplevelWindows) {
|
|
var doc = document;
|
|
if (!surface.isTemp) {
|
|
var win = window.open('','_blank',
|
|
'width='+surface.width+',height='+surface.height+
|
|
',left='+surface.x+',top='+surface.y+',screenX='+surface.x+',screenY='+surface.y+
|
|
',location=no,menubar=no,scrollbars=no,toolbar=no');
|
|
doc = win.document;
|
|
doc.open();
|
|
doc.write("<body></body>");
|
|
setupDocument(doc);
|
|
|
|
surface.window = win;
|
|
xOffset = 0;
|
|
yOffset = 0;
|
|
} else {
|
|
var transientToplevel = getTransientToplevel(surface);
|
|
if (transientToplevel) {
|
|
doc = transientToplevel.window.document;
|
|
xOffset = surface.x - transientToplevel.x;
|
|
yOffset = surface.y - transientToplevel.y;
|
|
}
|
|
}
|
|
|
|
ensureSurfaceInDocument(surface, doc);
|
|
}
|
|
|
|
surface.canvas.style["position"] = "absolute";
|
|
surface.canvas.style["left"] = xOffset + "px";
|
|
surface.canvas.style["top"] = yOffset + "px";
|
|
surface.canvas.style["display"] = "inline";
|
|
}
|
|
|
|
function cmdHideSurface(id)
|
|
{
|
|
var surface = surfaces[id];
|
|
|
|
if (!surface.visible)
|
|
return;
|
|
surface.visible = false;
|
|
|
|
surfaces[id].canvas.style["display"] = "none";
|
|
|
|
// Import the canvas into the main document
|
|
ensureSurfaceInDocument(surface, document);
|
|
|
|
if (surface.window) {
|
|
surface.window.close();
|
|
surface.window = null;
|
|
}
|
|
}
|
|
|
|
function cmdSetTransientFor(id, parentId)
|
|
{
|
|
var surface = surfaces[id];
|
|
|
|
if (surface.transientParent == parentId)
|
|
return;
|
|
|
|
surface.transientParent = parentId;
|
|
if (surface.visible && surface.isTemp) {
|
|
alert("TODO: move temps between transient parents when visible");
|
|
}
|
|
}
|
|
|
|
function cmdDeleteSurface(id)
|
|
{
|
|
var canvas = surfaces[id].canvas;
|
|
delete surfaces[id];
|
|
canvas.parentNode.removeChild(canvas);
|
|
}
|
|
|
|
function cmdMoveSurface(id, x, y)
|
|
{
|
|
var surface = surfaces[id];
|
|
surface.x = x;
|
|
surface.y = y;
|
|
|
|
if (surface.visible) {
|
|
if (surface.window) {
|
|
/* TODO: This moves the outer frame position, we really want the inner position.
|
|
* However this isn't *strictly* invalid, as any WM could have done whatever it
|
|
* wanted with the positioning of the window.
|
|
*/
|
|
surface.window.moveTo(surface.x, surface.y);
|
|
} else {
|
|
var xOffset = surface.x;
|
|
var yOffset = surface.y;
|
|
|
|
var transientToplevel = getTransientToplevel(surface);
|
|
if (transientToplevel) {
|
|
xOffset = surface.x - transientToplevel.x;
|
|
yOffset = surface.y - transientToplevel.y;
|
|
}
|
|
|
|
surface.canvas.style["left"] = xOffset + "px";
|
|
surface.canvas.style["top"] = yOffset + "px";
|
|
}
|
|
}
|
|
}
|
|
|
|
function cmdResizeSurface(id, w, h)
|
|
{
|
|
var surface = surfaces[id];
|
|
|
|
surface.width = w;
|
|
surface.height = h;
|
|
|
|
/* Flush any outstanding draw ops before changing size */
|
|
flushSurface(surface);
|
|
|
|
/* Canvas resize clears the data, so we need to save it first */
|
|
var tmpCanvas = surface.document.createElement("canvas");
|
|
tmpCanvas.width = surface.canvas.width;
|
|
tmpCanvas.height = surface.canvas.height;
|
|
var tmpContext = tmpCanvas.getContext("2d");
|
|
tmpContext.globalCompositeOperation = "copy";
|
|
tmpContext.drawImage(surface.canvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
|
|
|
|
surface.canvas.width = w;
|
|
surface.canvas.height = h;
|
|
|
|
surface.context.globalCompositeOperation = "copy";
|
|
surface.context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
|
|
|
|
if (surface.window) {
|
|
resizeBrowserWindow(surface.window, w, h);
|
|
}
|
|
}
|
|
|
|
function cmdFlushSurface(id)
|
|
{
|
|
flushSurface(surfaces[id]);
|
|
}
|
|
|
|
function cmdGrabPointer(id, ownerEvents)
|
|
{
|
|
doGrab(id, ownerEvents, false);
|
|
sendInput ("g", []);
|
|
}
|
|
|
|
function cmdUngrabPointer()
|
|
{
|
|
sendInput ("u", []);
|
|
|
|
grab.window = null;
|
|
}
|
|
|
|
function handleCommands(cmdObj)
|
|
{
|
|
var cmd = cmdObj.data;
|
|
var i = cmdObj.pos;
|
|
|
|
while (i < cmd.length) {
|
|
var command = cmd[i++];
|
|
lastSerial = base64_32(cmd, i);
|
|
i = i + 6;
|
|
switch (command) {
|
|
case 's': // create new surface
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var x = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var y = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var w = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var h = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var isTemp = cmd[i] == '1';
|
|
i = i + 1;
|
|
cmdCreateSurface(id, x, y, w, h, isTemp);
|
|
break;
|
|
|
|
case 'S': // Show a surface
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
cmdShowSurface(id);
|
|
break;
|
|
|
|
case 'H': // Hide a surface
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
cmdHideSurface(id);
|
|
break;
|
|
|
|
case 'p': // Set transient parent
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var parentId = base64_16(cmd, i);
|
|
i = i + 3;
|
|
cmdSetTransientFor(id, parentId);
|
|
break;
|
|
|
|
case 'd': // Delete surface
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
cmdDeleteSurface(id);
|
|
break;
|
|
|
|
case 'm': // Move a surface
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var x = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var y = base64_16(cmd, i);
|
|
i = i + 3;
|
|
cmdMoveSurface(id, x, y);
|
|
break;
|
|
|
|
case 'r': // Resize a surface
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var w = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var h = base64_16(cmd, i);
|
|
i = i + 3;
|
|
cmdResizeSurface(id, w, h);
|
|
break;
|
|
|
|
case 'i': // Put image data surface
|
|
var q = new Object();
|
|
q.op = 'i';
|
|
q.id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
q.x = base64_16(cmd, i);
|
|
i = i + 3;
|
|
q.y = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var size = base64_32(cmd, i);
|
|
i = i + 6;
|
|
var url = cmd.slice(i, i + size);
|
|
i = i + size;
|
|
q.img = new Image();
|
|
q.img.src = url;
|
|
surfaces[q.id].drawQueue.push(q);
|
|
if (!q.img.complete) {
|
|
cmdObj.pos = i;
|
|
q.img.onload = function() { handleOutstanding(); };
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case 'b': // Copy rects
|
|
var q = new Object();
|
|
q.op = 'b';
|
|
q.id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
|
|
var nrects = base64_16(cmd, i);
|
|
i = i + 3;
|
|
|
|
q.rects = [];
|
|
for (var r = 0; r < nrects; r++) {
|
|
var rect = new Object();
|
|
rect.x = base64_16(cmd, i);
|
|
i = i + 3;
|
|
rect.y = base64_16(cmd, i);
|
|
i = i + 3;
|
|
rect.w = base64_16(cmd, i);
|
|
i = i + 3;
|
|
rect.h = base64_16(cmd, i);
|
|
i = i + 3;
|
|
q.rects.push (rect);
|
|
}
|
|
|
|
q.dx = base64_16s(cmd, i);
|
|
i = i + 3;
|
|
q.dy = base64_16s(cmd, i);
|
|
i = i + 3;
|
|
surfaces[q.id].drawQueue.push(q);
|
|
break;
|
|
|
|
case 'f': // Flush surface
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
|
|
cmdFlushSurface(id);
|
|
break;
|
|
|
|
case 'g': // Grab
|
|
var id = base64_16(cmd, i);
|
|
i = i + 3;
|
|
var ownerEvents = cmd[i++] == '1';
|
|
|
|
cmdGrabPointer(id, ownerEvents);
|
|
break;
|
|
|
|
case 'u': // Ungrab
|
|
cmdUngrabPointer();
|
|
break;
|
|
default:
|
|
alert("Unknown op " + command);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function handleOutstanding()
|
|
{
|
|
while (outstandingCommands.length > 0) {
|
|
var cmd = outstandingCommands.shift();
|
|
if (!handleCommands(cmd)) {
|
|
outstandingCommands.unshift(cmd);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleLoad(event)
|
|
{
|
|
var cmdObj = {};
|
|
cmdObj.data = event.target.responseText;
|
|
cmdObj.pos = 0;
|
|
|
|
outstandingCommands.push(cmdObj);
|
|
if (outstandingCommands.length == 1) {
|
|
handleOutstanding();
|
|
}
|
|
}
|
|
|
|
function getSurfaceId(ev) {
|
|
var surface = ev.target.surface;
|
|
if (surface != undefined)
|
|
return surface.id;
|
|
return 0;
|
|
}
|
|
|
|
function sendInput(cmd, args)
|
|
{
|
|
if (inputSocket != null) {
|
|
inputSocket.send(cmd + ([lastSerial, lastTimeStamp].concat(args)).join(","));
|
|
}
|
|
}
|
|
|
|
function getDocumentCoordinates(element)
|
|
{
|
|
var res = new Object();
|
|
res.x = element.offsetLeft;
|
|
res.y = element.offsetTop;
|
|
|
|
var offsetParent = element.offsetParent;
|
|
while (offsetParent != null) {
|
|
res.x += offsetParent.offsetLeft;
|
|
res.y += offsetParent.offsetTop;
|
|
offsetParent = offsetParent.offsetParent;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
function getPositionsFromAbsCoord(absX, absY, relativeId) {
|
|
var res = Object();
|
|
|
|
res.rootX = absX;
|
|
res.rootY = absY;
|
|
res.winX = absX;
|
|
res.winY = absY;
|
|
if (relativeId != 0) {
|
|
var pos = getDocumentCoordinates(surfaces[relativeId].canvas);
|
|
res.winX = res.winX - pos.x;
|
|
res.winY = res.winY - pos.y;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
function getPositionsFromEvent(ev, relativeId) {
|
|
var res = getPositionsFromAbsCoord(ev.pageX, ev.pageY, relativeId);
|
|
|
|
lastX = res.rootX;
|
|
lastY = res.rootY;
|
|
|
|
return res;
|
|
}
|
|
|
|
function getEffectiveEventTarget (id) {
|
|
if (grab.window != null) {
|
|
if (!grab.ownerEvents)
|
|
return grab.window;
|
|
if (id == 0)
|
|
return grab.window;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
function updateForEvent(ev) {
|
|
lastTimeStamp = ev.timeStamp;
|
|
}
|
|
|
|
function onMouseMove (ev) {
|
|
updateForEvent(ev);
|
|
var id = getSurfaceId(ev);
|
|
id = getEffectiveEventTarget (id);
|
|
var pos = getPositionsFromEvent(ev, id);
|
|
sendInput ("m", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]);
|
|
}
|
|
|
|
function onMouseOver (ev) {
|
|
updateForEvent(ev);
|
|
var id = getSurfaceId(ev);
|
|
realWindowWithMouse = id;
|
|
id = getEffectiveEventTarget (id);
|
|
var pos = getPositionsFromEvent(ev, id);
|
|
windowWithMouse = id;
|
|
if (windowWithMouse != 0) {
|
|
sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
|
|
}
|
|
}
|
|
|
|
function onMouseOut (ev) {
|
|
updateForEvent(ev);
|
|
var id = getSurfaceId(ev);
|
|
var origId = id;
|
|
id = getEffectiveEventTarget (id);
|
|
var pos = getPositionsFromEvent(ev, id);
|
|
|
|
if (id != 0) {
|
|
sendInput ("l", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]);
|
|
}
|
|
realWindowWithMouse = 0;
|
|
windowWithMouse = 0;
|
|
}
|
|
|
|
function doGrab(id, ownerEvents, implicit) {
|
|
var pos;
|
|
|
|
if (windowWithMouse != id) {
|
|
if (windowWithMouse != 0) {
|
|
pos = getPositionsFromAbsCoord(lastX, lastY, windowWithMouse);
|
|
sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]);
|
|
}
|
|
pos = getPositionsFromAbsCoord(lastX, lastY, id);
|
|
sendInput ("e", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]);
|
|
windowWithMouse = id;
|
|
}
|
|
|
|
grab.window = id;
|
|
grab.ownerEvents = ownerEvents;
|
|
grab.implicit = implicit;
|
|
}
|
|
|
|
function doUngrab() {
|
|
var pos;
|
|
if (realWindowWithMouse != windowWithMouse) {
|
|
if (windowWithMouse != 0) {
|
|
pos = getPositionsFromAbsCoord(lastX, lastY, windowWithMouse);
|
|
sendInput ("l", [realWindowWithMouse, windowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]);
|
|
}
|
|
if (realWindowWithMouse != 0) {
|
|
pos = getPositionsFromAbsCoord(lastX, lastY, realWindowWithMouse);
|
|
sendInput ("e", [realWindowWithMouse, realWindowWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]);
|
|
}
|
|
windowWithMouse = realWindowWithMouse;
|
|
}
|
|
grab.window = null;
|
|
}
|
|
|
|
function onMouseDown (ev) {
|
|
updateForEvent(ev);
|
|
var id = getSurfaceId(ev);
|
|
id = getEffectiveEventTarget (id);
|
|
var pos = getPositionsFromEvent(ev, id);
|
|
if (grab.window != null)
|
|
doGrab (id, false, true);
|
|
var button = ev.button + 1;
|
|
lastState = lastState | getButtonMask (button);
|
|
sendInput ("b", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]);
|
|
}
|
|
|
|
function onMouseUp (ev) {
|
|
updateForEvent(ev);
|
|
var id = getSurfaceId(ev);
|
|
id = getEffectiveEventTarget (id);
|
|
var pos = getPositionsFromEvent(ev, id);
|
|
var button = ev.button + 1;
|
|
lastState = lastState & ~getButtonMask (button);
|
|
sendInput ("B", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]);
|
|
|
|
if (grab.window != null && grab.implicit)
|
|
doUngrab(ev.timeStamp);
|
|
}
|
|
|
|
var lastKeyDown = 0;
|
|
function onKeyDown (ev) {
|
|
updateForEvent(ev);
|
|
var keyCode = ev.keyCode;
|
|
if (keyCode != lastKeyDown) {
|
|
sendInput ("k", [keyCode]);
|
|
lastKeyDown = keyCode;
|
|
}
|
|
}
|
|
|
|
function onKeyUp (ev) {
|
|
updateForEvent(ev);
|
|
var keyCode = ev.keyCode;
|
|
sendInput ("K", [keyCode]);
|
|
lastKeyDown = 0;
|
|
}
|
|
|
|
function cancelEvent(ev)
|
|
{
|
|
ev = ev ? ev : window.event;
|
|
if (ev.stopPropagation)
|
|
ev.stopPropagation();
|
|
if (ev.preventDefault)
|
|
ev.preventDefault();
|
|
ev.cancelBubble = true;
|
|
ev.cancel = true;
|
|
ev.returnValue = false;
|
|
return false;
|
|
}
|
|
|
|
function onMouseWheel(ev)
|
|
{
|
|
updateForEvent(ev);
|
|
ev = ev ? ev : window.event;
|
|
|
|
var id = getSurfaceId(ev);
|
|
var pos = getPositionsFromEvent(ev, id);
|
|
|
|
var offset = ev.detail ? ev.detail : ev.wheelDelta;
|
|
var dir = 0;
|
|
if (offset > 0)
|
|
dir = 1;
|
|
sendInput ("s", [realWindowWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, dir]);
|
|
|
|
return cancelEvent(ev);
|
|
}
|
|
|
|
function setupDocument(document)
|
|
{
|
|
document.oncontextmenu = function () { return false; };
|
|
document.onmousemove = onMouseMove;
|
|
document.onmouseover = onMouseOver;
|
|
document.onmouseout = onMouseOut;
|
|
document.onmousedown = onMouseDown;
|
|
document.onmouseup = onMouseUp;
|
|
document.onkeydown = onKeyDown;
|
|
document.onkeyup = onKeyUp;
|
|
|
|
if (document.addEventListener) {
|
|
document.addEventListener('DOMMouseScroll', onMouseWheel, false);
|
|
document.addEventListener('mousewheel', onMouseWheel, false);
|
|
} else if (document.attachEvent) {
|
|
element.attachEvent("onmousewheel", onMouseWheel);
|
|
}
|
|
}
|
|
|
|
function connect()
|
|
{
|
|
var xhr = createXHR();
|
|
if (xhr) {
|
|
if (typeof xhr.multipart == 'undefined') {
|
|
alert("Sorry, this example only works in browsers that support multipart.");
|
|
return;
|
|
}
|
|
|
|
xhr.multipart = true;
|
|
xhr.open("GET", "/output", true);
|
|
xhr.onload = handleLoad;
|
|
xhr.send(null);
|
|
}
|
|
|
|
if ("WebSocket" in window) {
|
|
var loc = window.location.toString().replace("http:", "ws:");
|
|
loc = loc.substr(0, loc.lastIndexOf('/')) + "/input";
|
|
var ws = new WebSocket(loc, "broadway");
|
|
ws.onopen = function() {
|
|
inputSocket = ws;
|
|
};
|
|
ws.onclose = function() {
|
|
inputSocket = null;
|
|
};
|
|
} else {
|
|
alert("WebSocket not supported, input will not work!");
|
|
}
|
|
setupDocument(document);
|
|
}
|