Bug 303404. Crash when hitting escape in context menu for a menu item. r=dbaron, sr=neil

This commit is contained in:
aaronleventhal%moonset.net 2005-08-17 02:03:45 +00:00
Родитель 52277d9aec
Коммит 49f3d10eb4
13 изменённых файлов: 140 добавлений и 960 удалений

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

@ -1,790 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Ryner <bryner@brianryner.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsNativeThemeGTK.h"
#include "nsThemeConstants.h"
#include "nsDrawingSurfaceGTK.h"
#include "nsDeviceContextGTK.h"
#include "gtkdrawing.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
#include "nsIDocument.h"
#include "nsIContent.h"
#include "nsIEventStateManager.h"
#include "nsIViewManager.h"
#include "nsINameSpaceManager.h"
#include "nsILookAndFeel.h"
#include "nsIDeviceContext.h"
#include "nsTransform2D.h"
#include "nsIMenuFrame.h"
#include "nsIMenuParent.h"
#include "prlink.h"
#include <gdk/gdkprivate.h>
#include <gdk/gdkx.h>
NS_IMPL_ISUPPORTS2(nsNativeThemeGTK, nsITheme, nsIObserver)
static int gLastXError;
nsNativeThemeGTK::nsNativeThemeGTK()
{
if (moz_gtk_init() != MOZ_GTK_SUCCESS) {
memset(mDisabledWidgetTypes, 0xff, sizeof(mDisabledWidgetTypes));
return;
}
// We have to call moz_gtk_shutdown before the event loop stops running.
nsCOMPtr<nsIObserverService> obsServ =
do_GetService("@mozilla.org/observer-service;1");
obsServ->AddObserver(this, "quit-application", PR_FALSE);
mInputCheckedAtom = do_GetAtom("_moz-input-checked");
mInputAtom = do_GetAtom("input");
mCurPosAtom = do_GetAtom("curpos");
mMaxPosAtom = do_GetAtom("maxpos");
mMenuActiveAtom = do_GetAtom("_moz-menuactive");
memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes));
memset(mSafeWidgetStates, 0, sizeof(mSafeWidgetStates));
#ifdef MOZ_WIDGET_GTK
// Look up the symbol for gtk_style_get_prop_experimental
PRLibrary* gtkLibrary;
PRFuncPtr stylePropFunc = PR_FindFunctionSymbolAndLibrary("gtk_style_get_prop_experimental", &gtkLibrary);
if (stylePropFunc) {
moz_gtk_enable_style_props((style_prop_t) stylePropFunc);
PR_UnloadLibrary(gtkLibrary);
}
#endif
}
nsNativeThemeGTK::~nsNativeThemeGTK() {
}
NS_IMETHODIMP
nsNativeThemeGTK::Observe(nsISupports *aSubject, const char *aTopic,
const PRUnichar *aData)
{
if (!nsCRT::strcmp(aTopic, "quit-application")) {
moz_gtk_shutdown();
} else {
NS_NOTREACHED("unexpected topic");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
void
nsNativeThemeGTK::RefreshWidgetWindow(nsIFrame* aFrame)
{
nsIPresShell *shell = GetPresShell(aFrame);
if (!shell)
return;
nsIViewManager* vm = shell->GetViewManager();
if (!vm)
return;
vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
}
static PRBool IsWidgetTypeDisabled(PRUint8* aDisabledVector, PRUint8 aWidgetType) {
return aDisabledVector[aWidgetType >> 3] & (1 << (aWidgetType & 7));
}
static void SetWidgetTypeDisabled(PRUint8* aDisabledVector, PRUint8 aWidgetType) {
aDisabledVector[aWidgetType >> 3] |= (1 << (aWidgetType & 7));
}
static inline PRUint16
GetWidgetStateKey(PRUint8 aWidgetType, GtkWidgetState *aWidgetState)
{
return (aWidgetState->active |
aWidgetState->focused << 1 |
aWidgetState->inHover << 2 |
aWidgetState->disabled << 3 |
aWidgetState->isDefault << 4 |
aWidgetType << 5);
}
static PRBool IsWidgetStateSafe(PRUint8* aSafeVector,
PRUint8 aWidgetType,
GtkWidgetState *aWidgetState)
{
PRUint8 key = GetWidgetStateKey(aWidgetType, aWidgetState);
return aSafeVector[key >> 3] & (1 << (key & 7));
}
static void SetWidgetStateSafe(PRUint8 *aSafeVector,
PRUint8 aWidgetType,
GtkWidgetState *aWidgetState)
{
PRUint8 key = GetWidgetStateKey(aWidgetType, aWidgetState);
aSafeVector[key >> 3] |= (1 << (key & 7));
}
PRBool
nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
GtkThemeWidgetType& aGtkWidgetType,
GtkWidgetState* aState,
gint* aWidgetFlags)
{
if (aState) {
if (!aFrame) {
// reset the entire struct to zero
memset(aState, 0, sizeof(GtkWidgetState));
} else {
// for dropdown textfields, look at the parent frame (textbox or menulist)
if (aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD)
aFrame = aFrame->GetParent();
// For XUL checkboxes and radio buttons, the state of the parent
// determines our state.
if (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO ||
aWidgetType == NS_THEME_CHECKBOX_LABEL ||
aWidgetType == NS_THEME_RADIO_LABEL) {
if (aWidgetFlags) {
nsIAtom* atom = nsnull;
if (aFrame) {
nsIContent* content = aFrame->GetContent();
if (content->IsContentOfType(nsIContent::eXUL)) {
aFrame = aFrame->GetParent();
if (aWidgetType == NS_THEME_CHECKBOX_LABEL ||
aWidgetType == NS_THEME_RADIO_LABEL)
aFrame = aFrame->GetParent();
}
else if (content->Tag() == mInputAtom)
atom = mInputCheckedAtom;
}
if (!atom)
atom = (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_CHECKBOX_LABEL) ? mCheckedAtom : mSelectedAtom;
*aWidgetFlags = CheckBooleanAttr(aFrame, atom);
}
}
PRInt32 eventState = GetContentState(aFrame, aWidgetType);
aState->disabled = IsDisabled(aFrame);
aState->active = (eventState & NS_EVENT_STATE_ACTIVE) == NS_EVENT_STATE_ACTIVE;
aState->focused = (eventState & NS_EVENT_STATE_FOCUS) == NS_EVENT_STATE_FOCUS;
aState->inHover = (eventState & NS_EVENT_STATE_HOVER) == NS_EVENT_STATE_HOVER;
aState->isDefault = FALSE; // XXX fix me
aState->canDefault = FALSE; // XXX fix me
// For these widget types, some element (either a child or parent)
// actually has element focus, so we check the focused attribute
// to see whether to draw in the focused state.
if (aWidgetType == NS_THEME_TEXTFIELD ||
aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD ||
aWidgetType == NS_THEME_RADIO_CONTAINER ||
aWidgetType == NS_THEME_RADIO_LABEL ||
aWidgetType == NS_THEME_RADIO) {
aState->focused = IsFocused(aFrame);
}
if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL ||
aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) {
// for scrollbars we need to go up two to go from the thumb to
// the slider to the actual scrollbar object
nsIFrame *tmpFrame = aFrame->GetParent()->GetParent();
aState->curpos = CheckIntAttr(tmpFrame, mCurPosAtom);
aState->maxpos = CheckIntAttr(tmpFrame, mMaxPosAtom);
}
// menu item state is determined by the attribute "_moz-menuactive",
// and not by the mouse hovering (accessibility). as a special case,
// menus which are children of a menu bar are only marked as prelight
// if they are open, not on normal hover.
if (aWidgetType == NS_THEME_MENUITEM ||
aWidgetType == NS_THEME_CHECKMENUITEM ||
aWidgetType == NS_THEME_RADIOMENUITEM) {
PRBool isTopLevel = PR_FALSE;
nsIMenuFrame *menuFrame;
CallQueryInterface(aFrame, &menuFrame);
if (menuFrame) {
nsIMenuParent *menuParent;
menuFrame->GetMenuParent(&menuParent);
if (menuParent)
menuParent->IsMenuBar(isTopLevel);
}
if (isTopLevel) {
PRBool isOpen;
menuFrame->MenuIsOpen(isOpen);
aState->inHover = isOpen;
} else {
aState->inHover = CheckBooleanAttr(aFrame, mMenuActiveAtom);
}
aState->active = FALSE;
if (aWidgetType == NS_THEME_CHECKMENUITEM ||
aWidgetType == NS_THEME_RADIOMENUITEM) {
if (aFrame) {
nsAutoString attr;
nsresult res = aFrame->GetContent()->GetAttr(kNameSpaceID_None, mCheckedAtom, attr);
if (res == NS_CONTENT_ATTR_NO_VALUE ||
(res != NS_CONTENT_ATTR_NOT_THERE && attr.IsEmpty()))
*aWidgetFlags = FALSE;
else
*aWidgetFlags = attr.EqualsIgnoreCase("true");
} else {
*aWidgetFlags = FALSE;
}
}
}
}
}
switch (aWidgetType) {
case NS_THEME_BUTTON:
case NS_THEME_TOOLBAR_BUTTON:
case NS_THEME_TOOLBAR_DUAL_BUTTON:
if (aWidgetFlags)
*aWidgetFlags = (aWidgetType == NS_THEME_BUTTON) ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE;
aGtkWidgetType = MOZ_GTK_BUTTON;
break;
case NS_THEME_CHECKBOX:
case NS_THEME_RADIO:
aGtkWidgetType = (aWidgetType == NS_THEME_RADIO) ? MOZ_GTK_RADIOBUTTON : MOZ_GTK_CHECKBUTTON;
break;
case NS_THEME_SCROLLBAR_BUTTON_UP:
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
if (aWidgetFlags)
*aWidgetFlags = GtkArrowType(aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP);
aGtkWidgetType = MOZ_GTK_SCROLLBAR_BUTTON;
break;
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_VERTICAL;
break;
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL;
break;
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
break;
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
break;
case NS_THEME_TOOLBAR_GRIPPER:
aGtkWidgetType = MOZ_GTK_GRIPPER;
break;
case NS_THEME_TEXTFIELD:
case NS_THEME_DROPDOWN_TEXTFIELD:
aGtkWidgetType = MOZ_GTK_ENTRY;
break;
case NS_THEME_DROPDOWN:
aGtkWidgetType = MOZ_GTK_DROPDOWN;
break;
case NS_THEME_DROPDOWN_TEXT:
return PR_FALSE; // nothing to do, but prevents the bg from being drawn
case NS_THEME_DROPDOWN_BUTTON:
aGtkWidgetType = MOZ_GTK_DROPDOWN_ARROW;
break;
case NS_THEME_CHECKBOX_CONTAINER:
aGtkWidgetType = MOZ_GTK_CHECKBUTTON_CONTAINER;
break;
case NS_THEME_RADIO_CONTAINER:
aGtkWidgetType = MOZ_GTK_RADIOBUTTON_CONTAINER;
break;
case NS_THEME_CHECKBOX_LABEL:
aGtkWidgetType = MOZ_GTK_CHECKBUTTON_LABEL;
break;
case NS_THEME_RADIO_LABEL:
aGtkWidgetType = MOZ_GTK_RADIOBUTTON_LABEL;
break;
case NS_THEME_TOOLBAR:
aGtkWidgetType = MOZ_GTK_TOOLBAR;
break;
case NS_THEME_TOOLTIP:
aGtkWidgetType = MOZ_GTK_TOOLTIP;
break;
case NS_THEME_STATUSBAR_PANEL:
aGtkWidgetType = MOZ_GTK_FRAME;
break;
case NS_THEME_PROGRESSBAR:
case NS_THEME_PROGRESSBAR_VERTICAL:
aGtkWidgetType = MOZ_GTK_PROGRESSBAR;
break;
case NS_THEME_PROGRESSBAR_CHUNK:
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
aGtkWidgetType = MOZ_GTK_PROGRESS_CHUNK;
break;
case NS_THEME_TAB_PANELS:
aGtkWidgetType = MOZ_GTK_TABPANELS;
break;
case NS_THEME_TAB:
case NS_THEME_TAB_LEFT_EDGE:
case NS_THEME_TAB_RIGHT_EDGE:
{
if (aWidgetFlags) {
*aWidgetFlags = 0;
if (aWidgetType == NS_THEME_TAB &&
CheckBooleanAttr(aFrame, mSelectedAtom))
*aWidgetFlags |= MOZ_GTK_TAB_SELECTED;
else if (aWidgetType == NS_THEME_TAB_LEFT_EDGE)
*aWidgetFlags |= MOZ_GTK_TAB_BEFORE_SELECTED;
if (aFrame->GetContent()->HasAttr(kNameSpaceID_None, mFirstTabAtom))
*aWidgetFlags |= MOZ_GTK_TAB_FIRST;
}
aGtkWidgetType = MOZ_GTK_TAB;
}
break;
case NS_THEME_MENUBAR:
aGtkWidgetType = MOZ_GTK_MENUBAR;
break;
case NS_THEME_MENUPOPUP:
aGtkWidgetType = MOZ_GTK_MENUPOPUP;
break;
case NS_THEME_MENUITEM:
aGtkWidgetType = MOZ_GTK_MENUITEM;
break;
case NS_THEME_CHECKMENUITEM:
aGtkWidgetType = MOZ_GTK_CHECKMENUITEM;
break;
case NS_THEME_RADIOMENUITEM:
aGtkWidgetType = MOZ_GTK_RADIOMENUITEM;
break;
case NS_THEME_WINDOW:
case NS_THEME_DIALOG:
aGtkWidgetType = MOZ_GTK_WINDOW;
break;
default:
return PR_FALSE;
}
return PR_TRUE;
}
static int
NativeThemeErrorHandler(Display* dpy, XErrorEvent* error) {
gLastXError = error->error_code;
return 0;
}
NS_IMETHODIMP
nsNativeThemeGTK::DrawWidgetBackground(nsIRenderingContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
const nsRect& aRect,
const nsRect& aClipRect)
{
GtkWidgetState state;
GtkThemeWidgetType gtkWidgetType;
gint flags;
if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state,
&flags))
return NS_OK;
nsDrawingSurfaceGTK* surface;
aContext->GetDrawingSurface((nsIDrawingSurface**)&surface);
GdkWindow* window = (GdkWindow*) surface->GetDrawable();
nsTransform2D* transformMatrix;
aContext->GetCurrentTransform(transformMatrix);
nsRect tr(aRect);
transformMatrix->TransformCoord(&tr.x, &tr.y, &tr.width, &tr.height);
GdkRectangle gdk_rect = {tr.x, tr.y, tr.width, tr.height};
nsRect cr(aClipRect);
transformMatrix->TransformCoord(&cr.x, &cr.y, &cr.width, &cr.height);
GdkRectangle gdk_clip = {cr.x, cr.y, cr.width, cr.height};
NS_ASSERTION(!IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType),
"Trying to render an unsafe widget!");
PRBool safeState = IsWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state);
XErrorHandler oldHandler = nsnull;
if (!safeState) {
gLastXError = 0;
oldHandler = XSetErrorHandler(NativeThemeErrorHandler);
}
moz_gtk_widget_paint(gtkWidgetType, window, &gdk_rect, &gdk_clip, &state,
flags);
if (!safeState) {
gdk_flush();
XSetErrorHandler(oldHandler);
if (gLastXError) {
#ifdef DEBUG
printf("GTK theme failed for widget type %d, error was %d, state was "
"[active=%d,focused=%d,inHover=%d,disabled=%d]\n",
aWidgetType, gLastXError, state.active, state.focused,
state.inHover, state.disabled);
#endif
NS_WARNING("GTK theme failed; disabling unsafe widget");
SetWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType);
// force refresh of the window, because the widget was not
// successfully drawn it must be redrawn using the default look
RefreshWidgetWindow(aFrame);
} else {
SetWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
PRUint8 aWidgetType, nsMargin* aResult)
{
aResult->top = aResult->left = 0;
switch (aWidgetType) {
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
{
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
aResult->top = aResult->left = metrics.trough_border;
}
break;
case NS_THEME_TOOLBOX:
// gtk has no toolbox equivalent. So, although we map toolbox to
// gtk's 'toolbar' for purposes of painting the widget background,
// we don't use the toolbar border for toolbox.
break;
case NS_THEME_TOOLBAR_DUAL_BUTTON:
// TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw
// around the entire button + dropdown, and also an inner border if you're
// over the button part. But, we want the inner button to be right up
// against the edge of the outer button so that the borders overlap.
// To make this happen, we draw a button border for the outer button,
// but don't reserve any space for it.
break;
default:
{
GtkThemeWidgetType gtkWidgetType;
if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nsnull,
nsnull))
moz_gtk_get_widget_border(gtkWidgetType, &aResult->left,
&aResult->top);
}
}
aResult->right = aResult->left;
aResult->bottom = aResult->top;
return NS_OK;
}
PRBool
nsNativeThemeGTK::GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
nsMargin* aResult)
{
if (aWidgetType == NS_THEME_BUTTON_FOCUS ||
aWidgetType == NS_THEME_TOOLBAR_BUTTON ||
aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON) {
aResult->SizeTo(0, 0, 0, 0);
return PR_TRUE;
}
return PR_FALSE;
}
NS_IMETHODIMP
nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
nsSize* aResult, PRBool* aIsOverridable)
{
aResult->width = aResult->height = 0;
*aIsOverridable = PR_TRUE;
switch (aWidgetType) {
case NS_THEME_SCROLLBAR_BUTTON_UP:
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
{
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
aResult->width = metrics.slider_width;
aResult->height = metrics.stepper_size;
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
{
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
aResult->width = metrics.stepper_size;
aResult->height = metrics.slider_width;
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
{
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) {
aResult->width = metrics.slider_width;
aResult->height = metrics.min_slider_size;
} else {
aResult->width = metrics.min_slider_size;
aResult->height = metrics.slider_width;
}
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_DROPDOWN_BUTTON:
{
moz_gtk_get_dropdown_arrow_size(&aResult->width, &aResult->height);
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_CHECKBOX:
case NS_THEME_RADIO:
{
gint indicator_size, indicator_spacing;
if (aWidgetType == NS_THEME_CHECKBOX) {
moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
} else {
moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
}
// Include space for the indicator and the padding around it.
aResult->width = indicator_size + 3 * indicator_spacing;
aResult->height = indicator_size + 2 * indicator_spacing;
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
case NS_THEME_BUTTON:
case NS_THEME_TOOLBAR_BUTTON:
{
// Just include our border, and let the box code augment the size.
nsCOMPtr<nsIDeviceContext> dc;
aContext->GetDeviceContext(*getter_AddRefs(dc));
nsMargin border;
nsNativeThemeGTK::GetWidgetBorder(dc, aFrame, aWidgetType, &border);
aResult->width = border.left + border.right;
aResult->height = border.top + border.bottom;
}
break;
}
return NS_OK;
}
NS_IMETHODIMP
nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType,
nsIAtom* aAttribute, PRBool* aShouldRepaint)
{
// Some widget types just never change state.
if (aWidgetType == NS_THEME_TOOLBOX ||
aWidgetType == NS_THEME_TOOLBAR ||
aWidgetType == NS_THEME_STATUSBAR ||
aWidgetType == NS_THEME_STATUSBAR_PANEL ||
aWidgetType == NS_THEME_STATUSBAR_RESIZER_PANEL ||
aWidgetType == NS_THEME_PROGRESSBAR_CHUNK ||
aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL ||
aWidgetType == NS_THEME_PROGRESSBAR ||
aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL ||
aWidgetType == NS_THEME_MENUBAR ||
aWidgetType == NS_THEME_MENUPOPUP ||
aWidgetType == NS_THEME_TOOLTIP ||
aWidgetType == NS_THEME_WINDOW ||
aWidgetType == NS_THEME_DIALOG) {
*aShouldRepaint = PR_FALSE;
return NS_OK;
}
// XXXdwh Not sure what can really be done here. Can at least guess for
// specific widgets that they're highly unlikely to have certain states.
// For example, a toolbar doesn't care about any states.
if (!aAttribute) {
// Hover/focus/active changed. Always repaint.
*aShouldRepaint = PR_TRUE;
}
else {
// Check the attribute to see if it's relevant.
// disabled, checked, dlgtype, default, etc.
*aShouldRepaint = PR_FALSE;
if (aAttribute == mDisabledAtom || aAttribute == mCheckedAtom ||
aAttribute == mSelectedAtom || aAttribute == mFocusedAtom ||
aAttribute == mMenuActiveAtom)
*aShouldRepaint = PR_TRUE;
}
return NS_OK;
}
NS_IMETHODIMP
nsNativeThemeGTK::ThemeChanged()
{
nsDeviceContextGTK::ClearCachedSystemFonts();
memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes));
return NS_OK;
}
NS_IMETHODIMP_(PRBool)
nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
nsIFrame* aFrame,
PRUint8 aWidgetType)
{
if (aFrame) {
// For now don't support HTML.
if (aFrame->GetContent()->IsContentOfType(nsIContent::eHTML))
return PR_FALSE;
}
if (IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType))
return PR_FALSE;
switch (aWidgetType) {
case NS_THEME_BUTTON:
case NS_THEME_BUTTON_FOCUS:
case NS_THEME_RADIO:
case NS_THEME_CHECKBOX:
case NS_THEME_TOOLBOX: // N/A
case NS_THEME_TOOLBAR:
case NS_THEME_TOOLBAR_BUTTON:
case NS_THEME_TOOLBAR_DUAL_BUTTON: // so we can override the border with 0
// case NS_THEME_TOOLBAR_DUAL_BUTTON_DROPDOWN:
// case NS_THEME_TOOLBAR_SEPARATOR:
case NS_THEME_TOOLBAR_GRIPPER:
case NS_THEME_STATUSBAR:
case NS_THEME_STATUSBAR_PANEL:
// case NS_THEME_RESIZER: (n/a for gtk)
// case NS_THEME_LISTBOX:
// case NS_THEME_LISTBOX_LISTITEM:
// case NS_THEME_TREEVIEW:
// case NS_THEME_TREEVIEW_TREEITEM:
// case NS_THEME_TREEVIEW_TWISTY:
// case NS_THEME_TREEVIEW_LINE:
// case NS_THEME_TREEVIEW_HEADER:
// case NS_THEME_TREEVIEW_HEADER_CELL:
// case NS_THEME_TREEVIEW_HEADER_SORTARROW:
// case NS_THEME_TREEVIEW_TWISTY_OPEN:
case NS_THEME_PROGRESSBAR:
case NS_THEME_PROGRESSBAR_CHUNK:
case NS_THEME_PROGRESSBAR_VERTICAL:
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
case NS_THEME_TAB:
// case NS_THEME_TAB_PANEL:
case NS_THEME_TAB_LEFT_EDGE:
case NS_THEME_TAB_RIGHT_EDGE:
case NS_THEME_TAB_PANELS:
case NS_THEME_TOOLTIP:
// case NS_THEME_SPINNER:
// case NS_THEME_SPINNER_UP_BUTTON:
// case NS_THEME_SPINNER_DOWN_BUTTON:
// case NS_THEME_SCROLLBAR: (n/a for gtk)
case NS_THEME_SCROLLBAR_BUTTON_UP:
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
// case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL: (n/a for gtk)
// case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL: (n/a for gtk)
case NS_THEME_TEXTFIELD:
// case NS_THEME_TEXTFIELD_CARET:
case NS_THEME_DROPDOWN_BUTTON:
case NS_THEME_DROPDOWN_TEXTFIELD:
// case NS_THEME_SLIDER:
// case NS_THEME_SLIDER_THUMB:
// case NS_THEME_SLIDER_THUMB_START:
// case NS_THEME_SLIDER_THUMB_END:
// case NS_THEME_SLIDER_TICK:
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
#ifdef MOZ_WIDGET_GTK2
case NS_THEME_MENUBAR:
case NS_THEME_MENUPOPUP:
case NS_THEME_MENUITEM:
case NS_THEME_CHECKMENUITEM:
case NS_THEME_RADIOMENUITEM:
case NS_THEME_WINDOW:
case NS_THEME_DIALOG:
case NS_THEME_DROPDOWN:
case NS_THEME_DROPDOWN_TEXT:
#endif
return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
}
return PR_FALSE;
}
NS_IMETHODIMP_(PRBool)
nsNativeThemeGTK::WidgetIsContainer(PRUint8 aWidgetType)
{
// XXXdwh At some point flesh all of this out.
if (aWidgetType == NS_THEME_DROPDOWN_BUTTON ||
aWidgetType == NS_THEME_RADIO ||
aWidgetType == NS_THEME_CHECKBOX)
return PR_FALSE;
return PR_TRUE;
}

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

