Bug 566480 - Make dragging the menubar drag the window on GTK themes where that should work (and also fix GTK resize drags to initialize drag better). r=karlt,dbaron,enn,dao

This commit is contained in:
Michael Ventnor ext:(%2C%20L.%20David%20Baron%20%3Cdbaron%40dbaron.org%3E) 2010-07-17 10:11:54 +02:00
Родитель fba699e63b
Коммит 6e287b8de2
15 изменённых файлов: 167 добавлений и 45 удалений

Просмотреть файл

@ -1706,6 +1706,7 @@ GK_ATOM(windows_compositor, "windows-compositor")
GK_ATOM(windows_classic, "windows-classic")
GK_ATOM(touch_enabled, "touch-enabled")
GK_ATOM(maemo_classic, "maemo-classic")
GK_ATOM(menubar_drag, "menubar-drag")
// And the same again, as media query keywords.
GK_ATOM(_moz_scrollbar_start_backward, "-moz-scrollbar-start-backward")
@ -1721,3 +1722,4 @@ GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
GK_ATOM(_moz_touch_enabled, "-moz-touch-enabled")
GK_ATOM(_moz_maemo_classic, "-moz-maemo-classic")
GK_ATOM(_moz_menubar_drag, "-moz-menubar-drag")

Просмотреть файл

@ -9433,6 +9433,25 @@ nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
return rv;
}
NS_IMETHODIMP
nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent)
{
nsCOMPtr<nsIWidget> widget = GetMainWidget();
if (!widget) {
return NS_OK;
}
nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(aMouseDownEvent);
NS_ENSURE_TRUE(privEvent, NS_ERROR_FAILURE);
nsEvent *internalEvent = privEvent->GetInternalNSEvent();
NS_ENSURE_TRUE(internalEvent &&
internalEvent->eventStructType == NS_MOUSE_EVENT,
NS_ERROR_FAILURE);
nsMouseEvent *mouseEvent = static_cast<nsMouseEvent*>(internalEvent);
return widget->BeginMoveDrag(mouseEvent);
}
//Note: This call will lock the cursor, it will not change as it moves.
//To unlock, the cursor must be set back to CURSOR_AUTO.
NS_IMETHODIMP

Просмотреть файл

@ -40,9 +40,10 @@
interface nsIBrowserDOMWindow;
interface nsIDOMElement;
interface nsIDOMEvent;
interface nsIChromeFrameMessageManager;
[scriptable, uuid(adf6b19f-459f-4892-93eb-71c527bae2af)]
[scriptable, uuid(ec38cbaf-372f-4874-bc7a-dbf1f0b3d755)]
interface nsIDOMChromeWindow : nsISupports
{
const unsigned short STATE_MAXIMIZED = 1;
@ -76,4 +77,15 @@ interface nsIDOMChromeWindow : nsISupports
void notifyDefaultButtonLoaded(in nsIDOMElement defaultButton);
readonly attribute nsIChromeFrameMessageManager messageManager;
/**
* On some operating systems, we must allow the window manager to
* handle window dragging. This function tells the window manager to
* start dragging the window. This function will fail unless called
* while the left mouse button is held down, callers must check this.
*
* Returns NS_ERROR_NOT_IMPLEMENTED (and thus throws in JS) if the OS
* doesn't support this.
*/
void beginWindowMove(in nsIDOMEvent mouseDownEvent);
};

Просмотреть файл

