Bug 554919, support panels which can dragged via their backgrounds, r=dao,smaug

This commit is contained in:
Neil Deakin 2011-06-03 15:38:24 -04:00
parent f9daca5776
commit 8307283671
5 changed files with 95 additions and 17 deletions

View File

@ -190,7 +190,7 @@
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#include "nsIDOMXULControlElement.h"
#include "nsIFrame.h"
#include "nsMenuPopupFrame.h"
#endif
#include "xpcprivate.h"
@ -10214,9 +10214,28 @@ nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
}
NS_IMETHODIMP
nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent)
nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent, nsIDOMElement* aPanel)
{
nsCOMPtr<nsIWidget> widget = GetMainWidget();
nsCOMPtr<nsIWidget> widget;
// if a panel was supplied, use its widget instead.
#ifdef MOZ_XUL
if (aPanel) {
nsCOMPtr<nsIContent> panel = do_QueryInterface(aPanel);
NS_ENSURE_TRUE(panel, NS_ERROR_FAILURE);
nsIFrame* frame = panel->GetPrimaryFrame();
NS_ENSURE_TRUE(frame && frame->GetType() == nsGkAtoms::menuPopupFrame, NS_OK);
(static_cast<nsMenuPopupFrame*>(frame))->GetWidget(getter_AddRefs(widget));
}
else {
#endif
widget = GetMainWidget();
#ifdef MOZ_XUL
}
#endif
if (!widget) {
return NS_OK;
}

View File

@ -43,7 +43,7 @@ interface nsIDOMElement;
interface nsIDOMEvent;
interface nsIChromeFrameMessageManager;
[scriptable, uuid(ec38cbaf-372f-4874-bc7a-dbf1f0b3d755)]
[scriptable, uuid(7cfbc355-cbf9-4408-8e4c-a3c603ff1428)]
interface nsIDOMChromeWindow : nsISupports
{
const unsigned short STATE_MAXIMIZED = 1;
@ -84,8 +84,10 @@ interface nsIDOMChromeWindow : nsISupports
* start dragging the window. This function will fail unless called
* while the left mouse button is held down, callers must check this.
*
* The optional panel argument should be set when moving a panel.
*
* Returns NS_ERROR_NOT_IMPLEMENTED (and thus throws in JS) if the OS
* doesn't support this.
*/
void beginWindowMove(in nsIDOMEvent mouseDownEvent);
void beginWindowMove(in nsIDOMEvent mouseDownEvent, [optional] in nsIDOMElement panel);
};

View File

@ -40,10 +40,11 @@ function WindowDraggingElement(elem, window) {
this._elem = elem;
this._window = window;
#ifdef XP_WIN
this._elem.addEventListener("MozMouseHittest", this, false);
#else
this._elem.addEventListener("mousedown", this, false);
if (!this.isPanel())
this._elem.addEventListener("MozMouseHittest", this, false);
else
#endif
this._elem.addEventListener("mousedown", this, false);
}
WindowDraggingElement.prototype = {
@ -79,11 +80,20 @@ WindowDraggingElement.prototype = {
}
return true;
},
isPanel : function() {
return this._elem instanceof Components.interfaces.nsIDOMXULElement &&
this._elem.localName == "panel";
},
handleEvent: function(aEvent) {
let isPanel = this.isPanel();
#ifdef XP_WIN
if (this.shouldDrag(aEvent))
aEvent.preventDefault();
#else
if (!isPanel) {
if (this.shouldDrag(aEvent))
aEvent.preventDefault();
return;
}
#endif
switch (aEvent.type) {
case "mousedown":
if (!this.shouldDrag(aEvent))
@ -92,18 +102,27 @@ WindowDraggingElement.prototype = {
#ifdef MOZ_WIDGET_GTK2
// On GTK, there is a toolkit-level function which handles
// window dragging, which must be used.
this._window.beginWindowMove(aEvent);
this._window.beginWindowMove(aEvent, isPanel ? this._elem : null);
#else
this._deltaX = aEvent.screenX - this._window.screenX;
this._deltaY = aEvent.screenY - this._window.screenY;
if (isPanel) {
let screenRect = this._elem.getOuterScreenRect();
this._deltaX = aEvent.screenX - screenRect.left;
this._deltaY = aEvent.screenY - screenRect.top;
}
else {
this._deltaX = aEvent.screenX - this._window.screenX;
this._deltaY = aEvent.screenY - this._window.screenY;
}
this._draggingWindow = true;
this._window.addEventListener("mousemove", this, false);
this._window.addEventListener("mouseup", this, false);
#endif
break;
case "mousemove":
if (this._draggingWindow)
this._window.moveTo(aEvent.screenX - this._deltaX, aEvent.screenY - this._deltaY);
if (this._draggingWindow) {
let toDrag = this.isPanel() ? this._elem : this._window;
toDrag.moveTo(aEvent.screenX - this._deltaX, aEvent.screenY - this._deltaY);
}
break;
case "mouseup":
if (this._draggingWindow) {
@ -113,6 +132,5 @@ WindowDraggingElement.prototype = {
}
break;
}
#endif
}
}

View File

@ -227,6 +227,31 @@ var tests = [
panel.appendChild(tree);
checkTreeCoords();
}
},
{
testname: "noautohide panel with backdrag",
attrs: { noautohide: true, backdrag: "true" },
test: function(panel) {
var label = document.createElement("label");
label.id = "backdragspot";
label.setAttribute("value", "Hello There");
panel.appendChild(label);
panel.openPopupAtScreen(200, 230);
},
result: function(testname, panel) {
var oldrect = panel.getOuterScreenRect();
// Linux uses native window moving
if (navigator.platform.indexOf("Linux") == -1) {
var backdragspot = document.getElementById("backdragspot");
synthesizeMouse(backdragspot, 5, 5, { type: "mousedown" });
synthesizeMouse(backdragspot, 15, 20, { type: "mousemove" });
synthesizeMouse(backdragspot, 15, 20, { type: "mouseup" });
is(panel.getOuterScreenRect().left, 210, testname + "left");
is(panel.getOuterScreenRect().top, 245, testname + "top");
}
}
}
];

View File

@ -229,6 +229,20 @@
]]></getter>
</property>
<field name="_prevFocus">0</field>
<field name="_dragBindingAlive">true</field>
<constructor>
<![CDATA[
if (this.getAttribute("backdrag") == "true" && !this._draggableStarted) {
this._draggableStarted = true;
try {
let tmp = {};
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
let draghandle = new tmp.WindowDraggingElement(this, window);
draghandle.mouseDownCheck = function () this._dragBindingAlive;
} catch (e) {}
}
]]>
</constructor>
</implementation>
<handlers>