RenderThemeGtk.cpp [plain text]
#include "config.h"
#include "NotImplemented.h"
#include "RenderObject.h"
#include "RenderThemeGtk.h"
#include "gtkdrawing.h"
#include <gdk/gdk.h>
namespace WebCore {
RenderTheme* theme()
{
static RenderThemeGtk gtkTheme;
return >kTheme;
}
RenderThemeGtk::RenderThemeGtk()
: m_gtkWindow(0)
, m_gtkContainer(0)
, m_gtkEntry(0)
, m_gtkTreeView(0)
{
}
static bool supportsFocus(EAppearance appearance)
{
switch (appearance) {
case PushButtonAppearance:
case ButtonAppearance:
case TextFieldAppearance:
case TextAreaAppearance:
case SearchFieldAppearance:
case MenulistAppearance:
case RadioAppearance:
case CheckboxAppearance:
return true;
default:
return false;
}
}
bool RenderThemeGtk::supportsFocusRing(const RenderStyle* style) const
{
return supportsFocus(style->appearance());
}
bool RenderThemeGtk::controlSupportsTints(const RenderObject* o) const
{
return isEnabled(o);
}
short RenderThemeGtk::baselinePosition(const RenderObject* o) const
{
if (o->style()->appearance() == CheckboxAppearance ||
o->style()->appearance() == RadioAppearance)
return o->marginTop() + o->height() - 2;
return RenderTheme::baselinePosition(o);
}
static GtkTextDirection gtkTextDirection(TextDirection direction)
{
switch (direction) {
case RTL:
return GTK_TEXT_DIR_RTL;
case LTR:
return GTK_TEXT_DIR_LTR;
default:
return GTK_TEXT_DIR_NONE;
}
}
static void adjustMozStyle(RenderStyle* style, GtkThemeWidgetType type)
{
gint left, top, right, bottom;
GtkTextDirection direction = gtkTextDirection(style->direction());
gboolean inhtml = true;
if (moz_gtk_get_widget_border(type, &left, &top, &right, &bottom, direction, inhtml) != MOZ_GTK_SUCCESS)
return;
const int xpadding = 1;
const int ypadding = 1;
style->setPaddingLeft(Length(xpadding + left, Fixed));
style->setPaddingTop(Length(ypadding + top, Fixed));
style->setPaddingRight(Length(xpadding + right, Fixed));
style->setPaddingBottom(Length(ypadding + bottom, Fixed));
}
static void setMozState(RenderTheme* theme, GtkWidgetState* state, RenderObject* o)
{
state->active = theme->isPressed(o);
state->focused = theme->isFocused(o);
state->inHover = theme->isHovered(o);
state->disabled = !theme->isEnabled(o) || theme->isReadOnlyControl(o);
state->isDefault = false;
state->canDefault = false;
state->depressed = false;
}
static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
if (!i.context->gdkDrawable())
return true;
if (i.context->paintingDisabled())
return false;
GtkWidgetState mozState;
setMozState(theme, &mozState, o);
int flags;
switch (type) {
case MOZ_GTK_BUTTON:
flags = GTK_RELIEF_NORMAL;
break;
case MOZ_GTK_CHECKBUTTON:
case MOZ_GTK_RADIOBUTTON:
flags = theme->isChecked(o);
break;
default:
flags = 0;
break;
}
IntPoint pos = i.context->translatePoint(rect.location());
GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height());
GtkTextDirection direction = gtkTextDirection(o->style()->direction());
return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS;
}
static void setButtonPadding(RenderStyle* style)
{
const int padding = 8;
style->setPaddingLeft(Length(padding, Fixed));
style->setPaddingRight(Length(padding, Fixed));
style->setPaddingTop(Length(padding / 2, Fixed));
style->setPaddingBottom(Length(padding / 2, Fixed));
}
static void setToggleSize(RenderStyle* style, EAppearance appearance)
{
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
return;
gint indicator_size, indicator_spacing;
switch (appearance) {
case CheckboxAppearance:
if (moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing) != MOZ_GTK_SUCCESS)
return;
break;
case RadioAppearance:
if (moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing) != MOZ_GTK_SUCCESS)
return;
break;
default:
return;
}
int length = indicator_size + indicator_spacing;
if (style->width().isIntrinsicOrAuto())
style->setWidth(Length(length, Fixed));
if (style->height().isAuto())
style->setHeight(Length(length, Fixed));
}
void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const
{
setToggleSize(style, RadioAppearance);
}
bool RenderThemeGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect);
}
void RenderThemeGtk::setRadioSize(RenderStyle* style) const
{
setToggleSize(style, RadioAppearance);
}
bool RenderThemeGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect);
}
void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
{
if (style->appearance() == PushButtonAppearance) {
style->resetBorder();
style->setHeight(Length(Auto));
style->setWhiteSpace(PRE);
setButtonPadding(style);
} else {
style->setMinHeight(Length(14, Fixed));
style->resetBorderTop();
style->resetBorderBottom();
}
}
bool RenderThemeGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_BUTTON, o, i, rect);
}
void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
{
style->resetBorder();
style->resetPadding();
style->setHeight(Length(Auto));
style->setWhiteSpace(PRE);
adjustMozStyle(style, MOZ_GTK_DROPDOWN);
}
bool RenderThemeGtk::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_DROPDOWN, o, i, rect);
}
void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
style->resetBorder();
style->resetPadding();
style->setHeight(Length(Auto));
style->setWhiteSpace(PRE);
adjustMozStyle(style, MOZ_GTK_ENTRY);
}
bool RenderThemeGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_ENTRY, o, i, rect);
}
void RenderThemeGtk::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
adjustTextFieldStyle(selector, style, e);
}
bool RenderThemeGtk::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
return paintTextField(o, i, r);
}
void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
adjustSearchFieldCancelButtonStyle(selector, style, e);
}
bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect);
}
void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
style->resetBorder();
style->resetPadding();
IntSize size = IntSize(14, 14);
style->setWidth(Length(size.width(), Fixed));
style->setHeight(Length(size.height(), Fixed));
}
bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
}
void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
style->resetBorder();
style->resetPadding();
IntSize size = IntSize(14, 14);
style->setWidth(Length(size.width(), Fixed));
style->setHeight(Length(size.height(), Fixed));
}
bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
}
void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
adjustTextFieldStyle(selector, style, e);
}
bool RenderThemeGtk::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
return paintTextField(o, i, rect);
}
Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const
{
GtkWidget* widget = gtkEntry();
return widget->style->base[GTK_STATE_SELECTED];
}
Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const
{
GtkWidget* widget = gtkEntry();
return widget->style->base[GTK_STATE_ACTIVE];
}
Color RenderThemeGtk::platformActiveSelectionForegroundColor() const
{
GtkWidget* widget = gtkEntry();
return widget->style->text[GTK_STATE_SELECTED];
}
Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const
{
GtkWidget* widget = gtkEntry();
return widget->style->text[GTK_STATE_ACTIVE];
}
Color RenderThemeGtk::activeListBoxSelectionBackgroundColor() const
{
GtkWidget* widget = gtkTreeView();
return widget->style->base[GTK_STATE_SELECTED];
}
Color RenderThemeGtk::inactiveListBoxSelectionBackgroundColor() const
{
GtkWidget* widget = gtkTreeView();
return widget->style->base[GTK_STATE_ACTIVE];
}
Color RenderThemeGtk::activeListBoxSelectionForegroundColor() const
{
GtkWidget* widget = gtkTreeView();
return widget->style->text[GTK_STATE_SELECTED];
}
Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const
{
GtkWidget* widget = gtkTreeView();
return widget->style->text[GTK_STATE_ACTIVE];
}
double RenderThemeGtk::caretBlinkFrequency() const
{
GtkSettings* settings = gtk_settings_get_default();
gboolean shouldBlink;
gint time;
g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL);
if (!shouldBlink)
return 0;
return time / 2000.;
}
void RenderThemeGtk::systemFont(int, FontDescription&) const
{
notImplemented();
}
static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme)
{
renderTheme->platformColorsDidChange();
}
GtkContainer* RenderThemeGtk::gtkContainer() const
{
if (m_gtkContainer)
return m_gtkContainer;
m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP);
m_gtkContainer = GTK_CONTAINER(gtk_fixed_new());
gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer));
gtk_widget_realize(m_gtkWindow);
return m_gtkContainer;
}
GtkWidget* RenderThemeGtk::gtkEntry() const
{
if (m_gtkEntry)
return m_gtkEntry;
m_gtkEntry = gtk_entry_new();
g_signal_connect(m_gtkEntry, "style-set", G_CALLBACK(gtkStyleSetCallback), theme());
gtk_container_add(gtkContainer(), m_gtkEntry);
gtk_widget_realize(m_gtkEntry);
return m_gtkEntry;
}
GtkWidget* RenderThemeGtk::gtkTreeView() const
{
if (m_gtkTreeView)
return m_gtkTreeView;
m_gtkTreeView = gtk_tree_view_new();
g_signal_connect(m_gtkTreeView, "style-set", G_CALLBACK(gtkStyleSetCallback), theme());
gtk_container_add(gtkContainer(), m_gtkTreeView);
gtk_widget_realize(m_gtkTreeView);
return m_gtkTreeView;
}
}