@ -1000,6 +1000,11 @@ InitSystemMetrics()
sSystemMetrics->AppendElement(nsGkAtoms::images_in_buttons);
}
lookAndFeel->GetMetric(nsILookAndFeel::eMetric_MenuBarDrag, metricResult);
if (metricResult) {
sSystemMetrics->AppendElement(nsGkAtoms::menubar_drag);
}
rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_WindowsDefaultTheme, metricResult);
if (NS_SUCCEEDED(rv) && metricResult) {
sSystemMetrics->AppendElement(nsGkAtoms::windows_default_theme);

Просмотреть файл

@ -468,6 +468,13 @@ nsMediaFeatures::features[] = {
{ &nsGkAtoms::maemo_classic },
GetSystemMetric
},
{
&nsGkAtoms::_moz_menubar_drag,
nsMediaFeature::eMinMaxNotAllowed,
nsMediaFeature::eBoolInteger,
{ &nsGkAtoms::menubar_drag },
GetSystemMetric
},
// Null-mName terminator:
{

Просмотреть файл

@ -88,20 +88,28 @@ WindowDraggingElement.prototype = {
if (!this.shouldDrag(aEvent))
return;
#ifdef MOZ_WIDGET_GTK2
// On GTK, there is a toolkit-level function which handles
// window dragging, which must be used.
this._window.beginWindowMove(aEvent);
#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);
break;
case "mouseup":
this._draggingWindow = false;
this._window.removeEventListener("mousemove", this, false);
this._window.removeEventListener("mouseup", this, false);
if (this._draggingWindow) {
this._draggingWindow = false;
this._window.removeEventListener("mousemove", this, false);
this._window.removeEventListener("mouseup", this, false);
}
break;
}
#endif

Просмотреть файл

@ -67,6 +67,10 @@ progressmeter[mode="undetermined"] {
-moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter-undetermined");
}
toolbar[type="menubar"]:not(-moz-lwtheme):-moz-system-metric(menubar-drag) {
-moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag");
}
/* ::::: root elements ::::: */
window,

Просмотреть файл

@ -322,7 +322,11 @@ public:
/**
* If this metric != 0, show icons in buttons.
*/
eMetric_ImagesInButtons
eMetric_ImagesInButtons,
/**
* If this metric != 0, support window dragging on the menubar.
*/
eMetric_MenuBarDrag
} nsMetricID;
enum {

Просмотреть файл

@ -110,9 +110,10 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
#define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
#endif
// b7ec5f61-57df-4355-81f3-41ced52e8026
#define NS_IWIDGET_IID \
{ 0x271ac413, 0xa202, 0x46dc, \
{ 0xbc, 0xd5, 0x67, 0xa1, 0xfb, 0x58, 0x89, 0x7f } }
{ 0xb7ec5f61, 0x57df, 0x4355, \
{ 0x81, 0xf3, 0x41, 0xce, 0xd5, 0x2e, 0x80, 0x26 } }
/*
* Window shadow styles
@ -965,6 +966,11 @@ class nsIWidget : public nsISupports {
*/
NS_IMETHOD BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical) = 0;
/**
* Begin a window moving drag, based on the event passed in.
*/
NS_IMETHOD BeginMoveDrag(nsMouseEvent* aEvent) = 0;
enum Modifiers {
CAPS_LOCK = 0x01, // when CapsLock is active
NUM_LOCK = 0x02, // when NumLock is active

Просмотреть файл

@ -70,6 +70,7 @@ nscolor nsLookAndFeel::sComboBoxText = 0;
nscolor nsLookAndFeel::sComboBoxBackground = 0;
PRUnichar nsLookAndFeel::sInvisibleCharacter = PRUnichar('*');
float nsLookAndFeel::sCaretRatio = 0;
PRBool nsLookAndFeel::sMenuSupportsDrag = PR_FALSE;
//-------------------------------------------------------------------------
//
@ -631,6 +632,9 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricID aID, PRInt32 & aMetric)
case eMetric_ImagesInButtons:
aMetric = moz_gtk_images_in_buttons();
break;
case eMetric_MenuBarDrag:
aMetric = sMenuSupportsDrag;
break;
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
@ -797,6 +801,13 @@ nsLookAndFeel::InitLookAndFeel()
sMenuBarHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_SELECTED]);
}
// Some themes have a unified menu bar, and support window dragging on it
gboolean supports_menubar_drag = FALSE;
gtk_widget_style_get(menuBar,
"window-dragging", &supports_menubar_drag,
NULL);
sMenuSupportsDrag = supports_menubar_drag;
// GTK's guide to fancy odd row background colors:
// 1) Check if a theme explicitly defines an odd row color
// 2) If not, check if it defines an even row color, and darken it

Просмотреть файл