@ -38,9 +38,9 @@
#ifndef nsIMenuFrame_h___
#define nsIMenuFrame_h___
// {6A4CDE51-6C05-11d3-BB50-00104B7B7DEB}
// {2281EFC8-A8BA-4a73-8CF7-DB4EECA5EAEC}
#define NS_IMENUFRAME_IID \
{ 0x6a4cde51, 0x6c05, 0x11d3, { 0xbb, 0x50, 0x0, 0x10, 0x4b, 0x7b, 0x7d, 0xeb } }
{ 0x2281efc8, 0xa8ba, 0x4a73, { 0x8c, 0xf7, 0xdb, 0x4e, 0xec, 0xa5, 0xea, 0xec } };
class nsIMenuParent;
class nsIDOMElement;
@ -73,8 +73,8 @@ public:
NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag) = 0;
NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag) = 0;
NS_IMETHOD GetMenuParent(nsIMenuParent** aMenuParent) = 0;
NS_IMETHOD GetMenuChild(nsIFrame** aResult) = 0;
virtual nsIMenuParent *GetMenuParent() = 0;
virtual nsIFrame *GetMenuChild() = 0;
NS_IMETHOD GetRadioGroupName(nsString &aName) = 0;
NS_IMETHOD GetMenuType(nsMenuType &aType) = 0;

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

