1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* ***** BEGIN LICENSE BLOCK ***** 3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * http://www.mozilla.org/MPL/ 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 * 15 * The Original Code is mozilla.org code. 16 * 17 * The Initial Developer of the Original Code is 18 * Netscape Communications Corporation. 19 * Portions created by the Initial Developer are Copyright (C) 2002 20 * the Initial Developer. All Rights Reserved. 21 * 22 * Contributor(s): 23 * Brian Ryner <bryner (at) brianryner.com> (Original Author) 24 * Pierre Chanial <p_ch (at) verizon.net> 25 * Michael Ventnor <m.ventnor (at) gmail.com> 26 * Alp Toker <alp (at) nuanti.com> 27 * 28 * Alternatively, the contents of this file may be used under the terms of 29 * either the GNU General Public License Version 2 or later (the "GPL"), or 30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 31 * in which case the provisions of the GPL or the LGPL are applicable instead 32 * of those above. If you wish to allow use of your version of this file only 33 * under the terms of either the GPL or the LGPL, and not to allow others to 34 * use your version of this file under the terms of the MPL, indicate your 35 * decision by deleting the provisions above and replace them with the notice 36 * and other provisions required by the GPL or the LGPL. If you do not delete 37 * the provisions above, a recipient may use your version of this file under 38 * the terms of any one of the MPL, the GPL or the LGPL. 39 * 40 * ***** END LICENSE BLOCK ***** */ 41 42 /* 43 * This file contains painting functions for each of the gtk2 widgets. 44 * Adapted from the gtkdrawing.c, and gtk+2.0 source. 45 */ 46 47 #include <gdk/gdkprivate.h> 48 #include "gtkdrawing.h" 49 50 #include "Assertions.h" 51 52 #include <math.h> 53 #include <string.h> 54 55 #define XTHICKNESS(style) (style->xthickness) 56 #define YTHICKNESS(style) (style->ythickness) 57 #define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window)) 58 59 static GtkThemeParts *gParts = NULL; 60 static style_prop_t style_prop_func; 61 static gboolean have_arrow_scaling; 62 static gboolean is_initialized; 63 64 void 65 moz_gtk_use_theme_parts(GtkThemeParts* parts) 66 { 67 gParts = parts; 68 } 69 70 /* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine 71 that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific 72 things they may want to do. */ 73 static void 74 moz_gtk_set_widget_name(GtkWidget* widget) 75 { 76 gtk_widget_set_name(widget, "MozillaGtkWidget"); 77 } 78 79 gint 80 moz_gtk_enable_style_props(style_prop_t styleGetProp) 81 { 82 style_prop_func = styleGetProp; 83 return MOZ_GTK_SUCCESS; 84 } 85 86 static gint 87 ensure_window_widget() 88 { 89 if (!gParts->protoWindow) { 90 gParts->protoWindow = gtk_window_new(GTK_WINDOW_POPUP); 91 92 if (gParts->colormap) 93 gtk_widget_set_colormap(gParts->protoWindow, gParts->colormap); 94 95 gtk_widget_realize(gParts->protoWindow); 96 moz_gtk_set_widget_name(gParts->protoWindow); 97 } 98 return MOZ_GTK_SUCCESS; 99 } 100 101 static gint 102 setup_widget_prototype(GtkWidget* widget) 103 { 104 ensure_window_widget(); 105 if (!gParts->protoLayout) { 106 gParts->protoLayout = gtk_fixed_new(); 107 gtk_container_add(GTK_CONTAINER(gParts->protoWindow), gParts->protoLayout); 108 } 109 110 gtk_container_add(GTK_CONTAINER(gParts->protoLayout), widget); 111 gtk_widget_realize(widget); 112 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 113 return MOZ_GTK_SUCCESS; 114 } 115 116 static gint 117 ensure_button_widget() 118 { 119 if (!gParts->buttonWidget) { 120 gParts->buttonWidget = gtk_button_new_with_label("M"); 121 setup_widget_prototype(gParts->buttonWidget); 122 } 123 return MOZ_GTK_SUCCESS; 124 } 125 126 static gint 127 ensure_hpaned_widget() 128 { 129 if (!gParts->hpanedWidget) { 130 gParts->hpanedWidget = gtk_hpaned_new(); 131 setup_widget_prototype(gParts->hpanedWidget); 132 } 133 return MOZ_GTK_SUCCESS; 134 } 135 136 static gint 137 ensure_vpaned_widget() 138 { 139 if (!gParts->vpanedWidget) { 140 gParts->vpanedWidget = gtk_vpaned_new(); 141 setup_widget_prototype(gParts->vpanedWidget); 142 } 143 return MOZ_GTK_SUCCESS; 144 } 145 146 static gint 147 ensure_toggle_button_widget() 148 { 149 if (!gParts->toggleButtonWidget) { 150 gParts->toggleButtonWidget = gtk_toggle_button_new(); 151 setup_widget_prototype(gParts->toggleButtonWidget); 152 /* toggle button must be set active to get the right style on hover. */ 153 GTK_TOGGLE_BUTTON(gParts->toggleButtonWidget)->active = TRUE; 154 } 155 return MOZ_GTK_SUCCESS; 156 } 157 158 static gint 159 ensure_button_arrow_widget() 160 { 161 if (!gParts->buttonArrowWidget) { 162 ensure_toggle_button_widget(); 163 164 gParts->buttonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); 165 gtk_container_add(GTK_CONTAINER(gParts->toggleButtonWidget), gParts->buttonArrowWidget); 166 gtk_widget_realize(gParts->buttonArrowWidget); 167 } 168 return MOZ_GTK_SUCCESS; 169 } 170 171 static gint 172 ensure_checkbox_widget() 173 { 174 if (!gParts->checkboxWidget) { 175 gParts->checkboxWidget = gtk_check_button_new_with_label("M"); 176 setup_widget_prototype(gParts->checkboxWidget); 177 } 178 return MOZ_GTK_SUCCESS; 179 } 180 181 static gint 182 ensure_radiobutton_widget() 183 { 184 if (!gParts->radiobuttonWidget) { 185 gParts->radiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M"); 186 setup_widget_prototype(gParts->radiobuttonWidget); 187 } 188 return MOZ_GTK_SUCCESS; 189 } 190 191 static gint 192 ensure_scrollbar_widget() 193 { 194 if (!gParts->vertScrollbarWidget) { 195 gParts->vertScrollbarWidget = gtk_vscrollbar_new(NULL); 196 setup_widget_prototype(gParts->vertScrollbarWidget); 197 } 198 if (!gParts->horizScrollbarWidget) { 199 gParts->horizScrollbarWidget = gtk_hscrollbar_new(NULL); 200 setup_widget_prototype(gParts->horizScrollbarWidget); 201 } 202 return MOZ_GTK_SUCCESS; 203 } 204 205 static gint 206 ensure_spin_widget() 207 { 208 if (!gParts->spinWidget) { 209 gParts->spinWidget = gtk_spin_button_new(NULL, 1, 0); 210 setup_widget_prototype(gParts->spinWidget); 211 } 212 return MOZ_GTK_SUCCESS; 213 } 214 215 static gint 216 ensure_scale_widget() 217 { 218 if (!gParts->hScaleWidget) { 219 gParts->hScaleWidget = gtk_hscale_new(NULL); 220 setup_widget_prototype(gParts->hScaleWidget); 221 } 222 if (!gParts->vScaleWidget) { 223 gParts->vScaleWidget = gtk_vscale_new(NULL); 224 setup_widget_prototype(gParts->vScaleWidget); 225 } 226 return MOZ_GTK_SUCCESS; 227 } 228 229 static gint 230 ensure_entry_widget() 231 { 232 if (!gParts->entryWidget) { 233 gParts->entryWidget = gtk_entry_new(); 234 setup_widget_prototype(gParts->entryWidget); 235 } 236 return MOZ_GTK_SUCCESS; 237 } 238 239 /* We need to have pointers to the inner widgets (button, separator, arrow) 240 * of the ComboBox to get the correct rendering from theme engines which 241 * special cases their look. Since the inner layout can change, we ask GTK 242 * to NULL our pointers when they are about to become invalid because the 243 * corresponding widgets don't exist anymore. It's the role of 244 * g_object_add_weak_pointer(). 245 * Note that if we don't find the inner widgets (which shouldn't happen), we 246 * fallback to use generic "non-inner" widgets, and they don't need that kind 247 * of weak pointer since they are explicit children of gParts->protoWindow and as 248 * such GTK holds a strong reference to them. */ 249 static void 250 moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data) 251 { 252 if (GTK_IS_TOGGLE_BUTTON(widget)) { 253 gParts->comboBoxButtonWidget = widget; 254 g_object_add_weak_pointer(G_OBJECT(widget), 255 (gpointer) &gParts->comboBoxButtonWidget); 256 gtk_widget_realize(widget); 257 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 258 } 259 } 260 261 static void 262 moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget, 263 gpointer client_data) 264 { 265 if (GTK_IS_SEPARATOR(widget)) { 266 gParts->comboBoxSeparatorWidget = widget; 267 g_object_add_weak_pointer(G_OBJECT(widget), 268 (gpointer) &gParts->comboBoxSeparatorWidget); 269 } else if (GTK_IS_ARROW(widget)) { 270 gParts->comboBoxArrowWidget = widget; 271 g_object_add_weak_pointer(G_OBJECT(widget), 272 (gpointer) &gParts->comboBoxArrowWidget); 273 } else 274 return; 275 gtk_widget_realize(widget); 276 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 277 } 278 279 static gint 280 ensure_combo_box_widgets() 281 { 282 GtkWidget* buttonChild; 283 284 if (gParts->comboBoxButtonWidget && gParts->comboBoxArrowWidget) 285 return MOZ_GTK_SUCCESS; 286 287 /* Create a ComboBox if needed */ 288 if (!gParts->comboBoxWidget) { 289 gParts->comboBoxWidget = gtk_combo_box_new(); 290 setup_widget_prototype(gParts->comboBoxWidget); 291 } 292 293 /* Get its inner Button */ 294 gtk_container_forall(GTK_CONTAINER(gParts->comboBoxWidget), 295 moz_gtk_get_combo_box_inner_button, 296 NULL); 297 298 if (gParts->comboBoxButtonWidget) { 299 /* Get the widgets inside the Button */ 300 buttonChild = GTK_BIN(gParts->comboBoxButtonWidget)->child; 301 if (GTK_IS_HBOX(buttonChild)) { 302 /* appears-as-list = FALSE, cell-view = TRUE; the button 303 * contains an hbox. This hbox is there because the ComboBox 304 * needs to place a cell renderer, a separator, and an arrow in 305 * the button when appears-as-list is FALSE. */ 306 gtk_container_forall(GTK_CONTAINER(buttonChild), 307 moz_gtk_get_combo_box_button_inner_widgets, 308 NULL); 309 } else if(GTK_IS_ARROW(buttonChild)) { 310 /* appears-as-list = TRUE, or cell-view = FALSE; 311 * the button only contains an arrow */ 312 gParts->comboBoxArrowWidget = buttonChild; 313 g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) 314 &gParts->comboBoxArrowWidget); 315 gtk_widget_realize(gParts->comboBoxArrowWidget); 316 g_object_set_data(G_OBJECT(gParts->comboBoxArrowWidget), 317 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 318 } 319 } else { 320 /* Shouldn't be reached with current internal gtk implementation; we 321 * use a generic toggle button as last resort fallback to avoid 322 * crashing. */ 323 ensure_toggle_button_widget(); 324 gParts->comboBoxButtonWidget = gParts->toggleButtonWidget; 325 } 326 327 if (!gParts->comboBoxArrowWidget) { 328 /* Shouldn't be reached with current internal gtk implementation; 329 * we gParts->buttonArrowWidget as last resort fallback to avoid 330 * crashing. */ 331 ensure_button_arrow_widget(); 332 gParts->comboBoxArrowWidget = gParts->buttonArrowWidget; 333 } 334 335 /* We don't test the validity of gParts->comboBoxSeparatorWidget since there 336 * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it 337 * is invalid we just won't paint it. */ 338 339 return MOZ_GTK_SUCCESS; 340 } 341 342 /* We need to have pointers to the inner widgets (entry, button, arrow) of 343 * the ComboBoxEntry to get the correct rendering from theme engines which 344 * special cases their look. Since the inner layout can change, we ask GTK 345 * to NULL our pointers when they are about to become invalid because the 346 * corresponding widgets don't exist anymore. It's the role of 347 * g_object_add_weak_pointer(). 348 * Note that if we don't find the inner widgets (which shouldn't happen), we 349 * fallback to use generic "non-inner" widgets, and they don't need that kind 350 * of weak pointer since they are explicit children of gParts->protoWindow and as 351 * such GTK holds a strong reference to them. */ 352 static void 353 moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget, 354 gpointer client_data) 355 { 356 if (GTK_IS_TOGGLE_BUTTON(widget)) { 357 gParts->comboBoxEntryButtonWidget = widget; 358 g_object_add_weak_pointer(G_OBJECT(widget), 359 (gpointer) &gParts->comboBoxEntryButtonWidget); 360 } else if (GTK_IS_ENTRY(widget)) { 361 gParts->comboBoxEntryTextareaWidget = widget; 362 g_object_add_weak_pointer(G_OBJECT(widget), 363 (gpointer) &gParts->comboBoxEntryTextareaWidget); 364 } else 365 return; 366 gtk_widget_realize(widget); 367 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 368 } 369 370 static void 371 moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data) 372 { 373 if (GTK_IS_ARROW(widget)) { 374 gParts->comboBoxEntryArrowWidget = widget; 375 g_object_add_weak_pointer(G_OBJECT(widget), 376 (gpointer) &gParts->comboBoxEntryArrowWidget); 377 gtk_widget_realize(widget); 378 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 379 } 380 } 381 382 static gint 383 ensure_combo_box_entry_widgets() 384 { 385 GtkWidget* buttonChild; 386 387 if (gParts->comboBoxEntryTextareaWidget && 388 gParts->comboBoxEntryButtonWidget && 389 gParts->comboBoxEntryArrowWidget) 390 return MOZ_GTK_SUCCESS; 391 392 /* Create a ComboBoxEntry if needed */ 393 if (!gParts->comboBoxEntryWidget) { 394 gParts->comboBoxEntryWidget = gtk_combo_box_entry_new(); 395 setup_widget_prototype(gParts->comboBoxEntryWidget); 396 } 397 398 /* Get its inner Entry and Button */ 399 gtk_container_forall(GTK_CONTAINER(gParts->comboBoxEntryWidget), 400 moz_gtk_get_combo_box_entry_inner_widgets, 401 NULL); 402 403 if (!gParts->comboBoxEntryTextareaWidget) { 404 ensure_entry_widget(); 405 gParts->comboBoxEntryTextareaWidget = gParts->entryWidget; 406 } 407 408 if (gParts->comboBoxEntryButtonWidget) { 409 /* Get the Arrow inside the Button */ 410 buttonChild = GTK_BIN(gParts->comboBoxEntryButtonWidget)->child; 411 if (GTK_IS_HBOX(buttonChild)) { 412 /* appears-as-list = FALSE, cell-view = TRUE; the button 413 * contains an hbox. This hbox is there because ComboBoxEntry 414 * inherits from ComboBox which needs to place a cell renderer, 415 * a separator, and an arrow in the button when appears-as-list 416 * is FALSE. Here the hbox should only contain an arrow, since 417 * a ComboBoxEntry doesn't need all those widgets in the 418 * button. */ 419 gtk_container_forall(GTK_CONTAINER(buttonChild), 420 moz_gtk_get_combo_box_entry_arrow, 421 NULL); 422 } else if(GTK_IS_ARROW(buttonChild)) { 423 /* appears-as-list = TRUE, or cell-view = FALSE; 424 * the button only contains an arrow */ 425 gParts->comboBoxEntryArrowWidget = buttonChild; 426 g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) 427 &gParts->comboBoxEntryArrowWidget); 428 gtk_widget_realize(gParts->comboBoxEntryArrowWidget); 429 g_object_set_data(G_OBJECT(gParts->comboBoxEntryArrowWidget), 430 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 431 } 432 } else { 433 /* Shouldn't be reached with current internal gtk implementation; 434 * we use a generic toggle button as last resort fallback to avoid 435 * crashing. */ 436 ensure_toggle_button_widget(); 437 gParts->comboBoxEntryButtonWidget = gParts->toggleButtonWidget; 438 } 439 440 if (!gParts->comboBoxEntryArrowWidget) { 441 /* Shouldn't be reached with current internal gtk implementation; 442 * we gParts->buttonArrowWidget as last resort fallback to avoid 443 * crashing. */ 444 ensure_button_arrow_widget(); 445 gParts->comboBoxEntryArrowWidget = gParts->buttonArrowWidget; 446 } 447 448 return MOZ_GTK_SUCCESS; 449 } 450 451 452 static gint 453 ensure_handlebox_widget() 454 { 455 if (!gParts->handleBoxWidget) { 456 gParts->handleBoxWidget = gtk_handle_box_new(); 457 setup_widget_prototype(gParts->handleBoxWidget); 458 } 459 return MOZ_GTK_SUCCESS; 460 } 461 462 static gint 463 ensure_toolbar_widget() 464 { 465 if (!gParts->toolbarWidget) { 466 ensure_handlebox_widget(); 467 gParts->toolbarWidget = gtk_toolbar_new(); 468 gtk_container_add(GTK_CONTAINER(gParts->handleBoxWidget), gParts->toolbarWidget); 469 gtk_widget_realize(gParts->toolbarWidget); 470 g_object_set_data(G_OBJECT(gParts->toolbarWidget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 471 } 472 return MOZ_GTK_SUCCESS; 473 } 474 475 static gint 476 ensure_toolbar_separator_widget() 477 { 478 if (!gParts->toolbarSeparatorWidget) { 479 ensure_toolbar_widget(); 480 gParts->toolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new()); 481 setup_widget_prototype(gParts->toolbarSeparatorWidget); 482 } 483 return MOZ_GTK_SUCCESS; 484 } 485 486 static gint 487 ensure_tooltip_widget() 488 { 489 if (!gParts->tooltipWidget) { 490 gParts->tooltipWidget = gtk_window_new(GTK_WINDOW_POPUP); 491 gtk_widget_realize(gParts->tooltipWidget); 492 moz_gtk_set_widget_name(gParts->tooltipWidget); 493 } 494 return MOZ_GTK_SUCCESS; 495 } 496 497 static gint 498 ensure_tab_widget() 499 { 500 if (!gParts->tabWidget) { 501 gParts->tabWidget = gtk_notebook_new(); 502 setup_widget_prototype(gParts->tabWidget); 503 } 504 return MOZ_GTK_SUCCESS; 505 } 506 507 static gint 508 ensure_progress_widget() 509 { 510 if (!gParts->progresWidget) { 511 gParts->progresWidget = gtk_progress_bar_new(); 512 setup_widget_prototype(gParts->progresWidget); 513 } 514 return MOZ_GTK_SUCCESS; 515 } 516 517 static gint 518 ensure_statusbar_widget() 519 { 520 if (!gParts->statusbarWidget) { 521 gParts->statusbarWidget = gtk_statusbar_new(); 522 setup_widget_prototype(gParts->statusbarWidget); 523 } 524 return MOZ_GTK_SUCCESS; 525 } 526 527 static gint 528 ensure_frame_widget() 529 { 530 if (!gParts->frameWidget) { 531 ensure_statusbar_widget(); 532 gParts->frameWidget = gtk_frame_new(NULL); 533 gtk_container_add(GTK_CONTAINER(gParts->statusbarWidget), gParts->frameWidget); 534 gtk_widget_realize(gParts->frameWidget); 535 } 536 return MOZ_GTK_SUCCESS; 537 } 538 539 static gint 540 ensure_menu_bar_widget() 541 { 542 if (!gParts->menuBarWidget) { 543 gParts->menuBarWidget = gtk_menu_bar_new(); 544 setup_widget_prototype(gParts->menuBarWidget); 545 } 546 return MOZ_GTK_SUCCESS; 547 } 548 549 static gint 550 ensure_menu_bar_item_widget() 551 { 552 if (!gParts->menuBarItemWidget) { 553 ensure_menu_bar_widget(); 554 gParts->menuBarItemWidget = gtk_menu_item_new(); 555 gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuBarWidget), 556 gParts->menuBarItemWidget); 557 gtk_widget_realize(gParts->menuBarItemWidget); 558 g_object_set_data(G_OBJECT(gParts->menuBarItemWidget), 559 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 560 } 561 return MOZ_GTK_SUCCESS; 562 } 563 564 static gint 565 ensure_menu_popup_widget() 566 { 567 if (!gParts->menuPopupWidget) { 568 ensure_menu_bar_item_widget(); 569 gParts->menuPopupWidget = gtk_menu_new(); 570 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gParts->menuBarItemWidget), 571 gParts->menuPopupWidget); 572 gtk_widget_realize(gParts->menuPopupWidget); 573 g_object_set_data(G_OBJECT(gParts->menuPopupWidget), 574 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 575 } 576 return MOZ_GTK_SUCCESS; 577 } 578 579 static gint 580 ensure_menu_item_widget() 581 { 582 if (!gParts->menuItemWidget) { 583 ensure_menu_popup_widget(); 584 gParts->menuItemWidget = gtk_menu_item_new_with_label("M"); 585 gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget), 586 gParts->menuItemWidget); 587 gtk_widget_realize(gParts->menuItemWidget); 588 g_object_set_data(G_OBJECT(gParts->menuItemWidget), 589 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 590 } 591 return MOZ_GTK_SUCCESS; 592 } 593 594 static gint 595 ensure_image_menu_item_widget() 596 { 597 if (!gParts->imageMenuItemWidget) { 598 ensure_menu_popup_widget(); 599 gParts->imageMenuItemWidget = gtk_image_menu_item_new(); 600 gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget), 601 gParts->imageMenuItemWidget); 602 gtk_widget_realize(gParts->imageMenuItemWidget); 603 g_object_set_data(G_OBJECT(gParts->imageMenuItemWidget), 604 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 605 } 606 return MOZ_GTK_SUCCESS; 607 } 608 609 static gint 610 ensure_menu_separator_widget() 611 { 612 if (!gParts->menuSeparatorWidget) { 613 ensure_menu_popup_widget(); 614 gParts->menuSeparatorWidget = gtk_separator_menu_item_new(); 615 gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget), 616 gParts->menuSeparatorWidget); 617 gtk_widget_realize(gParts->menuSeparatorWidget); 618 g_object_set_data(G_OBJECT(gParts->menuSeparatorWidget), 619 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 620 } 621 return MOZ_GTK_SUCCESS; 622 } 623 624 static gint 625 ensure_check_menu_item_widget() 626 { 627 if (!gParts->checkMenuItemWidget) { 628 ensure_menu_popup_widget(); 629 gParts->checkMenuItemWidget = gtk_check_menu_item_new_with_label("M"); 630 gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget), 631 gParts->checkMenuItemWidget); 632 gtk_widget_realize(gParts->checkMenuItemWidget); 633 g_object_set_data(G_OBJECT(gParts->checkMenuItemWidget), 634 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 635 } 636 return MOZ_GTK_SUCCESS; 637 } 638 639 static gint 640 ensure_tree_view_widget() 641 { 642 if (!gParts->treeViewWidget) { 643 gParts->treeViewWidget = gtk_tree_view_new(); 644 setup_widget_prototype(gParts->treeViewWidget); 645 } 646 return MOZ_GTK_SUCCESS; 647 } 648 649 static gint 650 ensure_tree_header_cell_widget() 651 { 652 if(!gParts->treeHeaderCellWidget) { 653 /* 654 * Some GTK engines paint the first and last cell 655 * of a TreeView header with a highlight. 656 * Since we do not know where our widget will be relative 657 * to the other buttons in the TreeView header, we must 658 * paint it as a button that is between two others, 659 * thus ensuring it is neither the first or last button 660 * in the header. 661 * GTK doesn't give us a way to do this explicitly, 662 * so we must paint with a button that is between two 663 * others. 664 */ 665 666 GtkTreeViewColumn* firstTreeViewColumn; 667 GtkTreeViewColumn* lastTreeViewColumn; 668 669 ensure_tree_view_widget(); 670 671 /* Create and append our three columns */ 672 firstTreeViewColumn = gtk_tree_view_column_new(); 673 gtk_tree_view_column_set_title(firstTreeViewColumn, "M"); 674 gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget), firstTreeViewColumn); 675 676 gParts->middleTreeViewColumn = gtk_tree_view_column_new(); 677 gtk_tree_view_column_set_title(gParts->middleTreeViewColumn, "M"); 678 gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget), 679 gParts->middleTreeViewColumn); 680 681 lastTreeViewColumn = gtk_tree_view_column_new(); 682 gtk_tree_view_column_set_title(lastTreeViewColumn, "M"); 683 gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget), lastTreeViewColumn); 684 685 /* Use the middle column's header for our button */ 686 gParts->treeHeaderCellWidget = gParts->middleTreeViewColumn->button; 687 gParts->treeHeaderSortArrowWidget = gParts->middleTreeViewColumn->arrow; 688 g_object_set_data(G_OBJECT(gParts->treeHeaderCellWidget), 689 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 690 g_object_set_data(G_OBJECT(gParts->treeHeaderSortArrowWidget), 691 "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 692 } 693 return MOZ_GTK_SUCCESS; 694 } 695 696 static gint 697 ensure_expander_widget() 698 { 699 if (!gParts->expanderWidget) { 700 gParts->expanderWidget = gtk_expander_new("M"); 701 setup_widget_prototype(gParts->expanderWidget); 702 } 703 return MOZ_GTK_SUCCESS; 704 } 705 706 static gint 707 ensure_scrolled_window_widget() 708 { 709 if (!gParts->scrolledWindowWidget) { 710 gParts->scrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL); 711 setup_widget_prototype(gParts->scrolledWindowWidget); 712 } 713 return MOZ_GTK_SUCCESS; 714 } 715 716 static GtkStateType 717 ConvertGtkState(GtkWidgetState* state) 718 { 719 if (state->disabled) 720 return GTK_STATE_INSENSITIVE; 721 else if (state->depressed) 722 return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); 723 else if (state->inHover) 724 return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); 725 else 726 return GTK_STATE_NORMAL; 727 } 728 729 static gint 730 TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin) 731 { 732 int i; 733 /* there are 5 gc's in each array, for each of the widget states */ 734 for (i = 0; i < 5; ++i) 735 gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin); 736 return MOZ_GTK_SUCCESS; 737 } 738 739 static gint 740 TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin) 741 { 742 TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin); 743 TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin); 744 TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin); 745 TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin); 746 TSOffsetStyleGCArray(style->mid_gc, xorigin, yorigin); 747 TSOffsetStyleGCArray(style->text_gc, xorigin, yorigin); 748 TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin); 749 gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin); 750 gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin); 751 return MOZ_GTK_SUCCESS; 752 } 753 754 static gint 755 moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect, 756 GdkRectangle* cliprect, GtkWidgetState* state, 757 GtkReliefStyle relief, GtkWidget* widget, 758 GtkTextDirection direction) 759 { 760 GtkShadowType shadow_type; 761 GtkStyle* style = widget->style; 762 GtkStateType button_state = ConvertGtkState(state); 763 gint x = rect->x, y=rect->y, width=rect->width, height=rect->height; 764 765 gboolean interior_focus; 766 gint focus_width, focus_pad; 767 768 moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad); 769 770 if (WINDOW_IS_MAPPED(drawable)) { 771 gdk_window_set_back_pixmap(drawable, NULL, TRUE); 772 gdk_window_clear_area(drawable, cliprect->x, cliprect->y, 773 cliprect->width, cliprect->height); 774 } 775 776 gtk_widget_set_state(widget, button_state); 777 gtk_widget_set_direction(widget, direction); 778 779 if (state->isDefault) 780 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT); 781 782 GTK_BUTTON(widget)->relief = relief; 783 784 /* Some theme engines love to cause us pain in that gtk_paint_focus is a 785 no-op on buttons and button-like widgets. They only listen to this flag. */ 786 if (state->focused && !state->disabled) 787 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); 788 789 if (!interior_focus && state->focused) { 790 x += focus_width + focus_pad; 791 y += focus_width + focus_pad; 792 width -= 2 * (focus_width + focus_pad); 793 height -= 2 * (focus_width + focus_pad); 794 } 795 796 shadow_type = button_state == GTK_STATE_ACTIVE || 797 state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; 798 799 if (state->isDefault && relief == GTK_RELIEF_NORMAL) { 800 gtk_paint_box(style, drawable, button_state, shadow_type, cliprect, 801 widget, "buttondefault", x, y, width, height); 802 } 803 804 if (relief != GTK_RELIEF_NONE || state->depressed || 805 (button_state != GTK_STATE_NORMAL && 806 button_state != GTK_STATE_INSENSITIVE)) { 807 TSOffsetStyleGCs(style, x, y); 808 /* the following line can trigger an assertion (Crux theme) 809 file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area): 810 assertion `GDK_IS_WINDOW (window)' failed */ 811 gtk_paint_box(style, drawable, button_state, shadow_type, cliprect, 812 widget, "button", x, y, width, height); 813 } 814 815 if (state->focused) { 816 if (interior_focus) { 817 x += widget->style->xthickness + focus_pad; 818 y += widget->style->ythickness + focus_pad; 819 width -= 2 * (widget->style->xthickness + focus_pad); 820 height -= 2 * (widget->style->ythickness + focus_pad); 821 } else { 822 x -= focus_width + focus_pad; 823 y -= focus_width + focus_pad; 824 width += 2 * (focus_width + focus_pad); 825 height += 2 * (focus_width + focus_pad); 826 } 827 828 TSOffsetStyleGCs(style, x, y); 829 gtk_paint_focus(style, drawable, button_state, cliprect, 830 widget, "button", x, y, width, height); 831 } 832 833 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT); 834 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); 835 return MOZ_GTK_SUCCESS; 836 } 837 838 gint 839 moz_gtk_init() 840 { 841 GtkWidgetClass *entry_class; 842 843 is_initialized = TRUE; 844 have_arrow_scaling = (gtk_major_version > 2 || 845 (gtk_major_version == 2 && gtk_minor_version >= 12)); 846 847 /* Add style property to GtkEntry. 848 * Adding the style property to the normal GtkEntry class means that it 849 * will work without issues inside GtkComboBox and for Spinbuttons. */ 850 entry_class = g_type_class_ref(GTK_TYPE_ENTRY); 851 gtk_widget_class_install_style_property(entry_class, 852 g_param_spec_boolean("honors-transparent-bg-hint", 853 "Transparent BG enabling flag", 854 "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.", 855 FALSE, 856 G_PARAM_READWRITE)); 857 858 return MOZ_GTK_SUCCESS; 859 } 860 861 gint 862 moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing) 863 { 864 ensure_checkbox_widget(); 865 866 gtk_widget_style_get (gParts->checkboxWidget, 867 "indicator_size", indicator_size, 868 "indicator_spacing", indicator_spacing, 869 NULL); 870 871 return MOZ_GTK_SUCCESS; 872 } 873 874 gint 875 moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing) 876 { 877 ensure_radiobutton_widget(); 878 879 gtk_widget_style_get (gParts->radiobuttonWidget, 880 "indicator_size", indicator_size, 881 "indicator_spacing", indicator_spacing, 882 NULL); 883 884 return MOZ_GTK_SUCCESS; 885 } 886 887 gint 888 moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus, 889 gint* focus_width, gint* focus_pad) 890 { 891 gtk_widget_style_get (widget, 892 "interior-focus", interior_focus, 893 "focus-line-width", focus_width, 894 "focus-padding", focus_pad, 895 NULL); 896 897 return MOZ_GTK_SUCCESS; 898 } 899 900 gint 901 moz_gtk_splitter_get_metrics(gint orientation, gint* size) 902 { 903 if (orientation == GTK_ORIENTATION_HORIZONTAL) { 904 ensure_hpaned_widget(); 905 gtk_widget_style_get(gParts->hpanedWidget, "handle_size", size, NULL); 906 } else { 907 ensure_vpaned_widget(); 908 gtk_widget_style_get(gParts->vpanedWidget, "handle_size", size, NULL); 909 } 910 return MOZ_GTK_SUCCESS; 911 } 912 913 gint 914 moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border) 915 { 916 static const GtkBorder default_inner_border = { 1, 1, 1, 1 }; 917 GtkBorder *tmp_border; 918 919 gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL); 920 921 if (tmp_border) { 922 *inner_border = *tmp_border; 923 gtk_border_free(tmp_border); 924 } 925 else 926 *inner_border = default_inner_border; 927 928 return MOZ_GTK_SUCCESS; 929 } 930 931 static gint 932 moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, 933 GdkRectangle* cliprect, GtkWidgetState* state, 934 gboolean selected, gboolean inconsistent, 935 gboolean isradio, GtkTextDirection direction) 936 { 937 GtkStateType state_type = ConvertGtkState(state); 938 GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT; 939 gint indicator_size, indicator_spacing; 940 gint x, y, width, height; 941 gint focus_x, focus_y, focus_width, focus_height; 942 GtkWidget *w; 943 GtkStyle *style; 944 945 if (isradio) { 946 moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); 947 w = gParts->radiobuttonWidget; 948 } else { 949 moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); 950 w = gParts->checkboxWidget; 951 } 952 953 // "GetMinimumWidgetSize was ignored" 954 // FIXME: This assert causes a build failure in WebKitGTK+ debug 955 // builds, because it uses 'false' in its definition. We may want 956 // to force this file to be built with g++, by renaming it. 957 // ASSERT(rect->width == indicator_size); 958 959 /* 960 * vertically center in the box, since XUL sometimes ignores our 961 * GetMinimumWidgetSize in the vertical dimension 962 */ 963 x = rect->x; 964 y = rect->y + (rect->height - indicator_size) / 2; 965 width = indicator_size; 966 height = indicator_size; 967 968 focus_x = x - indicator_spacing; 969 focus_y = y - indicator_spacing; 970 focus_width = width + 2 * indicator_spacing; 971 focus_height = height + 2 * indicator_spacing; 972 973 style = w->style; 974 TSOffsetStyleGCs(style, x, y); 975 976 gtk_widget_set_sensitive(w, !state->disabled); 977 gtk_widget_set_direction(w, direction); 978 GTK_TOGGLE_BUTTON(w)->active = selected; 979 980 if (isradio) { 981 gtk_paint_option(style, drawable, state_type, shadow_type, cliprect, 982 gParts->radiobuttonWidget, "radiobutton", x, y, 983 width, height); 984 if (state->focused) { 985 gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, 986 gParts->radiobuttonWidget, "radiobutton", focus_x, focus_y, 987 focus_width, focus_height); 988 } 989 } 990 else { 991 /* 992 * 'indeterminate' type on checkboxes. In GTK, the shadow type 993 * must also be changed for the state to be drawn. 994 */ 995 if (inconsistent) { 996 gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), TRUE); 997 shadow_type = GTK_SHADOW_ETCHED_IN; 998 } else { 999 gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), FALSE); 1000 } 1001 1002 gtk_paint_check(style, drawable, state_type, shadow_type, cliprect, 1003 gParts->checkboxWidget, "checkbutton", x, y, width, height); 1004 if (state->focused) { 1005 gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, 1006 gParts->checkboxWidget, "checkbutton", focus_x, focus_y, 1007 focus_width, focus_height); 1008 } 1009 } 1010 1011 return MOZ_GTK_SUCCESS; 1012 } 1013 1014 static gint 1015 calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect, 1016 GdkRectangle* inner_rect, 1017 GtkTextDirection direction, 1018 gboolean ignore_focus) 1019 { 1020 GtkBorder inner_border; 1021 gboolean interior_focus; 1022 gint focus_width, focus_pad; 1023 GtkStyle* style; 1024 1025 style = button->style; 1026 1027 /* This mirrors gtkbutton's child positioning */ 1028 moz_gtk_button_get_inner_border(button, &inner_border); 1029 moz_gtk_widget_get_focus(button, &interior_focus, 1030 &focus_width, &focus_pad); 1031 1032 if (ignore_focus) 1033 focus_width = focus_pad = 0; 1034 1035 inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad; 1036 inner_rect->x += direction == GTK_TEXT_DIR_LTR ? 1037 inner_border.left : inner_border.right; 1038 inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) + 1039 focus_width + focus_pad; 1040 inner_rect->width = MAX(1, rect->width - inner_border.left - 1041 inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2); 1042 inner_rect->height = MAX(1, rect->height - inner_border.top - 1043 inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2); 1044 1045 return MOZ_GTK_SUCCESS; 1046 } 1047 1048 1049 static gint 1050 calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect, 1051 GdkRectangle* arrow_rect, GtkTextDirection direction) 1052 { 1053 /* defined in gtkarrow.c */ 1054 gfloat arrow_scaling = 0.7; 1055 gfloat xalign, xpad; 1056 gint extent; 1057 GtkMisc* misc = GTK_MISC(arrow); 1058 1059 if (have_arrow_scaling) 1060 gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL); 1061 1062 extent = MIN((rect->width - misc->xpad * 2), 1063 (rect->height - misc->ypad * 2)) * arrow_scaling; 1064 1065 xalign = direction == GTK_TEXT_DIR_LTR ? misc->xalign : 1.0 - misc->xalign; 1066 xpad = misc->xpad + (rect->width - extent) * xalign; 1067 1068 arrow_rect->x = direction == GTK_TEXT_DIR_LTR ? 1069 floor(rect->x + xpad) : ceil(rect->x + xpad); 1070 arrow_rect->y = floor(rect->y + misc->ypad + 1071 ((rect->height - extent) * misc->yalign)); 1072 1073 arrow_rect->width = arrow_rect->height = extent; 1074 1075 return MOZ_GTK_SUCCESS; 1076 } 1077 1078 static gint 1079 moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, 1080 GdkRectangle* cliprect, GtkWidgetState* state, 1081 GtkScrollbarButtonFlags flags, 1082 GtkTextDirection direction) 1083 { 1084 GtkStateType state_type = ConvertGtkState(state); 1085 GtkShadowType shadow_type = (state->active) ? 1086 GTK_SHADOW_IN : GTK_SHADOW_OUT; 1087 GdkRectangle arrow_rect; 1088 GtkStyle* style; 1089 GtkWidget *scrollbar; 1090 GtkArrowType arrow_type; 1091 gint arrow_displacement_x, arrow_displacement_y; 1092 const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ? 1093 "vscrollbar" : "hscrollbar"; 1094 1095 ensure_scrollbar_widget(); 1096 1097 if (flags & MOZ_GTK_STEPPER_VERTICAL) 1098 scrollbar = gParts->vertScrollbarWidget; 1099 else 1100 scrollbar = gParts->horizScrollbarWidget; 1101 1102 gtk_widget_set_direction(scrollbar, direction); 1103 1104 /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation 1105 to determine where it should paint rounded corners on the buttons. 1106 We need to trick them into drawing the buttons the way we want them. */ 1107 1108 scrollbar->allocation.x = rect->x; 1109 scrollbar->allocation.y = rect->y; 1110 scrollbar->allocation.width = rect->width; 1111 scrollbar->allocation.height = rect->height; 1112 1113 if (flags & MOZ_GTK_STEPPER_VERTICAL) { 1114 scrollbar->allocation.height *= 5; 1115 if (flags & MOZ_GTK_STEPPER_DOWN) { 1116 arrow_type = GTK_ARROW_DOWN; 1117 if (flags & MOZ_GTK_STEPPER_BOTTOM) 1118 scrollbar->allocation.y -= 4 * rect->height; 1119 else 1120 scrollbar->allocation.y -= rect->height; 1121 1122 } else { 1123 arrow_type = GTK_ARROW_UP; 1124 if (flags & MOZ_GTK_STEPPER_BOTTOM) 1125 scrollbar->allocation.y -= 3 * rect->height; 1126 } 1127 } else { 1128 scrollbar->allocation.width *= 5; 1129 if (flags & MOZ_GTK_STEPPER_DOWN) { 1130 arrow_type = GTK_ARROW_RIGHT; 1131 if (flags & MOZ_GTK_STEPPER_BOTTOM) 1132 scrollbar->allocation.x -= 4 * rect->width; 1133 else 1134 scrollbar->allocation.x -= rect->width; 1135 } else { 1136 arrow_type = GTK_ARROW_LEFT; 1137 if (flags & MOZ_GTK_STEPPER_BOTTOM) 1138 scrollbar->allocation.x -= 3 * rect->width; 1139 } 1140 } 1141 1142 style = scrollbar->style; 1143 1144 TSOffsetStyleGCs(style, rect->x, rect->y); 1145 1146 gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, 1147 scrollbar, detail, rect->x, rect->y, 1148 rect->width, rect->height); 1149 1150 arrow_rect.width = rect->width / 2; 1151 arrow_rect.height = rect->height / 2; 1152 arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; 1153 arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; 1154 1155 if (state_type == GTK_STATE_ACTIVE) { 1156 gtk_widget_style_get(scrollbar, 1157 "arrow-displacement-x", &arrow_displacement_x, 1158 "arrow-displacement-y", &arrow_displacement_y, 1159 NULL); 1160 1161 arrow_rect.x += arrow_displacement_x; 1162 arrow_rect.y += arrow_displacement_y; 1163 } 1164 1165 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, 1166 scrollbar, detail, arrow_type, TRUE, arrow_rect.x, 1167 arrow_rect.y, arrow_rect.width, arrow_rect.height); 1168 1169 return MOZ_GTK_SUCCESS; 1170 } 1171 1172 static gint 1173 moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget, 1174 GdkDrawable* drawable, GdkRectangle* rect, 1175 GdkRectangle* cliprect, GtkWidgetState* state, 1176 GtkTextDirection direction) 1177 { 1178 GtkStyle* style; 1179 GtkScrollbar *scrollbar; 1180 1181 ensure_scrollbar_widget(); 1182 1183 if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL) 1184 scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget); 1185 else 1186 scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget); 1187 1188 gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); 1189 1190 style = GTK_WIDGET(scrollbar)->style; 1191 1192 TSOffsetStyleGCs(style, rect->x, rect->y); 1193 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_ACTIVE, 1194 cliprect, rect->x, rect->y, 1195 rect->width, rect->height); 1196 1197 gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, 1198 GTK_WIDGET(scrollbar), "trough", rect->x, rect->y, 1199 rect->width, rect->height); 1200 1201 if (state->focused) { 1202 gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, 1203 GTK_WIDGET(scrollbar), "trough", 1204 rect->x, rect->y, rect->width, rect->height); 1205 } 1206 1207 return MOZ_GTK_SUCCESS; 1208 } 1209 1210 static gint 1211 moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, 1212 GdkDrawable* drawable, GdkRectangle* rect, 1213 GdkRectangle* cliprect, GtkWidgetState* state, 1214 GtkTextDirection direction) 1215 { 1216 GtkStateType state_type = (state->inHover || state->active) ? 1217 GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; 1218 GtkShadowType shadow_type = GTK_SHADOW_OUT; 1219 GtkStyle* style; 1220 GtkScrollbar *scrollbar; 1221 GtkAdjustment *adj; 1222 gboolean activate_slider; 1223 1224 ensure_scrollbar_widget(); 1225 1226 if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) 1227 scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget); 1228 else 1229 scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget); 1230 1231 gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); 1232 1233 /* Make sure to set the scrollbar range before painting so that 1234 everything is drawn properly. At least the bluecurve (and 1235 maybe other) themes don't draw the top or bottom black line 1236 surrounding the scrollbar if the theme thinks that it's butted 1237 up against the scrollbar arrows. Note the increases of the 1238 clip rect below. */ 1239 /* Changing the cliprect is pretty bogus. This lets themes draw 1240 outside the frame, which means we don't invalidate them 1241 correctly. See bug 297508. But some themes do seem to need 1242 it. So we modify the frame's overflow area to account for what 1243 we're doing here; see nsNativeThemeGTK::GetWidgetOverflow. */ 1244 adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar)); 1245 1246 if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) { 1247 cliprect->x -= 1; 1248 cliprect->width += 2; 1249 adj->page_size = rect->width; 1250 } 1251 else { 1252 cliprect->y -= 1; 1253 cliprect->height += 2; 1254 adj->page_size = rect->height; 1255 } 1256 1257 adj->lower = 0; 1258 adj->value = state->curpos; 1259 adj->upper = state->maxpos; 1260 gtk_adjustment_changed(adj); 1261 1262 style = GTK_WIDGET(scrollbar)->style; 1263 1264 gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider", 1265 &activate_slider, NULL); 1266 1267 if (activate_slider && state->active) { 1268 shadow_type = GTK_SHADOW_IN; 1269 state_type = GTK_STATE_ACTIVE; 1270 } 1271 1272 TSOffsetStyleGCs(style, rect->x, rect->y); 1273 1274 gtk_paint_slider(style, drawable, state_type, shadow_type, cliprect, 1275 GTK_WIDGET(scrollbar), "slider", rect->x, rect->y, 1276 rect->width, rect->height, 1277 (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ? 1278 GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); 1279 1280 return MOZ_GTK_SUCCESS; 1281 } 1282 1283 static gint 1284 moz_gtk_spin_paint(GdkDrawable* drawable, GdkRectangle* rect, 1285 GtkTextDirection direction) 1286 { 1287 GtkStyle* style; 1288 1289 ensure_spin_widget(); 1290 gtk_widget_set_direction(gParts->spinWidget, direction); 1291 style = gParts->spinWidget->style; 1292 1293 TSOffsetStyleGCs(style, rect->x, rect->y); 1294 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, 1295 gParts->spinWidget, "spinbutton", 1296 rect->x, rect->y, rect->width, rect->height); 1297 return MOZ_GTK_SUCCESS; 1298 } 1299 1300 static gint 1301 moz_gtk_spin_updown_paint(GdkDrawable* drawable, GdkRectangle* rect, 1302 gboolean isDown, GtkWidgetState* state, 1303 GtkTextDirection direction) 1304 { 1305 GdkRectangle arrow_rect; 1306 GtkStateType state_type = ConvertGtkState(state); 1307 GtkShadowType shadow_type = state_type == GTK_STATE_ACTIVE ? 1308 GTK_SHADOW_IN : GTK_SHADOW_OUT; 1309 GtkStyle* style; 1310 1311 ensure_spin_widget(); 1312 style = gParts->spinWidget->style; 1313 gtk_widget_set_direction(gParts->spinWidget, direction); 1314 1315 TSOffsetStyleGCs(style, rect->x, rect->y); 1316 gtk_paint_box(style, drawable, state_type, shadow_type, NULL, gParts->spinWidget, 1317 isDown ? "spinbutton_down" : "spinbutton_up", 1318 rect->x, rect->y, rect->width, rect->height); 1319 1320 /* hard code these values */ 1321 arrow_rect.width = 6; 1322 arrow_rect.height = 6; 1323 arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; 1324 arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; 1325 arrow_rect.y += isDown ? -1 : 1; 1326 1327 gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL, 1328 gParts->spinWidget, "spinbutton", 1329 isDown ? GTK_ARROW_DOWN : GTK_ARROW_UP, TRUE, 1330 arrow_rect.x, arrow_rect.y, 1331 arrow_rect.width, arrow_rect.height); 1332 1333 return MOZ_GTK_SUCCESS; 1334 } 1335 1336 static gint 1337 moz_gtk_scale_paint(GdkDrawable* drawable, GdkRectangle* rect, 1338 GdkRectangle* cliprect, GtkWidgetState* state, 1339 GtkOrientation flags, GtkTextDirection direction) 1340 { 1341 gint x = 0, y = 0; 1342 GtkStateType state_type = ConvertGtkState(state); 1343 GtkStyle* style; 1344 GtkWidget* widget; 1345 1346 ensure_scale_widget(); 1347 widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); 1348 gtk_widget_set_direction(widget, direction); 1349 1350 style = widget->style; 1351 1352 if (flags == GTK_ORIENTATION_HORIZONTAL) { 1353 x = XTHICKNESS(style); 1354 y++; 1355 } 1356 else { 1357 x++; 1358 y = YTHICKNESS(style); 1359 } 1360 1361 TSOffsetStyleGCs(style, rect->x, rect->y); 1362 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, 1363 cliprect, rect->x, rect->y, 1364 rect->width, rect->height); 1365 1366 gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, 1367 widget, "trough", rect->x + x, rect->y + y, 1368 rect->width - 2*x, rect->height - 2*y); 1369 1370 if (state->focused) 1371 gtk_paint_focus(style, drawable, state_type, cliprect, widget, "trough", 1372 rect->x, rect->y, rect->width, rect->height); 1373 1374 return MOZ_GTK_SUCCESS; 1375 } 1376 1377 static gint 1378 moz_gtk_scale_thumb_paint(GdkDrawable* drawable, GdkRectangle* rect, 1379 GdkRectangle* cliprect, GtkWidgetState* state, 1380 GtkOrientation flags, GtkTextDirection direction) 1381 { 1382 GtkStateType state_type = ConvertGtkState(state); 1383 GtkStyle* style; 1384 GtkWidget* widget; 1385 gint thumb_width, thumb_height, x, y; 1386 1387 ensure_scale_widget(); 1388 widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); 1389 gtk_widget_set_direction(widget, direction); 1390 1391 style = widget->style; 1392 1393 /* determine the thumb size, and position the thumb in the center in the opposite axis */ 1394 if (flags == GTK_ORIENTATION_HORIZONTAL) { 1395 moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height); 1396 x = rect->x; 1397 y = rect->y + (rect->height - thumb_height) / 2; 1398 } 1399 else { 1400 moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width); 1401 x = rect->x + (rect->width - thumb_width) / 2; 1402 y = rect->y; 1403 } 1404 1405 TSOffsetStyleGCs(style, rect->x, rect->y); 1406 gtk_paint_slider(style, drawable, state_type, GTK_SHADOW_OUT, cliprect, 1407 widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale", 1408 x, y, thumb_width, thumb_height, flags); 1409 1410 return MOZ_GTK_SUCCESS; 1411 } 1412 1413 static gint 1414 moz_gtk_gripper_paint(GdkDrawable* drawable, GdkRectangle* rect, 1415 GdkRectangle* cliprect, GtkWidgetState* state, 1416 GtkTextDirection direction) 1417 { 1418 GtkStateType state_type = ConvertGtkState(state); 1419 GtkShadowType shadow_type; 1420 GtkStyle* style; 1421 1422 ensure_handlebox_widget(); 1423 gtk_widget_set_direction(gParts->handleBoxWidget, direction); 1424 1425 style = gParts->handleBoxWidget->style; 1426 shadow_type = GTK_HANDLE_BOX(gParts->handleBoxWidget)->shadow_type; 1427 1428 TSOffsetStyleGCs(style, rect->x, rect->y); 1429 gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, 1430 gParts->handleBoxWidget, "handlebox_bin", rect->x, rect->y, 1431 rect->width, rect->height); 1432 1433 return MOZ_GTK_SUCCESS; 1434 } 1435 1436 static gint 1437 moz_gtk_hpaned_paint(GdkDrawable* drawable, GdkRectangle* rect, 1438 GdkRectangle* cliprect, GtkWidgetState* state) 1439 { 1440 GtkStateType hpaned_state = ConvertGtkState(state); 1441 1442 ensure_hpaned_widget(); 1443 gtk_paint_handle(gParts->hpanedWidget->style, drawable, hpaned_state, 1444 GTK_SHADOW_NONE, cliprect, gParts->hpanedWidget, "paned", 1445 rect->x, rect->y, rect->width, rect->height, 1446 GTK_ORIENTATION_VERTICAL); 1447 1448 return MOZ_GTK_SUCCESS; 1449 } 1450 1451 static gint 1452 moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect, 1453 GdkRectangle* cliprect, GtkWidgetState* state) 1454 { 1455 GtkStateType vpaned_state = ConvertGtkState(state); 1456 1457 ensure_vpaned_widget(); 1458 gtk_paint_handle(gParts->vpanedWidget->style, drawable, vpaned_state, 1459 GTK_SHADOW_NONE, cliprect, gParts->vpanedWidget, "paned", 1460 rect->x, rect->y, rect->width, rect->height, 1461 GTK_ORIENTATION_HORIZONTAL); 1462 1463 return MOZ_GTK_SUCCESS; 1464 } 1465 1466 static gint 1467 moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect, 1468 GdkRectangle* cliprect, GtkTextDirection direction) 1469 { 1470 GdkRectangle location = *rect; 1471 if (direction == GTK_TEXT_DIR_RTL) { 1472 /* gtk_draw_insertion_cursor ignores location.width */ 1473 location.x = rect->x + rect->width; 1474 } 1475 1476 ensure_entry_widget(); 1477 gtk_draw_insertion_cursor(gParts->entryWidget, drawable, cliprect, 1478 &location, TRUE, direction, FALSE); 1479 1480 return MOZ_GTK_SUCCESS; 1481 } 1482 1483 static gint 1484 moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, 1485 GdkRectangle* cliprect, GtkWidgetState* state, 1486 GtkWidget* widget, GtkTextDirection direction) 1487 { 1488 GtkStateType bg_state = state->disabled ? 1489 GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; 1490 gint x, y, width = rect->width, height = rect->height; 1491 GtkStyle* style; 1492 gboolean interior_focus; 1493 gboolean theme_honors_transparency = FALSE; 1494 gint focus_width; 1495 1496 gtk_widget_set_direction(widget, direction); 1497 1498 style = widget->style; 1499 1500 gtk_widget_style_get(widget, 1501 "interior-focus", &interior_focus, 1502 "focus-line-width", &focus_width, 1503 "honors-transparent-bg-hint", &theme_honors_transparency, 1504 NULL); 1505 1506 /* gtkentry.c uses two windows, one for the entire widget and one for the 1507 * text area inside it. The background of both windows is set to the "base" 1508 * color of the new state in gtk_entry_state_changed, but only the inner 1509 * textarea window uses gtk_paint_flat_box when exposed */ 1510 1511 TSOffsetStyleGCs(style, rect->x, rect->y); 1512 1513 /* This gets us a lovely greyish disabledish look */ 1514 gtk_widget_set_sensitive(widget, !state->disabled); 1515 1516 /* GTK fills the outer widget window with the base color before drawing the widget. 1517 * Some older themes rely on this behavior, but many themes nowadays use rounded 1518 * corners on their widgets. While most GTK apps are blissfully unaware of this 1519 * problem due to their use of the default window background, we render widgets on 1520 * many kinds of backgrounds on the web. 1521 * If the theme is able to cope with transparency, then we can skip pre-filling 1522 * and notify the theme it will paint directly on the canvas. */ 1523 if (theme_honors_transparency) { 1524 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); 1525 } else { 1526 gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE, 1527 cliprect->x, cliprect->y, cliprect->width, cliprect->height); 1528 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE)); 1529 } 1530 1531 /* Get the position of the inner window, see _gtk_entry_get_borders */ 1532 x = XTHICKNESS(style); 1533 y = YTHICKNESS(style); 1534 1535 if (!interior_focus) { 1536 x += focus_width; 1537 y += focus_width; 1538 } 1539 1540 /* Simulate an expose of the inner window */ 1541 gtk_paint_flat_box(style, drawable, bg_state, GTK_SHADOW_NONE, 1542 cliprect, widget, "entry_bg", rect->x + x, 1543 rect->y + y, rect->width - 2*x, rect->height - 2*y); 1544 1545 /* Now paint the shadow and focus border. 1546 * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad 1547 * smaller when focused if the focus is not interior, then the focus. */ 1548 x = rect->x; 1549 y = rect->y; 1550 1551 if (state->focused && !state->disabled) { 1552 /* This will get us the lit borders that focused textboxes enjoy on 1553 * some themes. */ 1554 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); 1555 1556 if (!interior_focus) { 1557 /* Indent the border a little bit if we have exterior focus 1558 (this is what GTK does to draw native entries) */ 1559 x += focus_width; 1560 y += focus_width; 1561 width -= 2 * focus_width; 1562 height -= 2 * focus_width; 1563 } 1564 } 1565 1566 gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, 1567 cliprect, widget, "entry", x, y, width, height); 1568 1569 if (state->focused && !state->disabled) { 1570 if (!interior_focus) { 1571 gtk_paint_focus(style, drawable, GTK_STATE_NORMAL, cliprect, 1572 widget, "entry", 1573 rect->x, rect->y, rect->width, rect->height); 1574 } 1575 1576 /* Now unset the focus flag. We don't want other entries to look 1577 * like they're focused too! */ 1578 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); 1579 } 1580 1581 return MOZ_GTK_SUCCESS; 1582 } 1583 1584 static gint 1585 moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect, 1586 GdkRectangle* cliprect, GtkWidgetState* state, 1587 GtkTextDirection direction) 1588 { 1589 gint xthickness, ythickness; 1590 1591 GtkStyle *style; 1592 GtkStateType state_type; 1593 1594 ensure_tree_view_widget(); 1595 ensure_scrolled_window_widget(); 1596 1597 gtk_widget_set_direction(gParts->treeViewWidget, direction); 1598 gtk_widget_set_direction(gParts->scrolledWindowWidget, direction); 1599 1600 /* only handle disabled and normal states, otherwise the whole background 1601 * area will be painted differently with other states */ 1602 state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; 1603 1604 /* In GTK the treeview sets the background of the window 1605 * which contains the cells to the treeview base color. 1606 * If we don't set it here the background color will not be correct.*/ 1607 gtk_widget_modify_bg(gParts->treeViewWidget, state_type, 1608 &gParts->treeViewWidget->style->base[state_type]); 1609 1610 style = gParts->scrolledWindowWidget->style; 1611 xthickness = XTHICKNESS(style); 1612 ythickness = YTHICKNESS(style); 1613 1614 TSOffsetStyleGCs(gParts->treeViewWidget->style, rect->x, rect->y); 1615 TSOffsetStyleGCs(style, rect->x, rect->y); 1616 1617 gtk_paint_flat_box(gParts->treeViewWidget->style, drawable, state_type, 1618 GTK_SHADOW_NONE, cliprect, gParts->treeViewWidget, "treeview", 1619 rect->x + xthickness, rect->y + ythickness, 1620 rect->width - 2 * xthickness, 1621 rect->height - 2 * ythickness); 1622 1623 gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, 1624 cliprect, gParts->scrolledWindowWidget, "scrolled_window", 1625 rect->x, rect->y, rect->width, rect->height); 1626 1627 return MOZ_GTK_SUCCESS; 1628 } 1629 1630 static gint 1631 moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect, 1632 GdkRectangle* cliprect, GtkWidgetState* state, 1633 gboolean isSorted, GtkTextDirection direction) 1634 { 1635 gtk_tree_view_column_set_sort_indicator(gParts->middleTreeViewColumn, 1636 isSorted); 1637 1638 moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, 1639 gParts->treeHeaderCellWidget, direction); 1640 return MOZ_GTK_SUCCESS; 1641 } 1642 1643 static gint 1644 moz_gtk_tree_header_sort_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, 1645 GdkRectangle* cliprect, 1646 GtkWidgetState* state, GtkArrowType flags, 1647 GtkTextDirection direction) 1648 { 1649 GdkRectangle arrow_rect; 1650 GtkStateType state_type = ConvertGtkState(state); 1651 GtkShadowType shadow_type = GTK_SHADOW_IN; 1652 GtkArrowType arrow_type = flags; 1653 GtkStyle* style; 1654 1655 ensure_tree_header_cell_widget(); 1656 gtk_widget_set_direction(gParts->treeHeaderSortArrowWidget, direction); 1657 1658 /* hard code these values */ 1659 arrow_rect.width = 11; 1660 arrow_rect.height = 11; 1661 arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; 1662 arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; 1663 1664 style = gParts->treeHeaderSortArrowWidget->style; 1665 TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y); 1666 1667 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, 1668 gParts->treeHeaderSortArrowWidget, "arrow", arrow_type, TRUE, 1669 arrow_rect.x, arrow_rect.y, 1670 arrow_rect.width, arrow_rect.height); 1671 1672 return MOZ_GTK_SUCCESS; 1673 } 1674 1675 static gint 1676 moz_gtk_treeview_expander_paint(GdkDrawable* drawable, GdkRectangle* rect, 1677 GdkRectangle* cliprect, GtkWidgetState* state, 1678 GtkExpanderStyle expander_state, 1679 GtkTextDirection direction) 1680 { 1681 GtkStyle *style; 1682 GtkStateType state_type; 1683 1684 ensure_tree_view_widget(); 1685 gtk_widget_set_direction(gParts->treeViewWidget, direction); 1686 1687 style = gParts->treeViewWidget->style; 1688 1689 /* Because the frame we get is of the entire treeview, we can't get the precise 1690 * event state of one expander, thus rendering hover and active feedback useless. */ 1691 state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; 1692 1693 TSOffsetStyleGCs(style, rect->x, rect->y); 1694 gtk_paint_expander(style, drawable, state_type, cliprect, gParts->treeViewWidget, "treeview", 1695 rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state); 1696 1697 return MOZ_GTK_SUCCESS; 1698 } 1699 1700 static gint 1701 moz_gtk_expander_paint(GdkDrawable* drawable, GdkRectangle* rect, 1702 GdkRectangle* cliprect, GtkWidgetState* state, 1703 GtkExpanderStyle expander_state, 1704 GtkTextDirection direction) 1705 { 1706 GtkStyle *style; 1707 GtkStateType state_type = ConvertGtkState(state); 1708 1709 ensure_expander_widget(); 1710 gtk_widget_set_direction(gParts->expanderWidget, direction); 1711 1712 style = gParts->expanderWidget->style; 1713 1714 TSOffsetStyleGCs(style, rect->x, rect->y); 1715 gtk_paint_expander(style, drawable, state_type, cliprect, gParts->expanderWidget, "expander", 1716 rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state); 1717 1718 return MOZ_GTK_SUCCESS; 1719 } 1720 1721 static gint 1722 moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect, 1723 GdkRectangle* cliprect, GtkWidgetState* state, 1724 gboolean ishtml, GtkTextDirection direction) 1725 { 1726 GdkRectangle arrow_rect, real_arrow_rect; 1727 gint /* arrow_size, */ separator_width; 1728 gboolean wide_separators; 1729 GtkStateType state_type = ConvertGtkState(state); 1730 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; 1731 GtkStyle* style; 1732 GtkRequisition arrow_req; 1733 1734 ensure_combo_box_widgets(); 1735 1736 /* Also sets the direction on gParts->comboBoxButtonWidget, which is then 1737 * inherited by the separator and arrow */ 1738 moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, 1739 gParts->comboBoxButtonWidget, direction); 1740 1741 calculate_button_inner_rect(gParts->comboBoxButtonWidget, 1742 rect, &arrow_rect, direction, ishtml); 1743 /* Now arrow_rect contains the inner rect ; we want to correct the width 1744 * to what the arrow needs (see gtk_combo_box_size_allocate) */ 1745 gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req); 1746 if (direction == GTK_TEXT_DIR_LTR) 1747 arrow_rect.x += arrow_rect.width - arrow_req.width; 1748 arrow_rect.width = arrow_req.width; 1749 1750 calculate_arrow_rect(gParts->comboBoxArrowWidget, 1751 &arrow_rect, &real_arrow_rect, direction); 1752 1753 style = gParts->comboBoxArrowWidget->style; 1754 TSOffsetStyleGCs(style, rect->x, rect->y); 1755 1756 gtk_widget_size_allocate(gParts->comboBoxWidget, rect); 1757 1758 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, 1759 gParts->comboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, 1760 real_arrow_rect.x, real_arrow_rect.y, 1761 real_arrow_rect.width, real_arrow_rect.height); 1762 1763 1764 /* If there is no separator in the theme, there's nothing left to do. */ 1765 if (!gParts->comboBoxSeparatorWidget) 1766 return MOZ_GTK_SUCCESS; 1767 1768 style = gParts->comboBoxSeparatorWidget->style; 1769 TSOffsetStyleGCs(style, rect->x, rect->y); 1770 1771 gtk_widget_style_get(gParts->comboBoxSeparatorWidget, 1772 "wide-separators", &wide_separators, 1773 "separator-width", &separator_width, 1774 NULL); 1775 1776 if (wide_separators) { 1777 if (direction == GTK_TEXT_DIR_LTR) 1778 arrow_rect.x -= separator_width; 1779 else 1780 arrow_rect.x += arrow_rect.width; 1781 1782 gtk_paint_box(style, drawable, 1783 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, 1784 cliprect, gParts->comboBoxSeparatorWidget, "vseparator", 1785 arrow_rect.x, arrow_rect.y, 1786 separator_width, arrow_rect.height); 1787 } else { 1788 if (direction == GTK_TEXT_DIR_LTR) 1789 arrow_rect.x -= XTHICKNESS(style); 1790 else 1791 arrow_rect.x += arrow_rect.width; 1792 1793 gtk_paint_vline(style, drawable, GTK_STATE_NORMAL, cliprect, 1794 gParts->comboBoxSeparatorWidget, "vseparator", 1795 arrow_rect.y, arrow_rect.y + arrow_rect.height, 1796 arrow_rect.x); 1797 } 1798 1799 return MOZ_GTK_SUCCESS; 1800 } 1801 1802 static gint 1803 moz_gtk_downarrow_paint(GdkDrawable* drawable, GdkRectangle* rect, 1804 GdkRectangle* cliprect, GtkWidgetState* state) 1805 { 1806 GtkStyle* style; 1807 GtkStateType state_type = ConvertGtkState(state); 1808 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; 1809 GdkRectangle arrow_rect; 1810 1811 ensure_button_arrow_widget(); 1812 style = gParts->buttonArrowWidget->style; 1813 1814 calculate_arrow_rect(gParts->buttonArrowWidget, rect, &arrow_rect, 1815 GTK_TEXT_DIR_LTR); 1816 1817 TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y); 1818 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, 1819 gParts->buttonArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, 1820 arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height); 1821 1822 return MOZ_GTK_SUCCESS; 1823 } 1824 1825 static gint 1826 moz_gtk_combo_box_entry_button_paint(GdkDrawable* drawable, GdkRectangle* rect, 1827 GdkRectangle* cliprect, 1828 GtkWidgetState* state, 1829 gboolean input_focus, 1830 GtkTextDirection direction) 1831 { 1832 gint x_displacement, y_displacement; 1833 GdkRectangle arrow_rect, real_arrow_rect; 1834 GtkStateType state_type = ConvertGtkState(state); 1835 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; 1836 GtkStyle* style; 1837 1838 ensure_combo_box_entry_widgets(); 1839 1840 if (input_focus) { 1841 /* Some themes draw a complementary focus ring for the dropdown button 1842 * when the dropdown entry has focus */ 1843 GTK_WIDGET_SET_FLAGS(gParts->comboBoxEntryTextareaWidget, GTK_HAS_FOCUS); 1844 } 1845 1846 moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, 1847 gParts->comboBoxEntryButtonWidget, direction); 1848 1849 if (input_focus) 1850 GTK_WIDGET_UNSET_FLAGS(gParts->comboBoxEntryTextareaWidget, GTK_HAS_FOCUS); 1851 1852 calculate_button_inner_rect(gParts->comboBoxEntryButtonWidget, 1853 rect, &arrow_rect, direction, FALSE); 1854 if (state_type == GTK_STATE_ACTIVE) { 1855 gtk_widget_style_get(gParts->comboBoxEntryButtonWidget, 1856 "child-displacement-x", &x_displacement, 1857 "child-displacement-y", &y_displacement, 1858 NULL); 1859 arrow_rect.x += x_displacement; 1860 arrow_rect.y += y_displacement; 1861 } 1862 1863 calculate_arrow_rect(gParts->comboBoxEntryArrowWidget, 1864 &arrow_rect, &real_arrow_rect, direction); 1865 1866 style = gParts->comboBoxEntryArrowWidget->style; 1867 TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y); 1868 1869 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, 1870 gParts->comboBoxEntryArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, 1871 real_arrow_rect.x, real_arrow_rect.y, 1872 real_arrow_rect.width, real_arrow_rect.height); 1873 1874 return MOZ_GTK_SUCCESS; 1875 } 1876 1877 static gint 1878 moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect, 1879 GdkRectangle* cliprect, GtkWidgetState* state, 1880 gboolean isradio, GtkTextDirection direction) 1881 { 1882 GtkStateType state_type = ConvertGtkState(state); 1883 GtkStyle* style; 1884 GtkWidget *widget; 1885 gboolean interior_focus; 1886 gint focus_width, focus_pad; 1887 1888 if (isradio) { 1889 ensure_radiobutton_widget(); 1890 widget = gParts->radiobuttonWidget; 1891 } else { 1892 ensure_checkbox_widget(); 1893 widget = gParts->checkboxWidget; 1894 } 1895 gtk_widget_set_direction(widget, direction); 1896 1897 style = widget->style; 1898 moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, 1899 &focus_pad); 1900 1901 TSOffsetStyleGCs(style, rect->x, rect->y); 1902 1903 /* The detail argument for the gtk_paint_* calls below are "checkbutton" 1904 even for radio buttons, to match what gtk does. */ 1905 1906 /* this is for drawing a prelight box */ 1907 if (state_type == GTK_STATE_PRELIGHT || state_type == GTK_STATE_ACTIVE) { 1908 gtk_paint_flat_box(style, drawable, GTK_STATE_PRELIGHT, 1909 GTK_SHADOW_ETCHED_OUT, cliprect, widget, 1910 "checkbutton", 1911 rect->x, rect->y, rect->width, rect->height); 1912 } 1913 1914 if (state_type != GTK_STATE_NORMAL && state_type != GTK_STATE_PRELIGHT) 1915 state_type = GTK_STATE_NORMAL; 1916 1917 if (state->focused && !interior_focus) { 1918 gtk_paint_focus(style, drawable, state_type, cliprect, widget, 1919 "checkbutton", 1920 rect->x, rect->y, rect->width, rect->height); 1921 } 1922 1923 return MOZ_GTK_SUCCESS; 1924 } 1925 1926 static gint 1927 moz_gtk_toggle_label_paint(GdkDrawable* drawable, GdkRectangle* rect, 1928 GdkRectangle* cliprect, GtkWidgetState* state, 1929 gboolean isradio, GtkTextDirection direction) 1930 { 1931 GtkStateType state_type; 1932 GtkStyle *style; 1933 GtkWidget *widget; 1934 gboolean interior_focus; 1935 1936 if (!state->focused) 1937 return MOZ_GTK_SUCCESS; 1938 1939 if (isradio) { 1940 ensure_radiobutton_widget(); 1941 widget = gParts->radiobuttonWidget; 1942 } else { 1943 ensure_checkbox_widget(); 1944 widget = gParts->checkboxWidget; 1945 } 1946 gtk_widget_set_direction(widget, direction); 1947 1948 gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL); 1949 if (!interior_focus) 1950 return MOZ_GTK_SUCCESS; 1951 1952 state_type = ConvertGtkState(state); 1953 1954 style = widget->style; 1955 TSOffsetStyleGCs(style, rect->x, rect->y); 1956 1957 /* Always "checkbutton" to match gtkcheckbutton.c */ 1958 gtk_paint_focus(style, drawable, state_type, cliprect, widget, 1959 "checkbutton", 1960 rect->x, rect->y, rect->width, rect->height); 1961 1962 return MOZ_GTK_SUCCESS; 1963 } 1964 1965 static gint 1966 moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect, 1967 GdkRectangle* cliprect, GtkTextDirection direction) 1968 { 1969 GtkStyle* style; 1970 GtkShadowType shadow_type; 1971 1972 ensure_toolbar_widget(); 1973 gtk_widget_set_direction(gParts->toolbarWidget, direction); 1974 1975 style = gParts->toolbarWidget->style; 1976 1977 TSOffsetStyleGCs(style, rect->x, rect->y); 1978 1979 gtk_style_apply_default_background(style, drawable, TRUE, 1980 GTK_STATE_NORMAL, 1981 cliprect, rect->x, rect->y, 1982 rect->width, rect->height); 1983 1984 gtk_widget_style_get(gParts->toolbarWidget, "shadow-type", &shadow_type, NULL); 1985 1986 gtk_paint_box (style, drawable, GTK_STATE_NORMAL, shadow_type, 1987 cliprect, gParts->toolbarWidget, "toolbar", 1988 rect->x, rect->y, rect->width, rect->height); 1989 1990 return MOZ_GTK_SUCCESS; 1991 } 1992 1993 static gint 1994 moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, 1995 GdkRectangle* cliprect, 1996 GtkTextDirection direction) 1997 { 1998 GtkStyle* style; 1999 gint separator_width; 2000 gint paint_width; 2001 gboolean wide_separators; 2002 2003 /* Defined as constants in GTK+ 2.10.14 */ 2004 const double start_fraction = 0.2; 2005 const double end_fraction = 0.8; 2006 2007 ensure_toolbar_separator_widget(); 2008 gtk_widget_set_direction(gParts->toolbarSeparatorWidget, direction); 2009 2010 style = gParts->toolbarSeparatorWidget->style; 2011 2012 gtk_widget_style_get(gParts->toolbarWidget, 2013 "wide-separators", &wide_separators, 2014 "separator-width", &separator_width, 2015 NULL); 2016 2017 TSOffsetStyleGCs(style, rect->x, rect->y); 2018 2019 if (wide_separators) { 2020 if (separator_width > rect->width) 2021 separator_width = rect->width; 2022 2023 gtk_paint_box(style, drawable, 2024 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, 2025 cliprect, gParts->toolbarWidget, "vseparator", 2026 rect->x + (rect->width - separator_width) / 2, 2027 rect->y + rect->height * start_fraction, 2028 separator_width, 2029 rect->height * (end_fraction - start_fraction)); 2030 2031 } else { 2032 paint_width = style->xthickness; 2033 2034 if (paint_width > rect->width) 2035 paint_width = rect->width; 2036 2037 gtk_paint_vline(style, drawable, 2038 GTK_STATE_NORMAL, cliprect, gParts->toolbarSeparatorWidget, 2039 "toolbar", 2040 rect->y + rect->height * start_fraction, 2041 rect->y + rect->height * end_fraction, 2042 rect->x + (rect->width - paint_width) / 2); 2043 } 2044 2045 return MOZ_GTK_SUCCESS; 2046 } 2047 2048 static gint 2049 moz_gtk_tooltip_paint(GdkDrawable* drawable, GdkRectangle* rect, 2050 GdkRectangle* cliprect, GtkTextDirection direction) 2051 { 2052 GtkStyle* style; 2053 2054 ensure_tooltip_widget(); 2055 gtk_widget_set_direction(gParts->tooltipWidget, direction); 2056 2057 style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), 2058 "gtk-tooltips", "GtkWindow", 2059 GTK_TYPE_WINDOW); 2060 2061 style = gtk_style_attach(style, gParts->tooltipWidget->window); 2062 TSOffsetStyleGCs(style, rect->x, rect->y); 2063 gtk_paint_flat_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, 2064 cliprect, gParts->tooltipWidget, "tooltip", 2065 rect->x, rect->y, rect->width, rect->height); 2066 2067 return MOZ_GTK_SUCCESS; 2068 } 2069 2070 static gint 2071 moz_gtk_resizer_paint(GdkDrawable* drawable, GdkRectangle* rect, 2072 GdkRectangle* cliprect, GtkWidgetState* state, 2073 GtkTextDirection direction) 2074 { 2075 GtkStyle* style; 2076 GtkStateType state_type = ConvertGtkState(state); 2077 2078 ensure_window_widget(); 2079 gtk_widget_set_direction(gParts->protoWindow, direction); 2080 2081 style = gParts->protoWindow->style; 2082 2083 TSOffsetStyleGCs(style, rect->x, rect->y); 2084 2085 gtk_paint_resize_grip(style, drawable, state_type, cliprect, gParts->protoWindow, 2086 NULL, (direction == GTK_TEXT_DIR_LTR) ? 2087 GDK_WINDOW_EDGE_SOUTH_EAST : 2088 GDK_WINDOW_EDGE_SOUTH_WEST, 2089 rect->x, rect->y, rect->width, rect->height); 2090 return MOZ_GTK_SUCCESS; 2091 } 2092 2093 static gint 2094 moz_gtk_frame_paint(GdkDrawable* drawable, GdkRectangle* rect, 2095 GdkRectangle* cliprect, GtkTextDirection direction) 2096 { 2097 GtkStyle* style; 2098 GtkShadowType shadow_type; 2099 2100 ensure_frame_widget(); 2101 gtk_widget_set_direction(gParts->frameWidget, direction); 2102 2103 style = gParts->frameWidget->style; 2104 2105 gtk_widget_style_get(gParts->statusbarWidget, "shadow-type", &shadow_type, NULL); 2106 2107 TSOffsetStyleGCs(style, rect->x, rect->y); 2108 gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, shadow_type, 2109 cliprect, gParts->frameWidget, "frame", rect->x, rect->y, 2110 rect->width, rect->height); 2111 2112 return MOZ_GTK_SUCCESS; 2113 } 2114 2115 static gint 2116 moz_gtk_progressbar_paint(GdkDrawable* drawable, GdkRectangle* rect, 2117 GdkRectangle* cliprect, GtkTextDirection direction) 2118 { 2119 GtkStyle* style; 2120 2121 ensure_progress_widget(); 2122 gtk_widget_set_direction(gParts->progresWidget, direction); 2123 2124 style = gParts->progresWidget->style; 2125 2126 TSOffsetStyleGCs(style, rect->x, rect->y); 2127 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, 2128 cliprect, gParts->progresWidget, "trough", rect->x, rect->y, 2129 rect->width, rect->height); 2130 2131 return MOZ_GTK_SUCCESS; 2132 } 2133 2134 static gint 2135 moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect, 2136 GdkRectangle* cliprect, GtkTextDirection direction) 2137 { 2138 GtkStyle* style; 2139 2140 ensure_progress_widget(); 2141 gtk_widget_set_direction(gParts->progresWidget, direction); 2142 2143 style = gParts->progresWidget->style; 2144 2145 TSOffsetStyleGCs(style, rect->x, rect->y); 2146 gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, 2147 cliprect, gParts->progresWidget, "bar", rect->x, rect->y, 2148 rect->width, rect->height); 2149 2150 return MOZ_GTK_SUCCESS; 2151 } 2152 2153 gint 2154 moz_gtk_get_tab_thickness(void) 2155 { 2156 ensure_tab_widget(); 2157 if (YTHICKNESS(gParts->tabWidget->style) < 2) 2158 return 2; /* some themes don't set ythickness correctly */ 2159 2160 return YTHICKNESS(gParts->tabWidget->style); 2161 } 2162 2163 static gint 2164 moz_gtk_tab_paint(GdkDrawable* drawable, GdkRectangle* rect, 2165 GdkRectangle* cliprect, GtkTabFlags flags, 2166 GtkTextDirection direction) 2167 { 2168 /* When the tab isn't selected, we just draw a notebook extension. 2169 * When it is selected, we overwrite the adjacent border of the tabpanel 2170 * touching the tab with a pierced border (called "the gap") to make the 2171 * tab appear physically attached to the tabpanel; see details below. */ 2172 2173 GtkStyle* style; 2174 2175 ensure_tab_widget(); 2176 gtk_widget_set_direction(gParts->tabWidget, direction); 2177 2178 style = gParts->tabWidget->style; 2179 TSOffsetStyleGCs(style, rect->x, rect->y); 2180 2181 if ((flags & MOZ_GTK_TAB_SELECTED) == 0) { 2182 /* Only draw the tab */ 2183 gtk_paint_extension(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, 2184 cliprect, gParts->tabWidget, "tab", 2185 rect->x, rect->y, rect->width, rect->height, 2186 (flags & MOZ_GTK_TAB_BOTTOM) ? 2187 GTK_POS_TOP : GTK_POS_BOTTOM ); 2188 } else { 2189 /* Draw the tab and the gap 2190 * We want the gap to be positionned exactly on the tabpanel top 2191 * border; since tabbox.css may set a negative margin so that the tab 2192 * frame rect already overlaps the tabpanel frame rect, we need to take 2193 * that into account when drawing. To that effect, nsNativeThemeGTK 2194 * passes us this negative margin (bmargin in the graphic below) in the 2195 * lowest bits of |flags|. We use it to set gap_voffset, the distance 2196 * between the top of the gap and the bottom of the tab (resp. the 2197 * bottom of the gap and the top of the tab when we draw a bottom tab), 2198 * while ensuring that the gap always touches the border of the tab, 2199 * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results 2200 * with big negative or positive margins. 2201 * Here is a graphical explanation in the case of top tabs: 2202 * ___________________________ 2203 * / \ 2204 * | T A B | 2205 * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel 2206 * : ^ bmargin : ^ 2207 * : | (-negative margin, : | 2208 * bottom : v passed in flags) : | gap_height 2209 * of -> :.............................: | (the size of the 2210 * the tab . part of the gap . | tabpanel top border) 2211 * . outside of the tab . v 2212 * ---------------------------------------------- 2213 * 2214 * To draw the gap, we use gtk_paint_box_gap(), see comment in 2215 * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall, 2216 * which should suffice to ensure that the only visible border is the 2217 * pierced one. If the tab is in the middle, we make the box_gap begin 2218 * a bit to the left of the tab and end a bit to the right, adjusting 2219 * the gap position so it still is under the tab, because we want the 2220 * rendering of a gap in the middle of a tabpanel. This is the role of 2221 * the gints gap_{l,r}_offset. On the contrary, if the tab is the 2222 * first, we align the start border of the box_gap with the start 2223 * border of the tab (left if LTR, right if RTL), by setting the 2224 * appropriate offset to 0.*/ 2225 gint gap_loffset, gap_roffset, gap_voffset, gap_height; 2226 2227 /* Get height needed by the gap */ 2228 gap_height = moz_gtk_get_tab_thickness(); 2229 2230 /* Extract gap_voffset from the first bits of flags */ 2231 gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK; 2232 if (gap_voffset > gap_height) 2233 gap_voffset = gap_height; 2234 2235 /* Set gap_{l,r}_offset to appropriate values */ 2236 gap_loffset = gap_roffset = 20; /* should be enough */ 2237 if (flags & MOZ_GTK_TAB_FIRST) { 2238 if (direction == GTK_TEXT_DIR_RTL) 2239 gap_roffset = 0; 2240 else 2241 gap_loffset = 0; 2242 } 2243 2244 if (flags & MOZ_GTK_TAB_BOTTOM) { 2245 /* Enlarge the cliprect to have room for the full gap height */ 2246 cliprect->height += gap_height - gap_voffset; 2247 cliprect->y -= gap_height - gap_voffset; 2248 2249 /* Draw the tab */ 2250 gtk_paint_extension(style, drawable, GTK_STATE_NORMAL, 2251 GTK_SHADOW_OUT, cliprect, gParts->tabWidget, "tab", 2252 rect->x, rect->y + gap_voffset, rect->width, 2253 rect->height - gap_voffset, GTK_POS_TOP); 2254 2255 /* Draw the gap; erase with background color before painting in 2256 * case theme does not */ 2257 gtk_style_apply_default_background(style, drawable, TRUE, 2258 GTK_STATE_NORMAL, cliprect, 2259 rect->x, 2260 rect->y + gap_voffset 2261 - gap_height, 2262 rect->width, gap_height); 2263 gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, 2264 cliprect, gParts->tabWidget, "notebook", 2265 rect->x - gap_loffset, 2266 rect->y + gap_voffset - 3 * gap_height, 2267 rect->width + gap_loffset + gap_roffset, 2268 3 * gap_height, GTK_POS_BOTTOM, 2269 gap_loffset, rect->width); 2270 } else { 2271 /* Enlarge the cliprect to have room for the full gap height */ 2272 cliprect->height += gap_height - gap_voffset; 2273 2274 /* Draw the tab */ 2275 gtk_paint_extension(style, drawable, GTK_STATE_NORMAL, 2276 GTK_SHADOW_OUT, cliprect, gParts->tabWidget, "tab", 2277 rect->x, rect->y, rect->width, 2278 rect->height - gap_voffset, GTK_POS_BOTTOM); 2279 2280 /* Draw the gap; erase with background color before painting in 2281 * case theme does not */ 2282 gtk_style_apply_default_background(style, drawable, TRUE, 2283 GTK_STATE_NORMAL, cliprect, 2284 rect->x, 2285 rect->y + rect->height 2286 - gap_voffset, 2287 rect->width, gap_height); 2288 gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, 2289 cliprect, gParts->tabWidget, "notebook", 2290 rect->x - gap_loffset, 2291 rect->y + rect->height - gap_voffset, 2292 rect->width + gap_loffset + gap_roffset, 2293 3 * gap_height, GTK_POS_TOP, 2294 gap_loffset, rect->width); 2295 } 2296 2297 } 2298 2299 return MOZ_GTK_SUCCESS; 2300 } 2301 2302 static gint 2303 moz_gtk_tabpanels_paint(GdkDrawable* drawable, GdkRectangle* rect, 2304 GdkRectangle* cliprect, GtkTextDirection direction) 2305 { 2306 /* We use gtk_paint_box_gap() to draw the tabpanels widget. gtk_paint_box() 2307 * draws an all-purpose box, which a lot of themes render differently. 2308 * A zero-width gap is still visible in most themes, so we hide it to the 2309 * left (10px should be enough) */ 2310 GtkStyle* style; 2311 2312 ensure_tab_widget(); 2313 gtk_widget_set_direction(gParts->tabWidget, direction); 2314 2315 style = gParts->tabWidget->style; 2316 2317 TSOffsetStyleGCs(style, rect->x, rect->y); 2318 gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, 2319 cliprect, gParts->tabWidget, "notebook", rect->x, rect->y, 2320 rect->width, rect->height, 2321 GTK_POS_TOP, -10, 0); 2322 2323 return MOZ_GTK_SUCCESS; 2324 } 2325 2326 static gint 2327 moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, 2328 GdkRectangle* cliprect, GtkWidgetState* state, 2329 GtkArrowType arrow_type, 2330 GtkTextDirection direction) 2331 { 2332 GtkStateType state_type = ConvertGtkState(state); 2333 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; 2334 GtkStyle* style; 2335 gint arrow_size = MIN(rect->width, rect->height); 2336 gint x = rect->x + (rect->width - arrow_size) / 2; 2337 gint y = rect->y + (rect->height - arrow_size) / 2; 2338 2339 ensure_tab_widget(); 2340 2341 style = gParts->tabWidget->style; 2342 TSOffsetStyleGCs(style, rect->x, rect->y); 2343 2344 if (direction == GTK_TEXT_DIR_RTL) { 2345 arrow_type = (arrow_type == GTK_ARROW_LEFT) ? 2346 GTK_ARROW_RIGHT : GTK_ARROW_LEFT; 2347 } 2348 2349 gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL, 2350 gParts->tabWidget, "notebook", arrow_type, TRUE, 2351 x, y, arrow_size, arrow_size); 2352 2353 return MOZ_GTK_SUCCESS; 2354 } 2355 2356 static gint 2357 moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect, 2358 GdkRectangle* cliprect, GtkTextDirection direction) 2359 { 2360 GtkStyle* style; 2361 GtkShadowType shadow_type; 2362 ensure_menu_bar_widget(); 2363 gtk_widget_set_direction(gParts->menuBarWidget, direction); 2364 2365 gtk_widget_style_get(gParts->menuBarWidget, "shadow-type", &shadow_type, NULL); 2366 2367 style = gParts->menuBarWidget->style; 2368 2369 TSOffsetStyleGCs(style, rect->x, rect->y); 2370 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, 2371 cliprect, rect->x, rect->y, 2372 rect->width, rect->height); 2373 2374 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, shadow_type, 2375 cliprect, gParts->menuBarWidget, "menubar", rect->x, rect->y, 2376 rect->width, rect->height); 2377 return MOZ_GTK_SUCCESS; 2378 } 2379 2380 static gint 2381 moz_gtk_menu_popup_paint(GdkDrawable* drawable, GdkRectangle* rect, 2382 GdkRectangle* cliprect, GtkTextDirection direction) 2383 { 2384 GtkStyle* style; 2385 ensure_menu_popup_widget(); 2386 gtk_widget_set_direction(gParts->menuPopupWidget, direction); 2387 2388 style = gParts->menuPopupWidget->style; 2389 2390 TSOffsetStyleGCs(style, rect->x, rect->y); 2391 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, 2392 cliprect, rect->x, rect->y, 2393 rect->width, rect->height); 2394 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, 2395 cliprect, gParts->menuPopupWidget, "menu", 2396 rect->x, rect->y, rect->width, rect->height); 2397 2398 return MOZ_GTK_SUCCESS; 2399 } 2400 2401 static gint 2402 moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, 2403 GdkRectangle* cliprect, GtkTextDirection direction) 2404 { 2405 GtkStyle* style; 2406 gboolean wide_separators; 2407 gint separator_height; 2408 guint horizontal_padding; 2409 gint paint_height; 2410 2411 ensure_menu_separator_widget(); 2412 gtk_widget_set_direction(gParts->menuSeparatorWidget, direction); 2413 2414 style = gParts->menuSeparatorWidget->style; 2415 2416 gtk_widget_style_get(gParts->menuSeparatorWidget, 2417 "wide-separators", &wide_separators, 2418 "separator-height", &separator_height, 2419 "horizontal-padding", &horizontal_padding, 2420 NULL); 2421 2422 TSOffsetStyleGCs(style, rect->x, rect->y); 2423 2424 if (wide_separators) { 2425 if (separator_height > rect->height) 2426 separator_height = rect->height; 2427 2428 gtk_paint_box(style, drawable, 2429 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, 2430 cliprect, gParts->menuSeparatorWidget, "hseparator", 2431 rect->x + horizontal_padding + style->xthickness, 2432 rect->y + (rect->height - separator_height - style->ythickness) / 2, 2433 rect->width - 2 * (horizontal_padding + style->xthickness), 2434 separator_height); 2435 } else { 2436 paint_height = style->ythickness; 2437 if (paint_height > rect->height) 2438 paint_height = rect->height; 2439 2440 gtk_paint_hline(style, drawable, 2441 GTK_STATE_NORMAL, cliprect, gParts->menuSeparatorWidget, 2442 "menuitem", 2443 rect->x + horizontal_padding + style->xthickness, 2444 rect->x + rect->width - horizontal_padding - style->xthickness - 1, 2445 rect->y + (rect->height - style->ythickness) / 2); 2446 } 2447 2448 return MOZ_GTK_SUCCESS; 2449 } 2450 2451 static gint 2452 moz_gtk_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect, 2453 GdkRectangle* cliprect, GtkWidgetState* state, 2454 gint flags, GtkTextDirection direction) 2455 { 2456 GtkStyle* style; 2457 GtkShadowType shadow_type; 2458 GtkWidget* item_widget; 2459 2460 if (state->inHover && !state->disabled) { 2461 if (flags & MOZ_TOPLEVEL_MENU_ITEM) { 2462 ensure_menu_bar_item_widget(); 2463 item_widget = gParts->menuBarItemWidget; 2464 } else { 2465 ensure_menu_item_widget(); 2466 item_widget = gParts->menuItemWidget; 2467 } 2468 gtk_widget_set_direction(item_widget, direction); 2469 2470 style = item_widget->style; 2471 TSOffsetStyleGCs(style, rect->x, rect->y); 2472 2473 gtk_widget_style_get(item_widget, "selected-shadow-type", 2474 &shadow_type, NULL); 2475 2476 gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, shadow_type, 2477 cliprect, item_widget, "menuitem", rect->x, rect->y, 2478 rect->width, rect->height); 2479 } 2480 2481 return MOZ_GTK_SUCCESS; 2482 } 2483 2484 static gint 2485 moz_gtk_menu_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, 2486 GdkRectangle* cliprect, GtkWidgetState* state, 2487 GtkTextDirection direction) 2488 { 2489 GtkStyle* style; 2490 GtkStateType state_type = ConvertGtkState(state); 2491 2492 ensure_menu_item_widget(); 2493 gtk_widget_set_direction(gParts->menuItemWidget, direction); 2494 2495 style = gParts->menuItemWidget->style; 2496 2497 TSOffsetStyleGCs(style, rect->x, rect->y); 2498 gtk_paint_arrow(style, drawable, state_type, 2499 (state_type == GTK_STATE_PRELIGHT) ? GTK_SHADOW_IN : GTK_SHADOW_OUT, 2500 cliprect, gParts->menuItemWidget, "menuitem", 2501 (direction == GTK_TEXT_DIR_LTR) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT, 2502 TRUE, rect->x, rect->y, rect->width, rect->height); 2503 2504 return MOZ_GTK_SUCCESS; 2505 } 2506 2507 static gint 2508 moz_gtk_check_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect, 2509 GdkRectangle* cliprect, GtkWidgetState* state, 2510 gboolean checked, gboolean isradio, 2511 GtkTextDirection direction) 2512 { 2513 GtkStateType state_type = ConvertGtkState(state); 2514 GtkStyle* style; 2515 GtkShadowType shadow_type = (checked)?GTK_SHADOW_IN:GTK_SHADOW_OUT; 2516 gint offset; 2517 gint indicator_size; 2518 gint x, y; 2519 2520 moz_gtk_menu_item_paint(drawable, rect, cliprect, state, FALSE, direction); 2521 2522 ensure_check_menu_item_widget(); 2523 gtk_widget_set_direction(gParts->checkMenuItemWidget, direction); 2524 2525 gtk_widget_style_get (gParts->checkMenuItemWidget, 2526 "indicator-size", &indicator_size, 2527 NULL); 2528 2529 if (checked || GTK_CHECK_MENU_ITEM(gParts->checkMenuItemWidget)->always_show_toggle) { 2530 style = gParts->checkMenuItemWidget->style; 2531 2532 offset = GTK_CONTAINER(gParts->checkMenuItemWidget)->border_width + 2533 gParts->checkMenuItemWidget->style->xthickness + 2; 2534 2535 /* while normally this "3" would be the horizontal-padding style value, passing it to Gecko 2536 as the value of menuitem padding causes problems with dropdowns (bug 406129), so in the menu.css 2537 file this is hardcoded as 3px. Yes it sucks, but we don't really have a choice. */ 2538 x = (direction == GTK_TEXT_DIR_RTL) ? 2539 rect->width - indicator_size - offset - 3: rect->x + offset + 3; 2540 y = rect->y + (rect->height - indicator_size) / 2; 2541 2542 TSOffsetStyleGCs(style, x, y); 2543 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gParts->checkMenuItemWidget), 2544 checked); 2545 2546 if (isradio) { 2547 gtk_paint_option(style, drawable, state_type, shadow_type, cliprect, 2548 gParts->checkMenuItemWidget, "option", 2549 x, y, indicator_size, indicator_size); 2550 } else { 2551 gtk_paint_check(style, drawable, state_type, shadow_type, cliprect, 2552 gParts->checkMenuItemWidget, "check", 2553 x, y, indicator_size, indicator_size); 2554 } 2555 } 2556 2557 return MOZ_GTK_SUCCESS; 2558 } 2559 2560 static gint 2561 moz_gtk_window_paint(GdkDrawable* drawable, GdkRectangle* rect, 2562 GdkRectangle* cliprect, GtkTextDirection direction) 2563 { 2564 GtkStyle* style; 2565 2566 ensure_window_widget(); 2567 gtk_widget_set_direction(gParts->protoWindow, direction); 2568 2569 style = gParts->protoWindow->style; 2570 2571 TSOffsetStyleGCs(style, rect->x, rect->y); 2572 gtk_style_apply_default_background(style, drawable, TRUE, 2573 GTK_STATE_NORMAL, 2574 cliprect, rect->x, rect->y, 2575 rect->width, rect->height); 2576 return MOZ_GTK_SUCCESS; 2577 } 2578 2579 gint 2580 moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, 2581 gint* right, gint* bottom, GtkTextDirection direction, 2582 gboolean inhtml) 2583 { 2584 GtkWidget* w; 2585 2586 switch (widget) { 2587 case MOZ_GTK_BUTTON: 2588 { 2589 GtkBorder inner_border; 2590 gboolean interior_focus; 2591 gint focus_width, focus_pad; 2592 2593 ensure_button_widget(); 2594 *left = *top = *right = *bottom = GTK_CONTAINER(gParts->buttonWidget)->border_width; 2595 2596 /* Don't add this padding in HTML, otherwise the buttons will 2597 become too big and stuff the layout. */ 2598 if (!inhtml) { 2599 moz_gtk_widget_get_focus(gParts->buttonWidget, &interior_focus, &focus_width, &focus_pad); 2600 moz_gtk_button_get_inner_border(gParts->buttonWidget, &inner_border); 2601 *left += focus_width + focus_pad + inner_border.left; 2602 *right += focus_width + focus_pad + inner_border.right; 2603 *top += focus_width + focus_pad + inner_border.top; 2604 *bottom += focus_width + focus_pad + inner_border.bottom; 2605 } 2606 2607 *left += gParts->buttonWidget->style->xthickness; 2608 *right += gParts->buttonWidget->style->xthickness; 2609 *top += gParts->buttonWidget->style->ythickness; 2610 *bottom += gParts->buttonWidget->style->ythickness; 2611 return MOZ_GTK_SUCCESS; 2612 } 2613 case MOZ_GTK_ENTRY: 2614 ensure_entry_widget(); 2615 w = gParts->entryWidget; 2616 break; 2617 case MOZ_GTK_TREEVIEW: 2618 ensure_tree_view_widget(); 2619 w = gParts->treeViewWidget; 2620 break; 2621 case MOZ_GTK_TREE_HEADER_CELL: 2622 { 2623 /* A Tree Header in GTK is just a different styled button 2624 * It must be placed in a TreeView for getting the correct style 2625 * assigned. 2626 * That is why the following code is the same as for MOZ_GTK_BUTTON. 2627 * */ 2628 2629 GtkBorder inner_border; 2630 gboolean interior_focus; 2631 gint focus_width, focus_pad; 2632 2633 ensure_tree_header_cell_widget(); 2634 *left = *top = *right = *bottom = GTK_CONTAINER(gParts->treeHeaderCellWidget)->border_width; 2635 2636 moz_gtk_widget_get_focus(gParts->treeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad); 2637 moz_gtk_button_get_inner_border(gParts->treeHeaderCellWidget, &inner_border); 2638 *left += focus_width + focus_pad + inner_border.left; 2639 *right += focus_width + focus_pad + inner_border.right; 2640 *top += focus_width + focus_pad + inner_border.top; 2641 *bottom += focus_width + focus_pad + inner_border.bottom; 2642 2643 *left += gParts->treeHeaderCellWidget->style->xthickness; 2644 *right += gParts->treeHeaderCellWidget->style->xthickness; 2645 *top += gParts->treeHeaderCellWidget->style->ythickness; 2646 *bottom += gParts->treeHeaderCellWidget->style->ythickness; 2647 return MOZ_GTK_SUCCESS; 2648 } 2649 case MOZ_GTK_TREE_HEADER_SORTARROW: 2650 ensure_tree_header_cell_widget(); 2651 w = gParts->treeHeaderSortArrowWidget; 2652 break; 2653 case MOZ_GTK_DROPDOWN_ENTRY: 2654 ensure_combo_box_entry_widgets(); 2655 w = gParts->comboBoxEntryTextareaWidget; 2656 break; 2657 case MOZ_GTK_DROPDOWN_ARROW: 2658 ensure_combo_box_entry_widgets(); 2659 w = gParts->comboBoxEntryButtonWidget; 2660 break; 2661 case MOZ_GTK_DROPDOWN: 2662 { 2663 /* We need to account for the arrow on the dropdown, so text 2664 * doesn't come too close to the arrow, or in some cases spill 2665 * into the arrow. */ 2666 gboolean ignored_interior_focus, wide_separators; 2667 gint focus_width, focus_pad, separator_width; 2668 GtkRequisition arrow_req; 2669 2670 ensure_combo_box_widgets(); 2671 2672 *left = GTK_CONTAINER(gParts->comboBoxButtonWidget)->border_width; 2673 2674 if (!inhtml) { 2675 moz_gtk_widget_get_focus(gParts->comboBoxButtonWidget, 2676 &ignored_interior_focus, 2677 &focus_width, &focus_pad); 2678 *left += focus_width + focus_pad; 2679 } 2680 2681 *top = *left + gParts->comboBoxButtonWidget->style->ythickness; 2682 *left += gParts->comboBoxButtonWidget->style->xthickness; 2683 2684 *right = *left; *bottom = *top; 2685 2686 /* If there is no separator, don't try to count its width. */ 2687 separator_width = 0; 2688 if (gParts->comboBoxSeparatorWidget) { 2689 gtk_widget_style_get(gParts->comboBoxSeparatorWidget, 2690 "wide-separators", &wide_separators, 2691 "separator-width", &separator_width, 2692 NULL); 2693 2694 if (!wide_separators) 2695 separator_width = 2696 XTHICKNESS(gParts->comboBoxSeparatorWidget->style); 2697 } 2698 2699 gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req); 2700 2701 if (direction == GTK_TEXT_DIR_RTL) 2702 *left += separator_width + arrow_req.width; 2703 else 2704 *right += separator_width + arrow_req.width; 2705 2706 return MOZ_GTK_SUCCESS; 2707 } 2708 case MOZ_GTK_TABPANELS: 2709 ensure_tab_widget(); 2710 w = gParts->tabWidget; 2711 break; 2712 case MOZ_GTK_PROGRESSBAR: 2713 ensure_progress_widget(); 2714 w = gParts->progresWidget; 2715 break; 2716 case MOZ_GTK_SPINBUTTON_ENTRY: 2717 case MOZ_GTK_SPINBUTTON_UP: 2718 case MOZ_GTK_SPINBUTTON_DOWN: 2719 ensure_spin_widget(); 2720 w = gParts->spinWidget; 2721 break; 2722 case MOZ_GTK_SCALE_HORIZONTAL: 2723 ensure_scale_widget(); 2724 w = gParts->hScaleWidget; 2725 break; 2726 case MOZ_GTK_SCALE_VERTICAL: 2727 ensure_scale_widget(); 2728 w = gParts->vScaleWidget; 2729 break; 2730 case MOZ_GTK_FRAME: 2731 ensure_frame_widget(); 2732 w = gParts->frameWidget; 2733 break; 2734 case MOZ_GTK_CHECKBUTTON_LABEL: 2735 case MOZ_GTK_RADIOBUTTON_LABEL: 2736 { 2737 gboolean interior_focus; 2738 gint focus_width, focus_pad; 2739 2740 /* If the focus is interior, then the label has a border of 2741 (focus_width + focus_pad). */ 2742 if (widget == MOZ_GTK_CHECKBUTTON_LABEL) { 2743 ensure_checkbox_widget(); 2744 moz_gtk_widget_get_focus(gParts->checkboxWidget, &interior_focus, 2745 &focus_width, &focus_pad); 2746 } 2747 else { 2748 ensure_radiobutton_widget(); 2749 moz_gtk_widget_get_focus(gParts->radiobuttonWidget, &interior_focus, 2750 &focus_width, &focus_pad); 2751 } 2752 2753 if (interior_focus) 2754 *left = *top = *right = *bottom = (focus_width + focus_pad); 2755 else 2756 *left = *top = *right = *bottom = 0; 2757 2758 return MOZ_GTK_SUCCESS; 2759 } 2760 2761 case MOZ_GTK_CHECKBUTTON_CONTAINER: 2762 case MOZ_GTK_RADIOBUTTON_CONTAINER: 2763 { 2764 gboolean interior_focus; 2765 gint focus_width, focus_pad; 2766 2767 /* If the focus is _not_ interior, then the container has a border 2768 of (focus_width + focus_pad). */ 2769 if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) { 2770 ensure_checkbox_widget(); 2771 moz_gtk_widget_get_focus(gParts->checkboxWidget, &interior_focus, 2772 &focus_width, &focus_pad); 2773 w = gParts->checkboxWidget; 2774 } else { 2775 ensure_radiobutton_widget(); 2776 moz_gtk_widget_get_focus(gParts->radiobuttonWidget, &interior_focus, 2777 &focus_width, &focus_pad); 2778 w = gParts->radiobuttonWidget; 2779 } 2780 2781 *left = *top = *right = *bottom = GTK_CONTAINER(w)->border_width; 2782 2783 if (!interior_focus) { 2784 *left += (focus_width + focus_pad); 2785 *right += (focus_width + focus_pad); 2786 *top += (focus_width + focus_pad); 2787 *bottom += (focus_width + focus_pad); 2788 } 2789 2790 return MOZ_GTK_SUCCESS; 2791 } 2792 case MOZ_GTK_MENUPOPUP: 2793 ensure_menu_popup_widget(); 2794 w = gParts->menuPopupWidget; 2795 break; 2796 case MOZ_GTK_MENUITEM: 2797 ensure_menu_item_widget(); 2798 ensure_menu_bar_item_widget(); 2799 w = gParts->menuItemWidget; 2800 break; 2801 case MOZ_GTK_CHECKMENUITEM: 2802 case MOZ_GTK_RADIOMENUITEM: 2803 ensure_check_menu_item_widget(); 2804 w = gParts->checkMenuItemWidget; 2805 break; 2806 case MOZ_GTK_TAB: 2807 ensure_tab_widget(); 2808 w = gParts->tabWidget; 2809 break; 2810 /* These widgets have no borders, since they are not containers. */ 2811 case MOZ_GTK_SPLITTER_HORIZONTAL: 2812 case MOZ_GTK_SPLITTER_VERTICAL: 2813 case MOZ_GTK_CHECKBUTTON: 2814 case MOZ_GTK_RADIOBUTTON: 2815 case MOZ_GTK_SCROLLBAR_BUTTON: 2816 case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: 2817 case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: 2818 case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: 2819 case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: 2820 case MOZ_GTK_SCALE_THUMB_HORIZONTAL: 2821 case MOZ_GTK_SCALE_THUMB_VERTICAL: 2822 case MOZ_GTK_GRIPPER: 2823 case MOZ_GTK_PROGRESS_CHUNK: 2824 case MOZ_GTK_EXPANDER: 2825 case MOZ_GTK_TREEVIEW_EXPANDER: 2826 case MOZ_GTK_TOOLBAR_SEPARATOR: 2827 case MOZ_GTK_MENUSEPARATOR: 2828 /* These widgets have no borders.*/ 2829 case MOZ_GTK_SPINBUTTON: 2830 case MOZ_GTK_TOOLTIP: 2831 case MOZ_GTK_WINDOW: 2832 case MOZ_GTK_RESIZER: 2833 case MOZ_GTK_MENUARROW: 2834 case MOZ_GTK_TOOLBARBUTTON_ARROW: 2835 case MOZ_GTK_TOOLBAR: 2836 case MOZ_GTK_MENUBAR: 2837 case MOZ_GTK_TAB_SCROLLARROW: 2838 case MOZ_GTK_ENTRY_CARET: 2839 *left = *top = *right = *bottom = 0; 2840 return MOZ_GTK_SUCCESS; 2841 default: 2842 g_warning("Unsupported widget type: %d", widget); 2843 return MOZ_GTK_UNKNOWN_WIDGET; 2844 } 2845 2846 *right = *left = XTHICKNESS(w->style); 2847 *bottom = *top = YTHICKNESS(w->style); 2848 2849 return MOZ_GTK_SUCCESS; 2850 } 2851 2852 gint 2853 moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height) 2854 { 2855 /* 2856 * We get the requisition of the drop down button, which includes 2857 * all padding, border and focus line widths the button uses, 2858 * as well as the minimum arrow size and its padding 2859 * */ 2860 GtkRequisition requisition; 2861 ensure_combo_box_entry_widgets(); 2862 2863 gtk_widget_size_request(gParts->comboBoxEntryButtonWidget, &requisition); 2864 *width = requisition.width; 2865 *height = requisition.height; 2866 2867 return MOZ_GTK_SUCCESS; 2868 } 2869 2870 gint 2871 moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height) 2872 { 2873 gint arrow_size; 2874 2875 ensure_tab_widget(); 2876 gtk_widget_style_get(gParts->tabWidget, 2877 "scroll-arrow-hlength", &arrow_size, 2878 NULL); 2879 2880 *height = *width = arrow_size; 2881 2882 return MOZ_GTK_SUCCESS; 2883 } 2884 2885 gint 2886 moz_gtk_get_downarrow_size(gint* width, gint* height) 2887 { 2888 GtkRequisition requisition; 2889 ensure_button_arrow_widget(); 2890 2891 gtk_widget_size_request(gParts->buttonArrowWidget, &requisition); 2892 *width = requisition.width; 2893 *height = requisition.height; 2894 2895 return MOZ_GTK_SUCCESS; 2896 } 2897 2898 gint 2899 moz_gtk_get_toolbar_separator_width(gint* size) 2900 { 2901 gboolean wide_separators; 2902 gint separator_width; 2903 GtkStyle* style; 2904 2905 ensure_toolbar_widget(); 2906 2907 style = gParts->toolbarWidget->style; 2908 2909 gtk_widget_style_get(gParts->toolbarWidget, 2910 "space-size", size, 2911 "wide-separators", &wide_separators, 2912 "separator-width", &separator_width, 2913 NULL); 2914 2915 /* Just in case... */ 2916 *size = MAX(*size, (wide_separators ? separator_width : style->xthickness)); 2917 2918 return MOZ_GTK_SUCCESS; 2919 } 2920 2921 gint 2922 moz_gtk_get_expander_size(gint* size) 2923 { 2924 ensure_expander_widget(); 2925 gtk_widget_style_get(gParts->expanderWidget, 2926 "expander-size", size, 2927 NULL); 2928 2929 return MOZ_GTK_SUCCESS; 2930 } 2931 2932 gint 2933 moz_gtk_get_treeview_expander_size(gint* size) 2934 { 2935 ensure_tree_view_widget(); 2936 gtk_widget_style_get(gParts->treeViewWidget, 2937 "expander-size", size, 2938 NULL); 2939 2940 return MOZ_GTK_SUCCESS; 2941 } 2942 2943 gint 2944 moz_gtk_get_menu_separator_height(gint *size) 2945 { 2946 gboolean wide_separators; 2947 gint separator_height; 2948 2949 ensure_menu_separator_widget(); 2950 2951 gtk_widget_style_get(gParts->menuSeparatorWidget, 2952 "wide-separators", &wide_separators, 2953 "separator-height", &separator_height, 2954 NULL); 2955 2956 if (wide_separators) 2957 *size = separator_height + gParts->menuSeparatorWidget->style->ythickness; 2958 else 2959 *size = gParts->menuSeparatorWidget->style->ythickness * 2; 2960 2961 return MOZ_GTK_SUCCESS; 2962 } 2963 2964 gint 2965 moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height) 2966 { 2967 GtkWidget* widget; 2968 2969 ensure_scale_widget(); 2970 widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget); 2971 2972 gtk_widget_style_get (widget, 2973 "slider_length", thumb_length, 2974 "slider_width", thumb_height, 2975 NULL); 2976 2977 return MOZ_GTK_SUCCESS; 2978 } 2979 2980 gint 2981 moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) 2982 { 2983 ensure_scrollbar_widget(); 2984 2985 gtk_widget_style_get (gParts->horizScrollbarWidget, 2986 "slider_width", &metrics->slider_width, 2987 "trough_border", &metrics->trough_border, 2988 "stepper_size", &metrics->stepper_size, 2989 "stepper_spacing", &metrics->stepper_spacing, 2990 NULL); 2991 2992 metrics->min_slider_size = 2993 GTK_RANGE(gParts->horizScrollbarWidget)->min_slider_size; 2994 2995 return MOZ_GTK_SUCCESS; 2996 } 2997 2998 gboolean 2999 moz_gtk_images_in_menus() 3000 { 3001 gboolean result; 3002 GtkSettings* settings; 3003 3004 ensure_image_menu_item_widget(); 3005 settings = gtk_widget_get_settings(gParts->imageMenuItemWidget); 3006 3007 g_object_get(settings, "gtk-menu-images", &result, NULL); 3008 return result; 3009 } 3010 3011 gint 3012 moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, 3013 GdkRectangle* rect, GdkRectangle* cliprect, 3014 GtkWidgetState* state, gint flags, 3015 GtkTextDirection direction) 3016 { 3017 switch (widget) { 3018 case MOZ_GTK_BUTTON: 3019 if (state->depressed) { 3020 ensure_toggle_button_widget(); 3021 return moz_gtk_button_paint(drawable, rect, cliprect, state, 3022 (GtkReliefStyle) flags, 3023 gParts->toggleButtonWidget, direction); 3024 } 3025 ensure_button_widget(); 3026 return moz_gtk_button_paint(drawable, rect, cliprect, state, 3027 (GtkReliefStyle) flags, gParts->buttonWidget, 3028 direction); 3029 break; 3030 case MOZ_GTK_CHECKBUTTON: 3031 case MOZ_GTK_RADIOBUTTON: 3032 return moz_gtk_toggle_paint(drawable, rect, cliprect, state, 3033 !!(flags & MOZ_GTK_WIDGET_CHECKED), 3034 !!(flags & MOZ_GTK_WIDGET_INCONSISTENT), 3035 (widget == MOZ_GTK_RADIOBUTTON), 3036 direction); 3037 break; 3038 case MOZ_GTK_SCROLLBAR_BUTTON: 3039 return moz_gtk_scrollbar_button_paint(drawable, rect, cliprect, state, 3040 (GtkScrollbarButtonFlags) flags, 3041 direction); 3042 break; 3043 case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: 3044 case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: 3045 return moz_gtk_scrollbar_trough_paint(widget, drawable, rect, 3046 cliprect, state, direction); 3047 break; 3048 case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: 3049 case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: 3050 return moz_gtk_scrollbar_thumb_paint(widget, drawable, rect, 3051 cliprect, state, direction); 3052 break; 3053 case MOZ_GTK_SCALE_HORIZONTAL: 3054 case MOZ_GTK_SCALE_VERTICAL: 3055 return moz_gtk_scale_paint(drawable, rect, cliprect, state, 3056 (GtkOrientation) flags, direction); 3057 break; 3058 case MOZ_GTK_SCALE_THUMB_HORIZONTAL: 3059 case MOZ_GTK_SCALE_THUMB_VERTICAL: 3060 return moz_gtk_scale_thumb_paint(drawable, rect, cliprect, state, 3061 (GtkOrientation) flags, direction); 3062 break; 3063 case MOZ_GTK_SPINBUTTON: 3064 return moz_gtk_spin_paint(drawable, rect, direction); 3065 break; 3066 case MOZ_GTK_SPINBUTTON_UP: 3067 case MOZ_GTK_SPINBUTTON_DOWN: 3068 return moz_gtk_spin_updown_paint(drawable, rect, 3069 (widget == MOZ_GTK_SPINBUTTON_DOWN), 3070 state, direction); 3071 break; 3072 case MOZ_GTK_SPINBUTTON_ENTRY: 3073 ensure_spin_widget(); 3074 return moz_gtk_entry_paint(drawable, rect, cliprect, state, 3075 gParts->spinWidget, direction); 3076 break; 3077 case MOZ_GTK_GRIPPER: 3078 return moz_gtk_gripper_paint(drawable, rect, cliprect, state, 3079 direction); 3080 break; 3081 case MOZ_GTK_TREEVIEW: 3082 return moz_gtk_treeview_paint(drawable, rect, cliprect, state, 3083 direction); 3084 break; 3085 case MOZ_GTK_TREE_HEADER_CELL: 3086 return moz_gtk_tree_header_cell_paint(drawable, rect, cliprect, state, 3087 flags, direction); 3088 break; 3089 case MOZ_GTK_TREE_HEADER_SORTARROW: 3090 return moz_gtk_tree_header_sort_arrow_paint(drawable, rect, cliprect, 3091 state, 3092 (GtkArrowType) flags, 3093 direction); 3094 break; 3095 case MOZ_GTK_TREEVIEW_EXPANDER: 3096 return moz_gtk_treeview_expander_paint(drawable, rect, cliprect, state, 3097 (GtkExpanderStyle) flags, direction); 3098 break; 3099 case MOZ_GTK_EXPANDER: 3100 return moz_gtk_expander_paint(drawable, rect, cliprect, state, 3101 (GtkExpanderStyle) flags, direction); 3102 break; 3103 case MOZ_GTK_ENTRY: 3104 ensure_entry_widget(); 3105 return moz_gtk_entry_paint(drawable, rect, cliprect, state, 3106 gParts->entryWidget, direction); 3107 break; 3108 case MOZ_GTK_ENTRY_CARET: 3109 return moz_gtk_caret_paint(drawable, rect, cliprect, direction); 3110 break; 3111 case MOZ_GTK_DROPDOWN: 3112 return moz_gtk_combo_box_paint(drawable, rect, cliprect, state, 3113 (gboolean) flags, direction); 3114 break; 3115 case MOZ_GTK_DROPDOWN_ARROW: 3116 return moz_gtk_combo_box_entry_button_paint(drawable, rect, cliprect, 3117 state, flags, direction); 3118 break; 3119 case MOZ_GTK_DROPDOWN_ENTRY: 3120 ensure_combo_box_entry_widgets(); 3121 return moz_gtk_entry_paint(drawable, rect, cliprect, state, 3122 gParts->comboBoxEntryTextareaWidget, direction); 3123 break; 3124 case MOZ_GTK_CHECKBUTTON_CONTAINER: 3125 case MOZ_GTK_RADIOBUTTON_CONTAINER: 3126 return moz_gtk_container_paint(drawable, rect, cliprect, state, 3127 (widget == MOZ_GTK_RADIOBUTTON_CONTAINER), 3128 direction); 3129 break; 3130 case MOZ_GTK_CHECKBUTTON_LABEL: 3131 case MOZ_GTK_RADIOBUTTON_LABEL: 3132 return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state, 3133 (widget == MOZ_GTK_RADIOBUTTON_LABEL), 3134 direction); 3135 break; 3136 case MOZ_GTK_TOOLBAR: 3137 return moz_gtk_toolbar_paint(drawable, rect, cliprect, direction); 3138 break; 3139 case MOZ_GTK_TOOLBAR_SEPARATOR: 3140 return moz_gtk_toolbar_separator_paint(drawable, rect, cliprect, 3141 direction); 3142 break; 3143 case MOZ_GTK_TOOLTIP: 3144 return moz_gtk_tooltip_paint(drawable, rect, cliprect, direction); 3145 break; 3146 case MOZ_GTK_FRAME: 3147 return moz_gtk_frame_paint(drawable, rect, cliprect, direction); 3148 break; 3149 case MOZ_GTK_RESIZER: 3150 return moz_gtk_resizer_paint(drawable, rect, cliprect, state, 3151 direction); 3152 break; 3153 case MOZ_GTK_PROGRESSBAR: 3154 return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction); 3155 break; 3156 case MOZ_GTK_PROGRESS_CHUNK: 3157 return moz_gtk_progress_chunk_paint(drawable, rect, cliprect, 3158 direction); 3159 break; 3160 case MOZ_GTK_TAB: 3161 return moz_gtk_tab_paint(drawable, rect, cliprect, 3162 (GtkTabFlags) flags, direction); 3163 break; 3164 case MOZ_GTK_TABPANELS: 3165 return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction); 3166 break; 3167 case MOZ_GTK_TAB_SCROLLARROW: 3168 return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state, 3169 (GtkArrowType) flags, direction); 3170 break; 3171 case MOZ_GTK_MENUBAR: 3172 return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction); 3173 break; 3174 case MOZ_GTK_MENUPOPUP: 3175 return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction); 3176 break; 3177 case MOZ_GTK_MENUSEPARATOR: 3178 return moz_gtk_menu_separator_paint(drawable, rect, cliprect, 3179 direction); 3180 break; 3181 case MOZ_GTK_MENUITEM: 3182 return moz_gtk_menu_item_paint(drawable, rect, cliprect, state, flags, 3183 direction); 3184 break; 3185 case MOZ_GTK_MENUARROW: 3186 return moz_gtk_menu_arrow_paint(drawable, rect, cliprect, state, 3187 direction); 3188 break; 3189 case MOZ_GTK_TOOLBARBUTTON_ARROW: 3190 return moz_gtk_downarrow_paint(drawable, rect, cliprect, state); 3191 break; 3192 case MOZ_GTK_CHECKMENUITEM: 3193 case MOZ_GTK_RADIOMENUITEM: 3194 return moz_gtk_check_menu_item_paint(drawable, rect, cliprect, state, 3195 (gboolean) flags, 3196 (widget == MOZ_GTK_RADIOMENUITEM), 3197 direction); 3198 break; 3199 case MOZ_GTK_SPLITTER_HORIZONTAL: 3200 return moz_gtk_vpaned_paint(drawable, rect, cliprect, state); 3201 break; 3202 case MOZ_GTK_SPLITTER_VERTICAL: 3203 return moz_gtk_hpaned_paint(drawable, rect, cliprect, state); 3204 break; 3205 case MOZ_GTK_WINDOW: 3206 return moz_gtk_window_paint(drawable, rect, cliprect, direction); 3207 break; 3208 default: 3209 g_warning("Unknown widget type: %d", widget); 3210 } 3211 3212 return MOZ_GTK_UNKNOWN_WIDGET; 3213 } 3214 3215 GtkWidget* moz_gtk_get_scrollbar_widget(void) 3216 { 3217 if (!is_initialized) 3218 return NULL; 3219 ensure_scrollbar_widget(); 3220 return gParts->horizScrollbarWidget; 3221 } 3222 3223 gint 3224 moz_gtk_shutdown() 3225 { 3226 GtkWidgetClass *entry_class; 3227 entry_class = g_type_class_peek(GTK_TYPE_ENTRY); 3228 g_type_class_unref(entry_class); 3229 3230 is_initialized = FALSE; 3231 3232 return MOZ_GTK_SUCCESS; 3233 } 3234 3235 void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts) 3236 { 3237 if (!parts) 3238 return; 3239 3240 if (parts->tooltipWidget) { 3241 gtk_widget_destroy(parts->tooltipWidget); 3242 parts->tooltipWidget = NULL; 3243 } 3244 3245 if (parts->protoWindow) { 3246 gtk_widget_destroy(parts->protoWindow); 3247 parts->protoWindow = NULL; 3248 } 3249 } 3250