mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound.
This commit is contained in:
commit
2ad9e11ee0
@ -802,10 +802,7 @@ pref("dom.datastore.enabled", true);
|
||||
#endif
|
||||
|
||||
// DOM Inter-App Communication API.
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Enable this only for gonk-specific build but not for desktop build.
|
||||
pref("dom.inter-app-communication-api.enabled", true);
|
||||
#endif
|
||||
|
||||
// Allow ADB to run for this many hours before disabling
|
||||
// (only applies when marionette is disabled)
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "36aa3e5d226a844b07b3e4b2219f54b549456ec1",
|
||||
"revision": "86e06b1db110e34eb66826d3b1bdee3a5d57b3a7",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -307,6 +307,9 @@ let SessionStoreInternal = {
|
||||
// states for all currently opened windows
|
||||
_windows: {},
|
||||
|
||||
// counter for creating unique window IDs
|
||||
_nextWindowID: 0,
|
||||
|
||||
// states for all recently closed windows
|
||||
_closedWindows: [],
|
||||
|
||||
@ -682,6 +685,15 @@ let SessionStoreInternal = {
|
||||
this._clearRestoringWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a unique window identifier
|
||||
* @return string
|
||||
* A unique string to identify a window
|
||||
*/
|
||||
_generateWindowID: function ssi_generateWindowID() {
|
||||
return "window" + (this._nextWindowID++);
|
||||
},
|
||||
|
||||
/**
|
||||
* If it's the first window load since app start...
|
||||
* - determine if we're reloading after a crash or a forced-restart
|
||||
@ -703,8 +715,9 @@ let SessionStoreInternal = {
|
||||
this._loadState == STATE_QUITTING)
|
||||
return;
|
||||
|
||||
// assign it a unique identifier (timestamp)
|
||||
aWindow.__SSi = "window" + Date.now();
|
||||
// Assign the window a unique identifier we can use to reference
|
||||
// internal data about the window.
|
||||
aWindow.__SSi = this._generateWindowID();
|
||||
|
||||
// and create its data object
|
||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
|
||||
@ -880,8 +893,10 @@ let SessionStoreInternal = {
|
||||
// this window was about to be restored - conserve its original data, if any
|
||||
let isFullyLoaded = this._isWindowLoaded(aWindow);
|
||||
if (!isFullyLoaded) {
|
||||
if (!aWindow.__SSi)
|
||||
aWindow.__SSi = "window" + Date.now();
|
||||
if (!aWindow.__SSi) {
|
||||
aWindow.__SSi = this._generateWindowID();
|
||||
}
|
||||
|
||||
this._windows[aWindow.__SSi] = this._statesToRestore[aWindow.__SS_restoreID];
|
||||
delete this._statesToRestore[aWindow.__SS_restoreID];
|
||||
delete aWindow.__SS_restoreID;
|
||||
|
@ -1037,14 +1037,10 @@ var GestureModule = {
|
||||
*/
|
||||
var InputSourceHelper = {
|
||||
isPrecise: false,
|
||||
touchIsActive: false,
|
||||
|
||||
init: function ish_init() {
|
||||
window.addEventListener("mousemove", this, true);
|
||||
window.addEventListener("mousedown", this, true);
|
||||
window.addEventListener("touchstart", this, true);
|
||||
window.addEventListener("touchend", this, true);
|
||||
window.addEventListener("touchcancel", this, true);
|
||||
Services.obs.addObserver(this, "metro_precise_input", false);
|
||||
Services.obs.addObserver(this, "metro_imprecise_input", false);
|
||||
},
|
||||
|
||||
_precise: function () {
|
||||
@ -1061,37 +1057,17 @@ var InputSourceHelper = {
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function ish_handleEvent(aEvent) {
|
||||
switch(aEvent.type) {
|
||||
case "touchstart":
|
||||
observe: function BrowserUI_observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "metro_precise_input":
|
||||
this._precise();
|
||||
break;
|
||||
case "metro_imprecise_input":
|
||||
this._imprecise();
|
||||
this.touchIsActive = true;
|
||||
break;
|
||||
case "touchend":
|
||||
case "touchcancel":
|
||||
this.touchIsActive = false;
|
||||
break;
|
||||
default:
|
||||
// Ignore mouse movement when touch is active. Prevents both mouse scrollbars
|
||||
// and touch scrollbars from displaying at the same time. Also works around
|
||||
// odd win8 bug involving an erant mousemove event after a touch sequence
|
||||
// starts (bug 896017).
|
||||
if (this.touchIsActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.mozInputSource) {
|
||||
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE:
|
||||
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_PEN:
|
||||
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_ERASER:
|
||||
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_CURSOR:
|
||||
this._precise();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
fireUpdate: function fireUpdate() {
|
||||
if (this.isPrecise) {
|
||||
this._fire("MozPrecisePointer");
|
||||
|
@ -32,44 +32,28 @@ function testState(aState) {
|
||||
}
|
||||
}
|
||||
|
||||
function sendMouseMoves() {
|
||||
let utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
for (let deg = 0; deg < 180; deg++) {
|
||||
let coord = Math.sin((deg * Math.PI)/180) * 750;
|
||||
utils.sendMouseEventToWindow("mousemove", coord, coord, 2, 1, 0, true,
|
||||
1, Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE);
|
||||
}
|
||||
function notifyPrecise()
|
||||
{
|
||||
Services.obs.notifyObservers(null, "metro_precise_input", null);
|
||||
}
|
||||
|
||||
function sendTouchStart() {
|
||||
EventUtils.synthesizeTouchAtPoint(100, 100, { type: "touchstart" }, window);
|
||||
}
|
||||
|
||||
function sendTouchMove() {
|
||||
EventUtils.synthesizeTouchAtPoint(100, 100, { type: "touchmove" }, window);
|
||||
}
|
||||
|
||||
function sendTouchEnd() {
|
||||
EventUtils.synthesizeTouchAtPoint(100, 100, { type: "touchend" }, window);
|
||||
function notifyImprecise()
|
||||
{
|
||||
Services.obs.notifyObservers(null, "metro_imprecise_input", null);
|
||||
}
|
||||
|
||||
gTests.push({
|
||||
desc: "precise/imprecise input switcher",
|
||||
setUp: setUp,
|
||||
run: function () {
|
||||
sendMouseMoves();
|
||||
notifyPrecise();
|
||||
testState("precise");
|
||||
sendTouchStart();
|
||||
notifyImprecise();
|
||||
testState("imprecise");
|
||||
sendMouseMoves();
|
||||
testState("imprecise");
|
||||
sendTouchMove();
|
||||
testState("imprecise");
|
||||
sendTouchEnd();
|
||||
testState("imprecise");
|
||||
sendMouseMoves();
|
||||
notifyPrecise();
|
||||
testState("precise");
|
||||
notifyImprecise();
|
||||
testState("imprecise");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -66,8 +66,14 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
|
||||
background-image: none;
|
||||
box-shadow: inset -1px 0 0 #222426;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
|
||||
background-image: none;
|
||||
box-shadow: inset 1px 0 0 #222426;
|
||||
}
|
||||
|
||||
/* Black box message and source progress meter */
|
||||
|
@ -64,8 +64,14 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
|
||||
background-image: none;
|
||||
box-shadow: inset -1px 0 0 #222426;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
|
||||
background-image: none;
|
||||
box-shadow: inset 1px 0 0 #222426;
|
||||
}
|
||||
|
||||
/* Black box message and source progress meter */
|
||||
|
@ -64,8 +64,14 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
|
||||
background-image: none;
|
||||
box-shadow: inset -1px 0 0 #222426;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
|
||||
background-image: none;
|
||||
box-shadow: inset 1px 0 0 #222426;
|
||||
}
|
||||
|
||||
/* Black box message and source progress meter */
|
||||
|
@ -66,7 +66,9 @@ nsDOMCameraManager::~nsDOMCameraManager()
|
||||
/* destructor code */
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1062,6 +1062,23 @@ ContactDB.prototype = {
|
||||
substringResult[event.target.result[i].id] = event.target.result[i];
|
||||
}
|
||||
}.bind(this);
|
||||
} else if (normalized[0] !== "+") {
|
||||
// We might have an international prefix like '00'
|
||||
let parsed = PhoneNumberUtils.parse(normalized);
|
||||
if (parsed && parsed.internationalNumber &&
|
||||
parsed.nationalNumber &&
|
||||
parsed.nationalNumber !== normalized &&
|
||||
parsed.internationalNumber !== normalized) {
|
||||
if (DEBUG) debug("Search with " + parsed.internationalNumber);
|
||||
let prefixRequest = index.mozGetAll(parsed.internationalNumber, limit);
|
||||
|
||||
prefixRequest.onsuccess = function (event) {
|
||||
if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
|
||||
for (let i in event.target.result) {
|
||||
substringResult[event.target.result[i].id] = event.target.result[i];
|
||||
}
|
||||
}.bind(this);
|
||||
}
|
||||
}
|
||||
|
||||
request = index.mozGetAll(normalized, limit);
|
||||
|
@ -61,6 +61,16 @@ var properties2 = {
|
||||
tel: [{type: ["work"], value: shortNumber, carrier: "testCarrier"}]
|
||||
};
|
||||
|
||||
var number3 = {
|
||||
international1: "0041557932012345",
|
||||
international2: "+557932012345"
|
||||
};
|
||||
|
||||
var properties3 = {
|
||||
name: "Testname2",
|
||||
tel: [{value: number3.international2}]
|
||||
};
|
||||
|
||||
var req;
|
||||
var index = 0;
|
||||
var createResult1;
|
||||
@ -237,6 +247,41 @@ var steps = [
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding a new contact with country code");
|
||||
createResult1 = new mozContact();
|
||||
createResult1.init(properties3);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
sample_id1 = createResult1.id;
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Searching for international number with prefix");
|
||||
var options = {filterBy: ["tel"],
|
||||
filterOp: "match",
|
||||
filterValue: number3.international1};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
ok(req.result.length == 1, "Found exactly 1 contact.");
|
||||
findResult1 = req.result[0];
|
||||
ok(findResult1.id == sample_id1, "Same ID");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Deleting database");
|
||||
req = mozContacts.clear();
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Deleted the database");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "all done!\n");
|
||||
SimpleTest.finish();
|
||||
|
@ -45,15 +45,17 @@
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
var itemNumber = 60;
|
||||
|
||||
function testStoreAdd() {
|
||||
var objects = [];
|
||||
for (var i = 0; i < 300; ++i) {
|
||||
for (var i = 0; i < itemNumber; ++i) {
|
||||
objects.push(i);
|
||||
}
|
||||
|
||||
function testStoreAddInternal() {
|
||||
if (!objects.length) {
|
||||
ok(true, "We inserted 300 items");
|
||||
ok(true, "We inserted " + itemNumber + " items");
|
||||
runTest();
|
||||
return;
|
||||
}
|
||||
@ -70,7 +72,7 @@
|
||||
|
||||
function testStoreGet() {
|
||||
var objects = [];
|
||||
for (var i = 1; i <= 300; ++i) {
|
||||
for (var i = 1; i <= itemNumber; ++i) {
|
||||
objects.push(i);
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,7 @@ SystemMessageManager.prototype = {
|
||||
dispatchers[aType] = { handler: aHandler, messages: [], isHandling: false };
|
||||
|
||||
// Ask for the list of currently pending messages.
|
||||
this.addMessageListeners("SystemMessageManager:GetPendingMessages:Return");
|
||||
cpmm.sendAsyncMessage("SystemMessageManager:GetPendingMessages",
|
||||
{ type: aType,
|
||||
uri: this._uri,
|
||||
@ -214,6 +215,8 @@ SystemMessageManager.prototype = {
|
||||
manifest: this._manifest,
|
||||
uri: this._uri,
|
||||
msgID: msg.msgID });
|
||||
} else if (aMessage.name == "SystemMessageManager:GetPendingMessages:Return") {
|
||||
this.removeMessageListeners(aMessage.name);
|
||||
}
|
||||
|
||||
let messages = (aMessage.name == "SystemMessageManager:Message")
|
||||
@ -248,8 +251,7 @@ SystemMessageManager.prototype = {
|
||||
// nsIDOMGlobalPropertyInitializer implementation.
|
||||
init: function sysMessMgr_init(aWindow) {
|
||||
debug("init");
|
||||
this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message",
|
||||
"SystemMessageManager:GetPendingMessages:Return"]);
|
||||
this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message"]);
|
||||
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
this._isInBrowserElement = principal.isInBrowserElement;
|
||||
|
@ -1152,6 +1152,7 @@ this.GECKO_ICC_SERVICES = {
|
||||
ADN: 2,
|
||||
FDN: 3,
|
||||
PLMNSEL: 7,
|
||||
MSISDN: 9,
|
||||
CBMI: 14,
|
||||
SPN: 17,
|
||||
SDN: 18,
|
||||
@ -1161,6 +1162,7 @@ this.GECKO_ICC_SERVICES = {
|
||||
BDN: 31,
|
||||
PNN: 51,
|
||||
OPL: 52,
|
||||
MDN: 53,
|
||||
SPDI: 56
|
||||
},
|
||||
usim: {
|
||||
@ -1170,10 +1172,12 @@ this.GECKO_ICC_SERVICES = {
|
||||
CBMI: 15,
|
||||
CBMIR: 16,
|
||||
SPN: 19,
|
||||
MSISDN: 21,
|
||||
DATA_DOWNLOAD_SMS_PP: 28,
|
||||
DATA_DOWNLOAD_SMS_CB: 29,
|
||||
PNN: 45,
|
||||
OPL: 46,
|
||||
MDN: 47,
|
||||
SPDI: 51
|
||||
},
|
||||
ruim: {
|
||||
|
@ -10995,10 +10995,8 @@ let ICCRecordHelper = {
|
||||
fetchICCRecords: function fetchICCRecords() {
|
||||
this.readICCID();
|
||||
RIL.getIMSI();
|
||||
this.readMSISDN();
|
||||
this.readAD();
|
||||
this.readSST();
|
||||
this.readMBDN();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -11143,6 +11141,13 @@ let ICCRecordHelper = {
|
||||
debug("SST: " + str);
|
||||
}
|
||||
|
||||
if (ICCUtilsHelper.isICCServiceAvailable("MSISDN")) {
|
||||
if (DEBUG) debug("MSISDN: MSISDN is available");
|
||||
this.readMSISDN();
|
||||
} else {
|
||||
if (DEBUG) debug("MSISDN: MSISDN service is not available");
|
||||
}
|
||||
|
||||
// Fetch SPN and PLMN list, if some of them are available.
|
||||
if (ICCUtilsHelper.isICCServiceAvailable("SPN")) {
|
||||
if (DEBUG) debug("SPN: SPN is available");
|
||||
@ -11151,6 +11156,13 @@ let ICCRecordHelper = {
|
||||
if (DEBUG) debug("SPN: SPN service is not available");
|
||||
}
|
||||
|
||||
if (ICCUtilsHelper.isICCServiceAvailable("MDN")) {
|
||||
if (DEBUG) debug("MDN: MDN available.");
|
||||
this.readMBDN();
|
||||
} else {
|
||||
if (DEBUG) debug("MDN: MDN service is not available");
|
||||
}
|
||||
|
||||
if (ICCUtilsHelper.isICCServiceAvailable("SPDI")) {
|
||||
if (DEBUG) debug("SPDI: SPDI available.");
|
||||
this.readSPDI();
|
||||
|
@ -1895,3 +1895,86 @@ add_test(function test_reading_ad_and_parsing_mcc_mnc() {
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_reading_optional_efs() {
|
||||
let worker = newUint8Worker();
|
||||
let record = worker.ICCRecordHelper;
|
||||
let gsmPdu = worker.GsmPDUHelper;
|
||||
let ril = worker.RIL;
|
||||
let buf = worker.Buf;
|
||||
let io = worker.ICCIOHelper;
|
||||
|
||||
function buildSST(supportedEf) {
|
||||
let sst = [];
|
||||
let len = supportedEf.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let index, bitmask, iccService;
|
||||
if (ril.appType === CARD_APPTYPE_SIM) {
|
||||
iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]];
|
||||
iccService -= 1;
|
||||
index = Math.floor(iccService / 4);
|
||||
bitmask = 2 << ((iccService % 4) << 1);
|
||||
} else if (ril.appType === CARD_APPTYPE_USIM){
|
||||
iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]];
|
||||
iccService -= 1;
|
||||
index = Math.floor(iccService / 8);
|
||||
bitmask = 1 << ((iccService % 8) << 0);
|
||||
}
|
||||
|
||||
if (sst) {
|
||||
sst[index] |= bitmask;
|
||||
}
|
||||
}
|
||||
return sst;
|
||||
}
|
||||
|
||||
ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() {
|
||||
// Ignore updateCellBroadcastConfig after reading SST
|
||||
};
|
||||
|
||||
function do_test(sst, supportedEf) {
|
||||
// Clone supportedEf to local array for testing
|
||||
let testEf = supportedEf.slice(0);
|
||||
|
||||
record.readMSISDN = function fakeReadMSISDN() {
|
||||
testEf.splice(testEf.indexOf("MSISDN"), 1);
|
||||
};
|
||||
|
||||
record.readMBDN = function fakeReadMBDN() {
|
||||
testEf.splice(testEf.indexOf("MDN"), 1);
|
||||
};
|
||||
|
||||
io.loadTransparentEF = function fakeLoadTransparentEF(options) {
|
||||
// Write data size
|
||||
buf.writeInt32(sst.length * 2);
|
||||
|
||||
// Write data
|
||||
for (let i = 0; i < sst.length; i++) {
|
||||
gsmPdu.writeHexOctet(sst[i] || 0);
|
||||
}
|
||||
|
||||
// Write string delimiter
|
||||
buf.writeStringDelimiter(sst.length * 2);
|
||||
|
||||
if (options.callback) {
|
||||
options.callback(options);
|
||||
}
|
||||
|
||||
if (testEf.length !== 0) {
|
||||
do_print("Un-handled EF: " + JSON.stringify(testEf));
|
||||
do_check_true(false);
|
||||
}
|
||||
};
|
||||
|
||||
record.readSST();
|
||||
}
|
||||
|
||||
// TODO: Add all necessary optional EFs eventually
|
||||
let supportedEf = ["MSISDN", "MDN"];
|
||||
ril.appType = CARD_APPTYPE_SIM;
|
||||
do_test(buildSST(supportedEf), supportedEf);
|
||||
ril.appType = CARD_APPTYPE_USIM;
|
||||
do_test(buildSST(supportedEf), supportedEf);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -198,7 +198,13 @@ ContainerRender(ContainerT* aContainer,
|
||||
continue;
|
||||
}
|
||||
|
||||
layerToRender->RenderLayer(childOffset, clipRect);
|
||||
if (layerToRender->HasLayerBeenComposited()) {
|
||||
// Composer2D will compose this layer so skip GPU composition
|
||||
// this time & reset composition flag for next composition phase
|
||||
layerToRender->SetLayerComposited(false);
|
||||
} else {
|
||||
layerToRender->RenderLayer(childOffset, clipRect);
|
||||
}
|
||||
// invariant: our GL context should be current here, I don't think we can
|
||||
// assert it though
|
||||
}
|
||||
|
@ -726,6 +726,7 @@ LayerComposite::LayerComposite(LayerManagerComposite *aManager)
|
||||
, mUseShadowClipRect(false)
|
||||
, mShadowTransformSetByAnimation(false)
|
||||
, mDestroyed(false)
|
||||
, mLayerComposited(false)
|
||||
{ }
|
||||
|
||||
LayerComposite::~LayerComposite()
|
||||
|
@ -381,12 +381,18 @@ public:
|
||||
mShadowTransformSetByAnimation = aSetByAnimation;
|
||||
}
|
||||
|
||||
void SetLayerComposited(bool value)
|
||||
{
|
||||
mLayerComposited = value;
|
||||
}
|
||||
|
||||
// These getters can be used anytime.
|
||||
float GetShadowOpacity() { return mShadowOpacity; }
|
||||
const nsIntRect* GetShadowClipRect() { return mUseShadowClipRect ? &mShadowClipRect : nullptr; }
|
||||
const nsIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
|
||||
const gfx3DMatrix& GetShadowTransform() { return mShadowTransform; }
|
||||
bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
|
||||
bool HasLayerBeenComposited() { return mLayerComposited; }
|
||||
|
||||
protected:
|
||||
gfx3DMatrix mShadowTransform;
|
||||
@ -398,6 +404,7 @@ protected:
|
||||
bool mUseShadowClipRect;
|
||||
bool mShadowTransformSetByAnimation;
|
||||
bool mDestroyed;
|
||||
bool mLayerComposited;
|
||||
};
|
||||
|
||||
|
||||
|
@ -635,6 +635,7 @@ RES_DRAWABLE_MDPI = \
|
||||
res/drawable-mdpi/ic_url_bar_search.png \
|
||||
res/drawable-mdpi/ic_url_bar_star.png \
|
||||
res/drawable-mdpi/ic_url_bar_tab.png \
|
||||
res/drawable-mdpi/icon_bookmarks_empty.png \
|
||||
res/drawable-mdpi/icon_last_tabs.png \
|
||||
res/drawable-mdpi/icon_last_tabs_empty.png \
|
||||
res/drawable-mdpi/icon_most_recent.png \
|
||||
@ -752,6 +753,7 @@ RES_DRAWABLE_HDPI = \
|
||||
res/drawable-hdpi/ic_url_bar_search.png \
|
||||
res/drawable-hdpi/ic_url_bar_star.png \
|
||||
res/drawable-hdpi/ic_url_bar_tab.png \
|
||||
res/drawable-hdpi/icon_bookmarks_empty.png \
|
||||
res/drawable-hdpi/icon_last_tabs.png \
|
||||
res/drawable-hdpi/icon_last_tabs_empty.png \
|
||||
res/drawable-hdpi/icon_most_recent.png \
|
||||
@ -855,6 +857,7 @@ RES_DRAWABLE_XHDPI = \
|
||||
res/drawable-xhdpi/ic_url_bar_search.png \
|
||||
res/drawable-xhdpi/ic_url_bar_star.png \
|
||||
res/drawable-xhdpi/ic_url_bar_tab.png \
|
||||
res/drawable-xhdpi/icon_bookmarks_empty.png \
|
||||
res/drawable-xhdpi/icon_last_tabs.png \
|
||||
res/drawable-xhdpi/icon_last_tabs_empty.png \
|
||||
res/drawable-xhdpi/icon_most_recent.png \
|
||||
|
@ -20,7 +20,10 @@ import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewStub;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A page in about:home that displays a ListView of bookmarks.
|
||||
@ -40,6 +43,9 @@ public class BookmarksPage extends HomeFragment {
|
||||
// Adapter for list of bookmarks.
|
||||
private BookmarksListAdapter mListAdapter;
|
||||
|
||||
// Reference to the View to display when there are no results.
|
||||
private View mEmptyView;
|
||||
|
||||
// Callback for cursor loaders.
|
||||
private CursorLoaderCallbacks mLoaderCallbacks;
|
||||
|
||||
@ -102,6 +108,7 @@ public class BookmarksPage extends HomeFragment {
|
||||
public void onDestroyView() {
|
||||
mList = null;
|
||||
mListAdapter = null;
|
||||
mEmptyView = null;
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@ -130,6 +137,22 @@ public class BookmarksPage extends HomeFragment {
|
||||
getLoaderManager().initLoader(LOADER_ID_BOOKMARKS_LIST, null, mLoaderCallbacks);
|
||||
}
|
||||
|
||||
private void updateUiFromCursor(Cursor c) {
|
||||
if ((c == null || c.getCount() == 0) && mEmptyView == null) {
|
||||
// Set empty page view. We delay this so that the empty view won't flash.
|
||||
final ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub);
|
||||
mEmptyView = emptyViewStub.inflate();
|
||||
|
||||
final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image);
|
||||
emptyIcon.setImageResource(R.drawable.icon_bookmarks_empty);
|
||||
|
||||
final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text);
|
||||
emptyText.setText(R.string.home_bookmarks_empty);
|
||||
|
||||
mList.setEmptyView(mEmptyView);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loader for the list for bookmarks.
|
||||
*/
|
||||
@ -167,6 +190,7 @@ public class BookmarksPage extends HomeFragment {
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
|
||||
mListAdapter.swapCursor(c);
|
||||
updateUiFromCursor(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -140,7 +140,13 @@ public class BrowserSearch extends HomeFragment
|
||||
}
|
||||
|
||||
public static BrowserSearch newInstance() {
|
||||
return new BrowserSearch();
|
||||
BrowserSearch browserSearch = new BrowserSearch();
|
||||
|
||||
final Bundle args = new Bundle();
|
||||
args.putBoolean(HomePager.CAN_LOAD_ARG, true);
|
||||
browserSearch.setArguments(args);
|
||||
|
||||
return browserSearch;
|
||||
}
|
||||
|
||||
public BrowserSearch() {
|
||||
@ -282,7 +288,7 @@ public class BrowserSearch extends HomeFragment
|
||||
registerForContextMenu(mList);
|
||||
registerEventListener("SearchEngines:Data");
|
||||
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null));
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -315,7 +321,7 @@ public class BrowserSearch extends HomeFragment
|
||||
|
||||
@Override
|
||||
protected void load() {
|
||||
getLoaderManager().initLoader(LOADER_ID_SEARCH, null, mCursorLoaderCallbacks);
|
||||
SearchLoader.init(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm);
|
||||
}
|
||||
|
||||
private void handleAutocomplete(String searchTerm, Cursor c) {
|
||||
@ -606,7 +612,7 @@ public class BrowserSearch extends HomeFragment
|
||||
mAdapter.notifyDataSetChanged();
|
||||
|
||||
// Restart loaders with the new search term
|
||||
SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm, false);
|
||||
SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm);
|
||||
filterSuggestions();
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ public class LastTabsPage extends HomeFragment {
|
||||
|
||||
private static class LastTabsAdapter extends CursorAdapter {
|
||||
public LastTabsAdapter(Context context) {
|
||||
super(context, null);
|
||||
super(context, null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,7 +25,7 @@ abstract class MultiTypeCursorAdapter extends CursorAdapter {
|
||||
abstract public void bindView(View view, Context context, int position);
|
||||
|
||||
public MultiTypeCursorAdapter(Context context, Cursor cursor, int[] viewTypes, int[] layouts) {
|
||||
super(context, cursor);
|
||||
super(context, cursor, 0);
|
||||
|
||||
if (viewTypes.length != layouts.length) {
|
||||
throw new IllegalStateException("The view types and the layouts should be of same size");
|
||||
|
@ -178,7 +178,7 @@ class PinSiteDialog extends DialogFragment {
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
public SearchAdapter(Context context) {
|
||||
super(context, null);
|
||||
super(context, null, 0);
|
||||
mInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ public class ReadingListPage extends HomeFragment {
|
||||
*/
|
||||
private class ReadingListAdapter extends CursorAdapter {
|
||||
public ReadingListAdapter(Context context, Cursor cursor) {
|
||||
super(context, cursor);
|
||||
super(context, cursor, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,33 +22,35 @@ class SearchLoader {
|
||||
// Key for search terms
|
||||
private static final String KEY_SEARCH_TERM = "search_term";
|
||||
|
||||
// Key for performing empty search
|
||||
private static final String KEY_PERFORM_EMPTY_SEARCH = "perform_empty_search";
|
||||
|
||||
private SearchLoader() {
|
||||
}
|
||||
|
||||
public static Loader<Cursor> createInstance(Context context, Bundle args) {
|
||||
if (args != null) {
|
||||
final String searchTerm = args.getString(KEY_SEARCH_TERM);
|
||||
final boolean performEmptySearch = args.getBoolean(KEY_PERFORM_EMPTY_SEARCH, false);
|
||||
return new SearchCursorLoader(context, searchTerm, performEmptySearch);
|
||||
return new SearchCursorLoader(context, searchTerm);
|
||||
} else {
|
||||
return new SearchCursorLoader(context, "", false);
|
||||
return new SearchCursorLoader(context, "");
|
||||
}
|
||||
}
|
||||
|
||||
private static Bundle createArgs(String searchTerm) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(SearchLoader.KEY_SEARCH_TERM, searchTerm);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
public static void init(LoaderManager manager, int loaderId,
|
||||
LoaderCallbacks<Cursor> callbacks, String searchTerm) {
|
||||
final Bundle args = createArgs(searchTerm);
|
||||
manager.initLoader(loaderId, args, callbacks);
|
||||
}
|
||||
|
||||
public static void restart(LoaderManager manager, int loaderId,
|
||||
LoaderCallbacks<Cursor> callbacks, String searchTerm) {
|
||||
restart(manager, loaderId, callbacks, searchTerm, true);
|
||||
}
|
||||
|
||||
public static void restart(LoaderManager manager, int loaderId,
|
||||
LoaderCallbacks<Cursor> callbacks, String searchTerm, boolean performEmptySearch) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(SearchLoader.KEY_SEARCH_TERM, searchTerm);
|
||||
bundle.putBoolean(SearchLoader.KEY_PERFORM_EMPTY_SEARCH, performEmptySearch);
|
||||
manager.restartLoader(loaderId, bundle, callbacks);
|
||||
final Bundle args = createArgs(searchTerm);
|
||||
manager.restartLoader(loaderId, args, callbacks);
|
||||
}
|
||||
|
||||
public static class SearchCursorLoader extends SimpleCursorLoader {
|
||||
@ -58,21 +60,13 @@ class SearchLoader {
|
||||
// The target search term associated with the loader
|
||||
private final String mSearchTerm;
|
||||
|
||||
// An empty search on the DB
|
||||
private final boolean mPerformEmptySearch;
|
||||
|
||||
public SearchCursorLoader(Context context, String searchTerm, boolean performEmptySearch) {
|
||||
public SearchCursorLoader(Context context, String searchTerm) {
|
||||
super(context);
|
||||
mSearchTerm = searchTerm;
|
||||
mPerformEmptySearch = performEmptySearch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor loadCursor() {
|
||||
if (!mPerformEmptySearch && TextUtils.isEmpty(mSearchTerm)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return BrowserDB.filter(getContext().getContentResolver(), mSearchTerm, SEARCH_LIMIT);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import org.mozilla.gecko.util.StringUtils;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Rect;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
@ -32,9 +33,9 @@ import java.util.EnumSet;
|
||||
public class TopSitesGridView extends GridView {
|
||||
private static final String LOGTAG = "GeckoTopSitesGridView";
|
||||
|
||||
// Listener for pinning sites.
|
||||
public static interface OnPinSiteListener {
|
||||
public void onPinSite(int position);
|
||||
// Listener for editing pinned sites.
|
||||
public static interface OnEditPinnedSiteListener {
|
||||
public void onEditPinnedSite(int position);
|
||||
}
|
||||
|
||||
// Max number of top sites that needs to be shown.
|
||||
@ -58,12 +59,17 @@ public class TopSitesGridView extends GridView {
|
||||
// On URL open listener.
|
||||
private OnUrlOpenListener mUrlOpenListener;
|
||||
|
||||
// Pin site listener.
|
||||
private OnPinSiteListener mPinSiteListener;
|
||||
// Edit pinned site listener.
|
||||
private OnEditPinnedSiteListener mEditPinnedSiteListener;
|
||||
|
||||
// Context menu info.
|
||||
private TopSitesGridContextMenuInfo mContextMenuInfo;
|
||||
|
||||
// Whether we're handling focus changes or not. This is used
|
||||
// to avoid infinite re-layouts when using this GridView as
|
||||
// a ListView header view (see bug 918044).
|
||||
private boolean mIsHandlingFocusChange;
|
||||
|
||||
public TopSitesGridView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@ -82,6 +88,8 @@ public class TopSitesGridView extends GridView {
|
||||
mHorizontalSpacing = a.getDimensionPixelOffset(R.styleable.TopSitesGridView_android_horizontalSpacing, 0x00);
|
||||
mVerticalSpacing = a.getDimensionPixelOffset(R.styleable.TopSitesGridView_android_verticalSpacing, 0x00);
|
||||
a.recycle();
|
||||
|
||||
mIsHandlingFocusChange = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,8 +114,8 @@ public class TopSitesGridView extends GridView {
|
||||
mUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
|
||||
}
|
||||
} else {
|
||||
if (mPinSiteListener != null) {
|
||||
mPinSiteListener.onPinSite(position);
|
||||
if (mEditPinnedSiteListener != null) {
|
||||
mEditPinnedSiteListener.onEditPinnedSite(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,7 +136,21 @@ public class TopSitesGridView extends GridView {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
mUrlOpenListener = null;
|
||||
mPinSiteListener = null;
|
||||
mEditPinnedSiteListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
|
||||
mIsHandlingFocusChange = true;
|
||||
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
|
||||
mIsHandlingFocusChange = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
if (!mIsHandlingFocusChange) {
|
||||
super.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,12 +229,12 @@ public class TopSitesGridView extends GridView {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pin site listener to be used by this view.
|
||||
* Set an edit pinned site listener to be used by this view.
|
||||
*
|
||||
* @param listener A pin site listener for this view.
|
||||
* @param listener An edit pinned site listener for this view.
|
||||
*/
|
||||
public void setOnPinSiteListener(OnPinSiteListener listener) {
|
||||
mPinSiteListener = listener;
|
||||
public void setOnEditPinnedSiteListener(final OnEditPinnedSiteListener listener) {
|
||||
mEditPinnedSiteListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,7 @@ import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.home.HomeListView.HomeContextMenuInfo;
|
||||
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
||||
import org.mozilla.gecko.home.PinSiteDialog.OnSiteSelectedListener;
|
||||
import org.mozilla.gecko.home.TopSitesGridView.OnPinSiteListener;
|
||||
import org.mozilla.gecko.home.TopSitesGridView.OnEditPinnedSiteListener;
|
||||
import org.mozilla.gecko.home.TopSitesGridView.TopSitesGridContextMenuInfo;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
@ -100,8 +100,8 @@ public class TopSitesPage extends HomeFragment {
|
||||
// Callback for thumbnail loader
|
||||
private ThumbnailsLoaderCallbacks mThumbnailsLoaderCallbacks;
|
||||
|
||||
// Listener for pinning sites
|
||||
private PinSiteListener mPinSiteListener;
|
||||
// Listener for editing pinned sites.
|
||||
private EditPinnedSiteListener mEditPinnedSiteListener;
|
||||
|
||||
// On URL open listener
|
||||
private OnUrlOpenListener mUrlOpenListener;
|
||||
@ -155,7 +155,7 @@ public class TopSitesPage extends HomeFragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
mPinSiteListener = new PinSiteListener();
|
||||
mEditPinnedSiteListener = new EditPinnedSiteListener();
|
||||
|
||||
mList.setTag(HomePager.LIST_TAG_TOP_SITES);
|
||||
mList.setHeaderDividersEnabled(false);
|
||||
@ -186,7 +186,7 @@ public class TopSitesPage extends HomeFragment {
|
||||
});
|
||||
|
||||
mGrid.setOnUrlOpenListener(mUrlOpenListener);
|
||||
mGrid.setOnPinSiteListener(mPinSiteListener);
|
||||
mGrid.setOnEditPinnedSiteListener(mEditPinnedSiteListener);
|
||||
|
||||
registerForContextMenu(mList);
|
||||
registerForContextMenu(mGrid);
|
||||
@ -338,7 +338,7 @@ public class TopSitesPage extends HomeFragment {
|
||||
}
|
||||
|
||||
if (itemId == R.id.top_sites_edit) {
|
||||
mPinSiteListener.onPinSite(info.position);
|
||||
mEditPinnedSiteListener.onEditPinnedSite(info.position);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -371,10 +371,10 @@ public class TopSitesPage extends HomeFragment {
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for pinning sites.
|
||||
* Listener for editing pinned sites.
|
||||
*/
|
||||
private class PinSiteListener implements OnPinSiteListener,
|
||||
OnSiteSelectedListener {
|
||||
private class EditPinnedSiteListener implements OnEditPinnedSiteListener,
|
||||
OnSiteSelectedListener {
|
||||
// Tag for the PinSiteDialog fragment.
|
||||
private static final String TAG_PIN_SITE = "pin_site";
|
||||
|
||||
@ -382,7 +382,7 @@ public class TopSitesPage extends HomeFragment {
|
||||
private int mPosition;
|
||||
|
||||
@Override
|
||||
public void onPinSite(int position) {
|
||||
public void onEditPinnedSite(int position) {
|
||||
mPosition = position;
|
||||
|
||||
final FragmentManager manager = getActivity().getSupportFragmentManager();
|
||||
@ -485,7 +485,7 @@ public class TopSitesPage extends HomeFragment {
|
||||
|
||||
private class VisitedAdapter extends CursorAdapter {
|
||||
public VisitedAdapter(Context context, Cursor cursor) {
|
||||
super(context, cursor);
|
||||
super(context, cursor, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -518,7 +518,7 @@ public class TopSitesPage extends HomeFragment {
|
||||
private Map<String, Bitmap> mThumbnails;
|
||||
|
||||
public TopSitesGridAdapter(Context context, Cursor cursor) {
|
||||
super(context, cursor);
|
||||
super(context, cursor, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -275,6 +275,7 @@ size. -->
|
||||
<!ENTITY home_top_sites_add "Add a site">
|
||||
|
||||
<!ENTITY home_history_title "History">
|
||||
<!ENTITY home_bookmarks_empty "Bookmarks you save show up here.">
|
||||
<!ENTITY home_last_tabs_title "Tabs from last time">
|
||||
<!ENTITY home_last_tabs_open "Open all tabs from last time">
|
||||
<!ENTITY home_last_tabs_empty "Your recent tabs show up here.">
|
||||
|
@ -141,7 +141,8 @@ public class SearchEnginePreference extends Preference implements View.OnLongCli
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if this object's UI should show that this is the default engine.
|
||||
* Set if this object's UI should show that this is the default engine. To ensure proper ordering,
|
||||
* this method should only be called after this Preference is added to the PreferenceCategory.
|
||||
* @param isDefault Flag indicating if this represents the default engine.
|
||||
*/
|
||||
public void setIsDefaultEngine(boolean isDefault) {
|
||||
@ -206,7 +207,9 @@ public class SearchEnginePreference extends Preference implements View.OnLongCli
|
||||
if (mPromptIcon == null && mIconBitmap != null) {
|
||||
mPromptIcon = new BitmapDrawable(mFaviconView.getBitmap());
|
||||
}
|
||||
builder.setIcon(mPromptIcon);
|
||||
|
||||
// Icons are hidden until Bug 926711 is fixed.
|
||||
//builder.setIcon(mPromptIcon);
|
||||
|
||||
// We have to construct the dialog itself on the UI thread.
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
|
@ -41,7 +41,7 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
|
||||
super.onAttachedToActivity();
|
||||
|
||||
// Ensures default engine remains at top of list.
|
||||
setOrderingAsAdded(false);
|
||||
setOrderingAsAdded(true);
|
||||
|
||||
// Request list of search engines from Gecko.
|
||||
GeckoAppShell.registerEventListener("SearchEngines:Data", this);
|
||||
@ -51,17 +51,14 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
|
||||
@Override
|
||||
public void handleMessage(String event, final JSONObject data) {
|
||||
if (event.equals("SearchEngines:Data")) {
|
||||
// Parse engines array from JSON. The first element in the array is the default engine.
|
||||
// We are no longer interested in this event from Gecko, as we do not request it again with
|
||||
// this instance.
|
||||
GeckoAppShell.unregisterEventListener("SearchEngines:Data", this);
|
||||
|
||||
// Parse engines array from JSON.
|
||||
JSONArray engines;
|
||||
JSONObject defaultEngine;
|
||||
final String defaultEngineName;
|
||||
try {
|
||||
engines = data.getJSONArray("searchEngines");
|
||||
if (engines.length() == 0) {
|
||||
return;
|
||||
}
|
||||
defaultEngine = engines.getJSONObject(0);
|
||||
defaultEngineName = defaultEngine.getString("name");
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Unable to decode search engine data from Gecko.", e);
|
||||
return;
|
||||
@ -75,14 +72,6 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
|
||||
|
||||
SearchEnginePreference enginePreference = new SearchEnginePreference(getContext(), this);
|
||||
enginePreference.setSearchEngineFromJSON(engineJSON);
|
||||
if (engineName.equals(defaultEngineName)) {
|
||||
// We set this here, not in setSearchEngineFromJSON, because it allows us to
|
||||
// keep a reference to the default engine to use when the AlertDialog
|
||||
// callbacks are used.
|
||||
enginePreference.setIsDefaultEngine(true);
|
||||
mDefaultEngineReference = enginePreference;
|
||||
}
|
||||
|
||||
enginePreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
@ -94,15 +83,20 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
|
||||
});
|
||||
|
||||
addPreference(enginePreference);
|
||||
|
||||
// The first element in the array is the default engine.
|
||||
if (i == 0) {
|
||||
// We set this here, not in setSearchEngineFromJSON, because it allows us to
|
||||
// keep a reference to the default engine to use when the AlertDialog
|
||||
// callbacks are used.
|
||||
enginePreference.setIsDefaultEngine(true);
|
||||
mDefaultEngineReference = enginePreference;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "JSONException parsing engine at index " + i, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are no longer interested in this event from Gecko, as we do not request it again with
|
||||
// this instance.
|
||||
GeckoAppShell.unregisterEventListener("SearchEngines:Data", this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 997 B |
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
@ -7,6 +7,11 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ViewStub android:id="@+id/home_empty_view_stub"
|
||||
android:layout="@layout/home_empty_page"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<org.mozilla.gecko.home.BookmarksListView
|
||||
android:id="@+id/bookmarks_list"
|
||||
android:layout_width="fill_parent"
|
||||
|
@ -257,6 +257,7 @@
|
||||
<string name="home_top_sites_title">&home_top_sites_title;</string>
|
||||
<string name="home_top_sites_add">&home_top_sites_add;</string>
|
||||
<string name="home_history_title">&home_history_title;</string>
|
||||
<string name="home_bookmarks_empty">&home_bookmarks_empty;</string>
|
||||
<string name="home_last_tabs_title">&home_last_tabs_title;</string>
|
||||
<string name="home_last_tabs_open">&home_last_tabs_open;</string>
|
||||
<string name="home_last_tabs_empty">&home_last_tabs_empty;</string>
|
||||
|
@ -98,7 +98,7 @@ PromiseWorker.prototype = {
|
||||
* @param {Error} error Some JS error.
|
||||
*/
|
||||
worker.onerror = function onerror(error) {
|
||||
self._log("Received uncaught error from worker", error.message);
|
||||
self._log("Received uncaught error from worker", error.message, error.filename, error.lineno);
|
||||
error.preventDefault();
|
||||
let {deferred} = self._queue.pop();
|
||||
deferred.reject(error);
|
||||
|
@ -29,24 +29,21 @@ Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAl
|
||||
Cu.import("resource://gre/modules/Deprecated.jsm", this);
|
||||
|
||||
// Boilerplate, to simplify the transition to require()
|
||||
let OS = SharedAll.OS;
|
||||
|
||||
let LOG = OS.Shared.LOG.bind(OS.Shared, "Controller");
|
||||
|
||||
let isTypedArray = OS.Shared.isTypedArray;
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Controller");
|
||||
let isTypedArray = SharedAll.isTypedArray;
|
||||
|
||||
// The constructor for file errors.
|
||||
let OSError;
|
||||
if (OS.Constants.Win) {
|
||||
Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", this);
|
||||
OSError = OS.Shared.Win.Error;
|
||||
} else if (OS.Constants.libc) {
|
||||
Cu.import("resource://gre/modules/osfile/osfile_unix_allthreads.jsm", this);
|
||||
OSError = OS.Shared.Unix.Error;
|
||||
let SysAll = {};
|
||||
if (SharedAll.Constants.Win) {
|
||||
Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", SysAll);
|
||||
} else if (SharedAll.Constants.libc) {
|
||||
Cu.import("resource://gre/modules/osfile/osfile_unix_allthreads.jsm", SysAll);
|
||||
} else {
|
||||
throw new Error("I am neither under Windows nor under a Posix system");
|
||||
}
|
||||
let Type = OS.Shared.Type;
|
||||
let OSError = SysAll.Error;
|
||||
let Type = SysAll.Type;
|
||||
|
||||
let Path = {};
|
||||
Cu.import("resource://gre/modules/osfile/ospath.jsm", Path);
|
||||
|
||||
@ -60,18 +57,16 @@ Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
|
||||
Cu.import("resource://gre/modules/AsyncShutdown.jsm", this);
|
||||
|
||||
LOG("Checking profileDir", OS.Constants.Path);
|
||||
|
||||
// If profileDir is not available, osfile.jsm has been imported before the
|
||||
// profile is setup. In this case, make this a lazy getter.
|
||||
if (!("profileDir" in OS.Constants.Path)) {
|
||||
Object.defineProperty(OS.Constants.Path, "profileDir", {
|
||||
if (!("profileDir" in SharedAll.Constants.Path)) {
|
||||
Object.defineProperty(SharedAll.Constants.Path, "profileDir", {
|
||||
get: function() {
|
||||
let path = undefined;
|
||||
try {
|
||||
path = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
|
||||
delete OS.Constants.Path.profileDir;
|
||||
OS.Constants.Path.profileDir = path;
|
||||
delete SharedAll.Constants.Path.profileDir;
|
||||
SharedAll.Constants.Path.profileDir = path;
|
||||
} catch (ex) {
|
||||
// Ignore errors: profileDir is still not available
|
||||
}
|
||||
@ -82,14 +77,14 @@ if (!("profileDir" in OS.Constants.Path)) {
|
||||
|
||||
LOG("Checking localProfileDir");
|
||||
|
||||
if (!("localProfileDir" in OS.Constants.Path)) {
|
||||
Object.defineProperty(OS.Constants.Path, "localProfileDir", {
|
||||
if (!("localProfileDir" in SharedAll.Constants.Path)) {
|
||||
Object.defineProperty(SharedAll.Constants.Path, "localProfileDir", {
|
||||
get: function() {
|
||||
let path = undefined;
|
||||
try {
|
||||
path = Services.dirsvc.get("ProfLD", Ci.nsIFile).path;
|
||||
delete OS.Constants.Path.localProfileDir;
|
||||
OS.Constants.Path.localProfileDir = path;
|
||||
delete SharedAll.Constants.Path.localProfileDir;
|
||||
SharedAll.Constants.Path.localProfileDir = path;
|
||||
} catch (ex) {
|
||||
// Ignore errors: localProfileDir is still not available
|
||||
}
|
||||
@ -123,7 +118,7 @@ let Scheduler = {
|
||||
latestPromise: Promise.resolve("OS.File scheduler hasn't been launched yet"),
|
||||
|
||||
post: function post(...args) {
|
||||
if (!this.launched && OS.Shared.DEBUG) {
|
||||
if (!this.launched && SharedAll.Config.DEBUG) {
|
||||
// If we have delayed sending SET_DEBUG, do it now.
|
||||
worker.post("SET_DEBUG", [true]);
|
||||
}
|
||||
@ -212,23 +207,23 @@ let readDebugPref = function readDebugPref(prefName, oldPref = false) {
|
||||
*/
|
||||
Services.prefs.addObserver(PREF_OSFILE_LOG,
|
||||
function prefObserver(aSubject, aTopic, aData) {
|
||||
OS.Shared.DEBUG = readDebugPref(PREF_OSFILE_LOG, OS.Shared.DEBUG);
|
||||
SharedAll.Config.DEBUG = readDebugPref(PREF_OSFILE_LOG, SharedAll.Config.DEBUG);
|
||||
if (Scheduler.launched) {
|
||||
// Don't start the worker just to set this preference.
|
||||
Scheduler.post("SET_DEBUG", [OS.Shared.DEBUG]);
|
||||
Scheduler.post("SET_DEBUG", [SharedAll.Config.DEBUG]);
|
||||
}
|
||||
}, false);
|
||||
OS.Shared.DEBUG = readDebugPref(PREF_OSFILE_LOG, false);
|
||||
SharedAll.Config.DEBUG = readDebugPref(PREF_OSFILE_LOG, false);
|
||||
|
||||
Services.prefs.addObserver(PREF_OSFILE_LOG_REDIRECT,
|
||||
function prefObserver(aSubject, aTopic, aData) {
|
||||
OS.Shared.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, OS.Shared.TEST);
|
||||
SharedAll.Config.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, OS.Shared.TEST);
|
||||
}, false);
|
||||
OS.Shared.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, false);
|
||||
SharedAll.Config.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, false);
|
||||
|
||||
// Update worker's DEBUG flag if it's true.
|
||||
// Don't start the worker just for this, though.
|
||||
if (OS.Shared.DEBUG && Scheduler.launched) {
|
||||
if (SharedAll.Config.DEBUG && Scheduler.launched) {
|
||||
Scheduler.post("SET_DEBUG", [true]);
|
||||
}
|
||||
|
||||
@ -507,6 +502,35 @@ File.open = function open(path, mode, options) {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and opens a file with a unique name. By default, generate a random HEX number and use it to create a unique new file name.
|
||||
*
|
||||
* @param {string} path The path to the file.
|
||||
* @param {*=} options Additional options for file opening. This
|
||||
* implementation interprets the following fields:
|
||||
*
|
||||
* - {number} humanReadable If |true|, create a new filename appending a decimal number. ie: filename-1.ext, filename-2.ext.
|
||||
* If |false| use HEX numbers ie: filename-A65BC0.ext
|
||||
* - {number} maxReadableNumber Used to limit the amount of tries after a failed
|
||||
* file creation. Default is 20.
|
||||
*
|
||||
* @return {Object} contains A file object{file} and the path{path}.
|
||||
* @throws {OS.File.Error} If the file could not be opened.
|
||||
*/
|
||||
File.openUnique = function openUnique(path, options) {
|
||||
return Scheduler.post(
|
||||
"openUnique", [Type.path.toMsg(path), options],
|
||||
path
|
||||
).then(
|
||||
function onSuccess(msg) {
|
||||
return {
|
||||
path: msg.path,
|
||||
file: new File(msg.file)
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the information on the file.
|
||||
*
|
||||
@ -769,13 +793,7 @@ File.Info = function Info(value) {
|
||||
}
|
||||
Object.defineProperty(this, "_deprecatedCreationDate", {value: value["creationDate"]});
|
||||
};
|
||||
if (OS.Constants.Win) {
|
||||
File.Info.prototype = Object.create(OS.Shared.Win.AbstractInfo.prototype);
|
||||
} else if (OS.Constants.libc) {
|
||||
File.Info.prototype = Object.create(OS.Shared.Unix.AbstractInfo.prototype);
|
||||
} else {
|
||||
throw new Error("I am neither under Windows nor under a Posix system");
|
||||
}
|
||||
File.Info.prototype = SysAll.AbstractInfo.prototype;
|
||||
|
||||
// Deprecated
|
||||
Object.defineProperty(File.Info.prototype, "creationDate", {
|
||||
@ -971,26 +989,35 @@ DirectoryIterator.prototype = {
|
||||
DirectoryIterator.Entry = function Entry(value) {
|
||||
return value;
|
||||
};
|
||||
if (OS.Constants.Win) {
|
||||
DirectoryIterator.Entry.prototype = Object.create(OS.Shared.Win.AbstractEntry.prototype);
|
||||
} else if (OS.Constants.libc) {
|
||||
DirectoryIterator.Entry.prototype = Object.create(OS.Shared.Unix.AbstractEntry.prototype);
|
||||
} else {
|
||||
throw new Error("I am neither under Windows nor under a Posix system");
|
||||
}
|
||||
DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
|
||||
|
||||
DirectoryIterator.Entry.fromMsg = function fromMsg(value) {
|
||||
return new DirectoryIterator.Entry(value);
|
||||
};
|
||||
|
||||
// Constants
|
||||
Object.defineProperty(File, "POS_START", {value: OS.Shared.POS_START});
|
||||
Object.defineProperty(File, "POS_CURRENT", {value: OS.Shared.POS_CURRENT});
|
||||
Object.defineProperty(File, "POS_END", {value: OS.Shared.POS_END});
|
||||
File.POS_START = SysAll.POS_START;
|
||||
File.POS_CURRENT = SysAll.POS_CURRENT;
|
||||
File.POS_END = SysAll.POS_END;
|
||||
|
||||
// Exports
|
||||
File.Error = OSError;
|
||||
File.DirectoryIterator = DirectoryIterator;
|
||||
|
||||
this.OS = {};
|
||||
OS.File = File;
|
||||
OS.File.Error = OSError;
|
||||
OS.File.DirectoryIterator = DirectoryIterator;
|
||||
OS.Constants = SharedAll.Constants;
|
||||
OS.Shared = {
|
||||
LOG: SharedAll.LOG,
|
||||
Type: SysAll.Type,
|
||||
get DEBUG() {
|
||||
return SharedAll.Config.DEBUG;
|
||||
},
|
||||
set DEBUG(x) {
|
||||
return SharedAll.Config.DEBUG = x;
|
||||
}
|
||||
};
|
||||
Object.freeze(OS.Shared);
|
||||
OS.Path = Path;
|
||||
|
||||
|
||||
|
@ -14,7 +14,8 @@ if (this.Components) {
|
||||
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
|
||||
let LOG = exports.OS.Shared.LOG.bind(exports.OS.Shared.LOG, "Agent");
|
||||
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Agent");
|
||||
|
||||
/**
|
||||
* Communications with the controller.
|
||||
@ -216,12 +217,12 @@ if (this.Components) {
|
||||
let Agent = {
|
||||
// Update worker's OS.Shared.DEBUG flag message from controller.
|
||||
SET_DEBUG: function SET_DEBUG (aDEBUG) {
|
||||
exports.OS.Shared.DEBUG = aDEBUG;
|
||||
SharedAll.Config.DEBUG = aDEBUG;
|
||||
},
|
||||
// Return worker's current OS.Shared.DEBUG value to controller.
|
||||
// Note: This is used for testing purposes.
|
||||
GET_DEBUG: function GET_DEBUG () {
|
||||
return exports.OS.Shared.DEBUG;
|
||||
return SharedAll.Config.DEBUG;
|
||||
},
|
||||
// Report file descriptors leaks.
|
||||
System_shutdown: function System_shutdown () {
|
||||
@ -270,6 +271,20 @@ if (this.Components) {
|
||||
path: filePath
|
||||
});
|
||||
},
|
||||
openUnique: function openUnique(path, options) {
|
||||
let filePath = Type.path.fromMsg(path);
|
||||
let openedFile = OS.Shared.AbstractFile.openUnique(filePath, options);
|
||||
let resourceId = OpenedFiles.add(openedFile.file, {
|
||||
// Adding path information to keep track of opened files
|
||||
// to report leaks when debugging.
|
||||
path: openedFile.path
|
||||
});
|
||||
|
||||
return {
|
||||
path: openedFile.path,
|
||||
file: resourceId
|
||||
};
|
||||
},
|
||||
read: function read(path, bytes, options) {
|
||||
let data = File.read(Type.path.fromMsg(path), bytes, options);
|
||||
return new Transfer({buffer: data.buffer, byteOffset: data.byteOffset, byteLength: data.byteLength}, [data.buffer]);
|
||||
|
@ -1026,11 +1026,6 @@ exports.OS = {
|
||||
offsetBy: offsetBy
|
||||
}
|
||||
};
|
||||
if (exports.Constants.Win) {
|
||||
exports.OS.Win = {};
|
||||
} else {
|
||||
exports.OS.Unix = {};
|
||||
}
|
||||
|
||||
Object.defineProperty(exports.OS.Shared, "DEBUG", {
|
||||
get: function() {
|
||||
|
@ -14,10 +14,11 @@ if (typeof Components != "undefined") {
|
||||
}
|
||||
(function(exports) {
|
||||
|
||||
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
|
||||
let SharedAll =
|
||||
require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
|
||||
let LOG = exports.OS.Shared.LOG.bind(OS.Shared, "Shared front-end");
|
||||
let clone = exports.OS.Shared.clone;
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Shared front-end");
|
||||
let clone = SharedAll.clone;
|
||||
|
||||
/**
|
||||
* Code shared by implementations of File.
|
||||
@ -89,7 +90,7 @@ AbstractFile.prototype = {
|
||||
break;
|
||||
}
|
||||
pos += chunkSize;
|
||||
ptr = exports.OS.Shared.offsetBy(ptr, chunkSize);
|
||||
ptr = SharedAll.offsetBy(ptr, chunkSize);
|
||||
}
|
||||
|
||||
return pos;
|
||||
@ -121,12 +122,70 @@ AbstractFile.prototype = {
|
||||
while (pos < bytes) {
|
||||
let chunkSize = this._write(ptr, bytes - pos, options);
|
||||
pos += chunkSize;
|
||||
ptr = exports.OS.Shared.offsetBy(ptr, chunkSize);
|
||||
ptr = SharedAll.offsetBy(ptr, chunkSize);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and opens a file with a unique name. By default, generate a random HEX number and use it to create a unique new file name.
|
||||
*
|
||||
* @param {string} path The path to the file.
|
||||
* @param {*=} options Additional options for file opening. This
|
||||
* implementation interprets the following fields:
|
||||
*
|
||||
* - {number} humanReadable If |true|, create a new filename appending a decimal number. ie: filename-1.ext, filename-2.ext.
|
||||
* If |false| use HEX numbers ie: filename-A65BC0.ext
|
||||
* - {number} maxReadableNumber Used to limit the amount of tries after a failed
|
||||
* file creation. Default is 20.
|
||||
*
|
||||
* @return {Object} contains A file object{file} and the path{path}.
|
||||
* @throws {OS.File.Error} If the file could not be opened.
|
||||
*/
|
||||
AbstractFile.openUnique = function openUnique(path, options = {}) {
|
||||
let mode = {
|
||||
create : true
|
||||
};
|
||||
|
||||
let dirName = OS.Path.dirname(path);
|
||||
let leafName = OS.Path.basename(path);
|
||||
let lastDotCharacter = leafName.lastIndexOf('.');
|
||||
let fileName = leafName.substring(0, lastDotCharacter != -1 ? lastDotCharacter : leafName.length);
|
||||
let suffix = (lastDotCharacter != -1 ? leafName.substring(lastDotCharacter) : "");
|
||||
let uniquePath = "";
|
||||
let maxAttempts = options.maxAttempts || 99;
|
||||
let humanReadable = !!options.humanReadable;
|
||||
const HEX_RADIX = 16;
|
||||
// We produce HEX numbers between 0 and 2^24 - 1.
|
||||
const MAX_HEX_NUMBER = 16777215;
|
||||
|
||||
try {
|
||||
return {
|
||||
path: path,
|
||||
file: OS.File.open(path, mode)
|
||||
};
|
||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) {
|
||||
for (let i = 0; i < maxAttempts; ++i) {
|
||||
try {
|
||||
if (humanReadable) {
|
||||
uniquePath = OS.Path.join(dirName, fileName + "-" + (i + 1) + suffix);
|
||||
} else {
|
||||
let hexNumber = Math.floor(Math.random() * MAX_HEX_NUMBER).toString(HEX_RADIX);
|
||||
uniquePath = OS.Path.join(dirName, fileName + "-" + hexNumber + suffix);
|
||||
}
|
||||
return {
|
||||
path: uniquePath,
|
||||
file: OS.File.open(uniquePath, mode)
|
||||
};
|
||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) {
|
||||
// keep trying ...
|
||||
}
|
||||
}
|
||||
throw OS.File.Error.exists("could not find an unused file name.");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function used to normalize a Typed Array or C
|
||||
* pointer into a uint8_t C pointer.
|
||||
@ -150,13 +209,13 @@ AbstractFile.normalizeToPointer = function normalizeToPointer(candidate, bytes)
|
||||
if (candidate.isNull()) {
|
||||
throw new TypeError("Expecting a non-null pointer");
|
||||
}
|
||||
ptr = exports.OS.Shared.Type.uint8_t.out_ptr.cast(candidate);
|
||||
ptr = SharedAll.Type.uint8_t.out_ptr.cast(candidate);
|
||||
if (bytes == null) {
|
||||
throw new TypeError("C pointer missing bytes indication.");
|
||||
}
|
||||
} else if (exports.OS.Shared.isTypedArray(candidate)) {
|
||||
} else if (SharedAll.isTypedArray(candidate)) {
|
||||
// Typed Array
|
||||
ptr = exports.OS.Shared.Type.uint8_t.out_ptr.implementation(candidate.buffer);
|
||||
ptr = SharedAll.Type.uint8_t.out_ptr.implementation(candidate.buffer);
|
||||
if (bytes == null) {
|
||||
bytes = candidate.byteLength;
|
||||
} else if (candidate.byteLength < bytes) {
|
||||
@ -430,5 +489,8 @@ AbstractFile.removeDir = function(path, options = {}) {
|
||||
OS.File.removeEmptyDir(path);
|
||||
};
|
||||
|
||||
exports.OS.Shared.AbstractFile = AbstractFile;
|
||||
if (!exports.OS.Shared) {
|
||||
exports.OS.Shared = {};
|
||||
}
|
||||
exports.OS.Shared.AbstractFile = AbstractFile;
|
||||
})(this);
|
||||
|
@ -14,323 +14,339 @@
|
||||
*
|
||||
* This module can be:
|
||||
* - opened from the main thread as a jsm module;
|
||||
* - opened from a chrome worker through importScripts.
|
||||
* - opened from a chrome worker through require().
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let SharedAll;
|
||||
if (typeof Components != "undefined") {
|
||||
let Cu = Components.utils;
|
||||
// Module is opened as a jsm module
|
||||
this.EXPORTED_SYMBOLS = ["OS"];
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://gre/modules/ctypes.jsm", this);
|
||||
|
||||
SharedAll = {};
|
||||
Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
|
||||
} else {
|
||||
Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
|
||||
this.exports = {};
|
||||
} else if (typeof "module" != "undefined" && typeof "require" != "undefined") {
|
||||
// Module is loaded with require()
|
||||
SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
} else {
|
||||
throw new Error("Please open this module with Component.utils.import or with require()");
|
||||
}
|
||||
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
if ("OS" in exports && "Shared" in exports.OS && "Unix" in exports.OS.Shared) {
|
||||
// Avoid double inclusion
|
||||
return;
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "allthreads");
|
||||
let Const = SharedAll.Constants.libc;
|
||||
|
||||
// Open libc
|
||||
let libc;
|
||||
let libc_candidates = [ "libSystem.B.dylib",
|
||||
"libc.so.6",
|
||||
"libc.so" ];
|
||||
for (let i = 0; i < libc_candidates.length; ++i) {
|
||||
try {
|
||||
libc = ctypes.open(libc_candidates[i]);
|
||||
break;
|
||||
} catch (x) {
|
||||
LOG("Could not open libc ", libc_candidates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
exports.OS = SharedAll.OS;
|
||||
if (!libc) {
|
||||
// Note: If you change the string here, please adapt tests accordingly
|
||||
throw new Error("Could not open system library: no libc");
|
||||
}
|
||||
exports.libc = libc;
|
||||
|
||||
exports.OS.Shared.Unix = {};
|
||||
// Define declareFFI
|
||||
let declareFFI = SharedAll.declareFFI.bind(null, libc);
|
||||
exports.declareFFI = declareFFI;
|
||||
|
||||
let LOG = OS.Shared.LOG.bind(OS.Shared, "Unix", "allthreads");
|
||||
// Define Error
|
||||
let strerror = libc.declare("strerror",
|
||||
ctypes.default_abi,
|
||||
/*return*/ ctypes.char.ptr,
|
||||
/*errnum*/ ctypes.int);
|
||||
|
||||
// Open libc
|
||||
let libc;
|
||||
let libc_candidates = [ "libSystem.B.dylib",
|
||||
"libc.so.6",
|
||||
"libc.so" ];
|
||||
for (let i = 0; i < libc_candidates.length; ++i) {
|
||||
try {
|
||||
libc = ctypes.open(libc_candidates[i]);
|
||||
break;
|
||||
} catch (x) {
|
||||
LOG("Could not open libc ", libc_candidates[i]);
|
||||
}
|
||||
/**
|
||||
* A File-related error.
|
||||
*
|
||||
* To obtain a human-readable error message, use method |toString|.
|
||||
* To determine the cause of the error, use the various |becauseX|
|
||||
* getters. To determine the operation that failed, use field
|
||||
* |operation|.
|
||||
*
|
||||
* Additionally, this implementation offers a field
|
||||
* |unixErrno|, which holds the OS-specific error
|
||||
* constant. If you need this level of detail, you may match the value
|
||||
* of this field against the error constants of |OS.Constants.libc|.
|
||||
*
|
||||
* @param {string=} operation The operation that failed. If unspecified,
|
||||
* the name of the calling function is taken to be the operation that
|
||||
* failed.
|
||||
* @param {number=} lastError The OS-specific constant detailing the
|
||||
* reason of the error. If unspecified, this is fetched from the system
|
||||
* status.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {OS.Shared.Error}
|
||||
*/
|
||||
let OSError = function OSError(operation, errno) {
|
||||
operation = operation || "unknown operation";
|
||||
SharedAll.OSError.call(this, operation);
|
||||
this.unixErrno = errno || ctypes.errno;
|
||||
};
|
||||
OSError.prototype = Object.create(SharedAll.OSError.prototype);
|
||||
OSError.prototype.toString = function toString() {
|
||||
return "Unix error " + this.unixErrno +
|
||||
" during operation " + this.operation +
|
||||
" (" + strerror(this.unixErrno).readString() + ")";
|
||||
};
|
||||
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* already exists, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseExists", {
|
||||
get: function becauseExists() {
|
||||
return this.unixErrno == Const.EEXIST;
|
||||
}
|
||||
if (!libc) {
|
||||
// Note: If you change the string here, please adapt tests accordingly
|
||||
throw new Error("Could not open system library: no libc");
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* does not exist, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
|
||||
get: function becauseNoSuchFile() {
|
||||
return this.unixErrno == Const.ENOENT;
|
||||
}
|
||||
exports.OS.Shared.Unix.libc = libc;
|
||||
});
|
||||
|
||||
// Define declareFFI
|
||||
let declareFFI = OS.Shared.declareFFI.bind(null, libc);
|
||||
exports.OS.Shared.Unix.declareFFI = declareFFI;
|
||||
/**
|
||||
* |true| if the error was raised because a directory is not empty
|
||||
* does not exist, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
|
||||
get: function becauseNotEmpty() {
|
||||
return this.unixErrno == Const.ENOTEMPTY;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* is closed, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseClosed", {
|
||||
get: function becauseClosed() {
|
||||
return this.unixErrno == Const.EBADF;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because permission is denied to
|
||||
* access a file or directory, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
|
||||
get: function becauseAccessDenied() {
|
||||
return this.unixErrno == Const.EACCES;
|
||||
}
|
||||
});
|
||||
|
||||
// Define Error
|
||||
let strerror = libc.declare("strerror",
|
||||
ctypes.default_abi,
|
||||
/*return*/ ctypes.char.ptr,
|
||||
/*errnum*/ ctypes.int);
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
* transmitted across threads (not necessarily a string).
|
||||
*/
|
||||
OSError.toMsg = function toMsg(error) {
|
||||
return {
|
||||
operation: error.operation,
|
||||
unixErrno: error.unixErrno
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Deserialize a message back to an instance of OSError
|
||||
*/
|
||||
OSError.fromMsg = function fromMsg(msg) {
|
||||
return new OSError(msg.operation, msg.unixErrno);
|
||||
};
|
||||
exports.Error = OSError;
|
||||
|
||||
/**
|
||||
* Code shared by implementations of File.Info on Unix
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
|
||||
lastModificationDate, unixLastStatusChangeDate,
|
||||
unixOwner, unixGroup, unixMode) {
|
||||
this._isDir = isDir;
|
||||
this._isSymlLink = isSymLink;
|
||||
this._size = size;
|
||||
this._lastAccessDate = lastAccessDate;
|
||||
this._lastModificationDate = lastModificationDate;
|
||||
this._unixLastStatusChangeDate = unixLastStatusChangeDate;
|
||||
this._unixOwner = unixOwner;
|
||||
this._unixGroup = unixGroup;
|
||||
this._unixMode = unixMode;
|
||||
};
|
||||
|
||||
AbstractInfo.prototype = {
|
||||
/**
|
||||
* A File-related error.
|
||||
* |true| if this file is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* |true| if this file is a symbolink link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return this._isSymlLink;
|
||||
},
|
||||
/**
|
||||
* The size of the file, in bytes.
|
||||
*
|
||||
* To obtain a human-readable error message, use method |toString|.
|
||||
* To determine the cause of the error, use the various |becauseX|
|
||||
* getters. To determine the operation that failed, use field
|
||||
* |operation|.
|
||||
* Note that the result may be |NaN| if the size of the file cannot be
|
||||
* represented in JavaScript.
|
||||
*
|
||||
* Additionally, this implementation offers a field
|
||||
* |unixErrno|, which holds the OS-specific error
|
||||
* constant. If you need this level of detail, you may match the value
|
||||
* of this field against the error constants of |OS.Constants.libc|.
|
||||
* @type {number}
|
||||
*/
|
||||
get size() {
|
||||
return this._size;
|
||||
},
|
||||
/**
|
||||
* The date of last access to this file.
|
||||
*
|
||||
* @param {string=} operation The operation that failed. If unspecified,
|
||||
* the name of the calling function is taken to be the operation that
|
||||
* failed.
|
||||
* @param {number=} lastError The OS-specific constant detailing the
|
||||
* reason of the error. If unspecified, this is fetched from the system
|
||||
* status.
|
||||
* Note that the definition of last access may depend on the
|
||||
* underlying operating system and file system.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {OS.Shared.Error}
|
||||
* @type {Date}
|
||||
*/
|
||||
let OSError = function OSError(operation, errno) {
|
||||
operation = operation || "unknown operation";
|
||||
exports.OS.Shared.Error.call(this, operation);
|
||||
this.unixErrno = errno || ctypes.errno;
|
||||
};
|
||||
OSError.prototype = new exports.OS.Shared.Error();
|
||||
OSError.prototype.toString = function toString() {
|
||||
return "Unix error " + this.unixErrno +
|
||||
" during operation " + this.operation +
|
||||
" (" + strerror(this.unixErrno).readString() + ")";
|
||||
};
|
||||
|
||||
get lastAccessDate() {
|
||||
return this._lastAccessDate;
|
||||
},
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* already exists, |false| otherwise.
|
||||
* Return the date of last modification of this file.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseExists", {
|
||||
get: function becauseExists() {
|
||||
return this.unixErrno == OS.Constants.libc.EEXIST;
|
||||
}
|
||||
});
|
||||
get lastModificationDate() {
|
||||
return this._lastModificationDate;
|
||||
},
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* does not exist, |false| otherwise.
|
||||
* Return the date at which the status of this file was last modified
|
||||
* (this is the date of the latest write/renaming/mode change/...
|
||||
* of the file)
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
|
||||
get: function becauseNoSuchFile() {
|
||||
return this.unixErrno == OS.Constants.libc.ENOENT;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* |true| if the error was raised because a directory is not empty
|
||||
* does not exist, |false| otherwise.
|
||||
get unixLastStatusChangeDate() {
|
||||
return this._unixLastStatusChangeDate;
|
||||
},
|
||||
/*
|
||||
* Return the Unix owner of this file
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
|
||||
get: function becauseNotEmpty() {
|
||||
return this.unixErrno == OS.Constants.libc.ENOTEMPTY;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* is closed, |false| otherwise.
|
||||
get unixOwner() {
|
||||
return this._unixOwner;
|
||||
},
|
||||
/*
|
||||
* Return the Unix group of this file
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseClosed", {
|
||||
get: function becauseClosed() {
|
||||
return this.unixErrno == OS.Constants.libc.EBADF;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because permission is denied to
|
||||
* access a file or directory, |false| otherwise.
|
||||
get unixGroup() {
|
||||
return this._unixGroup;
|
||||
},
|
||||
/*
|
||||
* Return the Unix group of this file
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
|
||||
get: function becauseAccessDenied() {
|
||||
return this.unixErrno == OS.Constants.libc.EACCES;
|
||||
}
|
||||
});
|
||||
get unixMode() {
|
||||
return this._unixMode;
|
||||
}
|
||||
};
|
||||
exports.AbstractInfo = AbstractInfo;
|
||||
|
||||
/**
|
||||
* Code shared by implementations of File.DirectoryIterator.Entry on Unix
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) {
|
||||
this._isDir = isDir;
|
||||
this._isSymlLink = isSymLink;
|
||||
this._name = name;
|
||||
this._path = path;
|
||||
};
|
||||
|
||||
AbstractEntry.prototype = {
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
* transmitted across threads (not necessarily a string).
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
OSError.toMsg = function toMsg(error) {
|
||||
return {
|
||||
operation: error.operation,
|
||||
unixErrno: error.unixErrno
|
||||
};
|
||||
};
|
||||
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* Deserialize a message back to an instance of OSError
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
OSError.fromMsg = function fromMsg(msg) {
|
||||
return new OSError(msg.operation, msg.unixErrno);
|
||||
};
|
||||
|
||||
exports.OS.Shared.Unix.Error = OSError;
|
||||
|
||||
get isSymLink() {
|
||||
return this._isSymlLink;
|
||||
},
|
||||
/**
|
||||
* Code shared by implementations of File.Info on Unix
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
|
||||
lastModificationDate, unixLastStatusChangeDate,
|
||||
unixOwner, unixGroup, unixMode) {
|
||||
this._isDir = isDir;
|
||||
this._isSymlLink = isSymLink;
|
||||
this._size = size;
|
||||
this._lastAccessDate = lastAccessDate;
|
||||
this._lastModificationDate = lastModificationDate;
|
||||
this._unixLastStatusChangeDate = unixLastStatusChangeDate;
|
||||
this._unixOwner = unixOwner;
|
||||
this._unixGroup = unixGroup;
|
||||
this._unixMode = unixMode;
|
||||
};
|
||||
|
||||
AbstractInfo.prototype = {
|
||||
/**
|
||||
* |true| if this file is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* |true| if this file is a symbolink link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return this._isSymlLink;
|
||||
},
|
||||
/**
|
||||
* The size of the file, in bytes.
|
||||
*
|
||||
* Note that the result may be |NaN| if the size of the file cannot be
|
||||
* represented in JavaScript.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get size() {
|
||||
return this._size;
|
||||
},
|
||||
/**
|
||||
* The date of last access to this file.
|
||||
*
|
||||
* Note that the definition of last access may depend on the
|
||||
* underlying operating system and file system.
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
get lastAccessDate() {
|
||||
return this._lastAccessDate;
|
||||
},
|
||||
/**
|
||||
* Return the date of last modification of this file.
|
||||
*/
|
||||
get lastModificationDate() {
|
||||
return this._lastModificationDate;
|
||||
},
|
||||
/**
|
||||
* Return the date at which the status of this file was last modified
|
||||
* (this is the date of the latest write/renaming/mode change/...
|
||||
* of the file)
|
||||
*/
|
||||
get unixLastStatusChangeDate() {
|
||||
return this._unixLastStatusChangeDate;
|
||||
},
|
||||
/*
|
||||
* Return the Unix owner of this file
|
||||
*/
|
||||
get unixOwner() {
|
||||
return this._unixOwner;
|
||||
},
|
||||
/*
|
||||
* Return the Unix group of this file
|
||||
*/
|
||||
get unixGroup() {
|
||||
return this._unixGroup;
|
||||
},
|
||||
/*
|
||||
* Return the Unix group of this file
|
||||
*/
|
||||
get unixMode() {
|
||||
return this._unixMode;
|
||||
}
|
||||
};
|
||||
exports.OS.Shared.Unix.AbstractInfo = AbstractInfo;
|
||||
|
||||
* The name of the entry
|
||||
* @type {string}
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
/**
|
||||
* Code shared by implementations of File.DirectoryIterator.Entry on Unix
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) {
|
||||
this._isDir = isDir;
|
||||
this._isSymlLink = isSymLink;
|
||||
this._name = name;
|
||||
this._path = path;
|
||||
};
|
||||
* The full path to the entry
|
||||
*/
|
||||
get path() {
|
||||
return this._path;
|
||||
}
|
||||
};
|
||||
exports.AbstractEntry = AbstractEntry;
|
||||
|
||||
AbstractEntry.prototype = {
|
||||
/**
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return this._isSymlLink;
|
||||
},
|
||||
/**
|
||||
* The name of the entry
|
||||
* @type {string}
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
/**
|
||||
* The full path to the entry
|
||||
*/
|
||||
get path() {
|
||||
return this._path;
|
||||
}
|
||||
};
|
||||
exports.OS.Shared.Unix.AbstractEntry = AbstractEntry;
|
||||
// Special constants that need to be defined on all platforms
|
||||
|
||||
// Special constants that need to be defined on all platforms
|
||||
exports.POS_START = Const.SEEK_SET;
|
||||
exports.POS_CURRENT = Const.SEEK_CUR;
|
||||
exports.POS_END = Const.SEEK_END;
|
||||
|
||||
Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.libc.SEEK_SET });
|
||||
Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.libc.SEEK_CUR });
|
||||
Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.libc.SEEK_END });
|
||||
// Special types that need to be defined for communication
|
||||
// between threads
|
||||
let Type = Object.create(SharedAll.Type);
|
||||
exports.Type = Type;
|
||||
|
||||
// Special types that need to be defined for communication
|
||||
// between threads
|
||||
let Types = exports.OS.Shared.Type;
|
||||
/**
|
||||
* Native paths
|
||||
*
|
||||
* Under Unix, expressed as C strings
|
||||
*/
|
||||
Type.path = Type.cstring.withName("[in] path");
|
||||
Type.out_path = Type.out_cstring.withName("[out] path");
|
||||
|
||||
/**
|
||||
* Native paths
|
||||
*
|
||||
* Under Unix, expressed as C strings
|
||||
*/
|
||||
Types.path = Types.cstring.withName("[in] path");
|
||||
Types.out_path = Types.out_cstring.withName("[out] path");
|
||||
// Special constructors that need to be defined on all threads
|
||||
OSError.closed = function closed(operation) {
|
||||
return new OSError(operation, Const.EBADF);
|
||||
};
|
||||
|
||||
// Special constructors that need to be defined on all threads
|
||||
OSError.closed = function closed(operation) {
|
||||
return new OSError(operation, OS.Constants.libc.EBADF);
|
||||
};
|
||||
OSError.exists = function exists(operation) {
|
||||
return new OSError(operation, Const.EEXIST);
|
||||
};
|
||||
|
||||
OSError.exists = function exists(operation) {
|
||||
return new OSError(operation, OS.Constants.libc.EEXIST);
|
||||
};
|
||||
OSError.noSuchFile = function noSuchFile(operation) {
|
||||
return new OSError(operation, Const.ENOENT);
|
||||
};
|
||||
|
||||
OSError.noSuchFile = function noSuchFile(operation) {
|
||||
return new OSError(operation, OS.Constants.libc.ENOENT);
|
||||
};
|
||||
})(this);
|
||||
let EXPORTED_SYMBOLS = [
|
||||
"declareFFI",
|
||||
"libc",
|
||||
"Error",
|
||||
"AbstractInfo",
|
||||
"AbstractEntry",
|
||||
"Type",
|
||||
"POS_START",
|
||||
"POS_CURRENT",
|
||||
"POS_END"
|
||||
];
|
||||
|
||||
//////////// Boilerplate
|
||||
if (typeof Components != "undefined") {
|
||||
this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
|
||||
for (let symbol of EXPORTED_SYMBOLS) {
|
||||
this[symbol] = exports[symbol];
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,13 @@
|
||||
return; // Avoid double initialization
|
||||
}
|
||||
|
||||
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
|
||||
|
||||
exports.OS.Unix.File = {};
|
||||
|
||||
let LOG = exports.OS.Shared.LOG.bind(OS.Shared, "Unix", "back");
|
||||
let libc = exports.OS.Shared.Unix.libc;
|
||||
let SharedAll =
|
||||
require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
let SysAll =
|
||||
require("resource://gre/modules/osfile/osfile_unix_allthreads.jsm");
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "back");
|
||||
let libc = SysAll.libc;
|
||||
let Const = SharedAll.Constants.libc;
|
||||
|
||||
/**
|
||||
* Initialize the Unix module.
|
||||
@ -35,27 +36,20 @@
|
||||
if (aDeclareFFI) {
|
||||
declareFFI = aDeclareFFI.bind(null, libc);
|
||||
} else {
|
||||
declareFFI = exports.OS.Shared.Unix.declareFFI;
|
||||
declareFFI = SysAll.declareFFI;
|
||||
}
|
||||
|
||||
// Shorthands
|
||||
let OSUnix = exports.OS.Unix;
|
||||
let UnixFile = exports.OS.Unix.File;
|
||||
if (!exports.OS.Types) {
|
||||
exports.OS.Types = {};
|
||||
}
|
||||
let Type = exports.OS.Shared.Type;
|
||||
let Types = Type;
|
||||
|
||||
// Initialize types that require additional OS-specific
|
||||
// support - either finalization or matching against
|
||||
// OS-specific constants.
|
||||
let Type = Object.create(SysAll.Type);
|
||||
let SysFile = exports.OS.Unix.File = { Type: Type };
|
||||
|
||||
/**
|
||||
* A file descriptor.
|
||||
*/
|
||||
Types.fd = Type.int.withName("fd");
|
||||
Types.fd.importFromC = function importFromC(fd_int) {
|
||||
Type.fd = Type.int.withName("fd");
|
||||
Type.fd.importFromC = function importFromC(fd_int) {
|
||||
return ctypes.CDataFinalizer(fd_int, _close);
|
||||
};
|
||||
|
||||
@ -64,8 +58,8 @@
|
||||
* A C integer holding -1 in case of error or a file descriptor
|
||||
* in case of success.
|
||||
*/
|
||||
Types.negativeone_or_fd = Types.fd.withName("negativeone_or_fd");
|
||||
Types.negativeone_or_fd.importFromC =
|
||||
Type.negativeone_or_fd = Type.fd.withName("negativeone_or_fd");
|
||||
Type.negativeone_or_fd.importFromC =
|
||||
function importFromC(fd_int) {
|
||||
if (fd_int == -1) {
|
||||
return -1;
|
||||
@ -77,31 +71,31 @@
|
||||
* A C integer holding -1 in case of error or a meaningless value
|
||||
* in case of success.
|
||||
*/
|
||||
Types.negativeone_or_nothing =
|
||||
Types.int.withName("negativeone_or_nothing");
|
||||
Type.negativeone_or_nothing =
|
||||
Type.int.withName("negativeone_or_nothing");
|
||||
|
||||
/**
|
||||
* A C integer holding -1 in case of error or a positive integer
|
||||
* in case of success.
|
||||
*/
|
||||
Types.negativeone_or_ssize_t =
|
||||
Types.ssize_t.withName("negativeone_or_ssize_t");
|
||||
Type.negativeone_or_ssize_t =
|
||||
Type.ssize_t.withName("negativeone_or_ssize_t");
|
||||
|
||||
/**
|
||||
* Various libc integer types
|
||||
*/
|
||||
Types.mode_t =
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_MODE_T).withName("mode_t");
|
||||
Types.uid_t =
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_UID_T).withName("uid_t");
|
||||
Types.gid_t =
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_GID_T).withName("gid_t");
|
||||
Type.mode_t =
|
||||
Type.intn_t(Const.OSFILE_SIZEOF_MODE_T).withName("mode_t");
|
||||
Type.uid_t =
|
||||
Type.intn_t(Const.OSFILE_SIZEOF_UID_T).withName("uid_t");
|
||||
Type.gid_t =
|
||||
Type.intn_t(Const.OSFILE_SIZEOF_GID_T).withName("gid_t");
|
||||
|
||||
/**
|
||||
* Type |time_t|
|
||||
*/
|
||||
Types.time_t =
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_TIME_T).withName("time_t");
|
||||
Type.time_t =
|
||||
Type.intn_t(Const.OSFILE_SIZEOF_TIME_T).withName("time_t");
|
||||
|
||||
// Structure |dirent|
|
||||
// Building this type is rather complicated, as its layout varies between
|
||||
@ -115,90 +109,90 @@
|
||||
// };
|
||||
{
|
||||
let d_name_extra_size = 0;
|
||||
if (OS.Constants.libc.OSFILE_SIZEOF_DIRENT_D_NAME < 8) {
|
||||
if (Const.OSFILE_SIZEOF_DIRENT_D_NAME < 8) {
|
||||
// d_name is defined like "char d_name[1];" on some platforms
|
||||
// (e.g. Solaris), we need to give it more size for our structure.
|
||||
d_name_extra_size = 256;
|
||||
}
|
||||
|
||||
let dirent = new OS.Shared.HollowStructure("dirent",
|
||||
OS.Constants.libc.OSFILE_SIZEOF_DIRENT + d_name_extra_size);
|
||||
if (OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_TYPE != undefined) {
|
||||
let dirent = new SharedAll.HollowStructure("dirent",
|
||||
Const.OSFILE_SIZEOF_DIRENT + d_name_extra_size);
|
||||
if (Const.OSFILE_OFFSETOF_DIRENT_D_TYPE != undefined) {
|
||||
// |dirent| doesn't have d_type on some platforms (e.g. Solaris).
|
||||
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_TYPE,
|
||||
dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_TYPE,
|
||||
"d_type", ctypes.uint8_t);
|
||||
}
|
||||
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_NAME,
|
||||
dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_NAME,
|
||||
"d_name", ctypes.ArrayType(ctypes.char,
|
||||
OS.Constants.libc.OSFILE_SIZEOF_DIRENT_D_NAME + d_name_extra_size));
|
||||
Const.OSFILE_SIZEOF_DIRENT_D_NAME + d_name_extra_size));
|
||||
|
||||
// We now have built |dirent|.
|
||||
Types.dirent = dirent.getType();
|
||||
Type.dirent = dirent.getType();
|
||||
}
|
||||
Types.null_or_dirent_ptr =
|
||||
new Type("null_of_dirent",
|
||||
Types.dirent.out_ptr.implementation);
|
||||
Type.null_or_dirent_ptr =
|
||||
new SharedAll.Type("null_of_dirent",
|
||||
Type.dirent.out_ptr.implementation);
|
||||
|
||||
// Structure |stat|
|
||||
// Same technique
|
||||
{
|
||||
let stat = new OS.Shared.HollowStructure("stat",
|
||||
OS.Constants.libc.OSFILE_SIZEOF_STAT);
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_MODE,
|
||||
"st_mode", Types.mode_t.implementation);
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_UID,
|
||||
"st_uid", Types.uid_t.implementation);
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_GID,
|
||||
"st_gid", Types.gid_t.implementation);
|
||||
let stat = new SharedAll.HollowStructure("stat",
|
||||
Const.OSFILE_SIZEOF_STAT);
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MODE,
|
||||
"st_mode", Type.mode_t.implementation);
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_UID,
|
||||
"st_uid", Type.uid_t.implementation);
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_GID,
|
||||
"st_gid", Type.gid_t.implementation);
|
||||
|
||||
// Here, things get complicated with different data structures.
|
||||
// Some platforms have |time_t st_atime| and some platforms have
|
||||
// |timespec st_atimespec|. However, since |timespec| starts with
|
||||
// a |time_t|, followed by nanoseconds, we just cheat and pretend
|
||||
// that everybody has |time_t st_atime|, possibly followed by padding
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_ATIME,
|
||||
"st_atime", Types.time_t.implementation);
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_MTIME,
|
||||
"st_mtime", Types.time_t.implementation);
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_CTIME,
|
||||
"st_ctime", Types.time_t.implementation);
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_ATIME,
|
||||
"st_atime", Type.time_t.implementation);
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MTIME,
|
||||
"st_mtime", Type.time_t.implementation);
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_CTIME,
|
||||
"st_ctime", Type.time_t.implementation);
|
||||
|
||||
// To complicate further, MacOS and some BSDs have a field |birthtime|
|
||||
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in OS.Constants.libc) {
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_BIRTHTIME,
|
||||
"st_birthtime", Types.time_t.implementation);
|
||||
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in Const) {
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_BIRTHTIME,
|
||||
"st_birthtime", Type.time_t.implementation);
|
||||
}
|
||||
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_SIZE,
|
||||
"st_size", Types.size_t.implementation);
|
||||
Types.stat = stat.getType();
|
||||
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_SIZE,
|
||||
"st_size", Type.size_t.implementation);
|
||||
Type.stat = stat.getType();
|
||||
}
|
||||
|
||||
// Structure |DIR|
|
||||
if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
|
||||
if ("OSFILE_SIZEOF_DIR" in Const) {
|
||||
// On platforms for which we need to access the fields of DIR
|
||||
// directly (e.g. because certain functions are implemented
|
||||
// as macros), we need to define DIR as a hollow structure.
|
||||
let DIR = new OS.Shared.HollowStructure(
|
||||
let DIR = new SharedAll.HollowStructure(
|
||||
"DIR",
|
||||
OS.Constants.libc.OSFILE_SIZEOF_DIR);
|
||||
Const.OSFILE_SIZEOF_DIR);
|
||||
|
||||
DIR.add_field_at(
|
||||
OS.Constants.libc.OSFILE_OFFSETOF_DIR_DD_FD,
|
||||
Const.OSFILE_OFFSETOF_DIR_DD_FD,
|
||||
"dd_fd",
|
||||
Types.fd.implementation);
|
||||
Type.fd.implementation);
|
||||
|
||||
Types.DIR = DIR.getType();
|
||||
Type.DIR = DIR.getType();
|
||||
} else {
|
||||
// On other platforms, we keep DIR as a blackbox
|
||||
Types.DIR =
|
||||
new Type("DIR",
|
||||
Type.DIR =
|
||||
new SharedAll.Type("DIR",
|
||||
ctypes.StructType("DIR"));
|
||||
}
|
||||
|
||||
Types.null_or_DIR_ptr =
|
||||
Types.DIR.out_ptr.withName("null_or_DIR*");
|
||||
Types.null_or_DIR_ptr.importFromC = function importFromC(dir) {
|
||||
Type.null_or_DIR_ptr =
|
||||
Type.DIR.out_ptr.withName("null_or_DIR*");
|
||||
Type.null_or_DIR_ptr.importFromC = function importFromC(dir) {
|
||||
if (dir == null || dir.isNull()) {
|
||||
return null;
|
||||
}
|
||||
@ -208,12 +202,12 @@
|
||||
// Declare libc functions as functions of |OS.Unix.File|
|
||||
|
||||
// Finalizer-related functions
|
||||
let _close = UnixFile._close =
|
||||
let _close = SysFile._close =
|
||||
libc.declare("close", ctypes.default_abi,
|
||||
/*return */ctypes.int,
|
||||
/*fd*/ ctypes.int);
|
||||
|
||||
UnixFile.close = function close(fd) {
|
||||
SysFile.close = function close(fd) {
|
||||
// Detach the finalizer and call |_close|.
|
||||
return fd.dispose();
|
||||
};
|
||||
@ -221,9 +215,9 @@
|
||||
let _close_dir =
|
||||
libc.declare("closedir", ctypes.default_abi,
|
||||
/*return */ctypes.int,
|
||||
/*dirp*/ Types.DIR.in_ptr.implementation);
|
||||
/*dirp*/ Type.DIR.in_ptr.implementation);
|
||||
|
||||
UnixFile.closedir = function closedir(fd) {
|
||||
SysFile.closedir = function closedir(fd) {
|
||||
// Detach the finalizer and call |_close_dir|.
|
||||
return fd.dispose();
|
||||
};
|
||||
@ -238,7 +232,7 @@
|
||||
// correct implementation free().
|
||||
default_lib = ctypes.open("a.out");
|
||||
|
||||
UnixFile.free =
|
||||
SysFile.free =
|
||||
default_lib.declare("free", ctypes.default_abi,
|
||||
/*return*/ ctypes.void_t,
|
||||
/*ptr*/ ctypes.voidptr_t);
|
||||
@ -247,7 +241,7 @@
|
||||
// We don't have an a.out library or a.out doesn't contain free.
|
||||
// Either way, use the ordinary libc free.
|
||||
|
||||
UnixFile.free =
|
||||
SysFile.free =
|
||||
libc.declare("free", ctypes.default_abi,
|
||||
/*return*/ ctypes.void_t,
|
||||
/*ptr*/ ctypes.voidptr_t);
|
||||
@ -256,293 +250,293 @@
|
||||
|
||||
|
||||
// Other functions
|
||||
UnixFile.access =
|
||||
SysFile.access =
|
||||
declareFFI("access", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*mode*/ Types.int);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.int);
|
||||
|
||||
UnixFile.chdir =
|
||||
SysFile.chdir =
|
||||
declareFFI("chdir", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
UnixFile.chmod =
|
||||
SysFile.chmod =
|
||||
declareFFI("chmod", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*mode*/ Types.mode_t);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.mode_t);
|
||||
|
||||
UnixFile.chown =
|
||||
SysFile.chown =
|
||||
declareFFI("chown", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*uid*/ Types.uid_t,
|
||||
/*gid*/ Types.gid_t);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*uid*/ Type.uid_t,
|
||||
/*gid*/ Type.gid_t);
|
||||
|
||||
UnixFile.copyfile =
|
||||
SysFile.copyfile =
|
||||
declareFFI("copyfile", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*source*/ Types.path,
|
||||
/*dest*/ Types.path,
|
||||
/*state*/ Types.void_t.in_ptr, // Ignored atm
|
||||
/*flags*/ Types.uint32_t);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path,
|
||||
/*state*/ Type.void_t.in_ptr, // Ignored atm
|
||||
/*flags*/ Type.uint32_t);
|
||||
|
||||
UnixFile.dup =
|
||||
SysFile.dup =
|
||||
declareFFI("dup", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_fd,
|
||||
/*fd*/ Types.fd);
|
||||
/*return*/ Type.negativeone_or_fd,
|
||||
/*fd*/ Type.fd);
|
||||
|
||||
if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
|
||||
if ("OSFILE_SIZEOF_DIR" in Const) {
|
||||
// On platforms for which |dirfd| is a macro
|
||||
UnixFile.dirfd =
|
||||
SysFile.dirfd =
|
||||
function dirfd(DIRp) {
|
||||
return Types.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
|
||||
return Type.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
|
||||
};
|
||||
} else {
|
||||
// On platforms for which |dirfd| is a function
|
||||
UnixFile.dirfd =
|
||||
SysFile.dirfd =
|
||||
declareFFI("dirfd", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_fd,
|
||||
/*dir*/ Types.DIR.in_ptr);
|
||||
/*return*/ Type.negativeone_or_fd,
|
||||
/*dir*/ Type.DIR.in_ptr);
|
||||
}
|
||||
|
||||
UnixFile.chdir =
|
||||
SysFile.chdir =
|
||||
declareFFI("chdir", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
UnixFile.fchdir =
|
||||
SysFile.fchdir =
|
||||
declareFFI("fchdir", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fd*/ Types.fd);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd);
|
||||
|
||||
UnixFile.fchown =
|
||||
SysFile.fchown =
|
||||
declareFFI("fchown", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fd*/ Types.fd,
|
||||
/*uid_t*/ Types.uid_t,
|
||||
/*gid_t*/ Types.gid_t);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*uid_t*/ Type.uid_t,
|
||||
/*gid_t*/ Type.gid_t);
|
||||
|
||||
UnixFile.fsync =
|
||||
SysFile.fsync =
|
||||
declareFFI("fsync", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fd*/ Types.fd);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd);
|
||||
|
||||
UnixFile.getcwd =
|
||||
SysFile.getcwd =
|
||||
declareFFI("getcwd", ctypes.default_abi,
|
||||
/*return*/ Types.out_path,
|
||||
/*buf*/ Types.out_path,
|
||||
/*size*/ Types.size_t);
|
||||
/*return*/ Type.out_path,
|
||||
/*buf*/ Type.out_path,
|
||||
/*size*/ Type.size_t);
|
||||
|
||||
UnixFile.getwd =
|
||||
SysFile.getwd =
|
||||
declareFFI("getwd", ctypes.default_abi,
|
||||
/*return*/ Types.out_path,
|
||||
/*buf*/ Types.out_path);
|
||||
/*return*/ Type.out_path,
|
||||
/*buf*/ Type.out_path);
|
||||
|
||||
// Two variants of |getwd| which allocate the memory
|
||||
// dynamically.
|
||||
|
||||
// Linux/Android version
|
||||
UnixFile.get_current_dir_name =
|
||||
SysFile.get_current_dir_name =
|
||||
declareFFI("get_current_dir_name", ctypes.default_abi,
|
||||
/*return*/ Types.out_path.releaseWith(UnixFile.free));
|
||||
/*return*/ Type.out_path.releaseWith(SysFile.free));
|
||||
|
||||
// MacOS/BSD version (will return NULL on Linux/Android)
|
||||
UnixFile.getwd_auto =
|
||||
SysFile.getwd_auto =
|
||||
declareFFI("getwd", ctypes.default_abi,
|
||||
/*return*/ Types.out_path.releaseWith(UnixFile.free),
|
||||
/*buf*/ Types.void_t.out_ptr);
|
||||
/*return*/ Type.out_path.releaseWith(SysFile.free),
|
||||
/*buf*/ Type.void_t.out_ptr);
|
||||
|
||||
UnixFile.fdatasync =
|
||||
SysFile.fdatasync =
|
||||
declareFFI("fdatasync", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fd*/ Types.fd); // Note: MacOS/BSD-specific
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd); // Note: MacOS/BSD-specific
|
||||
|
||||
UnixFile.ftruncate =
|
||||
SysFile.ftruncate =
|
||||
declareFFI("ftruncate", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fd*/ Types.fd,
|
||||
/*length*/ Types.off_t);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*length*/ Type.off_t);
|
||||
|
||||
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
UnixFile.fstat =
|
||||
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
SysFile.fstat =
|
||||
declareFFI("fstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
} else {
|
||||
UnixFile.fstat =
|
||||
SysFile.fstat =
|
||||
declareFFI("fstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
}
|
||||
|
||||
UnixFile.lchown =
|
||||
SysFile.lchown =
|
||||
declareFFI("lchown", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*uid_t*/ Types.uid_t,
|
||||
/*gid_t*/ Types.gid_t);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*uid_t*/ Type.uid_t,
|
||||
/*gid_t*/ Type.gid_t);
|
||||
|
||||
UnixFile.link =
|
||||
SysFile.link =
|
||||
declareFFI("link", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*source*/ Types.path,
|
||||
/*dest*/ Types.path);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path);
|
||||
|
||||
UnixFile.lseek =
|
||||
SysFile.lseek =
|
||||
declareFFI("lseek", ctypes.default_abi,
|
||||
/*return*/ Types.off_t,
|
||||
/*fd*/ Types.fd,
|
||||
/*offset*/ Types.off_t,
|
||||
/*whence*/ Types.int);
|
||||
/*return*/ Type.off_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*offset*/ Type.off_t,
|
||||
/*whence*/ Type.int);
|
||||
|
||||
UnixFile.mkdir =
|
||||
SysFile.mkdir =
|
||||
declareFFI("mkdir", ctypes.default_abi,
|
||||
/*return*/ Types.int,
|
||||
/*path*/ Types.path,
|
||||
/*mode*/ Types.int);
|
||||
/*return*/ Type.int,
|
||||
/*path*/ Type.path,
|
||||
/*mode*/ Type.int);
|
||||
|
||||
UnixFile.mkstemp =
|
||||
SysFile.mkstemp =
|
||||
declareFFI("mkstemp", ctypes.default_abi,
|
||||
/*return*/ Types.fd,
|
||||
/*template*/Types.out_path);
|
||||
/*return*/ Type.fd,
|
||||
/*template*/Type.out_path);
|
||||
|
||||
UnixFile.open =
|
||||
SysFile.open =
|
||||
declareFFI("open", ctypes.default_abi,
|
||||
/*return*/Types.negativeone_or_fd,
|
||||
/*path*/ Types.path,
|
||||
/*oflags*/Types.int,
|
||||
/*mode*/ Types.int);
|
||||
/*return*/Type.negativeone_or_fd,
|
||||
/*path*/ Type.path,
|
||||
/*oflags*/Type.int,
|
||||
/*mode*/ Type.int);
|
||||
|
||||
UnixFile.opendir =
|
||||
SysFile.opendir =
|
||||
declareFFI("opendir", ctypes.default_abi,
|
||||
/*return*/ Types.null_or_DIR_ptr,
|
||||
/*path*/ Types.path);
|
||||
/*return*/ Type.null_or_DIR_ptr,
|
||||
/*path*/ Type.path);
|
||||
|
||||
UnixFile.pread =
|
||||
SysFile.pread =
|
||||
declareFFI("pread", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_ssize_t,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.void_t.out_ptr,
|
||||
/*nbytes*/ Types.size_t,
|
||||
/*offset*/ Types.off_t);
|
||||
/*return*/ Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.out_ptr,
|
||||
/*nbytes*/ Type.size_t,
|
||||
/*offset*/ Type.off_t);
|
||||
|
||||
UnixFile.pwrite =
|
||||
SysFile.pwrite =
|
||||
declareFFI("pwrite", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_ssize_t,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.void_t.in_ptr,
|
||||
/*nbytes*/ Types.size_t,
|
||||
/*offset*/ Types.off_t);
|
||||
/*return*/ Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.in_ptr,
|
||||
/*nbytes*/ Type.size_t,
|
||||
/*offset*/ Type.off_t);
|
||||
|
||||
UnixFile.read =
|
||||
SysFile.read =
|
||||
declareFFI("read", ctypes.default_abi,
|
||||
/*return*/Types.negativeone_or_ssize_t,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.void_t.out_ptr,
|
||||
/*nbytes*/Types.size_t);
|
||||
/*return*/Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.out_ptr,
|
||||
/*nbytes*/Type.size_t);
|
||||
|
||||
UnixFile.posix_fadvise =
|
||||
SysFile.posix_fadvise =
|
||||
declareFFI("posix_fadvise", ctypes.default_abi,
|
||||
/*return*/ Types.int,
|
||||
/*fd*/ Types.fd,
|
||||
/*offset*/ Types.off_t,
|
||||
/*len*/ Types.off_t,
|
||||
/*advise*/ Types.int);
|
||||
/*return*/ Type.int,
|
||||
/*fd*/ Type.fd,
|
||||
/*offset*/ Type.off_t,
|
||||
/*len*/ Type.off_t,
|
||||
/*advise*/ Type.int);
|
||||
|
||||
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
// Special case for MacOS X 10.5+
|
||||
// Symbol name "readdir" still exists but is used for a
|
||||
// deprecated function that does not match the
|
||||
// constants of |OS.Constants.libc|.
|
||||
UnixFile.readdir =
|
||||
// constants of |Const|.
|
||||
SysFile.readdir =
|
||||
declareFFI("readdir$INODE64", ctypes.default_abi,
|
||||
/*return*/Types.null_or_dirent_ptr,
|
||||
/*dir*/ Types.DIR.in_ptr); // For MacOS X
|
||||
/*return*/Type.null_or_dirent_ptr,
|
||||
/*dir*/ Type.DIR.in_ptr); // For MacOS X
|
||||
} else {
|
||||
UnixFile.readdir =
|
||||
SysFile.readdir =
|
||||
declareFFI("readdir", ctypes.default_abi,
|
||||
/*return*/Types.null_or_dirent_ptr,
|
||||
/*dir*/ Types.DIR.in_ptr); // Other Unices
|
||||
/*return*/Type.null_or_dirent_ptr,
|
||||
/*dir*/ Type.DIR.in_ptr); // Other Unices
|
||||
}
|
||||
|
||||
UnixFile.rename =
|
||||
SysFile.rename =
|
||||
declareFFI("rename", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*old*/ Types.path,
|
||||
/*new*/ Types.path);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*old*/ Type.path,
|
||||
/*new*/ Type.path);
|
||||
|
||||
UnixFile.rmdir =
|
||||
SysFile.rmdir =
|
||||
declareFFI("rmdir", ctypes.default_abi,
|
||||
/*return*/ Types.int,
|
||||
/*path*/ Types.path);
|
||||
/*return*/ Type.int,
|
||||
/*path*/ Type.path);
|
||||
|
||||
UnixFile.splice =
|
||||
SysFile.splice =
|
||||
declareFFI("splice", ctypes.default_abi,
|
||||
/*return*/ Types.long,
|
||||
/*fd_in*/ Types.fd,
|
||||
/*off_in*/ Types.off_t.in_ptr,
|
||||
/*fd_out*/ Types.fd,
|
||||
/*off_out*/Types.off_t.in_ptr,
|
||||
/*len*/ Types.size_t,
|
||||
/*flags*/ Types.unsigned_int); // Linux/Android-specific
|
||||
/*return*/ Type.long,
|
||||
/*fd_in*/ Type.fd,
|
||||
/*off_in*/ Type.off_t.in_ptr,
|
||||
/*fd_out*/ Type.fd,
|
||||
/*off_out*/Type.off_t.in_ptr,
|
||||
/*len*/ Type.size_t,
|
||||
/*flags*/ Type.unsigned_int); // Linux/Android-specific
|
||||
|
||||
UnixFile.symlink =
|
||||
SysFile.symlink =
|
||||
declareFFI("symlink", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*source*/ Types.path,
|
||||
/*dest*/ Types.path);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*source*/ Type.path,
|
||||
/*dest*/ Type.path);
|
||||
|
||||
UnixFile.truncate =
|
||||
SysFile.truncate =
|
||||
declareFFI("truncate", ctypes.default_abi,
|
||||
/*return*/Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*length*/ Types.off_t);
|
||||
/*return*/Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*length*/ Type.off_t);
|
||||
|
||||
UnixFile.unlink =
|
||||
SysFile.unlink =
|
||||
declareFFI("unlink", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
UnixFile.write =
|
||||
SysFile.write =
|
||||
declareFFI("write", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_ssize_t,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.void_t.in_ptr,
|
||||
/*nbytes*/ Types.size_t);
|
||||
/*return*/ Type.negativeone_or_ssize_t,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.void_t.in_ptr,
|
||||
/*nbytes*/ Type.size_t);
|
||||
|
||||
// Weird cases that require special treatment
|
||||
|
||||
// OSes use a variety of hacks to differentiate between
|
||||
// 32-bits and 64-bits versions of |stat|, |lstat|, |fstat|.
|
||||
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
// MacOS X 64-bits
|
||||
UnixFile.stat =
|
||||
SysFile.stat =
|
||||
declareFFI("stat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
UnixFile.lstat =
|
||||
SysFile.lstat =
|
||||
declareFFI("lstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
UnixFile.fstat =
|
||||
SysFile.fstat =
|
||||
declareFFI("fstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
} else if (OS.Constants.libc._STAT_VER != undefined) {
|
||||
const ver = OS.Constants.libc._STAT_VER;
|
||||
let xstat_name, lxstat_name, fxstat_name
|
||||
} else if (Const._STAT_VER != undefined) {
|
||||
const ver = Const._STAT_VER;
|
||||
let xstat_name, lxstat_name, fxstat_name;
|
||||
if (OS.Constants.Sys.Name == "SunOS") {
|
||||
// Solaris
|
||||
xstat_name = "_xstat";
|
||||
@ -557,51 +551,51 @@
|
||||
|
||||
let xstat =
|
||||
declareFFI(xstat_name, ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Types.int,
|
||||
/*path*/ Types.path,
|
||||
/*buf*/ Types.stat.out_ptr);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Type.int,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr);
|
||||
let lxstat =
|
||||
declareFFI(lxstat_name, ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Types.int,
|
||||
/*path*/ Types.path,
|
||||
/*buf*/ Types.stat.out_ptr);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Type.int,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr);
|
||||
let fxstat =
|
||||
declareFFI(fxstat_name, ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Types.int,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr);
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Type.int,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr);
|
||||
|
||||
UnixFile.stat = function stat(path, buf) {
|
||||
SysFile.stat = function stat(path, buf) {
|
||||
return xstat(ver, path, buf);
|
||||
};
|
||||
UnixFile.lstat = function stat(path, buf) {
|
||||
SysFile.lstat = function stat(path, buf) {
|
||||
return lxstat(ver, path, buf);
|
||||
};
|
||||
UnixFile.fstat = function stat(fd, buf) {
|
||||
SysFile.fstat = function stat(fd, buf) {
|
||||
return fxstat(ver, fd, buf);
|
||||
};
|
||||
} else {
|
||||
// Mac OS X 32-bits, other Unix
|
||||
UnixFile.stat =
|
||||
SysFile.stat =
|
||||
declareFFI("stat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
UnixFile.lstat =
|
||||
SysFile.lstat =
|
||||
declareFFI("lstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.path,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*path*/ Type.path,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
UnixFile.fstat =
|
||||
SysFile.fstat =
|
||||
declareFFI("fstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fd*/ Type.fd,
|
||||
/*buf*/ Type.stat.out_ptr
|
||||
);
|
||||
}
|
||||
|
||||
@ -610,14 +604,14 @@
|
||||
|
||||
let _pipe =
|
||||
declareFFI("pipe", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fds*/ new Type("two file descriptors",
|
||||
/*return*/ Type.negativeone_or_nothing,
|
||||
/*fds*/ new SharedAll.Type("two file descriptors",
|
||||
ctypes.ArrayType(ctypes.int, 2)));
|
||||
|
||||
// A shared per-thread buffer used to communicate with |pipe|
|
||||
let _pipebuf = new (ctypes.ArrayType(ctypes.int, 2))();
|
||||
|
||||
UnixFile.pipe = function pipe(array) {
|
||||
SysFile.pipe = function pipe(array) {
|
||||
let result = _pipe(_pipebuf);
|
||||
if (result == -1) {
|
||||
return result;
|
||||
@ -627,6 +621,11 @@
|
||||
return result;
|
||||
};
|
||||
};
|
||||
exports.OS.Unix.File._init = init;
|
||||
|
||||
exports.OS.Unix = {
|
||||
File: {
|
||||
_init: init
|
||||
}
|
||||
};
|
||||
})(this);
|
||||
}
|
||||
|
@ -19,18 +19,19 @@
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
|
||||
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
|
||||
let Path = require("resource://gre/modules/osfile/ospath.jsm");
|
||||
|
||||
// exports.OS.Unix is created by osfile_unix_back.jsm
|
||||
if (exports.OS && exports.OS.File) {
|
||||
return; // Avoid double-initialization
|
||||
}
|
||||
|
||||
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
let Path = require("resource://gre/modules/osfile/ospath.jsm");
|
||||
let SysAll = require("resource://gre/modules/osfile/osfile_unix_allthreads.jsm");
|
||||
exports.OS.Unix.File._init();
|
||||
let Const = exports.OS.Constants.libc;
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Unix front-end");
|
||||
let Const = SharedAll.Constants.libc;
|
||||
let UnixFile = exports.OS.Unix.File;
|
||||
let LOG = OS.Shared.LOG.bind(OS.Shared, "Unix front-end");
|
||||
let Type = UnixFile.Type;
|
||||
|
||||
/**
|
||||
* Representation of a file.
|
||||
@ -269,7 +270,7 @@
|
||||
* @return {bool} true if the file exists, false otherwise.
|
||||
*/
|
||||
File.exists = function Unix_exists(path) {
|
||||
if (UnixFile.access(path, OS.Constants.libc.F_OK) == -1) {
|
||||
if (UnixFile.access(path, Const.F_OK) == -1) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@ -338,7 +339,7 @@
|
||||
let omode = options.unixMode !== undefined ? options.unixMode : DEFAULT_UNIX_MODE_DIR;
|
||||
let result = UnixFile.mkdir(path, omode);
|
||||
if (result != -1 ||
|
||||
options.ignoreExisting && ctypes.errno == OS.Constants.libc.EEXIST) {
|
||||
options.ignoreExisting && ctypes.errno == Const.EEXIST) {
|
||||
return;
|
||||
}
|
||||
throw new File.Error("makeDir");
|
||||
@ -518,10 +519,10 @@
|
||||
// We *might* be on a file system that does not support splice.
|
||||
// Try again with a fallback pump.
|
||||
if (total_read) {
|
||||
source.setPosition(-total_read, OS.File.POS_CURRENT);
|
||||
source.setPosition(-total_read, File.POS_CURRENT);
|
||||
}
|
||||
if (total_written) {
|
||||
dest.setPosition(-total_written, OS.File.POS_CURRENT);
|
||||
dest.setPosition(-total_written, File.POS_CURRENT);
|
||||
}
|
||||
return pump_userland(source, dest, options);
|
||||
}
|
||||
@ -620,7 +621,7 @@
|
||||
this._dir = UnixFile.opendir(this._path);
|
||||
if (this._dir == null) {
|
||||
let error = ctypes.errno;
|
||||
if (error != OS.Constants.libc.ENOENT) {
|
||||
if (error != Const.ENOENT) {
|
||||
throw new File.Error("DirectoryIterator", error);
|
||||
}
|
||||
this._exists = false;
|
||||
@ -663,11 +664,11 @@
|
||||
// |dirent| doesn't have d_type on some platforms (e.g. Solaris).
|
||||
let path = Path.join(this._path, name);
|
||||
throw_on_negative("lstat", UnixFile.lstat(path, gStatDataPtr));
|
||||
isDir = (gStatData.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFDIR;
|
||||
isSymLink = (gStatData.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFLNK;
|
||||
isDir = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFDIR;
|
||||
isSymLink = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFLNK;
|
||||
} else {
|
||||
isDir = contents.d_type == OS.Constants.libc.DT_DIR;
|
||||
isSymLink = contents.d_type == OS.Constants.libc.DT_LNK;
|
||||
isDir = contents.d_type == Const.DT_DIR;
|
||||
isSymLink = contents.d_type == Const.DT_LNK;
|
||||
}
|
||||
|
||||
return new File.DirectoryIterator.Entry(isDir, isSymLink, name, this._path);
|
||||
@ -713,9 +714,9 @@
|
||||
this._parent = parent;
|
||||
let path = Path.join(this._parent, name);
|
||||
|
||||
exports.OS.Shared.Unix.AbstractEntry.call(this, isDir, isSymLink, name, path);
|
||||
SysAll.AbstractEntry.call(this, isDir, isSymLink, name, path);
|
||||
};
|
||||
File.DirectoryIterator.Entry.prototype = Object.create(exports.OS.Shared.Unix.AbstractEntry.prototype);
|
||||
File.DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
|
||||
|
||||
/**
|
||||
* Return a version of an instance of
|
||||
@ -737,28 +738,28 @@
|
||||
return serialized;
|
||||
};
|
||||
|
||||
let gStatData = new OS.Shared.Type.stat.implementation();
|
||||
let gStatData = new Type.stat.implementation();
|
||||
let gStatDataPtr = gStatData.address();
|
||||
let MODE_MASK = 4095 /*= 07777*/;
|
||||
File.Info = function Info(stat) {
|
||||
let isDir = (stat.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFDIR;
|
||||
let isSymLink = (stat.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFLNK;
|
||||
let size = exports.OS.Shared.Type.size_t.importFromC(stat.st_size);
|
||||
let isDir = (stat.st_mode & Const.S_IFMT) == Const.S_IFDIR;
|
||||
let isSymLink = (stat.st_mode & Const.S_IFMT) == Const.S_IFLNK;
|
||||
let size = Type.size_t.importFromC(stat.st_size);
|
||||
|
||||
let lastAccessDate = new Date(stat.st_atime * 1000);
|
||||
let lastModificationDate = new Date(stat.st_mtime * 1000);
|
||||
let unixLastStatusChangeDate = new Date(stat.st_ctime * 1000);
|
||||
|
||||
let unixOwner = exports.OS.Shared.Type.uid_t.importFromC(stat.st_uid);
|
||||
let unixGroup = exports.OS.Shared.Type.gid_t.importFromC(stat.st_gid);
|
||||
let unixMode = exports.OS.Shared.Type.mode_t.importFromC(stat.st_mode & MODE_MASK);
|
||||
let unixOwner = Type.uid_t.importFromC(stat.st_uid);
|
||||
let unixGroup = Type.gid_t.importFromC(stat.st_gid);
|
||||
let unixMode = Type.mode_t.importFromC(stat.st_mode & MODE_MASK);
|
||||
|
||||
exports.OS.Shared.Unix.AbstractInfo.call(this, isDir, isSymLink, size, lastAccessDate,
|
||||
lastModificationDate, unixLastStatusChangeDate,
|
||||
unixOwner, unixGroup, unixMode);
|
||||
SysAll.AbstractInfo.call(this, isDir, isSymLink, size, lastAccessDate,
|
||||
lastModificationDate, unixLastStatusChangeDate,
|
||||
unixOwner, unixGroup, unixMode);
|
||||
|
||||
// Some platforms (e.g. MacOS X, some BSDs) store a file creation date
|
||||
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in OS.Constants.libc) {
|
||||
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in Const) {
|
||||
let date = new Date(stat.st_birthtime * 1000);
|
||||
|
||||
/**
|
||||
@ -773,7 +774,7 @@
|
||||
this.macBirthDate = date;
|
||||
}
|
||||
};
|
||||
File.Info.prototype = Object.create(exports.OS.Shared.Unix.AbstractInfo.prototype);
|
||||
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
|
||||
|
||||
// Deprecated, use macBirthDate/winBirthDate instead
|
||||
Object.defineProperty(File.Info.prototype, "creationDate", {
|
||||
@ -824,6 +825,7 @@
|
||||
|
||||
File.read = exports.OS.Shared.AbstractFile.read;
|
||||
File.writeAtomic = exports.OS.Shared.AbstractFile.writeAtomic;
|
||||
File.openUnique = exports.OS.Shared.AbstractFile.openUnique;
|
||||
File.removeDir = exports.OS.Shared.AbstractFile.removeDir;
|
||||
|
||||
/**
|
||||
@ -894,11 +896,12 @@
|
||||
}
|
||||
|
||||
File.Unix = exports.OS.Unix.File;
|
||||
File.Error = exports.OS.Shared.Unix.Error;
|
||||
File.Error = SysAll.Error;
|
||||
exports.OS.File = File;
|
||||
exports.OS.Shared.Type = Type;
|
||||
|
||||
Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
|
||||
Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
|
||||
Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
|
||||
Object.defineProperty(File, "POS_START", { value: SysAll.POS_START });
|
||||
Object.defineProperty(File, "POS_CURRENT", { value: SysAll.POS_CURRENT });
|
||||
Object.defineProperty(File, "POS_END", { value: SysAll.POS_END });
|
||||
})(this);
|
||||
}
|
||||
|
@ -8,354 +8,371 @@
|
||||
* of OS.File.
|
||||
*
|
||||
* It serves the following purposes:
|
||||
* - open libc;
|
||||
* - open kernel32;
|
||||
* - define OS.Shared.Win.Error;
|
||||
* - define a few constants and types that need to be defined on all platforms.
|
||||
*
|
||||
* This module can be:
|
||||
* - opened from the main thread as a jsm module;
|
||||
* - opened from a chrome worker through importScripts.
|
||||
* - opened from a chrome worker through require().
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let SharedAll;
|
||||
if (typeof Components != "undefined") {
|
||||
let Cu = Components.utils;
|
||||
// Module is opened as a jsm module
|
||||
this.EXPORTED_SYMBOLS = ["OS"];
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://gre/modules/ctypes.jsm", this);
|
||||
|
||||
SharedAll = {};
|
||||
Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
|
||||
} else {
|
||||
Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
|
||||
this.exports = {};
|
||||
} else if (typeof "module" != "undefined" && typeof "require" != "undefined") {
|
||||
// Module is loaded with require()
|
||||
SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
} else {
|
||||
throw new Error("Please open this module with Component.utils.import or with require()");
|
||||
}
|
||||
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
if (exports.OS && exports.OS.Shared && exports.OS.Shared.Win) {
|
||||
// Avoid double inclusion
|
||||
return;
|
||||
}
|
||||
exports.OS = SharedAll.OS;
|
||||
exports.OS.Shared.Win = {};
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Win", "allthreads");
|
||||
let Const = SharedAll.Constants.Win;
|
||||
|
||||
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win", "allthreads");
|
||||
// Open libc
|
||||
let libc;
|
||||
try {
|
||||
libc = ctypes.open("kernel32.dll");
|
||||
} catch (ex) {
|
||||
// Note: If you change the string here, please adapt consumers and
|
||||
// tests accordingly
|
||||
throw new Error("Could not open system library: " + ex.message);
|
||||
}
|
||||
exports.libc = libc;
|
||||
|
||||
// Open libc
|
||||
let libc;
|
||||
try {
|
||||
libc = ctypes.open("kernel32.dll");
|
||||
} catch (ex) {
|
||||
// Note: If you change the string here, please adapt consumers and
|
||||
// tests accordingly
|
||||
throw new Error("Could not open system library: " + ex.message);
|
||||
}
|
||||
exports.OS.Shared.Win.libc = libc;
|
||||
// Define declareFFI
|
||||
let declareFFI = SharedAll.declareFFI.bind(null, libc);
|
||||
exports.declareFFI = declareFFI;
|
||||
|
||||
// Define declareFFI
|
||||
let declareFFI = OS.Shared.declareFFI.bind(null, libc);
|
||||
exports.OS.Shared.Win.declareFFI = declareFFI;
|
||||
// Define Error
|
||||
let FormatMessage = libc.declare("FormatMessageW", ctypes.winapi_abi,
|
||||
/*return*/ ctypes.uint32_t,
|
||||
/*flags*/ ctypes.uint32_t,
|
||||
/*source*/ ctypes.voidptr_t,
|
||||
/*msgid*/ ctypes.uint32_t,
|
||||
/*langid*/ ctypes.uint32_t,
|
||||
/*buf*/ ctypes.jschar.ptr,
|
||||
/*size*/ ctypes.uint32_t,
|
||||
/*Arguments*/ctypes.voidptr_t
|
||||
);
|
||||
|
||||
// Define Error
|
||||
let FormatMessage = libc.declare("FormatMessageW", ctypes.winapi_abi,
|
||||
/*return*/ ctypes.uint32_t,
|
||||
/*flags*/ ctypes.uint32_t,
|
||||
/*source*/ ctypes.voidptr_t,
|
||||
/*msgid*/ ctypes.uint32_t,
|
||||
/*langid*/ ctypes.uint32_t,
|
||||
/*buf*/ ctypes.jschar.ptr,
|
||||
/*size*/ ctypes.uint32_t,
|
||||
/*Arguments*/ctypes.voidptr_t
|
||||
/**
|
||||
* A File-related error.
|
||||
*
|
||||
* To obtain a human-readable error message, use method |toString|.
|
||||
* To determine the cause of the error, use the various |becauseX|
|
||||
* getters. To determine the operation that failed, use field
|
||||
* |operation|.
|
||||
*
|
||||
* Additionally, this implementation offers a field
|
||||
* |winLastError|, which holds the OS-specific error
|
||||
* constant. If you need this level of detail, you may match the value
|
||||
* of this field against the error constants of |OS.Constants.Win|.
|
||||
*
|
||||
* @param {string=} operation The operation that failed. If unspecified,
|
||||
* the name of the calling function is taken to be the operation that
|
||||
* failed.
|
||||
* @param {number=} lastError The OS-specific constant detailing the
|
||||
* reason of the error. If unspecified, this is fetched from the system
|
||||
* status.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {OS.Shared.Error}
|
||||
*/
|
||||
let OSError = function OSError(operation, lastError) {
|
||||
operation = operation || "unknown operation";
|
||||
SharedAll.OSError.call(this, operation);
|
||||
this.winLastError = lastError || ctypes.winLastError;
|
||||
};
|
||||
OSError.prototype = Object.create(SharedAll.OSError.prototype);
|
||||
OSError.prototype.toString = function toString() {
|
||||
let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))();
|
||||
let result = FormatMessage(
|
||||
Const.FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
Const.FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
null,
|
||||
/* The error number */ this.winLastError,
|
||||
/* Default language */ 0,
|
||||
/* Output buffer*/ buf,
|
||||
/* Minimum size of buffer */ 1024,
|
||||
/* Format args*/ null
|
||||
);
|
||||
if (!result) {
|
||||
buf = "additional error " +
|
||||
ctypes.winLastError +
|
||||
" while fetching system error message";
|
||||
}
|
||||
return "Win error " + this.winLastError + " during operation "
|
||||
+ this.operation + " (" + buf.readString() + ")";
|
||||
};
|
||||
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* already exists, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseExists", {
|
||||
get: function becauseExists() {
|
||||
return this.winLastError == Const.ERROR_FILE_EXISTS ||
|
||||
this.winLastError == Const.ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* does not exist, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
|
||||
get: function becauseNoSuchFile() {
|
||||
return this.winLastError == Const.ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a directory is not empty
|
||||
* does not exist, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
|
||||
get: function becauseNotEmpty() {
|
||||
return this.winLastError == Const.ERROR_DIR_NOT_EMPTY;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* is closed, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseClosed", {
|
||||
get: function becauseClosed() {
|
||||
return this.winLastError == Const.ERROR_INVALID_HANDLE;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because permission is denied to
|
||||
* access a file or directory, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
|
||||
get: function becauseAccessDenied() {
|
||||
return this.winLastError == Const.ERROR_ACCESS_DENIED;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
* transmitted across threads (not necessarily a string).
|
||||
*/
|
||||
OSError.toMsg = function toMsg(error) {
|
||||
return {
|
||||
operation: error.operation,
|
||||
winLastError: error.winLastError
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Deserialize a message back to an instance of OSError
|
||||
*/
|
||||
OSError.fromMsg = function fromMsg(msg) {
|
||||
return new OSError(msg.operation, msg.winLastError);
|
||||
};
|
||||
exports.Error = OSError;
|
||||
|
||||
/**
|
||||
* Code shared by implementation of File.Info on Windows
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
|
||||
lastAccessDate, lastWriteDate) {
|
||||
this._isDir = isDir;
|
||||
this._isSymLink = isSymLink;
|
||||
this._size = size;
|
||||
this._winBirthDate = winBirthDate;
|
||||
this._lastAccessDate = lastAccessDate;
|
||||
this._lastModificationDate = lastWriteDate;
|
||||
};
|
||||
|
||||
AbstractInfo.prototype = {
|
||||
/**
|
||||
* A File-related error.
|
||||
* |true| if this file is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* |true| if this file is a symbolic link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return this._isSymLink;
|
||||
},
|
||||
/**
|
||||
* The size of the file, in bytes.
|
||||
*
|
||||
* To obtain a human-readable error message, use method |toString|.
|
||||
* To determine the cause of the error, use the various |becauseX|
|
||||
* getters. To determine the operation that failed, use field
|
||||
* |operation|.
|
||||
* Note that the result may be |NaN| if the size of the file cannot be
|
||||
* represented in JavaScript.
|
||||
*
|
||||
* Additionally, this implementation offers a field
|
||||
* |winLastError|, which holds the OS-specific error
|
||||
* constant. If you need this level of detail, you may match the value
|
||||
* of this field against the error constants of |OS.Constants.Win|.
|
||||
* @type {number}
|
||||
*/
|
||||
get size() {
|
||||
return this._size;
|
||||
},
|
||||
// Deprecated
|
||||
get creationDate() {
|
||||
return this._winBirthDate;
|
||||
},
|
||||
/**
|
||||
* The date of creation of this file.
|
||||
*
|
||||
* @param {string=} operation The operation that failed. If unspecified,
|
||||
* the name of the calling function is taken to be the operation that
|
||||
* failed.
|
||||
* @param {number=} lastError The OS-specific constant detailing the
|
||||
* reason of the error. If unspecified, this is fetched from the system
|
||||
* status.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winBirthDate() {
|
||||
return this._winBirthDate;
|
||||
},
|
||||
/**
|
||||
* The date of last access to this file.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {OS.Shared.Error}
|
||||
*/
|
||||
let OSError = function OSError(operation, lastError) {
|
||||
operation = operation || "unknown operation";
|
||||
exports.OS.Shared.Error.call(this, operation);
|
||||
this.winLastError = lastError || ctypes.winLastError;
|
||||
};
|
||||
OSError.prototype = new exports.OS.Shared.Error();
|
||||
OSError.prototype.toString = function toString() {
|
||||
let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))();
|
||||
let result = FormatMessage(
|
||||
exports.OS.Constants.Win.FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
exports.OS.Constants.Win.FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
null,
|
||||
/* The error number */ this.winLastError,
|
||||
/* Default language */ 0,
|
||||
/* Output buffer*/ buf,
|
||||
/* Minimum size of buffer */ 1024,
|
||||
/* Format args*/ null
|
||||
);
|
||||
if (!result) {
|
||||
buf = "additional error " +
|
||||
ctypes.winLastError +
|
||||
" while fetching system error message";
|
||||
}
|
||||
return "Win error " + this.winLastError + " during operation "
|
||||
+ this.operation + " (" + buf.readString() + ")";
|
||||
};
|
||||
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* already exists, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseExists", {
|
||||
get: function becauseExists() {
|
||||
return this.winLastError == exports.OS.Constants.Win.ERROR_FILE_EXISTS ||
|
||||
this.winLastError == exports.OS.Constants.Win.ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* does not exist, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
|
||||
get: function becauseNoSuchFile() {
|
||||
return this.winLastError == exports.OS.Constants.Win.ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a directory is not empty
|
||||
* does not exist, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
|
||||
get: function becauseNotEmpty() {
|
||||
return this.winLastError == OS.Constants.Win.ERROR_DIR_NOT_EMPTY;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* is closed, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseClosed", {
|
||||
get: function becauseClosed() {
|
||||
return this.winLastError == exports.OS.Constants.Win.ERROR_INVALID_HANDLE;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because permission is denied to
|
||||
* access a file or directory, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
|
||||
get: function becauseAccessDenied() {
|
||||
return this.winLastError == exports.OS.Constants.Win.ERROR_ACCESS_DENIED;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
* transmitted across threads (not necessarily a string).
|
||||
*/
|
||||
OSError.toMsg = function toMsg(error) {
|
||||
return {
|
||||
operation: error.operation,
|
||||
winLastError: error.winLastError
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Deserialize a message back to an instance of OSError
|
||||
*/
|
||||
OSError.fromMsg = function fromMsg(msg) {
|
||||
return new OSError(msg.operation, msg.winLastError);
|
||||
};
|
||||
|
||||
exports.OS.Shared.Win.Error = OSError;
|
||||
|
||||
/**
|
||||
* Code shared by implementation of File.Info on Windows
|
||||
* Note that the definition of last access may depend on the underlying
|
||||
* operating system and file system.
|
||||
*
|
||||
* @constructor
|
||||
* @type {Date}
|
||||
*/
|
||||
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
|
||||
lastAccessDate, lastWriteDate) {
|
||||
this._isDir = isDir;
|
||||
this._isSymLink = isSymLink;
|
||||
this._size = size;
|
||||
this._winBirthDate = winBirthDate;
|
||||
this._lastAccessDate = lastAccessDate;
|
||||
this._lastModificationDate = lastWriteDate;
|
||||
};
|
||||
|
||||
AbstractInfo.prototype = {
|
||||
/**
|
||||
* |true| if this file is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* |true| if this file is a symbolic link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return this._isSymLink;
|
||||
},
|
||||
/**
|
||||
* The size of the file, in bytes.
|
||||
*
|
||||
* Note that the result may be |NaN| if the size of the file cannot be
|
||||
* represented in JavaScript.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get size() {
|
||||
return this._size;
|
||||
},
|
||||
// Deprecated
|
||||
get creationDate() {
|
||||
return this._winBirthDate;
|
||||
},
|
||||
/**
|
||||
* The date of creation of this file.
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
get winBirthDate() {
|
||||
return this._winBirthDate;
|
||||
},
|
||||
/**
|
||||
* The date of last access to this file.
|
||||
*
|
||||
* Note that the definition of last access may depend on the underlying
|
||||
* operating system and file system.
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
get lastAccessDate() {
|
||||
return this._lastAccessDate;
|
||||
},
|
||||
/**
|
||||
* The date of last modification of this file.
|
||||
*
|
||||
* Note that the definition of last access may depend on the underlying
|
||||
* operating system and file system.
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
get lastModificationDate() {
|
||||
return this._lastModificationDate;
|
||||
}
|
||||
};
|
||||
exports.OS.Shared.Win.AbstractInfo = AbstractInfo;
|
||||
|
||||
get lastAccessDate() {
|
||||
return this._lastAccessDate;
|
||||
},
|
||||
/**
|
||||
* Code shared by implementation of File.DirectoryIterator.Entry on Windows
|
||||
* The date of last modification of this file.
|
||||
*
|
||||
* @constructor
|
||||
* Note that the definition of last access may depend on the underlying
|
||||
* operating system and file system.
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name,
|
||||
winCreationDate, winLastWriteDate,
|
||||
winLastAccessDate, path) {
|
||||
this._isDir = isDir;
|
||||
this._isSymLink = isSymLink;
|
||||
this._name = name;
|
||||
this._winCreationDate = winCreationDate;
|
||||
this._winLastWriteDate = winLastWriteDate;
|
||||
this._winLastAccessDate = winLastAccessDate;
|
||||
this._path = path;
|
||||
};
|
||||
get lastModificationDate() {
|
||||
return this._lastModificationDate;
|
||||
}
|
||||
};
|
||||
exports.AbstractInfo = AbstractInfo;
|
||||
|
||||
AbstractEntry.prototype = {
|
||||
/**
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* |true| if the entry is a symbolic link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return this._isSymLink;
|
||||
},
|
||||
/**
|
||||
* The name of the entry.
|
||||
* @type {string}
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
/**
|
||||
* The creation time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winCreationDate() {
|
||||
return this._winCreationDate;
|
||||
},
|
||||
/**
|
||||
* The last modification time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winLastWriteDate() {
|
||||
return this._winLastWriteDate;
|
||||
},
|
||||
/**
|
||||
* The last access time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winLastAccessDate() {
|
||||
return this._winLastAccessDate;
|
||||
},
|
||||
/**
|
||||
* The full path of the entry
|
||||
* @type {string}
|
||||
*/
|
||||
get path() {
|
||||
return this._path;
|
||||
}
|
||||
};
|
||||
exports.OS.Shared.Win.AbstractEntry = AbstractEntry;
|
||||
|
||||
// Special constants that need to be defined on all platforms
|
||||
|
||||
Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.Win.FILE_BEGIN });
|
||||
Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.Win.FILE_CURRENT });
|
||||
Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.Win.FILE_END });
|
||||
|
||||
// Special types that need to be defined for communication
|
||||
// between threads
|
||||
let Types = exports.OS.Shared.Type;
|
||||
/**
|
||||
* Code shared by implementation of File.DirectoryIterator.Entry on Windows
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name,
|
||||
winCreationDate, winLastWriteDate,
|
||||
winLastAccessDate, path) {
|
||||
this._isDir = isDir;
|
||||
this._isSymLink = isSymLink;
|
||||
this._name = name;
|
||||
this._winCreationDate = winCreationDate;
|
||||
this._winLastWriteDate = winLastWriteDate;
|
||||
this._winLastAccessDate = winLastAccessDate;
|
||||
this._path = path;
|
||||
};
|
||||
|
||||
AbstractEntry.prototype = {
|
||||
/**
|
||||
* Native paths
|
||||
*
|
||||
* Under Windows, expressed as wide strings
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
Types.path = Types.wstring.withName("[in] path");
|
||||
Types.out_path = Types.out_wstring.withName("[out] path");
|
||||
get isDir() {
|
||||
return this._isDir;
|
||||
},
|
||||
/**
|
||||
* |true| if the entry is a symbolic link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return this._isSymLink;
|
||||
},
|
||||
/**
|
||||
* The name of the entry.
|
||||
* @type {string}
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
/**
|
||||
* The creation time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winCreationDate() {
|
||||
return this._winCreationDate;
|
||||
},
|
||||
/**
|
||||
* The last modification time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winLastWriteDate() {
|
||||
return this._winLastWriteDate;
|
||||
},
|
||||
/**
|
||||
* The last access time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winLastAccessDate() {
|
||||
return this._winLastAccessDate;
|
||||
},
|
||||
/**
|
||||
* The full path of the entry
|
||||
* @type {string}
|
||||
*/
|
||||
get path() {
|
||||
return this._path;
|
||||
}
|
||||
};
|
||||
exports.AbstractEntry = AbstractEntry;
|
||||
|
||||
// Special constructors that need to be defined on all threads
|
||||
OSError.closed = function closed(operation) {
|
||||
return new OSError(operation, exports.OS.Constants.Win.ERROR_INVALID_HANDLE);
|
||||
};
|
||||
// Special constants that need to be defined on all platforms
|
||||
|
||||
OSError.exists = function exists(operation) {
|
||||
return new OSError(operation, exports.OS.Constants.Win.ERROR_FILE_EXISTS);
|
||||
};
|
||||
exports.POS_START = Const.FILE_BEGIN;
|
||||
exports.POS_CURRENT = Const.FILE_CURRENT;
|
||||
exports.POS_END = Const.FILE_END;
|
||||
|
||||
OSError.noSuchFile = function noSuchFile(operation) {
|
||||
return new OSError(operation, exports.OS.Constants.Win.ERROR_FILE_NOT_FOUND);
|
||||
};
|
||||
})(this);
|
||||
// Special types that need to be defined for communication
|
||||
// between threads
|
||||
let Type = Object.create(SharedAll.Type);
|
||||
exports.Type = Type;
|
||||
|
||||
/**
|
||||
* Native paths
|
||||
*
|
||||
* Under Windows, expressed as wide strings
|
||||
*/
|
||||
Type.path = Type.wstring.withName("[in] path");
|
||||
Type.out_path = Type.out_wstring.withName("[out] path");
|
||||
|
||||
// Special constructors that need to be defined on all threads
|
||||
OSError.closed = function closed(operation) {
|
||||
return new OSError(operation, Const.ERROR_INVALID_HANDLE);
|
||||
};
|
||||
|
||||
OSError.exists = function exists(operation) {
|
||||
return new OSError(operation, Const.ERROR_FILE_EXISTS);
|
||||
};
|
||||
|
||||
OSError.noSuchFile = function noSuchFile(operation) {
|
||||
return new OSError(operation, Const.ERROR_FILE_NOT_FOUND);
|
||||
};
|
||||
|
||||
let EXPORTED_SYMBOLS = [
|
||||
"declareFFI",
|
||||
"libc",
|
||||
"Error",
|
||||
"AbstractInfo",
|
||||
"AbstractEntry",
|
||||
"Type",
|
||||
"POS_START",
|
||||
"POS_CURRENT",
|
||||
"POS_END"
|
||||
];
|
||||
|
||||
//////////// Boilerplate
|
||||
if (typeof Components != "undefined") {
|
||||
this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
|
||||
for (let symbol of EXPORTED_SYMBOLS) {
|
||||
this[symbol] = exports[symbol];
|
||||
}
|
||||
}
|
||||
|
@ -34,11 +34,12 @@
|
||||
if (exports.OS && exports.OS.Win && exports.OS.Win.File) {
|
||||
return; // Avoid double initialization
|
||||
}
|
||||
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
|
||||
exports.OS.Win.File = {};
|
||||
|
||||
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win", "back");
|
||||
let libc = exports.OS.Shared.Win.libc;
|
||||
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
let SysAll = require("resource://gre/modules/osfile/osfile_win_allthreads.jsm");
|
||||
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "back");
|
||||
let libc = SysAll.libc;
|
||||
let Const = SharedAll.Constants.Win;
|
||||
|
||||
/**
|
||||
* Initialize the Windows module.
|
||||
@ -51,17 +52,14 @@
|
||||
if (aDeclareFFI) {
|
||||
declareFFI = aDeclareFFI.bind(null, libc);
|
||||
} else {
|
||||
declareFFI = exports.OS.Shared.Win.declareFFI;
|
||||
declareFFI = SysAll.declareFFI;
|
||||
}
|
||||
|
||||
// Shorthands
|
||||
let OSWin = exports.OS.Win;
|
||||
let WinFile = exports.OS.Win.File;
|
||||
if (!exports.OS.Types) {
|
||||
exports.OS.Types = {};
|
||||
}
|
||||
let Type = exports.OS.Shared.Type;
|
||||
let Types = Type;
|
||||
// Initialize types that require additional OS-specific
|
||||
// support - either finalization or matching against
|
||||
// OS-specific constants.
|
||||
let Type = Object.create(SysAll.Type);
|
||||
let SysFile = exports.OS.Win.File = { Type: Type };
|
||||
|
||||
// Initialize types
|
||||
|
||||
@ -69,10 +67,10 @@
|
||||
* A C integer holding INVALID_HANDLE_VALUE in case of error or
|
||||
* a file descriptor in case of success.
|
||||
*/
|
||||
Types.HANDLE =
|
||||
Types.voidptr_t.withName("HANDLE");
|
||||
Types.HANDLE.importFromC = function importFromC(maybe) {
|
||||
if (Types.int.cast(maybe).value == INVALID_HANDLE) {
|
||||
Type.HANDLE =
|
||||
Type.voidptr_t.withName("HANDLE");
|
||||
Type.HANDLE.importFromC = function importFromC(maybe) {
|
||||
if (Type.int.cast(maybe).value == INVALID_HANDLE) {
|
||||
// Ensure that API clients can effectively compare against
|
||||
// Const.INVALID_HANDLE_VALUE. Without this cast,
|
||||
// == would always return |false|.
|
||||
@ -80,88 +78,88 @@
|
||||
}
|
||||
return ctypes.CDataFinalizer(maybe, this.finalizeHANDLE);
|
||||
};
|
||||
Types.HANDLE.finalizeHANDLE = function placeholder() {
|
||||
Type.HANDLE.finalizeHANDLE = function placeholder() {
|
||||
throw new Error("finalizeHANDLE should be implemented");
|
||||
};
|
||||
let INVALID_HANDLE = exports.OS.Constants.Win.INVALID_HANDLE_VALUE;
|
||||
let INVALID_HANDLE = Const.INVALID_HANDLE_VALUE;
|
||||
|
||||
Types.file_HANDLE = Types.HANDLE.withName("file HANDLE");
|
||||
exports.OS.Shared.defineLazyGetter(Types.file_HANDLE,
|
||||
Type.file_HANDLE = Type.HANDLE.withName("file HANDLE");
|
||||
SharedAll.defineLazyGetter(Type.file_HANDLE,
|
||||
"finalizeHANDLE",
|
||||
function() {
|
||||
return _CloseHandle;
|
||||
});
|
||||
|
||||
Types.find_HANDLE = Types.HANDLE.withName("find HANDLE");
|
||||
exports.OS.Shared.defineLazyGetter(Types.find_HANDLE,
|
||||
Type.find_HANDLE = Type.HANDLE.withName("find HANDLE");
|
||||
SharedAll.defineLazyGetter(Type.find_HANDLE,
|
||||
"finalizeHANDLE",
|
||||
function() {
|
||||
return _FindClose;
|
||||
});
|
||||
|
||||
Types.DWORD = Types.int32_t.withName("DWORD");
|
||||
Type.DWORD = Type.int32_t.withName("DWORD");
|
||||
|
||||
/**
|
||||
* A C integer holding -1 in case of error or a positive integer
|
||||
* in case of success.
|
||||
*/
|
||||
Types.negative_or_DWORD =
|
||||
Types.DWORD.withName("negative_or_DWORD");
|
||||
Type.negative_or_DWORD =
|
||||
Type.DWORD.withName("negative_or_DWORD");
|
||||
|
||||
/**
|
||||
* A C integer holding 0 in case of error or a positive integer
|
||||
* in case of success.
|
||||
*/
|
||||
Types.zero_or_DWORD =
|
||||
Types.DWORD.withName("zero_or_DWORD");
|
||||
Type.zero_or_DWORD =
|
||||
Type.DWORD.withName("zero_or_DWORD");
|
||||
|
||||
/**
|
||||
* A C integer holding 0 in case of error, any other value in
|
||||
* case of success.
|
||||
*/
|
||||
Types.zero_or_nothing =
|
||||
Types.int.withName("zero_or_nothing");
|
||||
Type.zero_or_nothing =
|
||||
Type.int.withName("zero_or_nothing");
|
||||
|
||||
Types.SECURITY_ATTRIBUTES =
|
||||
Types.void_t.withName("SECURITY_ATTRIBUTES");
|
||||
Type.SECURITY_ATTRIBUTES =
|
||||
Type.void_t.withName("SECURITY_ATTRIBUTES");
|
||||
|
||||
Types.FILETIME =
|
||||
new Type("FILETIME",
|
||||
Type.FILETIME =
|
||||
new SharedAll.Type("FILETIME",
|
||||
ctypes.StructType("FILETIME", [
|
||||
{ lo: Types.DWORD.implementation },
|
||||
{ hi: Types.DWORD.implementation }]));
|
||||
{ lo: Type.DWORD.implementation },
|
||||
{ hi: Type.DWORD.implementation }]));
|
||||
|
||||
Types.FindData =
|
||||
new Type("FIND_DATA",
|
||||
Type.FindData =
|
||||
new SharedAll.Type("FIND_DATA",
|
||||
ctypes.StructType("FIND_DATA", [
|
||||
{ dwFileAttributes: ctypes.uint32_t },
|
||||
{ ftCreationTime: Types.FILETIME.implementation },
|
||||
{ ftLastAccessTime: Types.FILETIME.implementation },
|
||||
{ ftLastWriteTime: Types.FILETIME.implementation },
|
||||
{ nFileSizeHigh: Types.DWORD.implementation },
|
||||
{ nFileSizeLow: Types.DWORD.implementation },
|
||||
{ dwReserved0: Types.DWORD.implementation },
|
||||
{ dwReserved1: Types.DWORD.implementation },
|
||||
{ cFileName: ctypes.ArrayType(ctypes.jschar, exports.OS.Constants.Win.MAX_PATH) },
|
||||
{ ftCreationTime: Type.FILETIME.implementation },
|
||||
{ ftLastAccessTime: Type.FILETIME.implementation },
|
||||
{ ftLastWriteTime: Type.FILETIME.implementation },
|
||||
{ nFileSizeHigh: Type.DWORD.implementation },
|
||||
{ nFileSizeLow: Type.DWORD.implementation },
|
||||
{ dwReserved0: Type.DWORD.implementation },
|
||||
{ dwReserved1: Type.DWORD.implementation },
|
||||
{ cFileName: ctypes.ArrayType(ctypes.jschar, Const.MAX_PATH) },
|
||||
{ cAlternateFileName: ctypes.ArrayType(ctypes.jschar, 14) }
|
||||
]));
|
||||
|
||||
Types.FILE_INFORMATION =
|
||||
new Type("FILE_INFORMATION",
|
||||
Type.FILE_INFORMATION =
|
||||
new SharedAll.Type("FILE_INFORMATION",
|
||||
ctypes.StructType("FILE_INFORMATION", [
|
||||
{ dwFileAttributes: ctypes.uint32_t },
|
||||
{ ftCreationTime: Types.FILETIME.implementation },
|
||||
{ ftLastAccessTime: Types.FILETIME.implementation },
|
||||
{ ftLastWriteTime: Types.FILETIME.implementation },
|
||||
{ ftCreationTime: Type.FILETIME.implementation },
|
||||
{ ftLastAccessTime: Type.FILETIME.implementation },
|
||||
{ ftLastWriteTime: Type.FILETIME.implementation },
|
||||
{ dwVolumeSerialNumber: ctypes.uint32_t },
|
||||
{ nFileSizeHigh: Types.DWORD.implementation },
|
||||
{ nFileSizeLow: Types.DWORD.implementation },
|
||||
{ nFileSizeHigh: Type.DWORD.implementation },
|
||||
{ nFileSizeLow: Type.DWORD.implementation },
|
||||
{ nNumberOfLinks: ctypes.uint32_t },
|
||||
{ nFileIndex: ctypes.uint64_t }
|
||||
]));
|
||||
|
||||
Types.SystemTime =
|
||||
new Type("SystemTime",
|
||||
Type.SystemTime =
|
||||
new SharedAll.Type("SystemTime",
|
||||
ctypes.StructType("SystemTime", [
|
||||
{ wYear: ctypes.int16_t },
|
||||
{ wMonth: ctypes.int16_t },
|
||||
@ -175,12 +173,12 @@
|
||||
|
||||
// Special case: these functions are used by the
|
||||
// finalizer
|
||||
let _CloseHandle = WinFile._CloseHandle =
|
||||
let _CloseHandle = SysFile._CloseHandle =
|
||||
libc.declare("CloseHandle", ctypes.winapi_abi,
|
||||
/*return */ctypes.bool,
|
||||
/*handle*/ ctypes.voidptr_t);
|
||||
|
||||
WinFile.CloseHandle = function(fd) {
|
||||
SysFile.CloseHandle = function(fd) {
|
||||
if (fd == INVALID_HANDLE) {
|
||||
return true;
|
||||
} else {
|
||||
@ -193,7 +191,7 @@
|
||||
/*return */ctypes.bool,
|
||||
/*handle*/ ctypes.voidptr_t);
|
||||
|
||||
WinFile.FindClose = function(handle) {
|
||||
SysFile.FindClose = function(handle) {
|
||||
if (handle == INVALID_HANDLE) {
|
||||
return true;
|
||||
} else {
|
||||
@ -203,135 +201,140 @@
|
||||
|
||||
// Declare libc functions as functions of |OS.Win.File|
|
||||
|
||||
WinFile.CopyFile =
|
||||
SysFile.CopyFile =
|
||||
declareFFI("CopyFileW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*sourcePath*/ Types.path,
|
||||
/*destPath*/ Types.path,
|
||||
/*bailIfExist*/Types.bool);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*sourcePath*/ Type.path,
|
||||
/*destPath*/ Type.path,
|
||||
/*bailIfExist*/Type.bool);
|
||||
|
||||
WinFile.CreateDirectory =
|
||||
SysFile.CreateDirectory =
|
||||
declareFFI("CreateDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*name*/ Types.jschar.in_ptr,
|
||||
/*security*/Types.SECURITY_ATTRIBUTES.in_ptr);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*name*/ Type.jschar.in_ptr,
|
||||
/*security*/Type.SECURITY_ATTRIBUTES.in_ptr);
|
||||
|
||||
WinFile.CreateFile =
|
||||
SysFile.CreateFile =
|
||||
declareFFI("CreateFileW", ctypes.winapi_abi,
|
||||
/*return*/ Types.file_HANDLE,
|
||||
/*name*/ Types.path,
|
||||
/*access*/ Types.DWORD,
|
||||
/*share*/ Types.DWORD,
|
||||
/*security*/Types.SECURITY_ATTRIBUTES.in_ptr,
|
||||
/*creation*/Types.DWORD,
|
||||
/*flags*/ Types.DWORD,
|
||||
/*template*/Types.HANDLE);
|
||||
/*return*/ Type.file_HANDLE,
|
||||
/*name*/ Type.path,
|
||||
/*access*/ Type.DWORD,
|
||||
/*share*/ Type.DWORD,
|
||||
/*security*/Type.SECURITY_ATTRIBUTES.in_ptr,
|
||||
/*creation*/Type.DWORD,
|
||||
/*flags*/ Type.DWORD,
|
||||
/*template*/Type.HANDLE);
|
||||
|
||||
WinFile.DeleteFile =
|
||||
SysFile.DeleteFile =
|
||||
declareFFI("DeleteFileW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*path*/ Types.path);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
WinFile.FileTimeToSystemTime =
|
||||
SysFile.FileTimeToSystemTime =
|
||||
declareFFI("FileTimeToSystemTime", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*filetime*/Types.FILETIME.in_ptr,
|
||||
/*systime*/ Types.SystemTime.out_ptr);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*filetime*/Type.FILETIME.in_ptr,
|
||||
/*systime*/ Type.SystemTime.out_ptr);
|
||||
|
||||
WinFile.FindFirstFile =
|
||||
SysFile.FindFirstFile =
|
||||
declareFFI("FindFirstFileW", ctypes.winapi_abi,
|
||||
/*return*/ Types.find_HANDLE,
|
||||
/*pattern*/Types.path,
|
||||
/*data*/ Types.FindData.out_ptr);
|
||||
/*return*/ Type.find_HANDLE,
|
||||
/*pattern*/Type.path,
|
||||
/*data*/ Type.FindData.out_ptr);
|
||||
|
||||
WinFile.FindNextFile =
|
||||
SysFile.FindNextFile =
|
||||
declareFFI("FindNextFileW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*prev*/ Types.find_HANDLE,
|
||||
/*data*/ Types.FindData.out_ptr);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*prev*/ Type.find_HANDLE,
|
||||
/*data*/ Type.FindData.out_ptr);
|
||||
|
||||
WinFile.FormatMessage =
|
||||
SysFile.FormatMessage =
|
||||
declareFFI("FormatMessageW", ctypes.winapi_abi,
|
||||
/*return*/ Types.DWORD,
|
||||
/*flags*/ Types.DWORD,
|
||||
/*source*/ Types.void_t.in_ptr,
|
||||
/*msgid*/ Types.DWORD,
|
||||
/*langid*/ Types.DWORD,
|
||||
/*buf*/ Types.out_wstring,
|
||||
/*size*/ Types.DWORD,
|
||||
/*Arguments*/Types.void_t.in_ptr
|
||||
/*return*/ Type.DWORD,
|
||||
/*flags*/ Type.DWORD,
|
||||
/*source*/ Type.void_t.in_ptr,
|
||||
/*msgid*/ Type.DWORD,
|
||||
/*langid*/ Type.DWORD,
|
||||
/*buf*/ Type.out_wstring,
|
||||
/*size*/ Type.DWORD,
|
||||
/*Arguments*/Type.void_t.in_ptr
|
||||
);
|
||||
|
||||
WinFile.GetCurrentDirectory =
|
||||
SysFile.GetCurrentDirectory =
|
||||
declareFFI("GetCurrentDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_DWORD,
|
||||
/*length*/ Types.DWORD,
|
||||
/*buf*/ Types.out_path
|
||||
/*return*/ Type.zero_or_DWORD,
|
||||
/*length*/ Type.DWORD,
|
||||
/*buf*/ Type.out_path
|
||||
);
|
||||
|
||||
WinFile.GetFileInformationByHandle =
|
||||
SysFile.GetFileInformationByHandle =
|
||||
declareFFI("GetFileInformationByHandle", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*handle*/ Types.HANDLE,
|
||||
/*info*/ Types.FILE_INFORMATION.out_ptr);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*handle*/ Type.HANDLE,
|
||||
/*info*/ Type.FILE_INFORMATION.out_ptr);
|
||||
|
||||
WinFile.MoveFileEx =
|
||||
SysFile.MoveFileEx =
|
||||
declareFFI("MoveFileExW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*sourcePath*/ Types.path,
|
||||
/*destPath*/ Types.path,
|
||||
/*flags*/ Types.DWORD
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*sourcePath*/ Type.path,
|
||||
/*destPath*/ Type.path,
|
||||
/*flags*/ Type.DWORD
|
||||
);
|
||||
|
||||
WinFile.ReadFile =
|
||||
SysFile.ReadFile =
|
||||
declareFFI("ReadFile", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*file*/ Types.HANDLE,
|
||||
/*buffer*/ Types.voidptr_t,
|
||||
/*nbytes*/ Types.DWORD,
|
||||
/*nbytes_read*/Types.DWORD.out_ptr,
|
||||
/*overlapped*/Types.void_t.inout_ptr // FIXME: Implement?
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE,
|
||||
/*buffer*/ Type.voidptr_t,
|
||||
/*nbytes*/ Type.DWORD,
|
||||
/*nbytes_read*/Type.DWORD.out_ptr,
|
||||
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
|
||||
);
|
||||
|
||||
WinFile.RemoveDirectory =
|
||||
SysFile.RemoveDirectory =
|
||||
declareFFI("RemoveDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*path*/ Types.path);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*path*/ Type.path);
|
||||
|
||||
WinFile.SetCurrentDirectory =
|
||||
SysFile.SetCurrentDirectory =
|
||||
declareFFI("SetCurrentDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*path*/ Types.path
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*path*/ Type.path
|
||||
);
|
||||
|
||||
WinFile.SetEndOfFile =
|
||||
SysFile.SetEndOfFile =
|
||||
declareFFI("SetEndOfFile", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*file*/ Types.HANDLE);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE);
|
||||
|
||||
WinFile.SetFilePointer =
|
||||
SysFile.SetFilePointer =
|
||||
declareFFI("SetFilePointer", ctypes.winapi_abi,
|
||||
/*return*/ Types.negative_or_DWORD,
|
||||
/*file*/ Types.HANDLE,
|
||||
/*distlow*/Types.long,
|
||||
/*disthi*/ Types.long.in_ptr,
|
||||
/*method*/ Types.DWORD);
|
||||
/*return*/ Type.negative_or_DWORD,
|
||||
/*file*/ Type.HANDLE,
|
||||
/*distlow*/Type.long,
|
||||
/*disthi*/ Type.long.in_ptr,
|
||||
/*method*/ Type.DWORD);
|
||||
|
||||
WinFile.WriteFile =
|
||||
SysFile.WriteFile =
|
||||
declareFFI("WriteFile", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*file*/ Types.HANDLE,
|
||||
/*buffer*/ Types.voidptr_t,
|
||||
/*nbytes*/ Types.DWORD,
|
||||
/*nbytes_wr*/Types.DWORD.out_ptr,
|
||||
/*overlapped*/Types.void_t.inout_ptr // FIXME: Implement?
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE,
|
||||
/*buffer*/ Type.voidptr_t,
|
||||
/*nbytes*/ Type.DWORD,
|
||||
/*nbytes_wr*/Type.DWORD.out_ptr,
|
||||
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
|
||||
);
|
||||
|
||||
WinFile.FlushFileBuffers =
|
||||
SysFile.FlushFileBuffers =
|
||||
declareFFI("FlushFileBuffers", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*file*/ Types.HANDLE);
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE);
|
||||
};
|
||||
|
||||
exports.OS.Win = {
|
||||
File: {
|
||||
_init: init
|
||||
}
|
||||
};
|
||||
exports.OS.Win.File._init = init;
|
||||
})(this);
|
||||
}
|
||||
|
@ -19,18 +19,19 @@
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
|
||||
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
|
||||
let Path = require("resource://gre/modules/osfile/ospath.jsm");
|
||||
|
||||
// exports.OS.Win is created by osfile_win_back.jsm
|
||||
if (exports.OS && exports.OS.File) {
|
||||
return; // Avoid double-initialization
|
||||
}
|
||||
|
||||
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
let Path = require("resource://gre/modules/osfile/ospath.jsm");
|
||||
let SysAll = require("resource://gre/modules/osfile/osfile_win_allthreads.jsm");
|
||||
exports.OS.Win.File._init();
|
||||
let Const = exports.OS.Constants.Win;
|
||||
let WinFile = exports.OS.Win.File;
|
||||
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win front-end");
|
||||
let Type = WinFile.Type;
|
||||
|
||||
// Mutable thread-global data
|
||||
// In the Windows implementation, methods |read| and |write|
|
||||
@ -47,7 +48,7 @@
|
||||
let gBytesWrittenPtr = gBytesWritten.address();
|
||||
|
||||
// Same story for GetFileInformationByHandle
|
||||
let gFileInfo = new OS.Shared.Type.FILE_INFORMATION.implementation();
|
||||
let gFileInfo = new Type.FILE_INFORMATION.implementation();
|
||||
let gFileInfoPtr = gFileInfo.address();
|
||||
|
||||
/**
|
||||
@ -388,7 +389,7 @@
|
||||
let result = WinFile.CreateDirectory(path, security);
|
||||
if (result ||
|
||||
options.ignoreExisting &&
|
||||
ctypes.winLastError == OS.Constants.Win.ERROR_ALREADY_EXISTS) {
|
||||
ctypes.winLastError == Const.ERROR_ALREADY_EXISTS) {
|
||||
return;
|
||||
}
|
||||
throw new File.Error("makeDir");
|
||||
@ -465,7 +466,7 @@
|
||||
/**
|
||||
* A global value used to receive data during time conversions.
|
||||
*/
|
||||
let gSystemTime = new OS.Shared.Type.SystemTime.implementation();
|
||||
let gSystemTime = new Type.SystemTime.implementation();
|
||||
let gSystemTimePtr = gSystemTime.address();
|
||||
|
||||
/**
|
||||
@ -514,7 +515,7 @@
|
||||
|
||||
// Pre-open the first item.
|
||||
this._first = true;
|
||||
this._findData = new OS.Shared.Type.FindData.implementation();
|
||||
this._findData = new Type.FindData.implementation();
|
||||
this._findDataPtr = this._findData.address();
|
||||
this._handle = WinFile.FindFirstFile(this._pattern, this._findDataPtr);
|
||||
if (this._handle == Const.INVALID_HANDLE_VALUE) {
|
||||
@ -523,12 +524,12 @@
|
||||
this._findDataPtr = null;
|
||||
if (error == Const.ERROR_FILE_NOT_FOUND) {
|
||||
// Directory is empty, let's behave as if it were closed
|
||||
LOG("Directory is empty");
|
||||
SharedAll.LOG("Directory is empty");
|
||||
this._closed = true;
|
||||
this._exists = true;
|
||||
} else if (error == Const.ERROR_PATH_NOT_FOUND) {
|
||||
// Directory does not exist, let's throw if we attempt to walk it
|
||||
LOG("Directory does not exist");
|
||||
SharedAll.LOG("Directory does not exist");
|
||||
this._closed = true;
|
||||
this._exists = false;
|
||||
} else {
|
||||
@ -650,11 +651,11 @@
|
||||
|
||||
let path = Path.join(this._parent, name);
|
||||
|
||||
exports.OS.Shared.Win.AbstractEntry.call(this, isDir, isSymLink, name,
|
||||
winCreationDate, winLastWriteDate,
|
||||
winLastAccessDate, path);
|
||||
SysAll.AbstractEntry.call(this, isDir, isSymLink, name,
|
||||
winCreationDate, winLastWriteDate,
|
||||
winLastAccessDate, path);
|
||||
};
|
||||
File.DirectoryIterator.Entry.prototype = Object.create(exports.OS.Shared.Win.AbstractEntry.prototype);
|
||||
File.DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
|
||||
|
||||
/**
|
||||
* Return a version of an instance of
|
||||
@ -695,13 +696,13 @@
|
||||
let lastWriteDate = FILETIME_to_Date(stat.ftLastWriteTime);
|
||||
|
||||
let value = ctypes.UInt64.join(stat.nFileSizeHigh, stat.nFileSizeLow);
|
||||
let size = exports.OS.Shared.Type.uint64_t.importFromC(value);
|
||||
let size = Type.uint64_t.importFromC(value);
|
||||
|
||||
exports.OS.Shared.Win.AbstractInfo.call(this, isDir, isSymLink, size,
|
||||
winBirthDate, lastAccessDate,
|
||||
lastWriteDate);
|
||||
SysAll.AbstractInfo.call(this, isDir, isSymLink, size,
|
||||
winBirthDate, lastAccessDate,
|
||||
lastWriteDate);
|
||||
};
|
||||
File.Info.prototype = Object.create(exports.OS.Shared.Win.AbstractInfo.prototype);
|
||||
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
|
||||
|
||||
/**
|
||||
* Return a version of an instance of File.Info that can be sent
|
||||
@ -744,53 +745,54 @@
|
||||
// All of the following is required to ensure that File.stat
|
||||
// also works on directories.
|
||||
const FILE_STAT_MODE = {
|
||||
read:true
|
||||
read: true
|
||||
};
|
||||
const FILE_STAT_OPTIONS = {
|
||||
// Directories can be opened neither for reading(!) nor for writing
|
||||
winAccess: 0,
|
||||
// Directories can only be opened with backup semantics(!)
|
||||
winFlags: OS.Constants.Win.FILE_FLAG_BACKUP_SEMANTICS,
|
||||
winDisposition: OS.Constants.Win.OPEN_EXISTING
|
||||
winFlags: Const.FILE_FLAG_BACKUP_SEMANTICS,
|
||||
winDisposition: Const.OPEN_EXISTING
|
||||
};
|
||||
|
||||
File.read = exports.OS.Shared.AbstractFile.read;
|
||||
File.writeAtomic = exports.OS.Shared.AbstractFile.writeAtomic;
|
||||
File.openUnique = exports.OS.Shared.AbstractFile.openUnique;
|
||||
File.removeDir = exports.OS.Shared.AbstractFile.removeDir;
|
||||
|
||||
/**
|
||||
* Get the current directory by getCurrentDirectory.
|
||||
*/
|
||||
File.getCurrentDirectory = function getCurrentDirectory() {
|
||||
// This function is more complicated than one could hope.
|
||||
//
|
||||
// This is due to two facts:
|
||||
// - the maximal length of a path under Windows is not completely
|
||||
// specified (there is a constant MAX_PATH, but it is quite possible
|
||||
// to create paths that are much larger, see bug 744413);
|
||||
// - if we attempt to call |GetCurrentDirectory| with a buffer that
|
||||
// is too short, it returns the length of the current directory, but
|
||||
// this length might be insufficient by the time we can call again
|
||||
// the function with a larger buffer, in the (unlikely byt possible)
|
||||
// case in which the process changes directory to a directory with
|
||||
// a longer name between both calls.
|
||||
let buffer_size = 4096;
|
||||
while (true) {
|
||||
let array = new (ctypes.ArrayType(ctypes.jschar, buffer_size))();
|
||||
// This function is more complicated than one could hope.
|
||||
//
|
||||
// This is due to two facts:
|
||||
// - the maximal length of a path under Windows is not completely
|
||||
// specified (there is a constant MAX_PATH, but it is quite possible
|
||||
// to create paths that are much larger, see bug 744413);
|
||||
// - if we attempt to call |GetCurrentDirectory| with a buffer that
|
||||
// is too short, it returns the length of the current directory, but
|
||||
// this length might be insufficient by the time we can call again
|
||||
// the function with a larger buffer, in the (unlikely but possible)
|
||||
// case in which the process changes directory to a directory with
|
||||
// a longer name between both calls.
|
||||
//
|
||||
let buffer_size = 4096;
|
||||
while (true) {
|
||||
let array = new (ctypes.ArrayType(ctypes.jschar, buffer_size))();
|
||||
let expected_size = throw_on_zero("getCurrentDirectory",
|
||||
WinFile.GetCurrentDirectory(buffer_size, array)
|
||||
);
|
||||
if (expected_size <= buffer_size) {
|
||||
return array.readString();
|
||||
}
|
||||
// At this point, we are in a case in which our buffer was not
|
||||
// large enough to hold the name of the current directory.
|
||||
// Consequently
|
||||
|
||||
// Note that, even in crazy scenarios, the loop will eventually
|
||||
// converge, as the length of the paths cannot increase infinitely.
|
||||
buffer_size = expected_size;
|
||||
}
|
||||
WinFile.GetCurrentDirectory(buffer_size, array)
|
||||
);
|
||||
if (expected_size <= buffer_size) {
|
||||
return array.readString();
|
||||
}
|
||||
// At this point, we are in a case in which our buffer was not
|
||||
// large enough to hold the name of the current directory.
|
||||
// Consequently, we need to increase the size of the buffer.
|
||||
// Note that, even in crazy scenarios, the loop will eventually
|
||||
// converge, as the length of the paths cannot increase infinitely.
|
||||
buffer_size = expected_size + 1 /* to store \0 */;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -816,7 +818,7 @@
|
||||
|
||||
// Utility functions, used for error-handling
|
||||
function error_or_file(maybe) {
|
||||
if (maybe == exports.OS.Constants.Win.INVALID_HANDLE_VALUE) {
|
||||
if (maybe == Const.INVALID_HANDLE_VALUE) {
|
||||
throw new File.Error("open");
|
||||
}
|
||||
return new File(maybe);
|
||||
@ -841,13 +843,12 @@
|
||||
}
|
||||
|
||||
File.Win = exports.OS.Win.File;
|
||||
File.Error = exports.OS.Shared.Win.Error;
|
||||
File.Error = SysAll.Error;
|
||||
exports.OS.File = File;
|
||||
exports.OS.Shared.Type = Type;
|
||||
|
||||
exports.OS.Path = exports.Path;
|
||||
|
||||
Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
|
||||
Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
|
||||
Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
|
||||
Object.defineProperty(File, "POS_START", { value: SysAll.POS_START });
|
||||
Object.defineProperty(File, "POS_CURRENT", { value: SysAll.POS_CURRENT });
|
||||
Object.defineProperty(File, "POS_END", { value: SysAll.POS_END });
|
||||
})(this);
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ if (typeof Components != "undefined") {
|
||||
#ifdef XP_WIN
|
||||
importScripts(
|
||||
"resource://gre/modules/workers/require.js",
|
||||
"resource://gre/modules/osfile/osfile_win_allthreads.jsm",
|
||||
"resource://gre/modules/osfile/osfile_win_back.jsm",
|
||||
"resource://gre/modules/osfile/osfile_shared_front.jsm",
|
||||
"resource://gre/modules/osfile/osfile_win_front.jsm"
|
||||
@ -24,7 +23,6 @@ if (typeof Components != "undefined") {
|
||||
#else
|
||||
importScripts(
|
||||
"resource://gre/modules/workers/require.js",
|
||||
"resource://gre/modules/osfile/osfile_unix_allthreads.jsm",
|
||||
"resource://gre/modules/osfile/osfile_unix_back.jsm",
|
||||
"resource://gre/modules/osfile/osfile_shared_front.jsm",
|
||||
"resource://gre/modules/osfile/osfile_unix_front.jsm"
|
||||
|
@ -61,6 +61,9 @@ let maketest = function(prefix, test) {
|
||||
utils.info("Complete");
|
||||
}, function catch_uncaught_errors(err) {
|
||||
utils.fail("Uncaught error " + err);
|
||||
if (err && typeof err == "object" && "message" in err) {
|
||||
utils.fail("(" + err.message + ")");
|
||||
}
|
||||
if (err && typeof err == "object" && "stack" in err) {
|
||||
utils.fail("at " + err.stack);
|
||||
}
|
||||
@ -924,12 +927,9 @@ let test_duration = maketest("duration", function duration(test) {
|
||||
test.ok(copyOptions.outExecutionDuration >= backupDuration, "duration has increased 3");
|
||||
OS.File.remove(pathDest);
|
||||
|
||||
OS.Shared.TEST = true;
|
||||
|
||||
// Testing an operation that doesn't take arguments at all
|
||||
let file = yield OS.File.open(pathSource);
|
||||
yield file.stat();
|
||||
yield file.close();
|
||||
Services.prefs.setBoolPref("toolkit.osfile.log", false);
|
||||
});
|
||||
});
|
||||
|
@ -4,7 +4,7 @@
|
||||
function worker_handler(worker) {
|
||||
worker.onerror = function(error) {
|
||||
error.preventDefault();
|
||||
ok(false, "error "+error);
|
||||
ok(false, "Worker error " + error.message);
|
||||
}
|
||||
worker.onmessage = function(msg) {
|
||||
ok(true, "MAIN: onmessage " + JSON.stringify(msg.data));
|
||||
|
@ -2,6 +2,10 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
importScripts('worker_test_osfile_shared.js');
|
||||
importScripts("resource://gre/modules/workers/require.js");
|
||||
|
||||
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
SharedAll.Config.DEBUG = true;
|
||||
|
||||
function should_throw(f) {
|
||||
try {
|
||||
@ -59,9 +63,9 @@ function test_offsetby() {
|
||||
}
|
||||
|
||||
// Walk through the array with offsetBy by 8 bits
|
||||
let uint8 = OS.Shared.Type.uint8_t.in_ptr.implementation(buf);
|
||||
let uint8 = SharedAll.Type.uint8_t.in_ptr.implementation(buf);
|
||||
for (i = 0; i < LENGTH; ++i) {
|
||||
let value = OS.Shared.offsetBy(uint8, i).contents;
|
||||
let value = SharedAll.offsetBy(uint8, i).contents;
|
||||
if (value != i%256) {
|
||||
is(value, i % 256, "test_offsetby: Walking through array with offsetBy (8 bits)");
|
||||
break;
|
||||
@ -69,10 +73,10 @@ function test_offsetby() {
|
||||
}
|
||||
|
||||
// Walk again by 16 bits
|
||||
let uint16 = OS.Shared.Type.uint16_t.in_ptr.implementation(buf);
|
||||
let uint16 = SharedAll.Type.uint16_t.in_ptr.implementation(buf);
|
||||
let view2 = new Uint16Array(buf);
|
||||
for (i = 0; i < LENGTH/2; ++i) {
|
||||
let value = OS.Shared.offsetBy(uint16, i).contents;
|
||||
let value = SharedAll.offsetBy(uint16, i).contents;
|
||||
if (value != view2[i]) {
|
||||
is(value, view2[i], "test_offsetby: Walking through array with offsetBy (16 bits)");
|
||||
break;
|
||||
@ -80,15 +84,15 @@ function test_offsetby() {
|
||||
}
|
||||
|
||||
// Ensure that offsetBy(..., 0) is idempotent
|
||||
let startptr = OS.Shared.offsetBy(uint8, 0);
|
||||
let startptr2 = OS.Shared.offsetBy(startptr, 0);
|
||||
let startptr = SharedAll.offsetBy(uint8, 0);
|
||||
let startptr2 = SharedAll.offsetBy(startptr, 0);
|
||||
is(startptr.toString(), startptr2.toString(), "test_offsetby: offsetBy(..., 0) is idmpotent");
|
||||
|
||||
// Ensure that offsetBy(ptr, ...) does not work if ptr is a void*
|
||||
let ptr = ctypes.voidptr_t(0);
|
||||
let exn;
|
||||
try {
|
||||
OS.Shared.Utils.offsetBy(ptr, 1);
|
||||
SharedAll.offsetBy(ptr, 1);
|
||||
} catch (x) {
|
||||
exn = x;
|
||||
}
|
||||
|
@ -145,6 +145,10 @@ function run_test()
|
||||
|
||||
do_print("Testing the presence of ospath.jsm");
|
||||
let Scope = {};
|
||||
Components.utils.import("resource://gre/modules/osfile/ospath.jsm", Scope);
|
||||
try {
|
||||
Components.utils.import("resource://gre/modules/osfile/ospath.jsm", Scope);
|
||||
} catch (ex) {
|
||||
// Can't load ospath
|
||||
}
|
||||
do_check_true(!!Scope.basename);
|
||||
}
|
||||
|
90
toolkit/components/osfile/tests/xpcshell/test_unique.js
Normal file
90
toolkit/components/osfile/tests/xpcshell/test_unique.js
Normal file
@ -0,0 +1,90 @@
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function testFiles(filename) {
|
||||
return Task.spawn(function() {
|
||||
const MAX_TRIES = 10;
|
||||
let currentDir = yield OS.File.getCurrentDirectory();
|
||||
let path = OS.Path.join(currentDir, filename);
|
||||
let exists = yield OS.File.exists(path);
|
||||
// Check a file with the same name doesn't exist already
|
||||
do_check_false(exists);
|
||||
|
||||
// Ensure that openUnique() uses the file name if there is no file with that name already.
|
||||
let openedFile = yield OS.File.openUnique(path);
|
||||
do_print("\nCreate new file: " + openedFile.path);
|
||||
yield openedFile.file.close();
|
||||
exists = yield OS.File.exists(openedFile.path);
|
||||
do_check_true(exists);
|
||||
do_check_eq(path, openedFile.path);
|
||||
let fileInfo = yield OS.File.stat(openedFile.path);
|
||||
do_check_true(fileInfo.size == 0);
|
||||
|
||||
// Ensure that openUnique() creates a new file name using a HEX number, as the original name is already taken.
|
||||
openedFile = yield OS.File.openUnique(path);
|
||||
do_print("\nCreate unique HEX file: " + openedFile.path);
|
||||
yield openedFile.file.close();
|
||||
exists = yield OS.File.exists(openedFile.path);
|
||||
do_check_true(exists);
|
||||
let fileInfo = yield OS.File.stat(openedFile.path);
|
||||
do_check_true(fileInfo.size == 0);
|
||||
|
||||
// Ensure that openUnique() generates different file names each time, using the HEX number algorithm
|
||||
let filenames = new Set();
|
||||
for (let i=0; i < MAX_TRIES; i++) {
|
||||
openedFile = yield OS.File.openUnique(path);
|
||||
yield openedFile.file.close();
|
||||
filenames.add(openedFile.path);
|
||||
}
|
||||
|
||||
do_check_eq(filenames.size, MAX_TRIES);
|
||||
|
||||
// Ensure that openUnique() creates a new human readable file name using, as the original name is already taken.
|
||||
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
|
||||
do_print("\nCreate unique Human Readable file: " + openedFile.path);
|
||||
yield openedFile.file.close();
|
||||
exists = yield OS.File.exists(openedFile.path);
|
||||
do_check_true(exists);
|
||||
let fileInfo = yield OS.File.stat(openedFile.path);
|
||||
do_check_true(fileInfo.size == 0);
|
||||
|
||||
// Ensure that openUnique() generates different human readable file names each time
|
||||
filenames = new Set();
|
||||
for (let i=0; i < MAX_TRIES; i++) {
|
||||
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
|
||||
yield openedFile.file.close();
|
||||
filenames.add(openedFile.path);
|
||||
}
|
||||
|
||||
do_check_eq(filenames.size, MAX_TRIES);
|
||||
|
||||
let exn;
|
||||
try {
|
||||
for (let i=0; i < 100; i++) {
|
||||
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
|
||||
yield openedFile.file.close();
|
||||
}
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
|
||||
do_print("Ensure that this raises the correct error");
|
||||
do_check_true(!!exn);
|
||||
do_check_true(exn instanceof OS.File.Error);
|
||||
do_check_true(exn.becauseExists);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function test_unique() {
|
||||
OS.Shared.DEBUG = true;
|
||||
// Tests files with extension
|
||||
yield testFiles("dummy_unique_file.txt");
|
||||
// Tests files with no extension
|
||||
yield testFiles("dummy_unique_file_no_ext");
|
||||
});
|
@ -12,3 +12,4 @@ tail =
|
||||
[test_exception.js]
|
||||
[test_path_constants.js]
|
||||
[test_removeDir.js]
|
||||
[test_unique.js]
|
||||
|
@ -1138,6 +1138,29 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
- This handler may cancel a request to focus content by returning |false|
|
||||
- explicitly.
|
||||
-->
|
||||
<method name="shouldFocusContent">
|
||||
<body><![CDATA[
|
||||
const fm = Components.classes["@mozilla.org/focus-manager;1"]
|
||||
.getService(Components.interfaces.nsIFocusManager);
|
||||
if (fm.focusedWindow != window)
|
||||
return false;
|
||||
|
||||
let focusedElement = fm.focusedElement;
|
||||
if (!focusedElement)
|
||||
return false;
|
||||
|
||||
let bindingParent = document.getBindingParent(focusedElement);
|
||||
if (bindingParent != this && bindingParent != this._findField)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
|
@ -120,6 +120,7 @@ var SrcdirProvider = {
|
||||
"devtools/toolkit/webconsole": webconsoleURI,
|
||||
"devtools/app-actor-front": appActorURI,
|
||||
"devtools/styleinspector/css-logic": cssLogicURI,
|
||||
"devtools/css-color": cssColorURI,
|
||||
"devtools/touch-events": touchEventsURI,
|
||||
"devtools/client": clientURI,
|
||||
"escodegen": escodegenURI,
|
||||
|
@ -116,14 +116,22 @@ Finder.prototype = {
|
||||
},
|
||||
|
||||
focusContent: function() {
|
||||
let fastFind = this._fastFind;
|
||||
// Allow Finder listeners to cancel focusing the content.
|
||||
for (let l of this._listeners) {
|
||||
if (!l.shouldFocusContent())
|
||||
return;
|
||||
}
|
||||
|
||||
let fastFind = this._fastFind;
|
||||
const fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||
try {
|
||||
// Try to find the best possible match that should receive focus.
|
||||
// Try to find the best possible match that should receive focus and
|
||||
// block scrolling on focus since find already scrolls. Further
|
||||
// scrolling is due to user action, so don't override this.
|
||||
if (fastFind.foundLink) {
|
||||
fastFind.foundLink.focus();
|
||||
fm.setFocus(fastFind.foundLink, fm.FLAG_NOSCROLL);
|
||||
} else if (fastFind.foundEditable) {
|
||||
fastFind.foundEditable.focus();
|
||||
fm.setFocus(fastFind.foundEditable, fm.FLAG_NOSCROLL);
|
||||
fastFind.collapseSelection();
|
||||
} else {
|
||||
this._getWindow().focus()
|
||||
@ -136,8 +144,18 @@ Finder.prototype = {
|
||||
|
||||
switch (aEvent.keyCode) {
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_RETURN:
|
||||
if (this._fastFind.foundLink) // Todo: Handle ctrl click.
|
||||
this._fastFind.foundLink.click();
|
||||
if (this._fastFind.foundLink) {
|
||||
let view = this._fastFind.foundLink.ownerDocument.defaultView;
|
||||
this._fastFind.foundLink.dispatchEvent(new view.MouseEvent("click", {
|
||||
view: view,
|
||||
cancelable: true,
|
||||
bubbles: true,
|
||||
ctrlKey: aEvent.ctrlKey,
|
||||
altKey: aEvent.altKey,
|
||||
shiftKey: aEvent.shiftKey,
|
||||
metaKey: aEvent.metaKey
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_TAB:
|
||||
let direction = Services.focus.MOVEFOCUS_FORWARD;
|
||||
|
@ -114,6 +114,12 @@ RemoteFinderListener.prototype = {
|
||||
this._global.sendAsyncMessage("Finder:Result", data);
|
||||
},
|
||||
|
||||
//XXXmikedeboer-20131016: implement |shouldFocusContent| here to mitigate
|
||||
// issues like bug 921338 and bug 921308.
|
||||
shouldFocusContent: function () {
|
||||
return true;
|
||||
},
|
||||
|
||||
receiveMessage: function (aMessage) {
|
||||
let data = aMessage.data;
|
||||
|
||||
|
@ -10,27 +10,26 @@ support-files =
|
||||
[test_0015_check_incompat_basic_addons.xul]
|
||||
[test_0016_check_incompat_basic_license_addons.xul]
|
||||
[test_0017_check_staging_basic.xul]
|
||||
skip-if = os == 'linux'
|
||||
reason = Bug 918029 - timeout caused by copying too many files.
|
||||
[test_0021_check_billboard.xul]
|
||||
[test_0022_check_billboard_license.xul]
|
||||
[test_0023_check_incompat_billboard.xul]
|
||||
[test_0024_check_incompat_billboard_license.xul]
|
||||
[test_0025_check_incompat_billboard_addons.xul]
|
||||
[test_0026_check_incompat_billboard_license_addons.xul]
|
||||
[test_0027_check_staging_billboard.xul]
|
||||
[test_0031_available_basic.xul]
|
||||
[test_0032_available_basic_license.xul]
|
||||
[test_0033_available_incompat_basic.xul]
|
||||
[test_0034_available_incompat_basic_license.xul]
|
||||
[test_0035_available_incompat_basic_addons.xul]
|
||||
[test_0036_available_incompat_basic_license_addons.xul]
|
||||
[test_0037_available_staging_basic.xul]
|
||||
[test_0041_available_billboard.xul]
|
||||
[test_0042_available_billboard_license.xul]
|
||||
[test_0043_available_incompat_billboard.xul]
|
||||
[test_0044_available_incompat_billboard_license.xul]
|
||||
[test_0045_available_incompat_billboard_addons.xul]
|
||||
[test_0046_available_incompat_billboard_license_addons.xul]
|
||||
[test_0047_available_staging_billboard.xul]
|
||||
[test_0051_check_error_xml_malformed.xul]
|
||||
[test_0052_check_no_updates.xul]
|
||||
[test_0053_check_billboard_license_noAttr.xul]
|
||||
|
@ -1,62 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
-->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window title="Update Wizard pages: update check, billboard, download with staging, and finished"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="runTestDefault();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="utils.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const TESTS = [ {
|
||||
pageid: PAGEID_CHECKING
|
||||
}, {
|
||||
pageid: PAGEID_FOUND_BILLBOARD,
|
||||
extraDelayedCheckFunction: checkRemoteContentState,
|
||||
expectedRemoteContentState: "loading",
|
||||
extraDelayedFinishFunction: addRemoteContentLoadListener
|
||||
}, {
|
||||
pageid: PAGEID_FOUND_BILLBOARD,
|
||||
extraStartFunction: waitForRemoteContentLoaded,
|
||||
expectedRemoteContentState: "loaded",
|
||||
buttonClick: "next"
|
||||
}, {
|
||||
pageid: PAGEID_DOWNLOADING
|
||||
}, {
|
||||
pageid: PAGEID_FINISHED,
|
||||
buttonClick: "extra1"
|
||||
} ];
|
||||
|
||||
function runTest() {
|
||||
debugDump("entering");
|
||||
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
|
||||
|
||||
let url = URL_UPDATE + "?showBillboard=1&showDetails=1" + getVersionParams();
|
||||
setUpdateURLOverride(url);
|
||||
|
||||
setupTimer(180000); // 180 seconds
|
||||
|
||||
gUP.checkForUpdates();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
</window>
|
@ -1,53 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
-->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window title="Update Wizard pages: basic, download with staging, and finished"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="runTestDefault();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="utils.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const TESTS = [ {
|
||||
pageid: PAGEID_FOUND_BASIC,
|
||||
buttonClick: "next"
|
||||
}, {
|
||||
pageid: PAGEID_DOWNLOADING
|
||||
}, {
|
||||
pageid: PAGEID_FINISHED,
|
||||
buttonClick: "extra1"
|
||||
} ];
|
||||
|
||||
function runTest() {
|
||||
debugDump("entering");
|
||||
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
|
||||
|
||||
let url = URL_UPDATE + "?showDetails=1&showPrompt=1" + getVersionParams();
|
||||
setUpdateURLOverride(url);
|
||||
|
||||
setupTimer(180000); // 180 seconds
|
||||
|
||||
gAUS.checkForBackgroundUpdates();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
</window>
|
@ -1,61 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
-->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window title="Update Wizard pages: billboard, download with staging, and finished"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="runTestDefault();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="utils.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const TESTS = [ {
|
||||
pageid: PAGEID_FOUND_BILLBOARD,
|
||||
extraDelayedCheckFunction: checkRemoteContentState,
|
||||
expectedRemoteContentState: "loading",
|
||||
extraDelayedFinishFunction: addRemoteContentLoadListener
|
||||
}, {
|
||||
pageid: PAGEID_FOUND_BILLBOARD,
|
||||
extraStartFunction: waitForRemoteContentLoaded,
|
||||
expectedRemoteContentState: "loaded",
|
||||
buttonClick: "next"
|
||||
}, {
|
||||
pageid: PAGEID_DOWNLOADING,
|
||||
}, {
|
||||
pageid: PAGEID_FINISHED,
|
||||
buttonClick: "extra1"
|
||||
} ];
|
||||
|
||||
function runTest() {
|
||||
debugDump("entering");
|
||||
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
|
||||
|
||||
let url = URL_UPDATE + "?showBillboard=1&showDetails=1&showPrompt=1" +
|
||||
getVersionParams();
|
||||
setUpdateURLOverride(url);
|
||||
|
||||
setupTimer(180000); // 180 seconds
|
||||
|
||||
gAUS.notify(null);
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
</window>
|
@ -157,11 +157,13 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
|
||||
return true;
|
||||
}
|
||||
|
||||
float opacity = aLayer->GetEffectiveOpacity();
|
||||
if (opacity < 1) {
|
||||
uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0));
|
||||
#if ANDROID_VERSION < 18
|
||||
if (opacity < 0xFF) {
|
||||
LOGD("%s Layer has planar semitransparency which is unsupported", aLayer->Name());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIntRect clip;
|
||||
if (!HwcUtils::CalculateClipRect(aParentTransform * aGLWorldTransform,
|
||||
@ -276,7 +278,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
|
||||
|
||||
hwcLayer.acquireFenceFd = -1;
|
||||
hwcLayer.releaseFenceFd = -1;
|
||||
hwcLayer.planeAlpha = 0xFF; // Until plane alpha is enabled
|
||||
hwcLayer.planeAlpha = opacity;
|
||||
#else
|
||||
hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT;
|
||||
#endif
|
||||
@ -434,6 +436,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
|
||||
hwcLayer.transform = colorLayer->GetColor().Packed();
|
||||
}
|
||||
|
||||
mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData()));
|
||||
mList->numHwLayers++;
|
||||
return true;
|
||||
}
|
||||
@ -461,13 +464,29 @@ HwcComposer2D::TryHwComposition()
|
||||
|
||||
Prepare(fbsurface->lastHandle, -1);
|
||||
|
||||
bool fullHwcComposite = true;
|
||||
for (int j = 0; j < idx; j++) {
|
||||
if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER) {
|
||||
// After prepare, if there is an HWC_FRAMEBUFFER layer,
|
||||
// it means full HWC Composition is not possible this time
|
||||
LOGD("GPU or Partial HWC Composition");
|
||||
return false;
|
||||
fullHwcComposite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fullHwcComposite) {
|
||||
for (int k=0; k < idx; k++) {
|
||||
if (mList->hwLayers[k].compositionType == HWC_OVERLAY) {
|
||||
// HWC will compose HWC_OVERLAY layers in partial
|
||||
// HWC Composition, so set layer composition flag
|
||||
// on mapped LayerComposite to skip GPU composition
|
||||
mHwcLayerMap[k]->SetLayerComposited(true);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Full HWC Composition
|
||||
Commit();
|
||||
|
||||
@ -554,28 +573,26 @@ HwcComposer2D::Commit()
|
||||
|
||||
int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
|
||||
|
||||
for (int i = 0; i <= MAX_HWC_LAYERS; i++) {
|
||||
if (mPrevRelFd[i] <= 0) {
|
||||
break;
|
||||
if (!mPrevReleaseFds.IsEmpty()) {
|
||||
// Wait for previous retire Fence to signal.
|
||||
// Denotes contents on display have been replaced.
|
||||
// For buffer-sync, framework should not over-write
|
||||
// prev buffers until we close prev releaseFenceFds
|
||||
sp<Fence> fence = new Fence(mPrevReleaseFds[0]);
|
||||
if (fence->wait(1000) == -ETIME) {
|
||||
LOGE("Wait timed-out for retireFenceFd %d", mPrevReleaseFds[0]);
|
||||
}
|
||||
if (!i) {
|
||||
// Wait for previous retire Fence to signal.
|
||||
// Denotes contents on display have been replaced.
|
||||
// For buffer-sync, framework should not over-write
|
||||
// prev buffers until we close prev releaseFenceFds
|
||||
sp<Fence> fence = new Fence(mPrevRelFd[i]);
|
||||
if (fence->wait(1000) == -ETIME) {
|
||||
LOGE("Wait timed-out for retireFenceFd %d", mPrevRelFd[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mPrevReleaseFds.Length(); i++) {
|
||||
close(mPrevReleaseFds[i]);
|
||||
}
|
||||
close(mPrevRelFd[i]);
|
||||
mPrevRelFd[i] = -1;
|
||||
mPrevReleaseFds.Clear();
|
||||
}
|
||||
|
||||
mPrevRelFd[0] = mList->retireFenceFd;
|
||||
for (uint32_t j = 0; j < (mList->numHwLayers - 1); j++) {
|
||||
mPrevReleaseFds.AppendElement(mList->retireFenceFd);
|
||||
for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
|
||||
if (mList->hwLayers[j].compositionType == HWC_OVERLAY) {
|
||||
mPrevRelFd[j + 1] = mList->hwLayers[j].releaseFenceFd;
|
||||
mPrevReleaseFds.AppendElement(mList->hwLayers[j].releaseFenceFd);
|
||||
mList->hwLayers[j].releaseFenceFd = -1;
|
||||
}
|
||||
}
|
||||
@ -609,12 +626,14 @@ HwcComposer2D::TryRender(Layer* aRoot,
|
||||
MOZ_ASSERT(Initialized());
|
||||
if (mList) {
|
||||
mList->numHwLayers = 0;
|
||||
mHwcLayerMap.Clear();
|
||||
}
|
||||
|
||||
// XXX: The clear() below means all rect vectors will be have to be
|
||||
// reallocated. We may want to avoid this if possible
|
||||
mVisibleRegions.clear();
|
||||
|
||||
MOZ_ASSERT(mHwcLayerMap.IsEmpty());
|
||||
if (!PrepareLayerList(aRoot,
|
||||
mScreenRect,
|
||||
gfxMatrix(),
|
||||
|
@ -24,8 +24,6 @@
|
||||
|
||||
#include <hardware/hwcomposer.h>
|
||||
|
||||
#define MAX_HWC_LAYERS 15
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
@ -83,7 +81,8 @@ private:
|
||||
//Holds all the dynamically allocated RectVectors needed
|
||||
//to render the current frame
|
||||
std::list<RectVector> mVisibleRegions;
|
||||
int mPrevRelFd[MAX_HWC_LAYERS + 1];
|
||||
nsTArray<int> mPrevReleaseFds;
|
||||
nsTArray<layers::LayerComposite*> mHwcLayerMap;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -206,6 +206,7 @@ MetroInput::MetroInput(MetroWidget* aWidget,
|
||||
UI::Core::ICoreWindow* aWindow)
|
||||
: mWidget(aWidget),
|
||||
mChromeHitTestCacheForTouch(false),
|
||||
mCurrentInputLevel(LEVEL_IMPRECISE),
|
||||
mWindow(aWindow)
|
||||
{
|
||||
LogFunction();
|
||||
@ -240,6 +241,51 @@ MetroInput::~MetroInput()
|
||||
UnregisterInputEvents();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tracks the current input level (precise/imprecise) and fires an observer
|
||||
* when the mode changes.
|
||||
*/
|
||||
void
|
||||
MetroInput::UpdateInputLevel(InputPrecisionLevel aInputLevel)
|
||||
{
|
||||
// ignore mouse input if we have active touch input.
|
||||
if (aInputLevel == LEVEL_PRECISE && mTouches.Count() > 0) {
|
||||
return;
|
||||
}
|
||||
if (mCurrentInputLevel != aInputLevel) {
|
||||
mCurrentInputLevel = aInputLevel;
|
||||
MetroUtils::FireObserver(mCurrentInputLevel == LEVEL_PRECISE ?
|
||||
"metro_precise_input" : "metro_imprecise_input");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an IEdgeGestureEventArgs and returns the input source type
|
||||
* for the event. Also updates input level via UpdateInputLevel.
|
||||
*/
|
||||
uint16_t
|
||||
MetroInput::ProcessInputTypeForGesture(UI::Input::IEdgeGestureEventArgs* aArgs)
|
||||
{
|
||||
MOZ_ASSERT(aArgs);
|
||||
UI::Input::EdgeGestureKind kind;
|
||||
aArgs->get_Kind(&kind);
|
||||
switch(kind) {
|
||||
case UI::Input::EdgeGestureKind::EdgeGestureKind_Touch:
|
||||
UpdateInputLevel(LEVEL_PRECISE);
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
break;
|
||||
case UI::Input::EdgeGestureKind::EdgeGestureKind_Keyboard:
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
|
||||
break;
|
||||
case UI::Input::EdgeGestureKind::EdgeGestureKind_Mouse:
|
||||
UpdateInputLevel(LEVEL_IMPRECISE);
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
|
||||
break;
|
||||
}
|
||||
return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user swipes her/his finger in from the top of the screen,
|
||||
* we receive this event.
|
||||
@ -263,8 +309,7 @@ MetroInput::OnEdgeGestureStarted(UI::Input::IEdgeGesture* sender,
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(geckoEvent);
|
||||
geckoEvent.time = ::GetMessageTime();
|
||||
|
||||
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs);
|
||||
|
||||
// Safe
|
||||
DispatchEventIgnoreStatus(&geckoEvent);
|
||||
@ -295,8 +340,7 @@ MetroInput::OnEdgeGestureCanceled(UI::Input::IEdgeGesture* sender,
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(geckoEvent);
|
||||
geckoEvent.time = ::GetMessageTime();
|
||||
|
||||
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs);
|
||||
|
||||
// Safe
|
||||
DispatchEventIgnoreStatus(&geckoEvent);
|
||||
@ -326,15 +370,7 @@ MetroInput::OnEdgeGestureCompleted(UI::Input::IEdgeGesture* sender,
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(geckoEvent);
|
||||
geckoEvent.time = ::GetMessageTime();
|
||||
|
||||
UI::Input::EdgeGestureKind value;
|
||||
aArgs->get_Kind(&value);
|
||||
|
||||
if (value == UI::Input::EdgeGestureKind::EdgeGestureKind_Keyboard) {
|
||||
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
|
||||
} else {
|
||||
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
}
|
||||
geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs);
|
||||
|
||||
// Safe
|
||||
DispatchEventIgnoreStatus(&geckoEvent);
|
||||
@ -391,6 +427,7 @@ MetroInput::OnPointerNonTouch(UI::Input::IPointerPoint* aPoint) {
|
||||
event->message = NS_MOUSE_BUTTON_UP;
|
||||
break;
|
||||
}
|
||||
UpdateInputLevel(LEVEL_PRECISE);
|
||||
InitGeckoMouseEventFromPointerPoint(event, aPoint);
|
||||
DispatchAsyncEventIgnoreStatus(event);
|
||||
}
|
||||
@ -430,6 +467,8 @@ MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
|
||||
}
|
||||
|
||||
// This is touch input.
|
||||
UpdateInputLevel(LEVEL_IMPRECISE);
|
||||
|
||||
// Create the new touch point and add it to our event.
|
||||
uint32_t pointerId;
|
||||
currentPoint->get_PointerId(&pointerId);
|
||||
@ -517,6 +556,8 @@ MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
|
||||
}
|
||||
|
||||
// This is touch input.
|
||||
UpdateInputLevel(LEVEL_IMPRECISE);
|
||||
|
||||
// Get the touch associated with this touch point.
|
||||
uint32_t pointerId;
|
||||
currentPoint->get_PointerId(&pointerId);
|
||||
@ -614,6 +655,8 @@ MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender,
|
||||
}
|
||||
|
||||
// This is touch input.
|
||||
UpdateInputLevel(LEVEL_IMPRECISE);
|
||||
|
||||
// Get the touch associated with this touch point.
|
||||
uint32_t pointerId;
|
||||
currentPoint->get_PointerId(&pointerId);
|
||||
@ -748,9 +791,11 @@ MetroInput::OnPointerEntered(UI::Core::ICoreWindow* aSender,
|
||||
WidgetMouseEvent* event =
|
||||
new WidgetMouseEvent(true, NS_MOUSE_ENTER, mWidget.Get(),
|
||||
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
|
||||
UpdateInputLevel(LEVEL_PRECISE);
|
||||
InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
|
||||
DispatchAsyncEventIgnoreStatus(event);
|
||||
}
|
||||
UpdateInputLevel(LEVEL_IMPRECISE);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -779,9 +824,11 @@ MetroInput::OnPointerExited(UI::Core::ICoreWindow* aSender,
|
||||
WidgetMouseEvent* event =
|
||||
new WidgetMouseEvent(true, NS_MOUSE_EXIT, mWidget.Get(),
|
||||
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
|
||||
UpdateInputLevel(LEVEL_PRECISE);
|
||||
InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
|
||||
DispatchAsyncEventIgnoreStatus(event);
|
||||
}
|
||||
UpdateInputLevel(LEVEL_IMPRECISE);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,14 @@ private:
|
||||
|
||||
ModifierKeyState mModifierKeyState;
|
||||
|
||||
// Tracking input level
|
||||
enum InputPrecisionLevel {
|
||||
LEVEL_PRECISE,
|
||||
LEVEL_IMPRECISE
|
||||
};
|
||||
InputPrecisionLevel mCurrentInputLevel;
|
||||
void UpdateInputLevel(InputPrecisionLevel aInputLevel);
|
||||
|
||||
// Initialization/Uninitialization helpers
|
||||
void RegisterInputEvents();
|
||||
void UnregisterInputEvents();
|
||||
@ -174,6 +182,7 @@ private:
|
||||
Point const& aPosition,
|
||||
uint32_t aMagEventType,
|
||||
uint32_t aRotEventType);
|
||||
uint16_t ProcessInputTypeForGesture(IEdgeGestureEventArgs* aArgs);
|
||||
|
||||
// The W3C spec states that "whether preventDefault has been called" should
|
||||
// be tracked on a per-touchpoint basis, but it also states that touchstart
|
||||
|
Loading…
Reference in New Issue
Block a user