1 /* 2 * Copyright (C) 2007 Apple Inc. 3 * Copyright (C) 2007 Alp Toker <alp (at) atoker.com> 4 * Copyright (C) 2008 Collabora Ltd. 5 * Copyright (C) 2009 Kenneth Rohde Christiansen 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 * 22 */ 23 24 #include "config.h" 25 #include "RenderThemeGtk.h" 26 27 #include "AffineTransform.h" 28 #include "CString.h" 29 #include "GOwnPtr.h" 30 #include "GraphicsContext.h" 31 #include "HTMLMediaElement.h" 32 #include "HTMLNames.h" 33 #include "NotImplemented.h" 34 #include "RenderBox.h" 35 #include "RenderObject.h" 36 #include "UserAgentStyleSheets.h" 37 #include "gtkdrawing.h" 38 39 #include <gdk/gdk.h> 40 #include <gtk/gtk.h> 41 42 namespace WebCore { 43 44 using namespace HTMLNames; 45 46 #if ENABLE(VIDEO) 47 static HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o) 48 { 49 Node* node = o->node(); 50 Node* mediaNode = node ? node->shadowAncestorNode() : 0; 51 if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) 52 return 0; 53 54 return static_cast<HTMLMediaElement*>(mediaNode); 55 } 56 57 static gchar* getIconNameForTextDirection(const char* baseName) 58 { 59 GString* nameWithDirection = g_string_new(baseName); 60 GtkTextDirection textDirection = gtk_widget_get_default_direction(); 61 62 if (textDirection == GTK_TEXT_DIR_RTL) 63 g_string_append(nameWithDirection, "-rtl"); 64 else if (textDirection == GTK_TEXT_DIR_LTR) 65 g_string_append(nameWithDirection, "-ltr"); 66 67 return g_string_free(nameWithDirection, FALSE); 68 } 69 70 void RenderThemeGtk::initMediaStyling(GtkStyle* style, bool force) 71 { 72 static bool stylingInitialized = false; 73 74 if (!stylingInitialized || force) { 75 m_panelColor = style->bg[GTK_STATE_NORMAL]; 76 m_sliderColor = style->bg[GTK_STATE_ACTIVE]; 77 m_sliderThumbColor = style->bg[GTK_STATE_SELECTED]; 78 79 // Names of these icons can vary because of text direction. 80 gchar* playButtonIconName = getIconNameForTextDirection("gtk-media-play"); 81 gchar* seekBackButtonIconName = getIconNameForTextDirection("gtk-media-rewind"); 82 gchar* seekForwardButtonIconName = getIconNameForTextDirection("gtk-media-forward"); 83 84 m_fullscreenButton.clear(); 85 m_muteButton.clear(); 86 m_unmuteButton.clear(); 87 m_playButton.clear(); 88 m_pauseButton.clear(); 89 m_seekBackButton.clear(); 90 m_seekForwardButton.clear(); 91 92 m_fullscreenButton = Image::loadPlatformThemeIcon("gtk-fullscreen", m_mediaIconSize); 93 m_muteButton = Image::loadPlatformThemeIcon("audio-volume-muted", m_mediaIconSize); 94 m_unmuteButton = Image::loadPlatformThemeIcon("audio-volume-high", m_mediaIconSize); 95 m_playButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(playButtonIconName), m_mediaIconSize); 96 m_pauseButton = Image::loadPlatformThemeIcon("gtk-media-pause", m_mediaIconSize).releaseRef(); 97 m_seekBackButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekBackButtonIconName), m_mediaIconSize); 98 m_seekForwardButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekForwardButtonIconName), m_mediaIconSize); 99 100 g_free(playButtonIconName); 101 g_free(seekBackButtonIconName); 102 g_free(seekForwardButtonIconName); 103 stylingInitialized = true; 104 } 105 } 106 #endif 107 108 PassRefPtr<RenderTheme> RenderThemeGtk::create() 109 { 110 return adoptRef(new RenderThemeGtk()); 111 } 112 113 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 114 { 115 static RenderTheme* rt = RenderThemeGtk::create().releaseRef(); 116 return rt; 117 } 118 119 static int mozGtkRefCount = 0; 120 121 RenderThemeGtk::RenderThemeGtk() 122 : m_gtkWindow(0) 123 , m_gtkContainer(0) 124 , m_gtkEntry(0) 125 , m_gtkTreeView(0) 126 , m_panelColor(Color::white) 127 , m_sliderColor(Color::white) 128 , m_sliderThumbColor(Color::white) 129 , m_mediaIconSize(16) 130 , m_mediaSliderHeight(14) 131 , m_mediaSliderThumbWidth(12) 132 , m_mediaSliderThumbHeight(12) 133 , m_fullscreenButton(0) 134 , m_muteButton(0) 135 , m_unmuteButton(0) 136 , m_playButton(0) 137 , m_pauseButton(0) 138 , m_seekBackButton(0) 139 , m_seekForwardButton(0) 140 , m_partsTable(adoptGRef(g_hash_table_new_full(0, 0, 0, g_free))) 141 { 142 if (!mozGtkRefCount) { 143 moz_gtk_init(); 144 145 // Use the theme parts for the default drawable. 146 moz_gtk_use_theme_parts(partsForDrawable(0)); 147 } 148 149 ++mozGtkRefCount; 150 151 #if ENABLE(VIDEO) 152 initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), false); 153 #endif 154 } 155 156 RenderThemeGtk::~RenderThemeGtk() 157 { 158 --mozGtkRefCount; 159 160 if (!mozGtkRefCount) 161 moz_gtk_shutdown(); 162 163 m_fullscreenButton.clear(); 164 m_muteButton.clear(); 165 m_unmuteButton.clear(); 166 m_playButton.clear(); 167 m_pauseButton.clear(); 168 m_seekBackButton.clear(); 169 m_seekForwardButton.clear(); 170 171 GList* values = g_hash_table_get_values(m_partsTable.get()); 172 for (guint i = 0; i < g_list_length(values); i++) 173 moz_gtk_destroy_theme_parts_widgets( 174 static_cast<GtkThemeParts*>(g_list_nth_data(values, i))); 175 } 176 177 GtkThemeParts* RenderThemeGtk::partsForDrawable(GdkDrawable* drawable) const 178 { 179 // A null drawable represents the default screen colormap. 180 GdkColormap* colormap = 0; 181 if (!drawable) 182 colormap = gdk_screen_get_default_colormap(gdk_screen_get_default()); 183 else 184 colormap = gdk_drawable_get_colormap(drawable); 185 186 GtkThemeParts* parts = static_cast<GtkThemeParts*>(g_hash_table_lookup(m_partsTable.get(), colormap)); 187 if (!parts) { 188 parts = g_new0(GtkThemeParts, 1); 189 parts->colormap = colormap; 190 g_hash_table_insert(m_partsTable.get(), colormap, parts); 191 } 192 193 return parts; 194 } 195 196 static bool supportsFocus(ControlPart appearance) 197 { 198 switch (appearance) { 199 case PushButtonPart: 200 case ButtonPart: 201 case TextFieldPart: 202 case TextAreaPart: 203 case SearchFieldPart: 204 case MenulistPart: 205 case RadioPart: 206 case CheckboxPart: 207 return true; 208 default: 209 return false; 210 } 211 } 212 213 bool RenderThemeGtk::supportsFocusRing(const RenderStyle* style) const 214 { 215 return supportsFocus(style->appearance()); 216 } 217 218 bool RenderThemeGtk::controlSupportsTints(const RenderObject* o) const 219 { 220 return isEnabled(o); 221 } 222 223 int RenderThemeGtk::baselinePosition(const RenderObject* o) const 224 { 225 if (!o->isBox()) 226 return 0; 227 228 // FIXME: This strategy is possibly incorrect for the GTK+ port. 229 if (o->style()->appearance() == CheckboxPart 230 || o->style()->appearance() == RadioPart) { 231 const RenderBox* box = toRenderBox(o); 232 return box->marginTop() + box->height() - 2; 233 } 234 235 return RenderTheme::baselinePosition(o); 236 } 237 238 static GtkTextDirection gtkTextDirection(TextDirection direction) 239 { 240 switch (direction) { 241 case RTL: 242 return GTK_TEXT_DIR_RTL; 243 case LTR: 244 return GTK_TEXT_DIR_LTR; 245 default: 246 return GTK_TEXT_DIR_NONE; 247 } 248 } 249 250 static void adjustMozillaStyle(const RenderThemeGtk* theme, RenderStyle* style, GtkThemeWidgetType type) 251 { 252 gint left, top, right, bottom; 253 GtkTextDirection direction = gtkTextDirection(style->direction()); 254 gboolean inhtml = true; 255 256 if (moz_gtk_get_widget_border(type, &left, &top, &right, &bottom, direction, inhtml) != MOZ_GTK_SUCCESS) 257 return; 258 259 // FIXME: This approach is likely to be incorrect. See other ports and layout tests to see the problem. 260 const int xpadding = 1; 261 const int ypadding = 1; 262 263 style->setPaddingLeft(Length(xpadding + left, Fixed)); 264 style->setPaddingTop(Length(ypadding + top, Fixed)); 265 style->setPaddingRight(Length(xpadding + right, Fixed)); 266 style->setPaddingBottom(Length(ypadding + bottom, Fixed)); 267 } 268 269 static void setMozillaState(const RenderTheme* theme, GtkWidgetState* state, RenderObject* o) 270 { 271 state->active = theme->isPressed(o); 272 state->focused = theme->isFocused(o); 273 state->inHover = theme->isHovered(o); 274 // FIXME: Disabled does not always give the correct appearance for ReadOnly 275 state->disabled = !theme->isEnabled(o) || theme->isReadOnlyControl(o); 276 state->isDefault = false; 277 state->canDefault = false; 278 state->depressed = false; 279 } 280 281 static bool paintMozillaGtkWidget(const RenderThemeGtk* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 282 { 283 // No GdkWindow to render to, so return true to fall back 284 if (!i.context->gdkDrawable()) 285 return true; 286 287 // Painting is disabled so just claim to have succeeded 288 if (i.context->paintingDisabled()) 289 return false; 290 291 GtkWidgetState mozState; 292 setMozillaState(theme, &mozState, o); 293 294 int flags; 295 296 // We might want to make setting flags the caller's job at some point rather than doing it here. 297 switch (type) { 298 case MOZ_GTK_BUTTON: 299 flags = GTK_RELIEF_NORMAL; 300 break; 301 case MOZ_GTK_CHECKBUTTON: 302 case MOZ_GTK_RADIOBUTTON: 303 flags = theme->isChecked(o); 304 break; 305 default: 306 flags = 0; 307 break; 308 } 309 310 AffineTransform ctm = i.context->getCTM(); 311 312 IntPoint pos = ctm.mapPoint(rect.location()); 313 GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height()); 314 GtkTextDirection direction = gtkTextDirection(o->style()->direction()); 315 316 // Find the clip rectangle 317 cairo_t* cr = i.context->platformContext(); 318 double clipX1, clipX2, clipY1, clipY2; 319 cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2); 320 321 GdkRectangle gdkClipRect; 322 gdkClipRect.width = clipX2 - clipX1; 323 gdkClipRect.height = clipY2 - clipY1; 324 IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1)); 325 gdkClipRect.x = clipPos.x(); 326 gdkClipRect.y = clipPos.y(); 327 328 gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect); 329 330 // Since the theme renderer is going to be drawing onto this GdkDrawable, 331 // select the appropriate widgets for the drawable depth. 332 moz_gtk_use_theme_parts(theme->partsForDrawable(i.context->gdkDrawable())); 333 return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS; 334 } 335 336 static void setButtonPadding(RenderStyle* style) 337 { 338 // FIXME: This looks incorrect. 339 const int padding = 8; 340 style->setPaddingLeft(Length(padding, Fixed)); 341 style->setPaddingRight(Length(padding, Fixed)); 342 style->setPaddingTop(Length(padding / 2, Fixed)); 343 style->setPaddingBottom(Length(padding / 2, Fixed)); 344 } 345 346 static void setToggleSize(const RenderThemeGtk* theme, RenderStyle* style, ControlPart appearance) 347 { 348 // The width and height are both specified, so we shouldn't change them. 349 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 350 return; 351 352 // FIXME: This is probably not correct use of indicatorSize and indicatorSpacing. 353 gint indicatorSize, indicatorSpacing; 354 355 switch (appearance) { 356 case CheckboxPart: 357 if (moz_gtk_checkbox_get_metrics(&indicatorSize, &indicatorSpacing) != MOZ_GTK_SUCCESS) 358 return; 359 break; 360 case RadioPart: 361 if (moz_gtk_radio_get_metrics(&indicatorSize, &indicatorSpacing) != MOZ_GTK_SUCCESS) 362 return; 363 break; 364 default: 365 return; 366 } 367 368 // Other ports hard-code this to 13, but GTK+ users tend to demand the native look. 369 // It could be made a configuration option values other than 13 actually break site compatibility. 370 int length = indicatorSize + indicatorSpacing; 371 if (style->width().isIntrinsicOrAuto()) 372 style->setWidth(Length(length, Fixed)); 373 374 if (style->height().isAuto()) 375 style->setHeight(Length(length, Fixed)); 376 } 377 378 void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const 379 { 380 setToggleSize(this, style, RadioPart); 381 } 382 383 bool RenderThemeGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 384 { 385 return paintMozillaGtkWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect); 386 } 387 388 void RenderThemeGtk::setRadioSize(RenderStyle* style) const 389 { 390 setToggleSize(this, style, RadioPart); 391 } 392 393 bool RenderThemeGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 394 { 395 return paintMozillaGtkWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect); 396 } 397 398 void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const 399 { 400 // FIXME: Is this condition necessary? 401 if (style->appearance() == PushButtonPart) { 402 style->resetBorder(); 403 style->setHeight(Length(Auto)); 404 style->setWhiteSpace(PRE); 405 setButtonPadding(style); 406 } else { 407 // FIXME: This should not be hard-coded. 408 style->setMinHeight(Length(14, Fixed)); 409 style->resetBorderTop(); 410 style->resetBorderBottom(); 411 } 412 } 413 414 bool RenderThemeGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 415 { 416 return paintMozillaGtkWidget(this, MOZ_GTK_BUTTON, o, i, rect); 417 } 418 419 void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const 420 { 421 style->resetBorder(); 422 style->resetPadding(); 423 style->setHeight(Length(Auto)); 424 style->setWhiteSpace(PRE); 425 adjustMozillaStyle(this, style, MOZ_GTK_DROPDOWN); 426 } 427 428 bool RenderThemeGtk::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 429 { 430 return paintMozillaGtkWidget(this, MOZ_GTK_DROPDOWN, o, i, rect); 431 } 432 433 void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 434 { 435 style->resetBorder(); 436 style->resetPadding(); 437 style->setHeight(Length(Auto)); 438 style->setWhiteSpace(PRE); 439 adjustMozillaStyle(this, style, MOZ_GTK_ENTRY); 440 } 441 442 bool RenderThemeGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 443 { 444 return paintMozillaGtkWidget(this, MOZ_GTK_ENTRY, o, i, rect); 445 } 446 447 bool RenderThemeGtk::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 448 { 449 return paintTextField(o, i, r); 450 } 451 452 void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 453 { 454 adjustSearchFieldCancelButtonStyle(selector, style, e); 455 } 456 457 bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 458 { 459 return paintMozillaGtkWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect); 460 } 461 462 void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 463 { 464 style->resetBorder(); 465 style->resetPadding(); 466 467 // FIXME: This should not be hard-coded. 468 IntSize size = IntSize(14, 14); 469 style->setWidth(Length(size.width(), Fixed)); 470 style->setHeight(Length(size.height(), Fixed)); 471 } 472 473 bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 474 { 475 return paintMozillaGtkWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect); 476 } 477 478 void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 479 { 480 style->resetBorder(); 481 style->resetPadding(); 482 483 // FIXME: This should not be hard-coded. 484 IntSize size = IntSize(14, 14); 485 style->setWidth(Length(size.width(), Fixed)); 486 style->setHeight(Length(size.height(), Fixed)); 487 } 488 489 bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 490 { 491 return paintMozillaGtkWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect); 492 } 493 494 void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 495 { 496 adjustTextFieldStyle(selector, style, e); 497 } 498 499 bool RenderThemeGtk::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) 500 { 501 return paintTextField(o, i, rect); 502 } 503 504 void RenderThemeGtk::adjustSliderThumbSize(RenderObject* o) const 505 { 506 #if ENABLE(VIDEO) 507 if (o->style()->appearance() == MediaSliderThumbPart) { 508 o->style()->setWidth(Length(m_mediaSliderThumbWidth, Fixed)); 509 o->style()->setHeight(Length(m_mediaSliderThumbHeight, Fixed)); 510 } 511 #endif 512 } 513 514 Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const 515 { 516 GtkWidget* widget = gtkEntry(); 517 return widget->style->base[GTK_STATE_SELECTED]; 518 } 519 520 Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const 521 { 522 GtkWidget* widget = gtkEntry(); 523 return widget->style->base[GTK_STATE_ACTIVE]; 524 } 525 526 Color RenderThemeGtk::platformActiveSelectionForegroundColor() const 527 { 528 GtkWidget* widget = gtkEntry(); 529 return widget->style->text[GTK_STATE_SELECTED]; 530 } 531 532 Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const 533 { 534 GtkWidget* widget = gtkEntry(); 535 return widget->style->text[GTK_STATE_ACTIVE]; 536 } 537 538 Color RenderThemeGtk::activeListBoxSelectionBackgroundColor() const 539 { 540 GtkWidget* widget = gtkTreeView(); 541 return widget->style->base[GTK_STATE_SELECTED]; 542 } 543 544 Color RenderThemeGtk::inactiveListBoxSelectionBackgroundColor() const 545 { 546 GtkWidget* widget = gtkTreeView(); 547 return widget->style->base[GTK_STATE_ACTIVE]; 548 } 549 550 Color RenderThemeGtk::activeListBoxSelectionForegroundColor() const 551 { 552 GtkWidget* widget = gtkTreeView(); 553 return widget->style->text[GTK_STATE_SELECTED]; 554 } 555 556 Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const 557 { 558 GtkWidget* widget = gtkTreeView(); 559 return widget->style->text[GTK_STATE_ACTIVE]; 560 } 561 562 double RenderThemeGtk::caretBlinkInterval() const 563 { 564 GtkSettings* settings = gtk_settings_get_default(); 565 566 gboolean shouldBlink; 567 gint time; 568 569 g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL); 570 571 if (!shouldBlink) 572 return 0; 573 574 return time / 2000.; 575 } 576 577 void RenderThemeGtk::systemFont(int, FontDescription&) const 578 { 579 // If you remove this notImplemented(), replace it with an comment that explains why. 580 notImplemented(); 581 } 582 583 static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme) 584 { 585 // FIXME: Make sure this function doesn't get called many times for a single GTK+ style change signal. 586 renderTheme->platformColorsDidChange(); 587 } 588 589 GtkContainer* RenderThemeGtk::gtkContainer() const 590 { 591 if (m_gtkContainer) 592 return m_gtkContainer; 593 594 m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP); 595 m_gtkContainer = GTK_CONTAINER(gtk_fixed_new()); 596 g_signal_connect(m_gtkWindow, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); 597 gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer)); 598 gtk_widget_realize(m_gtkWindow); 599 600 return m_gtkContainer; 601 } 602 603 GtkWidget* RenderThemeGtk::gtkEntry() const 604 { 605 if (m_gtkEntry) 606 return m_gtkEntry; 607 608 m_gtkEntry = gtk_entry_new(); 609 g_signal_connect(m_gtkEntry, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); 610 gtk_container_add(gtkContainer(), m_gtkEntry); 611 gtk_widget_realize(m_gtkEntry); 612 613 return m_gtkEntry; 614 } 615 616 GtkWidget* RenderThemeGtk::gtkTreeView() const 617 { 618 if (m_gtkTreeView) 619 return m_gtkTreeView; 620 621 m_gtkTreeView = gtk_tree_view_new(); 622 g_signal_connect(m_gtkTreeView, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this)); 623 gtk_container_add(gtkContainer(), m_gtkTreeView); 624 gtk_widget_realize(m_gtkTreeView); 625 626 return m_gtkTreeView; 627 } 628 629 void RenderThemeGtk::platformColorsDidChange() 630 { 631 #if ENABLE(VIDEO) 632 initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), true); 633 #endif 634 RenderTheme::platformColorsDidChange(); 635 } 636 637 #if ENABLE(VIDEO) 638 String RenderThemeGtk::extraMediaControlsStyleSheet() 639 { 640 return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet)); 641 } 642 643 static inline bool paintMediaButton(GraphicsContext* context, const IntRect& r, Image* image, Color panelColor, int mediaIconSize) 644 { 645 context->fillRect(FloatRect(r), panelColor, DeviceColorSpace); 646 context->drawImage(image, DeviceColorSpace, 647 IntRect(r.x() + (r.width() - mediaIconSize) / 2, 648 r.y() + (r.height() - mediaIconSize) / 2, 649 mediaIconSize, mediaIconSize)); 650 651 return false; 652 } 653 654 bool RenderThemeGtk::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 655 { 656 return paintMediaButton(paintInfo.context, r, m_fullscreenButton.get(), m_panelColor, m_mediaIconSize); 657 } 658 659 bool RenderThemeGtk::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 660 { 661 HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); 662 if (!mediaElement) 663 return false; 664 665 return paintMediaButton(paintInfo.context, r, mediaElement->muted() ? m_unmuteButton.get() : m_muteButton.get(), m_panelColor, m_mediaIconSize); 666 } 667 668 bool RenderThemeGtk::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 669 { 670 HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o); 671 if (!mediaElement) 672 return false; 673 674 return paintMediaButton(paintInfo.context, r, mediaElement->canPlay() ? m_playButton.get() : m_pauseButton.get(), m_panelColor, m_mediaIconSize); 675 } 676 677 bool RenderThemeGtk::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 678 { 679 return paintMediaButton(paintInfo.context, r, m_seekBackButton.get(), m_panelColor, m_mediaIconSize); 680 } 681 682 bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 683 { 684 return paintMediaButton(paintInfo.context, r, m_seekForwardButton.get(), m_panelColor, m_mediaIconSize); 685 } 686 687 bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 688 { 689 paintInfo.context->fillRect(FloatRect(r), m_panelColor, DeviceColorSpace); 690 paintInfo.context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2, 691 r.width(), m_mediaSliderHeight)), m_sliderColor, DeviceColorSpace); 692 return false; 693 } 694 695 bool RenderThemeGtk::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) 696 { 697 // Make the thumb nicer with rounded corners. 698 paintInfo.context->fillRoundedRect(r, IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), m_sliderThumbColor, DeviceColorSpace); 699 return false; 700 } 701 #endif 702 703 } 704