Lots of fixes for native themed checkbox and radio buttons on gtk2. Bug 247631, r=caillon, sr=blizzard.

This commit is contained in:
bryner%brianryner.com 2005-08-20 07:14:00 +00:00
Родитель 54bb8c0ad7
Коммит f83f0d84d1
6 изменённых файлов: 435 добавлений и 234 удалений

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

@ -351,24 +351,44 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
GtkStyle* style = gCheckboxWidget->style;
if (indicator_size)
*indicator_size = style_prop_func(style,
"GtkCheckButton::indicator_size",
klass->indicator_size);
if (indicator_spacing)
*indicator_spacing = style_prop_func(style,
"GtkCheckButton::indicator_spacing",
klass->indicator_spacing);
*indicator_size = style_prop_func(style,
"GtkCheckButton::indicator_size",
klass->indicator_size);
*indicator_spacing = style_prop_func(style,
"GtkCheckButton::indicator_spacing",
klass->indicator_spacing);
} else {
if (indicator_size)
*indicator_size = klass->indicator_size;
if (indicator_spacing)
*indicator_spacing = klass->indicator_spacing;
*indicator_size = klass->indicator_size;
*indicator_spacing = klass->indicator_spacing;
}
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
{
return moz_gtk_checkbox_get_metrics(indicator_size, indicator_spacing);
}
gint
moz_gtk_checkbox_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad)
{
/* These values are hardcoded in gtk1. */
*interior_focus = FALSE;
*focus_width = 1;
*focus_pad = 0;
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_radio_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad)
{
return moz_gtk_checkbox_get_focus(interior_focus, focus_width, focus_pad);
}
static gint
moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect, GtkWidgetState* state,
@ -376,15 +396,15 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect,
{
GtkStateType state_type;
GtkShadowType shadow_type;
gint indicator_size;
gint indicator_size, indicator_spacing;
gint x, y, width, height;
GtkStyle* style;
moz_gtk_checkbox_get_metrics(&indicator_size, NULL);
moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
style = gCheckboxWidget->style;
/* centered within the rect */
x = rect->x + (rect->width - indicator_size) / 2;
/* offset by indicator_spacing, and centered vertically within the rect */
x = rect->x + indicator_spacing;
y = rect->y + (rect->height - indicator_size) / 2;
width = indicator_size;
height = indicator_size;
@ -833,13 +853,17 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* xthickness,
break;
case MOZ_GTK_CHECKBUTTON_CONTAINER:
case MOZ_GTK_RADIOBUTTON_CONTAINER:
/* This is a hardcoded value. */
if (xthickness)
*xthickness = 1;
if (ythickness)
*ythickness = 1;
ensure_checkbox_widget();
*xthickness = *ythickness =
GTK_CONTAINER(gCheckboxWidget)->border_width + 1;
return MOZ_GTK_SUCCESS;
break;
case MOZ_GTK_CHECKBUTTON_LABEL:
case MOZ_GTK_RADIOBUTTON_LABEL:
*xthickness = *ythickness = 0;
return MOZ_GTK_SUCCESS;
case MOZ_GTK_CHECKBUTTON:
case MOZ_GTK_RADIOBUTTON:
case MOZ_GTK_SCROLLBAR_BUTTON:
@ -852,20 +876,16 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* xthickness,
case MOZ_GTK_PROGRESS_CHUNK:
case MOZ_GTK_TAB:
/* These widgets have no borders, since they are not containers. */
if (xthickness)
*xthickness = 0;
if (ythickness)
*ythickness = 0;
*xthickness = 0;
*ythickness = 0;
return MOZ_GTK_SUCCESS;
default:
g_warning("Unsupported widget type: %d", widget);
return MOZ_GTK_UNKNOWN_WIDGET;
}
if (xthickness)
*xthickness = w->style->klass->xthickness;
if (ythickness)
*ythickness = w->style->klass->ythickness;
*xthickness = w->style->klass->xthickness;
*ythickness = w->style->klass->ythickness;
return MOZ_GTK_SUCCESS;
}
@ -881,22 +901,17 @@ moz_gtk_get_dropdown_arrow_size(gint* width, gint* height)
* 11 pixels.
*/
if (width) {
*width = 2 * (1 + gDropdownButtonWidget->style->klass->xthickness);
*width += 11 + GTK_MISC(gArrowWidget)->xpad * 2;
}
if (height) {
*height = 2 * (1 + gDropdownButtonWidget->style->klass->ythickness);
*height += 11 + GTK_MISC(gArrowWidget)->ypad * 2;
}
*width = 2 * (1 + gDropdownButtonWidget->style->klass->xthickness);
*width += 11 + GTK_MISC(gArrowWidget)->xpad * 2;
*height = 2 * (1 + gDropdownButtonWidget->style->klass->ythickness);
*height += 11 + GTK_MISC(gArrowWidget)->ypad * 2;
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_get_scrollbar_metrics(gint* slider_width, gint* trough_border,
gint* stepper_size, gint* stepper_spacing,
gint* min_slider_size)
moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
{
GtkRangeClass* klass;
GtkStyle* style;
@ -910,41 +925,30 @@ moz_gtk_get_scrollbar_metrics(gint* slider_width, gint* trough_border,
* This API is supported only in GTK+ >= 1.2.9, and gives per-theme values.
*/
if (slider_width)
*slider_width = style_prop_func(style, "GtkRange::slider_width",
klass->slider_width);
metrics->slider_width = style_prop_func(style, "GtkRange::slider_width",
klass->slider_width);
if (trough_border)
*trough_border = style_prop_func(style, "GtkRange::trough_border",
style->klass->xthickness);
metrics->trough_border = style_prop_func(style, "GtkRange::trough_border",
style->klass->xthickness);
if (stepper_size)
*stepper_size = style_prop_func(style, "GtkRange::stepper_size",
klass->stepper_size);
metrics->stepper_size = style_prop_func(style, "GtkRange::stepper_size",
klass->stepper_size);
if (stepper_spacing)
*stepper_spacing = style_prop_func(style, "GtkRange::stepper_spacing",
klass->stepper_slider_spacing);
metrics->stepper_spacing = style_prop_func(style,
"GtkRange::stepper_spacing",
klass->stepper_slider_spacing);
} else {
/*
* This is the older method, which gives per-engine values.
*/
if (slider_width)
*slider_width = klass->slider_width;
if (trough_border)
*trough_border = style->klass->xthickness;
if (stepper_size)
*stepper_size = klass->stepper_size;
if (stepper_spacing)
*stepper_spacing = klass->stepper_slider_spacing;
metrics->slider_width = klass->slider_width;
metrics->trough_border = style->klass->xthickness;
metrics->stepper_size = klass->stepper_size;
metrics->stepper_spacing = klass->stepper_slider_spacing;
}
if (min_slider_size)
*min_slider_size = klass->min_slider_size;
metrics->min_slider_size = klass->min_slider_size;
return MOZ_GTK_SUCCESS;
}
@ -1013,6 +1017,11 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
case MOZ_GTK_TABPANELS:
return moz_gtk_tabpanels_paint(drawable, rect, cliprect);
break;
case MOZ_GTK_CHECKBUTTON_LABEL:
case MOZ_GTK_RADIOBUTTON_LABEL:
/* We only support these so that we can prevent the CSS border
from being drawn. */
return MOZ_GTK_SUCCESS;
default:
g_warning("Unknown widget type: %d", widget);
}

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

