xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #473: 3junexprahtml5.patch

File 3junexprahtml5.patch, 57.8 KB (added by Josh, 8 years ago)

superseding my previous patch, cleaned up, many improvements

  • html5/include/websock.js

     
    2323// To force WebSocket emulator even when native WebSocket available
    2424//window.WEB_SOCKET_FORCE_FLASH = true;
    2525// To enable WebSocket emulator debug:
    26 //window.WEB_SOCKET_DEBUG=1;
     26window.WEB_SOCKET_DEBUG=1;
    2727
    2828if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
    2929    Websock_native = true;
  • html5/include/protocol.js

     
    107107function process_buffer() {
    108108        "use strict";
    109109
    110         if (buf[0]!=ord("P"))
     110        if (buf[0]!=ord("P")) {
    111111                throw "invalid packet header format: "+hex2(buf[0]);
     112        }
    112113
    113114        var proto_flags = buf[1];
    114115        if (proto_flags!=0)
     
    169170        var fn = "";
    170171        try {
    171172                packet_type = packet[0];
     173                show("recieved a " + packet_type + " packet");
    172174                fn = packet_handlers[packet_type];
    173175                if (fn==undefined)
    174176                        error("no packet handler for "+packet_type+"!");
  • html5/include/inflate.min.js

     
    1 /** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';function m(b){throw b;}var n=void 0,r=this;function s(b,d){var a=b.split("."),c=r;!(a[0]in c)&&c.execScript&&c.execScript("var "+a[0]);for(var f;a.length&&(f=a.shift());)!a.length&&d!==n?c[f]=d:c=c[f]?c[f]:c[f]={}};var u="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array;function v(b){var d=b.length,a=0,c=Number.POSITIVE_INFINITY,f,e,g,h,k,l,q,p,t;for(p=0;p<d;++p)b[p]>a&&(a=b[p]),b[p]<c&&(c=b[p]);f=1<<a;e=new (u?Uint32Array:Array)(f);g=1;h=0;for(k=2;g<=a;){for(p=0;p<d;++p)if(b[p]===g){l=0;q=h;for(t=0;t<g;++t)l=l<<1|q&1,q>>=1;for(t=l;t<f;t+=k)e[t]=g<<16|p;++h}++g;h<<=1;k<<=1}return[e,a,c]};function w(b,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=u?new Uint8Array(b):b;this.m=!1;this.i=x;this.r=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.r=d.resize);switch(this.i){case y:this.b=32768;this.c=new (u?Uint8Array:Array)(32768+this.h+258);break;case x:this.b=0;this.c=new (u?Uint8Array:Array)(this.h);this.e=this.z;this.n=this.v;this.j=this.w;break;default:m(Error("invalid inflate mode"))}}
    2 var y=0,x=1,z={t:y,s:x};
    3 w.prototype.k=function(){for(;!this.m;){var b=A(this,3);b&1&&(this.m=!0);b>>>=1;switch(b){case 0:var d=this.input,a=this.a,c=this.c,f=this.b,e=n,g=n,h=n,k=c.length,l=n;this.d=this.f=0;e=d[a++];e===n&&m(Error("invalid uncompressed block header: LEN (first byte)"));g=e;e=d[a++];e===n&&m(Error("invalid uncompressed block header: LEN (second byte)"));g|=e<<8;e=d[a++];e===n&&m(Error("invalid uncompressed block header: NLEN (first byte)"));h=e;e=d[a++];e===n&&m(Error("invalid uncompressed block header: NLEN (second byte)"));h|=
    4 e<<8;g===~h&&m(Error("invalid uncompressed block header: length verify"));a+g>d.length&&m(Error("input buffer is broken"));switch(this.i){case y:for(;f+g>c.length;){l=k-f;g-=l;if(u)c.set(d.subarray(a,a+l),f),f+=l,a+=l;else for(;l--;)c[f++]=d[a++];this.b=f;c=this.e();f=this.b}break;case x:for(;f+g>c.length;)c=this.e({p:2});break;default:m(Error("invalid inflate mode"))}if(u)c.set(d.subarray(a,a+g),f),f+=g,a+=g;else for(;g--;)c[f++]=d[a++];this.a=a;this.b=f;this.c=c;break;case 1:this.j(B,C);break;case 2:aa(this);
    5 break;default:m(Error("unknown BTYPE: "+b))}}return this.n()};
    6 var D=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],E=u?new Uint16Array(D):D,F=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],G=u?new Uint16Array(F):F,H=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],I=u?new Uint8Array(H):H,J=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],K=u?new Uint16Array(J):J,L=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,
    7 13],M=u?new Uint8Array(L):L,N=new (u?Uint8Array:Array)(288),O,P;O=0;for(P=N.length;O<P;++O)N[O]=143>=O?8:255>=O?9:279>=O?7:8;var B=v(N),Q=new (u?Uint8Array:Array)(30),R,S;R=0;for(S=Q.length;R<S;++R)Q[R]=5;var C=v(Q);function A(b,d){for(var a=b.f,c=b.d,f=b.input,e=b.a,g;c<d;)g=f[e++],g===n&&m(Error("input buffer is broken")),a|=g<<c,c+=8;g=a&(1<<d)-1;b.f=a>>>d;b.d=c-d;b.a=e;return g}
    8 function T(b,d){for(var a=b.f,c=b.d,f=b.input,e=b.a,g=d[0],h=d[1],k,l,q;c<h;){k=f[e++];if(k===n)break;a|=k<<c;c+=8}l=g[a&(1<<h)-1];q=l>>>16;b.f=a>>q;b.d=c-q;b.a=e;return l&65535}
    9 function aa(b){function d(a,b,c){var d,e,f,g;for(g=0;g<a;)switch(d=T(this,b),d){case 16:for(f=3+A(this,2);f--;)c[g++]=e;break;case 17:for(f=3+A(this,3);f--;)c[g++]=0;e=0;break;case 18:for(f=11+A(this,7);f--;)c[g++]=0;e=0;break;default:e=c[g++]=d}return c}var a=A(b,5)+257,c=A(b,5)+1,f=A(b,4)+4,e=new (u?Uint8Array:Array)(E.length),g,h,k,l;for(l=0;l<f;++l)e[E[l]]=A(b,3);g=v(e);h=new (u?Uint8Array:Array)(a);k=new (u?Uint8Array:Array)(c);b.j(v(d.call(b,a,g,h)),v(d.call(b,c,g,k)))}
    10 w.prototype.j=function(b,d){var a=this.c,c=this.b;this.o=b;for(var f=a.length-258,e,g,h,k;256!==(e=T(this,b));)if(256>e)c>=f&&(this.b=c,a=this.e(),c=this.b),a[c++]=e;else{g=e-257;k=G[g];0<I[g]&&(k+=A(this,I[g]));e=T(this,d);h=K[e];0<M[e]&&(h+=A(this,M[e]));c>=f&&(this.b=c,a=this.e(),c=this.b);for(;k--;)a[c]=a[c++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=c};
    11 w.prototype.w=function(b,d){var a=this.c,c=this.b;this.o=b;for(var f=a.length,e,g,h,k;256!==(e=T(this,b));)if(256>e)c>=f&&(a=this.e(),f=a.length),a[c++]=e;else{g=e-257;k=G[g];0<I[g]&&(k+=A(this,I[g]));e=T(this,d);h=K[e];0<M[e]&&(h+=A(this,M[e]));c+k>f&&(a=this.e(),f=a.length);for(;k--;)a[c]=a[c++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=c};
    12 w.prototype.e=function(){var b=new (u?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,c,f=this.c;if(u)b.set(f.subarray(32768,b.length));else{a=0;for(c=b.length;a<c;++a)b[a]=f[a+32768]}this.g.push(b);this.l+=b.length;if(u)f.set(f.subarray(d,d+32768));else for(a=0;32768>a;++a)f[a]=f[d+a];this.b=32768;return f};
    13 w.prototype.z=function(b){var d,a=this.input.length/this.a+1|0,c,f,e,g=this.input,h=this.c;b&&("number"===typeof b.p&&(a=b.p),"number"===typeof b.u&&(a+=b.u));2>a?(c=(g.length-this.a)/this.o[2],e=258*(c/2)|0,f=e<h.length?h.length+e:h.length<<1):f=h.length*a;u?(d=new Uint8Array(f),d.set(h)):d=h;return this.c=d};
    14 w.prototype.n=function(){var b=0,d=this.c,a=this.g,c,f=new (u?Uint8Array:Array)(this.l+(this.b-32768)),e,g,h,k;if(0===a.length)return u?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);e=0;for(g=a.length;e<g;++e){c=a[e];h=0;for(k=c.length;h<k;++h)f[b++]=c[h]}e=32768;for(g=this.b;e<g;++e)f[b++]=d[e];this.g=[];return this.buffer=f};
    15 w.prototype.v=function(){var b,d=this.b;u?this.r?(b=new Uint8Array(d),b.set(this.c.subarray(0,d))):b=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),b=this.c);return this.buffer=b};function U(b,d){var a,c;this.input=b;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.A=d.verify);a=b[this.a++];c=b[this.a++];switch(a&15){case V:this.method=V;break;default:m(Error("unsupported compression method"))}0!==((a<<8)+c)%31&&m(Error("invalid fcheck flag:"+((a<<8)+c)%31));c&32&&m(Error("fdict flag is not supported"));this.q=new w(b,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
    16 U.prototype.k=function(){var b=this.input,d,a;d=this.q.k();this.a=this.q.a;if(this.A){a=(b[this.a++]<<24|b[this.a++]<<16|b[this.a++]<<8|b[this.a++])>>>0;var c=d;if("string"===typeof c){var f=c.split(""),e,g;e=0;for(g=f.length;e<g;e++)f[e]=(f[e].charCodeAt(0)&255)>>>0;c=f}for(var h=1,k=0,l=c.length,q,p=0;0<l;){q=1024<l?1024:l;l-=q;do h+=c[p++],k+=h;while(--q);h%=65521;k%=65521}a!==(k<<16|h)>>>0&&m(Error("invalid adler-32 checksum"))}return d};var V=8;s("Zlib.Inflate",U);s("Zlib.Inflate.prototype.decompress",U.prototype.k);var W={ADAPTIVE:z.s,BLOCK:z.t},X,Y,Z,$;if(Object.keys)X=Object.keys(W);else for(Y in X=[],Z=0,W)X[Z++]=Y;Z=0;for($=X.length;Z<$;++Z)Y=X[Z],s("Zlib.Inflate.BufferType."+Y,W[Y]);}).call(this); //# sourceMappingURL=inflate.min.js.map
     1/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';var m=this;function q(c,d){var a=c.split("."),b=m;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&void 0!==d?b[e]=d:b=b[e]?b[e]:b[e]={}};var s="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function t(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,l,p,n,r,K;for(n=0;n<d;++n)c[n]>a&&(a=c[n]),c[n]<b&&(b=c[n]);e=1<<a;f=new (s?Uint32Array:Array)(e);g=1;h=0;for(k=2;g<=a;){for(n=0;n<d;++n)if(c[n]===g){l=0;p=h;for(r=0;r<g;++r)l=l<<1|p&1,p>>=1;K=g<<16|n;for(r=l;r<e;r+=k)f[r]=K;++h}++g;h<<=1;k<<=1}return[f,a,b]};function u(c,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=s?new Uint8Array(c):c;this.m=!1;this.i=v;this.s=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.s=d.resize);switch(this.i){case w:this.b=32768;this.c=new (s?Uint8Array:Array)(32768+this.h+258);break;case v:this.b=0;this.c=new (s?Uint8Array:Array)(this.h);this.e=this.A;this.n=this.w;this.j=this.z;break;default:throw Error("invalid inflate mode");
     2}}var w=0,v=1,x={u:w,t:v};
     3u.prototype.k=function(){for(;!this.m;){var c=y(this,3);c&1&&(this.m=!0);c>>>=1;switch(c){case 0:var d=this.input,a=this.a,b=this.c,e=this.b,f=d.length,g=void 0,h=void 0,k=b.length,l=void 0;this.d=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=d[a++]|d[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=d[a++]|d[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case w:for(;e+
     4g>b.length;){l=k-e;g-=l;if(s)b.set(d.subarray(a,a+l),e),e+=l,a+=l;else for(;l--;)b[e++]=d[a++];this.b=e;b=this.e();e=this.b}break;case v:for(;e+g>b.length;)b=this.e({p:2});break;default:throw Error("invalid inflate mode");}if(s)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.a=a;this.b=e;this.c=b;break;case 1:this.j(z,A);break;case 2:B(this);break;default:throw Error("unknown BTYPE: "+c);}}return this.n()};
     5var C=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],D=s?new Uint16Array(C):C,E=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],F=s?new Uint16Array(E):E,G=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],H=s?new Uint8Array(G):G,I=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],J=s?new Uint16Array(I):I,L=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,
     613],M=s?new Uint8Array(L):L,N=new (s?Uint8Array:Array)(288),O,P;O=0;for(P=N.length;O<P;++O)N[O]=143>=O?8:255>=O?9:279>=O?7:8;var z=t(N),Q=new (s?Uint8Array:Array)(30),R,S;R=0;for(S=Q.length;R<S;++R)Q[R]=5;var A=t(Q);function y(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h;b<d;){if(f>=g)throw Error("input buffer is broken");a|=e[f++]<<b;b+=8}h=a&(1<<d)-1;c.f=a>>>d;c.d=b-d;c.a=f;return h}
     7function T(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h=d[0],k=d[1],l,p;b<k&&!(f>=g);)a|=e[f++]<<b,b+=8;l=h[a&(1<<k)-1];p=l>>>16;c.f=a>>p;c.d=b-p;c.a=f;return l&65535}
     8function B(c){function d(a,c,b){var d,e=this.q,f,g;for(g=0;g<a;)switch(d=T(this,c),d){case 16:for(f=3+y(this,2);f--;)b[g++]=e;break;case 17:for(f=3+y(this,3);f--;)b[g++]=0;e=0;break;case 18:for(f=11+y(this,7);f--;)b[g++]=0;e=0;break;default:e=b[g++]=d}this.q=e;return b}var a=y(c,5)+257,b=y(c,5)+1,e=y(c,4)+4,f=new (s?Uint8Array:Array)(D.length),g,h,k,l;for(l=0;l<e;++l)f[D[l]]=y(c,3);if(!s){l=e;for(e=f.length;l<e;++l)f[D[l]]=0}g=t(f);h=new (s?Uint8Array:Array)(a);k=new (s?Uint8Array:Array)(b);c.q=0;
     9c.j(t(d.call(c,a,g,h)),t(d.call(c,b,g,k)))}u.prototype.j=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length-258,f,g,h,k;256!==(f=T(this,c));)if(256>f)b>=e&&(this.b=b,a=this.e(),b=this.b),a[b++]=f;else{g=f-257;k=F[g];0<H[g]&&(k+=y(this,H[g]));f=T(this,d);h=J[f];0<M[f]&&(h+=y(this,M[f]));b>=e&&(this.b=b,a=this.e(),b=this.b);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
     10u.prototype.z=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length,f,g,h,k;256!==(f=T(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=F[g];0<H[g]&&(k+=y(this,H[g]));f=T(this,d);h=J[f];0<M[f]&&(h+=y(this,M[f]));b+k>e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
     11u.prototype.e=function(){var c=new (s?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,b,e=this.c;if(s)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;a<b;++a)c[a]=e[a+32768]}this.g.push(c);this.l+=c.length;if(s)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];this.b=32768;return e};
     12u.prototype.A=function(c){var d,a=this.input.length/this.a+1|0,b,e,f,g=this.input,h=this.c;c&&("number"===typeof c.p&&(a=c.p),"number"===typeof c.v&&(a+=c.v));2>a?(b=(g.length-this.a)/this.o[2],f=258*(b/2)|0,e=f<h.length?h.length+f:h.length<<1):e=h.length*a;s?(d=new Uint8Array(e),d.set(h)):d=h;return this.c=d};
     13u.prototype.n=function(){var c=0,d=this.c,a=this.g,b,e=new (s?Uint8Array:Array)(this.l+(this.b-32768)),f,g,h,k;if(0===a.length)return s?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);f=0;for(g=a.length;f<g;++f){b=a[f];h=0;for(k=b.length;h<k;++h)e[c++]=b[h]}f=32768;for(g=this.b;f<g;++f)e[c++]=d[f];this.g=[];return this.buffer=e};
     14u.prototype.w=function(){var c,d=this.b;s?this.s?(c=new Uint8Array(d),c.set(this.c.subarray(0,d))):c=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),c=this.c);return this.buffer=c};function U(c,d){var a,b;this.input=c;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.B=d.verify);a=c[this.a++];b=c[this.a++];switch(a&15){case V:this.method=V;break;default:throw Error("unsupported compression method");}if(0!==((a<<8)+b)%31)throw Error("invalid fcheck flag:"+((a<<8)+b)%31);if(b&32)throw Error("fdict flag is not supported");this.r=new u(c,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
     15U.prototype.k=function(){var c=this.input,d,a;d=this.r.k();this.a=this.r.a;if(this.B){a=(c[this.a++]<<24|c[this.a++]<<16|c[this.a++]<<8|c[this.a++])>>>0;var b=d;if("string"===typeof b){var e=b.split(""),f,g;f=0;for(g=e.length;f<g;f++)e[f]=(e[f].charCodeAt(0)&255)>>>0;b=e}for(var h=1,k=0,l=b.length,p,n=0;0<l;){p=1024<l?1024:l;l-=p;do h+=b[n++],k+=h;while(--p);h%=65521;k%=65521}if(a!==(k<<16|h)>>>0)throw Error("invalid adler-32 checksum");}return d};var V=8;q("Zlib.Inflate",U);q("Zlib.Inflate.prototype.decompress",U.prototype.k);var W={ADAPTIVE:x.t,BLOCK:x.u},X,Y,Z,$;if(Object.keys)X=Object.keys(W);else for(Y in X=[],Z=0,W)X[Z++]=Y;Z=0;for($=X.length;Z<$;++Z)Y=X[Z],q("Zlib.Inflate.BufferType."+Y,W[Y]);}).call(this); //@ sourceMappingURL=inflate.min.js.map
  • html5/include/window.js

     
    77 * Based on shape.js
    88 */
    99
    10 var window_icons = {};
    11 //load the window icons
    12 var image_names = ["maximize", "minimize", "close"];
    13 function load_icon(name) {
    14         console.log("loading "+name);
    15         var tmp_canvas = document.createElement('canvas');
    16         var tmp_context = tmp_canvas.getContext('2d');
    17         var image = new Image();
    18         image.onload = function() {
    19                 show(""+name+"="+image);
    20                 tmp_context.drawImage(image, 0, 0);
    21                 var image_data = tmp_context.getImageData(0, 0, image.width, image.height);
    22                 window_icons[name] = image_data;
    23         };
    24         image.src = '/include/'+name+'.png';
    25 }
    26 
    27 for (var i in image_names) {
    28         load_icon(image_names[i]);
    29 }
    30 
    3110/**
    32  * A simple button we use to decorate the window.
    33  */
    34 function Button(canvas_state, name, x, y, w, h, fill, icon_name, click_callback) {
    35         "use strict";
    36         this.state = canvas_state;
    37         this.name = name;
    38         this.x = x || 0;
    39         this.y = y || 0;
    40         this.w = w || 1;
    41         this.h = h || 1;
    42         var ctx = canvas_state.canvas.getContext('2d');
    43         this.image = ctx.createImageData(w, h);
    44         //var data = this.image.data;
    45         for (var i=0; i<w*h*4; i++) {
    46                 this.image.data[i] = (fill || 0xAA) &0xFF;
    47         }
    48         var icon = window_icons[icon_name];
    49         if (icon) {
    50                 this.update_image(icon.width, icon.height, "premult_argb32", icon.data);
    51         }
    52         this.click_callback = click_callback;
    53 }
    54 Button.prototype.draw_at = function(ctx, x, y) {
    55         "use strict";
    56         //draw the window pixels:
    57         ctx.putImageData(this.image, this.x + x, this.y + y);
    58 };
    59 function rectangle_contains(rect, mx, my) {
    60         "use strict";
    61         // All we have to do is make sure the Mouse X,Y fall in the area between
    62         // the shape's X and (X + Height) and its Y and (Y + Height)
    63         return  (rect.x <= mx) && (rect.x + rect.w >= mx) &&
    64                                         (rect.y <= my) && (rect.y + rect.h >= my);
    65 };
    66 Button.prototype.get_geometry = function() {
    67         "use strict";
    68         return { x : this.x, y : this.y, w : this.w, h : this.h };
    69 };
    70 Button.prototype.contains = function(mx, my) {
    71         "use strict";
    72         return rectangle_contains(this.get_geometry(), mx, my);
    73 };
    74 Button.prototype.update_image = function(w, h, pixel_format, data) {
    75         "use strict";
    76         if (pixel_format!="premult_argb32") {
    77                 return;
    78         }
    79         var s, d, i;
    80         //to make this faster and better looking,
    81         //we could draw to a temporary canvas to scale it,
    82         //as per: http://stackoverflow.com/a/3449416/428751
    83         //here we just scale it by hand
    84         for (var x=0; x<this.w; x++) {
    85                 for (var y=0; y<this.h; y++) {
    86                         //destination index (simple)
    87                         d = ((y*this.w) + x) * 4;
    88                         //source index (scaled)
    89                         s = (Math.round(y*h/this.h)*w + Math.round(w*x/this.w)) * 4;
    90                         for (i=0; i<4; i++) {
    91                                 this.image.data[d+i] = data[s+i];
    92                         }
    93                 }
    94         }
    95 }
    96 
    97 /**
    98  * toString allows us to identify buttons:
    99  */
    100 Button.prototype.toString = function() {
    101         "use strict";
    102         return "Button("+this.name+")";
    103 };
    104 
    105 
    106 
    107 /**
    10811 * This is the class representing a window we draw on the canvas.
    10912 * It has a geometry, it may have borders and a top bar.
    11013 * The contents of the window is an image, which gets updated
    11114 * when we receive pixels from the server.
    11215 */
    113 function XpraWindow(canvas_state, wid, x, y, w, h, metadata, override_redirect, client_properties,
    114                 geometry_cb, mouse_move_cb, mouse_click_cb, window_closed) {
     16function XpraWindow(canvas_state, wid, x, y, w, h, metadata, override_redirect, client_properties, geometry_cb, mouse_move_cb, mouse_click_cb, set_focus_cb, window_closed_cb, htmldiv) {
    11517        "use strict";
     18        // use me in jquery callbacks as we lose 'this'
     19        var me = this;
    11620        //keep reference to the canvas:
    117         this.state = canvas_state;
     21        this.canvas = canvas_state;
     22        this.div = jQuery("#" + String(wid));
     23
    11824        //callbacks start null until we finish init:
    11925        this.geometry_cb = null;
    12026        this.mouse_move_cb = null;
    12127        this.mouse_click_cb = null;
    12228        this.window_closed_cb = null;
    12329
    124         //styling:
    125         this.borderColor = '#101028';
    126         this.topBarColor = '#B8B8C0';
    127 
    12830        //the window "backing":
    12931        this.image = null;
    13032
     
    13638
    13739        //window attributes:
    13840        this.title = null;
     41        this.windowtype = null;
    13942        this.fullscreen = false;
    14043        this.saved_geometry = null;
    14144        this.maximized = false;
    14245        this.focused = false;
    14346
    144         //not the real geometry we will use,
    145         //but enough to avoid errors if update_metadata fires changes
     47        //these values represent the internal geometry
     48        //i.e. geometry as windows appear to the compositor
    14649        this.x = x;
    14750        this.y = y;
    14851        this.w = w;
    14952        this.h = h;
    15053
    151         this.buttons = {};
     54        // get offsets
     55        this.leftoffset = parseInt(jQuery(this.div).css('border-left-width'), 10);
     56        this.rightoffset = parseInt(jQuery(this.div).css('border-right-width'), 10);
     57        this.topoffset = parseInt(jQuery(this.div).css('border-top-width'), 10);
     58        this.bottomoffset = parseInt(jQuery(this.div).css('border-bottom-width'), 10);
    15259
     60        // update metadata
    15361        this.update_metadata(metadata);
    15462
    155         // the space taken by window decorations:
    156         this.calculate_offsets();
    157 
    158         if (!this.fullscreen && !this.maximized) {
    159                 // if fullscreen or maximized, the metadata update will have set the new size already
    160                 // account for borders, and try to make the image area map to (x,y):
    161                 var rx = (x || 0) - this.borderWidth;
    162                 var ry = (y || 0) - this.topBarHeight + this.borderWidth;
    163                 var rw = (w || 1) + this.borderWidth*2;
    164                 var rh = (h || 1) + this.borderWidth*2 + this.topBarHeight;
    165                 this.move_resize(rx, ry, rw, rh);
    166                 //show("after move resize: ("+this.w+", "+this.h+")");
     63        // Hook up the events we want to receive:
     64        this.event_listeners = []
     65        var listeners = [
     66                        ['mousedown'    , true],
     67                        ['mouseup'              , true],
     68                        ['mousemove'    , true]
     69                        ];
     70        for (i = 0; i < listeners.length; i += 1) {
     71                var l = listeners[i];
     72                this.registerEventListener(l[0], l[1]);
    16773        }
    16874
    16975        // now safe to assign the callbacks:
    17076        this.geometry_cb = geometry_cb || null;
    17177        this.mouse_move_cb = mouse_move_cb || null;
    17278        this.mouse_click_cb = mouse_click_cb || null;
    173         this.window_closed_cb = window_closed || null;
     79        this.window_closed_cb = window_closed_cb || null;
    17480
    175         //create the buttons:
    176         if (!this.override_redirect) {
    177                 this.create_buttons();
     81        // create the decoration as part of the window, style is in CSS
     82        jQuery(this.div).addClass("window");
     83        jQuery(this.div).addClass("window-" + this.windowtype);
     84        // add a title bar to this window if we need to
     85        if((this.windowtype == "NORMAL") || (this.windowtype == "DIALOG") || (this.windowtype == "UTILITY")) {
     86                if(!this.override_redirect) {
     87                        // create header
     88                        jQuery(this.div).prepend('<div id="head' + String(wid) + '" class="windowhead"> <span class="windowtitle" id="title' + String(wid) + '">' + this.title + '</span> <span class="windowbuttons"> <span id="close' + String(wid) + '"><img src="include/close.png" /></span> </span></div>');
     89                        // make draggable
     90                        jQuery(this.div).draggable({
     91                                cancel: "canvas",
     92                                stop: function(e, ui) {
     93                                        me.handle_moved(ui);
     94                                }
     95                        });
     96                        // attach resize handles
     97                        jQuery(this.div).resizable({
     98                      helper: "ui-resizable-helper",
     99                      stop: function(e, ui) {
     100                        me.handle_resized(ui);
     101                      }
     102                    });
     103                        this.d_header = '#head' + String(wid);
     104                        this.d_closebtn = '#close' + String(wid);
     105                        // adjust top offset
     106                        this.topoffset = this.topoffset + parseInt(jQuery(this.d_header).css('height'), 10);
     107                        // assign some interesting callbacks
     108                        jQuery('#head' + String(wid)).click(function() {
     109                                set_focus_cb(wid);
     110                        });
     111                        jQuery('#close' + String(wid)).click(function() {
     112                                window_closed_cb(wid);
     113                        });
     114                }
    178115        }
     116
     117        // need to update the CSS geometry
     118        this.ensure_visible();
     119        this.updateCSSGeometry();
     120        //show("placing new window at "+this.x+","+this.y);
     121
    179122        //create the image holding the pixels (the "backing"):
    180123        this.create_image_backing();
    181         canvas_state.addShape(this);
    182124};
    183125
    184 /**
    185  * Creates the minimize, maximize and close buttons.
    186  */
    187 XpraWindow.prototype.create_buttons = function() {
    188         "use strict";
    189         var w = 24;
    190         var h = 24;
    191         var self = this;
    192         this.buttons["icon"] = new Button(this.state, "icon",           this.borderWidth,       this.borderWidth, w, h, 0x11, null, null);
    193         /*this.buttons["minimize"] = new Button(this.state, "minimize", this.w-(w+2)*3,         this.borderWidth, w, h, 0x44, function() {
    194                 //TODO!
    195         });*/
    196         this.buttons["maximize"] = new Button(this.state, "maximize",   this.w-(w+2)*2,         this.borderWidth, w, h, 0x66, "maximize", function() {
    197                 var m = !self.maximized;
    198                 self.client_properties["maximized"] = m;
    199                 self.set_maximized(m);
    200         });
    201         this.buttons["close"] = new Button(this.state, "close",         this.w-(w+2)*1,         this.borderWidth, w, h, 0x99, "close", function() {
    202                 if (self.window_closed_cb) {
    203                         self.window_closed_cb(self);
    204                 }
    205         });
    206 };
    207 /**
    208  * Ensures that the buttons are always in the same place
    209  * after a resize.
    210  */
    211 XpraWindow.prototype.move_buttons = function() {
    212         var w = 24;
    213         if ("maximize" in this.buttons) {
    214                 this.buttons["maximize"].x = this.w-(w+2)*2;
     126XpraWindow.prototype.ensure_visible = function() {
     127        var oldx = this.x;
     128        var oldy = this.y;
     129        // for now make sure we don't out of top left
     130        // this will be much smarter!
     131        if(oldx <= 0) {
     132                this.x = 0 + this.leftoffset;
    215133        }
    216         if ("close" in this.buttons) {
    217                 this.buttons["close"].x = this.w-(w+2)*1;
     134        if(oldy <= 10) {
     135                this.y = 0 + this.topoffset;
    218136        }
     137        if((oldx != this.x) || (oldy != this.y)) {
     138                this.updateCSSGeometry();
     139                return false;
     140        }
     141        return true;
    219142}
    220143
     144XpraWindow.prototype.updateCSSGeometry = function() {
     145        // set size of canvas if needed
     146        if(this.canvas.width != this.w) {
     147                this.canvas.width = this.w;
     148        }
     149        if(this.canvas.height != this.h) {
     150                this.canvas.height = this.h;
     151        }
     152        // work out outer size
     153        this.outerH = this.h + this.topoffset + this.bottomoffset;
     154        this.outerW = this.w + this.leftoffset + this.rightoffset;
     155        // set width and height
     156        jQuery(this.div).css('width', this.outerW);
     157        jQuery(this.div).css('height', this.outerH);
     158        // set CSS attributes to outerX and outerY
     159        this.outerX = this.x - this.leftoffset;
     160        this.outerY = this.y - this.topoffset;
     161        jQuery(this.div).css('left', this.outerX);
     162        jQuery(this.div).css('top', this.outerY);
     163}
    221164
     165XpraWindow.prototype.updateFocus = function() {
     166        if(this.focused) {
     167                // set focused style to div
     168                jQuery(this.div).addClass("windowinfocus");
     169
     170        } else {
     171                // set not in focus style
     172                jQuery(this.div).removeClass("windowinfocus");
     173        }
     174}
     175
     176XpraWindow.prototype.registerEventListener = function(event_type, useCapture) {
     177        var self = this;
     178        var fn_name = "on_"+event_type;
     179        var handler = self[fn_name];
     180        var fn = function(e) {
     181                handler.call(self, e);
     182        };
     183        this.event_listeners[event_type] = fn;
     184        this.canvas["on"+event_type] = fn;
     185};
     186
     187XpraWindow.prototype.getMouse = function(e) {
     188        "use strict";
     189
     190        // get mouse position take into account scroll
     191        var mx = e.clientX + jQuery(document).scrollLeft();
     192        var my = e.clientY + jQuery(document).scrollTop();
     193
     194        var mbutton = 0;
     195        if ("which" in e)  // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
     196                mbutton = Math.max(0, e.which);
     197        else if ("button" in e)  // IE, Opera (zero based)
     198                mbutton = Math.max(0, e.button)+1;
     199        //show("getmouse: button="+mbutton+", which="+e.which+", button="+e.button);
     200
     201        // We return a simple javascript object (a hash) with x and y defined
     202        return {x: mx, y: my, button: mbutton};
     203};
     204
     205XpraWindow.prototype.on_mousemove = function(e) {
     206        var mouse = this.getMouse(e),
     207                        mx = mouse.x,
     208                        my = mouse.y;
     209
     210                        var modifiers = [];
     211                        var buttons = [];
     212                        this.handle_mouse_move(mx, my, modifiers, buttons);
     213
     214};
     215
     216XpraWindow.prototype.on_mousedown = function(e) {
     217        var mouse, mx, my, shapes, l, i, mySel;
     218
     219        mouse = this.getMouse(e);
     220        mx = mouse.x;
     221        my = mouse.y;
     222
     223        // pass the click to the area:
     224        var modifiers = [];
     225        var buttons = [];
     226        this.handle_mouse_click(mouse.button, true, mx, my, modifiers, buttons);
     227        return;
     228};
     229
     230XpraWindow.prototype.on_mouseup = function(e) {
     231        // if not handling it ourselves, pass it down:
     232        var mouse = this.getMouse(e),
     233                        mx = mouse.x,
     234                        my = mouse.y;
     235        if (!this.dragging) {
     236                var modifiers = [];
     237                var buttons = [];
     238                this.handle_mouse_click(mouse.button, false, mx, my, modifiers, buttons);
     239        }
     240
     241        this.dragging = false;
     242};
     243
    222244/**
    223245 * toString allows us to identify windows by their unique window id.
    224246 */
     
    235257        var previous_image = this.image;
    236258        var img_geom = this.get_internal_geometry();
    237259        //show("createImageData: "+img_geom.toSource());
    238         this.image = canvas_state.canvas.getContext('2d').createImageData(img_geom.w, img_geom.h);
     260        this.image = this.canvas.getContext('2d').createImageData(img_geom.w, img_geom.h);
    239261        if (previous_image) {
    240262                //copy previous pixels to new image, ignoring bit gravity
    241                 //TODO!
     263                this.canvas.getContext('2d').putImageData(previous_image, 0, 0);
    242264        }
    243265};
    244266
    245267/**
    246  * Depending on the type of window (OR, fullscreen)
    247  * we calculate the offsets from the edge of the window
    248  * to the contents of the window.
    249  */
    250 XpraWindow.prototype.calculate_offsets = function() {
    251         "use strict";
    252         if (this.override_redirect || this.fullscreen) {
    253                 //no borders or top bar at all:
    254                 this.borderWidth = 0;
    255                 this.topBarHeight = 0;
    256         }
    257         else {
    258                 //regular borders and top bar:
    259                 this.borderWidth = 2;
    260                 this.topBarHeight = 24;
    261         }
    262         this.offsets = [this.borderWidth+this.topBarHeight, this.borderWidth, this.borderWidth, this.borderWidth];
    263 };
    264 
    265 /**
    266268 * Update our metadata cache with new key-values,
    267269 * then call set_metadata with these new key-values.
    268270 */
     
    288290    }
    289291    if ("title" in metadata) {
    290292        this.title = metadata["title"];
    291         //redraw everything (a bit wasteful):
    292         this.state.invalidate();
     293        jQuery('#title' + this.wid).html(this.title);
    293294    }
     295    if ("window-type" in metadata) {
     296        this.windowtype = metadata["window-type"][0];
     297    }
    294298};
    295299
    296300/**
     
    299303 */
    300304XpraWindow.prototype.save_geometry = function() {
    301305        "use strict";
     306        /*
     307
     308        TODO
     309
     310        * probably won't need to do this just use CSS to display: none;
     311        * see restore_geometry
     312
    302313        if (this.x==undefined || this.y==undefined)
    303314                return;
    304315    this.saved_geometry = {
     
    308319                "h" : this.h,
    309320                "maximized"     : this.maximized,
    310321                "fullscreen" : this.fullscreen};
     322    */
    311323}
    312324/**
    313325 * Restores the saved geometry (if it exists).
    314326 */
    315327XpraWindow.prototype.restore_geometry = function() {
    316328        "use strict";
     329        /*
     330
     331        TODO
     332
     333        * we probably won't need to do this since we can just change CSS to
     334        * display: none; to hide it!
     335
    317336        if (this.saved_geometry==null) {
    318337                return;
    319338        }
     
    323342        this.h = this.saved_geometry["h"];
    324343        this.maximized = this.saved_geometry["maximized"];
    325344        this.fullscreen = this.saved_geometry["fullscreen"];
     345        */
    326346};
    327347
    328348/**
     
    330350 */
    331351XpraWindow.prototype.set_maximized = function(maximized) {
    332352        "use strict";
     353        /*
     354
     355        TODO
     356
    333357        //show("set_maximized("+maximized+")");
    334358        if (this.maximized==maximized) {
    335359                return;
     
    338362        this.maximized = maximized;
    339363        this.calculate_offsets();
    340364        this.handle_resize();
     365        */
    341366};
    342367/**
    343368 * Fullscreen / unfullscreen the window.
    344369 */
    345370XpraWindow.prototype.set_fullscreen = function(fullscreen) {
    346371        "use strict";
     372        /*
     373
     374        TODO
     375
    347376        //show("set_fullscreen("+fullscreen+")");
    348377        if (this.fullscreen==fullscreen) {
    349378                return;
     
    352381        this.fullscreen = fullscreen;
    353382        this.calculate_offsets();
    354383        this.handle_resize();
     384        */
    355385};
    356386
    357387/**
     
    361391 */
    362392XpraWindow.prototype.max_save_restore = function(use_all_space) {
    363393        "use strict";
     394        /*
     395
     396        TODO
     397
     398        * again see save|restore_geometry
     399
    364400        if (use_all_space) {
    365401                this.save_geometry();
    366402                this.fill_canvas();
     
    368404        else {
    369405                this.restore_geometry();
    370406        }
     407        */
    371408};
    372409
    373410/**
     
    375412 */
    376413XpraWindow.prototype.fill_canvas = function() {
    377414        "use strict";
     415        /*
     416
     417        TODO
     418
    378419        this.x = 0;
    379420        this.y = 0;
    380         this.w = this.state.width;
    381         this.h = this.state.height;
     421        this.w = 640;
     422        this.h = 480;
     423        */
    382424};
    383425
    384426/**
    385427 * We have resized the window, so we need to:
     428 * - work out new position of internal canvas
     429 * - update external CSS position
    386430 * - resize the backing image
    387  * - tell the canvas to repaint us
    388431 * - fire the geometry_cb
    389432 */
    390 XpraWindow.prototype.handle_resize = function() {
     433XpraWindow.prototype.handle_resized = function(e) {
    391434        "use strict";
     435        // this function is called on local resize only,
     436        // remote resize will call this.resize()
     437        // need to update the internal geometry
     438        this.w = e.size.width - this.leftoffset - this.rightoffset;
     439        this.h = e.size.height - this.topoffset - this.bottomoffset;
     440        // then update CSS and redraw backing
     441        this.updateCSSGeometry();
    392442        this.create_image_backing();
    393         this.state.invalidate();
    394         this.move_buttons();
    395         if (this.geometry_cb!=null) {
    396                 this.geometry_cb(this);
    397         }
     443        // send geometry callback
     444        this.geometry_cb(this);
    398445};
    399446
    400447/**
     448 * Like handle_resized, except we should
     449 * store internal geometry, external is always in CSS left and top
     450 */
     451XpraWindow.prototype.handle_moved = function(e) {
     452        "use strict";
     453        // add on padding to the event position so that
     454        // it reflects the internal geometry of the canvas
     455        this.x = e.position.left + this.leftoffset;
     456        this.y = e.position.top + this.topoffset;
     457        // make sure we are visible after move
     458        this.ensure_visible();
     459        // tell remote we have moved window
     460        this.geometry_cb(this);
     461}
     462
     463/**
    401464 * The canvas ("screen") has been resized, we may need to resize our window to match
    402465 * if it is fullscreen or maximized.
    403466 */
    404467XpraWindow.prototype.canvas_resized = function() {
    405468        "use strict";
     469        /*
     470
     471        TODO
     472
    406473        if (this.fullscreen || this.maximized) {
    407474                this.fill_canvas();
    408475                this.handle_resize();
    409476        }
     477        */
    410478};
    411479
    412 XpraWindow.prototype.move_resize = Shape.prototype.move_resize;
    413 XpraWindow.prototype.move = Shape.prototype.move;
    414 XpraWindow.prototype.resize = Shape.prototype.resize;
    415 XpraWindow.prototype.get_window_geometry = Shape.prototype.get_window_geometry;
     480/**
     481 * Things ported from original shape
     482 */
    416483
     484XpraWindow.prototype.move_resize = function(x, y, w, h) {
     485        "use strict";
     486        // only do it if actually changed!
     487        if(!(this.w == w) || !(this.h == h) || !(this.x == x) || !(this.y == y)) {
     488                this.w = w;
     489                this.h = h;
     490                this.x = x;
     491                this.y = y;
     492                if(!this.ensure_visible()) {
     493                        // we had to move the window so that it was visible
     494                        // is this the right thing to do?
     495                        this.geometry_cb(this);
     496                }
     497                this.updateCSSGeometry();
     498                this.create_image_backing();
     499        }
     500};
     501
     502XpraWindow.prototype.move = function(x, y) {
     503        "use strict";
     504        this.move_resize(x, y, this.w, this.h);
     505};
     506
     507XpraWindow.prototype.resize = function(w, h) {
     508        "use strict";
     509        this.move_resize(this.x, this.y, w, h);
     510};
     511
    417512/**
    418513 * Returns the geometry of the window backing image,
    419514 * the inner window geometry (without any borders or top bar).
    420515 */
    421 XpraWindow.prototype.get_internal_geometry = function(ctx) {
     516XpraWindow.prototype.get_internal_geometry = function() {
    422517        "use strict";
    423         // This should always be true:
    424         //this.image.width = this.w - this.borderWidth*2;
    425         //this.image.height = this.h - (this.borderWidth*2 + this.topBarHeight);
    426         return { x : this.x+this.borderWidth,
    427                          y : this.y+this.borderWidth+this.topBarHeight,
    428                          w : this.w - this.borderWidth*2,
    429                          h : this.h - (this.borderWidth*2 + this.topBarHeight)};
     518        /* we store the internal geometry only
     519         * and work out external geometry on the fly whilst
     520         * updating CSS
     521         */
     522        return { x : this.x,
     523                         y : this.y,
     524                         w : this.w,
     525                         h : this.h};
    430526};
    431527
    432528/**
    433  * If the click is in the "internal_geometry" (see above),
     529 * Handle mouse click from this window's canvas,
    434530 * then we fire "mouse_click_cb" (if it is set).
    435531 */
    436532XpraWindow.prototype.handle_mouse_click = function(button, pressed, mx, my, modifiers, buttons) {
    437533        "use strict";
    438         var igeom = this.get_internal_geometry();
    439         if (this.mouse_click_cb!=null && rectangle_contains(igeom, mx, my)) {
    440                 this.mouse_click_cb(this, button, pressed, mx, my, modifiers, buttons);
    441                 return;
    442         }
    443         //maybe one of the buttons:
    444         //(use relative coordinates)
    445         var x = mx-this.x;
    446         var y = my-this.y
    447         for (var name in this.buttons) {
    448                 var button = this.buttons[name];
    449                 if (button.contains(x, y)) {
    450                         show("clicked on button "+name);
    451                         var cb = button.click_callback;
    452                         if (cb) {
    453                                 cb();
    454                         }
    455                         return;
    456                 }
    457         }
     534        console.log("got mouse click at ", mx, my)
     535        // mouse click event is from canvas just for this window so no need to check
     536        // internal geometry anymore
     537        this.mouse_click_cb(this, button, pressed, mx, my, modifiers, buttons);
    458538};
    459539
    460540/**
    461  * If the click is in the "internal_geometry" (see above),
     541 * Handle mouse move from this window's canvas,
    462542 * then we fire "mouse_move_cb" (if it is set).
    463543 */
    464544XpraWindow.prototype.handle_mouse_move = function(mx, my, modifiers, buttons) {
    465545        "use strict";
    466         var igeom = this.get_internal_geometry();
    467         if (this.mouse_move_cb!=null && rectangle_contains(igeom, mx, my)) {
    468                 this.mouse_move_cb(this, mx, my, modifiers, buttons);
    469         }
     546        this.mouse_move_cb(this, mx, my, modifiers, buttons);
    470547};
    471548
    472549
    473550XpraWindow.prototype.update_icon = function(w, h, pixel_format, data) {
    474551        "use strict";
    475         var icon = this.buttons["icon"];
    476         if (icon) {
    477                 icon.update_image(w, h, pixel_format, data);
    478                 this.state.invalidate();
    479         }
     552        // update icon
     553        // TODO
    480554}
    481555
    482556/**
     
    487561 */
    488562XpraWindow.prototype.draw = function(ctx) {
    489563        "use strict";
    490 
    491         if (!this.override_redirect && !this.fullscreen) {
    492                 //draw window frame:
    493                 this.draw_frame(ctx);
    494         }
    495 
    496564        //draw the window pixels:
    497         ctx.putImageData(this.image, this.x + this.borderWidth, this.y + this.borderWidth + this.topBarHeight);
    498 
    499         if (this.state.selection === this && !this.override_redirect) {
    500                 //window.alert("Shape.prototype.draw_selection="+Shape.prototype.draw_selection);
    501                 this.draw_selection(ctx);
    502         }
     565        var ctx = this.canvas.getContext('2d');
     566        ctx.putImageData(this.image, 0, 0);
    503567};
    504568
    505 /**
    506  * Draws the window frame:
    507  * a simple rectangle around the edge.
    508  */
    509 XpraWindow.prototype.draw_frame = function(ctx) {
    510         "use strict";
    511569
    512         // draw border:
    513         ctx.strokeStyle = this.borderColor;
    514         ctx.lineWidth = this.borderWidth;
    515         var hw = this.borderWidth/2;
    516         ctx.strokeRect(this.x+hw,this.y+hw,this.w-this.borderWidth,this.h-this.borderWidth);
    517 
    518         // draw top bar:
    519         ctx.fillStyle = this.topBarColor;
    520         ctx.fillRect(this.x+this.borderWidth, this.y+this.borderWidth, this.w-this.borderWidth*2, this.topBarHeight);
    521         // draw title:
    522         if (this.title) {
    523                 var size = 18;
    524                 ctx.font = ""+size+"px sans-serif";
    525                 ctx.fillStyle = "#FFFFFF";
    526                 ctx.fillText(this.title, this.x+32, this.y+this.borderWidth+this.topBarHeight-size/3);
    527         }
    528 
    529         // draw buttons:
    530         for (var name in this.buttons) {
    531                 var button = this.buttons[name];
    532                 button.draw_at(ctx, this.x, this.y);
    533         }
    534 };
    535 
    536 
    537570/**
    538  * Draws border and selection rectangles
    539  * which indicate that the window is selected
    540  */
    541 XpraWindow.prototype.draw_selection = function(ctx) {
    542         "use strict";
    543         if (this.maximized || this.fullscreen) {
    544                 return;
    545         }
    546         var i, cur, half;
    547 
    548         ctx.strokeStyle = this.state.selectionColor;
    549         ctx.lineWidth = this.state.selectionWidth;
    550         ctx.strokeRect(this.x,this.y,this.w,this.h);
    551 
    552         // draw the boxes
    553         half = this.state.selectionBoxSize / 2;
    554 
    555         // 0  1  2
    556         // 3     4
    557         // 5  6  7
    558 
    559         // top left, middle, right
    560         this.state.selectionHandles[0].x = this.x-half;
    561         this.state.selectionHandles[0].y = this.y-half;
    562 
    563         this.state.selectionHandles[1].x = this.x+this.w/2-half;
    564         this.state.selectionHandles[1].y = this.y-half;
    565 
    566         this.state.selectionHandles[2].x = this.x+this.w-half;
    567         this.state.selectionHandles[2].y = this.y-half;
    568 
    569         //middle left
    570         this.state.selectionHandles[3].x = this.x-half;
    571         this.state.selectionHandles[3].y = this.y+this.h/2-half;
    572 
    573         //middle right
    574         this.state.selectionHandles[4].x = this.x+this.w-half;
    575         this.state.selectionHandles[4].y = this.y+this.h/2-half;
    576 
    577         //bottom left, middle, right
    578         this.state.selectionHandles[6].x = this.x+this.w/2-half;
    579         this.state.selectionHandles[6].y = this.y+this.h-half;
    580 
    581         this.state.selectionHandles[5].x = this.x-half;
    582         this.state.selectionHandles[5].y = this.y+this.h-half;
    583 
    584         this.state.selectionHandles[7].x = this.x+this.w-half;
    585         this.state.selectionHandles[7].y = this.y+this.h-half;
    586 
    587         ctx.fillStyle = this.state.selectionBoxColor;
    588         for (i = 0; i < 8; i += 1) {
    589                 cur = this.state.selectionHandles[i];
    590                 ctx.fillRect(cur.x, cur.y, this.state.selectionBoxSize, this.state.selectionBoxSize);
    591         }
    592 };
    593 
    594 /**
    595571 * Updates the window image with new pixel data
    596572 * we have received from the server.
    597573 */
     
    625601        var stride = this.image.width*4;
    626602        //and we can paint the canvas with it
    627603        //(if we have transparency, we should probably repaint what is underneath...)
    628         var ctx = this.state.ctx;
     604        var ctx = this.canvas.getContext('2d');
    629605
    630606        if (x==0 && width==this.image.width && y+height<=this.image.height) {
    631607                //take a shortcut: copy all lines
     
    633609
    634610                if (this.focused) {
    635611                        //shortcut: paint canvas directly
    636                         ctx.putImageData(this.image, this.x + this.borderWidth, this.y + this.borderWidth + this.topBarHeight);
     612                        ctx.putImageData(this.image, 0, 0);
    637613                        return;
     614                } else {
     615                        // window is not in focus but should we draw it anyway?
     616                        ctx.putImageData(this.image, 0, 0);
     617                        return;
    638618                }
    639619        }
    640620        else if (x+width<=this.image.width && y+height<=this.image.height) {
     
    650630
    651631                if (this.focused) {
    652632                        //shortcut: paint canvas directly
    653                         ctx.putImageData(img, this.x + this.borderWidth + x, this.y + this.borderWidth + this.topBarHeight + y);
     633                        ctx.putImageData(img, x, y);
    654634                        return;
     635                } else {
     636                        // window is not in focus but should we draw it anyway?
     637                        ctx.putImageData(img, x, y);
     638                        return;
    655639                }
    656640        }
    657641        else {
    658642                //no action taken, no need to invalidate
    659643                return;
    660644        }
    661         this.state.invalidate();
     645        //this.state.invalidate();
    662646};
    663647
    664648/**
     
    666650 */
    667651XpraWindow.prototype.destroy = function destroy() {
    668652        "use strict";
    669         if (this.state!=null) {
    670                 this.state.removeShape(this);
    671                 this.state = null;
    672         }
     653        // remove div
     654        this.div.remove()
    673655};
    674 
    675 /**
    676  * Determine if a point is inside the window's contents
    677  */
    678 XpraWindow.prototype.contains = function(mx, my) {
    679         "use strict";
    680         // All we have to do is make sure the Mouse X,Y fall in the area between
    681         // the shape's X and (X + Height) and its Y and (Y + Height)
    682         return  (this.x <= mx) && (this.x + this.w >= mx) &&
    683                                         (this.y <= my) && (this.y + this.h >= my);
    684 };
    685 
    686 /**
    687  * Determine if a point is inside the window's grab area.
    688  * (the edges that are not part of the image backing)
    689  */
    690 XpraWindow.prototype.is_grab_area = function(mx, my) {
    691         "use strict";
    692         if (!this.contains(mx, my)) {
    693                 return false;
    694         }
    695         // use window relative values from here on:
    696         var x = mx - this.x;
    697         var y = my - this.y;
    698 
    699         // must be in the border area:
    700         if (!(y<=this.offsets[0] || my>=(this.h-this.offsets[2]) ||
    701                         x<=this.offsets[3] || x>=(this.w-this.offsets[1]))) {
    702                 return false;
    703         }
    704 
    705         // check that this isn't one of the buttons:
    706         for (var name in this.buttons) {
    707                 var button = this.buttons[name];
    708                 if (button.contains(x, y)) {
    709                         return false;
    710                 }
    711         }
    712         return true;
    713 };
  • html5/include/util.js

     
    44 */
    55
    66
     7
    78/**
    89 * Adds window.location.getParameter to those browsers that don't have it:
    910 *
  • html5/index.html

     
    1919                            width: 100%;
    2020                            padding: 0;
    2121                            margin: 0;
    22                             color: white;
     22                            overflow: hidden;
    2323                        }
    24                         div.form {
    25                                 background-color: #708090;
    26                                 border: 4px solid #506070;
    27                                 box-sizing: border-box;
    28                         }
    2924                        div#disconnect_form {
    3025                                display: none;
    3126                        }
    32                         fieldset {
    33                                 margin: 0px;
    34                                 border: 0px solid black;
    35                         }
    3627                        canvas {
    37                                 border: 0px solid black;
    38                                 display: none;
     28                                border: none;
     29                                padding: 0;
     30                                margin: 0;
    3931                        }
     32                        .window {
     33                                border: 1px;
     34                                position: absolute;
     35                                box-shadow: 0px 10px 25px rgba(0, 0, 0, 0.5);
     36                                padding: 0;
     37                                overflow: hidden; /* required for radius clip */
     38                        }
     39                        .window-NORMAL {
     40                                border-radius: 6px;
     41                        }
     42                        .window-DROPDOWN_MENU {
     43                                z-index: 20000;
     44                        }
     45                        .window-TOOLTIP {
     46                                z-index: 20000;
     47                        }
     48                        .window-POPUP_MENU {
     49                                z-index: 20000;
     50                        }
     51                        .window-COMBO {
     52                                z-index: 20000;
     53                        }
     54                        .window-UTILITY {
     55                                z-index: 15000;
     56                        }
     57                        .windowhead {
     58                                height: 30px;
     59                                color: #000000;
     60                                background-color: #c0c0c0;
     61                        }
     62                        .windowtitle {
     63                                display: inline-block;
     64                                float: left;
     65                                width: 80%;
     66                                overflow: hidden;
     67                                text-overflow:ellipsis;
     68                                white-space: nowrap;
     69                                padding: 5px;
     70                                cursor: default;
     71                        }
     72                        .windowbuttons {
     73                            display: inline-block;
     74                            float: right;
     75                            padding-right: 5px;
     76                            cursor: pointer;
     77                            padding-top: 7px;
     78                        }
     79                        .windowinfocus {
     80                                z-index: 10000;
     81                        }
     82                        .ui-resizable-helper {
     83                                border: 2px dotted #00F;
     84                                z-index: 30000 !important;
     85                        }
     86                        .ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
     87                        .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
     88                        .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
     89                        .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
     90                        .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
     91                        .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
     92                        .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
     93                        .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
     94                        .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
     95                        .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
    4096                </style>
    4197
     98                <script type="text/javascript" src="include/util.js"></script>
    4299                <script type="text/javascript" src="include/websock.js"></script>
    43100                <script type="text/javascript" src="include/bencode.js"></script>
    44101                <script type="text/javascript" src="include/inflate.min.js"></script>
    45102                <script type="text/javascript" src="include/protocol.js"></script>
    46103                <script type="text/javascript" src="include/keycodes.js"></script>
    47                 <script type="text/javascript" src="include/shapes.js"></script>
    48104                <script type="text/javascript" src="include/window.js"></script>
    49                 <script type="text/javascript" src="include/util.js"></script>
     105                <script type="text/javascript" src="include/jquery.min.js"></script>
     106                <script type="text/javascript" src="include/jqueryui.min.js"></script>
    50107
    51108                <script>
    52109                        var protocol;
    53110                        var status = "ready";
    54111
     112                        var topwindow = null;
     113                        var topindex = 0;
     114
    55115                        var id_to_window = {};
    56116                        var window_to_id = {};
    57117                        var focus = -1;
    58118                        var screen_size_change_pending = false;
    59119
     120                        // from http://stackoverflow.com/a/11744120
     121                        var w = window,
     122                            d = document,
     123                            e = d.documentElement,
     124                            g = d.getElementsByTagName('body')[0];
     125
     126                        var screen_width = w.innerWidth || e.clientWidth || g.clientWidth;
     127                        var screen_height = w.innerHeight|| e.clientHeight|| g.clientHeight;
     128
    60129                        var OLD_ENCODING_NAMES_TO_NEW = {"x264" : "h264", "vpx" : "vp8"};
    61130                        var RGB_FORMATS = ["RGBX", "RGBA"];
    62                         var canvas_state = null;
    63131
    64132                        var caps_lock = null;
    65133                        var alt_modifier = null;
    66134                        var meta_modifier = null;
    67135
     136                        // disable right click menu:
     137                        window.oncontextmenu = function(e) {
     138                                //showCustomMenu();
     139                                return false;
     140                        }
     141
    68142                        /**
    69143                         * Returns the modifiers set for the current event.
    70144                         * We get the list of modifiers using "get_event_modifiers"
     
    95169                         */
    96170                        function processKeyEvent(pressed, event) {
    97171                                "use strict";
    98                                 if (canvas_state==null)
    99                                         return;
    100172                                // MSIE hack
    101173                                if (window.event)
    102174                                        event = window.event;
     
    125197                                if ((caps_lock && shift) || (!caps_lock && !shift))
    126198                                        str = str.toLowerCase();
    127199
    128                                 var win = canvas_state.topOfStack();
    129                                 if (win != null) {
     200                                //var win = canvas_state.topOfStack();
     201                                if (topwindow != null) {
    130202                                        //show("win="+win.toSource()+", keycode="+keycode+", modifiers=["+modifiers+"], str="+str);
    131                                         var wid = window_to_id[win];
    132                                         var packet = ["key-action", wid, keyname, pressed, modifiers, keyval, str, keycode, group];
     203                                        var packet = ["key-action", topwindow, keyname, pressed, modifiers, keyval, str, keycode, group];
    133204                                        send(packet);
    134205                                }
    135206                        }
     
    256327                        //These are callbacks from XpraWindow to us
    257328                        //to notify us of window clicks and events:
    258329
    259                         function window_closed(win) {
     330                        function window_closed(wid) {
    260331                                "use strict";
    261                                 var wid = window_to_id[win];
     332                                //var wid = window_to_id[win];
    262333                                send(["close-window", wid]);
    263334                        }
    264335                        function window_geometry_changed(win) {
    265336                                "use strict";
    266                                 //show("window_geometry_changed("+win+") geometry="+win.get_window_geometry().toSource());
     337                                show("geometry changed");
     338                                //show("window_geometry_changed="+win.get_window_geometry().toSource());
    267339                                var geom = win.get_internal_geometry();
    268                                 var wid = window_to_id[win];
     340                                var wid = win.wid;
    269341                                if (!win.override_redirect)
    270342                                        self.set_focus(wid);
    271343                                send(["configure-window", wid, geom.x, geom.y, geom.w, geom.h, get_client_properties(win)]);
     
    278350                        function mouse_click(win, button, pressed, x, y, modifiers, buttons) {
    279351                                "use strict";
    280352                                var wid = window_to_id[win];
    281                                 //show("mouse_click(..) wid("+win+")="+wid);
    282                                 check_focus();
     353                                set_focus(wid);
    283354                                send(["button-action", wid, button, pressed, [x, y], modifiers, buttons]);
    284355                        };
    285356
    286357                        function check_focus() {
    287358                                "use strict";
    288359                                var wid = -1;
    289                                 var win = canvas_state.topOfStack();
    290360                                if (win != null)
    291361                                        wid = window_to_id[win];
    292362                                //show("check_focus() window_to_id["+win+"]="+wid+", focus="+wid+", window_to_id="+window_to_id.toSource());
     
    298368                                "use strict";
    299369                                focus = wid;
    300370                                send(["focus", focus, []]);
     371                                topwindow = wid;
    301372                                //set the focused flag on all windows:
    302373                var win;
    303374                                for (var i in id_to_window) {
    304375                                        win = id_to_window[i];
    305376                                        win.focused = (i==wid);
     377                                        win.updateFocus();
    306378                                }
    307379                        }
    308380
     381                        function refresh_window(wid) {
     382                                "use strict";
     383                                // refresh the window
     384                                show("send buffer-refresh");
     385                                send(['buffer-refresh', wid, true, 95]);
     386                        }
     387
    309388                        function get_client_properties(win) {
    310389                                "use strict";
    311390                                var cp = win.client_properties;
     
    315394
    316395                        function make_new_window(wid, x, y, w, h, metadata, override_redirect, client_properties) {
    317396                                "use strict";
    318                                 var win = new XpraWindow(canvas_state, wid, x, y, w, h, metadata, override_redirect, client_properties,
    319                                                 window_geometry_changed, mouse_move, mouse_click, window_closed);
    320                                 //show("make_new_window("+wid+", "+x+", "+y+", "+w+", "+h+", "+metadata+", "+override_redirect+", "+client_properties+")="+win);
     397                                // each window needs their own DIV that contains a canvas
     398                                var mydiv = document.createElement("div");
     399                                mydiv.id = String(wid);
     400                                var mycanvas = document.createElement("canvas");
     401                                mydiv.appendChild(mycanvas);
     402                                document.body.appendChild(mydiv);
     403                                // set initial sizes
     404                                mycanvas.width = w;
     405                                mycanvas.height = h;
     406                                // create the XpraWindow object to own the new div
     407                                var win = new XpraWindow(mycanvas, wid, x, y, w, h, metadata, override_redirect, client_properties,
     408                                                window_geometry_changed, mouse_move, mouse_click, set_focus, window_closed);
    321409                                id_to_window[wid] = win;
    322410                                window_to_id[win] = wid;
    323411                                var geom = win.get_internal_geometry();
     
    414502                                var win = id_to_window[wid];
    415503                                if (win!=null) {
    416504                                        win.destroy();
    417                                         check_focus();
    418505                                }
    419506                        }
    420507
     
    423510                                var wid = packet[1];
    424511                                var win = id_to_window[wid];
    425512                                if (win!=null) {
    426                                         canvas_state.raiseShape(win);
    427                                         focus = wid;
    428                                         check_focus();
     513                                        set_focus(wid);
    429514                                }
    430515                        }
    431516
    432517                        function process_window_resized(packet) {
    433                                 //TODO
     518                                var wid = packet[1];
     519                                var width = packet[2];
     520                                var height = packet[3];
     521                                var win = id_to_window[wid];
     522                                if (win!=null) {
     523                                        win.resize(width, height);
     524                                }
    434525                        }
     526
    435527                        function process_new_tray(packet) {
    436528                                //TODO
    437529                        }
     
    462554                                return 96;
    463555                        }
    464556
    465 
    466557                        function get_desktop_size() {
    467558                                "use strict";
    468                                 var canvas = document.getElementById('screen');
    469                                 return [canvas.width, canvas.height];
     559                                return [screen_width, screen_height];
    470560                        }
    471561                        function get_screen_sizes() {
    472562                                "use strict";
    473                                 var canvas = document.getElementById('screen');
    474563                                var dpi = get_DPI();
    475564                                /*
    476565                                equivallent GTK code:
     
    482571                                                monitors,
    483572                                                work_x, work_y, work_width, work_height)
    484573                                */
    485                                 var wmm = Math.round(canvas.width*25.4/dpi);
    486                                 var hmm = Math.round(canvas.height*25.4/dpi);
    487                                 var monitor = ["Canvas", 0, 0, canvas.width, canvas.height, wmm, hmm];
    488                                 var screen = ["HTML", canvas.width, canvas.height,
     574                                var wmm = Math.round(screen_width*25.4/dpi);
     575                                var hmm = Math.round(screen_height*25.4/dpi);
     576                                var monitor = ["Canvas", 0, 0, screen_width, screen_height, wmm, hmm];
     577                                var screen = ["HTML", screen_width, screen_height,
    489578                                                        wmm, hmm,
    490579                                                        [monitor],
    491                                                         0, 0, canvas.width, canvas.height
     580                                                        0, 0, screen_width, screen_height
    492581                                                ];
    493582                                //just a single screen:
    494583                                return [screen];
     
    510599                        function make_hello() {
    511600                                "use strict";
    512601                                return  {
    513                                                 "version"                                       : "0.14.0",
     602                                                "version"                                       : "0.11.0",
    514603                                                "platform"                                      : guess_platform(),
    515604                                                "platform.name"                         : guess_platform_name(),
    516605                                                "platform.processor"            : guess_platform_processor(),
     
    593682
    594683                        function do_send_new_screen_size() {
    595684                                //show("do_send_new_screen_size()");
    596                                 if (protocol==null || canvas_state==null)
    597                                         return;
    598685                                screen_size_change_pending = false;
    599686                                var ds = get_desktop_size();
    600687                                var ss = get_screen_sizes();
     
    607694                                }
    608695                        }
    609696
    610                         function onresize() {
    611                                 var container = document.getElementById('screen_container');
    612                                 var d_form = document.getElementById('disconnect_form');
    613                                 var c_form = document.getElementById('connect_form');
    614                                 /*show("onresize() container size: "+container.clientWidth+"x"+container.clientHeight+
    615                                                                 ", window size: "+window.innerWidth+"x"+window.innerHeight+
    616                                                                 ", d form size: "+d_form.offsetWidth+"x"+d_form.offsetHeight+
    617                                                                 ", c form size: "+c_form.offsetWidth+"x"+c_form.offsetHeight);*/
    618                                 if (canvas_state!=null) {
    619                                         var width = Math.min(container.clientWidth, window.innerWidth);
    620                                         var height = Math.max(0, window.innerHeight-d_form.offsetHeight-c_form.offsetHeight);
    621                                         canvas_state.canvas.width = width;
    622                                         canvas_state.canvas.height = height;
    623                                         canvas_state.width = width;
    624                                         canvas_state.height = height;
    625                                         canvas_state.invalidate();
    626                                 }
    627                                 send_new_screen_size();
    628                         }
    629 
    630697                        function do_start(params) {
    631698                                "use strict";
    632699                                show("start()");
    633                                 onresize();
    634700
    635701                                //hook document and window events:
    636702                                document.onkeydown = onkeydown;
    637703                                document.onkeyup = onkeyup;
    638704                                document.onkeypress = onkeypress;
    639                                 window.addEventListener("resize", onresize, false);
    640 
    641                                 var canvas = document.getElementById('screen');
    642                                 canvas.style.display = "block";
    643 
    644                                 if (canvas_state==null)
    645                                         canvas_state = new CanvasState(canvas);
    646705                                protocol = new Protocol();
    647706                                protocol.set_packet_handler("open", process_open);
    648707                                protocol.set_packet_handler("close", process_close);
     
    657716                                        show("opening connection to "+uri);
    658717                                        set_ui_message("connecting to "+uri);
    659718                                        protocol.open(uri);
     719                                        // dismiss connection dialog
     720                                        $('#connectModal').modal('hide');
    660721                                }
    661722                                catch (e) {
    662723                                        set_ui_message("error connecting to "+uri+": "+e, "red");
     
    672733                                document.onkeydown = null;
    673734                                document.onkeyup = null;
    674735                                document.onkeypress = null;
    675                                 window.removeEventListener("resize", onresize);
    676736                                if (protocol!=null) {
    677737                                        protocol.close();
    678738                                        protocol = null;
    679739                                }
    680                                 if (canvas_state!=null) {
    681                                         canvas_state.destroy();
    682                                         canvas_state = null;
    683                                 }
     740
    684741                                document.getElementById('connect_form').style.display = "block";
    685742                                document.getElementById('disconnect_form').style.display = "none";
    686743
    687                                 var canvas = document.getElementById('screen');
    688                                 canvas.style.display = "none";
    689744                                status = "ready";
    690745                        }
    691746
     
    714769                                        document.getElementById('disconnect_form').style.display = "block";
    715770                                else
    716771                                        document.getElementById('disconnect_form').style.display = "none";
    717                                 onresize();
    718772                                set_ui_message("");
    719773
    720774                                show("connected to server - sending hello");
     
    746800                                send(["hello", hello]);
    747801                        }
    748802
     803                        function pass() {
     804
     805                        }
     806
    749807                        function force_refresh() {
    750808                                "use strict";
    751809                                if (protocol!=null) {
     
    848906                                        else
    849907                                                do_start(params);
    850908                                }
     909
     910                                $('#connectModal').modal('show');
    851911                        }
    852912                </script>
    853913        </head>
    854914
    855915        <body onload="init()">
    856                 <div class="form" id="connect_form">
    857                         <form onsubmit="return false;">
    858                                 <fieldset>
    859                                         <table>
    860                                                 <tr>
    861                                                         <th>Host</th>
    862                                                         <td><input id="host" type="text" size="30" maxlength="60" value="" /></td>
    863                                                         <td rowspan="3">
    864                                                                 <span id="message"></span>
    865                                                         </td>
    866                                                 </tr>
    867                                                 <tr>
    868                                                         <th>Port</th>
    869                                                         <td><input id="port" type="text" size="5" maxlength="5" value="" /></td>
    870                                                 </tr>
    871                                                 <tr>
    872                                                         <th>SSL</th>
    873                                                         <td><input id="ssl" type="checkbox" /></td>
    874                                                 </tr>
    875                                                 <tr>
    876                                                         <th>Runtime Dialog</th>
    877                                                         <td><input id="options" type="checkbox" /></td>
    878                                                 </tr>
    879                                         </table>
    880                                         <button id="connect" value="true" onclick="start();">Connect</button>
    881                                         <button id="popup" value="true" onclick="new_popup();">Popup</button>
    882                                 </fieldset>
    883                         </form>
    884                 </div>
     916
     917                        <div class="form" id="connect_form">
     918                                        <form onsubmit="return false;">
     919                                                <fieldset>
     920                                                        <table>
     921                                                                <tr>
     922                                                                        <th>Host</th>
     923                                                                        <td><input id="host" type="text" size="30" maxlength="60" value="" /></td>
     924                                                                        <td rowspan="3">
     925                                                                                <span id="message"></span>
     926                                                                        </td>
     927                                                                </tr>
     928                                                                <tr>
     929                                                                        <th>Port</th>
     930                                                                        <td><input id="port" type="text" size="5" maxlength="5" value="" /></td>
     931                                                                </tr>
     932                                                                <tr>
     933                                                                        <th>SSL</th>
     934                                                                        <td><input id="ssl" type="checkbox" /></td>
     935                                                                </tr>
     936                                                                <tr>
     937                                                                        <th>Runtime Dialog</th>
     938                                                                        <td><input id="options" type="checkbox" /></td>
     939                                                                </tr>
     940                                                        </table>
     941                                                </fieldset>
     942                                                <button id="connect" value="true" class="btn btn-primary" onclick="start();">Connect</button>
     943                                </form>
     944                                </div>
     945                      </div>
     946
    885947                <div class="form" id="disconnect_form">
    886948                        <form onsubmit="return false;">
    887949                                <fieldset>
     
    891953                                </fieldset>
    892954                        </form>
    893955                </div>
    894                 <div id="screen_container">
    895                         <canvas id="screen" width="800" height="600"></canvas>
    896                 </div>
    897956                <div id="dpi" style="width: 1in; height: 1in; left: -100%; top: -100%; position: absolute;">
    898957                </div>
    899958        </body>