var getAuthString = Require('x11/core/auth'); var xutil = Require('x11/core/xutil'); function readVisuals(bl, visuals, n_visuals, cb) { if (n_visuals == 0) { cb(); return; } var visual = {}; bl.unpackTo( visual, [ 'L vid', 'C class', 'C bits_per_rgb', 'S map_ent', 'L red_mask', 'L green_mask', 'L blue_mask', 'xxxx' ], function() { var vid = visual.vid; // delete visual.vid; visuals[visual.vid] = visual; if (Object.keys(visuals).length == n_visuals) cb() else readVisuals(bl, visuals, n_visuals, cb); }); } function readScreens(bl, display, cbDisplayReady) { var numParsedDepths = 0; var readDepths = function(bl, display, depths, n_depths, cb) { if (n_depths == 0) { cb(); return; } bl.unpack( 'CxSxxxx', function(res) { var dep = res[0]; var n_visuals = res[1]; var visuals = {}; readVisuals(bl, visuals, n_visuals, function() { if (dep in depths) { for (var visual in visuals) { depths[dep][visual] = visuals[visual]; } } else { depths[dep] = visuals; } numParsedDepths++; if (numParsedDepths == n_depths) cb(); else readDepths(bl, display, depths, n_depths, cb); }); }); } // for (i=0; i < display.screen_num; ++i) { var scr = {}; bl.unpackTo( scr, [ 'L root', 'L default_colormap', 'L white_pixel', 'L black_pixel', 'L input_masks', 'S pixel_width', 'S pixel_height', 'S mm_width', 'S mm_height', 'S min_installed_maps', 'S max_installed_maps', 'L root_visual', 'C root_depth', 'C backing_stores', 'C root_depth', 'C num_depths' ], function () { var depths = {}; readDepths(bl, display, depths, scr.num_depths, function() { scr.depths = depths; delete scr.num_depths; display.screen.push(scr); if (display.screen.length == display.screen_num) { delete display.screen_num; cbDisplayReady(null, display); return; } else { readScreens(bl, display, cbDisplayReady); } }); }); } } function readServerHello(bl, cb) { bl.unpack('C', function(res) { if (res[0] == 0) { // conection time error // unpack error bl.unpack('Cxxxxxx', function (rlen) { bl.get(rlen[0], function (reason) { var err = new Error; err.message = 'X server connection failed: ' + reason.toString(); cb(err); }); }); // TODO: do we need to close stream from our side? // TODO: api to close source stream via attached unpackstream return; } var display = {}; bl.unpackTo( display, [ 'x', 'S major', 'S minor', 'S xlen', 'L release', 'L resource_base', 'L resource_mask', 'L motion_buffer_size', 'S vlen', 'S max_request_length', 'C screen_num', 'C format_num', 'C image_byte_order', 'C bitmap_bit_order', 'C bitmap_scanline_unit', 'C bitmap_scanline_pad', 'C min_keycode', 'C max_keycode', 'xxxx' ], function() { var pvlen = xutil.padded_length(display.vlen); // setup data to generate resource id // TODO: cleaunup code here var mask = display.resource_mask; display.rsrc_shift = 0; while (!( (mask >> display.rsrc_shift) & 1) ) display.rsrc_shift++; display.rsrc_id = 0; bl.get(pvlen, function(vendor) { display.vendor = vendor.toString().substr(0, display.vlen); // utf8 by default? display.format = {}; for (var i=0; i < display.format_num; ++i) { bl.unpack('CCCxxxxx', function(fmt) { var depth = fmt[0]; display.format[depth] = {}; display.format[depth].bits_per_pixel = fmt[1]; display.format[depth].scanline_pad = fmt[2]; if (Object.keys(display.format).length == display.format_num) { delete display.format_num; display.screen = []; readScreens(bl, display, cb); } }); } }); } ); }); } function getByteOrder() { var isLittleEndian = ((new Uint32Array((new Uint8Array([1,2,3,4])).buffer))[0] === 0x04030201); if (isLittleEndian) { return 'l'.charCodeAt(0); } else { return 'B'.charCodeAt(0); } } function writeClientHello(stream, displayNum, authHost, authFamily) { getAuthString( displayNum, authHost, authFamily, function( err, cookie ) { if (err) { throw err; } var byte_order = getByteOrder(); var protocol_major = 11; // TODO: config? env? var protocol_minor = 0; stream.pack( 'CxSSSSxxpp', [ byte_order, protocol_major, protocol_minor, cookie.authName.length, cookie.authData.length, cookie.authName, cookie.authData ] ); stream.flush(); }); } module.exports.readServerHello = readServerHello; module.exports.writeClientHello = writeClientHello;