@ -67,6 +67,14 @@ typedef struct {
gint32 maxpos;
} GtkWidgetState;
typedef struct {
gint slider_width;
gint trough_border;
gint stepper_size;
gint stepper_spacing;
gint min_slider_size;
} MozGtkScrollbarMetrics;
/** flags for tab state **/
typedef enum {
/* the first tab in the group */
@ -114,6 +122,10 @@ typedef enum {
MOZ_GTK_CHECKBUTTON_CONTAINER,
/* Paints the container part of a GtkRadioButton. */
MOZ_GTK_RADIOBUTTON_CONTAINER,
/* Paints the label of a GtkCheckButton (focus outline) */
MOZ_GTK_CHECKBUTTON_LABEL,
/* Paints the label of a GtkRadioButton (focus outline) */
MOZ_GTK_RADIOBUTTON_LABEL,
/* Paints the background of a GtkHandleBox. */
MOZ_GTK_TOOLBAR,
/* Paints a GtkToolTip */
@ -211,22 +223,32 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing);
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
#define moz_gtk_radio_get_metrics(x, y) moz_gtk_checkbox_get_metrics(x, y)
gint
moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
/**
* Get the desired metrics for a GtkScrollbar
* slider_width: [OUT] the width of the slider (thumb)
* trough_border: [OUT] the border of the trough (outside the thumb)
* stepper_size: [OUT] the size of an arrow button
* stepper_spacing: [OUT] the minimum space between the thumb and the arrow
* min_slider_size: [OUT] the minimum thumb size
/** Get the focus metrics for a checkbox or radio button
* interior_focus: [OUT] whether the focus is drawn around the
* label (TRUE) or around the whole container (FALSE)
* focus_width: [OUT] the width of the focus line
* focus_pad: [OUT] the padding between the focus line and children
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint
moz_gtk_get_scrollbar_metrics(gint* slider_width, gint* trough_border,
gint* stepper_size, gint* stepper_spacing,
gint* min_slider_size);
moz_gtk_checkbox_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
gint
moz_gtk_radio_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
/**
* Get the desired metrics for a GtkScrollbar
* metrics: [IN] struct which will contain the metrics
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint
moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics* metrics);
/**
* Get the desired size of a dropdown arrow button

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

@ -251,20 +251,26 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
aFrame = aFrame->GetParent();
// For XUL checkboxes and radio buttons, the state of the parent
// determines our state.
if (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO) {
if (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO ||
aWidgetType == NS_THEME_CHECKBOX_LABEL ||
aWidgetType == NS_THEME_RADIO_LABEL) {
if (aWidgetFlags) {
nsIAtom* atom = nsnull;
if (aFrame) {
nsIContent* content = aFrame->GetContent();
if (content->IsContentOfType(nsIContent::eXUL))
if (content->IsContentOfType(nsIContent::eXUL)) {
aFrame = aFrame->GetParent();
if (aWidgetType == NS_THEME_CHECKBOX_LABEL ||
aWidgetType == NS_THEME_RADIO_LABEL)
aFrame = aFrame->GetParent();
}
else if (content->Tag() == mInputAtom)
atom = mInputCheckedAtom;
}
if (!atom)
atom = (aWidgetType == NS_THEME_CHECKBOX) ? mCheckedAtom : mSelectedAtom;
atom = (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_CHECKBOX_LABEL) ? mCheckedAtom : mSelectedAtom;
*aWidgetFlags = CheckBooleanAttr(aFrame, atom);
}
}
@ -278,9 +284,14 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
aState->isDefault = FALSE; // XXX fix me
aState->canDefault = FALSE; // XXX fix me
// For these widget types, some element (either a child or parent)
// actually has element focus, so we check the focused attribute
// to see whether to draw in the focused state.
if (aWidgetType == NS_THEME_TEXTFIELD ||
aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD ||
aWidgetType == NS_THEME_RADIO_CONTAINER) {
aWidgetType == NS_THEME_RADIO_CONTAINER ||
aWidgetType == NS_THEME_RADIO_LABEL ||
aWidgetType == NS_THEME_RADIO) {
aState->focused = CheckBooleanAttr(aFrame, mFocusedAtom);
}
@ -371,6 +382,12 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
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;
@ -512,10 +529,9 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
{
gint trough_border;
moz_gtk_get_scrollbar_metrics(nsnull, &trough_border,
nsnull, nsnull, nsnull);
aResult->top = aResult->left = trough_border;
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
aResult->top = aResult->left = metrics.trough_border;
}
break;
case NS_THEME_TOOLBOX:
@ -535,6 +551,7 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
aResult->right = aResult->left;
aResult->bottom = aResult->top;
return NS_OK;
}
@ -552,28 +569,26 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
{
gint slider_width, stepper_size;
moz_gtk_get_scrollbar_metrics(&slider_width, nsnull, &stepper_size,
nsnull, nsnull);
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
aResult->width = slider_width;
aResult->height = stepper_size;
aResult->width = metrics.slider_width;
aResult->height = metrics.stepper_size;
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
{
gint slider_width, min_slider_size;
moz_gtk_get_scrollbar_metrics(&slider_width, nsnull, nsnull, nsnull,
&min_slider_size);
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) {
aResult->width = slider_width;
aResult->height = min_slider_size;
aResult->width = metrics.slider_width;
aResult->height = metrics.min_slider_size;
} else {
aResult->width = min_slider_size;
aResult->height = slider_width;
aResult->width = metrics.min_slider_size;
aResult->height = metrics.slider_width;
}
*aIsOverridable = PR_FALSE;
@ -581,31 +596,44 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
break;
case NS_THEME_DROPDOWN_BUTTON:
{
// First, get the minimum size for the button itself.
moz_gtk_get_dropdown_arrow_size(&aResult->width, &aResult->height);
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_CHECKBOX:
case NS_THEME_RADIO:
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
{
gint indicator_size, indicator_spacing;
if (aWidgetType == NS_THEME_CHECKBOX ||
aWidgetType == NS_THEME_CHECKBOX_CONTAINER)
if (aWidgetType == NS_THEME_CHECKBOX) {
moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
else
} else {
moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
}
// Hack alert: several themes have indicators larger than the default
// 10px size, but don't set the indicator size property. So, leave
// a little slop room by making the minimum size 14px.
aResult->width = aResult->height = MAX(indicator_size, 14);
// Include space for the indicator and the padding around it.
aResult->width = indicator_size + 3 * indicator_spacing;
aResult->height = indicator_size + 2 * indicator_spacing;
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
{
// Just include our border, and let the box code augment the size.
nsCOMPtr<nsIDeviceContext> dc;
aContext->GetDeviceContext(*getter_AddRefs(dc));
nsMargin border;
nsNativeThemeGTK::GetWidgetBorder(dc, aFrame, aWidgetType, &border);
aResult->width = border.left + border.right;
aResult->height = border.top + border.bottom;
}
break;
}
return NS_OK;
@ -737,6 +765,8 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsIPresContext* aPresContext,
// case NS_THEME_SLIDER_TICK:
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
#ifdef MOZ_WIDGET_GTK2
case NS_THEME_MENUBAR:
case NS_THEME_MENUPOPUP:

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

@ -408,33 +408,53 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
{
ensure_checkbox_widget();
if (indicator_size) {
gtk_widget_style_get (gCheckboxWidget, "indicator_size",
indicator_size, NULL);
}
if (indicator_spacing) {
gtk_widget_style_get (gCheckboxWidget, "indicator_spacing",
indicator_spacing, NULL);
}
gtk_widget_style_get (gCheckboxWidget,
"indicator_size", indicator_size,
"indicator_spacing", indicator_spacing,
NULL);
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_radiobutton_get_metrics(gint* indicator_size, gint* indicator_spacing)
moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
{
ensure_radiobutton_widget();
if (indicator_size) {
gtk_widget_style_get (gRadiobuttonWidget, "indicator_size",
indicator_size, NULL);
}
gtk_widget_style_get (gRadiobuttonWidget,
"indicator_size", indicator_size,
"indicator_spacing", indicator_spacing,
NULL);
if (indicator_spacing) {
gtk_widget_style_get (gRadiobuttonWidget, "indicator_spacing",
indicator_spacing, NULL);
}
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_checkbox_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad)
{
ensure_checkbox_widget();
gtk_widget_style_get (gCheckboxWidget,
"interior-focus", interior_focus,
"focus-line-width", focus_width,
"focus-padding", focus_pad,
NULL);
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_radio_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad)
{
ensure_radiobutton_widget();
gtk_widget_style_get (gRadiobuttonWidget,
"interior-focus", interior_focus,
"focus-line-width", focus_width,
"focus-padding", focus_pad,
NULL);
return MOZ_GTK_SUCCESS;
}
@ -446,35 +466,35 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect,
{
GtkStateType state_type = ConvertGtkState(state);
GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
gint indicator_size;
gint indicator_size, indicator_spacing;
gint x, y, width, height;
GtkStyle* style;
GtkWidget *w;
GtkStyle *style;
if (isradio) {
moz_gtk_radiobutton_get_metrics(&indicator_size, NULL);
style = gRadiobuttonWidget->style;
moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
w = gRadiobuttonWidget;
} else {
moz_gtk_checkbox_get_metrics(&indicator_size, NULL);
style = gCheckboxWidget->style;
moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
w = gCheckboxWidget;
}
/* centered within the rect */
x = rect->x + (rect->width - indicator_size) / 2;
/* offset by indicator_spacing, and centered vertically within the rect */
x = rect->x + indicator_spacing;
y = rect->y + (rect->height - indicator_size) / 2;
width = indicator_size;
height = indicator_size;
style = w->style;
TSOffsetStyleGCs(style, x, y);
/* Some themes check the widget state themselves. */
if (isradio) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gRadiobuttonWidget),
selected);
}
else {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gCheckboxWidget),
selected);
}
if (state->focused)
GTK_WIDGET_SET_FLAGS(w, GTK_HAS_FOCUS);
else
GTK_WIDGET_UNSET_FLAGS(w, GTK_HAS_FOCUS);
GTK_TOGGLE_BUTTON(w)->active = selected;
if (isradio) {
gtk_paint_option(style, drawable, state_type, shadow_type, cliprect,
@ -779,17 +799,24 @@ moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect,
{
GtkStateType state_type = ConvertGtkState(state);
GtkStyle* style;
gboolean interior_focus;
gint focus_width, focus_pad;
if (isradio) {
ensure_radiobutton_widget();
style = gRadiobuttonWidget->style;
moz_gtk_radio_get_focus(&interior_focus, &focus_width, &focus_pad);
} else {
ensure_checkbox_widget();
style = gCheckboxWidget->style;
moz_gtk_checkbox_get_focus(&interior_focus, &focus_width, &focus_pad);
}
TSOffsetStyleGCs(style, rect->x, rect->y);
/* The detail argument for the gtk_paint_* calls below are "checkbutton"
even for radio buttons, to match what gtk does. */
/* this is for drawing a prelight box */
if (state_type == GTK_STATE_PRELIGHT || state_type == GTK_STATE_ACTIVE) {
gtk_paint_flat_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_ETCHED_OUT,
@ -801,15 +828,53 @@ moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect,
if (state_type != GTK_STATE_NORMAL && state_type != GTK_STATE_PRELIGHT)
state_type = GTK_STATE_NORMAL;
if (state->focused) {
if (state->focused && !interior_focus) {
gtk_paint_focus(style, drawable, state_type, cliprect, gCheckboxWidget,
isradio ? "radiobutton" : "checkbutton",
"checkbutton",
rect->x, rect->y, rect->width, rect->height);
}
return MOZ_GTK_SUCCESS;
}
static gint
moz_gtk_toggle_label_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect, GtkWidgetState* state,
gboolean isradio)
{
GtkStateType state_type;
GtkStyle *style;
GtkWidget *widget;
gboolean interior_focus;
if (!state->focused)
return MOZ_GTK_SUCCESS;
if (isradio) {
ensure_radiobutton_widget();
widget = gRadiobuttonWidget;
} else {
ensure_checkbox_widget();
widget = gCheckboxWidget;
}
gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL);
if (!interior_focus)
return MOZ_GTK_SUCCESS;
state_type = ConvertGtkState(state);
style = widget->style;
TSOffsetStyleGCs(style, rect->x, rect->y);
/* Always "checkbutton" to match gtkcheckbutton.c */
gtk_paint_focus(style, drawable, state_type, cliprect, widget,
"checkbutton",
rect->x, rect->y, rect->width, rect->height);
return MOZ_GTK_SUCCESS;
}
static gint
moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
GdkRectangle* cliprect)
@ -1110,15 +1175,57 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* xthickness,
ensure_frame_widget();
w = gFrameWidget;
break;
case MOZ_GTK_CHECKBUTTON_LABEL:
case MOZ_GTK_RADIOBUTTON_LABEL:
{
gboolean interior_focus;
gint focus_width, focus_pad;
/* If the focus is interior, then the label has a border of
(focus_width + focus_pad). */
if (widget == MOZ_GTK_CHECKBUTTON_LABEL)
moz_gtk_checkbox_get_focus(&interior_focus,
&focus_width, &focus_pad);
else
moz_gtk_radio_get_focus(&interior_focus,
&focus_width, &focus_pad);
if (interior_focus)
*xthickness = *ythickness = (focus_width + focus_pad);
else
*xthickness = *ythickness = 0;
return MOZ_GTK_SUCCESS;
}
case MOZ_GTK_CHECKBUTTON_CONTAINER:
case MOZ_GTK_RADIOBUTTON_CONTAINER:
/* This is a hardcoded value. */
if (xthickness)
*xthickness = 1;
if (ythickness)
*ythickness = 1;
return MOZ_GTK_SUCCESS;
break;
{
gboolean interior_focus;
gint focus_width, focus_pad;
/* If the focus is _not_ interior, then the container has a border
of (focus_width + focus_pad). */
if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) {
w = gCheckboxWidget;
moz_gtk_checkbox_get_focus(&interior_focus,
&focus_width, &focus_pad);
} else {
w = gRadiobuttonWidget;
moz_gtk_radio_get_focus(&interior_focus,
&focus_width, &focus_pad);
}
*xthickness = *ythickness = GTK_CONTAINER(w)->border_width;
if (!interior_focus) {
*xthickness += (focus_width + focus_pad);
*ythickness += (focus_width + focus_pad);
}
return MOZ_GTK_SUCCESS;
}
case MOZ_GTK_MENUBAR:
ensure_menu_bar_widget();
w = gMenuBarWidget;
@ -1145,20 +1252,15 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* xthickness,
/* These widgets have no borders.*/
case MOZ_GTK_TOOLTIP:
case MOZ_GTK_WINDOW:
if (xthickness)
*xthickness = 0;
if (ythickness)
*ythickness = 0;
*xthickness = *ythickness = 0;
return MOZ_GTK_SUCCESS;
default:
g_warning("Unsupported widget type: %d", widget);
return MOZ_GTK_UNKNOWN_WIDGET;
}
if (xthickness)
*xthickness = XTHICKNESS(w->style);
if (ythickness)
*ythickness = YTHICKNESS(w->style);
*xthickness = XTHICKNESS(w->style);
*ythickness = YTHICKNESS(w->style);
return MOZ_GTK_SUCCESS;
}
@ -1174,48 +1276,29 @@ moz_gtk_get_dropdown_arrow_size(gint* width, gint* height)
* 11 pixels.
*/
if (width) {
*width = 2 * (1 + XTHICKNESS(gDropdownButtonWidget->style));
*width += 11 + GTK_MISC(gArrowWidget)->xpad * 2;
}
if (height) {
*height = 2 * (1 + YTHICKNESS(gDropdownButtonWidget->style));
*height += 11 + GTK_MISC(gArrowWidget)->ypad * 2;
}
*width = 2 * (1 + XTHICKNESS(gDropdownButtonWidget->style));
*width += 11 + GTK_MISC(gArrowWidget)->xpad * 2;
*height = 2 * (1 + YTHICKNESS(gDropdownButtonWidget->style));
*height += 11 + GTK_MISC(gArrowWidget)->ypad * 2;
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_get_scrollbar_metrics(gint* slider_width, gint* trough_border,
gint* stepper_size, gint* stepper_spacing,
gint* min_slider_size)
moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
{
ensure_scrollbar_widget();
if (slider_width) {
gtk_widget_style_get (gHorizScrollbarWidget, "slider_width",
slider_width, NULL);
}
gtk_widget_style_get (gHorizScrollbarWidget,
"slider_width", &metrics->slider_width,
"trough_border", &metrics->trough_border,
"stepper_size", &metrics->stepper_size,
"stepper_spacing", &metrics->stepper_spacing,
NULL);
if (trough_border) {
gtk_widget_style_get (gHorizScrollbarWidget, "trough_border",
trough_border, NULL);
}
if (stepper_size) {
gtk_widget_style_get (gHorizScrollbarWidget, "stepper_size",
stepper_size, NULL);
}
if (stepper_spacing) {
gtk_widget_style_get (gHorizScrollbarWidget, "stepper_spacing",
stepper_spacing, NULL);
}
if (min_slider_size) {
*min_slider_size = GTK_RANGE(gHorizScrollbarWidget)->min_slider_size;
}
metrics->min_slider_size =
GTK_RANGE(gHorizScrollbarWidget)->min_slider_size;
return MOZ_GTK_SUCCESS;
}
@ -1265,6 +1348,11 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
return moz_gtk_container_paint(drawable, rect, cliprect, state,
(widget == MOZ_GTK_RADIOBUTTON_CONTAINER));
break;
case MOZ_GTK_CHECKBUTTON_LABEL:
case MOZ_GTK_RADIOBUTTON_LABEL:
return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state,
(widget == MOZ_GTK_RADIOBUTTON_LABEL));
break;
case MOZ_GTK_TOOLBAR:
return moz_gtk_toolbar_paint(drawable, rect, cliprect);
break;

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