@ -40,9 +40,9 @@
#define nsIMenuParent_h___
// {D407BF61-3EFA-11d3-97FA-00400553EEF0}
// {81C0BF71-9F50-4f4d-8B6A-D6B233C100C2}
#define NS_IMENUPARENT_IID \
{ 0xd407bf61, 0x3efa, 0x11d3, { 0x97, 0xfa, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } }
{ 0x81c0bf71, 0x9f50, 0x4f4d, { 0x8b, 0x6a, 0xd6, 0xb2, 0x33, 0xc1, 0x0, 0xc2 } };
class nsIMenuFrame;
class nsIDOMKeyEvent;
@ -139,10 +139,10 @@ class nsIMenuParent : public nsISupports {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IMENUPARENT_IID)
NS_IMETHOD GetCurrentMenuItem(nsIMenuFrame** aMenuItem) = 0;
virtual nsIMenuFrame *GetCurrentMenuItem() = 0;
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem) = 0;
NS_IMETHOD GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult) = 0;
NS_IMETHOD GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult) = 0;
virtual nsIMenuFrame *GetNextMenuItem(nsIMenuFrame* aStart) = 0;
virtual nsIMenuFrame *GetPreviousMenuItem(nsIMenuFrame* aStart) = 0;
NS_IMETHOD SetActive(PRBool aActiveFlag) = 0;
NS_IMETHOD GetIsActive(PRBool& isActive) = 0;

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

@ -280,8 +280,7 @@ nsMenuBarFrame::ToggleMenuActiveState()
// Set the active menu to be the top left item (e.g., the File menu).
// We use an attribute called "menuactive" to track the current
// active menu.
nsIMenuFrame* firstFrame;
GetNextMenuItem(nsnull, &firstFrame);
nsIMenuFrame* firstFrame = GetNextMenuItem(nsnull);
if (firstFrame) {
firstFrame->SelectMenu(PR_TRUE);
@ -328,10 +327,11 @@ nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
if ( shortcutKey.Equals(Substring(&letter, &letter+1),
nsCaseInsensitiveStringComparator()) ) {
// We match!
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
if (menuFrame)
return menuFrame.get();
return nsnull;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame))) {
menuFrame = nsnull;
}
return menuFrame;
}
}
}
@ -405,11 +405,9 @@ nsMenuBarFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
if NS_DIRECTION_IS_INLINE(theDirection) {
nsIMenuFrame* nextItem;
if (theDirection == eNavigationDirection_End)
GetNextMenuItem(mCurrentMenu, &nextItem);
else GetPreviousMenuItem(mCurrentMenu, &nextItem);
nsIMenuFrame* nextItem = (theDirection == eNavigationDirection_End) ?
GetNextMenuItem(mCurrentMenu) :
GetPreviousMenuItem(mCurrentMenu);
SetCurrentMenuItem(nextItem);
if (nextItem) {
@ -430,8 +428,8 @@ nsMenuBarFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
return NS_OK;
}
NS_IMETHODIMP
nsMenuBarFrame::GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
/* virtual */ nsIMenuFrame*
nsMenuBarFrame::GetNextMenuItem(nsIMenuFrame* aStart)
{
nsIFrame* immediateParent = nsnull;
GetInsertionPoint(mPresContext->PresShell(), this, nsnull, &immediateParent);
@ -453,10 +451,10 @@ nsMenuBarFrame::GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
while (currFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = currFrame->GetNextSibling();
}
@ -467,22 +465,21 @@ nsMenuBarFrame::GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
while (currFrame && currFrame != startFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = currFrame->GetNextSibling();
}
// No luck. Just return our start value.
*aResult = aStart;
return NS_OK;
return aStart;
}
NS_IMETHODIMP
nsMenuBarFrame::GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
/* virtual */ nsIMenuFrame*
nsMenuBarFrame::GetPreviousMenuItem(nsIMenuFrame* aStart)
{
nsIFrame* immediateParent = nsnull;
GetInsertionPoint(mPresContext->PresShell(), this, nsnull, &immediateParent);
@ -505,10 +502,10 @@ nsMenuBarFrame::GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult
while (currFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = frames.GetPrevSiblingFor(currFrame);
}
@ -519,25 +516,23 @@ nsMenuBarFrame::GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult
while (currFrame && currFrame != startFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = frames.GetPrevSiblingFor(currFrame);
}
// No luck. Just return our start value.
*aResult = aStart;
return NS_OK;
return aStart;
}
NS_IMETHODIMP nsMenuBarFrame::GetCurrentMenuItem(nsIMenuFrame** aResult)
/* virtual */ nsIMenuFrame*
nsMenuBarFrame::GetCurrentMenuItem()
{
*aResult = mCurrentMenu;
NS_IF_ADDREF(*aResult);
return NS_OK;
return mCurrentMenu;
}

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

@ -68,10 +68,10 @@ public:
NS_DECL_ISUPPORTS
// nsIMenuParentInterface
NS_IMETHOD GetCurrentMenuItem(nsIMenuFrame** aResult);
virtual nsIMenuFrame* GetCurrentMenuItem();
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem);
NS_IMETHOD GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult);
NS_IMETHOD GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult);
virtual nsIMenuFrame* GetNextMenuItem(nsIMenuFrame* aStart);
virtual nsIMenuFrame* GetPreviousMenuItem(nsIMenuFrame* aStart);
NS_IMETHOD SetActive(PRBool aActiveFlag);
NS_IMETHOD GetIsActive(PRBool& isActive) { isActive = IsActive(); return NS_OK; };
NS_IMETHOD IsMenuBar(PRBool& isMenuBar) { isMenuBar = PR_TRUE; return NS_OK; };

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

