Rename the $() selector to $D() so that it doesn't collide with
the jQuery name.
The API change is that the 'target' option for Canvas and RFB objects
must now be a DOM Canvas element. A string is no longer accepted
because this requires that a DOM lookup is done and the Canvas and RFB
should have no UI code in them. Modularity.
Only call encode_message when the WebSockets object is actually
ready to send. Otherwise multiple base64 encode sequences can be
encoded into the same WebSockets frame. This causes the C version of
wsproxy to crash and the python version to ignore the subsequent
base64 sequence(s).
Thanks to Colin Dean (xvpsource.org) for finding this and helping
track it down.
- Add meta tag to vnc.html and vnc_auto.html so that if Chrome Frame
is installed, it is used.
- Add detection to default_controls.js that shows a message with
a Chrome Frame install link if the user is using a version of IE
without Canvas support.
- Fix web.py so that requests have their connection closed after they
are completed. This has been a bug for a while but it prevents
Chrome Frame from working because Chrome Frame doesn't activate
until the initial request connection closes.
This is WebKit bug https://bugs.webkit.org/show_bug.cgi?id=46319
The workaround is to wrap Canvas render functions with a function that
sets a flush timer. The flush function sets the right margin and then
1ms later sets it back. This triggers the canvas to redraw with the
correct contents.
Two downsides:
- rendering is slower, but only on the busted versions of webkit.
Correct and useful is better than fast and useless.
- There is a barely perceptible jitter of the control buttons because
the canvas size is changing by one pixel.
To support this functionality, we also have to read out the exact
webkit version from the user agent in the render engine detection code
in include/util.js.
- Make sure that canvas exists (i.e. didn't throw an error) before
trying to call canvas method get_canvas_uri.
- Typos in HTML render engine debug output.
- Split out ClientInitialisation state.
- In version 3.3 and 3.7, when the server has no auth (scheme
1), then we should skip from Authentication to ClientInitialisation.
- rQwait checks the receive queue to see if there is enough data to
satisfy the following request. If not it returns true (which is
almost always translated into an immediate return false by the
caller).
- rQwait is called quite a bit and this generally allows 4 lines to
become 1 line where it is called.
- rQwait allows simplification of cuttext processing. No global
tracking needed anymore.
Overall, about 60 lines less code.
DES is just used once during authentication and is not performance
sensitive so we save some space by generating and/or removing some
lookup tables. Also, shorten some very frequently used variables.
Shaves off about 100 lines.
- util.js that contains essential functions
- webutils.js that contains the GUI utility function.js
this helps to include noVNC in other project, especially Cappuccino Application
i
The decrypt functionality is never used so remove it. Also, we can
assume that we are always DES encrypting 16 characters which allows
several things to be simplified in DES.
Overall this removes about 80 lines of code.
- include/rfb.js: Keep track of the number of rects of each encoding
type and print them out when we close a connection (if 'info'
logging level).
- tests/vnc_perf.html: first pass at a noVNC based performance
benchmark.
- utils/wsproxy.py: Fix the output of the record filename.
- include/util.js: Add type and desc field to conf_default routine.
Make comment descriptions of settings into desc parameters that can
be queried. Also, use set_FOO in conf_default to set or coerce the
current setting so that we always have the right type for the value.
- include/rfb.js, include/default_config.js: add connectTimeout
setting to address situations with slow connections that may need
more than 2 seconds.
Yet another weird VNC server behavior: sending a failure and length
before the reason message. To calculated the length, the reason string
is already available, why not just send everything as one packet. Oh
well.
- include/canvas.js: When 'debug' logging, show browser detection
values.
- test/canvas.html: Only restore the canvas to it's starting state if
the logging level is not 'debug'.
- wsproxy.py: Append the session number to the record filename so that
multiple sessions don't stomp on each other.
In Safari, local cursor rendering is corrupt. In firefox 3.6.10, local
cursor rendering causes a segfault. Probable that the .cur format is
not 100% compliant (even though it works in Chrome and firefox 3.5 and
firefox 4.0). So just disable it by default until I can figure out how
to address the problems.
Add a new state 'disconnect' to reflect that we are not truly
'disconnected' until we get an onclose event. Add a disconnect timer
to match.
Handle disconnected cleanup better in updateState(). Anytime we enter
in a disconnect/disconnected state, make sure all running state is
cleaned up (WebSocket, timers, canvas).
Filed this issue for this bug:
http://github.com/gimite/web-socket-js/issues/issue/37
Right now the close() call only calls __flash.close() if readyState is OPEN.
But it should really call close any time that readyState is not CLOSED or
CLOSING.
The case I ran into is when I want to do the following:
1. make a test connection
2. tell the server to setup for a connection
3. connect again
I call close on the test connection, but since it is ignored when CONNECTING,
it eventually times out with a error. But by that time I have already issued a
new connection, it causes the new connection to fail. close() should cancel
CONNECTING state too.
Filed this bug about this issue:
http://github.com/gimite/web-socket-js/issues#issue/35
To work around the flash "recursive call" problem, WebSocket.as has
the onclose event disabled in the close() call and the javascript half
of the close() call does the onclose() call instead. This is fine, but
it needs to be asynchronous to act more like what happens with
a normal WebSockets object. The current behavior is that the onclose()
method is called inline (synchronously) when the close() is called and
this inconsistency make state handling more difficult.
web-socket-js now has all the functionality and fixes needed for noVNC
so remove the include/as3crypto_patched directory and the
include/web-socket-js/flash-src directory (i.e. the sources for
web-socket-js). This cleans up almost 3K from the include/ directory.
Update to web-socket-js build based on upstream (gimite/web-socket-js)
9e766377188.
The rfb variable wasn't available at the point settingsDisabled() was
being called since it was called inline with RFB() initialization. To
solve this we pass the updateState rfb variable so that the canvas can
be queried for setting the cursor_uri value.
When the documement/window is scrolled, the onMouseDisable routine was
not properly calculating the position to test whether to ignore the
event or not.
Generally, most servers send hextile updates as single updates
containing many rects. Some servers send hextile updates as many small
framebuffer updates with a few rects each (such as QEMU). This latter
cases revealed that shifting off the beginning of the receive queue
(which happens after each hextile FBU) performs poorly.
This change switches to using an indexed receive queue (instead of
actually shifting off the array). When the receive queue has grown to
a certain size, then it is compacted all at once.
The code is not as clean, but this change results in more than 2X
speedup under Chrome for the pessimal case and 10-20% in firefox.
Apparently there are versions of UltraVNC that report version 3.6.
This is not a legal version according to the spec, but we'll just
force version 3.3 if we receive it. Thanks to Larry Rowe for the info.
Turns out when Windows is running in QEMU and a window scroll happens,
there are lots of little hextile rects sent. This is slow in noVNC.
- Some recording/playback improvement.
- Add test harness to drive playback of recordings.
- By pulling off the rect header in one chunk we get a 3X speedup in
Chrome and a 20% speedup in firefox (specifically for the scroll
test).
- Also, get rid of some noise from creating timers for handle_message.
Check to make sure there isn't already a pending timer first.
This is very usefull when you need to open a new window (with a new document) from javascript,
without having to reload the script.js.
(cherry picked from commit 8ded53c1de06d01e50d58543c19e73926f0fbbd4)
Signed-off-by: Joel Martin <github@martintribe.org>
New API:
To use the RFB object, you now must instantiate it (this allows more
than one instance of it on the same page).
rfb = new RFB(settings);
The 'settings' variable is a namespace that contains initial default
settings. These can also be set and read using 'rfb.set_FOO()' and
'rfb.get_FOO()' where FOO is the setting name. The current settings
are (and defaults) are:
- target: the DOM Canvas element to use ('VNC_canvas').
- encrypt: whether to encrypt the connection (false)
- true_color: true_color or palette (true)
- b64encode: base64 encode the WebSockets data (true)
- local_cursor: use local cursor rendering (true if supported)
- connectTimeout: milliseconds to wait for connect (2000)
- updateState: callback when RFB state changes (none)
- clipboardReceive: callback when clipboard data received (none)
The parameters to the updateState callback have also changed. The
function spec is now updateState(rfb, state, oldstate, msg):
- rfb: the RFB object that this state change is for.
- state: the new state
- oldstate: the previous state
- msg: a message associate with the state (not always set).
The clipboardReceive spec is clipboardReceive(rfb, text):
- rfb: the RFB object that this text is from.
- text: the clipboard text received.
Changes:
- The RFB and Canvas namespaces are now more proper objects. Private
implementation is no longer exposed and the public API has been made
explicit. Also, instantiation allows more than one VNC connection
on the same page (to complete this, DefaultControls will also need
this same refactoring).
- Added 'none' logging level.
- Removed automatic stylesheet selection workaround in util.js and
move it to defaultcontrols so that it doesn't interfere with
intergration.
- Also, some major JSLinting.
- Fix input, canvas, and cursor tests to work with new model.
If cursor Data URI scheme detection threw an exception, it would cause
canvas initialization to fail. cursor detection exceptions should just
disable local cursor change support, not cause canvas init to fail.
Uses the CSS "scale()" operation. The main problem is that the DOM
container is not rescaled, only the size of the displayed content
within it so there will need to be some sort of mechanism to handle
this better so other elements reflow to the new size. Or it might just
not work and be removed later. The zoom property seems to do the right
behavior, but it's not widely supported. Worth exploring though.
After each complete framebufferUpdate, set a short timer to continue
processing the receive queue. This gives other events a chance to
fire. Especially important when noVNC is integrated into another
website.
noVNC was never processing more than one framebufferUpdate message per
onmessage event. If noVNC receives an incomplete framebufferUpdate and
then receives the rest of the framebufferUpdate plus another complete
framebufferUpdate, then it will fall permanently behind.
If there is more to process after a completed framebufferUpdate, then
execute normal_msg again.
All the render routines must return false if there is not enough data
in the receive queue to process their current update, and true
otherwise.
Move the whole RFB object to rfb.js. vnc.js is now just the loader
file. This allows an integrating project to easily replace vnc.js with
an alternate loader mechanism (or just do it directly in the html
file). Thanks for the idea primalmotion (http://github.com/primalmotion).
Also, JSLint the various files.
The following API changes may affect integrators:
- Settings have been moved out of the RFB.connect() call. Each
setting now has it's own setter function: setEncrypt, setBase64,
setTrueColor, setCursor.
- Encrypt and cursor settings now default to on.
- CSS changes:
- VNC_status_bar for input buttons switched to a element class.
- VNC_buttons split into VNC_buttons_right and
VNC_buttons_left
- New id styles for VNC_settings_menu and VNC_setting
Note: the encrypt, true_color and cursor, logging setting can all be
set on load using query string variables (in addition to host, port
and password).
Client cursor (cursor pseudo-encoding) support has been polished and
activated.
The RFB settings are now presented as radio button list items in
a drop-down "Settings" menu when using the default controls.
Also, in the settings menu is the ability to select between alternate
style-sheets.
Cookie and stylesheet selection support added to util.js.
To change the appearance of the cursor, we use the CSS cursor style
and set the url to a data URI scheme. The image data sent via the
cursor pseudo-encoding has to be encoded to a CUR format file before
being used in the data URI.
During Canvas initialization we try and set a simple cursor to see if
the browser has support. Opera is missing support for data URI scheme
in cursor URLs.
Disabled for now until we have a better way of specifying settings
overall (too many settings for control bar now).
Add new states 'loaded', 'connect' and 'fatal':
- Loaded state is first page state. Pass WebSockets mode message using
this state.
- Connect indicates that the user has issued a "connect" but we
haven't gotten an WebSockets onopen yet.
- Fatal is a condition that indicates inability to continue on: right
now, lack of WebSockets/Flash or non-working canvas.
Move much of the actual state transition code into updateState.
Handle 'password' state better in default_controls.js; instead of
disconnecting, prompt for password to send.
Add comments to updateState indicating possible states.
Util.Debug, Util.Info, Util.Warn, Util.Error routines instead of
direct calls to console.*. Add "logging=XXX" query variable that sets
the logging level (default is "warn").
Logging values:
debug: code debug logging (many calls in performance path are also
commented for performance reasons).
info: informative messages including timing information.
warn: significant events
error: something has gone wrong
The problem is, you can't set WebSocket.__swfLocation before you load
web_socket.js (because it creates the WebSocket global), but you also
can't reliably set WebSocket.__swfLocation after because if you are
doing dynamic script file includes then the onload (i.e.
WebSocket.__initialize) may fire before you have a chance to set
Websocket.__swfLocation.
Add message/state pollling in web-socket-js. Since Opera tends to drop
message events, we can dramatically increase performance by polling
every now for message event data.
Also, add more direct calls to update readyState so that it's not
missed when Opera drops events.
When using web-socket-js, the onopen event may happen inline so the
caller may not have time to set onopen before the event fires. In this
case set a short timeout and try again. In particular this affects
Opera most of the time.
Also, to get around Opera event droppings, always read the readyState
directly instead of relying on the local readyState variable to be
correct (which it isn't if stateChange event were dropped).
All browsers with Canvas imageData are faster with JS ops instead of
canvas ops. This gives significant performance improvement in Opera.
Except for missing web-socet-js message notifications, Opera 10.60 is
now faster than firefox 3.5.
Instead of relying on FABridge AS -> JS event delivery, we just use
the events to notify JS of pending data. The message handler then
calls the AS readSocketData routine which sends back an array of
the pending WebSocket frames.
There is still a minor bug somewhere that happens after the first
connect where the web-socket-js throws an "INVALID_STATE_ERR: Web
Socket connection has not been established". But, Opera is now usable
and we should be able to drop the packet sequence numbering and
re-ordering code.
Another minor issue to better support Opera is to move JS script
includes to the <head> of the page instead of after the body.
Interesting. Enough has changed in the Canvas tile operations, that
Canvas.prefer_js=true is better for firefox/gecko too. Approximately
2X improvement in firefox for large hextile renders.
Looks like disabling web-socket-js debug messages by default that we
get a minor speedup.
Python proxy should support both 75 and 76 (00) modes. Also, update ws
test to more reliably hit the WebSockets ordering/drop issue.
Some default_controls.js jslinting.
Needs to be some modularity between controls you probably always want
(like sending CtrlAltDel) and how the interface is presented and
controlled.