203 lines
7.0 KiB
JavaScript
203 lines
7.0 KiB
JavaScript
"use strict";
|
|
/*
|
|
Copyright (C) 2013 by Jeremy P. White <jwhite@codeweavers.com>
|
|
|
|
This file is part of spice-html5.
|
|
|
|
spice-html5 is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
spice-html5 is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with spice-html5. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** SpiceSimulateCursor
|
|
** Internet Explorer 10 does not support data uri's in cursor assignment.
|
|
** This file provides a number of gimmicks to compensate. First, if there
|
|
** is a preloaded cursor available, we will use that. Failing that, we will
|
|
** simulate a cursor using an image that is moved around the screen.
|
|
**--------------------------------------------------------------------------*/
|
|
var SpiceSimulateCursor = {
|
|
|
|
cursors : new Array(),
|
|
unknown_cursors : new Array(),
|
|
warned: false,
|
|
|
|
add_cursor: function(sha1, value)
|
|
{
|
|
SpiceSimulateCursor.cursors[sha1] = value;
|
|
},
|
|
|
|
unknown_cursor: function(sha1, curdata)
|
|
{
|
|
if (! SpiceSimulateCursor.warned)
|
|
{
|
|
SpiceSimulateCursor.warned = true;
|
|
alert("Internet Explorer does not support dynamic cursors. " +
|
|
"This page will now simulate cursors with images, " +
|
|
"which will be imperfect. We recommend using Chrome or Firefox instead. " +
|
|
"\n\nIf you need to use Internet Explorer, you can create a static cursor " +
|
|
"file for each cursor your application uses. " +
|
|
"View the console log for more information on creating static cursors for your environment.");
|
|
}
|
|
|
|
if (! SpiceSimulateCursor.unknown_cursors[sha1])
|
|
{
|
|
SpiceSimulateCursor.unknown_cursors[sha1] = curdata;
|
|
console.log('Unknown cursor. Simulation required. To avoid simulation for this cursor, create and include a custom javascript file, and add the following line:');
|
|
console.log('SpiceCursorSimulator.add_cursor("' + sha1 + '"), "<your filename here>.cur");');
|
|
console.log('And then run following command, redirecting output into <your filename here>.cur:');
|
|
console.log('php -r "echo urldecode(\'' + curdata + '\');"');
|
|
}
|
|
},
|
|
|
|
simulate_cursor: function (spicecursor, cursor, screen, pngstr)
|
|
{
|
|
var cursor_sha = hex_sha1(pngstr + ' ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y);
|
|
if (typeof SpiceSimulateCursor.cursors != 'undefined')
|
|
if (typeof SpiceSimulateCursor.cursors[cursor_sha] != 'undefined')
|
|
{
|
|
var curstr = 'url(' + SpiceSimulateCursor.cursors[cursor_sha] + '), default';
|
|
screen.style.cursor = curstr;
|
|
}
|
|
|
|
if (window.getComputedStyle(screen, null).cursor == 'auto')
|
|
{
|
|
SpiceSimulateCursor.unknown_cursor(cursor_sha,
|
|
SpiceSimulateCursor.create_icondir(cursor.header.width, cursor.header.height,
|
|
cursor.data.byteLength, cursor.header.hot_spot_x, cursor.header.hot_spot_y) + pngstr);
|
|
|
|
document.getElementById(spicecursor.parent.screen_id).style.cursor = 'none';
|
|
if (! spicecursor.spice_simulated_cursor)
|
|
{
|
|
spicecursor.spice_simulated_cursor = document.createElement('img');
|
|
|
|
spicecursor.spice_simulated_cursor.style.position = 'absolute';
|
|
spicecursor.spice_simulated_cursor.style.display = 'none';
|
|
spicecursor.spice_simulated_cursor.style.overflow = 'hidden';
|
|
|
|
spicecursor.spice_simulated_cursor.spice_screen = document.getElementById(spicecursor.parent.screen_id);
|
|
|
|
spicecursor.spice_simulated_cursor.addEventListener('mousemove', SpiceSimulateCursor.handle_sim_mousemove);
|
|
|
|
spicecursor.spice_simulated_cursor.spice_screen.appendChild(spicecursor.spice_simulated_cursor);
|
|
}
|
|
|
|
spicecursor.spice_simulated_cursor.src = 'data:image/png,' + pngstr;
|
|
|
|
spicecursor.spice_simulated_cursor.spice_hot_x = cursor.header.hot_spot_x;
|
|
spicecursor.spice_simulated_cursor.spice_hot_y = cursor.header.hot_spot_y;
|
|
|
|
spicecursor.spice_simulated_cursor.style.pointerEvents = "none";
|
|
}
|
|
else
|
|
{
|
|
if (spicecursor.spice_simulated_cursor)
|
|
{
|
|
spicecursor.spice_simulated_cursor.spice_screen.removeChild(spicecursor.spice_simulated_cursor);
|
|
delete spicecursor.spice_simulated_cursor;
|
|
}
|
|
}
|
|
},
|
|
|
|
handle_sim_mousemove: function(e)
|
|
{
|
|
var retval;
|
|
var f = SpiceSimulateCursor.duplicate_mouse_event(e, this.spice_screen);
|
|
return this.spice_screen.dispatchEvent(f);
|
|
},
|
|
|
|
duplicate_mouse_event: function(e, target)
|
|
{
|
|
var evt = document.createEvent("mouseevent");
|
|
evt.initMouseEvent(e.type, true, true, e.view, e.detail,
|
|
e.screenX, e.screenY, e.clientX, e.clientY,
|
|
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
|
|
return evt;
|
|
},
|
|
|
|
ICONDIR: function ()
|
|
{
|
|
},
|
|
|
|
ICONDIRENTRY: function(width, height, bytes, hot_x, hot_y)
|
|
{
|
|
this.width = width;
|
|
this.height = height;
|
|
this.bytes = bytes;
|
|
this.hot_x = hot_x;
|
|
this.hot_y = hot_y;
|
|
},
|
|
|
|
|
|
create_icondir: function (width, height, bytes, hot_x, hot_y)
|
|
{
|
|
var i;
|
|
var header = new SpiceSimulateCursor.ICONDIR();
|
|
var entry = new SpiceSimulateCursor.ICONDIRENTRY(width, height, bytes, hot_x, hot_y);
|
|
|
|
var mb = new ArrayBuffer(header.buffer_size() + entry.buffer_size());
|
|
var at = header.to_buffer(mb);
|
|
at = entry.to_buffer(mb, at);
|
|
|
|
var u8 = new Uint8Array(mb);
|
|
var str = "";
|
|
for (i = 0; i < at; i++)
|
|
{
|
|
str += "%";
|
|
if (u8[i] < 16)
|
|
str += "0";
|
|
str += u8[i].toString(16);
|
|
}
|
|
return str;
|
|
},
|
|
|
|
};
|
|
|
|
SpiceSimulateCursor.ICONDIR.prototype =
|
|
{
|
|
to_buffer: function(a, at)
|
|
{
|
|
at = at || 0;
|
|
var dv = new SpiceDataView(a);
|
|
dv.setUint16(at, 0, true); at += 2;
|
|
dv.setUint16(at, 2, true); at += 2;
|
|
dv.setUint16(at, 1, true); at += 2;
|
|
return at;
|
|
},
|
|
buffer_size: function()
|
|
{
|
|
return 6;
|
|
}
|
|
};
|
|
|
|
SpiceSimulateCursor.ICONDIRENTRY.prototype =
|
|
{
|
|
to_buffer: function(a, at)
|
|
{
|
|
at = at || 0;
|
|
var dv = new SpiceDataView(a);
|
|
dv.setUint8(at, this.width); at++;
|
|
dv.setUint8(at, this.height); at++;
|
|
dv.setUint8(at, 0); at++; /* color palette count, unused */
|
|
dv.setUint8(at, 0); at++; /* reserved */
|
|
dv.setUint16(at, this.hot_x, true); at += 2;
|
|
dv.setUint16(at, this.hot_y, true); at += 2;
|
|
dv.setUint32(at, this.bytes, true); at += 4;
|
|
dv.setUint32(at, at + 4, true); at += 4; /* Offset to bytes */
|
|
return at;
|
|
},
|
|
buffer_size: function()
|
|
{
|
|
return 16;
|
|
}
|
|
};
|