From: Pierre Ossman Date: Wed, 28 Feb 2018 15:08:25 +0000 (+0100) Subject: Separate out cursor handling X-Git-Tag: v1.1.0~62^2~1 X-Git-Url: https://git.proxmox.com/?p=mirror_novnc.git;a=commitdiff_plain;h=b475eed5fae5e7e1cdc80ae78604680b914d2a6e;ds=sidebyside Separate out cursor handling Make cursor handling more generic in preparation for generic handling of corner cases. --- diff --git a/core/display.js b/core/display.js index 9915615..44304ae 100644 --- a/core/display.js +++ b/core/display.js @@ -498,18 +498,6 @@ Display.prototype = { this._damage(x, y, img.width, img.height); }, - changeCursor: function (pixels, mask, hotx, hoty, w, h) { - Display.changeCursor(this._target, pixels, mask, hotx, hoty, w, h); - }, - - defaultCursor: function () { - this._target.style.cursor = "default"; - }, - - disableLocalCursor: function () { - this._target.style.cursor = "none"; - }, - autoscale: function (containerWidth, containerHeight) { var vp = this._viewportLoc; var targetAspectRatio = containerWidth / containerHeight; @@ -655,44 +643,3 @@ Display.prototype = { } }, }; - -// Class Methods -Display.changeCursor = function (target, pixels, mask, hotx, hoty, w, h) { - if ((w === 0) || (h === 0)) { - target.style.cursor = 'none'; - return; - } - - var cur = [] - var y, x; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - var idx = y * Math.ceil(w / 8) + Math.floor(x / 8); - var alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0; - idx = ((w * y) + x) * 4; - cur.push(pixels[idx + 2]); // red - cur.push(pixels[idx + 1]); // green - cur.push(pixels[idx]); // blue - cur.push(alpha); // alpha - } - } - - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - - canvas.width = w; - canvas.height = h; - - var img; - if (SUPPORTS_IMAGEDATA_CONSTRUCTOR) { - img = new ImageData(new Uint8ClampedArray(cur), w, h); - } else { - img = ctx.createImageData(w, h); - img.data.set(new Uint8ClampedArray(cur)); - } - ctx.clearRect(0, 0, w, h); - ctx.putImageData(img, 0, 0); - - var url = canvas.toDataURL(); - target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default'; -}; diff --git a/core/rfb.js b/core/rfb.js index 81e1e6a..741bf18 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -17,6 +17,7 @@ import EventTargetMixin from './util/eventtarget.js'; import Display from "./display.js"; import Keyboard from "./input/keyboard.js"; import Mouse from "./input/mouse.js"; +import Cursor from "./util/cursor.js"; import Websock from "./websock.js"; import DES from "./des.js"; import KeyTable from "./input/keysym.js"; @@ -164,6 +165,8 @@ export default function RFB(target, url, options) { this._canvas.tabIndex = -1; this._screen.appendChild(this._canvas); + this._cursor = new Cursor(); + // populate encHandlers with bound versions this._encHandlers[encodings.encodingRaw] = RFB.encodingHandlers.RAW.bind(this); this._encHandlers[encodings.encodingCopyRect] = RFB.encodingHandlers.COPYRECT.bind(this); @@ -413,6 +416,8 @@ RFB.prototype = { // Make our elements part of the page this._target.appendChild(this._screen); + this._cursor.attach(this._canvas); + // Monitor size changes of the screen // FIXME: Use ResizeObserver, or hidden overflow window.addEventListener('resize', this._eventHandlers.windowResize); @@ -426,6 +431,7 @@ RFB.prototype = { _disconnect: function () { Log.Debug(">> RFB.disconnect"); + this._cursor.detach(); this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas); this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas); window.removeEventListener('resize', this._eventHandlers.windowResize); @@ -1241,10 +1247,6 @@ RFB.prototype = { this._timing.fbu_rt_start = (new Date()).getTime(); this._timing.pixels = 0; - // Cursor will be server side until the server decides to honor - // our request and send over the cursor image - this._display.disableLocalCursor(); - this._updateConnectionState('connected'); return true; }, @@ -2522,9 +2524,9 @@ RFB.encodingHandlers = { this._FBU.bytes = pixelslength + masklength; if (this._sock.rQwait("cursor encoding", this._FBU.bytes)) { return false; } - this._display.changeCursor(this._sock.rQshiftBytes(pixelslength), - this._sock.rQshiftBytes(masklength), - x, y, w, h); + this._cursor.change(this._sock.rQshiftBytes(pixelslength), + this._sock.rQshiftBytes(masklength), + x, y, w, h); this._FBU.bytes = 0; this._FBU.rects--; diff --git a/core/util/cursor.js b/core/util/cursor.js new file mode 100644 index 0000000..b7dcd5f --- /dev/null +++ b/core/util/cursor.js @@ -0,0 +1,71 @@ +/* + * noVNC: HTML5 VNC client + * Copyright 2018 Pierre Ossman for noVNC + * Licensed under MPL 2.0 or any later version (see LICENSE.txt) + */ + +function Cursor(container) { + this._target = null; +} + +Cursor.prototype = { + attach: function (target) { + if (this._target) { + this.detach(); + } + + this._target = target; + + this.clear(); + }, + + detach: function () { + this._target = null; + }, + + change: function (pixels, mask, hotx, hoty, w, h) { + if ((w === 0) || (h === 0)) { + this.clear(); + return; + } + + let cur = [] + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + let idx = y * Math.ceil(w / 8) + Math.floor(x / 8); + let alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0; + idx = ((w * y) + x) * 4; + cur.push(pixels[idx + 2]); // red + cur.push(pixels[idx + 1]); // green + cur.push(pixels[idx]); // blue + cur.push(alpha); // alpha + } + } + + let canvas = document.createElement('canvas'); + let ctx = canvas.getContext('2d'); + + canvas.width = w; + canvas.height = h; + + let img; + try { + // IE doesn't support this + img = new ImageData(new Uint8ClampedArray(cur), w, h); + } catch (ex) { + img = ctx.createImageData(w, h); + img.data.set(new Uint8ClampedArray(cur)); + } + ctx.clearRect(0, 0, w, h); + ctx.putImageData(img, 0, 0); + + let url = this._canvas.toDataURL(); + this._target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default'; + }, + + clear: function () { + this._target.style.cursor = 'none'; + }, +}; + +export default Cursor; diff --git a/docs/API-internal.md b/docs/API-internal.md index 4943c1a..0b29afb 100644 --- a/docs/API-internal.md +++ b/docs/API-internal.md @@ -113,9 +113,6 @@ None | blitRgbImage | (x, y, width, height, arr, offset, from_queue) | Blit RGB encoded image to display | blitRgbxImage | (x, y, width, height, arr, offset, from_queue) | Blit RGBX encoded image to display | drawImage | (img, x, y) | Draw image and track damage -| changeCursor | (pixels, mask, hotx, hoty, w, h) | Change cursor appearance -| defaultCursor | () | Restore default cursor appearance -| disableLocalCursor | () | Disable local (client-side) cursor | autoscale | (containerWidth, containerHeight) | Scale the display ### 2.3.3 Callbacks