@ -78,6 +78,7 @@ protected:
static nscolor sComboBoxBackground;
static PRUnichar sInvisibleCharacter;
static float sCaretRatio;
static PRBool sMenuSupportsDrag;
static void InitLookAndFeel();
void InitWidget() {

Просмотреть файл

@ -6737,21 +6737,83 @@ nsWindow::GetThebesSurface()
return mThebesSurface;
}
// Code shared begin BeginMoveDrag and BeginResizeDrag
PRBool
nsWindow::GetDragInfo(nsMouseEvent* aMouseEvent,
GdkWindow** aWindow, gint* aButton,
gint* aRootX, gint* aRootY)
{
if (aMouseEvent->button != nsMouseEvent::eLeftButton) {
// we can only begin a move drag with the left mouse button
return PR_FALSE;
}
*aButton = 1;
// get the gdk window for this widget
GdkWindow* gdk_window = mGdkWindow;
if (!gdk_window) {
return PR_FALSE;
}
NS_ABORT_IF_FALSE(GDK_IS_WINDOW(gdk_window), "must really be window");
// find the top-level window
gdk_window = gdk_window_get_toplevel(gdk_window);
NS_ABORT_IF_FALSE(gdk_window,
"gdk_window_get_toplevel should not return null");
*aWindow = gdk_window;
if (!aMouseEvent->widget) {
return PR_FALSE;
}
// FIXME: It would be nice to have the widget position at the time
// of the event, but it's relatively unlikely that the widget has
// moved since the mousedown. (On the other hand, it's quite likely
// that the mouse has moved, which is why we use the mouse position
// from the event.)
nsIntPoint offset = aMouseEvent->widget->WidgetToScreenOffset();
*aRootX = aMouseEvent->refPoint.x + offset.x;
*aRootY = aMouseEvent->refPoint.y + offset.y;
return PR_TRUE;
}
NS_IMETHODIMP
nsWindow::BeginMoveDrag(nsMouseEvent* aEvent)
{
NS_ABORT_IF_FALSE(aEvent, "must have event");
NS_ABORT_IF_FALSE(aEvent->eventStructType == NS_MOUSE_EVENT,
"event must have correct struct type");
GdkWindow *gdk_window;
gint button, screenX, screenY;
if (!GetDragInfo(aEvent, &gdk_window, &button, &screenX, &screenY)) {
return NS_ERROR_FAILURE;
}
// tell the window manager to start the move
gdk_window_begin_move_drag(gdk_window, button, screenX, screenY,
aEvent->time);
return NS_OK;
}
NS_IMETHODIMP
nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical)
{
NS_ENSURE_ARG_POINTER(aEvent);
if (aEvent->eventStructType != NS_MOUSE_EVENT) {
// you can only begin a resize drag with a mouse event
return NS_ERROR_INVALID_ARG;
// you can only begin a resize drag with a mouse event
return NS_ERROR_INVALID_ARG;
}
nsMouseEvent* mouse_event = static_cast<nsMouseEvent*>(aEvent);
if (mouse_event->button != nsMouseEvent::eLeftButton) {
// you can only begin a resize drag with the left mouse button
return NS_ERROR_INVALID_ARG;
GdkWindow *gdk_window;
gint button, screenX, screenY;
if (!GetDragInfo(mouse_event, &gdk_window, &button, &screenX, &screenY)) {
return NS_ERROR_FAILURE;
}
// work out what GdkWindowEdge we're talking about
@ -6782,39 +6844,9 @@ nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVert
}
}
// get the gdk window for this widget
GdkWindow* gdk_window = mGdkWindow;
if (!GDK_IS_WINDOW(gdk_window)) {
return NS_ERROR_FAILURE;
}
// find the top-level window
gdk_window = gdk_window_get_toplevel(gdk_window);
if (!GDK_IS_WINDOW(gdk_window)) {
return NS_ERROR_FAILURE;
}
// get the current (default) display
GdkDisplay* display = gdk_display_get_default();
if (!GDK_IS_DISPLAY(display)) {
return NS_ERROR_FAILURE;
}
// get the current pointer position and button state
GdkScreen* screen = NULL;
gint screenX, screenY;
GdkModifierType mask;
gdk_display_get_pointer(display, &screen, &screenX, &screenY, &mask);
// we only support resizing with button 1
if (!(mask & GDK_BUTTON1_MASK)) {
return NS_ERROR_FAILURE;
}
// tell the window manager to start the resize
gdk_window_begin_resize_drag(gdk_window, window_edge, 1,
screenX, screenY, aEvent->time);
gdk_window_begin_resize_drag(gdk_window, window_edge, button,
screenX, screenY, aEvent->time);
return NS_OK;
}

Просмотреть файл

@ -302,7 +302,8 @@ public:
static guint32 sLastButtonPressTime;
static guint32 sLastButtonReleaseTime;
NS_IMETHOD BeginResizeDrag (nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical);
NS_IMETHOD BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical);
NS_IMETHOD BeginMoveDrag(nsMouseEvent* aEvent);
MozContainer* GetMozContainer() { return mContainer; }
GdkWindow* GetGdkWindow() { return mGdkWindow; }
@ -376,6 +377,9 @@ private:
PRBool DispatchCommandEvent(nsIAtom* aCommand);
void SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
PRBool aIntersectWithExisting);
PRBool GetDragInfo(nsMouseEvent* aMouseEvent,
GdkWindow** aWindow, gint* aButton,
gint* aRootX, gint* aRootY);
GtkWidget *mShell;
MozContainer *mContainer;

Просмотреть файл

@ -1041,6 +1041,12 @@ nsBaseWidget::BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 a
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBaseWidget::BeginMoveDrag(nsMouseEvent* aEvent)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//////////////////////////////////////////////////////////////
//

Просмотреть файл

@ -132,6 +132,7 @@ public:
virtual PRBool ShowsResizeIndicator(nsIntRect* aResizerRect);
virtual void FreeNativeData(void * data, PRUint32 aDataType) {}
NS_IMETHOD BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical);
NS_IMETHOD BeginMoveDrag(nsMouseEvent* aEvent);
virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD ResetInputState() { return NS_OK; }