merge m-c to fx-team

This commit is contained in:
Tim Taubert 2012-03-28 00:33:42 +02:00
commit 04ee0113a8
26 changed files with 764 additions and 594 deletions

View File

@ -44,9 +44,8 @@ let gDrop = {
* Handles the 'drop' event.
* @param aCell The drop target cell.
* @param aEvent The 'dragexit' event.
* @param aCallback The callback to call when the drop is finished.
*/
drop: function Drop_drop(aCell, aEvent, aCallback) {
drop: function Drop_drop(aCell, aEvent) {
// The cell that is the drop target could contain a pinned site. We need
// to find out where that site has gone and re-pin it there.
if (aCell.containsPinnedSite())
@ -58,7 +57,7 @@ let gDrop = {
this._cancelDelayedArrange();
// Update the grid and move all sites to their new places.
gUpdater.updateGrid(aCallback);
gUpdater.updateGrid();
},
/**

View File

@ -61,13 +61,12 @@ Site.prototype = {
/**
* Unpins the site and calls the given callback when done.
* @param aCallback The callback to be called when finished.
*/
unpin: function Site_unpin(aCallback) {
unpin: function Site_unpin() {
if (this.isPinned()) {
this._updateAttributes(false);
gPinnedLinks.unpin(this._link);
gUpdater.updateGrid(aCallback);
gUpdater.updateGrid();
}
},
@ -82,15 +81,14 @@ Site.prototype = {
/**
* Blocks the site (removes it from the grid) and calls the given callback
* when done.
* @param aCallback The function to be called when finished.
*/
block: function Site_block(aCallback) {
block: function Site_block() {
if (gBlockedLinks.isBlocked(this._link)) {
if (aCallback)
aCallback();
} else {
gBlockedLinks.block(this._link);
gUpdater.updateGrid(aCallback);
gUpdater.updateGrid();
}
},

View File

@ -15,13 +15,13 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8");
yield blockCell(cells[4]);
yield blockCell(4);
checkGrid("0,1,2,3,5,6,7,8,9");
yield blockCell(cells[4]);
yield blockCell(4);
checkGrid("0,1,2,3,6,7,8,9,");
yield blockCell(cells[4]);
yield blockCell(4);
checkGrid("0,1,2,3,7,8,9,,");
// we removed a pinned site
@ -32,7 +32,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1p,2,3,4,5,6,7,8");
yield blockCell(cells[1]);
yield blockCell(1);
checkGrid("0,2,3,4,5,6,7,8,");
// we remove the last site on the grid (which is pinned) and expect the gap
@ -44,7 +44,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8p");
yield blockCell(cells[8]);
yield blockCell(8);
checkGrid("0,1,2,3,4,5,6,7,9");
// we remove the first site on the grid with the last one pinned. all cells
@ -56,6 +56,6 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8p");
yield blockCell(cells[0]);
yield blockCell(0);
checkGrid("1,2,3,4,5,6,7,9,8p");
}

View File

@ -20,21 +20,12 @@ function runTests() {
fillHistory();
yield addNewTabPageTab();
is(cells[0].site.url, URL, "first site is our fake site");
is(getCell(0).site.url, URL, "first site is our fake site");
let page = {
update: function () {
executeSoon(TestRunner.next);
},
observe: function () {}
};
NewTabUtils.allPages.register(page);
whenPagesUpdated();
yield clearHistory();
NewTabUtils.allPages.unregister(page);
ok(!cells[0].site, "the fake site is gone");
ok(!getCell(0).site, "the fake site is gone");
}
function fillHistory() {

View File

@ -14,5 +14,5 @@ function runTests() {
ok(NewTabUtils.allPages.enabled, true, "page is enabled");
NewTabUtils.allPages.enabled = false;
ok(cw.gGrid.node.hasAttribute("page-disabled"), "page is disabled");
ok(getGrid().node.hasAttribute("page-disabled"), "page is disabled");
}

View File

@ -8,41 +8,23 @@ function runTests() {
yield addNewTabPageTab();
checkGridLocked(false, "grid is unlocked");
let cell = cells[0].node;
let site = cells[0].site.node;
let cell = getCell(0).node;
let site = getCell(0).site.node;
let link = site.querySelector(".newtab-link");
sendDragEvent(link, "dragstart");
sendDragEvent("dragstart", link);
checkGridLocked(true, "grid is now locked");
sendDragEvent(link, "dragend");
sendDragEvent("dragend", link);
checkGridLocked(false, "grid isn't locked anymore");
sendDragEvent(cell, "dragstart");
sendDragEvent("dragstart", cell);
checkGridLocked(false, "grid isn't locked - dragstart was ignored");
sendDragEvent(site, "dragstart");
sendDragEvent("dragstart", site);
checkGridLocked(false, "grid isn't locked - dragstart was ignored");
}
function checkGridLocked(aLocked, aMessage) {
is(cw.gGrid.node.hasAttribute("locked"), aLocked, aMessage);
}
function sendDragEvent(aNode, aType) {
let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
let dataTransfer = {
mozUserCancelled: false,
setData: function () null,
setDragImage: function () null,
getData: function () "about:blank"
};
let event = cw.document.createEvent("DragEvents");
event.initDragEvent(aType, true, true, cw, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
is(getGrid().node.hasAttribute("locked"), aLocked, aMessage);
}

View File

@ -8,45 +8,16 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8");
let cell = cells[0].node;
let cell = getCell(0).node;
sendDropEvent(cell, "about:blank#99\nblank");
sendDragEvent("drop", cell, "about:blank#99\nblank");
is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
"first cell is pinned and contains the dropped site");
yield whenPagesUpdated();
checkGrid("99p,0,1,2,3,4,5,6,7");
sendDropEvent(cell, "");
sendDragEvent("drop", cell, "");
is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
"first cell is still pinned with the site we dropped before");
}
function sendDropEvent(aNode, aData) {
let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
let dataTransfer = {
mozUserCancelled: false,
setData: function () null,
setDragImage: function () null,
getData: function () aData,
types: {
contains: function (aType) aType == "text/x-moz-url"
},
mozGetDataAt: function (aType, aIndex) {
if (aIndex || aType != "text/x-moz-url")
return null;
return aData;
},
};
let event = cw.document.createEvent("DragEvents");
event.initDragEvent("drop", true, true, cw, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
}

View File

@ -9,12 +9,13 @@ function runTests() {
checkGrid("0,1,2,3,4,5,6,7,8");
let receivedError = false;
let block = cw.document.querySelector(".newtab-control-block");
let block = getContentDocument().querySelector(".newtab-control-block");
function onError() {
receivedError = true;
}
let cw = getContentWindow();
cw.addEventListener("error", onError);
for (let i = 0; i < 3; i++)

View File

@ -8,15 +8,15 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8");
yield simulateDrop(cells[1]);
yield simulateDrop(1);
checkGrid("0,99p,1,2,3,4,5,6,7");
yield blockCell(cells[1]);
yield blockCell(1);
checkGrid("0,1,2,3,4,5,6,7,8");
yield simulateDrop(cells[1]);
yield simulateDrop(1);
checkGrid("0,99p,1,2,3,4,5,6,7");
yield blockCell(cells[1]);
yield blockCell(1);
checkGrid("0,1,2,3,4,5,6,7,8");
}

View File

@ -11,14 +11,14 @@ function runTests() {
setPinnedLinks("");
yield addNewTabPageTab();
let gridNode = cw.gGrid.node;
let gridNode = getGrid().node;
ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
NewTabUtils.allPages.enabled = false;
ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
let oldGridNode = cw.gGrid.node;
let oldGridNode = gridNode;
// create a second new tage page and make sure it's disabled. enable it
// again and check if the former page gets enabled as well.
@ -26,7 +26,7 @@ function runTests() {
ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
// check that no sites have been rendered
is(0, cw.document.querySelectorAll(".site").length, "no sites have been rendered");
is(0, getContentDocument().querySelectorAll(".site").length, "no sites have been rendered");
NewTabUtils.allPages.enabled = true;
ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");

View File

@ -15,7 +15,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8");
yield simulateDrop(cells[1], cells[0]);
yield simulateDrop(1, 0);
checkGrid("1,0p,2,3,4,5,6,7,8");
// drag a cell to its current cell and make sure it's not pinned afterwards
@ -25,7 +25,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8");
yield simulateDrop(cells[0], cells[0]);
yield simulateDrop(0, 0);
checkGrid("0,1,2,3,4,5,6,7,8");
// ensure that pinned pages aren't moved if that's not necessary
@ -35,7 +35,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1p,2p,3,4,5,6,7,8");
yield simulateDrop(cells[3], cells[0]);
yield simulateDrop(3, 0);
checkGrid("3,1p,2p,0p,4,5,6,7,8");
// pinned sites should always be moved around as blocks. if a pinned site is
@ -46,7 +46,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0p,1p,2,3,4,5,6,7,8");
yield simulateDrop(cells[0], cells[2]);
yield simulateDrop(0, 2);
checkGrid("2p,0p,1p,3,4,5,6,7,8");
// pinned sites should not be pushed out of the grid (unless there are only
@ -57,7 +57,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7p,8p");
yield simulateDrop(cells[8], cells[2]);
yield simulateDrop(8, 2);
checkGrid("0,1,3,4,5,6,7p,8p,2p");
// make sure that pinned sites are re-positioned correctly
@ -67,7 +67,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0p,1p,2p,3,4,5p,6,7,8");
yield simulateDrop(cells[4], cells[0]);
yield simulateDrop(4, 0);
checkGrid("3,1p,2p,4,0p,5p,6,7,8");
// drag a new site onto the very first cell
@ -77,7 +77,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7p,8p");
yield simulateDrop(cells[0]);
yield simulateDrop(0);
checkGrid("99p,0,1,2,3,4,5,7p,8p");
// drag a new site onto the grid and make sure that pinned cells don't get
@ -88,7 +88,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7p,8p");
yield simulateDrop(cells[7]);
yield simulateDrop(7);
checkGrid("0,1,2,3,4,5,7p,99p,8p");
// drag a new site beneath a pinned cell and make sure the pinned cell is
@ -99,7 +99,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8p");
yield simulateDrop(cells[7]);
yield simulateDrop(7);
checkGrid("0,1,2,3,4,5,6,99p,8p");
// drag a new site onto a block of pinned sites and make sure they're shifted
@ -110,6 +110,6 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0p,1p,2p");
yield simulateDrop(cells[1]);
yield simulateDrop(1);
checkGrid("0p,99p,1p,2p,3,4,5,6,7");
}

View File

@ -13,8 +13,9 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0p,1p,2p,3,4,5p,6,7,8");
cw.gDrag._draggedSite = cells[0].site;
let sites = cw.gDropPreview.rearrange(cells[4]);
let cw = getContentWindow();
cw.gDrag._draggedSite = getCell(0).site;
let sites = cw.gDropPreview.rearrange(getCell(4));
cw.gDrag._draggedSite = null;
checkGrid("3,1p,2p,4,0p,5p,6,7,8", sites);

View File

@ -16,7 +16,7 @@ function runTests() {
ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
yield addNewTabPageTab();
pinCell(cells[0]);
pinCell(0);
checkGrid("0p,1,2,3,4,5,6,7,8");
// enter private browsing mode
@ -27,10 +27,10 @@ function runTests() {
checkGrid("0p,1,2,3,4,5,6,7,8");
// modify the grid while we're in pb mode
yield blockCell(cells[1]);
yield blockCell(1);
checkGrid("0p,2,3,4,5,6,7,8");
yield unpinCell(cells[0]);
yield unpinCell(0);
checkGrid("0,2,3,4,5,6,7,8");
// exit private browsing mode

View File

@ -13,16 +13,16 @@ function runTests() {
setPinnedLinks("");
yield addNewTabPageTab();
let resetButton = cw.document.getElementById("toolbar-button-reset");
let resetButton = getContentDocument().getElementById("toolbar-button-reset");
checkGrid("0,1,2,3,4,5,6,7,8");
ok(!resetButton.hasAttribute("modified"), "page is not modified");
yield blockCell(cells[4]);
yield blockCell(4);
checkGrid("0,1,2,3,5,6,7,8,");
ok(resetButton.hasAttribute("modified"), "page is modified");
yield cw.gToolbar.reset(TestRunner.next);
yield getContentWindow().gToolbar.reset(TestRunner.next);
checkGrid("0,1,2,3,4,5,6,7,8");
ok(!resetButton.hasAttribute("modified"), "page is not modified");
}

View File

@ -17,45 +17,45 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1p,2,3,4,5,6,7,8");
let resetButton = cw.document.getElementById("toolbar-button-reset");
let resetButton = getContentDocument().getElementById("toolbar-button-reset");
ok(!resetButton.hasAttribute("modified"), "page is not modified");
let oldCw = cw;
let oldSites = getGrid().sites;
let oldResetButton = resetButton;
// create the new tab page
yield addNewTabPageTab();
checkGrid("0,1p,2,3,4,5,6,7,8");
resetButton = cw.document.getElementById("toolbar-button-reset");
resetButton = getContentDocument().getElementById("toolbar-button-reset");
ok(!resetButton.hasAttribute("modified"), "page is not modified");
// unpin a cell
yield unpinCell(cells[1]);
yield unpinCell(1);
checkGrid("0,1,2,3,4,5,6,7,8");
checkGrid("0,1,2,3,4,5,6,7,8", oldCw.gGrid.sites);
checkGrid("0,1,2,3,4,5,6,7,8", oldSites);
// remove a cell
yield blockCell(cells[1]);
yield blockCell(1);
checkGrid("0,2,3,4,5,6,7,8,9");
checkGrid("0,2,3,4,5,6,7,8,9", oldCw.gGrid.sites);
checkGrid("0,2,3,4,5,6,7,8,9", oldSites);
ok(resetButton.hasAttribute("modified"), "page is modified");
ok(oldResetButton.hasAttribute("modified"), "page is modified");
// insert a new cell by dragging
yield simulateDrop(cells[1]);
yield simulateDrop(1);
checkGrid("0,99p,2,3,4,5,6,7,8");
checkGrid("0,99p,2,3,4,5,6,7,8", oldCw.gGrid.sites);
checkGrid("0,99p,2,3,4,5,6,7,8", oldSites);
// drag a cell around
yield simulateDrop(cells[1], cells[2]);
yield simulateDrop(1, 2);
checkGrid("0,2p,99p,3,4,5,6,7,8");
checkGrid("0,2p,99p,3,4,5,6,7,8", oldCw.gGrid.sites);
checkGrid("0,2p,99p,3,4,5,6,7,8", oldSites);
// reset the new tab page
yield cw.gToolbar.reset(TestRunner.next);
yield getContentWindow().gToolbar.reset(TestRunner.next);
checkGrid("0,1,2,3,4,5,6,7,8");
checkGrid("0,1,2,3,4,5,6,7,8", oldCw.gGrid.sites);
checkGrid("0,1,2,3,4,5,6,7,8", oldSites);
ok(!resetButton.hasAttribute("modified"), "page is not modified");
ok(!oldResetButton.hasAttribute("modified"), "page is not modified");
}

View File

@ -14,7 +14,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,1p,2,3,4,5,6,7,8");
yield unpinCell(cells[1]);
yield unpinCell(1);
checkGrid("0,1,2,3,4,5,6,7,8");
// we have a pinned link that is not anymore in the list of the most-visited
@ -26,7 +26,7 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("0,99p,1,2,3,4,5,6,7");
yield unpinCell(cells[1]);
yield unpinCell(1);
checkGrid("0,1,2,3,4,5,6,7,8");
// we have a pinned link that changed its position since it was pinned. it
@ -37,10 +37,10 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("2,1p,3,4,5,6,7,,0p");
yield unpinCell(cells[1]);
yield unpinCell(1);
checkGrid("1,2,3,4,5,6,7,,0p");
yield unpinCell(cells[8]);
yield unpinCell(8);
checkGrid("0,1,2,3,4,5,6,7,");
// we have pinned link that changed its position since it was pinned. the
@ -51,6 +51,6 @@ function runTests() {
yield addNewTabPageTab();
checkGrid("9p,0,1,2,3,4,5,6,7");
yield unpinCell(cells[0]);
yield unpinCell(0);
checkGrid("0,1,2,3,4,5,6,7,8");
}

View File

@ -16,12 +16,6 @@ registerCleanupFunction(function () {
Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED);
});
/**
* Global variables that are accessed by tests.
*/
let cw;
let cells;
/**
* We'll want to restore the original links provider later.
*/
@ -81,6 +75,39 @@ let TestRunner = {
}
};
/**
* Returns the selected tab's content window.
* @return The content window.
*/
function getContentWindow() {
return gBrowser.selectedBrowser.contentWindow;
}
/**
* Returns the selected tab's content document.
* @return The content document.
*/
function getContentDocument() {
return gBrowser.selectedBrowser.contentDocument;
}
/**
* Returns the newtab grid of the selected tab.
* @return The newtab grid.
*/
function getGrid() {
return getContentWindow().gGrid;
}
/**
* Returns the cell at the given index of the selected tab's newtab grid.
* @param aIndex The cell index.
* @return The newtab cell.
*/
function getCell(aIndex) {
return getGrid().cells[aIndex];
}
/**
* Allows to provide a list of links that is used to construct the grid.
* @param aLinksPattern the pattern (see below)
@ -143,18 +170,14 @@ function addNewTabPageTab() {
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
cw = browser.contentWindow;
if (NewTabUtils.allPages.enabled) {
// Continue when the link cache has been populated.
NewTabUtils.links.populateCache(function () {
cells = cw.gGrid.cells;
executeSoon(TestRunner.next);
});
} else {
TestRunner.next();
}
}, true);
}
@ -169,118 +192,118 @@ function addNewTabPageTab() {
* The fourth cell contains the pinned site 'about:blank#4'.
*/
function checkGrid(aSitesPattern, aSites) {
let valid = true;
let length = aSitesPattern.split(",").length;
let sites = (aSites || getGrid().sites).slice(0, length);
let expected = sites.map(function (aSite) {
if (!aSite)
return "";
aSites = aSites || cw.gGrid.sites;
let pinned = aSite.isPinned();
let pinButton = aSite.node.querySelector(".newtab-control-pin");
let hasPinnedAttr = pinButton.hasAttribute("pinned");
aSitesPattern.split(/\s*,\s*/).forEach(function (id, index) {
let site = aSites[index];
let match = id.match(/^\d+/);
if (pinned != hasPinnedAttr)
ok(false, "invalid state (site.isPinned() != site[pinned])");
// We expect the cell to be empty.
if (!match) {
if (site) {
valid = false;
ok(false, "expected cell#" + index + " to be empty");
}
return;
}
// We expect the cell to contain a site.
if (!site) {
valid = false;
ok(false, "didn't expect cell#" + index + " to be empty");
return;
}
let num = match[0];
// Check the site's url.
if (site.url != "about:blank#" + num) {
valid = false;
is(site.url, "about:blank#" + num, "cell#" + index + " has the wrong url");
}
let shouldBePinned = /p$/.test(id);
let cellContainsPinned = site.isPinned();
let cssClassPinned = site.node && site.node.querySelector(".newtab-control-pin").hasAttribute("pinned");
// Check if the site should be and is pinned.
if (shouldBePinned) {
if (!cellContainsPinned) {
valid = false;
ok(false, "expected cell#" + index + " to be pinned");
} else if (!cssClassPinned) {
valid = false;
ok(false, "expected cell#" + index + " to have css class 'pinned'");
}
} else {
if (cellContainsPinned) {
valid = false;
ok(false, "didn't expect cell#" + index + " to be pinned");
} else if (cssClassPinned) {
valid = false;
ok(false, "didn't expect cell#" + index + " to have css class 'pinned'");
}
}
return aSite.url.replace(/^about:blank#(\d+)$/, "$1") + (pinned ? "p" : "");
});
// If every test passed, say so.
if (valid)
ok(true, "grid status = " + aSitesPattern);
is(aSitesPattern, expected, "grid status = " + aSitesPattern);
}
/**
* Blocks the given cell's site from the grid.
* @param aCell the cell that contains the site to block
* Blocks a site from the grid.
* @param aIndex The cell index.
*/
function blockCell(aCell) {
aCell.site.block(function () executeSoon(TestRunner.next));
function blockCell(aIndex) {
whenPagesUpdated();
getCell(aIndex).site.block();
}
/**
* Pins a given cell's site on a given position.
* @param aCell the cell that contains the site to pin
* @param aIndex the index the defines where the site should be pinned
* Pins a site on a given position.
* @param aIndex The cell index.
* @param aPinIndex The index the defines where the site should be pinned.
*/
function pinCell(aCell, aIndex) {
aCell.site.pin(aIndex);
function pinCell(aIndex, aPinIndex) {
getCell(aIndex).site.pin(aPinIndex);
}
/**
* Unpins the given cell's site.
* @param aCell the cell that contains the site to unpin
* @param aIndex The cell index.
*/
function unpinCell(aCell) {
aCell.site.unpin(function () executeSoon(TestRunner.next));
function unpinCell(aIndex) {
whenPagesUpdated();
getCell(aIndex).site.unpin();
}
/**
* Simulates a drop and drop operation.
* @param aDropTarget the cell that is the drop target
* @param aDragSource the cell that contains the dragged site (optional)
* @param aDropIndex The cell index of the drop target.
* @param aDragIndex The cell index containing the dragged site (optional).
*/
function simulateDrop(aDropTarget, aDragSource) {
let event = {
clientX: 0,
clientY: 0,
dataTransfer: {
mozUserCancelled: false,
setData: function () null,
setDragImage: function () null,
getData: function () "about:blank#99\nblank"
function simulateDrop(aDropIndex, aDragIndex) {
let draggedSite;
let {gDrag: drag, gDrop: drop} = getContentWindow();
let event = createDragEvent("drop", "about:blank#99\nblank");
if (typeof aDragIndex != "undefined")
draggedSite = getCell(aDragIndex).site;
if (draggedSite)
drag.start(draggedSite, event);
whenPagesUpdated();
drop.drop(getCell(aDropIndex), event);
if (draggedSite)
drag.end(draggedSite);
}
/**
* Sends a custom drag event to a given DOM element.
* @param aEventType The drag event's type.
* @param aTarget The DOM element that the event is dispatched to.
* @param aData The event's drag data (optional).
*/
function sendDragEvent(aEventType, aTarget, aData) {
let event = createDragEvent(aEventType, aData);
let ifaceReq = getContentWindow().QueryInterface(Ci.nsIInterfaceRequestor);
let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.dispatchDOMEventViaPresShell(aTarget, event, true);
}
/**
* Creates a custom drag event.
* @param aEventType The drag event's type.
* @param aData The event's drag data (optional).
* @return The drag event.
*/
function createDragEvent(aEventType, aData) {
let dataTransfer = {
mozUserCancelled: false,
setData: function () null,
setDragImage: function () null,
getData: function () aData,
types: {
contains: function (aType) aType == "text/x-moz-url"
},
mozGetDataAt: function (aType, aIndex) {
if (aIndex || aType != "text/x-moz-url")
return null;
return aData;
}
};
if (aDragSource)
cw.gDrag.start(aDragSource.site, event);
let event = getContentDocument().createEvent("DragEvents");
event.initDragEvent(aEventType, true, true, getContentWindow(), 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
cw.gDrop.drop(aDropTarget, event, function () executeSoon(TestRunner.next));
if (aDragSource)
cw.gDrag.end(aDragSource.site);
return event;
}
/**

View File

@ -747,10 +747,6 @@ nsDefaultCommandLineHandler.prototype = {
return this;
},
// List of uri's that were passed via the command line without the app
// running and have already been handled. This is compared against uri's
// opened using DDE on Win32 so we only open one of the requests.
_handledURIs: [ ],
#ifdef XP_WIN
_haveProfile: false,
#endif
@ -784,25 +780,8 @@ nsDefaultCommandLineHandler.prototype = {
try {
var ar;
while ((ar = cmdLine.handleFlagWithParam("url", false))) {
var found = false;
var uri = resolveURIInternal(cmdLine, ar);
// count will never be greater than zero except on Win32.
var count = this._handledURIs.length;
for (var i = 0; i < count; ++i) {
if (this._handledURIs[i].spec == uri.spec) {
this._handledURIs.splice(i, 1);
found = true;
cmdLine.preventDefault = true;
break;
}
}
if (!found) {
urilist.push(uri);
// The requestpending command line flag is only used on Win32.
if (cmdLine.handleFlag("requestpending", false) &&
cmdLine.state == nsICommandLine.STATE_INITIAL_LAUNCH)
this._handledURIs.push(uri)
}
urilist.push(uri);
}
}
catch (e) {

View File

@ -77,7 +77,10 @@
#define INITGUID
#include <shlobj.h>
#pragma comment(lib, "shlwapi.lib") // for SHDeleteKeyW
#include <mbstring.h>
#include <shlwapi.h>
#ifndef MAX_BUF
#define MAX_BUF 4096
@ -129,23 +132,17 @@ OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
//
// HKCU\SOFTWARE\Classes\FirefoxHTML\
// DefaultIcon (default) REG_SZ <apppath>,1
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ Firefox
// \Topic (default) REG_SZ WWW_OpenURL
// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ <empty string>
//
// - Windows Vista Protocol Handler
// - Windows Vista and above Protocol Handler
//
// HKCU\SOFTWARE\Classes\FirefoxURL\ (default) REG_SZ <appname> URL
// EditFlags REG_DWORD 2
// FriendlyTypeName REG_SZ <appname> URL
// DefaultIcon (default) REG_SZ <apppath>,1
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ Firefox
// \Topic (default) REG_SZ WWW_OpenURL
// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ <empty string>
//
// - Protocol Mappings
// -----------------
@ -155,13 +152,10 @@ OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
//
// HKCU\SOFTWARE\Classes\<protocol>\
// DefaultIcon (default) REG_SZ <apppath>,1
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ Firefox
// \Topic (default) REG_SZ WWW_OpenURL
// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ <empty string>
//
// - Windows Start Menu (Win2K SP2, XP SP1, and newer)
// - Windows Start Menu (XP SP1 and newer)
// -------------------------------------------------
// The following keys are set to make Firefox appear in the Start Menu as the
// browser:
@ -180,19 +174,22 @@ OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
// shell\safemode\command (default) REG_SZ <apppath> -safe-mode
//
// The values checked are all default values so the value name is not needed.
typedef struct {
char* keyName;
char* valueName;
char* valueData;
char* oldValueData;
} SETTING;
#define APP_REG_NAME L"Firefox"
#define CLS_HTML "FirefoxHTML"
#define CLS_URL "FirefoxURL"
#define VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
#define VAL_FILE_ICON "%APPPATH%,1"
#define VAL_OPEN "\"%APPPATH%\" -osint -url \"%1\""
#define OLD_VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
#define DI "\\DefaultIcon"
#define SOP "\\shell\\open\\command"
#define SOC "\\shell\\open\\command"
#define SOD "\\shell\\open\\ddeexec"
// Used for updating the FTP protocol handler's shell open command under HKCU.
#define FTP_SOC L"Software\\Classes\\ftp\\shell\\open\\command"
#define MAKE_KEY_NAME1(PREFIX, MID) \
PREFIX MID
@ -201,19 +198,37 @@ typedef struct {
// Firefox is the default browser for file handlers since other applications
// (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
// Handlers. see http://msdn2.microsoft.com/en-us/library/aa969357.aspx for
// more info.
// more info. The FTP protocol is not checked so advanced users can set the FTP
// handler to another application and still have Firefox check if it is the
// default HTTP and HTTPS handler.
static SETTING gSettings[] = {
// File Handler Class
{ MAKE_KEY_NAME1(CLS_HTML, SOP), "", VAL_OPEN },
{ MAKE_KEY_NAME1("FirefoxHTML", SOC), VAL_OPEN, OLD_VAL_OPEN },
// Protocol Handler Class - for Vista and above
{ MAKE_KEY_NAME1(CLS_URL, SOP), "", VAL_OPEN },
{ MAKE_KEY_NAME1("FirefoxURL", SOC), VAL_OPEN, OLD_VAL_OPEN },
// Protocol Handlers
{ MAKE_KEY_NAME1("HTTP", DI), "", VAL_FILE_ICON },
{ MAKE_KEY_NAME1("HTTP", SOP), "", VAL_OPEN },
{ MAKE_KEY_NAME1("HTTPS", DI), "", VAL_FILE_ICON },
{ MAKE_KEY_NAME1("HTTPS", SOP), "", VAL_OPEN }
{ MAKE_KEY_NAME1("HTTP", DI), VAL_FILE_ICON },
{ MAKE_KEY_NAME1("HTTP", SOC), VAL_OPEN, OLD_VAL_OPEN },
{ MAKE_KEY_NAME1("HTTPS", DI), VAL_FILE_ICON },
{ MAKE_KEY_NAME1("HTTPS", SOC), VAL_OPEN, OLD_VAL_OPEN }
};
// The settings to disable DDE are separate from the default browser settings
// since they are only checked when Firefox is the default browser and if they
// are incorrect they are fixed without notifying the user.
static SETTING gDDESettings[] = {
// File Handler Class
{ MAKE_KEY_NAME1("Software\\Classes\\FirefoxHTML", SOD) },
// Protocol Handler Class - for Vista and above
{ MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) },
// Protocol Handlers
{ MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
{ MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
{ MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
};
nsresult
@ -245,11 +260,10 @@ LaunchHelper(nsAutoString& aPath)
STARTUPINFOW si = {sizeof(si), 0};
PROCESS_INFORMATION pi = {0};
BOOL ok = CreateProcessW(NULL, (LPWSTR)aPath.get(), NULL, NULL,
FALSE, 0, NULL, NULL, &si, &pi);
if (!ok)
if (!CreateProcessW(NULL, (LPWSTR)aPath.get(), NULL, NULL, FALSE, 0, NULL,
NULL, &si, &pi)) {
return NS_ERROR_FAILURE;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
@ -367,9 +381,6 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
if (aStartupCheck)
mCheckedThisSession = true;
SETTING* settings;
SETTING* end = gSettings + sizeof(gSettings)/sizeof(SETTING);
*aIsDefaultBrowser = true;
PRUnichar exePath[MAX_BUF];
@ -383,40 +394,171 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
nsAutoString appLongPath(exePath);
HKEY theKey;
DWORD res;
nsresult rv;
PRUnichar currValue[MAX_BUF];
for (settings = gSettings; settings < end; ++settings) {
NS_ConvertUTF8toUTF16 dataLongPath(settings->valueData);
NS_ConvertUTF8toUTF16 key(settings->keyName);
NS_ConvertUTF8toUTF16 value(settings->valueName);
PRInt32 offset = dataLongPath.Find("%APPPATH%");
dataLongPath.Replace(offset, 9, appLongPath);
::ZeroMemory(currValue, sizeof(currValue));
HKEY theKey;
rv = OpenKeyForReading(HKEY_CLASSES_ROOT, key, &theKey);
SETTING* settings;
SETTING* end = gSettings + sizeof(gSettings) / sizeof(SETTING);
for (settings = gSettings; settings < end; ++settings) {
NS_ConvertUTF8toUTF16 keyName(settings->keyName);
NS_ConvertUTF8toUTF16 valueData(settings->valueData);
PRInt32 offset = valueData.Find("%APPPATH%");
valueData.Replace(offset, 9, appLongPath);
rv = OpenKeyForReading(HKEY_CLASSES_ROOT, keyName, &theKey);
if (NS_FAILED(rv)) {
*aIsDefaultBrowser = false;
return NS_OK;
}
::ZeroMemory(currValue, sizeof(currValue));
DWORD len = sizeof currValue;
DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(value).get(),
NULL, NULL, (LPBYTE)currValue, &len);
// Close the key we opened.
res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue, &len);
// Close the key that was opened.
::RegCloseKey(theKey);
if (REG_FAILED(res) ||
!dataLongPath.Equals(currValue, CaseInsensitiveCompare)) {
// Key wasn't set, or was set to something other than our registry entry
*aIsDefaultBrowser = false;
return NS_OK;
!valueData.Equals(currValue, CaseInsensitiveCompare)) {
// Key wasn't set or was set to something other than our registry entry.
NS_ConvertUTF8toUTF16 oldValueData(settings->oldValueData);
offset = oldValueData.Find("%APPPATH%");
oldValueData.Replace(offset, 9, appLongPath);
// The current registry value doesn't match the current or the old format.
if (!oldValueData.Equals(currValue, CaseInsensitiveCompare)) {
*aIsDefaultBrowser = false;
return NS_OK;
}
res = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, PromiseFlatString(keyName).get(),
0, KEY_SET_VALUE, &theKey);
if (REG_FAILED(res)) {
// If updating the open command fails try to update it using the helper
// application when setting Firefox as the default browser.
*aIsDefaultBrowser = false;
return NS_OK;
}
const nsString &flatValue = PromiseFlatString(valueData);
res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
(const BYTE *) flatValue.get(),
(flatValue.Length() + 1) * sizeof(PRUnichar));
// Close the key that was created.
::RegCloseKey(theKey);
if (REG_FAILED(res)) {
// If updating the open command fails try to update it using the helper
// application when setting Firefox as the default browser.
*aIsDefaultBrowser = false;
return NS_OK;
}
}
}
// Only check if Firefox is the default browser on Vista if the previous
// checks show that Firefox is the default browser.
if (*aIsDefaultBrowser)
// Only check if Firefox is the default browser on Vista and above if the
// previous checks show that Firefox is the default browser.
if (*aIsDefaultBrowser) {
IsDefaultBrowserVista(aIsDefaultBrowser);
}
// To handle the case where DDE isn't disabled due for a user because there
// account didn't perform a Firefox update this will check if Firefox is the
// default browser and if dde is disabled for each handler
// and if it isn't disable it. When Firefox is not the default browser the
// helper application will disable dde for each handler.
if (*aIsDefaultBrowser) {
// Check ftp settings
end = gDDESettings + sizeof(gDDESettings) / sizeof(SETTING);
for (settings = gDDESettings; settings < end; ++settings) {
NS_ConvertUTF8toUTF16 keyName(settings->keyName);
rv = OpenKeyForReading(HKEY_CURRENT_USER, keyName, &theKey);
if (NS_FAILED(rv)) {
::RegCloseKey(theKey);
// If disabling DDE fails try to disable it using the helper
// application when setting Firefox as the default browser.
*aIsDefaultBrowser = false;
return NS_OK;
}
::ZeroMemory(currValue, sizeof(currValue));
DWORD len = sizeof currValue;
res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue,
&len);
// Close the key that was opened.
::RegCloseKey(theKey);
if (REG_FAILED(res) || PRUnichar('\0') != *currValue) {
// Key wasn't set or was set to something other than our registry entry.
// Delete the key along with all of its childrean and then recreate it.
const nsString &flatName = PromiseFlatString(keyName);
::SHDeleteKeyW(HKEY_CURRENT_USER, flatName.get());
res = ::RegCreateKeyExW(HKEY_CURRENT_USER, flatName.get(), 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL,
&theKey, NULL);
if (REG_FAILED(res)) {
// If disabling DDE fails try to disable it using the helper
// application when setting Firefox as the default browser.
*aIsDefaultBrowser = false;
return NS_OK;
}
res = ::RegSetValueExW(theKey, L"", 0, REG_SZ, (const BYTE *) L"",
sizeof(PRUnichar));
// Close the key that was created.
::RegCloseKey(theKey);
if (REG_FAILED(res)) {
// If disabling DDE fails try to disable it using the helper
// application when setting Firefox as the default browser.
*aIsDefaultBrowser = false;
return NS_OK;
}
}
}
// Update the FTP protocol handler's shell open command if it is the old
// format.
res = ::RegOpenKeyExW(HKEY_CURRENT_USER, FTP_SOC, 0, KEY_ALL_ACCESS,
&theKey);
// Don't update the FTP protocol handler's shell open command when opening
// its registry key fails under HKCU since it most likely doesn't exist.
if (NS_FAILED(rv)) {
return NS_OK;
}
NS_ConvertUTF8toUTF16 oldValueOpen(OLD_VAL_OPEN);
PRInt32 offset = oldValueOpen.Find("%APPPATH%");
oldValueOpen.Replace(offset, 9, appLongPath);
::ZeroMemory(currValue, sizeof(currValue));
DWORD len = sizeof currValue;
res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue,
&len);
// Don't update the FTP protocol handler's shell open command when the
// current registry value doesn't exist or matches the old format.
if (REG_FAILED(res) ||
!oldValueOpen.Equals(currValue, CaseInsensitiveCompare)) {
::RegCloseKey(theKey);
return NS_OK;
}
NS_ConvertUTF8toUTF16 valueData(VAL_OPEN);
valueData.Replace(offset, 9, appLongPath);
const nsString &flatValue = PromiseFlatString(valueData);
res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
(const BYTE *) flatValue.get(),
(flatValue.Length() + 1) * sizeof(PRUnichar));
// Close the key that was created.
::RegCloseKey(theKey);
// If updating the FTP protocol handlers shell open command fails try to
// update it using the helper application when setting Firefox as the
// default browser.
if (REG_FAILED(res)) {
*aIsDefaultBrowser = false;
}
}
return NS_OK;
}

View File

@ -25,9 +25,6 @@ const Ci = Components.interfaces;
Cu.import("resource:///modules/PageThumbs.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
@ -104,268 +101,252 @@ function Channel(aURI) {
}
Channel.prototype = {
/**
* Tracks if the channel has been opened, yet.
*/
_uri: null,
_referrer: null,
_canceled: false,
_status: Cr.NS_OK,
_isPending: false,
_wasOpened: false,
_responseText: "OK",
_responseStatus: 200,
_responseHeaders: null,
_requestMethod: "GET",
_requestStarted: false,
_allowPipelining: true,
_requestSucceeded: true,
/* :::::::: nsIChannel ::::::::::::::: */
get URI() this._uri,
owner: null,
notificationCallbacks: null,
get securityInfo() null,
contentType: PageThumbs.contentType,
contentCharset: null,
contentLength: -1,
get contentDisposition() {
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
},
get contentDispositionFilename() {
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
},
get contentDispositionHeader() {
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
},
open: function Channel_open() {
throw (Components.returnCode = Cr.NS_ERROR_NOT_IMPLEMENTED);
},
/**
* Opens this channel asynchronously.
* @param aListener The listener that receives the channel data when available.
* @param aContext A custom context passed to the listener's methods.
*/
asyncOpen: function Channel_asyncOpen(aListener, aContext) {
if (this._isPending)
throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
if (this._wasOpened)
throw Cr.NS_ERROR_ALREADY_OPENED;
throw (Components.returnCode = Cr.NS_ERROR_ALREADY_OPENED);
if (this.canceled)
return;
this._listener = aListener;
this._context = aContext;
if (this._canceled)
return (Components.returnCode = this._status);
this._isPending = true;
this._wasOpened = true;
// Try to read the data from the thumbnail cache.
this._readCache(function (aData) {
let telemetryThumbnailFound = true;
this._listener = aListener;
this._context = aContext;
// Update response if there's no data.
if (!aData) {
this._responseStatus = 404;
this._responseText = "Not Found";
telemetryThumbnailFound = false;
}
if (this.loadGroup)
this.loadGroup.addRequest(this, null);
Services.telemetry.getHistogramById("FX_THUMBNAILS_HIT_OR_MISS")
.add(telemetryThumbnailFound);
if (this._canceled)
return;
this._startRequest();
if (!this.canceled) {
this._addToLoadGroup();
if (aData)
this._serveData(aData);
if (!this.canceled)
this._stopRequest();
}
}.bind(this));
},
/**
* Reads a data stream from the cache entry.
* @param aCallback The callback the data is passed to.
*/
_readCache: function Channel_readCache(aCallback) {
let {url} = parseURI(this._uri);
// Return early if there's no valid URL given.
if (!url) {
aCallback(null);
this._serveThumbnailNotFound();
return;
}
// Try to get a cache entry.
PageThumbsCache.getReadEntry(url, function (aEntry) {
let inputStream = aEntry && aEntry.openInputStream(0);
function closeEntryAndFinish(aData) {
if (aEntry) {
aEntry.close();
}
aCallback(aData);
}
// Check if we have a valid entry and if it has any data.
if (!inputStream || !inputStream.available()) {
closeEntryAndFinish();
if (aEntry)
aEntry.close();
this._serveThumbnailNotFound();
return;
}
try {
// Read the cache entry's data.
NetUtil.asyncFetch(inputStream, function (aData, aStatus) {
// We might have been canceled while waiting.
if (this.canceled)
return;
this._entry = aEntry;
this._pump = Cc["@mozilla.org/network/input-stream-pump;1"].
createInstance(Ci.nsIInputStreamPump);
// Check if we have a valid data stream.
if (!Components.isSuccessCode(aStatus) || !aData.available())
aData = null;
this._pump.init(inputStream, -1, -1, 0, 0, true);
this._pump.asyncRead(this, null);
closeEntryAndFinish(aData);
}.bind(this));
} catch (e) {
closeEntryAndFinish();
}
this._trackThumbnailHitOrMiss(true);
}.bind(this));
},
/**
* Calls onStartRequest on the channel listener.
* Serves a "404 Not Found" if we didn't find the requested thumbnail.
*/
_startRequest: function Channel_startRequest() {
try {
this._listener.onStartRequest(this, this._context);
} catch (e) {
// The listener might throw if the request has been canceled.
this.cancel(Cr.NS_BINDING_ABORTED);
}
_serveThumbnailNotFound: function Channel_serveThumbnailNotFound() {
this._responseStatus = 404;
this._responseText = "Not Found";
this._requestSucceeded = false;
this.onStartRequest(this, null);
this.onStopRequest(this, null, Cr.NS_OK);
this._trackThumbnailHitOrMiss(false);
},
/**
* Calls onDataAvailable on the channel listener and passes the data stream.
* @param aData The data to be delivered.
* Implements telemetry tracking for thumbnail cache hits and misses.
* @param aFound Whether the thumbnail was found.
*/
_serveData: function Channel_serveData(aData) {
try {
let available = aData.available();
this._listener.onDataAvailable(this, this._context, aData, 0, available);
} catch (e) {
// The listener might throw if the request has been canceled.
this.cancel(Cr.NS_BINDING_ABORTED);
}
_trackThumbnailHitOrMiss: function Channel_trackThumbnailHitOrMiss(aFound) {
Services.telemetry.getHistogramById("FX_THUMBNAILS_HIT_OR_MISS")
.add(aFound);
},
/**
* Calls onStopRequest on the channel listener.
*/
_stopRequest: function Channel_stopRequest() {
try {
this._listener.onStopRequest(this, this._context, this.status);
} catch (e) {
// This might throw but is generally ignored.
}
/* :::::::: nsIStreamListener ::::::::::::::: */
// The request has finished, clean up after ourselves.
this._cleanup();
onStartRequest: function Channel_onStartRequest(aRequest, aContext) {
if (!this.canceled && Components.isSuccessCode(this._status))
this._status = aRequest.status;
this._requestStarted = true;
this._listener.onStartRequest(this, this._context);
},
/**
* Adds this request to the load group, if any.
*/
_addToLoadGroup: function Channel_addToLoadGroup() {
onDataAvailable: function Channel_onDataAvailable(aRequest, aContext,
aInStream, aOffset, aCount) {
this._listener.onDataAvailable(this, this._context, aInStream, aOffset, aCount);
},
onStopRequest: function Channel_onStopRequest(aRequest, aContext, aStatus) {
this._isPending = false;
this._status = aStatus;
this._listener.onStopRequest(this, this._context, aStatus);
this._listener = null;
this._context = null;
if (this._entry)
this._entry.close();
if (this.loadGroup)
this.loadGroup.addRequest(this, this._context);
this.loadGroup.removeRequest(this, null, aStatus);
},
/**
* Removes this request from its load group, if any.
*/
_removeFromLoadGroup: function Channel_removeFromLoadGroup() {
if (!this.loadGroup)
/* :::::::: nsIRequest ::::::::::::::: */
get status() this._status,
get name() this._uri.spec,
isPending: function Channel_isPending() this._isPending,
loadFlags: Ci.nsIRequest.LOAD_NORMAL,
loadGroup: null,
cancel: function Channel_cancel(aStatus) {
if (this._canceled)
return;
try {
this.loadGroup.removeRequest(this, this._context, this.status);
} catch (e) {
// This might throw but is ignored.
}
this._canceled = true;
this._status = aStatus;
if (this._pump)
this._pump.cancel(aStatus);
},
/**
* Cleans up the channel when the request has finished.
*/
_cleanup: function Channel_cleanup() {
this._removeFromLoadGroup();
this.loadGroup = null;
this._isPending = false;
delete this._listener;
delete this._context;
suspend: function Channel_suspend() {
if (this._pump)
this._pump.suspend();
},
/* :::::::: nsIChannel ::::::::::::::: */
contentType: PageThumbs.contentType,
contentLength: -1,
owner: null,
contentCharset: null,
notificationCallbacks: null,
get URI() this._uri,
get securityInfo() null,
/**
* Opens this channel synchronously. Not supported.
*/
open: function Channel_open() {
// Synchronous data delivery is not implemented.
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
resume: function Channel_resume() {
if (this._pump)
this._pump.resume();
},
/* :::::::: nsIHttpChannel ::::::::::::::: */
redirectionLimit: 10,
requestMethod: "GET",
allowPipelining: true,
referrer: null,
get referrer() this._referrer,
get requestSucceeded() true,
set referrer(aReferrer) {
if (this._wasOpened)
throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
_responseStatus: 200,
get responseStatus() this._responseStatus,
_responseText: "OK",
get responseStatusText() this._responseText,
/**
* Checks if the server sent the equivalent of a "Cache-control: no-cache"
* response header.
* @return Always false.
*/
isNoCacheResponse: function () false,
/**
* Checks if the server sent the equivalent of a "Cache-control: no-cache"
* response header.
* @return Always false.
*/
isNoStoreResponse: function () false,
/**
* Returns the value of a particular request header. Not implemented.
*/
getRequestHeader: function Channel_getRequestHeader() {
throw Cr.NS_ERROR_NOT_AVAILABLE;
this._referrer = aReferrer;
},
get requestMethod() this._requestMethod,
set requestMethod(aMethod) {
if (this._wasOpened)
throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
this._requestMethod = aMethod.toUpperCase();
},
get allowPipelining() this._allowPipelining,
set allowPipelining(aAllow) {
if (this._wasOpened)
throw (Components.returnCode = Cr.NS_ERROR_FAILURE);
this._allowPipelining = aAllow;
},
redirectionLimit: 10,
get responseStatus() {
if (this._requestStarted)
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
return this._responseStatus;
},
get responseStatusText() {
if (this._requestStarted)
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
return this._responseText;
},
get requestSucceeded() {
if (this._requestStarted)
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
return this._requestSucceeded;
},
isNoCacheResponse: function Channel_isNoCacheResponse() false,
isNoStoreResponse: function Channel_isNoStoreResponse() false,
getRequestHeader: function Channel_getRequestHeader() {
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
},
/**
* This method is called to set the value of a particular request header.
* Not implemented.
*/
setRequestHeader: function Channel_setRequestHeader() {
if (this._wasOpened)
throw Cr.NS_ERROR_IN_PROGRESS;
throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
},
/**
* Call this method to visit all request headers. Not implemented.
*/
visitRequestHeaders: function () {},
visitRequestHeaders: function Channel_visitRequestHeaders() {},
/**
* Gets the value of a particular response header.
* @param aHeader The case-insensitive name of the response header to query.
* @return The header value.
*/
getResponseHeader: function Channel_getResponseHeader(aHeader) {
let name = aHeader.toLowerCase();
if (name in this._responseHeaders)
return this._responseHeaders[name];
throw Cr.NS_ERROR_NOT_AVAILABLE;
throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
},
/**
* This method is called to set the value of a particular response header.
* @param aHeader The case-insensitive name of the response header to query.
* @param aValue The response header value to set.
*/
setResponseHeader: function Channel_setResponseHeader(aHeader, aValue, aMerge) {
let name = aHeader.toLowerCase();
if (!aValue && !aMerge)
@ -374,10 +355,6 @@ Channel.prototype = {
this._responseHeaders[name] = aValue;
},
/**
* Call this method to visit all response headers.
* @param aVisitor The header visitor.
*/
visitResponseHeaders: function Channel_visitResponseHeaders(aVisitor) {
for (let name in this._responseHeaders) {
let value = this._responseHeaders[name];
@ -391,48 +368,17 @@ Channel.prototype = {
}
},
/* :::::::: nsIRequest ::::::::::::::: */
loadFlags: Ci.nsIRequest.LOAD_NORMAL,
loadGroup: null,
get name() this._uri.spec,
_status: Cr.NS_OK,
get status() this._status,
_isPending: false,
isPending: function () this._isPending,
resume: function () {},
suspend: function () {},
/**
* Cancels this request.
* @param aStatus The reason for cancelling.
*/
cancel: function Channel_cancel(aStatus) {
if (this.canceled)
return;
this._isCanceled = true;
this._status = aStatus;
this._cleanup();
},
/* :::::::: nsIHttpChannelInternal ::::::::::::::: */
documentURI: null,
_isCanceled: false,
get canceled() this._isCanceled,
get canceled() this._canceled,
allowSpdy: false,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel,
Ci.nsIHttpChannel,
Ci.nsIHttpChannelInternal,
Ci.nsIRequest])
};
}
/**
* Parses a given URI and extracts all parameters relevant to this protocol.

View File

@ -103,7 +103,7 @@ VIAddVersionKey "OriginalFilename" "setup.exe"
; Must be inserted before other macros that use logging
!insertmacro _LoggingCommon
!insertmacro AddDDEHandlerValues
!insertmacro AddDisabledDDEHandlerValues
!insertmacro ChangeMUIHeaderImage
!insertmacro CheckForFilesInUse
!insertmacro CleanUpdatesDir
@ -352,17 +352,15 @@ Section "-Application" APP_IDX
${SetUninstallKeys}
; On install always add the FirefoxHTML and FirefoxURL keys.
; An empty string is used for the 5th param because FirefoxHTML and FirefoxURL
; are not protocol handlers.
; An empty string is used for the 5th param because FirefoxHTML is not a
; protocol handler.
${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
StrCpy $2 "$\"$8$\" -requestPending -osint -url $\"%1$\""
StrCpy $3 "$\"%1$\",,0,0,,,,"
StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} Document" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
"${AppRegName} Document" ""
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
"true"
; The following keys should only be set if we can write to HKLM
${If} $TmpVal == "HKLM"

View File

@ -79,7 +79,7 @@
${GetLongPath} "$0" $0
${EndIf}
${If} "$0" == "$INSTDIR"
${SetStartMenuInternet}
${SetStartMenuInternet} ; Does not use SHCTX
${EndIf}
ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"
@ -156,12 +156,12 @@
!define PostUpdate "!insertmacro PostUpdate"
!macro SetAsDefaultAppGlobal
${RemoveDeprecatedKeys}
${RemoveDeprecatedKeys} ; Does not use SHCTX
SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
${SetHandlers}
${SetStartMenuInternet}
${FixShellIconHandler}
${SetHandlers} ; Uses SHCTX
${SetStartMenuInternet} ; Does not use SHCTX
${FixShellIconHandler} ; Does not use SHCTX
${ShowShortcuts}
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
WriteRegStr HKLM "Software\Clients\StartMenuInternet" "" "$R9"
@ -306,7 +306,7 @@
${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
StrCpy $0 "SOFTWARE\Classes"
StrCpy $2 "$\"$8$\" -requestPending -osint -url $\"%1$\""
StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
; Associate the file handlers with FirefoxHTML
ReadRegStr $6 SHCTX "$0\.htm" ""
@ -340,25 +340,20 @@
WriteRegStr SHCTX "$0\.webm" "" "FirefoxHTML"
${EndIf}
StrCpy $3 "$\"%1$\",,0,0,,,,"
; An empty string is used for the 5th param because FirefoxHTML is not a
; protocol handler
${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
"${AppRegName} HTML Document" ""
${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
"true"
; An empty string is used for the 4th & 5th params because the following
; protocol handlers already have a display name and the additional keys
; required for a protocol handler.
${AddDDEHandlerValues} "ftp" "$2" "$8,1" "" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDDEHandlerValues} "http" "$2" "$8,1" "" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDDEHandlerValues} "https" "$2" "$8,1" "" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "ftp" "$2" "$8,1" "" ""
${AddDisabledDDEHandlerValues} "http" "$2" "$8,1" "" ""
${AddDisabledDDEHandlerValues} "https" "$2" "$8,1" "" ""
!macroend
!define SetHandlers "!insertmacro SetHandlers"
@ -567,8 +562,7 @@
!macro UpdateProtocolHandlers
; Store the command to open the app with an url in a register for easy access.
${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
StrCpy $2 "$\"$8$\" -requestPending -osint -url $\"%1$\""
StrCpy $3 "$\"%1$\",,0,0,,,,"
StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
; Only set the file and protocol handlers if the existing one under HKCR is
; for this install location.
@ -577,32 +571,32 @@
${If} "$R9" == "true"
; An empty string is used for the 5th param because FirefoxHTML is not a
; protocol handler.
${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
"${AppRegName} HTML Document" ""
${EndIf}
${IsHandlerForInstallDir} "FirefoxURL" $R9
${If} "$R9" == "true"
${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" \
"${AppRegName} URL" "true"
${EndIf}
; An empty string is used for the 4th & 5th params because the following
; protocol handlers already have a display name and the additional keys
; required for a protocol handler.
${IsHandlerForInstallDir} "ftp" $R9
${If} "$R9" == "true"
${AddDDEHandlerValues} "ftp" "$2" "$8,1" "" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "ftp" "$2" "$8,1" "" ""
${EndIf}
${IsHandlerForInstallDir} "http" $R9
${If} "$R9" == "true"
${AddDDEHandlerValues} "http" "$2" "$8,1" "" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "http" "$2" "$8,1" "" ""
${EndIf}
${IsHandlerForInstallDir} "https" $R9
${If} "$R9" == "true"
${AddDDEHandlerValues} "https" "$2" "$8,1" "" "" \
"${DDEApplication}" "$3" "WWW_OpenURL"
${AddDisabledDDEHandlerValues} "https" "$2" "$8,1" "" ""
${EndIf}
!macroend
!define UpdateProtocolHandlers "!insertmacro UpdateProtocolHandlers"
@ -1164,11 +1158,13 @@ Function SetAsDefaultAppUser
; b) is not a member of the administrators group and chooses to elevate
${ElevateUAC}
${SetStartMenuInternet}
${SetStartMenuInternet} ; Does not use SHCTX
SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)
${FixShellIconHandler}
${RemoveDeprecatedKeys}
${FixClassKeys} ; Does not use SHCTX
${FixShellIconHandler} ; Does not use SHCTX
${RemoveDeprecatedKeys} ; Does not use SHCTX
ClearErrors
${GetParameters} $0

View File

@ -92,7 +92,7 @@ Var MaintCertKey
VIAddVersionKey "FileDescription" "${BrandShortName} Helper"
VIAddVersionKey "OriginalFilename" "helper.exe"
!insertmacro AddDDEHandlerValues
!insertmacro AddDisabledDDEHandlerValues
!insertmacro CleanVirtualStore
!insertmacro ElevateUAC
!insertmacro GetLongPath

View File

@ -630,7 +630,6 @@ var xml = <prefs>
<pref><name>font.size.variable.x-guru</name></pref>
<pref><name>font.size.variable.x-gujr</name></pref>
<pref><name>network.protocol-handler.external.vnd.ms.radio</name></pref>
<pref><name>advanced.system.supportDDEExec</name></pref>
<pref><name>browser.tabs.opentabfor.urlbar</name></pref>
<pref><name>font.name.sans-serif.x-khmr</name></pref>
<pref><name>mousewheel.horizscroll.withshiftkey.sysnumlines</name></pref>

View File

@ -2085,13 +2085,6 @@ pref("plugin.allow.asyncdrawing", false);
// when a network address is unreachable.
pref("network.autodial-helper.enabled", true);
// Pref to control whether we set ddeexec subkeys for the http
// Internet shortcut protocol if we are handling it. These
// subkeys will be set only while we are running (to avoid the
// problem of Windows showing an alert when it tries to use DDE
// and we're not already running).
pref("advanced.system.supportDDEExec", true);
// Switch the keyboard layout per window
pref("intl.keyboard.per_window_layout", false);

View File

@ -1193,7 +1193,9 @@
* @param _VALOPEN
* The path and args to launch the application.
* @param _VALICON
* The path to an exe that contains an icon and the icon resource id.
* The path to the binary that contains the icon group for the default icon
* followed by a comma and either the icon group's resource index or the icon
* group's resource id prefixed with a minus sign
* @param _DISPNAME
* The display name for the handler. If emtpy no value will be set.
* @param _ISPROTOCOL
@ -1237,10 +1239,9 @@
WriteRegStr SHCTX "$R4" "" "$R7"
WriteRegStr SHCTX "$R4" "FriendlyTypeName" "$R7"
StrCmp "$R8" "true" +1 +8
StrCmp "$R8" "true" +1 +2
WriteRegStr SHCTX "$R4" "URL Protocol" ""
StrCpy $R3 ""
ClearErrors
ReadRegDWord $R3 SHCTX "$R4" "EditFlags"
StrCmp $R3 "" +1 +3 ; Only add EditFlags if a value doesn't exist
DeleteRegValue SHCTX "$R4" "EditFlags"
@ -1336,7 +1337,9 @@
* @param _VALOPEN
* The path and args to launch the application.
* @param _VALICON
* The path to an exe that contains an icon and the icon resource id.
* The path to the binary that contains the icon group for the default icon
* followed by a comma and either the icon group's resource index or the icon
* group's resource id prefixed with a minus sign
* @param _DISPNAME
* The display name for the handler. If emtpy no value will be set.
* @param _ISPROTOCOL
@ -1389,10 +1392,9 @@
WriteRegStr SHCTX "$R0\$R2" "" "$R5"
WriteRegStr SHCTX "$R0\$R2" "FriendlyTypeName" "$R5"
StrCmp "$R6" "true" +1 +8
StrCmp "$R6" "true" +1 +2
WriteRegStr SHCTX "$R0\$R2" "URL Protocol" ""
StrCpy $R1 ""
ClearErrors
ReadRegDWord $R1 SHCTX "$R0\$R2" "EditFlags"
StrCmp $R1 "" +1 +3 ; Only add EditFlags if a value doesn't exist
DeleteRegValue SHCTX "$R0\$R2" "EditFlags"
@ -1485,6 +1487,154 @@
!endif
!macroend
/**
* Writes common registry values for a handler that DOES NOT use DDE using SHCTX.
*
* @param _KEY
* The key name in relation to the HKCR root. SOFTWARE\Classes is
* prefixed to this value when using SHCTX.
* @param _VALOPEN
* The path and args to launch the application.
* @param _VALICON
* The path to the binary that contains the icon group for the default icon
* followed by a comma and either the icon group's resource index or the icon
* group's resource id prefixed with a minus sign
* @param _DISPNAME
* The display name for the handler. If emtpy no value will be set.
* @param _ISPROTOCOL
* Sets protocol handler specific registry values when "true".
*
* $R3 = storage for SOFTWARE\Classes
* $R4 = string value of the current registry key path.
* $R5 = _KEY
* $R6 = _VALOPEN
* $R7 = _VALICON
* $R8 = _DISPNAME
* $R9 = _ISPROTOCOL
*/
!macro AddDisabledDDEHandlerValues
!ifndef ${_MOZFUNC_UN}AddDisabledDDEHandlerValues
!verbose push
!verbose ${_MOZFUNC_VERBOSE}
!define ${_MOZFUNC_UN}AddDisabledDDEHandlerValues "!insertmacro ${_MOZFUNC_UN}AddDisabledDDEHandlerValuesCall"
Function ${_MOZFUNC_UN}AddDisabledDDEHandlerValues
Exch $R9 ; true if a protocol handler
Exch 1
Exch $R8 ; FriendlyTypeName
Exch 2
Exch $R7 ; icon index
Exch 3
Exch $R6 ; shell\open\command
Exch 4
Exch $R5 ; reg key
Push $R4 ;
Push $R3 ; base reg class
StrCpy $R3 "SOFTWARE\Classes"
StrCmp "$R8" "" +6 +1
ReadRegStr $R4 SHCTX "$R5" "FriendlyTypeName"
StrCmp "$R4" "" +1 +3
WriteRegStr SHCTX "$R3\$R5" "" "$R8"
WriteRegStr SHCTX "$R3\$R5" "FriendlyTypeName" "$R8"
StrCmp "$R9" "true" +1 +2
WriteRegStr SHCTX "$R3\$R5" "URL Protocol" ""
StrCpy $R4 ""
ReadRegDWord $R4 SHCTX "$R3\$R5" "EditFlags"
StrCmp $R4 "" +1 +3 ; Only add EditFlags if a value doesn't exist
DeleteRegValue SHCTX "$R3\$R5" "EditFlags"
WriteRegDWord SHCTX "$R3\$R5" "EditFlags" 0x00000002
StrCmp "$R7" "" +2 +1
WriteRegStr SHCTX "$R3\$R5\DefaultIcon" "" "$R7"
; Main command handler for the app
WriteRegStr SHCTX "$R3\$R5\shell\open\command" "" "$R6"
; Drop support for DDE (bug 491947), and remove old dde entries if
; they exist.
;
; Note, changes in SHCTX should propegate to hkey classes root when
; current user or local machine entries are written. Windows will also
; attempt to propegate entries when a handler is used. CR entries are a
; combination of LM and CU, with CU taking priority.
;
; To disable dde, an empty shell/ddeexec key must be created in current
; user or local machine. Unfortunately, settings have various different
; behaviors depending on the windows version. The following code attempts
; to address these differences.
;
; On XP (no SP, SP1, SP2), Vista: An empty default string
; must be set under ddeexec. Empty strings propagate to CR.
;
; Win7: IE does not configure ddeexec, so issues with left over ddeexec keys
; in LM are reduced. We configure an empty ddeexec key with an empty default
; string in CU to be sure.
;
DeleteRegKey SHCTX "SOFTWARE\Classes\$R5\shell\open\ddeexec"
WriteRegStr SHCTX "SOFTWARE\Classes\$R5\shell\open\ddeexec" "" ""
ClearErrors
Pop $R3
Pop $R4
Exch $R5
Exch 4
Exch $R6
Exch 3
Exch $R7
Exch 2
Exch $R8
Exch 1
Exch $R9
FunctionEnd
!verbose pop
!endif
!macroend
!macro AddDisabledDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL
!verbose push
!verbose ${_MOZFUNC_VERBOSE}
Push "${_KEY}"
Push "${_VALOPEN}"
Push "${_VALICON}"
Push "${_DISPNAME}"
Push "${_ISPROTOCOL}"
Call AddDisabledDDEHandlerValues
!verbose pop
!macroend
!macro un.AddDisabledDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL
!verbose push
!verbose ${_MOZFUNC_VERBOSE}
Push "${_KEY}"
Push "${_VALOPEN}"
Push "${_VALICON}"
Push "${_DISPNAME}"
Push "${_ISPROTOCOL}"
Call un.AddDisabledDDEHandlerValues
!verbose pop
!macroend
!macro un.AddDisabledDDEHandlerValues
!ifndef un.AddDisabledDDEHandlerValues
!verbose push
!verbose ${_MOZFUNC_VERBOSE}
!undef _MOZFUNC_UN
!define _MOZFUNC_UN "un."
!insertmacro AddDisabledDDEHandlerValues
!undef _MOZFUNC_UN
!define _MOZFUNC_UN
!verbose pop
!endif
!macroend
################################################################################
# Macros for handling DLL registration
@ -2804,6 +2954,7 @@
StrCmp "$R7" "$R8" +1 end
DeleteRegValue HKLM "Software\Classes\$R9\DefaultIcon" ""
DeleteRegValue HKLM "Software\Classes\$R9\shell\open" ""
DeleteRegValue HKLM "Software\Classes\$R9\shell\open\command" ""
DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec" ""
DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Application" ""
DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Topic" ""