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