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