@ -67,6 +67,14 @@ typedef struct {
gint32 maxpos;
} GtkWidgetState;
typedef struct {
gint slider_width;
gint trough_border;
gint stepper_size;
gint stepper_spacing;
gint min_slider_size;
} MozGtkScrollbarMetrics;
/** flags for tab state **/
typedef enum {
/* the first tab in the group */
@ -114,6 +122,10 @@ typedef enum {
MOZ_GTK_CHECKBUTTON_CONTAINER,
/* Paints the container part of a GtkRadioButton. */
MOZ_GTK_RADIOBUTTON_CONTAINER,
/* Paints the label of a GtkCheckButton (focus outline) */
MOZ_GTK_CHECKBUTTON_LABEL,
/* Paints the label of a GtkRadioButton (focus outline) */
MOZ_GTK_RADIOBUTTON_LABEL,
/* Paints the background of a GtkHandleBox. */
MOZ_GTK_TOOLBAR,
/* Paints a GtkToolTip */
@ -211,22 +223,32 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing);
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
#define moz_gtk_radio_get_metrics(x, y) moz_gtk_checkbox_get_metrics(x, y)
gint
moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
/**
* Get the desired metrics for a GtkScrollbar
* slider_width: [OUT] the width of the slider (thumb)
* trough_border: [OUT] the border of the trough (outside the thumb)
* stepper_size: [OUT] the size of an arrow button
* stepper_spacing: [OUT] the minimum space between the thumb and the arrow
* min_slider_size: [OUT] the minimum thumb size
/** Get the focus metrics for a checkbox or radio button
* interior_focus: [OUT] whether the focus is drawn around the
* label (TRUE) or around the whole container (FALSE)
* focus_width: [OUT] the width of the focus line
* focus_pad: [OUT] the padding between the focus line and children
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint
moz_gtk_get_scrollbar_metrics(gint* slider_width, gint* trough_border,
gint* stepper_size, gint* stepper_spacing,
gint* min_slider_size);
moz_gtk_checkbox_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
gint
moz_gtk_radio_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
/**
* Get the desired metrics for a GtkScrollbar
* metrics: [IN] struct which will contain the metrics
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint
moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics* metrics);
/**
* Get the desired size of a dropdown arrow button

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

@ -251,20 +251,26 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
aFrame = aFrame->GetParent();
// For XUL checkboxes and radio buttons, the state of the parent
// determines our state.
if (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO) {
if (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO ||
aWidgetType == NS_THEME_CHECKBOX_LABEL ||
aWidgetType == NS_THEME_RADIO_LABEL) {
if (aWidgetFlags) {
nsIAtom* atom = nsnull;
if (aFrame) {
nsIContent* content = aFrame->GetContent();
if (content->IsContentOfType(nsIContent::eXUL))
if (content->IsContentOfType(nsIContent::eXUL)) {
aFrame = aFrame->GetParent();
if (aWidgetType == NS_THEME_CHECKBOX_LABEL ||
aWidgetType == NS_THEME_RADIO_LABEL)
aFrame = aFrame->GetParent();
}
else if (content->Tag() == mInputAtom)
atom = mInputCheckedAtom;
}
if (!atom)
atom = (aWidgetType == NS_THEME_CHECKBOX) ? mCheckedAtom : mSelectedAtom;
atom = (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_CHECKBOX_LABEL) ? mCheckedAtom : mSelectedAtom;
*aWidgetFlags = CheckBooleanAttr(aFrame, atom);
}
}
@ -278,9 +284,14 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
aState->isDefault = FALSE; // XXX fix me
aState->canDefault = FALSE; // XXX fix me
// For these widget types, some element (either a child or parent)
// actually has element focus, so we check the focused attribute
// to see whether to draw in the focused state.
if (aWidgetType == NS_THEME_TEXTFIELD ||
aWidgetType == NS_THEME_DROPDOWN_TEXTFIELD ||
aWidgetType == NS_THEME_RADIO_CONTAINER) {
aWidgetType == NS_THEME_RADIO_CONTAINER ||
aWidgetType == NS_THEME_RADIO_LABEL ||
aWidgetType == NS_THEME_RADIO) {
aState->focused = CheckBooleanAttr(aFrame, mFocusedAtom);
}
@ -371,6 +382,12 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
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;
@ -512,10 +529,9 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
{
gint trough_border;
moz_gtk_get_scrollbar_metrics(nsnull, &trough_border,
nsnull, nsnull, nsnull);
aResult->top = aResult->left = trough_border;
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
aResult->top = aResult->left = metrics.trough_border;
}
break;
case NS_THEME_TOOLBOX:
@ -535,6 +551,7 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
aResult->right = aResult->left;
aResult->bottom = aResult->top;
return NS_OK;
}
@ -552,28 +569,26 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
{
gint slider_width, stepper_size;
moz_gtk_get_scrollbar_metrics(&slider_width, nsnull, &stepper_size,
nsnull, nsnull);
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
aResult->width = slider_width;
aResult->height = stepper_size;
aResult->width = metrics.slider_width;
aResult->height = metrics.stepper_size;
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
{
gint slider_width, min_slider_size;
moz_gtk_get_scrollbar_metrics(&slider_width, nsnull, nsnull, nsnull,
&min_slider_size);
MozGtkScrollbarMetrics metrics;
moz_gtk_get_scrollbar_metrics(&metrics);
if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) {
aResult->width = slider_width;
aResult->height = min_slider_size;
aResult->width = metrics.slider_width;
aResult->height = metrics.min_slider_size;
} else {
aResult->width = min_slider_size;
aResult->height = slider_width;
aResult->width = metrics.min_slider_size;
aResult->height = metrics.slider_width;
}
*aIsOverridable = PR_FALSE;
@ -581,31 +596,44 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
break;
case NS_THEME_DROPDOWN_BUTTON:
{
// First, get the minimum size for the button itself.
moz_gtk_get_dropdown_arrow_size(&aResult->width, &aResult->height);
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_CHECKBOX:
case NS_THEME_RADIO:
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
{
gint indicator_size, indicator_spacing;
if (aWidgetType == NS_THEME_CHECKBOX ||
aWidgetType == NS_THEME_CHECKBOX_CONTAINER)
if (aWidgetType == NS_THEME_CHECKBOX) {
moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
else
} else {
moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
}
// Hack alert: several themes have indicators larger than the default
// 10px size, but don't set the indicator size property. So, leave
// a little slop room by making the minimum size 14px.
aResult->width = aResult->height = MAX(indicator_size, 14);
// Include space for the indicator and the padding around it.
aResult->width = indicator_size + 3 * indicator_spacing;
aResult->height = indicator_size + 2 * indicator_spacing;
*aIsOverridable = PR_FALSE;
}
break;
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
{
// Just include our border, and let the box code augment the size.
nsCOMPtr<nsIDeviceContext> dc;
aContext->GetDeviceContext(*getter_AddRefs(dc));
nsMargin border;
nsNativeThemeGTK::GetWidgetBorder(dc, aFrame, aWidgetType, &border);
aResult->width = border.left + border.right;
aResult->height = border.top + border.bottom;
}
break;
}
return NS_OK;
@ -737,6 +765,8 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsIPresContext* aPresContext,
// case NS_THEME_SLIDER_TICK:
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
#ifdef MOZ_WIDGET_GTK2
case NS_THEME_MENUBAR:
case NS_THEME_MENUPOPUP: