Fixes for a number of native theme button problems on gtk2 (bug 255911). In order to more easily accomodate CSS fallbacks for when native theme rendering is not available, this adds GetWidgetPadding() to nsITheme, which allows the native theme impl to supply padding values which will override the css padding. This way, padding for the css fallback can be given without having it be added to the padding that's part of the native theme-rendered border. r=caillon, sr=roc.

This commit is contained in:
bryner%brianryner.com 2005-08-20 07:14:07 +00:00
Родитель 2b8c557704
Коммит ca84c668d4
11 изменённых файлов: 165 добавлений и 33 удалений

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

@ -228,7 +228,7 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing);
gint
moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
/** Get the focus metrics for a checkbox or radio button
/** Get the focus metrics for a button, 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
@ -237,6 +237,9 @@ moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint
moz_gtk_button_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
gint
moz_gtk_checkbox_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
gint

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

@ -123,14 +123,8 @@ GetPrimaryPresShell(nsIFrame* aFrame)
if (!aFrame)
return nsnull;
nsIPresShell *shell = nsnull;
nsIDocument* doc = aFrame->GetContent()->GetDocument();
if (doc) {
shell = doc->GetShellAt(0);
}
return shell;
nsPresContext *context = aFrame->GetPresContext();
return context ? context->GetPresShell() : nsnull;
}
static void RefreshWidgetWindow(nsIFrame* aFrame)
@ -337,6 +331,7 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
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;
@ -543,6 +538,14 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
// gtk's 'toolbar' for purposes of painting the widget background,
// we don't use the toolbar border for toolbox.
break;
case NS_THEME_TOOLBAR_DUAL_BUTTON:
// TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw
// around the entire button + dropdown, and also an inner border if you're
// over the button part. But, we want the inner button to be right up
// against the edge of the outer button so that the borders overlap.
// To make this happen, we draw a button border for the outer button,
// but don't reserve any space for it.
break;
default:
{
GtkThemeWidgetType gtkWidgetType;
@ -559,6 +562,21 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
return NS_OK;
}
PRBool
nsNativeThemeGTK::GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
nsMargin* aResult)
{
if (aWidgetType == NS_THEME_BUTTON_FOCUS ||
aWidgetType == NS_THEME_TOOLBAR_BUTTON ||
aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON) {
aResult->SizeTo(0, 0, 0, 0);
return PR_TRUE;
}
return PR_FALSE;
}
NS_IMETHODIMP
nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
@ -626,6 +644,8 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
case NS_THEME_BUTTON:
case NS_THEME_TOOLBAR_BUTTON:
{
// Just include our border, and let the box code augment the size.
@ -710,6 +730,7 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
switch (aWidgetType) {
case NS_THEME_BUTTON:
case NS_THEME_BUTTON_FOCUS:
case NS_THEME_RADIO:
case NS_THEME_CHECKBOX:
case NS_THEME_TOOLBOX: // N/A

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

@ -59,6 +59,11 @@ public:
NS_IMETHOD GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
PRUint8 aWidgetType, nsMargin* aResult);
virtual NS_HIDDEN_(PRBool) GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
nsMargin* aResult);
NS_IMETHOD GetMinimumWidgetSize(nsIRenderingContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
nsSize* aResult, PRBool* aIsOverridable);

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

@ -346,10 +346,14 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
{
GtkShadowType shadow_type;
GtkStyle* style = widget->style;
gint default_spacing = 7; /* xxx fix me */
GtkStateType button_state = ConvertGtkState(state);
gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
gboolean interior_focus;
gint focus_width, focus_pad;
moz_gtk_button_get_focus(&interior_focus, &focus_width, &focus_pad);
if (WINDOW_IS_MAPPED(drawable)) {
gdk_window_set_back_pixmap(drawable, NULL, TRUE);
gdk_window_clear_area(drawable, cliprect->x, cliprect->y,
@ -358,6 +362,8 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
gtk_widget_set_state(widget, button_state);
/*
* XXX fix this code when we have default state working.
if (state->isDefault) {
TSOffsetStyleGCs(style, x, y);
gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
@ -374,12 +380,13 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
x += (1 + default_spacing) / 2;
y += (1 + default_spacing) / 2;
}
if (state->focused) {
x += 1;
y += 1;
width -= 2;
height -= 2;
*/
if (!interior_focus && state->focused) {
x += focus_width + focus_pad;
y += focus_width + focus_pad;
width -= 2 * (focus_width + focus_pad);
height -= 2 * (focus_width + focus_pad);
}
shadow_type = button_state == GTK_STATE_ACTIVE ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
@ -395,11 +402,18 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
}
if (state->focused) {
x -= 1;
y -= 1;
width += 2;
height += 2;
if (interior_focus) {
x += widget->style->xthickness + focus_pad;
y += widget->style->ythickness + focus_pad;
width -= 2 * (widget->style->xthickness + focus_pad);
height -= 2 * (widget->style->ythickness + focus_pad);
} else {
x -= focus_width + focus_pad;
y -= focus_width + focus_pad;
width += 2 * (focus_width + focus_pad);
height += 2 * (focus_width + focus_pad);
}
TSOffsetStyleGCs(style, x, y);
gtk_paint_focus(style, drawable, button_state, cliprect,
widget, "button", x, y, width, height);
@ -470,6 +484,21 @@ moz_gtk_radio_get_focus(gboolean* interior_focus,
return MOZ_GTK_SUCCESS;
}
gint
moz_gtk_button_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad)
{
ensure_button_widget();
gtk_widget_style_get (gButtonWidget,
"interior-focus", interior_focus,
"focus-line-width", focus_width,
"focus-padding", focus_pad,
NULL);
return MOZ_GTK_SUCCESS;
}
static gint
moz_gtk_option_menu_get_metrics(gboolean* interior_focus,
GtkRequisition* indicator_size,
@ -1270,9 +1299,26 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* xthickness,
switch (widget) {
case MOZ_GTK_BUTTON:
ensure_button_widget();
w = gButtonWidget;
break;
{
/* Constant in gtkbutton.c */
static const gint child_spacing = 1;
gboolean interior_focus;
gint focus_width, focus_pad;
ensure_button_widget();
moz_gtk_button_get_focus(&interior_focus,
&focus_width, &focus_pad);
*xthickness = *ythickness =
GTK_CONTAINER(gButtonWidget)->border_width + child_spacing
+ focus_width + focus_pad;
*xthickness += gButtonWidget->style->xthickness;
*ythickness += gButtonWidget->style->ythickness;
return MOZ_GTK_SUCCESS;
}
case MOZ_GTK_TOOLBAR:
ensure_toolbar_widget();
w = gToolbarWidget;

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

@ -228,7 +228,7 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing);
gint
moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
/** Get the focus metrics for a checkbox or radio button
/** Get the focus metrics for a button, 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
@ -237,6 +237,9 @@ moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint
moz_gtk_button_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
gint
moz_gtk_checkbox_get_focus(gboolean* interior_focus,
gint* focus_width, gint* focus_pad);
gint

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

@ -123,14 +123,8 @@ GetPrimaryPresShell(nsIFrame* aFrame)
if (!aFrame)
return nsnull;
nsIPresShell *shell = nsnull;
nsIDocument* doc = aFrame->GetContent()->GetDocument();
if (doc) {
shell = doc->GetShellAt(0);
}
return shell;
nsPresContext *context = aFrame->GetPresContext();
return context ? context->GetPresShell() : nsnull;
}
static void RefreshWidgetWindow(nsIFrame* aFrame)
@ -337,6 +331,7 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
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;
@ -543,6 +538,14 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
// gtk's 'toolbar' for purposes of painting the widget background,
// we don't use the toolbar border for toolbox.
break;
case NS_THEME_TOOLBAR_DUAL_BUTTON:
// TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw
// around the entire button + dropdown, and also an inner border if you're
// over the button part. But, we want the inner button to be right up
// against the edge of the outer button so that the borders overlap.
// To make this happen, we draw a button border for the outer button,
// but don't reserve any space for it.
break;
default:
{
GtkThemeWidgetType gtkWidgetType;
@ -559,6 +562,21 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
return NS_OK;
}
PRBool
nsNativeThemeGTK::GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
nsMargin* aResult)
{
if (aWidgetType == NS_THEME_BUTTON_FOCUS ||
aWidgetType == NS_THEME_TOOLBAR_BUTTON ||
aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON) {
aResult->SizeTo(0, 0, 0, 0);
return PR_TRUE;
}
return PR_FALSE;
}
NS_IMETHODIMP
nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
@ -626,6 +644,8 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsIRenderingContext* aContext,
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
case NS_THEME_BUTTON:
case NS_THEME_TOOLBAR_BUTTON:
{
// Just include our border, and let the box code augment the size.
@ -710,6 +730,7 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
switch (aWidgetType) {
case NS_THEME_BUTTON:
case NS_THEME_BUTTON_FOCUS:
case NS_THEME_RADIO:
case NS_THEME_CHECKBOX:
case NS_THEME_TOOLBOX: // N/A

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

@ -59,6 +59,11 @@ public:
NS_IMETHOD GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,
PRUint8 aWidgetType, nsMargin* aResult);
virtual NS_HIDDEN_(PRBool) GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
nsMargin* aResult);
NS_IMETHOD GetMinimumWidgetSize(nsIRenderingContext* aContext,
nsIFrame* aFrame, PRUint8 aWidgetType,
nsSize* aResult, PRBool* aIsOverridable);

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

@ -535,6 +535,14 @@ nsNativeThemeMac::GetWidgetBorder(nsIDeviceContext* aContext,
return NS_OK;
}
PRBool
nsNativeThemeMac::GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
nsMargin* aResult)
{
return PR_FALSE;
}
NS_IMETHODIMP
nsNativeThemeMac::GetMinimumWidgetSize(nsIRenderingContext* aContext, nsIFrame* aFrame,

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

@ -63,6 +63,12 @@ public:
nsIFrame* aFrame,
PRUint8 aWidgetType,
nsMargin* aResult);
virtual PRBool GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
nsMargin* aResult);
NS_IMETHOD GetMinimumWidgetSize(nsIRenderingContext* aContext, nsIFrame* aFrame,
PRUint8 aWidgetType,
nsSize* aResult, PRBool* aIsOverridable);

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

@ -777,6 +777,15 @@ nsNativeThemeWin::GetWidgetBorder(nsIDeviceContext* aContext,
return NS_OK;
}
PRBool
nsNativeThemeWin::GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
nsMargin* aResult)
{
return PR_FALSE;
}
NS_IMETHODIMP
nsNativeThemeWin::GetMinimumWidgetSize(nsIRenderingContext* aContext, nsIFrame* aFrame,
PRUint8 aWidgetType,

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

@ -60,6 +60,11 @@ public:
PRUint8 aWidgetType,
nsMargin* aResult);
virtual PRBool GetWidgetPadding(nsIDeviceContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
nsMargin* aResult);
NS_IMETHOD GetMinimumWidgetSize(nsIRenderingContext* aContext, nsIFrame* aFrame,
PRUint8 aWidgetType,
nsSize* aResult,