@ -69,11 +69,10 @@ nsMenuDismissalListener::MouseDown(nsIDOMEvent* aMouseEvent)
return NS_OK;
}
void
nsMenuDismissalListener::GetCurrentMenuParent(nsIMenuParent** aMenuParent)
nsIMenuParent*
nsMenuDismissalListener::GetCurrentMenuParent()
{
*aMenuParent = mMenuParent;
NS_IF_ADDREF(*aMenuParent);
return mMenuParent;
}
void
@ -149,9 +148,13 @@ nsMenuDismissalListener::GetSubmenuWidgetChain(nsISupportsArray **_retval)
// move up the chain
nsIFrame* currAsFrame = nsnull;
if ( NS_SUCCEEDED(CallQueryInterface(curr, &currAsFrame)) ) {
nsCOMPtr<nsIMenuFrame> menuFrame ( do_QueryInterface(currAsFrame->GetParent()) );
nsIMenuFrame *menuFrame = nsnull;
nsIFrame *parentFrame = currAsFrame->GetParent();
if (parentFrame) {
CallQueryInterface(parentFrame, &menuFrame);
}
if ( menuFrame ) {
menuFrame->GetMenuParent ( &curr ); // Advance to next parent
curr = menuFrame->GetMenuParent (); // Advance to next parent
}
else {
// we are a menuParent but not a menuFrame. This is probably the case

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

@ -77,7 +77,7 @@ public:
NS_IMETHOD EnableListener(PRBool aEnabled);
void SetCurrentMenuParent(nsIMenuParent* aMenuParent);
void GetCurrentMenuParent(nsIMenuParent** aMenuParent);
nsIMenuParent* GetCurrentMenuParent();
NS_IMETHOD Unregister();

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

@ -335,8 +335,7 @@ nsMenuFrame::Destroy(nsPresContext* aPresContext)
{
// are we our menu parent's current menu item?
if (mMenuParent) {
nsIMenuFrame *curItem = nsnull;
mMenuParent->GetCurrentMenuItem(&curItem);
nsIMenuFrame *curItem = mMenuParent->GetCurrentMenuItem();
if (curItem == this) {
// yes; tell it that we're going away
mMenuParent->SetCurrentMenuItem(nsnull);
@ -1261,9 +1260,7 @@ nsMenuFrame::SelectFirstItem()
nsIFrame* frame = mPopupFrames.FirstChild();
if (frame) {
nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
nsIMenuFrame* result;
popup->GetNextMenuItem(nsnull, &result);
popup->SetCurrentMenuItem(result);
popup->SetCurrentMenuItem(popup->GetNextMenuItem(nsnull));
}
return NS_OK;
@ -1955,8 +1952,7 @@ nsMenuFrame::GetActiveChild(nsIDOMElement** aResult)
if (!frame)
return NS_ERROR_FAILURE;
nsIMenuFrame* menuFrame;
menuPopup->GetCurrentMenuItem(&menuFrame);
nsIMenuFrame* menuFrame = menuPopup->GetCurrentMenuItem();
if (!menuFrame) {
*aResult = nsnull;
@ -1992,9 +1988,10 @@ nsMenuFrame::SetActiveChild(nsIDOMElement* aChild)
mPresContext->PresShell()->GetPrimaryFrameFor(child, &kid);
if (!kid)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(kid));
if (!menuFrame)
return NS_ERROR_FAILURE;
nsIMenuFrame *menuFrame;
nsresult rv = CallQueryInterface(kid, &menuFrame);
if (NS_FAILED(rv))
return rv;
menuPopup->SetCurrentMenuItem(menuFrame);
return NS_OK;
}

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

@ -150,8 +150,8 @@ public:
NS_IMETHOD SetParent(const nsIFrame* aParent);
NS_IMETHOD GetMenuParent(nsIMenuParent** aResult) { *aResult = mMenuParent; return NS_OK; };
NS_IMETHOD GetMenuChild(nsIFrame** aResult) { *aResult = mPopupFrames.FirstChild(); return NS_OK; }
virtual nsIMenuParent *GetMenuParent() { return mMenuParent; };
virtual nsIFrame *GetMenuChild() { return mPopupFrames.FirstChild(); }
NS_IMETHOD GetRadioGroupName(nsString &aName) { aName = mGroupName; return NS_OK; };
NS_IMETHOD GetMenuType(nsMenuType &aType) { aType = mType; return NS_OK; };
NS_IMETHOD MarkChildrenStyleChange();

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

@ -186,7 +186,10 @@ nsMenuListener::KeyPress(nsIDOMEvent* aKeyEvent)
}
else if (theChar == NS_VK_ESCAPE) {
// Close one level.
// Prevents us from getting destroyed by Escape(), we need to return to ourselves
NS_ADDREF_THIS();
mMenuParent->Escape(handled);
NS_RELEASE_THIS();
if (!handled)
mMenuParent->DismissChain();
}

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

@ -1130,8 +1130,8 @@ static void GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame*
aShell->FrameConstructor()->GetInsertionPoint(aFrame, child, aResult);
}
NS_IMETHODIMP
nsMenuPopupFrame::GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
/* virtual */ nsIMenuFrame*
nsMenuPopupFrame::GetNextMenuItem(nsIMenuFrame* aStart)
{
nsIFrame* immediateParent = nsnull;
GetInsertionPoint(mPresContext->PresShell(), this, nsnull, &immediateParent);
@ -1153,10 +1153,10 @@ nsMenuPopupFrame::GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
while (currFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = currFrame->GetNextSibling();
}
@ -1167,22 +1167,21 @@ nsMenuPopupFrame::GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
while (currFrame && currFrame != startFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = currFrame->GetNextSibling();
}
// No luck. Just return our start value.
*aResult = aStart;
return NS_OK;
return aStart;
}
NS_IMETHODIMP
nsMenuPopupFrame::GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult)
/* virtual */ nsIMenuFrame*
nsMenuPopupFrame::GetPreviousMenuItem(nsIMenuFrame* aStart)
{
nsIFrame* immediateParent = nsnull;
GetInsertionPoint(mPresContext->PresShell(), this, nsnull, &immediateParent);
@ -1205,10 +1204,10 @@ nsMenuPopupFrame::GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResu
while (currFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = frames.GetPrevSiblingFor(currFrame);
}
@ -1219,25 +1218,23 @@ nsMenuPopupFrame::GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResu
while (currFrame && currFrame != startFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
*aResult = menuFrame.get();
NS_IF_ADDREF(*aResult);
return NS_OK;
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = frames.GetPrevSiblingFor(currFrame);
}
// No luck. Just return our start value.
*aResult = aStart;
return NS_OK;
return aStart;
}
NS_IMETHODIMP nsMenuPopupFrame::GetCurrentMenuItem(nsIMenuFrame** aResult)
/* virtual */ nsIMenuFrame*
nsMenuPopupFrame::GetCurrentMenuItem()
{
*aResult = mCurrentMenu;
NS_IF_ADDREF(*aResult);
return NS_OK;
return mCurrentMenu;
}
NS_IMETHODIMP nsMenuPopupFrame::ConsumeOutsideClicks(PRBool& aConsumeOutsideClicks)
@ -1359,8 +1356,7 @@ NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
{
// When a context menu is open, the current menu is locked, and no change
// to the menu is allowed.
nsCOMPtr<nsIMenuParent> contextMenu;
GetContextMenu(getter_AddRefs(contextMenu));
nsIMenuParent *contextMenu = GetContextMenu();
if (contextMenu)
return NS_OK;
@ -1409,8 +1405,7 @@ nsMenuPopupFrame::Escape(PRBool& aHandledFlag)
mIncrementalString.Truncate();
// See if we have a context menu open.
nsCOMPtr<nsIMenuParent> contextMenu;
GetContextMenu(getter_AddRefs(contextMenu));
nsIMenuParent* contextMenu = GetContextMenu();
if (contextMenu) {
// Get the context menu parent.
nsIFrame* childFrame;
@ -1450,8 +1445,7 @@ nsMenuPopupFrame::Enter()
mIncrementalString.Truncate();
// See if we have a context menu open.
nsCOMPtr<nsIMenuParent> contextMenu;
GetContextMenu(getter_AddRefs(contextMenu));
nsIMenuParent *contextMenu = GetContextMenu();
if (contextMenu)
return contextMenu->Enter();
@ -1462,24 +1456,19 @@ nsMenuPopupFrame::Enter()
return NS_OK;
}
void
nsMenuPopupFrame::GetContextMenu(nsIMenuParent** aContextMenu)
nsIMenuParent*
nsMenuPopupFrame::GetContextMenu()
{
*aContextMenu = nsnull;
if (mIsContextMenu || !nsMenuFrame::sDismissalListener)
return;
return nsnull;
nsCOMPtr<nsIMenuParent> menuParent;
nsMenuFrame::sDismissalListener->GetCurrentMenuParent(getter_AddRefs(menuParent));
nsIMenuParent *menuParent = nsMenuFrame::sDismissalListener->GetCurrentMenuParent();
if (!menuParent)
return;
return nsnull;
PRBool isContextMenu;
menuParent->GetIsContextMenu(isContextMenu);
if (isContextMenu) {
*aContextMenu = menuParent;
NS_ADDREF(*aContextMenu);
}
return isContextMenu ? menuParent : nsnull;
}
nsIMenuFrame*
@ -1582,25 +1571,25 @@ nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, PRBool& doActi
if (StringBeginsWith(textKey, incrementalString,
nsCaseInsensitiveStringComparator())) {
// mIncrementalString is a prefix of textKey
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
if (menuFrame) {
nsIMenuFrame* menuFrame;
if (NS_SUCCEEDED(CallQueryInterface(currFrame, &menuFrame))) {
// There is one match
matchCount++;
if (isShortcut) {
// There is one shortcut-key match
matchShortcutCount++;
// Record the matched item. If there is only one matched shortcut item, do it
frameShortcut = menuFrame.get();
frameShortcut = menuFrame;
}
if (!foundActive) {
// It's a first candidate item located before/on the current item
if (!frameBefore)
frameBefore = menuFrame.get();
frameBefore = menuFrame;
}
else {
// It's a first candidate item located after the current item
if (!frameAfter)
frameAfter = menuFrame.get();
frameAfter = menuFrame;
}
}
else
@ -1614,8 +1603,9 @@ nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, PRBool& doActi
if (stringLength > 1) {
// If there is more than one char typed, the current item has highest priority,
// otherwise the item next to current has highest priority
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
if (menuFrame && menuFrame.get() == frameBefore) {
nsIMenuFrame* menuFrame;
if (NS_SUCCEEDED(CallQueryInterface(currFrame, &menuFrame)) &&
menuFrame == frameBefore) {
return frameBefore;
}
}
@ -1681,8 +1671,7 @@ NS_IMETHODIMP
nsMenuPopupFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
{
// See if we have a context menu open.
nsCOMPtr<nsIMenuParent> contextMenu;
GetContextMenu(getter_AddRefs(contextMenu));
nsIMenuParent *contextMenu = GetContextMenu();
if (contextMenu)
return contextMenu->KeyboardNavigation(aKeyCode, aHandledFlag);
@ -1696,8 +1685,7 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
// We've been opened, but we haven't had anything selected.
// We can handle End, but our parent handles Start.
if (theDirection == eNavigationDirection_End) {
nsIMenuFrame* nextItem;
GetNextMenuItem(nsnull, &nextItem);
nsIMenuFrame* nextItem = GetNextMenuItem(nsnull);
if (nextItem) {
aHandledFlag = PR_TRUE;
SetCurrentMenuItem(nextItem);
@ -1737,13 +1725,13 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
nsIMenuFrame* nextItem;
if (theDirection == eNavigationDirection_Before)
GetPreviousMenuItem(mCurrentMenu, &nextItem);
nextItem = GetPreviousMenuItem(mCurrentMenu);
else if (theDirection == eNavigationDirection_After)
GetNextMenuItem(mCurrentMenu, &nextItem);
nextItem = GetNextMenuItem(mCurrentMenu);
else if (theDirection == eNavigationDirection_First)
GetNextMenuItem(nsnull, &nextItem);
nextItem = GetNextMenuItem(nsnull);
else
GetPreviousMenuItem(nsnull, &nextItem);
nextItem = GetPreviousMenuItem(nsnull);
if (nextItem) {
aHandledFlag = PR_TRUE;
@ -1771,11 +1759,7 @@ nsMenuPopupFrame::GetParentPopup(nsIMenuParent** aMenuParent)
if (frame) {
nsIFrame* grandparent = frame->GetParent();
if (grandparent ) {
nsCOMPtr<nsIMenuParent> menuParent = do_QueryInterface(grandparent);
if (menuParent) {
*aMenuParent = menuParent.get();
NS_ADDREF(*aMenuParent);
}
CallQueryInterface(grandparent, aMenuParent);
}
}
return NS_OK;
@ -1795,8 +1779,8 @@ nsMenuPopupFrame::HideChain()
nsIFrame* frame = GetParent();
if (frame) {
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(frame);
if (!menuFrame) {
nsIMenuFrame* menuFrame;
if (NS_FAILED(CallQueryInterface(frame, &menuFrame))) {
nsIPopupSetFrame* popupSetFrame = GetPopupSetFrame(mPresContext);
if (popupSetFrame)
// Hide the popup.
@ -1808,8 +1792,7 @@ nsMenuPopupFrame::HideChain()
menuFrame->SelectMenu(PR_FALSE);
// Get the parent.
nsCOMPtr<nsIMenuParent> menuParent;
menuFrame->GetMenuParent(getter_AddRefs(menuParent));
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
if (menuParent)
menuParent->HideChain();
}
@ -1852,8 +1835,7 @@ nsMenuPopupFrame::DismissChain()
menuFrame->OpenMenu(PR_FALSE);
// Get the parent.
nsIMenuParent* menuParent;
menuFrame->GetMenuParent(&menuParent);
nsIMenuParent* menuParent = menuFrame->GetMenuParent();
if (menuParent)
menuParent->DismissChain();
}
@ -2055,26 +2037,15 @@ nsMenuPopupFrame::Notify(nsITimer* aTimer)
// Walk through all of the sub-menus of this menu item until we get to the
// last sub-menu, then check if that sub-menu has an active menu item. If it
// does, then keep that menu open. If it doesn't, close menu and its sub-menus.
nsIFrame* child;
mTimerMenu->GetMenuChild(&child);
nsCOMPtr<nsIMenuFrame> currentMenuItem = nsnull;
nsCOMPtr<nsIMenuParent> menuParent = do_QueryInterface(child);
while (menuParent)
nsIFrame* child = mTimerMenu->GetMenuChild();
nsIMenuFrame *currentMenuItem = nsnull;
nsIMenuParent *menuParent;
while (child && NS_SUCCEEDED(CallQueryInterface(child, &menuParent)))
{
// get the selected menu item for this sub-menu
menuParent->GetCurrentMenuItem(getter_AddRefs(currentMenuItem));
menuParent = nsnull;
if (currentMenuItem)
{
// this sub-menu has a selected menu item - does that item open a sub-menu?
currentMenuItem->GetMenuChild(&child);
if (child) {
// the selected menu item opens a sub-menu - move down
// to that sub-menu and then go through the loop again
menuParent = do_QueryInterface(child);
}
} // if item is selected
currentMenuItem = menuParent->GetCurrentMenuItem();
// if this sub-menu has a selected menu item, does that item open a sub-menu?
child = currentMenuItem ? currentMenuItem->GetMenuChild() : nsnull;
} // while we're not at the last submenu
if (currentMenuItem)

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

@ -84,10 +84,10 @@ public:
NS_DECL_NSITIMERCALLBACK
// nsIMenuParentInterface
NS_IMETHOD GetCurrentMenuItem(nsIMenuFrame** aResult);
virtual nsIMenuFrame* GetCurrentMenuItem();
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem);
NS_IMETHOD GetNextMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult);
NS_IMETHOD GetPreviousMenuItem(nsIMenuFrame* aStart, nsIMenuFrame** aResult);
virtual nsIMenuFrame* GetNextMenuItem(nsIMenuFrame* aStart);
virtual nsIMenuFrame* GetPreviousMenuItem(nsIMenuFrame* aStart);
NS_IMETHOD SetActive(PRBool aActiveFlag) { return NS_OK; }; // We don't care.
NS_IMETHOD GetIsActive(PRBool& isActive) { isActive = PR_FALSE; return NS_OK; };
NS_IMETHOD IsMenuBar(PRBool& isMenuBar) { isMenuBar = PR_FALSE; return NS_OK; };
@ -161,7 +161,7 @@ public:
PRBool IsValidItem(nsIContent* aContent);
PRBool IsDisabled(nsIContent* aContent);
void GetContextMenu(nsIMenuParent** aContextMenu);
nsIMenuParent* GetContextMenu();
NS_IMETHOD KillCloseTimer();

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

@ -177,8 +177,7 @@ nsPopupSetFrame::Destroy(nsPresContext* aPresContext)
if (mPopupList) {
// Try to hide any active popups
if (nsMenuFrame::sDismissalListener) {
nsCOMPtr<nsIMenuParent> menuParent;
nsMenuFrame::sDismissalListener->GetCurrentMenuParent(getter_AddRefs(menuParent));
nsIMenuParent *menuParent = nsMenuFrame::sDismissalListener->GetCurrentMenuParent();
nsIFrame* frame;
CallQueryInterface(menuParent, &frame);
// Rollup popups, but only if they're ours
@ -419,12 +418,13 @@ nsPopupSetFrame::HidePopup(nsIFrame* aPopup)
mPresContext->PresShell()->GetPrimaryFrameFor(entry->mElementContent,
&popupFrame);
if (popupFrame) {
nsCOMPtr<nsIMenuParent> menuParent(do_QueryInterface(popupFrame));
if (menuParent)
nsIMenuParent *menuParent;
if (NS_SUCCEEDED(CallQueryInterface(popupFrame, &menuParent))) {
menuParent->HideChain();
}
}
}
}
return NS_OK;
}
@ -450,12 +450,13 @@ nsPopupSetFrame::DestroyPopup(nsIFrame* aPopup, PRBool aDestroyEntireChain)
mPresContext->PresShell()->GetPrimaryFrameFor(entry->mElementContent,
&popupFrame);
if (popupFrame) {
nsCOMPtr<nsIMenuParent> menuParent(do_QueryInterface(popupFrame));
if (menuParent)
nsIMenuParent *menuParent;
if (NS_SUCCEEDED(CallQueryInterface(popupFrame, &menuParent))) {
menuParent->DismissChain();
}
}
}
}
// clear things out for next time
entry->mCreateHandlerSucceeded = PR_FALSE;