]> Pileus Git - ~andy/gtk/blob - gdk/broadway/broadway.js
Merge branch 'master' into broadway
[~andy/gtk] / gdk / broadway / broadway.js
1 var base64_val = [
2   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
3   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
4   255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
5    52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255,
6   255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
7    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
8   255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
9    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255
10 ]
11
12 function base64_8(str, index) {
13   var v =
14     (base64_val[str.charCodeAt(index)]) +
15     (base64_val[str.charCodeAt(index+1)] << 6);
16   return v;
17 }
18
19 function base64_16(str, index) {
20   var v =
21     (base64_val[str.charCodeAt(index)]) +
22     (base64_val[str.charCodeAt(index+1)] << 6) +
23     (base64_val[str.charCodeAt(index+2)] << 12);
24   return v;
25 }
26
27 function base64_16s(str, index) {
28   var v = base64_16(str, index);
29   if (v > 32767)
30     return v - 65536;
31   else
32     return v;
33 }
34
35 function base64_24(str, index) {
36   var v =
37     (base64_val[str.charCodeAt(index)]) +
38     (base64_val[str.charCodeAt(index+1)] << 6) +
39     (base64_val[str.charCodeAt(index+2)] << 12) +
40     (base64_val[str.charCodeAt(index+3)] << 18);
41   return v;
42 }
43
44 function base64_32(str, index) {
45   var v =
46     (base64_val[str.charCodeAt(index)]) +
47     (base64_val[str.charCodeAt(index+1)] << 6) +
48     (base64_val[str.charCodeAt(index+2)] << 12) +
49     (base64_val[str.charCodeAt(index+3)] << 18) +
50     (base64_val[str.charCodeAt(index+4)] << 24) +
51     (base64_val[str.charCodeAt(index+5)] << 30);
52   return v;
53 }
54
55 function createXHR()
56 {
57   try { return new XMLHttpRequest(); } catch(e) {}
58   try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
59   try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
60   try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
61   try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
62
63   return null;
64 }
65
66 var surfaces = {};
67 var outstanding_commands = new Array();
68 var input_socket = null;
69
70 function initContext(canvas, x, y, id)
71 {
72   canvas.surface_id = id;
73   canvas.style["position"] = "absolute"
74   canvas.style["left"] = x + "px"
75   canvas.style["top"] = y + "px"
76   canvas.style["display"] = "none"
77   context = canvas.getContext("2d")
78   context.globalCompositeOperation = "src-over"
79   context.fillRect(0, 0, canvas.width, canvas.height);
80   document.body.appendChild(canvas)
81
82   return context
83 }
84
85 function handleCommands(cmd_obj)
86 {
87   var cmd = cmd_obj.data;
88   var i = cmd_obj.pos;
89
90   while (i < cmd.length) {
91     var command = cmd[i++];
92     switch (command) {
93       /* create new surface */
94       case 's':
95         var id = base64_16(cmd, i);
96         i = i + 3;
97         var x = base64_16(cmd, i);
98         i = i + 3;
99         var y = base64_16(cmd, i);
100         i = i + 3;
101         var w = base64_16(cmd, i);
102         i = i + 3;
103         var h = base64_16(cmd, i);
104         i = i + 3;
105         var surface = document.createElement("canvas");
106         surface.width = w;
107         surface.height = h;
108         surfaces[id] = initContext(surface, x, y, id);
109         break;
110
111       /* show a surface */
112       case 'S':
113         var id = base64_16(cmd, i);
114         i = i + 3;
115         surfaces[id].canvas.style["display"] = "inline";
116         break;
117
118       /* hide a surface */
119       case 'H':
120         var id = base64_16(cmd, i);
121         i = i + 3;
122         surfaces[id].canvas.style["display"] = "inline";
123         break;
124
125       /* delete surface */
126       case 'd':
127         var id = base64_16(cmd, i);
128         i = i + 3;
129         var canvas = surfaces[id].canvas
130         delete surfaces[id]
131         canvas.parentNode.removeChild(canvas);
132
133         break;
134
135       /* move a surface */
136       case 'm':
137         var id = base64_16(cmd, i);
138         i = i + 3;
139         var x = base64_16(cmd, i);
140         i = i + 3;
141         var y = base64_16(cmd, i);
142         i = i + 3;
143         surfaces[id].canvas.style["left"] = x + "px";
144         surfaces[id].canvas.style["top"] = y + "px";
145         break;
146
147       /* resize a surface */
148       case 'r':
149         var id = base64_16(cmd, i);
150         i = i + 3;
151         var w = base64_16(cmd, i);
152         i = i + 3;
153         var h = base64_16(cmd, i);
154         i = i + 3;
155         surfaces[id].canvas.width = w;
156         surfaces[id].canvas.height = h;
157         break;
158
159       /* put image data surface */
160       case 'i':
161         var id = base64_16(cmd, i);
162         i = i + 3;
163         var x = base64_16(cmd, i);
164         i = i + 3;
165         var y = base64_16(cmd, i);
166         i = i + 3;
167         var size = base64_32(cmd, i);
168         i = i + 6;
169         var url = cmd.slice(i, i + size);
170         i = i + size;
171         var img = new Image();
172         img.src = url
173         if (img.complete) {
174           surfaces[id].drawImage(img, x, y);
175         } else {
176           cmd_obj.pos = i;
177           img.onload = function() { surfaces[id].drawImage(img, x, y); handleOutstanding(); }
178           return false
179         }
180
181         break;
182
183       /* copy rects */
184       case 'b':
185         var id = base64_16(cmd, i);
186         i = i + 3;
187
188         var nrects = base64_16(cmd, i);
189         i = i + 3;
190
191         var context = surfaces[id];
192         context.save();
193
194         var minx;
195         var miny;
196         var maxx;
197         var maxy;
198         for (var r = 0; r < nrects; r++) {
199           var x = base64_16(cmd, i);
200           i = i + 3;
201           var y = base64_16(cmd, i);
202           i = i + 3;
203           var w = base64_16(cmd, i);
204           i = i + 3;
205           var h = base64_16(cmd, i);
206           i = i + 3;
207           context.rect(x, y, w, h);
208
209           if (r == 0) {
210               minx = x;
211               miny = y;
212               maxx = x + w;
213               maxy = y + h;
214           } else {
215               if (x < minx)
216                   minx = x;
217               if (y < miny)
218                   miny = y;
219               if (x + w > maxx)
220                   maxx = x + w;
221               if (y + h > maxy)
222                   maxy = y + h;
223           }
224         }
225
226         context.clip()
227
228         var dx = base64_16s(cmd, i);
229         i = i + 3;
230         var dy = base64_16s(cmd, i);
231         i = i + 3;
232
233         context.drawImage(context.canvas,
234                           minx - dx, miny - dy, maxx - minx, maxy - miny,
235                           minx, miny, maxx - minx, maxy - miny);
236
237         context.restore();
238         break;
239
240       default:
241         alert("Unknown op " + command);
242     }
243   }
244   return true;
245 }
246
247 function handleOutstanding()
248 {
249   while (outstanding_commands.length > 0) {
250     var cmd = outstanding_commands.shift();
251     if (!handleCommands(cmd)) {
252       outstanding_commands.unshift(cmd);
253       return;
254     }
255   }
256 }
257
258 function handleLoad(event)
259 {
260   var cmd_obj = {};
261   cmd_obj.data = event.target.responseText;
262   cmd_obj.pos = 0;
263
264   outstanding_commands.push(cmd_obj);
265   if (outstanding_commands.length == 1) {
266     handleOutstanding()
267   }
268 }
269
270 function get_surface_id(ev) {
271   var id = ev.target.surface_id;
272   if (id != undefined)
273     return id;
274   return 0;
275 }
276
277 function send_input(cmd, args)
278 {
279   if (input_socket != null) {
280       input_socket.send(cmd + args.join(","));
281   }
282 }
283
284 function on_mouse_move (ev) {
285   send_input ("m", [get_surface_id(ev), ev.pageX, ev.pageY, ev.timeStamp])
286 }
287
288 function on_mouse_down (ev) {
289   send_input ("b", [get_surface_id(ev), ev.pageX, ev.pageY, ev.button, ev.timeStamp])
290 }
291
292 function on_mouse_up (ev) {
293   send_input ("B", [get_surface_id(ev), ev.pageX, ev.pageY, ev.button, ev.timeStamp])
294 }
295
296 var last_key_down = 0;
297 function on_key_down (ev) {
298   var key_code = ev.keyCode;
299   if (key_code != last_key_down) {
300     send_input ("k", [key_code, ev.timeStamp]);
301     last_key_down = key_code;
302   }
303 }
304
305 function on_key_up (ev) {
306   var key_code = ev.keyCode;
307   send_input ("K", [key_code, ev.timeStamp]);
308   last_key_down = 0;
309 }
310
311 function cancel_event(ev)
312 {
313   ev = ev ? ev : window.event;
314   if (ev.stopPropagation)
315     ev.stopPropagation();
316   if (ev.preventDefault)
317     ev.preventDefault();
318   ev.cancelBubble = true;
319   ev.cancel = true;
320   ev.returnValue = false;
321   return false;
322 }
323
324 function on_mouse_wheel(ev)
325 {
326   ev = ev ? ev : window.event;
327   var offset = ev.detail ? ev.detail : ev.wheelDelta;
328   var dir = 0
329   if (offset > 0)
330     dir = 1;
331   send_input ("s", [get_surface_id(ev), ev.pageX, ev.pageY, dir, ev.timeStamp])
332
333   return cancel_event(ev);
334 }
335
336 function connect()
337 {
338   var xhr = createXHR();
339   if (xhr) {
340     if (typeof xhr.multipart == 'undefined') {
341       alert("Sorry, this example only works in browsers that support multipart.");
342       return;
343     }
344
345     xhr.multipart = true;
346     xhr.open("GET", "/output", true);
347     xhr.onload = handleLoad;
348     xhr.send(null);
349   }
350
351   if ("WebSocket" in window) {
352     var loc = window.location.toString().replace("http:", "ws:");
353     loc = loc.substr(0, loc.lastIndexOf('/')) + "/input";
354     var ws = new WebSocket(loc, "broadway");
355     ws.onopen = function() {
356       input_socket = ws;
357     };
358     ws.onclose = function() {
359       input_socket = null;
360     };
361   } else {
362      alert("WebSocket not supported, input will not work!");
363   }
364   document.oncontextmenu = function () { return false; }
365   document.onmousemove = on_mouse_move;
366   document.onmousedown = on_mouse_down;
367   document.onmouseup = on_mouse_up;
368   document.onkeydown = on_key_down;
369   document.onkeyup = on_key_up;
370
371   if (document.addEventListener) {
372     document.addEventListener('DOMMouseScroll', on_mouse_wheel, false);
373     document.addEventListener('mousewheel', on_mouse_wheel, false);
374   } else if (document.attachEvent) {
375     element.attachEvent("onmousewheel", on_mouse_wheel);
376   }
377
378 }