Ticket #473: xprahtml5.patch
File xprahtml5.patch, 26.7 KB (added by , 8 years ago) |
---|
-
index.html
34 34 border: 0px solid black; 35 35 } 36 36 canvas { 37 border: 0px solid black; 38 display: none; 37 border: 1px solid black; 39 38 } 39 .window { 40 border: 10px solid black; 41 position: absolute; 42 box-shadow: 0px 0px 35px #000000; 43 } 44 .windowhead { 45 height: 20px; 46 color: #000000; 47 background-color: #ffffff; 48 } 40 49 </style> 41 50 42 51 <script type="text/javascript" src="include/websock.js"></script> … … 48 57 <script type="text/javascript" src="include/window.js"></script> 49 58 <script type="text/javascript" src="include/util.js"></script> 50 59 60 <script type="text/javascript" src="include/jquery.min.js"></script> 61 <script type="text/javascript" src="include/jqueryui.min.js"></script> 62 51 63 <script> 52 64 var protocol; 53 65 var status = "ready"; 54 66 67 var topwindow = null; 68 55 69 var id_to_window = {}; 56 70 var window_to_id = {}; 57 71 var focus = -1; 58 72 var screen_size_change_pending = false; 59 73 74 var screen_width = 800; 75 var screen_height = 600; 76 60 77 var OLD_ENCODING_NAMES_TO_NEW = {"x264" : "h264", "vpx" : "vp8"}; 61 78 var RGB_FORMATS = ["RGBX", "RGBA"]; 62 var canvas_state = null;63 79 64 80 var caps_lock = null; 65 81 var alt_modifier = null; 66 82 var meta_modifier = null; 67 83 84 // disable right click menu: 85 window.oncontextmenu = function(e) { 86 //showCustomMenu(); 87 return false; 88 } 89 68 90 /** 69 91 * Returns the modifiers set for the current event. 70 92 * We get the list of modifiers using "get_event_modifiers" … … 95 117 */ 96 118 function processKeyEvent(pressed, event) { 97 119 "use strict"; 98 if (canvas_state==null)99 return;100 120 // MSIE hack 101 121 if (window.event) 102 122 event = window.event; … … 125 145 if ((caps_lock && shift) || (!caps_lock && !shift)) 126 146 str = str.toLowerCase(); 127 147 128 var win = canvas_state.topOfStack();129 if ( win!= null) {148 //var win = canvas_state.topOfStack(); 149 if (topwindow != null) { 130 150 //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]; 151 var packet = ["key-action", topwindow, keyname, pressed, modifiers, keyval, str, keycode, group]; 133 152 send(packet); 134 153 } 135 154 } … … 278 297 function mouse_click(win, button, pressed, x, y, modifiers, buttons) { 279 298 "use strict"; 280 299 var wid = window_to_id[win]; 281 //show("mouse_click(..) wid("+win+")="+wid); 282 check_focus(); 300 set_focus(wid); 283 301 send(["button-action", wid, button, pressed, [x, y], modifiers, buttons]); 284 302 }; 285 303 286 304 function check_focus() { 287 305 "use strict"; 288 306 var wid = -1; 289 var win = canvas_state.topOfStack();290 307 if (win != null) 291 308 wid = window_to_id[win]; 292 309 //show("check_focus() window_to_id["+win+"]="+wid+", focus="+wid+", window_to_id="+window_to_id.toSource()); … … 298 315 "use strict"; 299 316 focus = wid; 300 317 send(["focus", focus, []]); 318 topwindow = wid; 301 319 //set the focused flag on all windows: 302 320 var win; 303 321 for (var i in id_to_window) { … … 315 333 316 334 function make_new_window(wid, x, y, w, h, metadata, override_redirect, client_properties) { 317 335 "use strict"; 318 var win = new XpraWindow(canvas_state, wid, x, y, w, h, metadata, override_redirect, client_properties, 336 // each window needs their own DIV that contains a canvas 337 var mydiv = document.createElement("div"); 338 mydiv.id = String(wid); 339 var mycanvas = document.createElement("canvas"); 340 mydiv.appendChild(mycanvas); 341 document.body.appendChild(mydiv); 342 // set initial sizes 343 mycanvas.width = w; 344 mycanvas.height = h; 345 jQuery(mydiv).addClass("window"); 346 jQuery(mydiv).prepend('<div id="head' + String(wid) + '"class="windowhead">window title</div>'); 347 jQuery(mydiv).draggable({cancel: "canvas"}); 348 // create the XpraWindow object that sits in the new div 349 var win = new XpraWindow(mycanvas, wid, x, y, w, h, metadata, override_redirect, client_properties, 319 350 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);321 351 id_to_window[wid] = win; 322 352 window_to_id[win] = wid; 323 353 var geom = win.get_internal_geometry(); … … 423 453 var wid = packet[1]; 424 454 var win = id_to_window[wid]; 425 455 if (win!=null) { 426 canvas_state.raiseShape(win);456 //canvas_state.raiseShape(win); 427 457 focus = wid; 428 458 check_focus(); 429 459 } … … 465 495 466 496 function get_desktop_size() { 467 497 "use strict"; 468 var canvas = document.getElementById('screen'); 469 return [canvas.width, canvas.height]; 498 return [screen_width, screen_height]; 470 499 } 471 500 function get_screen_sizes() { 472 501 "use strict"; 473 var canvas = document.getElementById('screen');474 502 var dpi = get_DPI(); 475 503 /* 476 504 equivallent GTK code: … … 482 510 monitors, 483 511 work_x, work_y, work_width, work_height) 484 512 */ 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,513 var wmm = Math.round(screen_width*25.4/dpi); 514 var hmm = Math.round(screen_height*25.4/dpi); 515 var monitor = ["Canvas", 0, 0, screen_width, screen_height, wmm, hmm]; 516 var screen = ["HTML", screen_width, screen_height, 489 517 wmm, hmm, 490 518 [monitor], 491 0, 0, canvas.width, canvas.height519 0, 0, screen_width, screen_height 492 520 ]; 493 521 //just a single screen: 494 522 return [screen]; … … 510 538 function make_hello() { 511 539 "use strict"; 512 540 return { 513 "version" : "0.1 4.0",541 "version" : "0.11.0", 514 542 "platform" : guess_platform(), 515 543 "platform.name" : guess_platform_name(), 516 544 "platform.processor" : guess_platform_processor(), … … 593 621 594 622 function do_send_new_screen_size() { 595 623 //show("do_send_new_screen_size()"); 596 if (protocol==null || canvas_state==null)597 return;598 624 screen_size_change_pending = false; 599 625 var ds = get_desktop_size(); 600 626 var ss = get_screen_sizes(); … … 607 633 } 608 634 } 609 635 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 630 636 function do_start(params) { 631 637 "use strict"; 632 638 show("start()"); 633 onresize();634 639 635 640 //hook document and window events: 636 641 document.onkeydown = onkeydown; 637 642 document.onkeyup = onkeyup; 638 643 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);646 644 protocol = new Protocol(); 647 645 protocol.set_packet_handler("open", process_open); 648 646 protocol.set_packet_handler("close", process_close); … … 672 670 document.onkeydown = null; 673 671 document.onkeyup = null; 674 672 document.onkeypress = null; 675 window.removeEventListener("resize", onresize);676 673 if (protocol!=null) { 677 674 protocol.close(); 678 675 protocol = null; 679 676 } 680 if (canvas_state!=null) { 681 canvas_state.destroy(); 682 canvas_state = null; 683 } 677 684 678 document.getElementById('connect_form').style.display = "block"; 685 679 document.getElementById('disconnect_form').style.display = "none"; 686 680 687 var canvas = document.getElementById('screen');688 canvas.style.display = "none";689 681 status = "ready"; 690 682 } 691 683 … … 714 706 document.getElementById('disconnect_form').style.display = "block"; 715 707 else 716 708 document.getElementById('disconnect_form').style.display = "none"; 717 onresize();718 709 set_ui_message(""); 719 710 720 711 show("connected to server - sending hello"); … … 746 737 send(["hello", hello]); 747 738 } 748 739 740 function pass() { 741 742 } 743 749 744 function force_refresh() { 750 745 "use strict"; 751 746 if (protocol!=null) { … … 891 886 </fieldset> 892 887 </form> 893 888 </div> 894 <div id="screen_container">895 <canvas id="screen" width="800" height="600"></canvas>896 </div>897 889 <div id="dpi" style="width: 1in; height: 1in; left: -100%; top: -100%; position: absolute;"> 898 890 </div> 899 891 </body> -
include/window.js
7 7 * Based on shape.js 8 8 */ 9 9 10 var window_icons = {};11 //load the window icons12 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 10 27 for (var i in image_names) {28 load_icon(image_names[i]);29 }30 11 31 /**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 between62 // 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/42875183 //here we just scale it by hand84 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 12 97 /**98 * toString allows us to identify buttons:99 */100 Button.prototype.toString = function() {101 "use strict";102 return "Button("+this.name+")";103 };104 13 105 106 107 14 /** 108 15 * This is the class representing a window we draw on the canvas. 109 16 * It has a geometry, it may have borders and a top bar. 110 17 * The contents of the window is an image, which gets updated 111 18 * when we receive pixels from the server. 112 19 */ 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) { 20 function XpraWindow(canvas_state, wid, x, y, w, h, metadata, override_redirect, client_properties, geometry_cb, mouse_move_cb, mouse_click_cb, window_closed, htmldiv) { 115 21 "use strict"; 116 22 //keep reference to the canvas: 117 this.state = canvas_state; 23 this.canvas = canvas_state; 24 this.div = jQuery("#" + String(wid)); 118 25 //callbacks start null until we finish init: 119 26 this.geometry_cb = null; 120 27 this.mouse_move_cb = null; … … 124 31 //styling: 125 32 this.borderColor = '#101028'; 126 33 this.topBarColor = '#B8B8C0'; 34 // This complicates things a little but but fixes mouse co-ordinate problems 35 // when there's a border or padding. See getMouse for more detail 36 var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop, 37 html, self, i; 38 if (document.defaultView && document.defaultView.getComputedStyle) { 39 this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(this.canvas, null).paddingLeft, 10) || 0; 40 this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(this.canvas, null).paddingTop, 10) || 0; 41 this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(this.canvas, null).borderLeftWidth, 10) || 0; 42 this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(this.canvas, null).borderTopWidth, 10) || 0; 43 } 44 // Some pages have fixed-position bars (like the stumbleupon bar) at the top or left of the page 45 // They will mess up mouse coordinates and this fixes that 46 html = document.body.parentNode; 47 this.htmlTop = html.offsetTop; 48 this.htmlLeft = html.offsetLeft; 127 49 128 50 //the window "backing": 129 51 this.image = null; … … 143 65 144 66 //not the real geometry we will use, 145 67 //but enough to avoid errors if update_metadata fires changes 146 this.x = x;147 this.y = y;68 this.x = 0; 69 this.y = 0; 148 70 this.w = w; 149 71 this.h = h; 150 72 … … 155 77 // the space taken by window decorations: 156 78 this.calculate_offsets(); 157 79 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+")"); 80 console.log(x, y, w, h); 81 82 // Hook up the events we want to receive: 83 this.event_listeners = [] 84 var listeners = [ 85 ['mousedown' , true], 86 ['mouseup' , true], 87 ['mousemove' , true] 88 ]; 89 for (i = 0; i < listeners.length; i += 1) { 90 var l = listeners[i]; 91 this.registerEventListener(l[0], l[1]); 167 92 } 168 93 169 94 // now safe to assign the callbacks: … … 172 97 this.mouse_click_cb = mouse_click_cb || null; 173 98 this.window_closed_cb = window_closed || null; 174 99 175 //create the buttons:176 if (!this.override_redirect) {177 this.create_buttons();178 }179 100 //create the image holding the pixels (the "backing"): 180 101 this.create_image_backing(); 181 canvas_state.addShape(this);182 102 }; 183 103 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; 104 XpraWindow.prototype.registerEventListener = function(event_type, useCapture) { 191 105 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 }); 106 var fn_name = "on_"+event_type; 107 var handler = self[fn_name]; 108 var fn = function(e) { 109 handler.call(self, e); 110 }; 111 this.event_listeners[event_type] = fn; 112 this.canvas["on"+event_type] = fn; 206 113 }; 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; 114 115 XpraWindow.prototype.getMouse = function(e) { 116 "use strict"; 117 var element = this.canvas, offsetX = 0, offsetY = 0, mx, my; 118 119 // Compute the total offset 120 if (element.offsetParent !== undefined) { 121 do { 122 offsetX += element.offsetLeft; 123 offsetY += element.offsetTop; 124 element = element.offsetParent; 125 } while (element); 215 126 } 216 if ("close" in this.buttons) { 217 this.buttons["close"].x = this.w-(w+2)*1; 127 128 // Add padding and border style widths to offset 129 // Also add the <html> offsets in case there's a position:fixed bar 130 offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft; 131 offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop; 132 133 mx = e.pageX - offsetX; 134 my = e.pageY - offsetY; 135 136 var mbutton = 0; 137 if ("which" in e) // Gecko (Firefox), WebKit (Safari/Chrome) & Opera 138 mbutton = Math.max(0, e.which); 139 else if ("button" in e) // IE, Opera (zero based) 140 mbutton = Math.max(0, e.button)+1; 141 //show("getmouse: button="+mbutton+", which="+e.which+", button="+e.button); 142 143 // We return a simple javascript object (a hash) with x and y defined 144 return {x: mx, y: my, button: mbutton}; 145 }; 146 147 XpraWindow.prototype.on_mousemove = function(e) { 148 var mouse = this.getMouse(e), 149 mx = mouse.x, 150 my = mouse.y; 151 152 var modifiers = []; 153 var buttons = []; 154 this.handle_mouse_move(mx, my, modifiers, buttons); 155 156 }; 157 158 XpraWindow.prototype.on_mousedown = function(e) { 159 var mouse, mx, my, shapes, l, i, mySel; 160 161 mouse = this.getMouse(e); 162 mx = mouse.x; 163 my = mouse.y; 164 165 // pass the click to the area: 166 var modifiers = []; 167 var buttons = []; 168 this.handle_mouse_click(mouse.button, true, mx, my, modifiers, buttons); 169 return; 170 }; 171 172 XpraWindow.prototype.on_mouseup = function(e) { 173 // if not handling it ourselves, pass it down: 174 var mouse = this.getMouse(e), 175 mx = mouse.x, 176 my = mouse.y; 177 if (!this.dragging) { 178 var modifiers = []; 179 var buttons = []; 180 this.handle_mouse_click(mouse.button, false, mx, my, modifiers, buttons); 218 181 } 219 }220 182 183 this.dragging = false; 184 }; 221 185 222 186 /** 223 187 * toString allows us to identify windows by their unique window id. … … 235 199 var previous_image = this.image; 236 200 var img_geom = this.get_internal_geometry(); 237 201 //show("createImageData: "+img_geom.toSource()); 238 this.image = canvas_state.canvas.getContext('2d').createImageData(img_geom.w, img_geom.h);202 this.image = this.canvas.getContext('2d').createImageData(img_geom.w, img_geom.h); 239 203 if (previous_image) { 240 204 //copy previous pixels to new image, ignoring bit gravity 241 205 //TODO! … … 249 213 */ 250 214 XpraWindow.prototype.calculate_offsets = function() { 251 215 "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]; 216 217 this.offsets = [0, 0, 0, 0]; 263 218 }; 264 219 265 220 /** … … 288 243 } 289 244 if ("title" in metadata) { 290 245 this.title = metadata["title"]; 291 //redraw everything (a bit wasteful):292 this.state.invalidate();293 246 } 294 247 }; 295 248 … … 377 330 "use strict"; 378 331 this.x = 0; 379 332 this.y = 0; 380 this.w = this.state.width;381 this.h = this.state.height;333 this.w = 640; 334 this.h = 480; 382 335 }; 383 336 384 337 /** … … 390 343 XpraWindow.prototype.handle_resize = function() { 391 344 "use strict"; 392 345 this.create_image_backing(); 393 this.state.invalidate();346 //this.state.invalidate(); 394 347 this.move_buttons(); 395 348 if (this.geometry_cb!=null) { 396 349 this.geometry_cb(this); … … 423 376 // This should always be true: 424 377 //this.image.width = this.w - this.borderWidth*2; 425 378 //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)};379 return { x : this.x, 380 y : this.y, 381 w : this.w, 382 h : this.h}; 430 383 }; 431 384 432 385 /** … … 436 389 XpraWindow.prototype.handle_mouse_click = function(button, pressed, mx, my, modifiers, buttons) { 437 390 "use strict"; 438 391 var igeom = this.get_internal_geometry(); 392 console.log("got mouse click at ", mx, my) 439 393 if (this.mouse_click_cb!=null && rectangle_contains(igeom, mx, my)) { 440 394 this.mouse_click_cb(this, button, pressed, mx, my, modifiers, buttons); 441 395 return; 442 396 } 443 //maybe one of the buttons:444 //(use relative coordinates)445 var x = mx-this.x;446 var y = my-this.y447 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 }458 397 }; 459 398 460 399 /** … … 463 402 */ 464 403 XpraWindow.prototype.handle_mouse_move = function(mx, my, modifiers, buttons) { 465 404 "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 } 405 // should we handle mouse move? 406 this.mouse_move_cb(this, mx, my, modifiers, buttons); 470 407 }; 471 408 472 409 473 410 XpraWindow.prototype.update_icon = function(w, h, pixel_format, data) { 474 411 "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 } 412 // update icon 480 413 } 481 414 482 415 /** … … 488 421 XpraWindow.prototype.draw = function(ctx) { 489 422 "use strict"; 490 423 491 if (!this.override_redirect && !this.fullscreen) {492 //draw window frame:493 this.draw_frame(ctx);494 }495 496 424 //draw the window pixels: 497 ctx.putImageData(this.image, this.x + this.borderWidth, this.y + this.borderWidth + this.topBarHeight);425 ctx.putImageData(this.image, this.x, this.y); 498 426 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 }503 427 }; 504 428 505 /**506 * Draws the window frame:507 * a simple rectangle around the edge.508 */509 XpraWindow.prototype.draw_frame = function(ctx) {510 "use strict";511 429 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 537 430 /** 538 * Draws border and selection rectangles539 * which indicate that the window is selected540 */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 boxes553 half = this.state.selectionBoxSize / 2;554 555 // 0 1 2556 // 3 4557 // 5 6 7558 559 // top left, middle, right560 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 left570 this.state.selectionHandles[3].x = this.x-half;571 this.state.selectionHandles[3].y = this.y+this.h/2-half;572 573 //middle right574 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, right578 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 /**595 431 * Updates the window image with new pixel data 596 432 * we have received from the server. 597 433 */ … … 625 461 var stride = this.image.width*4; 626 462 //and we can paint the canvas with it 627 463 //(if we have transparency, we should probably repaint what is underneath...) 628 var ctx = this. state.ctx;464 var ctx = this.canvas.getContext('2d'); 629 465 630 466 if (x==0 && width==this.image.width && y+height<=this.image.height) { 631 467 //take a shortcut: copy all lines … … 633 469 634 470 if (this.focused) { 635 471 //shortcut: paint canvas directly 636 ctx.putImageData(this.image, this.x + this.borderWidth, this.y + this.borderWidth + this.topBarHeight);472 ctx.putImageData(this.image, this.x , this.y); 637 473 return; 638 474 } 639 475 } … … 650 486 651 487 if (this.focused) { 652 488 //shortcut: paint canvas directly 653 ctx.putImageData(img, this.x + this.borderWidth + x, this.y + this.borderWidth + this.topBarHeight+ y);489 ctx.putImageData(img, this.x + x, this.y + y); 654 490 return; 655 491 } 656 492 } … … 658 494 //no action taken, no need to invalidate 659 495 return; 660 496 } 661 this.state.invalidate();497 //this.state.invalidate(); 662 498 }; 663 499 664 500 /** … … 666 502 */ 667 503 XpraWindow.prototype.destroy = function destroy() { 668 504 "use strict"; 669 if (this.state!=null) { 670 this.state.removeShape(this); 671 this.state = null; 672 } 505 // remove div 506 this.div.remove() 673 507 }; 674 508 675 509 /**