1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gtk/nsNativeThemeGTK.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1490 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsNativeThemeGTK.h" 1.10 +#include "nsThemeConstants.h" 1.11 +#include "gtkdrawing.h" 1.12 + 1.13 +#include "nsIObserverService.h" 1.14 +#include "nsIServiceManager.h" 1.15 +#include "nsIFrame.h" 1.16 +#include "nsIPresShell.h" 1.17 +#include "nsIContent.h" 1.18 +#include "nsViewManager.h" 1.19 +#include "nsNameSpaceManager.h" 1.20 +#include "nsGfxCIID.h" 1.21 +#include "nsTransform2D.h" 1.22 +#include "nsMenuFrame.h" 1.23 +#include "prlink.h" 1.24 +#include "nsIDOMHTMLInputElement.h" 1.25 +#include "nsRenderingContext.h" 1.26 +#include "nsGkAtoms.h" 1.27 + 1.28 +#include "mozilla/EventStates.h" 1.29 +#include "mozilla/Services.h" 1.30 + 1.31 +#include <gdk/gdkprivate.h> 1.32 +#include <gtk/gtk.h> 1.33 + 1.34 +#include "gfxContext.h" 1.35 +#include "gfxPlatformGtk.h" 1.36 +#include "gfxGdkNativeRenderer.h" 1.37 +#include <algorithm> 1.38 + 1.39 +using namespace mozilla; 1.40 + 1.41 +NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeGTK, nsNativeTheme, nsITheme, 1.42 + nsIObserver) 1.43 + 1.44 +static int gLastGdkError; 1.45 + 1.46 +nsNativeThemeGTK::nsNativeThemeGTK() 1.47 +{ 1.48 + if (moz_gtk_init() != MOZ_GTK_SUCCESS) { 1.49 + memset(mDisabledWidgetTypes, 0xff, sizeof(mDisabledWidgetTypes)); 1.50 + return; 1.51 + } 1.52 + 1.53 + // We have to call moz_gtk_shutdown before the event loop stops running. 1.54 + nsCOMPtr<nsIObserverService> obsServ = 1.55 + mozilla::services::GetObserverService(); 1.56 + obsServ->AddObserver(this, "xpcom-shutdown", false); 1.57 + 1.58 + memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes)); 1.59 + memset(mSafeWidgetStates, 0, sizeof(mSafeWidgetStates)); 1.60 +} 1.61 + 1.62 +nsNativeThemeGTK::~nsNativeThemeGTK() { 1.63 +} 1.64 + 1.65 +NS_IMETHODIMP 1.66 +nsNativeThemeGTK::Observe(nsISupports *aSubject, const char *aTopic, 1.67 + const char16_t *aData) 1.68 +{ 1.69 + if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) { 1.70 + moz_gtk_shutdown(); 1.71 + } else { 1.72 + NS_NOTREACHED("unexpected topic"); 1.73 + return NS_ERROR_UNEXPECTED; 1.74 + } 1.75 + 1.76 + return NS_OK; 1.77 +} 1.78 + 1.79 +void 1.80 +nsNativeThemeGTK::RefreshWidgetWindow(nsIFrame* aFrame) 1.81 +{ 1.82 + nsIPresShell *shell = GetPresShell(aFrame); 1.83 + if (!shell) 1.84 + return; 1.85 + 1.86 + nsViewManager* vm = shell->GetViewManager(); 1.87 + if (!vm) 1.88 + return; 1.89 + 1.90 + vm->InvalidateAllViews(); 1.91 +} 1.92 + 1.93 +static bool IsFrameContentNodeInNamespace(nsIFrame *aFrame, uint32_t aNamespace) 1.94 +{ 1.95 + nsIContent *content = aFrame ? aFrame->GetContent() : nullptr; 1.96 + if (!content) 1.97 + return false; 1.98 + return content->IsInNamespace(aNamespace); 1.99 +} 1.100 + 1.101 +static bool IsWidgetTypeDisabled(uint8_t* aDisabledVector, uint8_t aWidgetType) { 1.102 + return (aDisabledVector[aWidgetType >> 3] & (1 << (aWidgetType & 7))) != 0; 1.103 +} 1.104 + 1.105 +static void SetWidgetTypeDisabled(uint8_t* aDisabledVector, uint8_t aWidgetType) { 1.106 + aDisabledVector[aWidgetType >> 3] |= (1 << (aWidgetType & 7)); 1.107 +} 1.108 + 1.109 +static inline uint16_t 1.110 +GetWidgetStateKey(uint8_t aWidgetType, GtkWidgetState *aWidgetState) 1.111 +{ 1.112 + return (aWidgetState->active | 1.113 + aWidgetState->focused << 1 | 1.114 + aWidgetState->inHover << 2 | 1.115 + aWidgetState->disabled << 3 | 1.116 + aWidgetState->isDefault << 4 | 1.117 + aWidgetType << 5); 1.118 +} 1.119 + 1.120 +static bool IsWidgetStateSafe(uint8_t* aSafeVector, 1.121 + uint8_t aWidgetType, 1.122 + GtkWidgetState *aWidgetState) 1.123 +{ 1.124 + uint8_t key = GetWidgetStateKey(aWidgetType, aWidgetState); 1.125 + return (aSafeVector[key >> 3] & (1 << (key & 7))) != 0; 1.126 +} 1.127 + 1.128 +static void SetWidgetStateSafe(uint8_t *aSafeVector, 1.129 + uint8_t aWidgetType, 1.130 + GtkWidgetState *aWidgetState) 1.131 +{ 1.132 + uint8_t key = GetWidgetStateKey(aWidgetType, aWidgetState); 1.133 + aSafeVector[key >> 3] |= (1 << (key & 7)); 1.134 +} 1.135 + 1.136 +static GtkTextDirection GetTextDirection(nsIFrame* aFrame) 1.137 +{ 1.138 + if (!aFrame) 1.139 + return GTK_TEXT_DIR_NONE; 1.140 + 1.141 + switch (aFrame->StyleVisibility()->mDirection) { 1.142 + case NS_STYLE_DIRECTION_RTL: 1.143 + return GTK_TEXT_DIR_RTL; 1.144 + case NS_STYLE_DIRECTION_LTR: 1.145 + return GTK_TEXT_DIR_LTR; 1.146 + } 1.147 + 1.148 + return GTK_TEXT_DIR_NONE; 1.149 +} 1.150 + 1.151 +// Returns positive for negative margins (otherwise 0). 1.152 +gint 1.153 +nsNativeThemeGTK::GetTabMarginPixels(nsIFrame* aFrame) 1.154 +{ 1.155 + nscoord margin = 1.156 + IsBottomTab(aFrame) ? aFrame->GetUsedMargin().top 1.157 + : aFrame->GetUsedMargin().bottom; 1.158 + 1.159 + return std::min<gint>(MOZ_GTK_TAB_MARGIN_MASK, 1.160 + std::max(0, 1.161 + aFrame->PresContext()->AppUnitsToDevPixels(-margin))); 1.162 +} 1.163 + 1.164 +bool 1.165 +nsNativeThemeGTK::GetGtkWidgetAndState(uint8_t aWidgetType, nsIFrame* aFrame, 1.166 + GtkThemeWidgetType& aGtkWidgetType, 1.167 + GtkWidgetState* aState, 1.168 + gint* aWidgetFlags) 1.169 +{ 1.170 + if (aState) { 1.171 + if (!aFrame) { 1.172 + // reset the entire struct to zero 1.173 + memset(aState, 0, sizeof(GtkWidgetState)); 1.174 + } else { 1.175 + 1.176 + // For XUL checkboxes and radio buttons, the state of the parent 1.177 + // determines our state. 1.178 + nsIFrame *stateFrame = aFrame; 1.179 + if (aFrame && ((aWidgetFlags && (aWidgetType == NS_THEME_CHECKBOX || 1.180 + aWidgetType == NS_THEME_RADIO)) || 1.181 + aWidgetType == NS_THEME_CHECKBOX_LABEL || 1.182 + aWidgetType == NS_THEME_RADIO_LABEL)) { 1.183 + 1.184 + nsIAtom* atom = nullptr; 1.185 + if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) { 1.186 + if (aWidgetType == NS_THEME_CHECKBOX_LABEL || 1.187 + aWidgetType == NS_THEME_RADIO_LABEL) { 1.188 + // Adjust stateFrame so GetContentState finds the correct state. 1.189 + stateFrame = aFrame = aFrame->GetParent()->GetParent(); 1.190 + } else { 1.191 + // GetContentState knows to look one frame up for radio/checkbox 1.192 + // widgets, so don't adjust stateFrame here. 1.193 + aFrame = aFrame->GetParent(); 1.194 + } 1.195 + if (aWidgetFlags) { 1.196 + if (!atom) { 1.197 + atom = (aWidgetType == NS_THEME_CHECKBOX || 1.198 + aWidgetType == NS_THEME_CHECKBOX_LABEL) ? nsGkAtoms::checked 1.199 + : nsGkAtoms::selected; 1.200 + } 1.201 + *aWidgetFlags = CheckBooleanAttr(aFrame, atom); 1.202 + } 1.203 + } else { 1.204 + if (aWidgetFlags) { 1.205 + nsCOMPtr<nsIDOMHTMLInputElement> inputElt(do_QueryInterface(aFrame->GetContent())); 1.206 + *aWidgetFlags = 0; 1.207 + if (inputElt) { 1.208 + bool isHTMLChecked; 1.209 + inputElt->GetChecked(&isHTMLChecked); 1.210 + if (isHTMLChecked) 1.211 + *aWidgetFlags |= MOZ_GTK_WIDGET_CHECKED; 1.212 + } 1.213 + 1.214 + if (GetIndeterminate(aFrame)) 1.215 + *aWidgetFlags |= MOZ_GTK_WIDGET_INCONSISTENT; 1.216 + } 1.217 + } 1.218 + } else if (aWidgetType == NS_THEME_TOOLBAR_BUTTON_DROPDOWN || 1.219 + aWidgetType == NS_THEME_TREEVIEW_HEADER_SORTARROW || 1.220 + aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS || 1.221 + aWidgetType == NS_THEME_BUTTON_ARROW_NEXT || 1.222 + aWidgetType == NS_THEME_BUTTON_ARROW_UP || 1.223 + aWidgetType == NS_THEME_BUTTON_ARROW_DOWN) { 1.224 + // The state of an arrow comes from its parent. 1.225 + stateFrame = aFrame = aFrame->GetParent(); 1.226 + } 1.227 + 1.228 + EventStates eventState = GetContentState(stateFrame, aWidgetType); 1.229 + 1.230 + aState->disabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame); 1.231 + aState->active = eventState.HasState(NS_EVENT_STATE_ACTIVE); 1.232 + aState->focused = eventState.HasState(NS_EVENT_STATE_FOCUS); 1.233 + aState->inHover = eventState.HasState(NS_EVENT_STATE_HOVER); 1.234 + aState->isDefault = IsDefaultButton(aFrame); 1.235 + aState->canDefault = FALSE; // XXX fix me 1.236 + aState->depressed = FALSE; 1.237 + 1.238 + if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) { 1.239 + // For these widget types, some element (either a child or parent) 1.240 + // actually has element focus, so we check the focused attribute 1.241 + // to see whether to draw in the focused state. 1.242 + if (aWidgetType == NS_THEME_NUMBER_INPUT || 1.243 + aWidgetType == NS_THEME_TEXTFIELD || 1.244 + aWidgetType == NS_THEME_TEXTFIELD_MULTILINE || 1.245 + aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD || 1.246 + aWidgetType == NS_THEME_SPINNER_TEXTFIELD || 1.247 + aWidgetType == NS_THEME_RADIO_CONTAINER || 1.248 + aWidgetType == NS_THEME_RADIO_LABEL) { 1.249 + aState->focused = IsFocused(aFrame); 1.250 + } else if (aWidgetType == NS_THEME_RADIO || 1.251 + aWidgetType == NS_THEME_CHECKBOX) { 1.252 + // In XUL, checkboxes and radios shouldn't have focus rings, their labels do 1.253 + aState->focused = FALSE; 1.254 + } 1.255 + 1.256 + if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL || 1.257 + aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) { 1.258 + // for scrollbars we need to go up two to go from the thumb to 1.259 + // the slider to the actual scrollbar object 1.260 + nsIFrame *tmpFrame = aFrame->GetParent()->GetParent(); 1.261 + 1.262 + aState->curpos = CheckIntAttr(tmpFrame, nsGkAtoms::curpos, 0); 1.263 + aState->maxpos = CheckIntAttr(tmpFrame, nsGkAtoms::maxpos, 100); 1.264 + } 1.265 + 1.266 + if (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP || 1.267 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN || 1.268 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || 1.269 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT) { 1.270 + // set the state to disabled when the scrollbar is scrolled to 1.271 + // the beginning or the end, depending on the button type. 1.272 + int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0); 1.273 + int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100); 1.274 + if ((curpos == 0 && (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP || 1.275 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT)) || 1.276 + (curpos == maxpos && 1.277 + (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN || 1.278 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT))) 1.279 + aState->disabled = true; 1.280 + 1.281 + // In order to simulate native GTK scrollbar click behavior, 1.282 + // we set the active attribute on the element to true if it's 1.283 + // pressed with any mouse button. 1.284 + // This allows us to show that it's active without setting :active 1.285 + else if (CheckBooleanAttr(aFrame, nsGkAtoms::active)) 1.286 + aState->active = true; 1.287 + 1.288 + if (aWidgetFlags) { 1.289 + *aWidgetFlags = GetScrollbarButtonType(aFrame); 1.290 + if (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP < 2) 1.291 + *aWidgetFlags |= MOZ_GTK_STEPPER_VERTICAL; 1.292 + } 1.293 + } 1.294 + 1.295 + // menu item state is determined by the attribute "_moz-menuactive", 1.296 + // and not by the mouse hovering (accessibility). as a special case, 1.297 + // menus which are children of a menu bar are only marked as prelight 1.298 + // if they are open, not on normal hover. 1.299 + 1.300 + if (aWidgetType == NS_THEME_MENUITEM || 1.301 + aWidgetType == NS_THEME_CHECKMENUITEM || 1.302 + aWidgetType == NS_THEME_RADIOMENUITEM || 1.303 + aWidgetType == NS_THEME_MENUSEPARATOR || 1.304 + aWidgetType == NS_THEME_MENUARROW) { 1.305 + bool isTopLevel = false; 1.306 + nsMenuFrame *menuFrame = do_QueryFrame(aFrame); 1.307 + if (menuFrame) { 1.308 + isTopLevel = menuFrame->IsOnMenuBar(); 1.309 + } 1.310 + 1.311 + if (isTopLevel) { 1.312 + aState->inHover = menuFrame->IsOpen(); 1.313 + *aWidgetFlags |= MOZ_TOPLEVEL_MENU_ITEM; 1.314 + } else { 1.315 + aState->inHover = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive); 1.316 + *aWidgetFlags &= ~MOZ_TOPLEVEL_MENU_ITEM; 1.317 + } 1.318 + 1.319 + aState->active = FALSE; 1.320 + 1.321 + if (aWidgetType == NS_THEME_CHECKMENUITEM || 1.322 + aWidgetType == NS_THEME_RADIOMENUITEM) { 1.323 + *aWidgetFlags = 0; 1.324 + if (aFrame && aFrame->GetContent()) { 1.325 + *aWidgetFlags = aFrame->GetContent()-> 1.326 + AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked, 1.327 + nsGkAtoms::_true, eIgnoreCase); 1.328 + } 1.329 + } 1.330 + } 1.331 + 1.332 + // A button with drop down menu open or an activated toggle button 1.333 + // should always appear depressed. 1.334 + if (aWidgetType == NS_THEME_BUTTON || 1.335 + aWidgetType == NS_THEME_TOOLBAR_BUTTON || 1.336 + aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON || 1.337 + aWidgetType == NS_THEME_TOOLBAR_BUTTON_DROPDOWN || 1.338 + aWidgetType == NS_THEME_DROPDOWN || 1.339 + aWidgetType == NS_THEME_DROPDOWN_BUTTON) { 1.340 + bool menuOpen = IsOpenButton(aFrame); 1.341 + aState->depressed = IsCheckedButton(aFrame) || menuOpen; 1.342 + // we must not highlight buttons with open drop down menus on hover. 1.343 + aState->inHover = aState->inHover && !menuOpen; 1.344 + } 1.345 + 1.346 + // When the input field of the drop down button has focus, some themes 1.347 + // should draw focus for the drop down button as well. 1.348 + if (aWidgetType == NS_THEME_DROPDOWN_BUTTON && aWidgetFlags) { 1.349 + *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused); 1.350 + } 1.351 + } 1.352 + } 1.353 + } 1.354 + 1.355 + switch (aWidgetType) { 1.356 + case NS_THEME_BUTTON: 1.357 + case NS_THEME_TOOLBAR_BUTTON: 1.358 + case NS_THEME_TOOLBAR_DUAL_BUTTON: 1.359 + if (aWidgetFlags) 1.360 + *aWidgetFlags = (aWidgetType == NS_THEME_BUTTON) ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE; 1.361 + aGtkWidgetType = MOZ_GTK_BUTTON; 1.362 + break; 1.363 + case NS_THEME_CHECKBOX: 1.364 + case NS_THEME_RADIO: 1.365 + aGtkWidgetType = (aWidgetType == NS_THEME_RADIO) ? MOZ_GTK_RADIOBUTTON : MOZ_GTK_CHECKBUTTON; 1.366 + break; 1.367 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.368 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.369 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.370 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.371 + aGtkWidgetType = MOZ_GTK_SCROLLBAR_BUTTON; 1.372 + break; 1.373 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.374 + aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_VERTICAL; 1.375 + break; 1.376 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.377 + aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL; 1.378 + break; 1.379 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.380 + aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL; 1.381 + break; 1.382 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.383 + aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL; 1.384 + break; 1.385 + case NS_THEME_SPINNER: 1.386 + aGtkWidgetType = MOZ_GTK_SPINBUTTON; 1.387 + break; 1.388 + case NS_THEME_SPINNER_UP_BUTTON: 1.389 + aGtkWidgetType = MOZ_GTK_SPINBUTTON_UP; 1.390 + break; 1.391 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.392 + aGtkWidgetType = MOZ_GTK_SPINBUTTON_DOWN; 1.393 + break; 1.394 + case NS_THEME_SPINNER_TEXTFIELD: 1.395 + aGtkWidgetType = MOZ_GTK_SPINBUTTON_ENTRY; 1.396 + break; 1.397 + case NS_THEME_RANGE: 1.398 + { 1.399 + if (IsRangeHorizontal(aFrame)) { 1.400 + if (aWidgetFlags) 1.401 + *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; 1.402 + aGtkWidgetType = MOZ_GTK_SCALE_HORIZONTAL; 1.403 + } else { 1.404 + if (aWidgetFlags) 1.405 + *aWidgetFlags = GTK_ORIENTATION_VERTICAL; 1.406 + aGtkWidgetType = MOZ_GTK_SCALE_VERTICAL; 1.407 + } 1.408 + break; 1.409 + } 1.410 + case NS_THEME_RANGE_THUMB: 1.411 + { 1.412 + if (IsRangeHorizontal(aFrame)) { 1.413 + if (aWidgetFlags) 1.414 + *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; 1.415 + aGtkWidgetType = MOZ_GTK_SCALE_THUMB_HORIZONTAL; 1.416 + } else { 1.417 + if (aWidgetFlags) 1.418 + *aWidgetFlags = GTK_ORIENTATION_VERTICAL; 1.419 + aGtkWidgetType = MOZ_GTK_SCALE_THUMB_VERTICAL; 1.420 + } 1.421 + break; 1.422 + } 1.423 + case NS_THEME_SCALE_HORIZONTAL: 1.424 + if (aWidgetFlags) 1.425 + *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; 1.426 + aGtkWidgetType = MOZ_GTK_SCALE_HORIZONTAL; 1.427 + break; 1.428 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.429 + if (aWidgetFlags) 1.430 + *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL; 1.431 + aGtkWidgetType = MOZ_GTK_SCALE_THUMB_HORIZONTAL; 1.432 + break; 1.433 + case NS_THEME_SCALE_VERTICAL: 1.434 + if (aWidgetFlags) 1.435 + *aWidgetFlags = GTK_ORIENTATION_VERTICAL; 1.436 + aGtkWidgetType = MOZ_GTK_SCALE_VERTICAL; 1.437 + break; 1.438 + case NS_THEME_TOOLBAR_SEPARATOR: 1.439 + aGtkWidgetType = MOZ_GTK_TOOLBAR_SEPARATOR; 1.440 + break; 1.441 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.442 + if (aWidgetFlags) 1.443 + *aWidgetFlags = GTK_ORIENTATION_VERTICAL; 1.444 + aGtkWidgetType = MOZ_GTK_SCALE_THUMB_VERTICAL; 1.445 + break; 1.446 + case NS_THEME_TOOLBAR_GRIPPER: 1.447 + aGtkWidgetType = MOZ_GTK_GRIPPER; 1.448 + break; 1.449 + case NS_THEME_RESIZER: 1.450 + aGtkWidgetType = MOZ_GTK_RESIZER; 1.451 + break; 1.452 + case NS_THEME_NUMBER_INPUT: 1.453 + case NS_THEME_TEXTFIELD: 1.454 + case NS_THEME_TEXTFIELD_MULTILINE: 1.455 + aGtkWidgetType = MOZ_GTK_ENTRY; 1.456 + break; 1.457 + case NS_THEME_LISTBOX: 1.458 + case NS_THEME_TREEVIEW: 1.459 + aGtkWidgetType = MOZ_GTK_TREEVIEW; 1.460 + break; 1.461 + case NS_THEME_TREEVIEW_HEADER_CELL: 1.462 + if (aWidgetFlags) { 1.463 + // In this case, the flag denotes whether the header is the sorted one or not 1.464 + if (GetTreeSortDirection(aFrame) == eTreeSortDirection_Natural) 1.465 + *aWidgetFlags = false; 1.466 + else 1.467 + *aWidgetFlags = true; 1.468 + } 1.469 + aGtkWidgetType = MOZ_GTK_TREE_HEADER_CELL; 1.470 + break; 1.471 + case NS_THEME_TREEVIEW_HEADER_SORTARROW: 1.472 + if (aWidgetFlags) { 1.473 + switch (GetTreeSortDirection(aFrame)) { 1.474 + case eTreeSortDirection_Ascending: 1.475 + *aWidgetFlags = GTK_ARROW_DOWN; 1.476 + break; 1.477 + case eTreeSortDirection_Descending: 1.478 + *aWidgetFlags = GTK_ARROW_UP; 1.479 + break; 1.480 + case eTreeSortDirection_Natural: 1.481 + default: 1.482 + /* This prevents the treecolums from getting smaller 1.483 + * and wider when switching sort direction off and on 1.484 + * */ 1.485 + *aWidgetFlags = GTK_ARROW_NONE; 1.486 + break; 1.487 + } 1.488 + } 1.489 + aGtkWidgetType = MOZ_GTK_TREE_HEADER_SORTARROW; 1.490 + break; 1.491 + case NS_THEME_TREEVIEW_TWISTY: 1.492 + aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER; 1.493 + if (aWidgetFlags) 1.494 + *aWidgetFlags = GTK_EXPANDER_COLLAPSED; 1.495 + break; 1.496 + case NS_THEME_TREEVIEW_TWISTY_OPEN: 1.497 + aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER; 1.498 + if (aWidgetFlags) 1.499 + *aWidgetFlags = GTK_EXPANDER_EXPANDED; 1.500 + break; 1.501 + case NS_THEME_DROPDOWN: 1.502 + aGtkWidgetType = MOZ_GTK_DROPDOWN; 1.503 + if (aWidgetFlags) 1.504 + *aWidgetFlags = IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML); 1.505 + break; 1.506 + case NS_THEME_DROPDOWN_TEXT: 1.507 + return false; // nothing to do, but prevents the bg from being drawn 1.508 + case NS_THEME_DROPDOWN_TEXTFIELD: 1.509 + aGtkWidgetType = MOZ_GTK_DROPDOWN_ENTRY; 1.510 + break; 1.511 + case NS_THEME_DROPDOWN_BUTTON: 1.512 + aGtkWidgetType = MOZ_GTK_DROPDOWN_ARROW; 1.513 + break; 1.514 + case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: 1.515 + case NS_THEME_BUTTON_ARROW_DOWN: 1.516 + case NS_THEME_BUTTON_ARROW_UP: 1.517 + case NS_THEME_BUTTON_ARROW_NEXT: 1.518 + case NS_THEME_BUTTON_ARROW_PREVIOUS: 1.519 + aGtkWidgetType = MOZ_GTK_TOOLBARBUTTON_ARROW; 1.520 + if (aWidgetFlags) { 1.521 + *aWidgetFlags = GTK_ARROW_DOWN; 1.522 + 1.523 + if (aWidgetType == NS_THEME_BUTTON_ARROW_UP) 1.524 + *aWidgetFlags = GTK_ARROW_UP; 1.525 + else if (aWidgetType == NS_THEME_BUTTON_ARROW_NEXT) 1.526 + *aWidgetFlags = GTK_ARROW_RIGHT; 1.527 + else if (aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS) 1.528 + *aWidgetFlags = GTK_ARROW_LEFT; 1.529 + } 1.530 + break; 1.531 + case NS_THEME_CHECKBOX_CONTAINER: 1.532 + aGtkWidgetType = MOZ_GTK_CHECKBUTTON_CONTAINER; 1.533 + break; 1.534 + case NS_THEME_RADIO_CONTAINER: 1.535 + aGtkWidgetType = MOZ_GTK_RADIOBUTTON_CONTAINER; 1.536 + break; 1.537 + case NS_THEME_CHECKBOX_LABEL: 1.538 + aGtkWidgetType = MOZ_GTK_CHECKBUTTON_LABEL; 1.539 + break; 1.540 + case NS_THEME_RADIO_LABEL: 1.541 + aGtkWidgetType = MOZ_GTK_RADIOBUTTON_LABEL; 1.542 + break; 1.543 + case NS_THEME_TOOLBAR: 1.544 + aGtkWidgetType = MOZ_GTK_TOOLBAR; 1.545 + break; 1.546 + case NS_THEME_TOOLTIP: 1.547 + aGtkWidgetType = MOZ_GTK_TOOLTIP; 1.548 + break; 1.549 + case NS_THEME_STATUSBAR_PANEL: 1.550 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.551 + aGtkWidgetType = MOZ_GTK_FRAME; 1.552 + break; 1.553 + case NS_THEME_PROGRESSBAR: 1.554 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.555 + aGtkWidgetType = MOZ_GTK_PROGRESSBAR; 1.556 + break; 1.557 + case NS_THEME_PROGRESSBAR_CHUNK: 1.558 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.559 + { 1.560 + nsIFrame* stateFrame = aFrame->GetParent(); 1.561 + EventStates eventStates = GetContentState(stateFrame, aWidgetType); 1.562 + 1.563 + aGtkWidgetType = IsIndeterminateProgress(stateFrame, eventStates) 1.564 + ? (stateFrame->StyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL) 1.565 + ? MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE 1.566 + : MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE 1.567 + : MOZ_GTK_PROGRESS_CHUNK; 1.568 + } 1.569 + break; 1.570 + case NS_THEME_TAB_SCROLLARROW_BACK: 1.571 + case NS_THEME_TAB_SCROLLARROW_FORWARD: 1.572 + if (aWidgetFlags) 1.573 + *aWidgetFlags = aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK ? 1.574 + GTK_ARROW_LEFT : GTK_ARROW_RIGHT; 1.575 + aGtkWidgetType = MOZ_GTK_TAB_SCROLLARROW; 1.576 + break; 1.577 + case NS_THEME_TAB_PANELS: 1.578 + aGtkWidgetType = MOZ_GTK_TABPANELS; 1.579 + break; 1.580 + case NS_THEME_TAB: 1.581 + { 1.582 + if (aWidgetFlags) { 1.583 + /* First bits will be used to store max(0,-bmargin) where bmargin 1.584 + * is the bottom margin of the tab in pixels (resp. top margin, 1.585 + * for bottom tabs). */ 1.586 + if (IsBottomTab(aFrame)) { 1.587 + *aWidgetFlags = MOZ_GTK_TAB_BOTTOM; 1.588 + } else { 1.589 + *aWidgetFlags = 0; 1.590 + } 1.591 + 1.592 + *aWidgetFlags |= GetTabMarginPixels(aFrame); 1.593 + 1.594 + if (IsSelectedTab(aFrame)) 1.595 + *aWidgetFlags |= MOZ_GTK_TAB_SELECTED; 1.596 + 1.597 + if (IsFirstTab(aFrame)) 1.598 + *aWidgetFlags |= MOZ_GTK_TAB_FIRST; 1.599 + } 1.600 + 1.601 + aGtkWidgetType = MOZ_GTK_TAB; 1.602 + } 1.603 + break; 1.604 + case NS_THEME_SPLITTER: 1.605 + if (IsHorizontal(aFrame)) 1.606 + aGtkWidgetType = MOZ_GTK_SPLITTER_VERTICAL; 1.607 + else 1.608 + aGtkWidgetType = MOZ_GTK_SPLITTER_HORIZONTAL; 1.609 + break; 1.610 + case NS_THEME_MENUBAR: 1.611 + aGtkWidgetType = MOZ_GTK_MENUBAR; 1.612 + break; 1.613 + case NS_THEME_MENUPOPUP: 1.614 + aGtkWidgetType = MOZ_GTK_MENUPOPUP; 1.615 + break; 1.616 + case NS_THEME_MENUITEM: 1.617 + aGtkWidgetType = MOZ_GTK_MENUITEM; 1.618 + break; 1.619 + case NS_THEME_MENUSEPARATOR: 1.620 + aGtkWidgetType = MOZ_GTK_MENUSEPARATOR; 1.621 + break; 1.622 + case NS_THEME_MENUARROW: 1.623 + aGtkWidgetType = MOZ_GTK_MENUARROW; 1.624 + break; 1.625 + case NS_THEME_CHECKMENUITEM: 1.626 + aGtkWidgetType = MOZ_GTK_CHECKMENUITEM; 1.627 + break; 1.628 + case NS_THEME_RADIOMENUITEM: 1.629 + aGtkWidgetType = MOZ_GTK_RADIOMENUITEM; 1.630 + break; 1.631 + case NS_THEME_WINDOW: 1.632 + case NS_THEME_DIALOG: 1.633 + aGtkWidgetType = MOZ_GTK_WINDOW; 1.634 + break; 1.635 + default: 1.636 + return false; 1.637 + } 1.638 + 1.639 + return true; 1.640 +} 1.641 + 1.642 +#if (MOZ_WIDGET_GTK == 2) 1.643 +class ThemeRenderer : public gfxGdkNativeRenderer { 1.644 +public: 1.645 + ThemeRenderer(GtkWidgetState aState, GtkThemeWidgetType aGTKWidgetType, 1.646 + gint aFlags, GtkTextDirection aDirection, 1.647 + const GdkRectangle& aGDKRect, const GdkRectangle& aGDKClip) 1.648 + : mState(aState), mGTKWidgetType(aGTKWidgetType), mFlags(aFlags), 1.649 + mDirection(aDirection), mGDKRect(aGDKRect), mGDKClip(aGDKClip) {} 1.650 + nsresult DrawWithGDK(GdkDrawable * drawable, gint offsetX, gint offsetY, 1.651 + GdkRectangle * clipRects, uint32_t numClipRects); 1.652 +private: 1.653 + GtkWidgetState mState; 1.654 + GtkThemeWidgetType mGTKWidgetType; 1.655 + gint mFlags; 1.656 + GtkTextDirection mDirection; 1.657 + const GdkRectangle& mGDKRect; 1.658 + const GdkRectangle& mGDKClip; 1.659 +}; 1.660 + 1.661 +nsresult 1.662 +ThemeRenderer::DrawWithGDK(GdkDrawable * drawable, gint offsetX, 1.663 + gint offsetY, GdkRectangle * clipRects, uint32_t numClipRects) 1.664 +{ 1.665 + GdkRectangle gdk_rect = mGDKRect; 1.666 + gdk_rect.x += offsetX; 1.667 + gdk_rect.y += offsetY; 1.668 + 1.669 + GdkRectangle gdk_clip = mGDKClip; 1.670 + gdk_clip.x += offsetX; 1.671 + gdk_clip.y += offsetY; 1.672 + 1.673 + GdkRectangle surfaceRect; 1.674 + surfaceRect.x = 0; 1.675 + surfaceRect.y = 0; 1.676 + gdk_drawable_get_size(drawable, &surfaceRect.width, &surfaceRect.height); 1.677 + gdk_rectangle_intersect(&gdk_clip, &surfaceRect, &gdk_clip); 1.678 + 1.679 + NS_ASSERTION(numClipRects == 0, "We don't support clipping!!!"); 1.680 + moz_gtk_widget_paint(mGTKWidgetType, drawable, &gdk_rect, &gdk_clip, 1.681 + &mState, mFlags, mDirection); 1.682 + 1.683 + return NS_OK; 1.684 +} 1.685 +#endif 1.686 + 1.687 +bool 1.688 +nsNativeThemeGTK::GetExtraSizeForWidget(nsIFrame* aFrame, uint8_t aWidgetType, 1.689 + nsIntMargin* aExtra) 1.690 +{ 1.691 + *aExtra = nsIntMargin(0,0,0,0); 1.692 + // Allow an extra one pixel above and below the thumb for certain 1.693 + // GTK2 themes (Ximian Industrial, Bluecurve, Misty, at least); 1.694 + // We modify the frame's overflow area. See bug 297508. 1.695 + switch (aWidgetType) { 1.696 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.697 + aExtra->top = aExtra->bottom = 1; 1.698 + return true; 1.699 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.700 + aExtra->left = aExtra->right = 1; 1.701 + return true; 1.702 + 1.703 + // Include the indicator spacing (the padding around the control). 1.704 + case NS_THEME_CHECKBOX: 1.705 + case NS_THEME_RADIO: 1.706 + { 1.707 + gint indicator_size, indicator_spacing; 1.708 + 1.709 + if (aWidgetType == NS_THEME_CHECKBOX) { 1.710 + moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); 1.711 + } else { 1.712 + moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); 1.713 + } 1.714 + 1.715 + aExtra->top = indicator_spacing; 1.716 + aExtra->right = indicator_spacing; 1.717 + aExtra->bottom = indicator_spacing; 1.718 + aExtra->left = indicator_spacing; 1.719 + return true; 1.720 + } 1.721 + case NS_THEME_BUTTON : 1.722 + { 1.723 + if (IsDefaultButton(aFrame)) { 1.724 + // Some themes draw a default indicator outside the widget, 1.725 + // include that in overflow 1.726 + gint top, left, bottom, right; 1.727 + moz_gtk_button_get_default_overflow(&top, &left, &bottom, &right); 1.728 + aExtra->top = top; 1.729 + aExtra->right = right; 1.730 + aExtra->bottom = bottom; 1.731 + aExtra->left = left; 1.732 + return true; 1.733 + } 1.734 + } 1.735 + case NS_THEME_TAB : 1.736 + { 1.737 + if (!IsSelectedTab(aFrame)) 1.738 + return false; 1.739 + 1.740 + gint gap_height = moz_gtk_get_tab_thickness(); 1.741 + 1.742 + int32_t extra = gap_height - GetTabMarginPixels(aFrame); 1.743 + if (extra <= 0) 1.744 + return false; 1.745 + 1.746 + if (IsBottomTab(aFrame)) { 1.747 + aExtra->top = extra; 1.748 + } else { 1.749 + aExtra->bottom = extra; 1.750 + } 1.751 + } 1.752 + default: 1.753 + return false; 1.754 + } 1.755 +} 1.756 + 1.757 +NS_IMETHODIMP 1.758 +nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext, 1.759 + nsIFrame* aFrame, 1.760 + uint8_t aWidgetType, 1.761 + const nsRect& aRect, 1.762 + const nsRect& aDirtyRect) 1.763 +{ 1.764 + GtkWidgetState state; 1.765 + GtkThemeWidgetType gtkWidgetType; 1.766 + GtkTextDirection direction = GetTextDirection(aFrame); 1.767 + gint flags; 1.768 + if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state, 1.769 + &flags)) 1.770 + return NS_OK; 1.771 + 1.772 + gfxContext* ctx = aContext->ThebesContext(); 1.773 + nsPresContext *presContext = aFrame->PresContext(); 1.774 + 1.775 + gfxRect rect = presContext->AppUnitsToGfxUnits(aRect); 1.776 + gfxRect dirtyRect = presContext->AppUnitsToGfxUnits(aDirtyRect); 1.777 + 1.778 + // Align to device pixels where sensible 1.779 + // to provide crisper and faster drawing. 1.780 + // Don't snap if it's a non-unit scale factor. We're going to have to take 1.781 + // slow paths then in any case. 1.782 + bool snapXY = ctx->UserToDevicePixelSnapped(rect); 1.783 + if (snapXY) { 1.784 + // Leave rect in device coords but make dirtyRect consistent. 1.785 + dirtyRect = ctx->UserToDevice(dirtyRect); 1.786 + } 1.787 + 1.788 + // Translate the dirty rect so that it is wrt the widget top-left. 1.789 + dirtyRect.MoveBy(-rect.TopLeft()); 1.790 + // Round out the dirty rect to gdk pixels to ensure that gtk draws 1.791 + // enough pixels for interpolation to device pixels. 1.792 + dirtyRect.RoundOut(); 1.793 + 1.794 + // GTK themes can only draw an integer number of pixels 1.795 + // (even when not snapped). 1.796 + nsIntRect widgetRect(0, 0, NS_lround(rect.Width()), NS_lround(rect.Height())); 1.797 + nsIntRect overflowRect(widgetRect); 1.798 + nsIntMargin extraSize; 1.799 + if (GetExtraSizeForWidget(aFrame, aWidgetType, &extraSize)) { 1.800 + overflowRect.Inflate(extraSize); 1.801 + } 1.802 + 1.803 + // This is the rectangle that will actually be drawn, in gdk pixels 1.804 + nsIntRect drawingRect(int32_t(dirtyRect.X()), 1.805 + int32_t(dirtyRect.Y()), 1.806 + int32_t(dirtyRect.Width()), 1.807 + int32_t(dirtyRect.Height())); 1.808 + if (widgetRect.IsEmpty() 1.809 + || !drawingRect.IntersectRect(overflowRect, drawingRect)) 1.810 + return NS_OK; 1.811 + 1.812 + // gdk rectangles are wrt the drawing rect. 1.813 + 1.814 + GdkRectangle gdk_rect = {-drawingRect.x, -drawingRect.y, 1.815 + widgetRect.width, widgetRect.height}; 1.816 + 1.817 + // translate everything so (0,0) is the top left of the drawingRect 1.818 + gfxContextAutoSaveRestore autoSR(ctx); 1.819 + if (snapXY) { 1.820 + // Rects are in device coords. 1.821 + ctx->IdentityMatrix(); 1.822 + } 1.823 + ctx->Translate(rect.TopLeft() + gfxPoint(drawingRect.x, drawingRect.y)); 1.824 + 1.825 + NS_ASSERTION(!IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType), 1.826 + "Trying to render an unsafe widget!"); 1.827 + 1.828 + bool safeState = IsWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state); 1.829 + if (!safeState) { 1.830 + gLastGdkError = 0; 1.831 + gdk_error_trap_push (); 1.832 + } 1.833 + 1.834 +#if (MOZ_WIDGET_GTK == 2) 1.835 + // The gdk_clip is just advisory here, meaning "you don't 1.836 + // need to draw outside this rect if you don't feel like it!" 1.837 + GdkRectangle gdk_clip = {0, 0, drawingRect.width, drawingRect.height}; 1.838 + 1.839 + ThemeRenderer renderer(state, gtkWidgetType, flags, direction, 1.840 + gdk_rect, gdk_clip); 1.841 + 1.842 + // Some themes (e.g. Clearlooks) just don't clip properly to any 1.843 + // clip rect we provide, so we cannot advertise support for clipping within 1.844 + // the widget bounds. 1.845 + uint32_t rendererFlags = 0; 1.846 + if (GetWidgetTransparency(aFrame, aWidgetType) == eOpaque) { 1.847 + rendererFlags |= gfxGdkNativeRenderer::DRAW_IS_OPAQUE; 1.848 + } 1.849 + 1.850 + // GtkStyles (used by the widget drawing backend) are created for a 1.851 + // particular colormap/visual. 1.852 + GdkColormap* colormap = moz_gtk_widget_get_colormap(); 1.853 + 1.854 + renderer.Draw(ctx, drawingRect.Size(), rendererFlags, colormap); 1.855 +#else 1.856 + moz_gtk_widget_paint(gtkWidgetType, ctx->GetCairo(), &gdk_rect, 1.857 + &state, flags, direction); 1.858 +#endif 1.859 + 1.860 + if (!safeState) { 1.861 + gdk_flush(); 1.862 + gLastGdkError = gdk_error_trap_pop (); 1.863 + 1.864 + if (gLastGdkError) { 1.865 +#ifdef DEBUG 1.866 + printf("GTK theme failed for widget type %d, error was %d, state was " 1.867 + "[active=%d,focused=%d,inHover=%d,disabled=%d]\n", 1.868 + aWidgetType, gLastGdkError, state.active, state.focused, 1.869 + state.inHover, state.disabled); 1.870 +#endif 1.871 + NS_WARNING("GTK theme failed; disabling unsafe widget"); 1.872 + SetWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType); 1.873 + // force refresh of the window, because the widget was not 1.874 + // successfully drawn it must be redrawn using the default look 1.875 + RefreshWidgetWindow(aFrame); 1.876 + } else { 1.877 + SetWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state); 1.878 + } 1.879 + } 1.880 + 1.881 + // Indeterminate progress bar are animated. 1.882 + if (gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || 1.883 + gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { 1.884 + if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) { 1.885 + NS_WARNING("unable to animate widget!"); 1.886 + } 1.887 + } 1.888 + 1.889 + return NS_OK; 1.890 +} 1.891 + 1.892 +NS_IMETHODIMP 1.893 +nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, 1.894 + uint8_t aWidgetType, nsIntMargin* aResult) 1.895 +{ 1.896 + GtkTextDirection direction = GetTextDirection(aFrame); 1.897 + aResult->top = aResult->left = aResult->right = aResult->bottom = 0; 1.898 + switch (aWidgetType) { 1.899 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.900 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.901 + { 1.902 + MozGtkScrollbarMetrics metrics; 1.903 + moz_gtk_get_scrollbar_metrics(&metrics); 1.904 + aResult->top = aResult->left = aResult->right = aResult->bottom = metrics.trough_border; 1.905 + } 1.906 + break; 1.907 + case NS_THEME_TOOLBOX: 1.908 + // gtk has no toolbox equivalent. So, although we map toolbox to 1.909 + // gtk's 'toolbar' for purposes of painting the widget background, 1.910 + // we don't use the toolbar border for toolbox. 1.911 + break; 1.912 + case NS_THEME_TOOLBAR_DUAL_BUTTON: 1.913 + // TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw 1.914 + // around the entire button + dropdown, and also an inner border if you're 1.915 + // over the button part. But, we want the inner button to be right up 1.916 + // against the edge of the outer button so that the borders overlap. 1.917 + // To make this happen, we draw a button border for the outer button, 1.918 + // but don't reserve any space for it. 1.919 + break; 1.920 + case NS_THEME_TAB: 1.921 + // Top tabs have no bottom border, bottom tabs have no top border 1.922 + moz_gtk_get_widget_border(MOZ_GTK_TAB, &aResult->left, &aResult->top, 1.923 + &aResult->right, &aResult->bottom, direction, 1.924 + FALSE); 1.925 + if (IsBottomTab(aFrame)) 1.926 + aResult->top = 0; 1.927 + else 1.928 + aResult->bottom = 0; 1.929 + break; 1.930 + case NS_THEME_MENUITEM: 1.931 + case NS_THEME_CHECKMENUITEM: 1.932 + case NS_THEME_RADIOMENUITEM: 1.933 + // For regular menuitems, we will be using GetWidgetPadding instead of 1.934 + // GetWidgetBorder to pad up the widget's internals; other menuitems 1.935 + // will need to fall through and use the default case as before. 1.936 + if (IsRegularMenuItem(aFrame)) 1.937 + break; 1.938 + default: 1.939 + { 1.940 + GtkThemeWidgetType gtkWidgetType; 1.941 + if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr, 1.942 + nullptr)) { 1.943 + moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top, 1.944 + &aResult->right, &aResult->bottom, direction, 1.945 + IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML)); 1.946 + } 1.947 + } 1.948 + } 1.949 + return NS_OK; 1.950 +} 1.951 + 1.952 +bool 1.953 +nsNativeThemeGTK::GetWidgetPadding(nsDeviceContext* aContext, 1.954 + nsIFrame* aFrame, uint8_t aWidgetType, 1.955 + nsIntMargin* aResult) 1.956 +{ 1.957 + switch (aWidgetType) { 1.958 + case NS_THEME_BUTTON_FOCUS: 1.959 + case NS_THEME_TOOLBAR_BUTTON: 1.960 + case NS_THEME_TOOLBAR_DUAL_BUTTON: 1.961 + case NS_THEME_TAB_SCROLLARROW_BACK: 1.962 + case NS_THEME_TAB_SCROLLARROW_FORWARD: 1.963 + case NS_THEME_DROPDOWN_BUTTON: 1.964 + case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: 1.965 + case NS_THEME_BUTTON_ARROW_UP: 1.966 + case NS_THEME_BUTTON_ARROW_DOWN: 1.967 + case NS_THEME_BUTTON_ARROW_NEXT: 1.968 + case NS_THEME_BUTTON_ARROW_PREVIOUS: 1.969 + case NS_THEME_RANGE_THUMB: 1.970 + // Radios and checkboxes return a fixed size in GetMinimumWidgetSize 1.971 + // and have a meaningful baseline, so they can't have 1.972 + // author-specified padding. 1.973 + case NS_THEME_CHECKBOX: 1.974 + case NS_THEME_RADIO: 1.975 + aResult->SizeTo(0, 0, 0, 0); 1.976 + return true; 1.977 + case NS_THEME_MENUITEM: 1.978 + case NS_THEME_CHECKMENUITEM: 1.979 + case NS_THEME_RADIOMENUITEM: 1.980 + { 1.981 + // Menubar and menulist have their padding specified in CSS. 1.982 + if (!IsRegularMenuItem(aFrame)) 1.983 + return false; 1.984 + 1.985 + aResult->SizeTo(0, 0, 0, 0); 1.986 + GtkThemeWidgetType gtkWidgetType; 1.987 + if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr, 1.988 + nullptr)) { 1.989 + moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top, 1.990 + &aResult->right, &aResult->bottom, GetTextDirection(aFrame), 1.991 + IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML)); 1.992 + } 1.993 + 1.994 + gint horizontal_padding; 1.995 + 1.996 + if (aWidgetType == NS_THEME_MENUITEM) 1.997 + moz_gtk_menuitem_get_horizontal_padding(&horizontal_padding); 1.998 + else 1.999 + moz_gtk_checkmenuitem_get_horizontal_padding(&horizontal_padding); 1.1000 + 1.1001 + aResult->left += horizontal_padding; 1.1002 + aResult->right += horizontal_padding; 1.1003 + 1.1004 + return true; 1.1005 + } 1.1006 + } 1.1007 + 1.1008 + return false; 1.1009 +} 1.1010 + 1.1011 +bool 1.1012 +nsNativeThemeGTK::GetWidgetOverflow(nsDeviceContext* aContext, 1.1013 + nsIFrame* aFrame, uint8_t aWidgetType, 1.1014 + nsRect* aOverflowRect) 1.1015 +{ 1.1016 + nsIntMargin extraSize; 1.1017 + if (!GetExtraSizeForWidget(aFrame, aWidgetType, &extraSize)) 1.1018 + return false; 1.1019 + 1.1020 + int32_t p2a = aContext->AppUnitsPerDevPixel(); 1.1021 + nsMargin m(NSIntPixelsToAppUnits(extraSize.top, p2a), 1.1022 + NSIntPixelsToAppUnits(extraSize.right, p2a), 1.1023 + NSIntPixelsToAppUnits(extraSize.bottom, p2a), 1.1024 + NSIntPixelsToAppUnits(extraSize.left, p2a)); 1.1025 + 1.1026 + aOverflowRect->Inflate(m); 1.1027 + return true; 1.1028 +} 1.1029 + 1.1030 +NS_IMETHODIMP 1.1031 +nsNativeThemeGTK::GetMinimumWidgetSize(nsRenderingContext* aContext, 1.1032 + nsIFrame* aFrame, uint8_t aWidgetType, 1.1033 + nsIntSize* aResult, bool* aIsOverridable) 1.1034 +{ 1.1035 + aResult->width = aResult->height = 0; 1.1036 + *aIsOverridable = true; 1.1037 + 1.1038 + switch (aWidgetType) { 1.1039 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.1040 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.1041 + { 1.1042 + MozGtkScrollbarMetrics metrics; 1.1043 + moz_gtk_get_scrollbar_metrics(&metrics); 1.1044 + 1.1045 + aResult->width = metrics.slider_width; 1.1046 + aResult->height = metrics.stepper_size; 1.1047 + *aIsOverridable = false; 1.1048 + } 1.1049 + break; 1.1050 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.1051 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.1052 + { 1.1053 + MozGtkScrollbarMetrics metrics; 1.1054 + moz_gtk_get_scrollbar_metrics(&metrics); 1.1055 + 1.1056 + aResult->width = metrics.stepper_size; 1.1057 + aResult->height = metrics.slider_width; 1.1058 + *aIsOverridable = false; 1.1059 + } 1.1060 + break; 1.1061 + case NS_THEME_SPLITTER: 1.1062 + { 1.1063 + gint metrics; 1.1064 + if (IsHorizontal(aFrame)) { 1.1065 + moz_gtk_splitter_get_metrics(GTK_ORIENTATION_HORIZONTAL, &metrics); 1.1066 + aResult->width = metrics; 1.1067 + aResult->height = 0; 1.1068 + } else { 1.1069 + moz_gtk_splitter_get_metrics(GTK_ORIENTATION_VERTICAL, &metrics); 1.1070 + aResult->width = 0; 1.1071 + aResult->height = metrics; 1.1072 + } 1.1073 + *aIsOverridable = false; 1.1074 + } 1.1075 + break; 1.1076 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.1077 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.1078 + { 1.1079 + /* While we enforce a minimum size for the thumb, this is ignored 1.1080 + * for the some scrollbars if buttons are hidden (bug 513006) because 1.1081 + * the thumb isn't a direct child of the scrollbar, unlike the buttons 1.1082 + * or track. So add a minimum size to the track as well to prevent a 1.1083 + * 0-width scrollbar. */ 1.1084 + MozGtkScrollbarMetrics metrics; 1.1085 + moz_gtk_get_scrollbar_metrics(&metrics); 1.1086 + 1.1087 + if (aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL) 1.1088 + aResult->width = metrics.slider_width + 2 * metrics.trough_border; 1.1089 + else 1.1090 + aResult->height = metrics.slider_width + 2 * metrics.trough_border; 1.1091 + 1.1092 + *aIsOverridable = false; 1.1093 + } 1.1094 + break; 1.1095 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.1096 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.1097 + { 1.1098 + MozGtkScrollbarMetrics metrics; 1.1099 + moz_gtk_get_scrollbar_metrics(&metrics); 1.1100 + 1.1101 + nsRect rect = aFrame->GetParent()->GetRect(); 1.1102 + int32_t p2a = aFrame->PresContext()->DeviceContext()-> 1.1103 + AppUnitsPerDevPixel(); 1.1104 + nsMargin margin; 1.1105 + 1.1106 + /* Get the available space, if that is smaller then the minimum size, 1.1107 + * adjust the mininum size to fit into it. 1.1108 + * Setting aIsOverridable to true has no effect for thumbs. */ 1.1109 + aFrame->GetMargin(margin); 1.1110 + rect.Deflate(margin); 1.1111 + aFrame->GetParent()->GetBorderAndPadding(margin); 1.1112 + rect.Deflate(margin); 1.1113 + 1.1114 + if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) { 1.1115 + aResult->width = metrics.slider_width; 1.1116 + aResult->height = std::min(NSAppUnitsToIntPixels(rect.height, p2a), 1.1117 + metrics.min_slider_size); 1.1118 + } else { 1.1119 + aResult->height = metrics.slider_width; 1.1120 + aResult->width = std::min(NSAppUnitsToIntPixels(rect.width, p2a), 1.1121 + metrics.min_slider_size); 1.1122 + } 1.1123 + 1.1124 + *aIsOverridable = false; 1.1125 + } 1.1126 + break; 1.1127 + case NS_THEME_RANGE_THUMB: 1.1128 + { 1.1129 + gint thumb_length, thumb_height; 1.1130 + 1.1131 + if (IsRangeHorizontal(aFrame)) { 1.1132 + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height); 1.1133 + } else { 1.1134 + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_length); 1.1135 + } 1.1136 + aResult->width = thumb_length; 1.1137 + aResult->height = thumb_height; 1.1138 + 1.1139 + *aIsOverridable = false; 1.1140 + } 1.1141 + break; 1.1142 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.1143 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.1144 + { 1.1145 + gint thumb_length, thumb_height; 1.1146 + 1.1147 + if (aWidgetType == NS_THEME_SCALE_THUMB_VERTICAL) { 1.1148 + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_length, &thumb_height); 1.1149 + aResult->width = thumb_height; 1.1150 + aResult->height = thumb_length; 1.1151 + } else { 1.1152 + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height); 1.1153 + aResult->width = thumb_length; 1.1154 + aResult->height = thumb_height; 1.1155 + } 1.1156 + 1.1157 + *aIsOverridable = false; 1.1158 + } 1.1159 + break; 1.1160 + case NS_THEME_TAB_SCROLLARROW_BACK: 1.1161 + case NS_THEME_TAB_SCROLLARROW_FORWARD: 1.1162 + { 1.1163 + moz_gtk_get_tab_scroll_arrow_size(&aResult->width, &aResult->height); 1.1164 + *aIsOverridable = false; 1.1165 + } 1.1166 + break; 1.1167 + case NS_THEME_DROPDOWN_BUTTON: 1.1168 + { 1.1169 + moz_gtk_get_combo_box_entry_button_size(&aResult->width, 1.1170 + &aResult->height); 1.1171 + *aIsOverridable = false; 1.1172 + } 1.1173 + break; 1.1174 + case NS_THEME_MENUSEPARATOR: 1.1175 + { 1.1176 + gint separator_height; 1.1177 + 1.1178 + moz_gtk_get_menu_separator_height(&separator_height); 1.1179 + aResult->height = separator_height; 1.1180 + 1.1181 + *aIsOverridable = false; 1.1182 + } 1.1183 + break; 1.1184 + case NS_THEME_CHECKBOX: 1.1185 + case NS_THEME_RADIO: 1.1186 + { 1.1187 + gint indicator_size, indicator_spacing; 1.1188 + 1.1189 + if (aWidgetType == NS_THEME_CHECKBOX) { 1.1190 + moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); 1.1191 + } else { 1.1192 + moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); 1.1193 + } 1.1194 + 1.1195 + // Include space for the indicator and the padding around it. 1.1196 + aResult->width = indicator_size; 1.1197 + aResult->height = indicator_size; 1.1198 + } 1.1199 + break; 1.1200 + case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: 1.1201 + case NS_THEME_BUTTON_ARROW_UP: 1.1202 + case NS_THEME_BUTTON_ARROW_DOWN: 1.1203 + case NS_THEME_BUTTON_ARROW_NEXT: 1.1204 + case NS_THEME_BUTTON_ARROW_PREVIOUS: 1.1205 + { 1.1206 + moz_gtk_get_arrow_size(&aResult->width, &aResult->height); 1.1207 + *aIsOverridable = false; 1.1208 + } 1.1209 + break; 1.1210 + case NS_THEME_CHECKBOX_CONTAINER: 1.1211 + case NS_THEME_RADIO_CONTAINER: 1.1212 + case NS_THEME_CHECKBOX_LABEL: 1.1213 + case NS_THEME_RADIO_LABEL: 1.1214 + case NS_THEME_BUTTON: 1.1215 + case NS_THEME_DROPDOWN: 1.1216 + case NS_THEME_TOOLBAR_BUTTON: 1.1217 + case NS_THEME_TREEVIEW_HEADER_CELL: 1.1218 + { 1.1219 + // Just include our border, and let the box code augment the size. 1.1220 + nsIntMargin border; 1.1221 + nsNativeThemeGTK::GetWidgetBorder(aContext->DeviceContext(), 1.1222 + aFrame, aWidgetType, &border); 1.1223 + aResult->width = border.left + border.right; 1.1224 + aResult->height = border.top + border.bottom; 1.1225 + } 1.1226 + break; 1.1227 + case NS_THEME_TOOLBAR_SEPARATOR: 1.1228 + { 1.1229 + gint separator_width; 1.1230 + 1.1231 + moz_gtk_get_toolbar_separator_width(&separator_width); 1.1232 + 1.1233 + aResult->width = separator_width; 1.1234 + } 1.1235 + break; 1.1236 + case NS_THEME_SPINNER: 1.1237 + // hard code these sizes 1.1238 + aResult->width = 14; 1.1239 + aResult->height = 26; 1.1240 + break; 1.1241 + case NS_THEME_TREEVIEW_HEADER_SORTARROW: 1.1242 + case NS_THEME_SPINNER_UP_BUTTON: 1.1243 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.1244 + // hard code these sizes 1.1245 + aResult->width = 14; 1.1246 + aResult->height = 13; 1.1247 + break; 1.1248 + case NS_THEME_RESIZER: 1.1249 + // same as Windows to make our lives easier 1.1250 + aResult->width = aResult->height = 15; 1.1251 + *aIsOverridable = false; 1.1252 + break; 1.1253 + case NS_THEME_TREEVIEW_TWISTY: 1.1254 + case NS_THEME_TREEVIEW_TWISTY_OPEN: 1.1255 + { 1.1256 + gint expander_size; 1.1257 + 1.1258 + moz_gtk_get_treeview_expander_size(&expander_size); 1.1259 + aResult->width = aResult->height = expander_size; 1.1260 + *aIsOverridable = false; 1.1261 + } 1.1262 + break; 1.1263 + } 1.1264 + return NS_OK; 1.1265 +} 1.1266 + 1.1267 +NS_IMETHODIMP 1.1268 +nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, 1.1269 + nsIAtom* aAttribute, bool* aShouldRepaint) 1.1270 +{ 1.1271 + // Some widget types just never change state. 1.1272 + if (aWidgetType == NS_THEME_TOOLBOX || 1.1273 + aWidgetType == NS_THEME_TOOLBAR || 1.1274 + aWidgetType == NS_THEME_STATUSBAR || 1.1275 + aWidgetType == NS_THEME_STATUSBAR_PANEL || 1.1276 + aWidgetType == NS_THEME_STATUSBAR_RESIZER_PANEL || 1.1277 + aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || 1.1278 + aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || 1.1279 + aWidgetType == NS_THEME_PROGRESSBAR || 1.1280 + aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL || 1.1281 + aWidgetType == NS_THEME_MENUBAR || 1.1282 + aWidgetType == NS_THEME_MENUPOPUP || 1.1283 + aWidgetType == NS_THEME_TOOLTIP || 1.1284 + aWidgetType == NS_THEME_MENUSEPARATOR || 1.1285 + aWidgetType == NS_THEME_WINDOW || 1.1286 + aWidgetType == NS_THEME_DIALOG) { 1.1287 + *aShouldRepaint = false; 1.1288 + return NS_OK; 1.1289 + } 1.1290 + 1.1291 + if ((aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP || 1.1292 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN || 1.1293 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || 1.1294 + aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT) && 1.1295 + (aAttribute == nsGkAtoms::curpos || 1.1296 + aAttribute == nsGkAtoms::maxpos)) { 1.1297 + *aShouldRepaint = true; 1.1298 + return NS_OK; 1.1299 + } 1.1300 + 1.1301 + // XXXdwh Not sure what can really be done here. Can at least guess for 1.1302 + // specific widgets that they're highly unlikely to have certain states. 1.1303 + // For example, a toolbar doesn't care about any states. 1.1304 + if (!aAttribute) { 1.1305 + // Hover/focus/active changed. Always repaint. 1.1306 + *aShouldRepaint = true; 1.1307 + } 1.1308 + else { 1.1309 + // Check the attribute to see if it's relevant. 1.1310 + // disabled, checked, dlgtype, default, etc. 1.1311 + *aShouldRepaint = false; 1.1312 + if (aAttribute == nsGkAtoms::disabled || 1.1313 + aAttribute == nsGkAtoms::checked || 1.1314 + aAttribute == nsGkAtoms::selected || 1.1315 + aAttribute == nsGkAtoms::focused || 1.1316 + aAttribute == nsGkAtoms::readonly || 1.1317 + aAttribute == nsGkAtoms::_default || 1.1318 + aAttribute == nsGkAtoms::menuactive || 1.1319 + aAttribute == nsGkAtoms::open || 1.1320 + aAttribute == nsGkAtoms::parentfocused) 1.1321 + *aShouldRepaint = true; 1.1322 + } 1.1323 + 1.1324 + return NS_OK; 1.1325 +} 1.1326 + 1.1327 +NS_IMETHODIMP 1.1328 +nsNativeThemeGTK::ThemeChanged() 1.1329 +{ 1.1330 + memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes)); 1.1331 + return NS_OK; 1.1332 +} 1.1333 + 1.1334 +NS_IMETHODIMP_(bool) 1.1335 +nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext, 1.1336 + nsIFrame* aFrame, 1.1337 + uint8_t aWidgetType) 1.1338 +{ 1.1339 + if (IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType)) 1.1340 + return false; 1.1341 + 1.1342 + switch (aWidgetType) { 1.1343 + case NS_THEME_BUTTON: 1.1344 + case NS_THEME_BUTTON_FOCUS: 1.1345 + case NS_THEME_RADIO: 1.1346 + case NS_THEME_CHECKBOX: 1.1347 + case NS_THEME_TOOLBOX: // N/A 1.1348 + case NS_THEME_TOOLBAR: 1.1349 + case NS_THEME_TOOLBAR_BUTTON: 1.1350 + case NS_THEME_TOOLBAR_DUAL_BUTTON: // so we can override the border with 0 1.1351 + case NS_THEME_TOOLBAR_BUTTON_DROPDOWN: 1.1352 + case NS_THEME_BUTTON_ARROW_UP: 1.1353 + case NS_THEME_BUTTON_ARROW_DOWN: 1.1354 + case NS_THEME_BUTTON_ARROW_NEXT: 1.1355 + case NS_THEME_BUTTON_ARROW_PREVIOUS: 1.1356 + case NS_THEME_TOOLBAR_SEPARATOR: 1.1357 + case NS_THEME_TOOLBAR_GRIPPER: 1.1358 + case NS_THEME_STATUSBAR: 1.1359 + case NS_THEME_STATUSBAR_PANEL: 1.1360 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.1361 + case NS_THEME_RESIZER: 1.1362 + case NS_THEME_LISTBOX: 1.1363 + // case NS_THEME_LISTBOX_LISTITEM: 1.1364 + case NS_THEME_TREEVIEW: 1.1365 + // case NS_THEME_TREEVIEW_TREEITEM: 1.1366 + case NS_THEME_TREEVIEW_TWISTY: 1.1367 + // case NS_THEME_TREEVIEW_LINE: 1.1368 + // case NS_THEME_TREEVIEW_HEADER: 1.1369 + case NS_THEME_TREEVIEW_HEADER_CELL: 1.1370 + case NS_THEME_TREEVIEW_HEADER_SORTARROW: 1.1371 + case NS_THEME_TREEVIEW_TWISTY_OPEN: 1.1372 + case NS_THEME_PROGRESSBAR: 1.1373 + case NS_THEME_PROGRESSBAR_CHUNK: 1.1374 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.1375 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.1376 + case NS_THEME_TAB: 1.1377 + // case NS_THEME_TAB_PANEL: 1.1378 + case NS_THEME_TAB_PANELS: 1.1379 + case NS_THEME_TAB_SCROLLARROW_BACK: 1.1380 + case NS_THEME_TAB_SCROLLARROW_FORWARD: 1.1381 + case NS_THEME_TOOLTIP: 1.1382 + case NS_THEME_SPINNER: 1.1383 + case NS_THEME_SPINNER_UP_BUTTON: 1.1384 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.1385 + case NS_THEME_SPINNER_TEXTFIELD: 1.1386 + // case NS_THEME_SCROLLBAR: (n/a for gtk) 1.1387 + // case NS_THEME_SCROLLBAR_SMALL: (n/a for gtk) 1.1388 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.1389 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.1390 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.1391 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.1392 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.1393 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.1394 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.1395 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.1396 + case NS_THEME_NUMBER_INPUT: 1.1397 + case NS_THEME_TEXTFIELD: 1.1398 + case NS_THEME_TEXTFIELD_MULTILINE: 1.1399 + case NS_THEME_DROPDOWN_TEXTFIELD: 1.1400 + case NS_THEME_RANGE: 1.1401 + case NS_THEME_RANGE_THUMB: 1.1402 + case NS_THEME_SCALE_HORIZONTAL: 1.1403 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.1404 + case NS_THEME_SCALE_VERTICAL: 1.1405 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.1406 + // case NS_THEME_SCALE_THUMB_START: 1.1407 + // case NS_THEME_SCALE_THUMB_END: 1.1408 + // case NS_THEME_SCALE_TICK: 1.1409 + case NS_THEME_CHECKBOX_CONTAINER: 1.1410 + case NS_THEME_RADIO_CONTAINER: 1.1411 + case NS_THEME_CHECKBOX_LABEL: 1.1412 + case NS_THEME_RADIO_LABEL: 1.1413 + case NS_THEME_MENUBAR: 1.1414 + case NS_THEME_MENUPOPUP: 1.1415 + case NS_THEME_MENUITEM: 1.1416 + case NS_THEME_MENUARROW: 1.1417 + case NS_THEME_MENUSEPARATOR: 1.1418 + case NS_THEME_CHECKMENUITEM: 1.1419 + case NS_THEME_RADIOMENUITEM: 1.1420 + case NS_THEME_SPLITTER: 1.1421 + case NS_THEME_WINDOW: 1.1422 + case NS_THEME_DIALOG: 1.1423 + case NS_THEME_DROPDOWN: 1.1424 + case NS_THEME_DROPDOWN_TEXT: 1.1425 + return !IsWidgetStyled(aPresContext, aFrame, aWidgetType); 1.1426 + 1.1427 + case NS_THEME_DROPDOWN_BUTTON: 1.1428 + // "Native" dropdown buttons cause padding and margin problems, but only 1.1429 + // in HTML so allow them in XUL. 1.1430 + return (!aFrame || IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) && 1.1431 + !IsWidgetStyled(aPresContext, aFrame, aWidgetType); 1.1432 + 1.1433 + } 1.1434 + 1.1435 + return false; 1.1436 +} 1.1437 + 1.1438 +NS_IMETHODIMP_(bool) 1.1439 +nsNativeThemeGTK::WidgetIsContainer(uint8_t aWidgetType) 1.1440 +{ 1.1441 + // XXXdwh At some point flesh all of this out. 1.1442 + if (aWidgetType == NS_THEME_DROPDOWN_BUTTON || 1.1443 + aWidgetType == NS_THEME_RADIO || 1.1444 + aWidgetType == NS_THEME_RANGE_THUMB || 1.1445 + aWidgetType == NS_THEME_CHECKBOX || 1.1446 + aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK || 1.1447 + aWidgetType == NS_THEME_TAB_SCROLLARROW_FORWARD || 1.1448 + aWidgetType == NS_THEME_BUTTON_ARROW_UP || 1.1449 + aWidgetType == NS_THEME_BUTTON_ARROW_DOWN || 1.1450 + aWidgetType == NS_THEME_BUTTON_ARROW_NEXT || 1.1451 + aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS) 1.1452 + return false; 1.1453 + return true; 1.1454 +} 1.1455 + 1.1456 +bool 1.1457 +nsNativeThemeGTK::ThemeDrawsFocusForWidget(uint8_t aWidgetType) 1.1458 +{ 1.1459 + if (aWidgetType == NS_THEME_DROPDOWN || 1.1460 + aWidgetType == NS_THEME_BUTTON || 1.1461 + aWidgetType == NS_THEME_TREEVIEW_HEADER_CELL) 1.1462 + return true; 1.1463 + 1.1464 + return false; 1.1465 +} 1.1466 + 1.1467 +bool 1.1468 +nsNativeThemeGTK::ThemeNeedsComboboxDropmarker() 1.1469 +{ 1.1470 + return false; 1.1471 +} 1.1472 + 1.1473 +nsITheme::Transparency 1.1474 +nsNativeThemeGTK::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) 1.1475 +{ 1.1476 + switch (aWidgetType) { 1.1477 + // These widgets always draw a default background. 1.1478 +#if (MOZ_WIDGET_GTK == 2) 1.1479 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.1480 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.1481 + case NS_THEME_TOOLBAR: 1.1482 + case NS_THEME_MENUBAR: 1.1483 +#endif 1.1484 + case NS_THEME_MENUPOPUP: 1.1485 + case NS_THEME_WINDOW: 1.1486 + case NS_THEME_DIALOG: 1.1487 + // Tooltips use gtk_paint_flat_box(). 1.1488 + case NS_THEME_TOOLTIP: 1.1489 + return eOpaque; 1.1490 + } 1.1491 + 1.1492 + return eUnknownTransparency; 1.1493 +}