michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsNativeThemeGTK.h" michael@0: #include "nsThemeConstants.h" michael@0: #include "gtkdrawing.h" michael@0: michael@0: #include "nsIObserverService.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsIContent.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsGfxCIID.h" michael@0: #include "nsTransform2D.h" michael@0: #include "nsMenuFrame.h" michael@0: #include "prlink.h" michael@0: #include "nsIDOMHTMLInputElement.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "nsGkAtoms.h" michael@0: michael@0: #include "mozilla/EventStates.h" michael@0: #include "mozilla/Services.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "gfxContext.h" michael@0: #include "gfxPlatformGtk.h" michael@0: #include "gfxGdkNativeRenderer.h" michael@0: #include michael@0: michael@0: using namespace mozilla; michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeGTK, nsNativeTheme, nsITheme, michael@0: nsIObserver) michael@0: michael@0: static int gLastGdkError; michael@0: michael@0: nsNativeThemeGTK::nsNativeThemeGTK() michael@0: { michael@0: if (moz_gtk_init() != MOZ_GTK_SUCCESS) { michael@0: memset(mDisabledWidgetTypes, 0xff, sizeof(mDisabledWidgetTypes)); michael@0: return; michael@0: } michael@0: michael@0: // We have to call moz_gtk_shutdown before the event loop stops running. michael@0: nsCOMPtr obsServ = michael@0: mozilla::services::GetObserverService(); michael@0: obsServ->AddObserver(this, "xpcom-shutdown", false); michael@0: michael@0: memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes)); michael@0: memset(mSafeWidgetStates, 0, sizeof(mSafeWidgetStates)); michael@0: } michael@0: michael@0: nsNativeThemeGTK::~nsNativeThemeGTK() { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeGTK::Observe(nsISupports *aSubject, const char *aTopic, michael@0: const char16_t *aData) michael@0: { michael@0: if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) { michael@0: moz_gtk_shutdown(); michael@0: } else { michael@0: NS_NOTREACHED("unexpected topic"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsNativeThemeGTK::RefreshWidgetWindow(nsIFrame* aFrame) michael@0: { michael@0: nsIPresShell *shell = GetPresShell(aFrame); michael@0: if (!shell) michael@0: return; michael@0: michael@0: nsViewManager* vm = shell->GetViewManager(); michael@0: if (!vm) michael@0: return; michael@0: michael@0: vm->InvalidateAllViews(); michael@0: } michael@0: michael@0: static bool IsFrameContentNodeInNamespace(nsIFrame *aFrame, uint32_t aNamespace) michael@0: { michael@0: nsIContent *content = aFrame ? aFrame->GetContent() : nullptr; michael@0: if (!content) michael@0: return false; michael@0: return content->IsInNamespace(aNamespace); michael@0: } michael@0: michael@0: static bool IsWidgetTypeDisabled(uint8_t* aDisabledVector, uint8_t aWidgetType) { michael@0: return (aDisabledVector[aWidgetType >> 3] & (1 << (aWidgetType & 7))) != 0; michael@0: } michael@0: michael@0: static void SetWidgetTypeDisabled(uint8_t* aDisabledVector, uint8_t aWidgetType) { michael@0: aDisabledVector[aWidgetType >> 3] |= (1 << (aWidgetType & 7)); michael@0: } michael@0: michael@0: static inline uint16_t michael@0: GetWidgetStateKey(uint8_t aWidgetType, GtkWidgetState *aWidgetState) michael@0: { michael@0: return (aWidgetState->active | michael@0: aWidgetState->focused << 1 | michael@0: aWidgetState->inHover << 2 | michael@0: aWidgetState->disabled << 3 | michael@0: aWidgetState->isDefault << 4 | michael@0: aWidgetType << 5); michael@0: } michael@0: michael@0: static bool IsWidgetStateSafe(uint8_t* aSafeVector, michael@0: uint8_t aWidgetType, michael@0: GtkWidgetState *aWidgetState) michael@0: { michael@0: uint8_t key = GetWidgetStateKey(aWidgetType, aWidgetState); michael@0: return (aSafeVector[key >> 3] & (1 << (key & 7))) != 0; michael@0: } michael@0: michael@0: static void SetWidgetStateSafe(uint8_t *aSafeVector, michael@0: uint8_t aWidgetType, michael@0: GtkWidgetState *aWidgetState) michael@0: { michael@0: uint8_t key = GetWidgetStateKey(aWidgetType, aWidgetState); michael@0: aSafeVector[key >> 3] |= (1 << (key & 7)); michael@0: } michael@0: michael@0: static GtkTextDirection GetTextDirection(nsIFrame* aFrame) michael@0: { michael@0: if (!aFrame) michael@0: return GTK_TEXT_DIR_NONE; michael@0: michael@0: switch (aFrame->StyleVisibility()->mDirection) { michael@0: case NS_STYLE_DIRECTION_RTL: michael@0: return GTK_TEXT_DIR_RTL; michael@0: case NS_STYLE_DIRECTION_LTR: michael@0: return GTK_TEXT_DIR_LTR; michael@0: } michael@0: michael@0: return GTK_TEXT_DIR_NONE; michael@0: } michael@0: michael@0: // Returns positive for negative margins (otherwise 0). michael@0: gint michael@0: nsNativeThemeGTK::GetTabMarginPixels(nsIFrame* aFrame) michael@0: { michael@0: nscoord margin = michael@0: IsBottomTab(aFrame) ? aFrame->GetUsedMargin().top michael@0: : aFrame->GetUsedMargin().bottom; michael@0: michael@0: return std::min(MOZ_GTK_TAB_MARGIN_MASK, michael@0: std::max(0, michael@0: aFrame->PresContext()->AppUnitsToDevPixels(-margin))); michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeGTK::GetGtkWidgetAndState(uint8_t aWidgetType, nsIFrame* aFrame, michael@0: GtkThemeWidgetType& aGtkWidgetType, michael@0: GtkWidgetState* aState, michael@0: gint* aWidgetFlags) michael@0: { michael@0: if (aState) { michael@0: if (!aFrame) { michael@0: // reset the entire struct to zero michael@0: memset(aState, 0, sizeof(GtkWidgetState)); michael@0: } else { michael@0: michael@0: // For XUL checkboxes and radio buttons, the state of the parent michael@0: // determines our state. michael@0: nsIFrame *stateFrame = aFrame; michael@0: if (aFrame && ((aWidgetFlags && (aWidgetType == NS_THEME_CHECKBOX || michael@0: aWidgetType == NS_THEME_RADIO)) || michael@0: aWidgetType == NS_THEME_CHECKBOX_LABEL || michael@0: aWidgetType == NS_THEME_RADIO_LABEL)) { michael@0: michael@0: nsIAtom* atom = nullptr; michael@0: if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) { michael@0: if (aWidgetType == NS_THEME_CHECKBOX_LABEL || michael@0: aWidgetType == NS_THEME_RADIO_LABEL) { michael@0: // Adjust stateFrame so GetContentState finds the correct state. michael@0: stateFrame = aFrame = aFrame->GetParent()->GetParent(); michael@0: } else { michael@0: // GetContentState knows to look one frame up for radio/checkbox michael@0: // widgets, so don't adjust stateFrame here. michael@0: aFrame = aFrame->GetParent(); michael@0: } michael@0: if (aWidgetFlags) { michael@0: if (!atom) { michael@0: atom = (aWidgetType == NS_THEME_CHECKBOX || michael@0: aWidgetType == NS_THEME_CHECKBOX_LABEL) ? nsGkAtoms::checked michael@0: : nsGkAtoms::selected; michael@0: } michael@0: *aWidgetFlags = CheckBooleanAttr(aFrame, atom); michael@0: } michael@0: } else { michael@0: if (aWidgetFlags) { michael@0: nsCOMPtr inputElt(do_QueryInterface(aFrame->GetContent())); michael@0: *aWidgetFlags = 0; michael@0: if (inputElt) { michael@0: bool isHTMLChecked; michael@0: inputElt->GetChecked(&isHTMLChecked); michael@0: if (isHTMLChecked) michael@0: *aWidgetFlags |= MOZ_GTK_WIDGET_CHECKED; michael@0: } michael@0: michael@0: if (GetIndeterminate(aFrame)) michael@0: *aWidgetFlags |= MOZ_GTK_WIDGET_INCONSISTENT; michael@0: } michael@0: } michael@0: } else if (aWidgetType == NS_THEME_TOOLBAR_BUTTON_DROPDOWN || michael@0: aWidgetType == NS_THEME_TREEVIEW_HEADER_SORTARROW || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_NEXT || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_UP || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_DOWN) { michael@0: // The state of an arrow comes from its parent. michael@0: stateFrame = aFrame = aFrame->GetParent(); michael@0: } michael@0: michael@0: EventStates eventState = GetContentState(stateFrame, aWidgetType); michael@0: michael@0: aState->disabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame); michael@0: aState->active = eventState.HasState(NS_EVENT_STATE_ACTIVE); michael@0: aState->focused = eventState.HasState(NS_EVENT_STATE_FOCUS); michael@0: aState->inHover = eventState.HasState(NS_EVENT_STATE_HOVER); michael@0: aState->isDefault = IsDefaultButton(aFrame); michael@0: aState->canDefault = FALSE; // XXX fix me michael@0: aState->depressed = FALSE; michael@0: michael@0: if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) { michael@0: // For these widget types, some element (either a child or parent) michael@0: // actually has element focus, so we check the focused attribute michael@0: // to see whether to draw in the focused state. michael@0: if (aWidgetType == NS_THEME_NUMBER_INPUT || michael@0: aWidgetType == NS_THEME_TEXTFIELD || michael@0: aWidgetType == NS_THEME_TEXTFIELD_MULTILINE || michael@0: aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD || michael@0: aWidgetType == NS_THEME_SPINNER_TEXTFIELD || michael@0: aWidgetType == NS_THEME_RADIO_CONTAINER || michael@0: aWidgetType == NS_THEME_RADIO_LABEL) { michael@0: aState->focused = IsFocused(aFrame); michael@0: } else if (aWidgetType == NS_THEME_RADIO || michael@0: aWidgetType == NS_THEME_CHECKBOX) { michael@0: // In XUL, checkboxes and radios shouldn't have focus rings, their labels do michael@0: aState->focused = FALSE; michael@0: } michael@0: michael@0: if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL || michael@0: aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) { michael@0: // for scrollbars we need to go up two to go from the thumb to michael@0: // the slider to the actual scrollbar object michael@0: nsIFrame *tmpFrame = aFrame->GetParent()->GetParent(); michael@0: michael@0: aState->curpos = CheckIntAttr(tmpFrame, nsGkAtoms::curpos, 0); michael@0: aState->maxpos = CheckIntAttr(tmpFrame, nsGkAtoms::maxpos, 100); michael@0: } michael@0: michael@0: if (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT) { michael@0: // set the state to disabled when the scrollbar is scrolled to michael@0: // the beginning or the end, depending on the button type. michael@0: int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0); michael@0: int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100); michael@0: if ((curpos == 0 && (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT)) || michael@0: (curpos == maxpos && michael@0: (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT))) michael@0: aState->disabled = true; michael@0: michael@0: // In order to simulate native GTK scrollbar click behavior, michael@0: // we set the active attribute on the element to true if it's michael@0: // pressed with any mouse button. michael@0: // This allows us to show that it's active without setting :active michael@0: else if (CheckBooleanAttr(aFrame, nsGkAtoms::active)) michael@0: aState->active = true; michael@0: michael@0: if (aWidgetFlags) { michael@0: *aWidgetFlags = GetScrollbarButtonType(aFrame); michael@0: if (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP < 2) michael@0: *aWidgetFlags |= MOZ_GTK_STEPPER_VERTICAL; michael@0: } michael@0: } michael@0: michael@0: // menu item state is determined by the attribute "_moz-menuactive", michael@0: // and not by the mouse hovering (accessibility). as a special case, michael@0: // menus which are children of a menu bar are only marked as prelight michael@0: // if they are open, not on normal hover. michael@0: michael@0: if (aWidgetType == NS_THEME_MENUITEM || michael@0: aWidgetType == NS_THEME_CHECKMENUITEM || michael@0: aWidgetType == NS_THEME_RADIOMENUITEM || michael@0: aWidgetType == NS_THEME_MENUSEPARATOR || michael@0: aWidgetType == NS_THEME_MENUARROW) { michael@0: bool isTopLevel = false; michael@0: nsMenuFrame *menuFrame = do_QueryFrame(aFrame); michael@0: if (menuFrame) { michael@0: isTopLevel = menuFrame->IsOnMenuBar(); michael@0: } michael@0: michael@0: if (isTopLevel) { michael@0: aState->inHover = menuFrame->IsOpen(); michael@0: *aWidgetFlags |= MOZ_TOPLEVEL_MENU_ITEM; michael@0: } else { michael@0: aState->inHover = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive); michael@0: *aWidgetFlags &= ~MOZ_TOPLEVEL_MENU_ITEM; michael@0: } michael@0: michael@0: aState->active = FALSE; michael@0: michael@0: if (aWidgetType == NS_THEME_CHECKMENUITEM || michael@0: aWidgetType == NS_THEME_RADIOMENUITEM) { michael@0: *aWidgetFlags = 0; michael@0: if (aFrame && aFrame->GetContent()) { michael@0: *aWidgetFlags = aFrame->GetContent()-> michael@0: AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked, michael@0: nsGkAtoms::_true, eIgnoreCase); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // A button with drop down menu open or an activated toggle button michael@0: // should always appear depressed. michael@0: if (aWidgetType == NS_THEME_BUTTON || michael@0: aWidgetType == NS_THEME_TOOLBAR_BUTTON || michael@0: aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON || michael@0: aWidgetType == NS_THEME_TOOLBAR_BUTTON_DROPDOWN || michael@0: aWidgetType == NS_THEME_DROPDOWN || michael@0: aWidgetType == NS_THEME_DROPDOWN_BUTTON) { michael@0: bool menuOpen = IsOpenButton(aFrame); michael@0: aState->depressed = IsCheckedButton(aFrame) || menuOpen; michael@0: // we must not highlight buttons with open drop down menus on hover. michael@0: aState->inHover = aState->inHover && !menuOpen; michael@0: } michael@0: michael@0: // When the input field of the drop down button has focus, some themes michael@0: // should draw focus for the drop down button as well. michael@0: if (aWidgetType == NS_THEME_DROPDOWN_BUTTON && aWidgetFlags) { michael@0: *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: switch (aWidgetType) { michael@0: case NS_THEME_BUTTON: michael@0: case NS_THEME_TOOLBAR_BUTTON: michael@0: case NS_THEME_TOOLBAR_DUAL_BUTTON: michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = (aWidgetType == NS_THEME_BUTTON) ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE; michael@0: aGtkWidgetType = MOZ_GTK_BUTTON; michael@0: break; michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: aGtkWidgetType = (aWidgetType == NS_THEME_RADIO) ? MOZ_GTK_RADIOBUTTON : MOZ_GTK_CHECKBUTTON; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: aGtkWidgetType = MOZ_GTK_SCROLLBAR_BUTTON; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_VERTICAL; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL; michael@0: break; michael@0: case NS_THEME_SPINNER: michael@0: aGtkWidgetType = MOZ_GTK_SPINBUTTON; michael@0: break; michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: aGtkWidgetType = MOZ_GTK_SPINBUTTON_UP; michael@0: break; michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: aGtkWidgetType = MOZ_GTK_SPINBUTTON_DOWN; michael@0: break; michael@0: case NS_THEME_SPINNER_TEXTFIELD: michael@0: aGtkWidgetType = MOZ_GTK_SPINBUTTON_ENTRY; michael@0: break; michael@0: case NS_THEME_RANGE: michael@0: { michael@0: if (IsRangeHorizontal(aFrame)) { michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_HORIZONTAL; michael@0: } else { michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_VERTICAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_VERTICAL; michael@0: } michael@0: break; michael@0: } michael@0: case NS_THEME_RANGE_THUMB: michael@0: { michael@0: if (IsRangeHorizontal(aFrame)) { michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_THUMB_HORIZONTAL; michael@0: } else { michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_VERTICAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_THUMB_VERTICAL; michael@0: } michael@0: break; michael@0: } michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_HORIZONTAL; michael@0: break; michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_THUMB_HORIZONTAL; michael@0: break; michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_VERTICAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_VERTICAL; michael@0: break; michael@0: case NS_THEME_TOOLBAR_SEPARATOR: michael@0: aGtkWidgetType = MOZ_GTK_TOOLBAR_SEPARATOR; michael@0: break; michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_ORIENTATION_VERTICAL; michael@0: aGtkWidgetType = MOZ_GTK_SCALE_THUMB_VERTICAL; michael@0: break; michael@0: case NS_THEME_TOOLBAR_GRIPPER: michael@0: aGtkWidgetType = MOZ_GTK_GRIPPER; michael@0: break; michael@0: case NS_THEME_RESIZER: michael@0: aGtkWidgetType = MOZ_GTK_RESIZER; michael@0: break; michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: aGtkWidgetType = MOZ_GTK_ENTRY; michael@0: break; michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_TREEVIEW: michael@0: aGtkWidgetType = MOZ_GTK_TREEVIEW; michael@0: break; michael@0: case NS_THEME_TREEVIEW_HEADER_CELL: michael@0: if (aWidgetFlags) { michael@0: // In this case, the flag denotes whether the header is the sorted one or not michael@0: if (GetTreeSortDirection(aFrame) == eTreeSortDirection_Natural) michael@0: *aWidgetFlags = false; michael@0: else michael@0: *aWidgetFlags = true; michael@0: } michael@0: aGtkWidgetType = MOZ_GTK_TREE_HEADER_CELL; michael@0: break; michael@0: case NS_THEME_TREEVIEW_HEADER_SORTARROW: michael@0: if (aWidgetFlags) { michael@0: switch (GetTreeSortDirection(aFrame)) { michael@0: case eTreeSortDirection_Ascending: michael@0: *aWidgetFlags = GTK_ARROW_DOWN; michael@0: break; michael@0: case eTreeSortDirection_Descending: michael@0: *aWidgetFlags = GTK_ARROW_UP; michael@0: break; michael@0: case eTreeSortDirection_Natural: michael@0: default: michael@0: /* This prevents the treecolums from getting smaller michael@0: * and wider when switching sort direction off and on michael@0: * */ michael@0: *aWidgetFlags = GTK_ARROW_NONE; michael@0: break; michael@0: } michael@0: } michael@0: aGtkWidgetType = MOZ_GTK_TREE_HEADER_SORTARROW; michael@0: break; michael@0: case NS_THEME_TREEVIEW_TWISTY: michael@0: aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER; michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_EXPANDER_COLLAPSED; michael@0: break; michael@0: case NS_THEME_TREEVIEW_TWISTY_OPEN: michael@0: aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER; michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = GTK_EXPANDER_EXPANDED; michael@0: break; michael@0: case NS_THEME_DROPDOWN: michael@0: aGtkWidgetType = MOZ_GTK_DROPDOWN; michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML); michael@0: break; michael@0: case NS_THEME_DROPDOWN_TEXT: michael@0: return false; // nothing to do, but prevents the bg from being drawn michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: michael@0: aGtkWidgetType = MOZ_GTK_DROPDOWN_ENTRY; michael@0: break; michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: aGtkWidgetType = MOZ_GTK_DROPDOWN_ARROW; michael@0: break; michael@0: case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: michael@0: case NS_THEME_BUTTON_ARROW_DOWN: michael@0: case NS_THEME_BUTTON_ARROW_UP: michael@0: case NS_THEME_BUTTON_ARROW_NEXT: michael@0: case NS_THEME_BUTTON_ARROW_PREVIOUS: michael@0: aGtkWidgetType = MOZ_GTK_TOOLBARBUTTON_ARROW; michael@0: if (aWidgetFlags) { michael@0: *aWidgetFlags = GTK_ARROW_DOWN; michael@0: michael@0: if (aWidgetType == NS_THEME_BUTTON_ARROW_UP) michael@0: *aWidgetFlags = GTK_ARROW_UP; michael@0: else if (aWidgetType == NS_THEME_BUTTON_ARROW_NEXT) michael@0: *aWidgetFlags = GTK_ARROW_RIGHT; michael@0: else if (aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS) michael@0: *aWidgetFlags = GTK_ARROW_LEFT; michael@0: } michael@0: break; michael@0: case NS_THEME_CHECKBOX_CONTAINER: michael@0: aGtkWidgetType = MOZ_GTK_CHECKBUTTON_CONTAINER; michael@0: break; michael@0: case NS_THEME_RADIO_CONTAINER: michael@0: aGtkWidgetType = MOZ_GTK_RADIOBUTTON_CONTAINER; michael@0: break; michael@0: case NS_THEME_CHECKBOX_LABEL: michael@0: aGtkWidgetType = MOZ_GTK_CHECKBUTTON_LABEL; michael@0: break; michael@0: case NS_THEME_RADIO_LABEL: michael@0: aGtkWidgetType = MOZ_GTK_RADIOBUTTON_LABEL; michael@0: break; michael@0: case NS_THEME_TOOLBAR: michael@0: aGtkWidgetType = MOZ_GTK_TOOLBAR; michael@0: break; michael@0: case NS_THEME_TOOLTIP: michael@0: aGtkWidgetType = MOZ_GTK_TOOLTIP; michael@0: break; michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: aGtkWidgetType = MOZ_GTK_FRAME; michael@0: break; michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: aGtkWidgetType = MOZ_GTK_PROGRESSBAR; michael@0: break; michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: { michael@0: nsIFrame* stateFrame = aFrame->GetParent(); michael@0: EventStates eventStates = GetContentState(stateFrame, aWidgetType); michael@0: michael@0: aGtkWidgetType = IsIndeterminateProgress(stateFrame, eventStates) michael@0: ? (stateFrame->StyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL) michael@0: ? MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE michael@0: : MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE michael@0: : MOZ_GTK_PROGRESS_CHUNK; michael@0: } michael@0: break; michael@0: case NS_THEME_TAB_SCROLLARROW_BACK: michael@0: case NS_THEME_TAB_SCROLLARROW_FORWARD: michael@0: if (aWidgetFlags) michael@0: *aWidgetFlags = aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK ? michael@0: GTK_ARROW_LEFT : GTK_ARROW_RIGHT; michael@0: aGtkWidgetType = MOZ_GTK_TAB_SCROLLARROW; michael@0: break; michael@0: case NS_THEME_TAB_PANELS: michael@0: aGtkWidgetType = MOZ_GTK_TABPANELS; michael@0: break; michael@0: case NS_THEME_TAB: michael@0: { michael@0: if (aWidgetFlags) { michael@0: /* First bits will be used to store max(0,-bmargin) where bmargin michael@0: * is the bottom margin of the tab in pixels (resp. top margin, michael@0: * for bottom tabs). */ michael@0: if (IsBottomTab(aFrame)) { michael@0: *aWidgetFlags = MOZ_GTK_TAB_BOTTOM; michael@0: } else { michael@0: *aWidgetFlags = 0; michael@0: } michael@0: michael@0: *aWidgetFlags |= GetTabMarginPixels(aFrame); michael@0: michael@0: if (IsSelectedTab(aFrame)) michael@0: *aWidgetFlags |= MOZ_GTK_TAB_SELECTED; michael@0: michael@0: if (IsFirstTab(aFrame)) michael@0: *aWidgetFlags |= MOZ_GTK_TAB_FIRST; michael@0: } michael@0: michael@0: aGtkWidgetType = MOZ_GTK_TAB; michael@0: } michael@0: break; michael@0: case NS_THEME_SPLITTER: michael@0: if (IsHorizontal(aFrame)) michael@0: aGtkWidgetType = MOZ_GTK_SPLITTER_VERTICAL; michael@0: else michael@0: aGtkWidgetType = MOZ_GTK_SPLITTER_HORIZONTAL; michael@0: break; michael@0: case NS_THEME_MENUBAR: michael@0: aGtkWidgetType = MOZ_GTK_MENUBAR; michael@0: break; michael@0: case NS_THEME_MENUPOPUP: michael@0: aGtkWidgetType = MOZ_GTK_MENUPOPUP; michael@0: break; michael@0: case NS_THEME_MENUITEM: michael@0: aGtkWidgetType = MOZ_GTK_MENUITEM; michael@0: break; michael@0: case NS_THEME_MENUSEPARATOR: michael@0: aGtkWidgetType = MOZ_GTK_MENUSEPARATOR; michael@0: break; michael@0: case NS_THEME_MENUARROW: michael@0: aGtkWidgetType = MOZ_GTK_MENUARROW; michael@0: break; michael@0: case NS_THEME_CHECKMENUITEM: michael@0: aGtkWidgetType = MOZ_GTK_CHECKMENUITEM; michael@0: break; michael@0: case NS_THEME_RADIOMENUITEM: michael@0: aGtkWidgetType = MOZ_GTK_RADIOMENUITEM; michael@0: break; michael@0: case NS_THEME_WINDOW: michael@0: case NS_THEME_DIALOG: michael@0: aGtkWidgetType = MOZ_GTK_WINDOW; michael@0: break; michael@0: default: michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: class ThemeRenderer : public gfxGdkNativeRenderer { michael@0: public: michael@0: ThemeRenderer(GtkWidgetState aState, GtkThemeWidgetType aGTKWidgetType, michael@0: gint aFlags, GtkTextDirection aDirection, michael@0: const GdkRectangle& aGDKRect, const GdkRectangle& aGDKClip) michael@0: : mState(aState), mGTKWidgetType(aGTKWidgetType), mFlags(aFlags), michael@0: mDirection(aDirection), mGDKRect(aGDKRect), mGDKClip(aGDKClip) {} michael@0: nsresult DrawWithGDK(GdkDrawable * drawable, gint offsetX, gint offsetY, michael@0: GdkRectangle * clipRects, uint32_t numClipRects); michael@0: private: michael@0: GtkWidgetState mState; michael@0: GtkThemeWidgetType mGTKWidgetType; michael@0: gint mFlags; michael@0: GtkTextDirection mDirection; michael@0: const GdkRectangle& mGDKRect; michael@0: const GdkRectangle& mGDKClip; michael@0: }; michael@0: michael@0: nsresult michael@0: ThemeRenderer::DrawWithGDK(GdkDrawable * drawable, gint offsetX, michael@0: gint offsetY, GdkRectangle * clipRects, uint32_t numClipRects) michael@0: { michael@0: GdkRectangle gdk_rect = mGDKRect; michael@0: gdk_rect.x += offsetX; michael@0: gdk_rect.y += offsetY; michael@0: michael@0: GdkRectangle gdk_clip = mGDKClip; michael@0: gdk_clip.x += offsetX; michael@0: gdk_clip.y += offsetY; michael@0: michael@0: GdkRectangle surfaceRect; michael@0: surfaceRect.x = 0; michael@0: surfaceRect.y = 0; michael@0: gdk_drawable_get_size(drawable, &surfaceRect.width, &surfaceRect.height); michael@0: gdk_rectangle_intersect(&gdk_clip, &surfaceRect, &gdk_clip); michael@0: michael@0: NS_ASSERTION(numClipRects == 0, "We don't support clipping!!!"); michael@0: moz_gtk_widget_paint(mGTKWidgetType, drawable, &gdk_rect, &gdk_clip, michael@0: &mState, mFlags, mDirection); michael@0: michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: nsNativeThemeGTK::GetExtraSizeForWidget(nsIFrame* aFrame, uint8_t aWidgetType, michael@0: nsIntMargin* aExtra) michael@0: { michael@0: *aExtra = nsIntMargin(0,0,0,0); michael@0: // Allow an extra one pixel above and below the thumb for certain michael@0: // GTK2 themes (Ximian Industrial, Bluecurve, Misty, at least); michael@0: // We modify the frame's overflow area. See bug 297508. michael@0: switch (aWidgetType) { michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: aExtra->top = aExtra->bottom = 1; michael@0: return true; michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: aExtra->left = aExtra->right = 1; michael@0: return true; michael@0: michael@0: // Include the indicator spacing (the padding around the control). michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: { michael@0: gint indicator_size, indicator_spacing; michael@0: michael@0: if (aWidgetType == NS_THEME_CHECKBOX) { michael@0: moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); michael@0: } else { michael@0: moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); michael@0: } michael@0: michael@0: aExtra->top = indicator_spacing; michael@0: aExtra->right = indicator_spacing; michael@0: aExtra->bottom = indicator_spacing; michael@0: aExtra->left = indicator_spacing; michael@0: return true; michael@0: } michael@0: case NS_THEME_BUTTON : michael@0: { michael@0: if (IsDefaultButton(aFrame)) { michael@0: // Some themes draw a default indicator outside the widget, michael@0: // include that in overflow michael@0: gint top, left, bottom, right; michael@0: moz_gtk_button_get_default_overflow(&top, &left, &bottom, &right); michael@0: aExtra->top = top; michael@0: aExtra->right = right; michael@0: aExtra->bottom = bottom; michael@0: aExtra->left = left; michael@0: return true; michael@0: } michael@0: } michael@0: case NS_THEME_TAB : michael@0: { michael@0: if (!IsSelectedTab(aFrame)) michael@0: return false; michael@0: michael@0: gint gap_height = moz_gtk_get_tab_thickness(); michael@0: michael@0: int32_t extra = gap_height - GetTabMarginPixels(aFrame); michael@0: if (extra <= 0) michael@0: return false; michael@0: michael@0: if (IsBottomTab(aFrame)) { michael@0: aExtra->top = extra; michael@0: } else { michael@0: aExtra->bottom = extra; michael@0: } michael@0: } michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: const nsRect& aRect, michael@0: const nsRect& aDirtyRect) michael@0: { michael@0: GtkWidgetState state; michael@0: GtkThemeWidgetType gtkWidgetType; michael@0: GtkTextDirection direction = GetTextDirection(aFrame); michael@0: gint flags; michael@0: if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state, michael@0: &flags)) michael@0: return NS_OK; michael@0: michael@0: gfxContext* ctx = aContext->ThebesContext(); michael@0: nsPresContext *presContext = aFrame->PresContext(); michael@0: michael@0: gfxRect rect = presContext->AppUnitsToGfxUnits(aRect); michael@0: gfxRect dirtyRect = presContext->AppUnitsToGfxUnits(aDirtyRect); michael@0: michael@0: // Align to device pixels where sensible michael@0: // to provide crisper and faster drawing. michael@0: // Don't snap if it's a non-unit scale factor. We're going to have to take michael@0: // slow paths then in any case. michael@0: bool snapXY = ctx->UserToDevicePixelSnapped(rect); michael@0: if (snapXY) { michael@0: // Leave rect in device coords but make dirtyRect consistent. michael@0: dirtyRect = ctx->UserToDevice(dirtyRect); michael@0: } michael@0: michael@0: // Translate the dirty rect so that it is wrt the widget top-left. michael@0: dirtyRect.MoveBy(-rect.TopLeft()); michael@0: // Round out the dirty rect to gdk pixels to ensure that gtk draws michael@0: // enough pixels for interpolation to device pixels. michael@0: dirtyRect.RoundOut(); michael@0: michael@0: // GTK themes can only draw an integer number of pixels michael@0: // (even when not snapped). michael@0: nsIntRect widgetRect(0, 0, NS_lround(rect.Width()), NS_lround(rect.Height())); michael@0: nsIntRect overflowRect(widgetRect); michael@0: nsIntMargin extraSize; michael@0: if (GetExtraSizeForWidget(aFrame, aWidgetType, &extraSize)) { michael@0: overflowRect.Inflate(extraSize); michael@0: } michael@0: michael@0: // This is the rectangle that will actually be drawn, in gdk pixels michael@0: nsIntRect drawingRect(int32_t(dirtyRect.X()), michael@0: int32_t(dirtyRect.Y()), michael@0: int32_t(dirtyRect.Width()), michael@0: int32_t(dirtyRect.Height())); michael@0: if (widgetRect.IsEmpty() michael@0: || !drawingRect.IntersectRect(overflowRect, drawingRect)) michael@0: return NS_OK; michael@0: michael@0: // gdk rectangles are wrt the drawing rect. michael@0: michael@0: GdkRectangle gdk_rect = {-drawingRect.x, -drawingRect.y, michael@0: widgetRect.width, widgetRect.height}; michael@0: michael@0: // translate everything so (0,0) is the top left of the drawingRect michael@0: gfxContextAutoSaveRestore autoSR(ctx); michael@0: if (snapXY) { michael@0: // Rects are in device coords. michael@0: ctx->IdentityMatrix(); michael@0: } michael@0: ctx->Translate(rect.TopLeft() + gfxPoint(drawingRect.x, drawingRect.y)); michael@0: michael@0: NS_ASSERTION(!IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType), michael@0: "Trying to render an unsafe widget!"); michael@0: michael@0: bool safeState = IsWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state); michael@0: if (!safeState) { michael@0: gLastGdkError = 0; michael@0: gdk_error_trap_push (); michael@0: } michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: // The gdk_clip is just advisory here, meaning "you don't michael@0: // need to draw outside this rect if you don't feel like it!" michael@0: GdkRectangle gdk_clip = {0, 0, drawingRect.width, drawingRect.height}; michael@0: michael@0: ThemeRenderer renderer(state, gtkWidgetType, flags, direction, michael@0: gdk_rect, gdk_clip); michael@0: michael@0: // Some themes (e.g. Clearlooks) just don't clip properly to any michael@0: // clip rect we provide, so we cannot advertise support for clipping within michael@0: // the widget bounds. michael@0: uint32_t rendererFlags = 0; michael@0: if (GetWidgetTransparency(aFrame, aWidgetType) == eOpaque) { michael@0: rendererFlags |= gfxGdkNativeRenderer::DRAW_IS_OPAQUE; michael@0: } michael@0: michael@0: // GtkStyles (used by the widget drawing backend) are created for a michael@0: // particular colormap/visual. michael@0: GdkColormap* colormap = moz_gtk_widget_get_colormap(); michael@0: michael@0: renderer.Draw(ctx, drawingRect.Size(), rendererFlags, colormap); michael@0: #else michael@0: moz_gtk_widget_paint(gtkWidgetType, ctx->GetCairo(), &gdk_rect, michael@0: &state, flags, direction); michael@0: #endif michael@0: michael@0: if (!safeState) { michael@0: gdk_flush(); michael@0: gLastGdkError = gdk_error_trap_pop (); michael@0: michael@0: if (gLastGdkError) { michael@0: #ifdef DEBUG michael@0: printf("GTK theme failed for widget type %d, error was %d, state was " michael@0: "[active=%d,focused=%d,inHover=%d,disabled=%d]\n", michael@0: aWidgetType, gLastGdkError, state.active, state.focused, michael@0: state.inHover, state.disabled); michael@0: #endif michael@0: NS_WARNING("GTK theme failed; disabling unsafe widget"); michael@0: SetWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType); michael@0: // force refresh of the window, because the widget was not michael@0: // successfully drawn it must be redrawn using the default look michael@0: RefreshWidgetWindow(aFrame); michael@0: } else { michael@0: SetWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state); michael@0: } michael@0: } michael@0: michael@0: // Indeterminate progress bar are animated. michael@0: if (gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || michael@0: gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { michael@0: if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) { michael@0: NS_WARNING("unable to animate widget!"); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, michael@0: uint8_t aWidgetType, nsIntMargin* aResult) michael@0: { michael@0: GtkTextDirection direction = GetTextDirection(aFrame); michael@0: aResult->top = aResult->left = aResult->right = aResult->bottom = 0; michael@0: switch (aWidgetType) { michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: { michael@0: MozGtkScrollbarMetrics metrics; michael@0: moz_gtk_get_scrollbar_metrics(&metrics); michael@0: aResult->top = aResult->left = aResult->right = aResult->bottom = metrics.trough_border; michael@0: } michael@0: break; michael@0: case NS_THEME_TOOLBOX: michael@0: // gtk has no toolbox equivalent. So, although we map toolbox to michael@0: // gtk's 'toolbar' for purposes of painting the widget background, michael@0: // we don't use the toolbar border for toolbox. michael@0: break; michael@0: case NS_THEME_TOOLBAR_DUAL_BUTTON: michael@0: // TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw michael@0: // around the entire button + dropdown, and also an inner border if you're michael@0: // over the button part. But, we want the inner button to be right up michael@0: // against the edge of the outer button so that the borders overlap. michael@0: // To make this happen, we draw a button border for the outer button, michael@0: // but don't reserve any space for it. michael@0: break; michael@0: case NS_THEME_TAB: michael@0: // Top tabs have no bottom border, bottom tabs have no top border michael@0: moz_gtk_get_widget_border(MOZ_GTK_TAB, &aResult->left, &aResult->top, michael@0: &aResult->right, &aResult->bottom, direction, michael@0: FALSE); michael@0: if (IsBottomTab(aFrame)) michael@0: aResult->top = 0; michael@0: else michael@0: aResult->bottom = 0; michael@0: break; michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: // For regular menuitems, we will be using GetWidgetPadding instead of michael@0: // GetWidgetBorder to pad up the widget's internals; other menuitems michael@0: // will need to fall through and use the default case as before. michael@0: if (IsRegularMenuItem(aFrame)) michael@0: break; michael@0: default: michael@0: { michael@0: GtkThemeWidgetType gtkWidgetType; michael@0: if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr, michael@0: nullptr)) { michael@0: moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top, michael@0: &aResult->right, &aResult->bottom, direction, michael@0: IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML)); michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeGTK::GetWidgetPadding(nsDeviceContext* aContext, michael@0: nsIFrame* aFrame, uint8_t aWidgetType, michael@0: nsIntMargin* aResult) michael@0: { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_BUTTON_FOCUS: michael@0: case NS_THEME_TOOLBAR_BUTTON: michael@0: case NS_THEME_TOOLBAR_DUAL_BUTTON: michael@0: case NS_THEME_TAB_SCROLLARROW_BACK: michael@0: case NS_THEME_TAB_SCROLLARROW_FORWARD: michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: michael@0: case NS_THEME_BUTTON_ARROW_UP: michael@0: case NS_THEME_BUTTON_ARROW_DOWN: michael@0: case NS_THEME_BUTTON_ARROW_NEXT: michael@0: case NS_THEME_BUTTON_ARROW_PREVIOUS: michael@0: case NS_THEME_RANGE_THUMB: michael@0: // Radios and checkboxes return a fixed size in GetMinimumWidgetSize michael@0: // and have a meaningful baseline, so they can't have michael@0: // author-specified padding. michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: aResult->SizeTo(0, 0, 0, 0); michael@0: return true; michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: { michael@0: // Menubar and menulist have their padding specified in CSS. michael@0: if (!IsRegularMenuItem(aFrame)) michael@0: return false; michael@0: michael@0: aResult->SizeTo(0, 0, 0, 0); michael@0: GtkThemeWidgetType gtkWidgetType; michael@0: if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr, michael@0: nullptr)) { michael@0: moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top, michael@0: &aResult->right, &aResult->bottom, GetTextDirection(aFrame), michael@0: IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML)); michael@0: } michael@0: michael@0: gint horizontal_padding; michael@0: michael@0: if (aWidgetType == NS_THEME_MENUITEM) michael@0: moz_gtk_menuitem_get_horizontal_padding(&horizontal_padding); michael@0: else michael@0: moz_gtk_checkmenuitem_get_horizontal_padding(&horizontal_padding); michael@0: michael@0: aResult->left += horizontal_padding; michael@0: aResult->right += horizontal_padding; michael@0: michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeGTK::GetWidgetOverflow(nsDeviceContext* aContext, michael@0: nsIFrame* aFrame, uint8_t aWidgetType, michael@0: nsRect* aOverflowRect) michael@0: { michael@0: nsIntMargin extraSize; michael@0: if (!GetExtraSizeForWidget(aFrame, aWidgetType, &extraSize)) michael@0: return false; michael@0: michael@0: int32_t p2a = aContext->AppUnitsPerDevPixel(); michael@0: nsMargin m(NSIntPixelsToAppUnits(extraSize.top, p2a), michael@0: NSIntPixelsToAppUnits(extraSize.right, p2a), michael@0: NSIntPixelsToAppUnits(extraSize.bottom, p2a), michael@0: NSIntPixelsToAppUnits(extraSize.left, p2a)); michael@0: michael@0: aOverflowRect->Inflate(m); michael@0: return true; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeGTK::GetMinimumWidgetSize(nsRenderingContext* aContext, michael@0: nsIFrame* aFrame, uint8_t aWidgetType, michael@0: nsIntSize* aResult, bool* aIsOverridable) michael@0: { michael@0: aResult->width = aResult->height = 0; michael@0: *aIsOverridable = true; michael@0: michael@0: switch (aWidgetType) { michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: { michael@0: MozGtkScrollbarMetrics metrics; michael@0: moz_gtk_get_scrollbar_metrics(&metrics); michael@0: michael@0: aResult->width = metrics.slider_width; michael@0: aResult->height = metrics.stepper_size; michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: { michael@0: MozGtkScrollbarMetrics metrics; michael@0: moz_gtk_get_scrollbar_metrics(&metrics); michael@0: michael@0: aResult->width = metrics.stepper_size; michael@0: aResult->height = metrics.slider_width; michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_SPLITTER: michael@0: { michael@0: gint metrics; michael@0: if (IsHorizontal(aFrame)) { michael@0: moz_gtk_splitter_get_metrics(GTK_ORIENTATION_HORIZONTAL, &metrics); michael@0: aResult->width = metrics; michael@0: aResult->height = 0; michael@0: } else { michael@0: moz_gtk_splitter_get_metrics(GTK_ORIENTATION_VERTICAL, &metrics); michael@0: aResult->width = 0; michael@0: aResult->height = metrics; michael@0: } michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: { michael@0: /* While we enforce a minimum size for the thumb, this is ignored michael@0: * for the some scrollbars if buttons are hidden (bug 513006) because michael@0: * the thumb isn't a direct child of the scrollbar, unlike the buttons michael@0: * or track. So add a minimum size to the track as well to prevent a michael@0: * 0-width scrollbar. */ michael@0: MozGtkScrollbarMetrics metrics; michael@0: moz_gtk_get_scrollbar_metrics(&metrics); michael@0: michael@0: if (aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL) michael@0: aResult->width = metrics.slider_width + 2 * metrics.trough_border; michael@0: else michael@0: aResult->height = metrics.slider_width + 2 * metrics.trough_border; michael@0: michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: { michael@0: MozGtkScrollbarMetrics metrics; michael@0: moz_gtk_get_scrollbar_metrics(&metrics); michael@0: michael@0: nsRect rect = aFrame->GetParent()->GetRect(); michael@0: int32_t p2a = aFrame->PresContext()->DeviceContext()-> michael@0: AppUnitsPerDevPixel(); michael@0: nsMargin margin; michael@0: michael@0: /* Get the available space, if that is smaller then the minimum size, michael@0: * adjust the mininum size to fit into it. michael@0: * Setting aIsOverridable to true has no effect for thumbs. */ michael@0: aFrame->GetMargin(margin); michael@0: rect.Deflate(margin); michael@0: aFrame->GetParent()->GetBorderAndPadding(margin); michael@0: rect.Deflate(margin); michael@0: michael@0: if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) { michael@0: aResult->width = metrics.slider_width; michael@0: aResult->height = std::min(NSAppUnitsToIntPixels(rect.height, p2a), michael@0: metrics.min_slider_size); michael@0: } else { michael@0: aResult->height = metrics.slider_width; michael@0: aResult->width = std::min(NSAppUnitsToIntPixels(rect.width, p2a), michael@0: metrics.min_slider_size); michael@0: } michael@0: michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_RANGE_THUMB: michael@0: { michael@0: gint thumb_length, thumb_height; michael@0: michael@0: if (IsRangeHorizontal(aFrame)) { michael@0: moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height); michael@0: } else { michael@0: moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_length); michael@0: } michael@0: aResult->width = thumb_length; michael@0: aResult->height = thumb_height; michael@0: michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: { michael@0: gint thumb_length, thumb_height; michael@0: michael@0: if (aWidgetType == NS_THEME_SCALE_THUMB_VERTICAL) { michael@0: moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_length, &thumb_height); michael@0: aResult->width = thumb_height; michael@0: aResult->height = thumb_length; michael@0: } else { michael@0: moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height); michael@0: aResult->width = thumb_length; michael@0: aResult->height = thumb_height; michael@0: } michael@0: michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_TAB_SCROLLARROW_BACK: michael@0: case NS_THEME_TAB_SCROLLARROW_FORWARD: michael@0: { michael@0: moz_gtk_get_tab_scroll_arrow_size(&aResult->width, &aResult->height); michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: { michael@0: moz_gtk_get_combo_box_entry_button_size(&aResult->width, michael@0: &aResult->height); michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_MENUSEPARATOR: michael@0: { michael@0: gint separator_height; michael@0: michael@0: moz_gtk_get_menu_separator_height(&separator_height); michael@0: aResult->height = separator_height; michael@0: michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: { michael@0: gint indicator_size, indicator_spacing; michael@0: michael@0: if (aWidgetType == NS_THEME_CHECKBOX) { michael@0: moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); michael@0: } else { michael@0: moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); michael@0: } michael@0: michael@0: // Include space for the indicator and the padding around it. michael@0: aResult->width = indicator_size; michael@0: aResult->height = indicator_size; michael@0: } michael@0: break; michael@0: case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: michael@0: case NS_THEME_BUTTON_ARROW_UP: michael@0: case NS_THEME_BUTTON_ARROW_DOWN: michael@0: case NS_THEME_BUTTON_ARROW_NEXT: michael@0: case NS_THEME_BUTTON_ARROW_PREVIOUS: michael@0: { michael@0: moz_gtk_get_arrow_size(&aResult->width, &aResult->height); michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: case NS_THEME_CHECKBOX_CONTAINER: michael@0: case NS_THEME_RADIO_CONTAINER: michael@0: case NS_THEME_CHECKBOX_LABEL: michael@0: case NS_THEME_RADIO_LABEL: michael@0: case NS_THEME_BUTTON: michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_TOOLBAR_BUTTON: michael@0: case NS_THEME_TREEVIEW_HEADER_CELL: michael@0: { michael@0: // Just include our border, and let the box code augment the size. michael@0: nsIntMargin border; michael@0: nsNativeThemeGTK::GetWidgetBorder(aContext->DeviceContext(), michael@0: aFrame, aWidgetType, &border); michael@0: aResult->width = border.left + border.right; michael@0: aResult->height = border.top + border.bottom; michael@0: } michael@0: break; michael@0: case NS_THEME_TOOLBAR_SEPARATOR: michael@0: { michael@0: gint separator_width; michael@0: michael@0: moz_gtk_get_toolbar_separator_width(&separator_width); michael@0: michael@0: aResult->width = separator_width; michael@0: } michael@0: break; michael@0: case NS_THEME_SPINNER: michael@0: // hard code these sizes michael@0: aResult->width = 14; michael@0: aResult->height = 26; michael@0: break; michael@0: case NS_THEME_TREEVIEW_HEADER_SORTARROW: michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: // hard code these sizes michael@0: aResult->width = 14; michael@0: aResult->height = 13; michael@0: break; michael@0: case NS_THEME_RESIZER: michael@0: // same as Windows to make our lives easier michael@0: aResult->width = aResult->height = 15; michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_TREEVIEW_TWISTY: michael@0: case NS_THEME_TREEVIEW_TWISTY_OPEN: michael@0: { michael@0: gint expander_size; michael@0: michael@0: moz_gtk_get_treeview_expander_size(&expander_size); michael@0: aResult->width = aResult->height = expander_size; michael@0: *aIsOverridable = false; michael@0: } michael@0: break; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, michael@0: nsIAtom* aAttribute, bool* aShouldRepaint) michael@0: { michael@0: // Some widget types just never change state. michael@0: if (aWidgetType == NS_THEME_TOOLBOX || michael@0: aWidgetType == NS_THEME_TOOLBAR || michael@0: aWidgetType == NS_THEME_STATUSBAR || michael@0: aWidgetType == NS_THEME_STATUSBAR_PANEL || michael@0: aWidgetType == NS_THEME_STATUSBAR_RESIZER_PANEL || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || michael@0: aWidgetType == NS_THEME_PROGRESSBAR || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL || michael@0: aWidgetType == NS_THEME_MENUBAR || michael@0: aWidgetType == NS_THEME_MENUPOPUP || michael@0: aWidgetType == NS_THEME_TOOLTIP || michael@0: aWidgetType == NS_THEME_MENUSEPARATOR || michael@0: aWidgetType == NS_THEME_WINDOW || michael@0: aWidgetType == NS_THEME_DIALOG) { michael@0: *aShouldRepaint = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if ((aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || michael@0: aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT) && michael@0: (aAttribute == nsGkAtoms::curpos || michael@0: aAttribute == nsGkAtoms::maxpos)) { michael@0: *aShouldRepaint = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // XXXdwh Not sure what can really be done here. Can at least guess for michael@0: // specific widgets that they're highly unlikely to have certain states. michael@0: // For example, a toolbar doesn't care about any states. michael@0: if (!aAttribute) { michael@0: // Hover/focus/active changed. Always repaint. michael@0: *aShouldRepaint = true; michael@0: } michael@0: else { michael@0: // Check the attribute to see if it's relevant. michael@0: // disabled, checked, dlgtype, default, etc. michael@0: *aShouldRepaint = false; michael@0: if (aAttribute == nsGkAtoms::disabled || michael@0: aAttribute == nsGkAtoms::checked || michael@0: aAttribute == nsGkAtoms::selected || michael@0: aAttribute == nsGkAtoms::focused || michael@0: aAttribute == nsGkAtoms::readonly || michael@0: aAttribute == nsGkAtoms::_default || michael@0: aAttribute == nsGkAtoms::menuactive || michael@0: aAttribute == nsGkAtoms::open || michael@0: aAttribute == nsGkAtoms::parentfocused) michael@0: *aShouldRepaint = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeGTK::ThemeChanged() michael@0: { michael@0: memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(bool) michael@0: nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType) michael@0: { michael@0: if (IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType)) michael@0: return false; michael@0: michael@0: switch (aWidgetType) { michael@0: case NS_THEME_BUTTON: michael@0: case NS_THEME_BUTTON_FOCUS: michael@0: case NS_THEME_RADIO: michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_TOOLBOX: // N/A michael@0: case NS_THEME_TOOLBAR: michael@0: case NS_THEME_TOOLBAR_BUTTON: michael@0: case NS_THEME_TOOLBAR_DUAL_BUTTON: // so we can override the border with 0 michael@0: case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: michael@0: case NS_THEME_BUTTON_ARROW_UP: michael@0: case NS_THEME_BUTTON_ARROW_DOWN: michael@0: case NS_THEME_BUTTON_ARROW_NEXT: michael@0: case NS_THEME_BUTTON_ARROW_PREVIOUS: michael@0: case NS_THEME_TOOLBAR_SEPARATOR: michael@0: case NS_THEME_TOOLBAR_GRIPPER: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: case NS_THEME_RESIZER: michael@0: case NS_THEME_LISTBOX: michael@0: // case NS_THEME_LISTBOX_LISTITEM: michael@0: case NS_THEME_TREEVIEW: michael@0: // case NS_THEME_TREEVIEW_TREEITEM: michael@0: case NS_THEME_TREEVIEW_TWISTY: michael@0: // case NS_THEME_TREEVIEW_LINE: michael@0: // case NS_THEME_TREEVIEW_HEADER: michael@0: case NS_THEME_TREEVIEW_HEADER_CELL: michael@0: case NS_THEME_TREEVIEW_HEADER_SORTARROW: michael@0: case NS_THEME_TREEVIEW_TWISTY_OPEN: michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: case NS_THEME_TAB: michael@0: // case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_TAB_PANELS: michael@0: case NS_THEME_TAB_SCROLLARROW_BACK: michael@0: case NS_THEME_TAB_SCROLLARROW_FORWARD: michael@0: case NS_THEME_TOOLTIP: michael@0: case NS_THEME_SPINNER: michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: case NS_THEME_SPINNER_TEXTFIELD: michael@0: // case NS_THEME_SCROLLBAR: (n/a for gtk) michael@0: // case NS_THEME_SCROLLBAR_SMALL: (n/a for gtk) michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: michael@0: case NS_THEME_RANGE: michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: // case NS_THEME_SCALE_THUMB_START: michael@0: // case NS_THEME_SCALE_THUMB_END: michael@0: // case NS_THEME_SCALE_TICK: michael@0: case NS_THEME_CHECKBOX_CONTAINER: michael@0: case NS_THEME_RADIO_CONTAINER: michael@0: case NS_THEME_CHECKBOX_LABEL: michael@0: case NS_THEME_RADIO_LABEL: michael@0: case NS_THEME_MENUBAR: michael@0: case NS_THEME_MENUPOPUP: michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_MENUARROW: michael@0: case NS_THEME_MENUSEPARATOR: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: case NS_THEME_SPLITTER: michael@0: case NS_THEME_WINDOW: michael@0: case NS_THEME_DIALOG: michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_DROPDOWN_TEXT: michael@0: return !IsWidgetStyled(aPresContext, aFrame, aWidgetType); michael@0: michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: // "Native" dropdown buttons cause padding and margin problems, but only michael@0: // in HTML so allow them in XUL. michael@0: return (!aFrame || IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) && michael@0: !IsWidgetStyled(aPresContext, aFrame, aWidgetType); michael@0: michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(bool) michael@0: nsNativeThemeGTK::WidgetIsContainer(uint8_t aWidgetType) michael@0: { michael@0: // XXXdwh At some point flesh all of this out. michael@0: if (aWidgetType == NS_THEME_DROPDOWN_BUTTON || michael@0: aWidgetType == NS_THEME_RADIO || michael@0: aWidgetType == NS_THEME_RANGE_THUMB || michael@0: aWidgetType == NS_THEME_CHECKBOX || michael@0: aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK || michael@0: aWidgetType == NS_THEME_TAB_SCROLLARROW_FORWARD || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_UP || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_DOWN || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_NEXT || michael@0: aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS) michael@0: return false; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeGTK::ThemeDrawsFocusForWidget(uint8_t aWidgetType) michael@0: { michael@0: if (aWidgetType == NS_THEME_DROPDOWN || michael@0: aWidgetType == NS_THEME_BUTTON || michael@0: aWidgetType == NS_THEME_TREEVIEW_HEADER_CELL) michael@0: return true; michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeGTK::ThemeNeedsComboboxDropmarker() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: nsITheme::Transparency michael@0: nsNativeThemeGTK::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) michael@0: { michael@0: switch (aWidgetType) { michael@0: // These widgets always draw a default background. michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_TOOLBAR: michael@0: case NS_THEME_MENUBAR: michael@0: #endif michael@0: case NS_THEME_MENUPOPUP: michael@0: case NS_THEME_WINDOW: michael@0: case NS_THEME_DIALOG: michael@0: // Tooltips use gtk_paint_flat_box(). michael@0: case NS_THEME_TOOLTIP: michael@0: return eOpaque; michael@0: } michael@0: michael@0: return eUnknownTransparency; michael@0: }