2 * This file is part of the WebKit project.
4 * Copyright (C) 2006 Apple Computer, Inc.
5 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
6 * Copyright (C) 2007 Holger Hans Peter Freyther
7 * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
28 #include "RenderThemeGtk.h"
30 #include "NotImplemented.h"
31 #include "RenderObject.h"
35 #define THEME_COLOR 204
36 #define THEME_FONT 210
43 // Textfield constants
44 #define TFP_TEXTFIELD 1
45 #define TFS_READONLY 6
48 * Approach to theming:
49 * a) keep one copy of each to be drawn widget, GtkEntry, GtkButton, Gtk...
50 * + the button will look like the native control
51 * + we don't need to worry about style updates and loading the right GtkStyle
52 * - resources are wasted. The native windows will not be used, we might have issues
55 * b) Use GtkStyle directly and copy and paste Gtk+ code
60 * - Create GtkWidgets to hold the state (disabled/enabled), selected, not selected.
61 * - Use a GdkPixmap to make the GtkStyle draw to and then try to convert set it the
62 * source of the current operation.
70 static RenderThemeGtk gdkTheme;
74 RenderThemeGtk::RenderThemeGtk()
85 void RenderThemeGtk::close()
89 void RenderThemeGtk::addIntrinsicMargins(RenderStyle* style) const
91 // Cut out the intrinsic margins completely if we end up using a small font size
92 if (style->fontSize() < 11)
95 // Intrinsic margin value.
98 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
99 if (style->width().isIntrinsicOrAuto()) {
100 if (style->marginLeft().quirk())
101 style->setMarginLeft(Length(m, Fixed));
102 if (style->marginRight().quirk())
103 style->setMarginRight(Length(m, Fixed));
106 if (style->height().isAuto()) {
107 if (style->marginTop().quirk())
108 style->setMarginTop(Length(m, Fixed));
109 if (style->marginBottom().quirk())
110 style->setMarginBottom(Length(m, Fixed));
114 bool RenderThemeGtk::supportsFocus(EAppearance appearance)
116 switch (appearance) {
117 case PushButtonAppearance:
118 case ButtonAppearance:
119 case TextFieldAppearance:
128 GtkStateType RenderThemeGtk::determineState(RenderObject* o)
130 GtkStateType result = GTK_STATE_NORMAL;
132 result = GTK_STATE_INSENSITIVE;
133 else if (isPressed(o))
134 result = GTK_STATE_ACTIVE;
135 else if (isHovered(o))
136 result = GTK_STATE_PRELIGHT;
140 GtkShadowType RenderThemeGtk::determineShadow(RenderObject* o)
142 return isChecked(o) ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
145 ThemeData RenderThemeGtk::getThemeData(RenderObject* o)
148 switch (o->style()->appearance()) {
149 case PushButtonAppearance:
150 case ButtonAppearance:
151 result.m_part = BP_BUTTON;
152 result.m_state = determineState(o);
154 case CheckboxAppearance:
155 result.m_part = BP_CHECKBOX;
156 result.m_state = determineState(o);
158 case RadioAppearance:
159 result.m_part = BP_RADIO;
160 result.m_state = determineState(o);
162 case TextFieldAppearance:
163 result.m_part = TFP_TEXTFIELD;
164 result.m_state = determineState(o);
174 void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const
179 bool RenderThemeGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
181 // FIXME: is it the right thing to do?
182 GtkWidget* checkbox = gtkCheckbox();
183 IntPoint pos = i.context->translatePoint(rect.location());
184 gtk_paint_check(checkbox->style, i.context->gdkDrawable(),
185 determineState(o), determineShadow(o),
186 NULL, checkbox, "checkbutton",
187 pos.x(), pos.y(), rect.width(), rect.height());
192 void RenderThemeGtk::setRadioSize(RenderStyle* style) const
195 // If the width and height are both specified, then we have nothing to do.
196 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
200 // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox.
201 // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
202 // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
205 if (style->width().isIntrinsicOrAuto())
206 style->setWidth(Length(ff, Fixed));
208 if (style->height().isAuto())
209 style->setHeight(Length(ff, Fixed));
212 bool RenderThemeGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
214 // FIXME: is it the right thing to do?
215 GtkWidget* radio = gtkRadioButton();
216 IntPoint pos = i.context->translatePoint(rect.location());
217 gtk_paint_option(radio->style, i.context->gdkDrawable(),
218 determineState(o), determineShadow(o),
219 NULL, radio, "radiobutton",
220 pos.x(), pos.y(), rect.width(), rect.height());
225 bool RenderThemeGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
227 // FIXME: should use theme-aware drawing. This should honor the state as well
228 GtkWidget* button = gtkButton();
229 IntPoint pos = i.context->translatePoint(rect.location());
230 gtk_paint_box(button->style, i.context->gdkDrawable(),
231 determineState(o), determineShadow(o),
232 NULL, button, "button",
233 pos.x(), pos.y(), rect.width(), rect.height());
237 void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element* e) const
242 bool RenderThemeGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
244 // FIXME: should use theme-aware drawing
248 bool RenderThemeGtk::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
250 return paintTextField(o, i, r);
253 void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
255 addIntrinsicMargins(style);
258 void RenderThemeGtk::systemFont(int propId, FontDescription&) const
262 GtkWidget* RenderThemeGtk::gtkButton() const
265 m_gtkButton = gtk_button_new();
266 gtk_container_add(GTK_CONTAINER(gtkWindowContainer()), m_gtkButton);
267 gtk_widget_realize(m_gtkButton);
273 GtkWidget* RenderThemeGtk::gtkCheckbox() const
275 if (!m_gtkCheckbox) {
276 m_gtkCheckbox = gtk_check_button_new();
277 gtk_container_add(GTK_CONTAINER(gtkWindowContainer()), m_gtkCheckbox);
278 gtk_widget_realize(m_gtkCheckbox);
281 return m_gtkCheckbox;
284 GtkWidget* RenderThemeGtk::gtkRadioButton() const
286 if (!m_gtkRadioButton) {
287 m_gtkRadioButton = gtk_radio_button_new(NULL);
288 gtk_container_add(GTK_CONTAINER(gtkWindowContainer()), m_gtkRadioButton);
289 gtk_widget_realize(m_gtkRadioButton);
292 return m_gtkRadioButton;
295 GtkWidget* RenderThemeGtk::gtkWindowContainer() const
298 m_unmappedWindow = gtk_window_new(GTK_WINDOW_POPUP);
299 // Some GTK themes (i.e. Clearlooks) draw the buttons differently
300 // (in particular, call gtk_style_apply_default_background) if they
301 // are unallocated and are children of a GtkFixed widget, which is
302 // apparently what some "make Firefox buttons look like GTK" code
303 // does. To avoid this ugly look, we use a GtkHBox as a parent,
304 // rather than a GtkFixed.
305 m_container = gtk_hbox_new(false, 0);
306 gtk_container_add(GTK_CONTAINER(m_unmappedWindow), m_container);
307 gtk_widget_realize(m_unmappedWindow);