2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2002
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Brian Ryner <bryner@brianryner.com> (Original Author)
|
2007-06-04 20:26:43 -07:00
|
|
|
* Michael Ventnor <m.ventnor@gmail.com>
|
2007-12-04 17:09:29 -08:00
|
|
|
* Teune van Steeg <t.vansteeg@gmail.com>
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsNativeThemeGTK.h"
|
|
|
|
#include "nsThemeConstants.h"
|
|
|
|
#include "gtkdrawing.h"
|
|
|
|
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIEventStateManager.h"
|
|
|
|
#include "nsIViewManager.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsILookAndFeel.h"
|
|
|
|
#include "nsIDeviceContext.h"
|
|
|
|
#include "nsGfxCIID.h"
|
|
|
|
#include "nsTransform2D.h"
|
|
|
|
#include "nsIMenuFrame.h"
|
|
|
|
#include "prlink.h"
|
|
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
|
|
#include "nsWidgetAtoms.h"
|
|
|
|
|
|
|
|
#include <gdk/gdkprivate.h>
|
|
|
|
#include <gdk/gdkx.h>
|
2007-11-13 00:43:03 -08:00
|
|
|
#include <gtk/gtk.h>
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxPlatformGtk.h"
|
|
|
|
#include "gfxXlibNativeRenderer.h"
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS2(nsNativeThemeGTK, nsITheme, nsIObserver)
|
|
|
|
|
|
|
|
static int gLastXError;
|
|
|
|
|
2007-05-09 12:17:17 -07:00
|
|
|
static inline bool IsCheckboxWidgetType(PRUint8 aWidgetType)
|
|
|
|
{
|
|
|
|
return (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_CHECKBOX_SMALL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool IsRadioWidgetType(PRUint8 aWidgetType)
|
|
|
|
{
|
|
|
|
return (aWidgetType == NS_THEME_RADIO || aWidgetType == NS_THEME_RADIO_SMALL);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsNativeThemeGTK::nsNativeThemeGTK()
|
|
|
|
{
|
|
|
|
if (moz_gtk_init() != MOZ_GTK_SUCCESS) {
|
|
|
|
memset(mDisabledWidgetTypes, 0xff, sizeof(mDisabledWidgetTypes));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have to call moz_gtk_shutdown before the event loop stops running.
|
|
|
|
nsCOMPtr<nsIObserverService> obsServ =
|
|
|
|
do_GetService("@mozilla.org/observer-service;1");
|
|
|
|
obsServ->AddObserver(this, "xpcom-shutdown", PR_FALSE);
|
|
|
|
|
|
|
|
memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes));
|
|
|
|
memset(mSafeWidgetStates, 0, sizeof(mSafeWidgetStates));
|
|
|
|
}
|
|
|
|
|
|
|
|
nsNativeThemeGTK::~nsNativeThemeGTK() {
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNativeThemeGTK::Observe(nsISupports *aSubject, const char *aTopic,
|
|
|
|
const PRUnichar *aData)
|
|
|
|
{
|
|
|
|
if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) {
|
|
|
|
moz_gtk_shutdown();
|
|
|
|
} else {
|
|
|
|
NS_NOTREACHED("unexpected topic");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsNativeThemeGTK::RefreshWidgetWindow(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
nsIPresShell *shell = GetPresShell(aFrame);
|
|
|
|
if (!shell)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIViewManager* vm = shell->GetViewManager();
|
|
|
|
if (!vm)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRBool IsWidgetTypeDisabled(PRUint8* aDisabledVector, PRUint8 aWidgetType) {
|
|
|
|
return aDisabledVector[aWidgetType >> 3] & (1 << (aWidgetType & 7));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SetWidgetTypeDisabled(PRUint8* aDisabledVector, PRUint8 aWidgetType) {
|
|
|
|
aDisabledVector[aWidgetType >> 3] |= (1 << (aWidgetType & 7));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline PRUint16
|
|
|
|
GetWidgetStateKey(PRUint8 aWidgetType, GtkWidgetState *aWidgetState)
|
|
|
|
{
|
|
|
|
return (aWidgetState->active |
|
|
|
|
aWidgetState->focused << 1 |
|
|
|
|
aWidgetState->inHover << 2 |
|
|
|
|
aWidgetState->disabled << 3 |
|
|
|
|
aWidgetState->isDefault << 4 |
|
|
|
|
aWidgetType << 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRBool IsWidgetStateSafe(PRUint8* aSafeVector,
|
|
|
|
PRUint8 aWidgetType,
|
|
|
|
GtkWidgetState *aWidgetState)
|
|
|
|
{
|
|
|
|
PRUint8 key = GetWidgetStateKey(aWidgetType, aWidgetState);
|
|
|
|
return aSafeVector[key >> 3] & (1 << (key & 7));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SetWidgetStateSafe(PRUint8 *aSafeVector,
|
|
|
|
PRUint8 aWidgetType,
|
|
|
|
GtkWidgetState *aWidgetState)
|
|
|
|
{
|
|
|
|
PRUint8 key = GetWidgetStateKey(aWidgetType, aWidgetState);
|
|
|
|
aSafeVector[key >> 3] |= (1 << (key & 7));
|
|
|
|
}
|
|
|
|
|
2007-12-13 23:26:03 -08:00
|
|
|
static GtkTextDirection GetTextDirection(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
if (!aFrame)
|
|
|
|
return GTK_TEXT_DIR_NONE;
|
|
|
|
|
|
|
|
switch (aFrame->GetStyleVisibility()->mDirection) {
|
|
|
|
case NS_STYLE_DIRECTION_RTL:
|
|
|
|
return GTK_TEXT_DIR_RTL;
|
|
|
|
case NS_STYLE_DIRECTION_LTR:
|
|
|
|
return GTK_TEXT_DIR_LTR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GTK_TEXT_DIR_NONE;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRBool
|
|
|
|
nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
|
|
|
|
GtkThemeWidgetType& aGtkWidgetType,
|
|
|
|
GtkWidgetState* aState,
|
|
|
|
gint* aWidgetFlags)
|
|
|
|
{
|
|
|
|
if (aState) {
|
|
|
|
if (!aFrame) {
|
|
|
|
// reset the entire struct to zero
|
|
|
|
memset(aState, 0, sizeof(GtkWidgetState));
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// For XUL checkboxes and radio buttons, the state of the parent
|
|
|
|
// determines our state.
|
|
|
|
nsIFrame *stateFrame = aFrame;
|
2007-05-09 12:17:17 -07:00
|
|
|
if (aFrame && ((aWidgetFlags && (IsCheckboxWidgetType(aWidgetType) ||
|
|
|
|
IsRadioWidgetType(aWidgetType))) ||
|
2007-03-22 10:30:00 -07:00
|
|
|
aWidgetType == NS_THEME_CHECKBOX_LABEL ||
|
|
|
|
aWidgetType == NS_THEME_RADIO_LABEL)) {
|
|
|
|
|
|
|
|
nsIAtom* atom = nsnull;
|
|
|
|
nsIContent *content = aFrame->GetContent();
|
|
|
|
if (content->IsNodeOfType(nsINode::eXUL)) {
|
|
|
|
if (aWidgetType == NS_THEME_CHECKBOX_LABEL ||
|
|
|
|
aWidgetType == NS_THEME_RADIO_LABEL) {
|
|
|
|
// Adjust stateFrame so GetContentState finds the correct state.
|
|
|
|
stateFrame = aFrame = aFrame->GetParent()->GetParent();
|
|
|
|
} else {
|
|
|
|
// GetContentState knows to look one frame up for radio/checkbox
|
|
|
|
// widgets, so don't adjust stateFrame here.
|
|
|
|
aFrame = aFrame->GetParent();
|
|
|
|
}
|
|
|
|
if (aWidgetFlags) {
|
|
|
|
if (!atom) {
|
2007-05-09 12:17:17 -07:00
|
|
|
atom = (IsCheckboxWidgetType(aWidgetType) ||
|
2007-03-22 10:30:00 -07:00
|
|
|
aWidgetType == NS_THEME_CHECKBOX_LABEL) ? nsWidgetAtoms::checked
|
|
|
|
: nsWidgetAtoms::selected;
|
|
|
|
}
|
|
|
|
*aWidgetFlags = CheckBooleanAttr(aFrame, atom);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (aWidgetFlags) {
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> inputElt(do_QueryInterface(content));
|
|
|
|
if (inputElt) {
|
|
|
|
PRBool isHTMLChecked;
|
|
|
|
inputElt->GetChecked(&isHTMLChecked);
|
|
|
|
*aWidgetFlags = isHTMLChecked;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-26 20:32:31 -08:00
|
|
|
} else if (aWidgetType == NS_THEME_TOOLBAR_BUTTON_DROPDOWN ||
|
|
|
|
aWidgetType == NS_THEME_TREEVIEW_HEADER_SORTARROW) {
|
|
|
|
stateFrame = aFrame->GetParent();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 eventState = GetContentState(stateFrame, aWidgetType);
|
|
|
|
|
2007-06-04 20:26:43 -07:00
|
|
|
aState->disabled = (IsDisabled(aFrame) || IsReadOnly(aFrame));
|
2007-03-22 10:30:00 -07:00
|
|
|
aState->active = (eventState & NS_EVENT_STATE_ACTIVE) == NS_EVENT_STATE_ACTIVE;
|
|
|
|
aState->focused = (eventState & NS_EVENT_STATE_FOCUS) == NS_EVENT_STATE_FOCUS;
|
|
|
|
aState->inHover = (eventState & NS_EVENT_STATE_HOVER) == NS_EVENT_STATE_HOVER;
|
2007-09-02 09:38:54 -07:00
|
|
|
aState->isDefault = IsDefaultButton(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
aState->canDefault = FALSE; // XXX fix me
|
2007-12-03 01:14:18 -08:00
|
|
|
aState->depressed = FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-26 23:38:51 -07:00
|
|
|
if (aFrame && aFrame->GetContent()->IsNodeOfType(nsINode::eXUL)) {
|
|
|
|
// For these widget types, some element (either a child or parent)
|
|
|
|
// actually has element focus, so we check the focused attribute
|
|
|
|
// to see whether to draw in the focused state.
|
|
|
|
if (aWidgetType == NS_THEME_TEXTFIELD ||
|
|
|
|
aWidgetType == NS_THEME_TEXTFIELD_MULTILINE ||
|
|
|
|
aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD ||
|
2007-12-21 03:30:00 -08:00
|
|
|
aWidgetType == NS_THEME_SPINNER_TEXTFIELD ||
|
2007-06-26 23:38:51 -07:00
|
|
|
aWidgetType == NS_THEME_RADIO_CONTAINER ||
|
|
|
|
aWidgetType == NS_THEME_RADIO_LABEL) {
|
|
|
|
aState->focused = IsFocused(aFrame);
|
|
|
|
} else if (IsRadioWidgetType(aWidgetType) ||
|
|
|
|
IsCheckboxWidgetType(aWidgetType)) {
|
|
|
|
// In XUL, checkboxes and radios shouldn't have focus rings, their labels do
|
|
|
|
aState->focused = FALSE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-26 23:38:51 -07:00
|
|
|
if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) {
|
|
|
|
// for scrollbars we need to go up two to go from the thumb to
|
|
|
|
// the slider to the actual scrollbar object
|
|
|
|
nsIFrame *tmpFrame = aFrame->GetParent()->GetParent();
|
2007-06-25 21:13:30 -07:00
|
|
|
|
2007-06-26 23:38:51 -07:00
|
|
|
aState->curpos = CheckIntAttr(tmpFrame, nsWidgetAtoms::curpos);
|
|
|
|
aState->maxpos = CheckIntAttr(tmpFrame, nsWidgetAtoms::maxpos);
|
2007-06-26 15:16:07 -07:00
|
|
|
}
|
2007-06-25 21:13:30 -07:00
|
|
|
|
2007-06-26 23:38:51 -07:00
|
|
|
if (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT) {
|
2008-02-07 01:26:22 -08:00
|
|
|
// set the state to disabled when the scrollbar is scrolled to
|
|
|
|
// the beginning or the end, depending on the button type.
|
|
|
|
PRInt32 curpos = CheckIntAttr(aFrame, nsWidgetAtoms::curpos);
|
|
|
|
PRInt32 maxpos = CheckIntAttr(aFrame, nsWidgetAtoms::maxpos);
|
|
|
|
if ((curpos == 0 && (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT)) ||
|
|
|
|
(curpos == maxpos &&
|
|
|
|
(aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT)))
|
|
|
|
aState->disabled = PR_TRUE;
|
|
|
|
|
|
|
|
// In order to simulate native GTK scrollbar click behavior,
|
|
|
|
// we set the active attribute on the element to true if it's
|
|
|
|
// pressed with any mouse button.
|
|
|
|
// This allows us to show that it's active without setting :active
|
|
|
|
else if (CheckBooleanAttr(aFrame, nsWidgetAtoms::active))
|
2008-01-12 20:13:50 -08:00
|
|
|
aState->active = PR_TRUE;
|
|
|
|
|
|
|
|
if (aWidgetFlags) {
|
|
|
|
*aWidgetFlags = GetScrollbarButtonType(aFrame);
|
|
|
|
if (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP < 2)
|
|
|
|
*aWidgetFlags |= MOZ_GTK_STEPPER_VERTICAL;
|
|
|
|
}
|
2007-06-26 15:16:07 -07:00
|
|
|
}
|
2007-06-25 21:13:30 -07:00
|
|
|
|
2007-06-26 23:38:51 -07:00
|
|
|
// menu item state is determined by the attribute "_moz-menuactive",
|
|
|
|
// and not by the mouse hovering (accessibility). as a special case,
|
|
|
|
// menus which are children of a menu bar are only marked as prelight
|
|
|
|
// if they are open, not on normal hover.
|
|
|
|
|
|
|
|
if (aWidgetType == NS_THEME_MENUITEM ||
|
|
|
|
aWidgetType == NS_THEME_CHECKMENUITEM ||
|
2007-11-28 14:45:21 -08:00
|
|
|
aWidgetType == NS_THEME_RADIOMENUITEM ||
|
2007-12-11 01:09:09 -08:00
|
|
|
aWidgetType == NS_THEME_MENUSEPARATOR ||
|
2007-11-28 14:45:21 -08:00
|
|
|
aWidgetType == NS_THEME_MENUARROW) {
|
2007-06-26 23:38:51 -07:00
|
|
|
PRBool isTopLevel = PR_FALSE;
|
|
|
|
nsIMenuFrame *menuFrame;
|
|
|
|
CallQueryInterface(aFrame, &menuFrame);
|
|
|
|
|
|
|
|
if (menuFrame) {
|
2007-07-04 08:49:38 -07:00
|
|
|
isTopLevel = menuFrame->IsOnMenuBar();
|
2007-06-26 23:38:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isTopLevel) {
|
2007-07-04 08:49:38 -07:00
|
|
|
aState->inHover = menuFrame->IsOpen();
|
2007-12-03 22:28:34 -08:00
|
|
|
*aWidgetFlags |= MOZ_TOPLEVEL_MENU_ITEM;
|
2007-06-26 23:38:51 -07:00
|
|
|
} else {
|
|
|
|
aState->inHover = CheckBooleanAttr(aFrame, nsWidgetAtoms::mozmenuactive);
|
2007-12-03 22:28:34 -08:00
|
|
|
*aWidgetFlags &= ~MOZ_TOPLEVEL_MENU_ITEM;
|
2007-06-26 23:38:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
aState->active = FALSE;
|
|
|
|
|
|
|
|
if (aWidgetType == NS_THEME_CHECKMENUITEM ||
|
|
|
|
aWidgetType == NS_THEME_RADIOMENUITEM) {
|
|
|
|
*aWidgetFlags = aFrame && aFrame->GetContent()->
|
|
|
|
AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::checked,
|
|
|
|
nsWidgetAtoms::_true, eIgnoreCase);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-12-03 01:14:18 -08:00
|
|
|
|
|
|
|
// A button with drop down menu open or an activated toggle button
|
|
|
|
// should always appear depressed.
|
|
|
|
if (aWidgetType == NS_THEME_BUTTON ||
|
|
|
|
aWidgetType == NS_THEME_TOOLBAR_BUTTON ||
|
2008-01-12 18:56:01 -08:00
|
|
|
aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON ||
|
2008-01-26 20:32:31 -08:00
|
|
|
aWidgetType == NS_THEME_TOOLBAR_BUTTON_DROPDOWN ||
|
2008-01-26 21:11:15 -08:00
|
|
|
aWidgetType == NS_THEME_DROPDOWN ||
|
|
|
|
aWidgetType == NS_THEME_DROPDOWN_BUTTON) {
|
2008-01-26 20:32:31 -08:00
|
|
|
if (aWidgetType == NS_THEME_TOOLBAR_BUTTON_DROPDOWN)
|
|
|
|
aFrame = aFrame->GetParent();
|
|
|
|
|
2007-12-03 01:14:18 -08:00
|
|
|
PRBool menuOpen = CheckBooleanAttr(aFrame, nsWidgetAtoms::open);
|
|
|
|
aState->depressed = IsCheckedButton(aFrame) || menuOpen;
|
|
|
|
// we must not highlight buttons with open drop down menus on hover.
|
|
|
|
aState->inHover = aState->inHover && !menuOpen;
|
|
|
|
}
|
2008-02-10 00:30:04 -08:00
|
|
|
|
|
|
|
// When the input field of the drop down button has focus, some themes
|
|
|
|
// should draw focus for the drop down button as well.
|
|
|
|
if (aWidgetType == NS_THEME_DROPDOWN_BUTTON && aWidgetFlags) {
|
|
|
|
*aWidgetFlags = CheckBooleanAttr(aFrame, nsWidgetAtoms::parentfocused);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (aWidgetType) {
|
|
|
|
case NS_THEME_BUTTON:
|
|
|
|
case NS_THEME_TOOLBAR_BUTTON:
|
|
|
|
case NS_THEME_TOOLBAR_DUAL_BUTTON:
|
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = (aWidgetType == NS_THEME_BUTTON) ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE;
|
|
|
|
aGtkWidgetType = MOZ_GTK_BUTTON;
|
|
|
|
break;
|
|
|
|
case NS_THEME_CHECKBOX:
|
2007-05-09 12:17:17 -07:00
|
|
|
case NS_THEME_CHECKBOX_SMALL:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_RADIO:
|
2007-05-09 12:17:17 -07:00
|
|
|
case NS_THEME_RADIO_SMALL:
|
|
|
|
aGtkWidgetType = IsRadioWidgetType(aWidgetType) ? MOZ_GTK_RADIOBUTTON : MOZ_GTK_CHECKBUTTON;
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_UP:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCROLLBAR_BUTTON;
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_VERTICAL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
|
|
|
|
break;
|
2007-12-21 03:30:29 -08:00
|
|
|
case NS_THEME_SPINNER:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SPINBUTTON;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_SPINNER_UP_BUTTON:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SPINBUTTON_UP;
|
|
|
|
break;
|
|
|
|
case NS_THEME_SPINNER_DOWN_BUTTON:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SPINBUTTON_DOWN;
|
|
|
|
break;
|
2007-12-21 03:30:29 -08:00
|
|
|
case NS_THEME_SPINNER_TEXTFIELD:
|
|
|
|
aGtkWidgetType = MOZ_GTK_SPINBUTTON_ENTRY;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_SCALE_HORIZONTAL:
|
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = GTK_ORIENTATION_HORIZONTAL;
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCALE_HORIZONTAL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCALE_THUMB_HORIZONTAL:
|
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = GTK_ORIENTATION_HORIZONTAL;
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCALE_THUMB_HORIZONTAL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCALE_VERTICAL:
|
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = GTK_ORIENTATION_VERTICAL;
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCALE_VERTICAL;
|
|
|
|
break;
|
2007-12-03 01:13:29 -08:00
|
|
|
case NS_THEME_TOOLBAR_SEPARATOR:
|
|
|
|
aGtkWidgetType = MOZ_GTK_TOOLBAR_SEPARATOR;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_SCALE_THUMB_VERTICAL:
|
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = GTK_ORIENTATION_VERTICAL;
|
|
|
|
aGtkWidgetType = MOZ_GTK_SCALE_THUMB_VERTICAL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_TOOLBAR_GRIPPER:
|
|
|
|
aGtkWidgetType = MOZ_GTK_GRIPPER;
|
|
|
|
break;
|
2007-11-08 23:32:54 -08:00
|
|
|
case NS_THEME_RESIZER:
|
|
|
|
aGtkWidgetType = MOZ_GTK_RESIZER;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_TEXTFIELD:
|
2007-05-06 19:06:58 -07:00
|
|
|
case NS_THEME_TEXTFIELD_MULTILINE:
|
2007-03-22 10:30:00 -07:00
|
|
|
aGtkWidgetType = MOZ_GTK_ENTRY;
|
|
|
|
break;
|
2007-11-07 01:14:58 -08:00
|
|
|
case NS_THEME_LISTBOX:
|
|
|
|
case NS_THEME_TREEVIEW:
|
|
|
|
aGtkWidgetType = MOZ_GTK_TREEVIEW;
|
|
|
|
break;
|
|
|
|
case NS_THEME_TREEVIEW_HEADER_CELL:
|
2008-03-18 12:35:23 -07:00
|
|
|
if (aWidgetFlags) {
|
|
|
|
// In this case, the flag denotes whether the header is the sorted one or not
|
|
|
|
if (GetTreeSortDirection(aFrame) == eTreeSortDirection_Natural)
|
|
|
|
*aWidgetFlags = PR_FALSE;
|
|
|
|
else
|
|
|
|
*aWidgetFlags = PR_TRUE;
|
|
|
|
}
|
2007-11-07 01:14:58 -08:00
|
|
|
aGtkWidgetType = MOZ_GTK_TREE_HEADER_CELL;
|
|
|
|
break;
|
2007-11-13 00:43:03 -08:00
|
|
|
case NS_THEME_TREEVIEW_HEADER_SORTARROW:
|
|
|
|
if (aWidgetFlags) {
|
|
|
|
switch (GetTreeSortDirection(aFrame)) {
|
|
|
|
case eTreeSortDirection_Ascending:
|
|
|
|
*aWidgetFlags = GTK_ARROW_DOWN;
|
|
|
|
break;
|
|
|
|
case eTreeSortDirection_Descending:
|
|
|
|
*aWidgetFlags = GTK_ARROW_UP;
|
|
|
|
break;
|
|
|
|
case eTreeSortDirection_Natural:
|
|
|
|
default:
|
|
|
|
/* GTK_ARROW_NONE is implemented since GTK 2.10
|
|
|
|
* This prevents the treecolums from getting smaller
|
|
|
|
* and wider when switching sort direction off and on
|
|
|
|
* */
|
|
|
|
#if GTK_CHECK_VERSION(2,10,0)
|
|
|
|
*aWidgetFlags = GTK_ARROW_NONE;
|
|
|
|
#else
|
|
|
|
return PR_FALSE; // Don't draw when we shouldn't
|
|
|
|
#endif // GTK_CHECK_VERSION(2,10,0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
aGtkWidgetType = MOZ_GTK_TREE_HEADER_SORTARROW;
|
|
|
|
break;
|
2007-11-14 19:47:16 -08:00
|
|
|
case NS_THEME_TREEVIEW_TWISTY:
|
2008-01-02 23:07:32 -08:00
|
|
|
aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER;
|
2007-11-14 19:47:16 -08:00
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = GTK_EXPANDER_COLLAPSED;
|
|
|
|
break;
|
|
|
|
case NS_THEME_TREEVIEW_TWISTY_OPEN:
|
2008-01-02 23:07:32 -08:00
|
|
|
aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER;
|
2007-11-14 19:47:16 -08:00
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = GTK_EXPANDER_EXPANDED;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_DROPDOWN:
|
|
|
|
aGtkWidgetType = MOZ_GTK_DROPDOWN;
|
|
|
|
break;
|
|
|
|
case NS_THEME_DROPDOWN_TEXT:
|
|
|
|
return PR_FALSE; // nothing to do, but prevents the bg from being drawn
|
2008-01-14 03:12:29 -08:00
|
|
|
case NS_THEME_DROPDOWN_TEXTFIELD:
|
|
|
|
aGtkWidgetType = MOZ_GTK_DROPDOWN_ENTRY;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_DROPDOWN_BUTTON:
|
|
|
|
aGtkWidgetType = MOZ_GTK_DROPDOWN_ARROW;
|
|
|
|
break;
|
2008-01-17 02:24:31 -08:00
|
|
|
case NS_THEME_TOOLBAR_BUTTON_DROPDOWN:
|
|
|
|
aGtkWidgetType = MOZ_GTK_TOOLBARBUTTON_ARROW;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_CHECKBOX_CONTAINER:
|
|
|
|
aGtkWidgetType = MOZ_GTK_CHECKBUTTON_CONTAINER;
|
|
|
|
break;
|
|
|
|
case NS_THEME_RADIO_CONTAINER:
|
|
|
|
aGtkWidgetType = MOZ_GTK_RADIOBUTTON_CONTAINER;
|
|
|
|
break;
|
|
|
|
case NS_THEME_CHECKBOX_LABEL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_CHECKBUTTON_LABEL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_RADIO_LABEL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_RADIOBUTTON_LABEL;
|
|
|
|
break;
|
|
|
|
case NS_THEME_TOOLBAR:
|
|
|
|
aGtkWidgetType = MOZ_GTK_TOOLBAR;
|
|
|
|
break;
|
|
|
|
case NS_THEME_TOOLTIP:
|
|
|
|
aGtkWidgetType = MOZ_GTK_TOOLTIP;
|
|
|
|
break;
|
|
|
|
case NS_THEME_STATUSBAR_PANEL:
|
2007-11-14 23:35:41 -08:00
|
|
|
case NS_THEME_STATUSBAR_RESIZER_PANEL:
|
2007-03-22 10:30:00 -07:00
|
|
|
aGtkWidgetType = MOZ_GTK_FRAME;
|
|
|
|
break;
|
|
|
|
case NS_THEME_PROGRESSBAR:
|
|
|
|
case NS_THEME_PROGRESSBAR_VERTICAL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_PROGRESSBAR;
|
|
|
|
break;
|
|
|
|
case NS_THEME_PROGRESSBAR_CHUNK:
|
|
|
|
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
|
|
|
|
aGtkWidgetType = MOZ_GTK_PROGRESS_CHUNK;
|
|
|
|
break;
|
2008-02-14 21:28:44 -08:00
|
|
|
case NS_THEME_TAB_SCROLLARROW_BACK:
|
|
|
|
case NS_THEME_TAB_SCROLLARROW_FORWARD:
|
|
|
|
if (aWidgetFlags)
|
|
|
|
*aWidgetFlags = aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK ?
|
|
|
|
GTK_ARROW_LEFT : GTK_ARROW_RIGHT;
|
|
|
|
aGtkWidgetType = MOZ_GTK_TAB_SCROLLARROW;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_TAB_PANELS:
|
|
|
|
aGtkWidgetType = MOZ_GTK_TABPANELS;
|
|
|
|
break;
|
|
|
|
case NS_THEME_TAB:
|
|
|
|
{
|
|
|
|
if (aWidgetFlags) {
|
2007-12-21 03:51:48 -08:00
|
|
|
/* First bits will be used to store max(0,-bmargin) where bmargin
|
|
|
|
* is the bottom margin of the tab in pixels (resp. top margin,
|
|
|
|
* for bottom tabs). */
|
2008-01-08 23:40:21 -08:00
|
|
|
nscoord margin;
|
2007-12-21 03:51:48 -08:00
|
|
|
if (IsBottomTab(aFrame)) {
|
|
|
|
*aWidgetFlags = MOZ_GTK_TAB_BOTTOM;
|
|
|
|
margin = aFrame->GetUsedMargin().top;
|
|
|
|
} else {
|
|
|
|
*aWidgetFlags = 0;
|
|
|
|
margin = aFrame->GetUsedMargin().bottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aWidgetFlags |= PR_MIN(MOZ_GTK_TAB_MARGIN_MASK,
|
|
|
|
PR_MAX(0, aFrame->PresContext()->
|
|
|
|
AppUnitsToDevPixels(-margin) ));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-12-21 03:51:48 -08:00
|
|
|
if (IsSelectedTab(aFrame))
|
2007-03-22 10:30:00 -07:00
|
|
|
*aWidgetFlags |= MOZ_GTK_TAB_SELECTED;
|
|
|
|
|
2007-12-21 03:51:48 -08:00
|
|
|
if (IsFirstTab(aFrame))
|
2007-03-22 10:30:00 -07:00
|
|
|
*aWidgetFlags |= MOZ_GTK_TAB_FIRST;
|
|
|
|
}
|
|
|
|
|
|
|
|
aGtkWidgetType = MOZ_GTK_TAB;
|
|
|
|
}
|
|
|
|
break;
|
2007-12-21 03:17:01 -08:00
|
|
|
case NS_THEME_SPLITTER:
|
|
|
|
if (IsHorizontal(aFrame))
|
|
|
|
aGtkWidgetType = MOZ_GTK_SPLITTER_VERTICAL;
|
|
|
|
else
|
|
|
|
aGtkWidgetType = MOZ_GTK_SPLITTER_HORIZONTAL;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_MENUBAR:
|
|
|
|
aGtkWidgetType = MOZ_GTK_MENUBAR;
|
|
|
|
break;
|
|
|
|
case NS_THEME_MENUPOPUP:
|
|
|
|
aGtkWidgetType = MOZ_GTK_MENUPOPUP;
|
|
|
|
break;
|
|
|
|
case NS_THEME_MENUITEM:
|
|
|
|
aGtkWidgetType = MOZ_GTK_MENUITEM;
|
|
|
|
break;
|
2007-12-11 01:09:09 -08:00
|
|
|
case NS_THEME_MENUSEPARATOR:
|
|
|
|
aGtkWidgetType = MOZ_GTK_MENUSEPARATOR;
|
|
|
|
break;
|
2007-11-28 14:45:21 -08:00
|
|
|
case NS_THEME_MENUARROW:
|
|
|
|
aGtkWidgetType = MOZ_GTK_MENUARROW;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_CHECKMENUITEM:
|
|
|
|
aGtkWidgetType = MOZ_GTK_CHECKMENUITEM;
|
|
|
|
break;
|
|
|
|
case NS_THEME_RADIOMENUITEM:
|
|
|
|
aGtkWidgetType = MOZ_GTK_RADIOMENUITEM;
|
|
|
|
break;
|
|
|
|
case NS_THEME_WINDOW:
|
|
|
|
case NS_THEME_DIALOG:
|
|
|
|
aGtkWidgetType = MOZ_GTK_WINDOW;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
NativeThemeErrorHandler(Display* dpy, XErrorEvent* error) {
|
|
|
|
gLastXError = error->error_code;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
class ThemeRenderer : public gfxXlibNativeRenderer {
|
|
|
|
public:
|
|
|
|
ThemeRenderer(GtkWidgetState aState, GtkThemeWidgetType aGTKWidgetType,
|
2007-12-13 23:26:03 -08:00
|
|
|
gint aFlags, GtkTextDirection aDirection,
|
|
|
|
const GdkRectangle& aGDKRect, const GdkRectangle& aGDKClip)
|
2007-03-22 10:30:00 -07:00
|
|
|
: mState(aState), mGTKWidgetType(aGTKWidgetType), mFlags(aFlags),
|
2007-12-13 23:26:03 -08:00
|
|
|
mDirection(aDirection), mGDKRect(aGDKRect), mGDKClip(aGDKClip) {}
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult NativeDraw(Display* dpy, Drawable drawable, Visual* visual,
|
|
|
|
short offsetX, short offsetY,
|
|
|
|
XRectangle* clipRects, PRUint32 numClipRects);
|
|
|
|
private:
|
|
|
|
GtkWidgetState mState;
|
|
|
|
GtkThemeWidgetType mGTKWidgetType;
|
|
|
|
gint mFlags;
|
2007-12-13 23:26:03 -08:00
|
|
|
GtkTextDirection mDirection;
|
2007-03-22 10:30:00 -07:00
|
|
|
GdkWindow* mWindow;
|
|
|
|
const GdkRectangle& mGDKRect;
|
|
|
|
const GdkRectangle& mGDKClip;
|
|
|
|
};
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ThemeRenderer::NativeDraw(Display* dpy, Drawable drawable, Visual* visual,
|
|
|
|
short offsetX, short offsetY,
|
|
|
|
XRectangle* clipRects, PRUint32 numClipRects)
|
|
|
|
{
|
|
|
|
GdkRectangle gdk_rect = mGDKRect;
|
|
|
|
gdk_rect.x += offsetX;
|
|
|
|
gdk_rect.y += offsetY;
|
|
|
|
|
|
|
|
GdkRectangle gdk_clip = mGDKClip;
|
|
|
|
gdk_clip.x += offsetX;
|
|
|
|
gdk_clip.y += offsetY;
|
|
|
|
|
|
|
|
GdkDisplay* gdkDpy = gdk_x11_lookup_xdisplay(dpy);
|
|
|
|
if (!gdkDpy)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
GdkPixmap* gdkPixmap = gdk_pixmap_lookup_for_display(gdkDpy, drawable);
|
|
|
|
if (gdkPixmap) {
|
|
|
|
g_object_ref(G_OBJECT(gdkPixmap));
|
|
|
|
} else {
|
|
|
|
gdkPixmap = gdk_pixmap_foreign_new_for_display(gdkDpy, drawable);
|
|
|
|
if (!gdkPixmap)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (visual) {
|
|
|
|
GdkScreen* gdkScreen = gdk_display_get_default_screen(gdkDpy);
|
|
|
|
GdkVisual* gdkVisual = gdk_x11_screen_lookup_visual(gdkScreen, visual->visualid);
|
|
|
|
Colormap cmap = DefaultScreenOfDisplay(dpy)->cmap;
|
|
|
|
GdkColormap* colormap =
|
|
|
|
gdk_x11_colormap_foreign_new(gdkVisual, cmap);
|
|
|
|
|
|
|
|
gdk_drawable_set_colormap(gdkPixmap, colormap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(numClipRects == 0, "We don't support clipping!!!");
|
|
|
|
moz_gtk_widget_paint(mGTKWidgetType, gdkPixmap, &gdk_rect, &gdk_clip, &mState,
|
2007-12-13 23:26:03 -08:00
|
|
|
mFlags, mDirection);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
g_object_unref(G_OBJECT(gdkPixmap));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRBool
|
|
|
|
GetExtraSizeForWidget(PRUint8 aWidgetType, nsIntMargin* aExtra)
|
|
|
|
{
|
|
|
|
*aExtra = nsIntMargin(0,0,0,0);
|
|
|
|
// Allow an extra one pixel above and below the thumb for certain
|
|
|
|
// GTK2 themes (Ximian Industrial, Bluecurve, Misty, at least);
|
|
|
|
// see moz_gtk_scrollbar_thumb_paint in gtk2drawing.c
|
|
|
|
switch (aWidgetType) {
|
|
|
|
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
|
|
|
|
aExtra->top = aExtra->bottom = 1;
|
|
|
|
return PR_TRUE;
|
|
|
|
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
|
|
|
|
aExtra->left = aExtra->right = 1;
|
|
|
|
return PR_TRUE;
|
2008-03-07 09:58:11 -08:00
|
|
|
|
|
|
|
// Include the indicator spacing (the padding around the control).
|
|
|
|
case NS_THEME_CHECKBOX:
|
|
|
|
case NS_THEME_CHECKBOX_SMALL:
|
|
|
|
case NS_THEME_RADIO:
|
|
|
|
case NS_THEME_RADIO_SMALL:
|
|
|
|
{
|
|
|
|
gint indicator_size, indicator_spacing;
|
|
|
|
|
|
|
|
if (IsCheckboxWidgetType(aWidgetType)) {
|
|
|
|
moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
|
|
|
|
} else {
|
|
|
|
moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
aExtra->top = indicator_spacing;
|
|
|
|
aExtra->right = indicator_spacing;
|
|
|
|
aExtra->bottom = indicator_spacing;
|
|
|
|
aExtra->left = indicator_spacing;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
default:
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkRectangle
|
|
|
|
ConvertToGdkRect(const nsRect &aRect, PRInt32 aP2A)
|
|
|
|
{
|
|
|
|
GdkRectangle gdk_rect;
|
|
|
|
gdk_rect.x = NSAppUnitsToIntPixels(aRect.x, aP2A);
|
|
|
|
gdk_rect.y = NSAppUnitsToIntPixels(aRect.y, aP2A);
|
|
|
|
gdk_rect.width = NSAppUnitsToIntPixels(aRect.XMost(), aP2A) - gdk_rect.x;
|
|
|
|
gdk_rect.height = NSAppUnitsToIntPixels(aRect.YMost(), aP2A) - gdk_rect.y;
|
|
|
|
return gdk_rect;
|
|
|
|
}
|
|
|
|
|
2007-12-04 17:09:29 -08:00
|
|
|
static GdkRectangle
|
|
|
|
ConvertGfxToGdkRect(const gfxRect &aRect, const gfxPoint &aTranslation)
|
|
|
|
{
|
|
|
|
GdkRectangle gdk_rect;
|
|
|
|
gdk_rect.x = NSToIntRound(aRect.X()) - NSToIntRound(aTranslation.x);
|
|
|
|
gdk_rect.y = NSToIntRound(aRect.Y()) - NSToIntRound(aTranslation.y);
|
|
|
|
gdk_rect.width = NSToIntRound(aRect.Width());
|
|
|
|
gdk_rect.height = NSToIntRound(aRect.Height());
|
|
|
|
return gdk_rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gfxRect
|
|
|
|
ConvertToGfxRect(const nsRect &aRect, PRInt32 aP2A)
|
|
|
|
{
|
|
|
|
gfxRect rect(NSAppUnitsToFloatPixels(aRect.x, aP2A),
|
|
|
|
NSAppUnitsToFloatPixels(aRect.y, aP2A),
|
|
|
|
NSAppUnitsToFloatPixels(aRect.width, aP2A),
|
|
|
|
NSAppUnitsToFloatPixels(aRect.height, aP2A));
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNativeThemeGTK::DrawWidgetBackground(nsIRenderingContext* aContext,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
PRUint8 aWidgetType,
|
|
|
|
const nsRect& aRect,
|
|
|
|
const nsRect& aClipRect)
|
|
|
|
{
|
|
|
|
GtkWidgetState state;
|
|
|
|
GtkThemeWidgetType gtkWidgetType;
|
2007-12-13 23:26:03 -08:00
|
|
|
GtkTextDirection direction = GetTextDirection(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
gint flags;
|
|
|
|
if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state,
|
|
|
|
&flags))
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDeviceContext> dctx = nsnull;
|
|
|
|
aContext->GetDeviceContext(*getter_AddRefs(dctx));
|
|
|
|
PRInt32 p2a = dctx->AppUnitsPerDevPixel();
|
|
|
|
|
|
|
|
// This is the rectangle that will actually be drawn, in appunits
|
|
|
|
nsRect drawingRect(aClipRect);
|
|
|
|
nsIntMargin extraSize;
|
|
|
|
GetExtraSizeForWidget(aWidgetType, &extraSize);
|
|
|
|
// inflate drawing rect to account for the overdraw
|
|
|
|
nsMargin extraSizeAppUnits(NSIntPixelsToAppUnits(extraSize.left, p2a),
|
|
|
|
NSIntPixelsToAppUnits(extraSize.top, p2a),
|
|
|
|
NSIntPixelsToAppUnits(extraSize.right, p2a),
|
|
|
|
NSIntPixelsToAppUnits(extraSize.bottom, p2a));
|
|
|
|
drawingRect.Inflate(extraSizeAppUnits);
|
|
|
|
|
|
|
|
// translate everything so (0,0) is the top left of the drawingRect
|
|
|
|
nsIRenderingContext::AutoPushTranslation
|
2007-04-25 23:57:37 -07:00
|
|
|
autoTranslation(aContext, drawingRect.x, drawingRect.y);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_ASSERTION(!IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType),
|
|
|
|
"Trying to render an unsafe widget!");
|
|
|
|
|
|
|
|
PRBool safeState = IsWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state);
|
|
|
|
XErrorHandler oldHandler = nsnull;
|
|
|
|
if (!safeState) {
|
|
|
|
gLastXError = 0;
|
|
|
|
oldHandler = XSetErrorHandler(NativeThemeErrorHandler);
|
|
|
|
}
|
|
|
|
|
2007-12-18 15:01:15 -08:00
|
|
|
gfxContext* ctx = aContext->ThebesContext();
|
2007-12-04 17:09:29 -08:00
|
|
|
gfxMatrix current = ctx->CurrentMatrix();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// We require the use of the default display and visual
|
|
|
|
// because I'm afraid that otherwise the GTK theme may explode.
|
|
|
|
// Some themes (e.g. Clearlooks) just don't clip properly to any
|
|
|
|
// clip rect we provide, so we cannot advertise support for clipping within the
|
|
|
|
// widget bounds. The gdk_clip is just advisory here, meanining "you don't
|
|
|
|
// need to draw outside this rect if you don't feel like it!"
|
2007-12-04 17:09:29 -08:00
|
|
|
GdkRectangle gdk_rect, gdk_clip;
|
|
|
|
gfxRect gfx_rect = ConvertToGfxRect(aRect - drawingRect.TopLeft(), p2a);
|
2008-03-07 09:58:11 -08:00
|
|
|
gfxRect gfx_clip = ConvertToGfxRect(drawingRect - drawingRect.TopLeft(), p2a);
|
2007-12-04 17:09:29 -08:00
|
|
|
if (ctx->UserToDevicePixelSnapped(gfx_rect) &&
|
|
|
|
ctx->UserToDevicePixelSnapped(gfx_clip)) {
|
|
|
|
gfxPoint currentTranslation = current.GetTranslation();
|
|
|
|
gdk_rect = ConvertGfxToGdkRect(gfx_rect, currentTranslation);
|
|
|
|
gdk_clip = ConvertGfxToGdkRect(gfx_clip, currentTranslation);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
gdk_rect = ConvertToGdkRect(aRect - drawingRect.TopLeft(), p2a);
|
2008-03-07 09:58:11 -08:00
|
|
|
gdk_clip = ConvertToGdkRect(drawingRect - drawingRect.TopLeft(), p2a);
|
2007-12-04 17:09:29 -08:00
|
|
|
}
|
2007-12-13 23:26:03 -08:00
|
|
|
ThemeRenderer renderer(state, gtkWidgetType, flags, direction, gdk_rect, gdk_clip);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-13 15:34:06 -07:00
|
|
|
// XXXbz do we really want to round here, then snap, then round again?
|
2007-03-22 10:30:00 -07:00
|
|
|
gfxRect rect(0, 0, NSAppUnitsToIntPixels(drawingRect.width, p2a),
|
|
|
|
NSAppUnitsToIntPixels(drawingRect.height, p2a));
|
2007-12-04 17:09:29 -08:00
|
|
|
|
|
|
|
PRUint32 rendererFlags = gfxXlibNativeRenderer::DRAW_SUPPORTS_OFFSET;
|
2007-03-22 10:30:00 -07:00
|
|
|
// Don't snap if it's a non-unit scale factor. We're going to have to take
|
|
|
|
// slow paths then in any case.
|
|
|
|
PRBool snapXY = ctx->UserToDevicePixelSnapped(rect) &&
|
|
|
|
!current.HasNonTranslation();
|
|
|
|
if (snapXY) {
|
|
|
|
gfxMatrix translation;
|
|
|
|
translation.Translate(rect.TopLeft());
|
|
|
|
ctx->SetMatrix(translation);
|
|
|
|
renderer.Draw(gdk_x11_get_default_xdisplay(), ctx,
|
|
|
|
NSToCoordRound(rect.Width()), NSToCoordRound(rect.Height()),
|
|
|
|
rendererFlags, nsnull);
|
|
|
|
ctx->SetMatrix(current);
|
|
|
|
} else {
|
|
|
|
renderer.Draw(gdk_x11_get_default_xdisplay(), ctx,
|
2007-06-13 15:34:06 -07:00
|
|
|
NSToIntCeil(NSAppUnitsToFloatPixels(drawingRect.width, p2a)),
|
|
|
|
NSToIntCeil(NSAppUnitsToFloatPixels(drawingRect.height, p2a)),
|
|
|
|
rendererFlags, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!safeState) {
|
|
|
|
gdk_flush();
|
|
|
|
XSetErrorHandler(oldHandler);
|
|
|
|
|
|
|
|
if (gLastXError) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("GTK theme failed for widget type %d, error was %d, state was "
|
2007-04-25 23:57:37 -07:00
|
|
|
"[active=%d,focused=%d,inHover=%d,disabled=%d]\n",
|
2007-03-22 10:30:00 -07:00
|
|
|
aWidgetType, gLastXError, state.active, state.focused,
|
|
|
|
state.inHover, state.disabled);
|
|
|
|
#endif
|
|
|
|
NS_WARNING("GTK theme failed; disabling unsafe widget");
|
|
|
|
SetWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType);
|
|
|
|
// force refresh of the window, because the widget was not
|
|
|
|
// successfully drawn it must be redrawn using the default look
|
|
|
|
RefreshWidgetWindow(aFrame);
|
|
|
|
} else {
|
|
|
|
SetWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
|
|
|
|
PRUint8 aWidgetType, nsMargin* aResult)
|
|
|
|
{
|
2007-12-21 03:51:48 -08:00
|
|
|
GtkTextDirection direction = GetTextDirection(aFrame);
|
2007-06-04 20:26:43 -07:00
|
|
|
aResult->top = aResult->left = aResult->right = aResult->bottom = 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
switch (aWidgetType) {
|
|
|
|
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
|
|
|
|
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
|
|
|
|
{
|
|
|
|
MozGtkScrollbarMetrics metrics;
|
|
|
|
moz_gtk_get_scrollbar_metrics(&metrics);
|
2007-06-04 20:26:43 -07:00
|
|
|
aResult->top = aResult->left = aResult->right = aResult->bottom = metrics.trough_border;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NS_THEME_TOOLBOX:
|
|
|
|
// gtk has no toolbox equivalent. So, although we map toolbox to
|
|
|
|
// gtk's 'toolbar' for purposes of painting the widget background,
|
|
|
|
// we don't use the toolbar border for toolbox.
|
|
|
|
break;
|
|
|
|
case NS_THEME_TOOLBAR_DUAL_BUTTON:
|
|
|
|
// TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw
|
|
|
|
// around the entire button + dropdown, and also an inner border if you're
|
|
|
|
// over the button part. But, we want the inner button to be right up
|
|
|
|
// against the edge of the outer button so that the borders overlap.
|
|
|
|
// To make this happen, we draw a button border for the outer button,
|
|
|
|
// but don't reserve any space for it.
|
|
|
|
break;
|
2007-12-21 03:51:48 -08:00
|
|
|
case NS_THEME_TAB:
|
|
|
|
// Top tabs have no bottom border, bottom tabs have no top border
|
|
|
|
moz_gtk_get_widget_border(MOZ_GTK_TAB, &aResult->left, &aResult->top,
|
|
|
|
&aResult->right, &aResult->bottom, direction,
|
|
|
|
FALSE);
|
|
|
|
if (IsBottomTab(aFrame))
|
|
|
|
aResult->top = 0;
|
|
|
|
else
|
|
|
|
aResult->bottom = 0;
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
GtkThemeWidgetType gtkWidgetType;
|
|
|
|
if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nsnull,
|
|
|
|
nsnull))
|
2007-06-04 20:26:43 -07:00
|
|
|
moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top,
|
2007-12-13 23:26:03 -08:00
|
|
|
&aResult->right, &aResult->bottom, direction,
|
2007-12-21 03:51:48 -08:00
|
|
|
aFrame && aFrame->GetContent()->
|
|
|
|
IsNodeOfType(nsINode::eHTML));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsNativeThemeGTK::GetWidgetPadding(nsIDeviceContext* aContext,
|
|
|
|
nsIFrame* aFrame, PRUint8 aWidgetType,
|
|
|
|
nsMargin* aResult)
|
|
|
|
{
|
2008-03-07 09:57:34 -08:00
|
|
|
switch (aWidgetType) {
|
|
|
|
case NS_THEME_BUTTON_FOCUS:
|
|
|
|
case NS_THEME_TOOLBAR_BUTTON:
|
|
|
|
case NS_THEME_TOOLBAR_DUAL_BUTTON:
|
2008-03-11 01:55:54 -07:00
|
|
|
case NS_THEME_TAB_SCROLLARROW_BACK:
|
2008-03-07 09:57:34 -08:00
|
|
|
case NS_THEME_TAB_SCROLLARROW_FORWARD:
|
2008-03-11 01:55:54 -07:00
|
|
|
case NS_THEME_DROPDOWN_BUTTON:
|
2008-03-07 09:57:34 -08:00
|
|
|
// Radios and checkboxes return a fixed size in GetMinimumWidgetSize
|
|
|
|
// and have a meaningful baseline, so they can't have
|
|
|
|
// author-specified padding.
|
|
|
|
case NS_THEME_CHECKBOX:
|
|
|
|
case NS_THEME_CHECKBOX_SMALL:
|
|
|
|
case NS_THEME_RADIO:
|
|
|
|
case NS_THEME_RADIO_SMALL:
|
|
|
|
aResult->SizeTo(0, 0, 0, 0);
|
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsNativeThemeGTK::GetWidgetOverflow(nsIDeviceContext* aContext,
|
|
|
|
nsIFrame* aFrame, PRUint8 aWidgetType,
|
|
|
|
nsRect* aResult)
|
|
|
|
{
|
2008-01-08 23:40:21 -08:00
|
|
|
nsMargin m;
|
|
|
|
PRInt32 p2a;
|
2007-12-21 03:51:48 -08:00
|
|
|
if (aWidgetType == NS_THEME_TAB)
|
|
|
|
{
|
|
|
|
if (!IsSelectedTab(aFrame))
|
|
|
|
return PR_FALSE;
|
|
|
|
|
2008-01-08 23:40:21 -08:00
|
|
|
p2a = aContext->AppUnitsPerDevPixel();
|
|
|
|
|
2007-12-21 03:51:48 -08:00
|
|
|
if (IsBottomTab(aFrame)) {
|
2008-01-08 23:40:21 -08:00
|
|
|
m = nsMargin(0, NSIntPixelsToAppUnits(moz_gtk_get_tab_thickness(), p2a)
|
|
|
|
+ PR_MIN(0, aFrame->GetUsedMargin().top), 0, 0);
|
2007-12-21 03:51:48 -08:00
|
|
|
} else {
|
2008-01-08 23:40:21 -08:00
|
|
|
m = nsMargin(0, 0, 0,
|
|
|
|
NSIntPixelsToAppUnits(moz_gtk_get_tab_thickness(), p2a)
|
|
|
|
+ PR_MIN(0, aFrame->GetUsedMargin().bottom));
|
2007-12-21 03:51:48 -08:00
|
|
|
}
|
2008-01-08 23:40:21 -08:00
|
|
|
} else {
|
|
|
|
nsIntMargin extraSize;
|
|
|
|
if (!GetExtraSizeForWidget(aWidgetType, &extraSize))
|
|
|
|
return PR_FALSE;
|
|
|
|
|
|
|
|
p2a = aContext->AppUnitsPerDevPixel();
|
|
|
|
m = nsMargin(NSIntPixelsToAppUnits(extraSize.left, p2a),
|
|
|
|
NSIntPixelsToAppUnits(extraSize.top, p2a),
|
|
|
|
NSIntPixelsToAppUnits(extraSize.right, p2a),
|
|
|
|
NSIntPixelsToAppUnits(extraSize.bottom, p2a));
|
2007-12-21 03:51:48 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsRect r(nsPoint(0, 0), aFrame->GetSize());
|
|
|
|
r.Inflate(m);
|
|
|
|
*aResult = r;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
|
|
|
|
nsIFrame* aFrame, PRUint8 aWidgetType,
|
|
|
|
nsSize* aResult, PRBool* aIsOverridable)
|
|
|
|
{
|
|
|
|
aResult->width = aResult->height = 0;
|
|
|
|
*aIsOverridable = PR_TRUE;
|
|
|
|
|
|
|
|
switch (aWidgetType) {
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_UP:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
|
|
|
|
{
|
|
|
|
MozGtkScrollbarMetrics metrics;
|
|
|
|
moz_gtk_get_scrollbar_metrics(&metrics);
|
|
|
|
|
|
|
|
aResult->width = metrics.slider_width;
|
|
|
|
aResult->height = metrics.stepper_size;
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
|
|
|
{
|
|
|
|
MozGtkScrollbarMetrics metrics;
|
|
|
|
moz_gtk_get_scrollbar_metrics(&metrics);
|
|
|
|
|
|
|
|
aResult->width = metrics.stepper_size;
|
|
|
|
aResult->height = metrics.slider_width;
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2007-12-21 03:17:01 -08:00
|
|
|
case NS_THEME_SPLITTER:
|
|
|
|
{
|
|
|
|
gint metrics;
|
|
|
|
if (IsHorizontal(aFrame)) {
|
|
|
|
moz_gtk_splitter_get_metrics(GTK_ORIENTATION_HORIZONTAL, &metrics);
|
|
|
|
aResult->width = metrics;
|
|
|
|
aResult->height = 0;
|
|
|
|
} else {
|
|
|
|
moz_gtk_splitter_get_metrics(GTK_ORIENTATION_VERTICAL, &metrics);
|
|
|
|
aResult->width = 0;
|
|
|
|
aResult->height = metrics;
|
|
|
|
}
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
|
|
|
|
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
|
|
|
|
{
|
|
|
|
MozGtkScrollbarMetrics metrics;
|
|
|
|
moz_gtk_get_scrollbar_metrics(&metrics);
|
|
|
|
|
2008-01-23 23:28:35 -08:00
|
|
|
nsRect rect = aFrame->GetParent()->GetRect();
|
|
|
|
PRInt32 p2a = aFrame->PresContext()->DeviceContext()->
|
|
|
|
AppUnitsPerDevPixel();
|
|
|
|
nsMargin margin;
|
|
|
|
|
|
|
|
/* Get the available space, if that is smaller then the minimum size,
|
|
|
|
* adjust the mininum size to fit into it.
|
|
|
|
* Setting aIsOverridable to PR_TRUE has no effect for thumbs. */
|
|
|
|
aFrame->GetMargin(margin);
|
|
|
|
rect.Deflate(margin);
|
|
|
|
aFrame->GetParent()->GetBorderAndPadding(margin);
|
|
|
|
rect.Deflate(margin);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) {
|
|
|
|
aResult->width = metrics.slider_width;
|
2008-01-23 23:28:35 -08:00
|
|
|
aResult->height = PR_MIN(NSAppUnitsToIntPixels(rect.height, p2a),
|
|
|
|
metrics.min_slider_size);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
|
|
|
aResult->height = metrics.slider_width;
|
2008-01-23 23:28:35 -08:00
|
|
|
aResult->width = PR_MIN(NSAppUnitsToIntPixels(rect.width, p2a),
|
|
|
|
metrics.min_slider_size);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NS_THEME_SCALE_THUMB_HORIZONTAL:
|
|
|
|
case NS_THEME_SCALE_THUMB_VERTICAL:
|
|
|
|
{
|
|
|
|
gint thumb_length, thumb_height;
|
|
|
|
|
|
|
|
if (aWidgetType == NS_THEME_SCALE_THUMB_VERTICAL) {
|
|
|
|
moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_length, &thumb_height);
|
|
|
|
aResult->width = thumb_height;
|
|
|
|
aResult->height = thumb_length;
|
|
|
|
} else {
|
|
|
|
moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height);
|
|
|
|
aResult->width = thumb_length;
|
|
|
|
aResult->height = thumb_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2008-02-14 21:28:44 -08:00
|
|
|
case NS_THEME_TAB_SCROLLARROW_BACK:
|
|
|
|
case NS_THEME_TAB_SCROLLARROW_FORWARD:
|
|
|
|
{
|
|
|
|
moz_gtk_get_tab_scroll_arrow_size(&aResult->width, &aResult->height);
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_DROPDOWN_BUTTON:
|
|
|
|
{
|
2008-03-12 03:54:22 -07:00
|
|
|
moz_gtk_get_combo_box_entry_button_size(&aResult->width,
|
|
|
|
&aResult->height);
|
2007-03-22 10:30:00 -07:00
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2007-12-11 01:09:09 -08:00
|
|
|
case NS_THEME_MENUSEPARATOR:
|
|
|
|
{
|
|
|
|
gint separator_height;
|
|
|
|
|
|
|
|
moz_gtk_get_menu_separator_height(&separator_height);
|
|
|
|
aResult->height = separator_height;
|
|
|
|
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_CHECKBOX:
|
2007-05-09 12:17:17 -07:00
|
|
|
case NS_THEME_CHECKBOX_SMALL:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_RADIO:
|
2007-05-09 12:17:17 -07:00
|
|
|
case NS_THEME_RADIO_SMALL:
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
gint indicator_size, indicator_spacing;
|
|
|
|
|
2007-05-09 12:17:17 -07:00
|
|
|
if (IsCheckboxWidgetType(aWidgetType)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
|
|
|
|
} else {
|
|
|
|
moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Include space for the indicator and the padding around it.
|
2008-03-07 09:58:11 -08:00
|
|
|
aResult->width = indicator_size;
|
|
|
|
aResult->height = indicator_size;
|
2007-03-22 10:30:00 -07:00
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2008-03-12 10:27:03 -07:00
|
|
|
case NS_THEME_TOOLBAR_BUTTON_DROPDOWN:
|
|
|
|
{
|
|
|
|
moz_gtk_get_downarrow_size(&aResult->width, &aResult->height);
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_CHECKBOX_CONTAINER:
|
|
|
|
case NS_THEME_RADIO_CONTAINER:
|
|
|
|
case NS_THEME_CHECKBOX_LABEL:
|
|
|
|
case NS_THEME_RADIO_LABEL:
|
|
|
|
case NS_THEME_BUTTON:
|
2008-03-16 14:05:46 -07:00
|
|
|
case NS_THEME_DROPDOWN:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_TOOLBAR_BUTTON:
|
2007-11-07 01:14:58 -08:00
|
|
|
case NS_THEME_TREEVIEW_HEADER_CELL:
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// Just include our border, and let the box code augment the size.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDeviceContext> dc;
|
|
|
|
aContext->GetDeviceContext(*getter_AddRefs(dc));
|
|
|
|
|
|
|
|
nsMargin border;
|
|
|
|
nsNativeThemeGTK::GetWidgetBorder(dc, aFrame, aWidgetType, &border);
|
|
|
|
aResult->width = border.left + border.right;
|
|
|
|
aResult->height = border.top + border.bottom;
|
|
|
|
}
|
|
|
|
break;
|
2007-12-03 01:13:29 -08:00
|
|
|
case NS_THEME_TOOLBAR_SEPARATOR:
|
|
|
|
{
|
|
|
|
gint separator_width;
|
|
|
|
|
|
|
|
moz_gtk_get_toolbar_separator_width(&separator_width);
|
|
|
|
|
|
|
|
aResult->width = separator_width;
|
|
|
|
}
|
|
|
|
break;
|
2007-12-21 03:30:29 -08:00
|
|
|
case NS_THEME_SPINNER:
|
|
|
|
// hard code these sizes
|
|
|
|
aResult->width = 14;
|
|
|
|
aResult->height = 26;
|
|
|
|
break;
|
2007-11-13 00:43:03 -08:00
|
|
|
case NS_THEME_TREEVIEW_HEADER_SORTARROW:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_SPINNER_UP_BUTTON:
|
|
|
|
case NS_THEME_SPINNER_DOWN_BUTTON:
|
|
|
|
// hard code these sizes
|
|
|
|
aResult->width = 14;
|
|
|
|
aResult->height = 13;
|
|
|
|
break;
|
2007-12-11 02:08:35 -08:00
|
|
|
case NS_THEME_RESIZER:
|
|
|
|
// same as Windows to make our lives easier
|
|
|
|
aResult->width = aResult->height = 15;
|
|
|
|
break;
|
2007-11-14 19:47:16 -08:00
|
|
|
case NS_THEME_TREEVIEW_TWISTY:
|
|
|
|
case NS_THEME_TREEVIEW_TWISTY_OPEN:
|
|
|
|
{
|
|
|
|
gint expander_size;
|
|
|
|
|
2008-01-02 23:07:32 -08:00
|
|
|
moz_gtk_get_treeview_expander_size(&expander_size);
|
2007-11-14 19:47:16 -08:00
|
|
|
aResult->width = aResult->height = expander_size;
|
|
|
|
*aIsOverridable = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType,
|
|
|
|
nsIAtom* aAttribute, PRBool* aShouldRepaint)
|
|
|
|
{
|
|
|
|
// Some widget types just never change state.
|
|
|
|
if (aWidgetType == NS_THEME_TOOLBOX ||
|
|
|
|
aWidgetType == NS_THEME_TOOLBAR ||
|
|
|
|
aWidgetType == NS_THEME_STATUSBAR ||
|
|
|
|
aWidgetType == NS_THEME_STATUSBAR_PANEL ||
|
|
|
|
aWidgetType == NS_THEME_STATUSBAR_RESIZER_PANEL ||
|
|
|
|
aWidgetType == NS_THEME_PROGRESSBAR_CHUNK ||
|
|
|
|
aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL ||
|
|
|
|
aWidgetType == NS_THEME_PROGRESSBAR ||
|
|
|
|
aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL ||
|
|
|
|
aWidgetType == NS_THEME_MENUBAR ||
|
|
|
|
aWidgetType == NS_THEME_MENUPOPUP ||
|
|
|
|
aWidgetType == NS_THEME_TOOLTIP ||
|
2007-12-11 01:09:09 -08:00
|
|
|
aWidgetType == NS_THEME_MENUSEPARATOR ||
|
2007-03-22 10:30:00 -07:00
|
|
|
aWidgetType == NS_THEME_WINDOW ||
|
|
|
|
aWidgetType == NS_THEME_DIALOG) {
|
|
|
|
*aShouldRepaint = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-02-07 01:26:22 -08:00
|
|
|
if ((aWidgetType == NS_THEME_SCROLLBAR_BUTTON_UP ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_DOWN ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT ||
|
|
|
|
aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT) &&
|
|
|
|
(aAttribute == nsWidgetAtoms::curpos ||
|
|
|
|
aAttribute == nsWidgetAtoms::maxpos)) {
|
|
|
|
*aShouldRepaint = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXXdwh Not sure what can really be done here. Can at least guess for
|
|
|
|
// specific widgets that they're highly unlikely to have certain states.
|
|
|
|
// For example, a toolbar doesn't care about any states.
|
|
|
|
if (!aAttribute) {
|
|
|
|
// Hover/focus/active changed. Always repaint.
|
|
|
|
*aShouldRepaint = PR_TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Check the attribute to see if it's relevant.
|
|
|
|
// disabled, checked, dlgtype, default, etc.
|
|
|
|
*aShouldRepaint = PR_FALSE;
|
|
|
|
if (aAttribute == nsWidgetAtoms::disabled ||
|
|
|
|
aAttribute == nsWidgetAtoms::checked ||
|
|
|
|
aAttribute == nsWidgetAtoms::selected ||
|
|
|
|
aAttribute == nsWidgetAtoms::focused ||
|
2007-06-04 20:26:43 -07:00
|
|
|
aAttribute == nsWidgetAtoms::readonly ||
|
2007-09-02 09:38:54 -07:00
|
|
|
aAttribute == nsWidgetAtoms::_default ||
|
2008-01-12 18:56:01 -08:00
|
|
|
aAttribute == nsWidgetAtoms::mozmenuactive ||
|
2008-02-10 00:30:04 -08:00
|
|
|
aAttribute == nsWidgetAtoms::open ||
|
|
|
|
aAttribute == nsWidgetAtoms::parentfocused)
|
2007-03-22 10:30:00 -07:00
|
|
|
*aShouldRepaint = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsNativeThemeGTK::ThemeChanged()
|
|
|
|
{
|
|
|
|
// this totally sucks. this method is really supposed to be
|
|
|
|
// static, which is why we can call it without any initialization.
|
|
|
|
static NS_DEFINE_CID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
|
|
|
|
nsCOMPtr<nsIDeviceContext> dctx = do_CreateInstance(kDeviceContextCID);
|
|
|
|
dctx->ClearCachedSystemFonts();
|
|
|
|
|
|
|
|
memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(PRBool)
|
|
|
|
nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
PRUint8 aWidgetType)
|
|
|
|
{
|
|
|
|
if (IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType))
|
|
|
|
return PR_FALSE;
|
|
|
|
|
|
|
|
switch (aWidgetType) {
|
|
|
|
case NS_THEME_BUTTON:
|
|
|
|
case NS_THEME_BUTTON_FOCUS:
|
|
|
|
case NS_THEME_RADIO:
|
2007-05-09 12:17:17 -07:00
|
|
|
case NS_THEME_RADIO_SMALL:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_CHECKBOX:
|
2007-05-09 12:17:17 -07:00
|
|
|
case NS_THEME_CHECKBOX_SMALL:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_TOOLBOX: // N/A
|
|
|
|
case NS_THEME_TOOLBAR:
|
|
|
|
case NS_THEME_TOOLBAR_BUTTON:
|
|
|
|
case NS_THEME_TOOLBAR_DUAL_BUTTON: // so we can override the border with 0
|
2008-01-17 02:24:31 -08:00
|
|
|
case NS_THEME_TOOLBAR_BUTTON_DROPDOWN:
|
2007-12-03 01:13:29 -08:00
|
|
|
case NS_THEME_TOOLBAR_SEPARATOR:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_TOOLBAR_GRIPPER:
|
|
|
|
case NS_THEME_STATUSBAR:
|
|
|
|
case NS_THEME_STATUSBAR_PANEL:
|
2007-11-14 23:35:41 -08:00
|
|
|
case NS_THEME_STATUSBAR_RESIZER_PANEL:
|
2007-12-11 02:08:35 -08:00
|
|
|
case NS_THEME_RESIZER:
|
2007-06-12 11:29:51 -07:00
|
|
|
case NS_THEME_LISTBOX:
|
2007-03-22 10:30:00 -07:00
|
|
|
// case NS_THEME_LISTBOX_LISTITEM:
|
2007-11-07 01:14:58 -08:00
|
|
|
case NS_THEME_TREEVIEW:
|
2007-03-22 10:30:00 -07:00
|
|
|
// case NS_THEME_TREEVIEW_TREEITEM:
|
2007-11-14 19:47:16 -08:00
|
|
|
case NS_THEME_TREEVIEW_TWISTY:
|
2007-03-22 10:30:00 -07:00
|
|
|
// case NS_THEME_TREEVIEW_LINE:
|
|
|
|
// case NS_THEME_TREEVIEW_HEADER:
|
2007-11-07 01:14:58 -08:00
|
|
|
case NS_THEME_TREEVIEW_HEADER_CELL:
|
2007-11-13 00:43:03 -08:00
|
|
|
case NS_THEME_TREEVIEW_HEADER_SORTARROW:
|
2007-11-14 19:47:16 -08:00
|
|
|
case NS_THEME_TREEVIEW_TWISTY_OPEN:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_PROGRESSBAR:
|
|
|
|
case NS_THEME_PROGRESSBAR_CHUNK:
|
|
|
|
case NS_THEME_PROGRESSBAR_VERTICAL:
|
|
|
|
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
|
|
|
|
case NS_THEME_TAB:
|
|
|
|
// case NS_THEME_TAB_PANEL:
|
|
|
|
case NS_THEME_TAB_PANELS:
|
2008-02-14 21:28:44 -08:00
|
|
|
case NS_THEME_TAB_SCROLLARROW_BACK:
|
|
|
|
case NS_THEME_TAB_SCROLLARROW_FORWARD:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_TOOLTIP:
|
2007-12-21 03:30:29 -08:00
|
|
|
case NS_THEME_SPINNER:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_SPINNER_UP_BUTTON:
|
|
|
|
case NS_THEME_SPINNER_DOWN_BUTTON:
|
2007-12-21 03:30:29 -08:00
|
|
|
case NS_THEME_SPINNER_TEXTFIELD:
|
2007-03-22 10:30:00 -07:00
|
|
|
// case NS_THEME_SCROLLBAR: (n/a for gtk)
|
2007-07-13 14:46:28 -07:00
|
|
|
// case NS_THEME_SCROLLBAR_SMALL: (n/a for gtk)
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_UP:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
|
|
|
|
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
|
|
|
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
|
|
|
|
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
|
|
|
|
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
|
|
|
|
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
|
|
|
|
// case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL: (n/a for gtk)
|
|
|
|
// case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL: (n/a for gtk)
|
|
|
|
case NS_THEME_TEXTFIELD:
|
2007-05-06 19:06:58 -07:00
|
|
|
case NS_THEME_TEXTFIELD_MULTILINE:
|
2007-03-22 10:30:00 -07:00
|
|
|
// case NS_THEME_TEXTFIELD_CARET:
|
|
|
|
case NS_THEME_DROPDOWN_TEXTFIELD:
|
|
|
|
case NS_THEME_SCALE_HORIZONTAL:
|
|
|
|
case NS_THEME_SCALE_THUMB_HORIZONTAL:
|
|
|
|
case NS_THEME_SCALE_VERTICAL:
|
|
|
|
case NS_THEME_SCALE_THUMB_VERTICAL:
|
|
|
|
// case NS_THEME_SCALE_THUMB_START:
|
|
|
|
// case NS_THEME_SCALE_THUMB_END:
|
|
|
|
// case NS_THEME_SCALE_TICK:
|
|
|
|
case NS_THEME_CHECKBOX_CONTAINER:
|
|
|
|
case NS_THEME_RADIO_CONTAINER:
|
|
|
|
case NS_THEME_CHECKBOX_LABEL:
|
|
|
|
case NS_THEME_RADIO_LABEL:
|
|
|
|
case NS_THEME_MENUBAR:
|
|
|
|
case NS_THEME_MENUPOPUP:
|
|
|
|
case NS_THEME_MENUITEM:
|
2007-11-28 14:45:21 -08:00
|
|
|
case NS_THEME_MENUARROW:
|
2007-12-11 01:09:09 -08:00
|
|
|
case NS_THEME_MENUSEPARATOR:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_CHECKMENUITEM:
|
|
|
|
case NS_THEME_RADIOMENUITEM:
|
2007-12-21 03:17:01 -08:00
|
|
|
case NS_THEME_SPLITTER:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_THEME_WINDOW:
|
|
|
|
case NS_THEME_DIALOG:
|
|
|
|
case NS_THEME_DROPDOWN:
|
|
|
|
case NS_THEME_DROPDOWN_TEXT:
|
|
|
|
return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
|
2007-10-25 13:23:13 -07:00
|
|
|
|
|
|
|
case NS_THEME_DROPDOWN_BUTTON:
|
|
|
|
// "Native" dropdown buttons cause padding and margin problems, but only
|
|
|
|
// in HTML so allow them in XUL.
|
|
|
|
return (!aFrame || aFrame->GetContent()->IsNodeOfType(nsINode::eXUL)) &&
|
|
|
|
!IsWidgetStyled(aPresContext, aFrame, aWidgetType);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(PRBool)
|
|
|
|
nsNativeThemeGTK::WidgetIsContainer(PRUint8 aWidgetType)
|
|
|
|
{
|
|
|
|
// XXXdwh At some point flesh all of this out.
|
2008-02-14 21:28:44 -08:00
|
|
|
if (aWidgetType == NS_THEME_DROPDOWN_BUTTON ||
|
2007-05-09 12:17:17 -07:00
|
|
|
IsRadioWidgetType(aWidgetType) ||
|
2008-02-14 21:28:44 -08:00
|
|
|
IsCheckboxWidgetType(aWidgetType) ||
|
|
|
|
aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK ||
|
|
|
|
aWidgetType == NS_THEME_TAB_SCROLLARROW_FORWARD)
|
2007-03-22 10:30:00 -07:00
|
|
|
return PR_FALSE;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsNativeThemeGTK::ThemeDrawsFocusForWidget(nsPresContext* aPresContext, nsIFrame* aFrame, PRUint8 aWidgetType)
|
|
|
|
{
|
2007-06-04 20:26:43 -07:00
|
|
|
if (aWidgetType == NS_THEME_DROPDOWN ||
|
2007-11-07 01:14:58 -08:00
|
|
|
aWidgetType == NS_THEME_BUTTON ||
|
|
|
|
aWidgetType == NS_THEME_TREEVIEW_HEADER_CELL)
|
2007-06-04 20:26:43 -07:00
|
|
|
return PR_TRUE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2007-05-17 20:04:04 -07:00
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsNativeThemeGTK::ThemeNeedsComboboxDropmarker()
|
|
|
|
{
|
2007-06-04 20:26:43 -07:00
|
|
|
return PR_FALSE;
|
2007-05-17 20:04:04 -07:00
|
|
|
}
|