gtkpathbar.c 55.8 KB
Newer Older
1
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2
/* gtkpathbar.c
3 4 5 6 7 8 9 10 11 12 13 14 15
 * Copyright (C) 2004  Red Hat, Inc.,  Jonathan Blandford <jrb@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
16
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 18
 */

19
#include "config.h"
20

21
#include "gtkpathbar.h"
22 23 24

#include <string.h>

25
#include "gtkarrow.h"
26
#include "gtkbox.h"
27
#include "gtkdnd.h"
28
#include "gtkicontheme.h"
29 30
#include "gtkimage.h"
#include "gtkintl.h"
31
#include "gtklabel.h"
32 33
#include "gtkmain.h"
#include "gtkmarshalers.h"
34 35
#include "gtksettings.h"
#include "gtktogglebutton.h"
36
#include "gtkwidgetpath.h"
37
#include "gtkwidgetprivate.h"
38

39 40 41 42 43 44 45 46 47
struct _GtkPathBarPrivate
{
  GtkFileSystem *file_system;
  GFile *root_file;
  GFile *home_file;
  GFile *desktop_file;

  GCancellable *get_info_cancellable;

48 49 50
  cairo_surface_t *root_icon;
  cairo_surface_t *home_icon;
  cairo_surface_t *desktop_icon;
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

  GdkWindow *event_window;

  GList *button_list;
  GList *first_scrolled_button;
  GList *fake_root;
  GtkWidget *up_slider_button;
  GtkWidget *down_slider_button;
  guint settings_signal_id;
  gint icon_size;
  gint16 slider_width;
  gint16 button_offset;
  guint timer;
  guint slider_visible : 1;
  guint need_timer     : 1;
  guint ignore_click   : 1;
  guint scrolling_up   : 1;
  guint scrolling_down : 1;
};
70 71 72 73 74 75

enum {
  PATH_CLICKED,
  LAST_SIGNAL
};

76 77 78 79
typedef enum {
  NORMAL_BUTTON,
  ROOT_BUTTON,
  HOME_BUTTON,
80
  DESKTOP_BUTTON
81 82
} ButtonType;

83 84
#define BUTTON_DATA(x) ((ButtonData *)(x))

85
#define SCROLL_DELAY_FACTOR 5
86 87
#define TIMEOUT_INITIAL     500
#define TIMEOUT_REPEAT      50
88

89 90
static guint path_bar_signals [LAST_SIGNAL] = { 0 };

91
/* Icon size for if we can't get it from the theme */
92
#define FALLBACK_ICON_SIZE 16
93

94 95 96 97 98 99 100
typedef struct _ButtonData ButtonData;

struct _ButtonData
{
  GtkWidget *button;
  ButtonType type;
  char *dir_name;
101
  GFile *file;
102 103
  GtkWidget *image;
  GtkWidget *label;
104
  GCancellable *cancellable;
105 106
  guint ignore_changes : 1;
  guint file_is_hidden : 1;
107
};
108 109 110 111 112
/* This macro is used to check if a button can be used as a fake root.
 * All buttons in front of a fake root are automatically hidden when in a
 * directory below a fake root and replaced with the "<" arrow button.
 */
#define BUTTON_IS_FAKE_ROOT(button) ((button)->type == HOME_BUTTON)
113

114
G_DEFINE_TYPE_WITH_PRIVATE (GtkPathBar, gtk_path_bar, GTK_TYPE_CONTAINER)
115

116 117
static void gtk_path_bar_finalize                 (GObject          *object);
static void gtk_path_bar_dispose                  (GObject          *object);
118 119
static void gtk_path_bar_realize                  (GtkWidget        *widget);
static void gtk_path_bar_unrealize                (GtkWidget        *widget);
120 121 122 123 124 125
static void gtk_path_bar_get_preferred_width      (GtkWidget        *widget,
                                                   gint             *minimum,
                                                   gint             *natural);
static void gtk_path_bar_get_preferred_height     (GtkWidget        *widget,
                                                   gint             *minimum,
                                                   gint             *natural);
126 127
static void gtk_path_bar_map                      (GtkWidget        *widget);
static void gtk_path_bar_unmap                    (GtkWidget        *widget);
128 129 130 131 132 133 134 135 136 137
static void gtk_path_bar_size_allocate            (GtkWidget        *widget,
						   GtkAllocation    *allocation);
static void gtk_path_bar_add                      (GtkContainer     *container,
						   GtkWidget        *widget);
static void gtk_path_bar_remove                   (GtkContainer     *container,
						   GtkWidget        *widget);
static void gtk_path_bar_forall                   (GtkContainer     *container,
						   gboolean          include_internals,
						   GtkCallback       callback,
						   gpointer          callback_data);
138 139
static GtkWidgetPath *gtk_path_bar_get_path_for_child (GtkContainer *container,
                                                       GtkWidget    *child);
140 141 142 143
static gboolean gtk_path_bar_scroll               (GtkWidget        *widget,
						   GdkEventScroll   *event);
static void gtk_path_bar_scroll_up                (GtkPathBar       *path_bar);
static void gtk_path_bar_scroll_down              (GtkPathBar       *path_bar);
144
static void gtk_path_bar_stop_scrolling           (GtkPathBar       *path_bar);
145 146 147 148 149 150
static gboolean gtk_path_bar_slider_up_defocus    (GtkWidget        *widget,
						   GdkEventButton   *event,
						   GtkPathBar       *path_bar);
static gboolean gtk_path_bar_slider_down_defocus  (GtkWidget        *widget,
						   GdkEventButton   *event,
						   GtkPathBar       *path_bar);
151 152 153 154 155 156 157 158 159 160
static gboolean gtk_path_bar_slider_button_press  (GtkWidget        *widget,
						   GdkEventButton   *event,
						   GtkPathBar       *path_bar);
static gboolean gtk_path_bar_slider_button_release(GtkWidget        *widget,
						   GdkEventButton   *event,
						   GtkPathBar       *path_bar);
static void gtk_path_bar_grab_notify              (GtkWidget        *widget,
						   gboolean          was_grabbed);
static void gtk_path_bar_state_changed            (GtkWidget        *widget,
						   GtkStateType      previous_state);
161
static void gtk_path_bar_style_updated            (GtkWidget        *widget);
162 163 164 165 166 167
static void gtk_path_bar_screen_changed           (GtkWidget        *widget,
						   GdkScreen        *previous_screen);
static void gtk_path_bar_check_icon_theme         (GtkPathBar       *path_bar);
static void gtk_path_bar_update_button_appearance (GtkPathBar       *path_bar,
						   ButtonData       *button_data,
						   gboolean          current_dir);
168

169 170 171 172
static void
on_slider_unmap (GtkWidget  *widget,
		 GtkPathBar *path_bar)
{
173 174 175
  if (path_bar->priv->timer &&
      ((widget == path_bar->priv->up_slider_button && path_bar->priv->scrolling_up) ||
       (widget == path_bar->priv->down_slider_button && path_bar->priv->scrolling_down)))
176
    gtk_path_bar_stop_scrolling (path_bar);
177 178
}

179 180
static void
gtk_path_bar_init (GtkPathBar *path_bar)
181
{
182 183
  GtkStyleContext *context;

184
  path_bar->priv = gtk_path_bar_get_instance_private (path_bar);
185

186
  gtk_widget_init_template (GTK_WIDGET (path_bar));
187

188 189 190 191 192
  /* Add the children manually because GtkPathBar derives from an abstract class,
   * Glade cannot edit a <template> in gtkpathbar.ui if it's only a GtkContainer.
   */
  gtk_container_add (GTK_CONTAINER (path_bar), path_bar->priv->down_slider_button);
  gtk_container_add (GTK_CONTAINER (path_bar), path_bar->priv->up_slider_button);
193

194 195 196 197 198 199 200
  /* GtkBuilder wont let us connect 'swapped' without specifying the signal's
   * user data in the .ui file
   */
  g_signal_connect_swapped (path_bar->priv->up_slider_button, "clicked",
			    G_CALLBACK (gtk_path_bar_scroll_up), path_bar);
  g_signal_connect_swapped (path_bar->priv->down_slider_button, "clicked",
			    G_CALLBACK (gtk_path_bar_scroll_down), path_bar);
201

202
  gtk_widget_set_has_window (GTK_WIDGET (path_bar), FALSE);
203 204
  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (path_bar), FALSE);

205 206 207
  context = gtk_widget_get_style_context (GTK_WIDGET (path_bar));
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_LINKED);

208 209
  path_bar->priv->get_info_cancellable = NULL;
  path_bar->priv->icon_size = FALLBACK_ICON_SIZE;
210 211 212 213 214 215 216 217 218 219 220 221 222
}

static void
gtk_path_bar_class_init (GtkPathBarClass *path_bar_class)
{
  GObjectClass *gobject_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

  gobject_class = (GObjectClass *) path_bar_class;
  widget_class = (GtkWidgetClass *) path_bar_class;
  container_class = (GtkContainerClass *) path_bar_class;

223
  gobject_class->finalize = gtk_path_bar_finalize;
224
  gobject_class->dispose = gtk_path_bar_dispose;
225

226 227
  widget_class->get_preferred_width = gtk_path_bar_get_preferred_width;
  widget_class->get_preferred_height = gtk_path_bar_get_preferred_height;
228 229 230
  widget_class->realize = gtk_path_bar_realize;
  widget_class->unrealize = gtk_path_bar_unrealize;
  widget_class->map = gtk_path_bar_map;
231
  widget_class->unmap = gtk_path_bar_unmap;
232
  widget_class->size_allocate = gtk_path_bar_size_allocate;
233
  widget_class->style_updated = gtk_path_bar_style_updated;
234
  widget_class->screen_changed = gtk_path_bar_screen_changed;
235 236
  widget_class->grab_notify = gtk_path_bar_grab_notify;
  widget_class->state_changed = gtk_path_bar_state_changed;
237
  widget_class->scroll_event = gtk_path_bar_scroll;
238 239 240 241

  container_class->add = gtk_path_bar_add;
  container_class->forall = gtk_path_bar_forall;
  container_class->remove = gtk_path_bar_remove;
242
  container_class->get_path_for_child = gtk_path_bar_get_path_for_child;
243
  gtk_container_class_handle_border_width (container_class);
244 245
  /* FIXME: */
  /*  container_class->child_type = gtk_path_bar_child_type;*/
246 247

  path_bar_signals [PATH_CLICKED] =
248
    g_signal_new (I_("path-clicked"),
249
		  G_OBJECT_CLASS_TYPE (gobject_class),
250 251 252
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkPathBarClass, path_clicked),
		  NULL, NULL,
253 254 255
		  _gtk_marshal_VOID__POINTER_POINTER_BOOLEAN,
		  G_TYPE_NONE, 3,
		  G_TYPE_POINTER,
Federico Mena Quintero's avatar
Federico Mena Quintero committed
256 257
		  G_TYPE_POINTER,
		  G_TYPE_BOOLEAN);
258 259 260 261

  /* Bind class to template
   */
  gtk_widget_class_set_template_from_resource (widget_class,
262
					       "/org/gtk/libgtk/ui/gtkpathbar.ui");
263

264 265
  gtk_widget_class_bind_template_child_private (widget_class, GtkPathBar, up_slider_button);
  gtk_widget_class_bind_template_child_private (widget_class, GtkPathBar, down_slider_button);
266 267 268 269 270 271 272 273

  gtk_widget_class_bind_template_callback (widget_class, gtk_path_bar_slider_button_press);
  gtk_widget_class_bind_template_callback (widget_class, gtk_path_bar_slider_button_release);
  gtk_widget_class_bind_template_callback (widget_class, gtk_path_bar_slider_up_defocus);
  gtk_widget_class_bind_template_callback (widget_class, gtk_path_bar_slider_down_defocus);
  gtk_widget_class_bind_template_callback (widget_class, gtk_path_bar_scroll_up);
  gtk_widget_class_bind_template_callback (widget_class, gtk_path_bar_scroll_down);
  gtk_widget_class_bind_template_callback (widget_class, on_slider_unmap);
274 275 276 277
}


static void
278
gtk_path_bar_finalize (GObject *object)
279 280 281 282
{
  GtkPathBar *path_bar;

  path_bar = GTK_PATH_BAR (object);
283 284 285

  gtk_path_bar_stop_scrolling (path_bar);

286 287 288 289 290 291 292
  g_list_free (path_bar->priv->button_list);
  if (path_bar->priv->root_file)
    g_object_unref (path_bar->priv->root_file);
  if (path_bar->priv->home_file)
    g_object_unref (path_bar->priv->home_file);
  if (path_bar->priv->desktop_file)
    g_object_unref (path_bar->priv->desktop_file);
293

294
  if (path_bar->priv->root_icon)
295
    cairo_surface_destroy (path_bar->priv->root_icon);
296
  if (path_bar->priv->home_icon)
297
    cairo_surface_destroy (path_bar->priv->home_icon);
298
  if (path_bar->priv->desktop_icon)
299
    cairo_surface_destroy (path_bar->priv->desktop_icon);
300

301 302
  if (path_bar->priv->file_system)
    g_object_unref (path_bar->priv->file_system);
303

304
  G_OBJECT_CLASS (gtk_path_bar_parent_class)->finalize (object);
305 306
}

307 308 309 310 311
/* Removes the settings signal handler.  It's safe to call multiple times */
static void
remove_settings_signal (GtkPathBar *path_bar,
			GdkScreen  *screen)
{
312
  if (path_bar->priv->settings_signal_id)
313 314 315 316 317
    {
      GtkSettings *settings;

      settings = gtk_settings_get_for_screen (screen);
      g_signal_handler_disconnect (settings,
318 319
				   path_bar->priv->settings_signal_id);
      path_bar->priv->settings_signal_id = 0;
320 321 322 323 324 325
    }
}

static void
gtk_path_bar_dispose (GObject *object)
{
326 327 328 329
  GtkPathBar *path_bar = GTK_PATH_BAR (object);

  remove_settings_signal (path_bar, gtk_widget_get_screen (GTK_WIDGET (object)));

330 331 332
  if (path_bar->priv->get_info_cancellable)
    g_cancellable_cancel (path_bar->priv->get_info_cancellable);
  path_bar->priv->get_info_cancellable = NULL;
333 334 335 336

  G_OBJECT_CLASS (gtk_path_bar_parent_class)->dispose (object);
}

337 338 339 340 341 342
/* Size requisition:
 * 
 * Ideally, our size is determined by another widget, and we are just filling
 * available space.
 */
static void
343 344 345
gtk_path_bar_get_preferred_width (GtkWidget *widget,
                                  gint      *minimum,
                                  gint      *natural)
346
{
347
  ButtonData *button_data;
348 349
  GtkPathBar *path_bar;
  GList *list;
350 351 352
  gint child_height;
  gint height;
  gint child_min, child_nat;
353 354 355

  path_bar = GTK_PATH_BAR (widget);

356 357
  *minimum = *natural = 0;
  height = 0;
358

359
  for (list = path_bar->priv->button_list; list; list = list->next)
360
    {
361
      button_data = BUTTON_DATA (list->data);
362 363 364
      gtk_widget_get_preferred_width (button_data->button, &child_min, &child_nat);
      gtk_widget_get_preferred_height (button_data->button, &child_height, NULL);
      height = MAX (height, child_height);
365

366
      if (button_data->type == NORMAL_BUTTON)
367 368 369 370 371 372 373
        {
          /* Use 2*Height as button width because of ellipsized label.  */
          child_min = MAX (child_min, child_height * 2);
          child_nat = MAX (child_min, child_height * 2);
        }

      *minimum = MAX (*minimum, child_min);
374
      *natural = *natural + child_nat;
375 376 377 378 379 380
    }

  /* Add space for slider, if we have more than one path */
  /* Theoretically, the slider could be bigger than the other button.  But we're
   * not going to worry about that now.
   */
381 382
  path_bar->priv->slider_width = MIN (height * 2 / 3 + 5, height);
  if (path_bar->priv->button_list && path_bar->priv->button_list->next != NULL)
383
    {
384 385
      *minimum += path_bar->priv->slider_width * 2;
      *natural += path_bar->priv->slider_width * 2;
386 387
    }
}
388

389 390 391 392 393 394 395 396 397 398 399 400 401 402
static void
gtk_path_bar_get_preferred_height (GtkWidget *widget,
                                   gint      *minimum,
                                   gint      *natural)
{
  ButtonData *button_data;
  GtkPathBar *path_bar;
  GList *list;
  gint child_min, child_nat;

  path_bar = GTK_PATH_BAR (widget);

  *minimum = *natural = 0;

403
  for (list = path_bar->priv->button_list; list; list = list->next)
404 405 406 407 408 409 410
    {
      button_data = BUTTON_DATA (list->data);
      gtk_widget_get_preferred_height (button_data->button, &child_min, &child_nat);

      *minimum = MAX (*minimum, child_min);
      *natural = MAX (*natural, child_nat);
    }
411 412 413 414 415
}

static void
gtk_path_bar_update_slider_buttons (GtkPathBar *path_bar)
{
416
  if (path_bar->priv->button_list)
417 418 419
    {
      GtkWidget *button;

420
      button = BUTTON_DATA (path_bar->priv->button_list->data)->button;
421
      if (gtk_widget_get_child_visible (button))
422 423
	{
	  gtk_path_bar_stop_scrolling (path_bar);
424
	  gtk_widget_set_sensitive (path_bar->priv->down_slider_button, FALSE);
425
	}
426
      else
427
	gtk_widget_set_sensitive (path_bar->priv->down_slider_button, TRUE);
428

429
      button = BUTTON_DATA (g_list_last (path_bar->priv->button_list)->data)->button;
430
      if (gtk_widget_get_child_visible (button))
431 432
	{
	  gtk_path_bar_stop_scrolling (path_bar);
433
	  gtk_widget_set_sensitive (path_bar->priv->up_slider_button, FALSE);
434
	}
435
      else
436
	gtk_widget_set_sensitive (path_bar->priv->up_slider_button, TRUE);
437 438 439
    }
}

440 441 442
static void
gtk_path_bar_map (GtkWidget *widget)
{
443
  gdk_window_show (GTK_PATH_BAR (widget)->priv->event_window);
444 445 446 447

  GTK_WIDGET_CLASS (gtk_path_bar_parent_class)->map (widget);
}

448 449 450 451
static void
gtk_path_bar_unmap (GtkWidget *widget)
{
  gtk_path_bar_stop_scrolling (GTK_PATH_BAR (widget));
452
  gdk_window_hide (GTK_PATH_BAR (widget)->priv->event_window);
453 454 455 456

  GTK_WIDGET_CLASS (gtk_path_bar_parent_class)->unmap (widget);
}

457 458 459 460
static void
gtk_path_bar_realize (GtkWidget *widget)
{
  GtkPathBar *path_bar;
461 462
  GtkAllocation allocation;
  GdkWindow *window;
463 464 465
  GdkWindowAttr attributes;
  gint attributes_mask;

466
  gtk_widget_set_realized (widget, TRUE);
467 468

  path_bar = GTK_PATH_BAR (widget);
469 470 471 472 473
  window = gtk_widget_get_parent_window (widget);
  gtk_widget_set_window (widget, window);
  g_object_ref (window);

  gtk_widget_get_allocation (widget, &allocation);
474 475

  attributes.window_type = GDK_WINDOW_CHILD;
476 477 478 479
  attributes.x = allocation.x;
  attributes.y = allocation.y;
  attributes.width = allocation.width;
  attributes.height = allocation.height;
480 481 482 483 484
  attributes.wclass = GDK_INPUT_ONLY;
  attributes.event_mask = gtk_widget_get_events (widget);
  attributes.event_mask |= GDK_SCROLL_MASK;
  attributes_mask = GDK_WA_X | GDK_WA_Y;

485
  path_bar->priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
486
                                           &attributes, attributes_mask);
487
  gtk_widget_register_window (widget, path_bar->priv->event_window);
488 489 490 491 492 493 494 495 496
}

static void
gtk_path_bar_unrealize (GtkWidget *widget)
{
  GtkPathBar *path_bar;

  path_bar = GTK_PATH_BAR (widget);

497 498 499
  gtk_widget_unregister_window (widget, path_bar->priv->event_window);
  gdk_window_destroy (path_bar->priv->event_window);
  path_bar->priv->event_window = NULL;
500

501
  GTK_WIDGET_CLASS (gtk_path_bar_parent_class)->unrealize (widget);
502 503
}

504 505 506 507 508
static void
child_ordering_changed (GtkPathBar *path_bar)
{
  GList *l;

509 510
  if (path_bar->priv->up_slider_button)
    _gtk_widget_invalidate_style_context (path_bar->priv->up_slider_button,
511
                                          GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION);
512 513
  if (path_bar->priv->down_slider_button)
    _gtk_widget_invalidate_style_context (path_bar->priv->down_slider_button,
514
                                          GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION);
515

516
  for (l = path_bar->priv->button_list; l; l = l->next)
517 518 519
    {
      ButtonData *data = l->data;

520 521
      _gtk_widget_invalidate_style_context (data->button,
                                            GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION);
522 523 524
    }
}

525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
/* This is a tad complicated
 */
static void
gtk_path_bar_size_allocate (GtkWidget     *widget,
			    GtkAllocation *allocation)
{
  GtkWidget *child;
  GtkPathBar *path_bar = GTK_PATH_BAR (widget);
  GtkTextDirection direction;
  GtkAllocation child_allocation;
  GList *list, *first_button;
  gint width;
  gint allocation_width;
  gboolean need_sliders = FALSE;
  gint up_slider_offset = 0;
540
  gint down_slider_offset = 0;
541
  GtkRequisition child_requisition;
542
  gboolean needs_reorder = FALSE;
543

544
  gtk_widget_set_allocation (widget, allocation);
545

546
  if (gtk_widget_get_realized (widget))
547
    gdk_window_move_resize (path_bar->priv->event_window,
548 549 550
			    allocation->x, allocation->y,
			    allocation->width, allocation->height);

551
  /* No path is set; we don't have to allocate anything. */
552
  if (path_bar->priv->button_list == NULL)
553 554 555
    return;

  direction = gtk_widget_get_direction (widget);
556
  allocation_width = allocation->width;
557 558

  /* First, we check to see if we need the scrollbars. */
559
  if (path_bar->priv->fake_root)
560
    width = path_bar->priv->slider_width;
561
  else
562
    width = 0;
563

564
  for (list = path_bar->priv->button_list; list; list = list->next)
565
    {
566
      child = BUTTON_DATA (list->data)->button;
567

568
      gtk_widget_get_preferred_size (child, &child_requisition, NULL);
569

570
      width += child_requisition.width;
571
      if (list == path_bar->priv->fake_root)
572
	break;
573 574 575 576
    }

  if (width <= allocation_width)
    {
577 578
      if (path_bar->priv->fake_root)
	first_button = path_bar->priv->fake_root;
579
      else
580
	first_button = g_list_last (path_bar->priv->button_list);
581 582 583 584
    }
  else
    {
      gboolean reached_end = FALSE;
585
      gint slider_space = 2 * path_bar->priv->slider_width;
586

587 588
      if (path_bar->priv->first_scrolled_button)
	first_button = path_bar->priv->first_scrolled_button;
589
      else
590
	first_button = path_bar->priv->button_list;
591 592 593 594 595 596 597
      need_sliders = TRUE;
      
      /* To see how much space we have, and how many buttons we can display.
       * We start at the first button, count forward until hit the new
       * button, then count backwards.
       */
      /* Count down the path chain towards the end. */
598 599
      gtk_widget_get_preferred_size (BUTTON_DATA (first_button->data)->button,
                                     &child_requisition, NULL);
600 601

      width = child_requisition.width;
602 603 604
      list = first_button->prev;
      while (list && !reached_end)
	{
605
	  child = BUTTON_DATA (list->data)->button;
606

607
          gtk_widget_get_preferred_size (child, &child_requisition, NULL);
608

609
	  if (width + child_requisition.width + slider_space > allocation_width)
610
	    reached_end = TRUE;
611
	  else if (list == path_bar->priv->fake_root)
612
	    break;
613
	  else
614
	    width += child_requisition.width;
615 616 617 618 619 620

	  list = list->prev;
	}

      /* Finally, we walk up, seeing how many of the previous buttons we can
       * add */
621
      while (first_button->next && !reached_end)
622
	{
623
	  child = BUTTON_DATA (first_button->next->data)->button;
624

625
          gtk_widget_get_preferred_size (child, &child_requisition, NULL);
626

627
	  if (width + child_requisition.width + slider_space > allocation_width)
628 629 630 631 632
	    {
	      reached_end = TRUE;
	    }
	  else
	    {
633
	      width += child_requisition.width;
634
	      if (first_button == path_bar->priv->fake_root)
635
		break;
636 637 638 639 640 641
	      first_button = first_button->next;
	    }
	}
    }

  /* Now, we allocate space to the buttons */
642 643
  child_allocation.y = allocation->y;
  child_allocation.height = allocation->height;
644 645 646

  if (direction == GTK_TEXT_DIR_RTL)
    {
647
      child_allocation.x = allocation->x + allocation->width;
648
      if (need_sliders || path_bar->priv->fake_root)
649
	{
650
	  child_allocation.x -= path_bar->priv->slider_width;
651
	  up_slider_offset = allocation->width - path_bar->priv->slider_width;
652 653 654 655
	}
    }
  else
    {
656
      child_allocation.x = allocation->x;
657
      if (need_sliders || path_bar->priv->fake_root)
658
	{
659
	  up_slider_offset = 0;
660
	  child_allocation.x += path_bar->priv->slider_width;
661 662 663 664 665
	}
    }

  for (list = first_button; list; list = list->prev)
    {
666
      GtkAllocation widget_allocation;
667 668 669 670 671
      ButtonData *button_data;

      button_data = BUTTON_DATA (list->data);
      child = button_data->button;

672
      gtk_widget_get_preferred_size (child, &child_requisition, NULL);
673 674

      child_allocation.width = MIN (child_requisition.width,
675
				    allocation_width - 2 * path_bar->priv->slider_width);
676

677 678
      if (direction == GTK_TEXT_DIR_RTL)
	child_allocation.x -= child_allocation.width;
679 680 681 682

      /* Check to see if we've don't have any more space to allocate buttons */
      if (need_sliders && direction == GTK_TEXT_DIR_RTL)
	{
683
          gtk_widget_get_allocation (widget, &widget_allocation);
684
	  if (child_allocation.x - path_bar->priv->slider_width < widget_allocation.x)
685 686 687 688
	    break;
	}
      else if (need_sliders && direction == GTK_TEXT_DIR_LTR)
	{
689
          gtk_widget_get_allocation (widget, &widget_allocation);
690
	  if (child_allocation.x + child_allocation.width + path_bar->priv->slider_width >
691
	      widget_allocation.x + allocation_width)
692 693 694
	    break;
	}

695
      if (child_allocation.width < child_requisition.width)
696 697 698 699 700 701 702
	{
	  if (!gtk_widget_get_has_tooltip (child))
	    gtk_widget_set_tooltip_text (child, button_data->dir_name);
	}
      else if (gtk_widget_get_has_tooltip (child))
	gtk_widget_set_tooltip_text (child, NULL);
      
703
      needs_reorder |= gtk_widget_get_child_visible (child) == FALSE;
704
      gtk_widget_set_child_visible (child, TRUE);
705 706
      gtk_widget_size_allocate (child, &child_allocation);

707 708 709 710 711 712 713 714 715
      if (direction == GTK_TEXT_DIR_RTL)
        {
          down_slider_offset = child_allocation.x - allocation->x - path_bar->priv->slider_width;
        }
      else
        {
          down_slider_offset += child_allocation.width;
          child_allocation.x += child_allocation.width;
        }
716 717 718 719
    }
  /* Now we go hide all the widgets that don't fit */
  while (list)
    {
720
      child = BUTTON_DATA (list->data)->button;
721
      needs_reorder |= gtk_widget_get_child_visible (child) == TRUE;
722
      gtk_widget_set_child_visible (child, FALSE);
723 724 725 726
      list = list->prev;
    }
  for (list = first_button->next; list; list = list->next)
    {
727
      child = BUTTON_DATA (list->data)->button;
728
      needs_reorder |= gtk_widget_get_child_visible (child) == TRUE;
729
      gtk_widget_set_child_visible (child, FALSE);
730 731
    }

732
  if (need_sliders || path_bar->priv->fake_root)
733
    {
734
      child_allocation.width = path_bar->priv->slider_width;
735
      child_allocation.x = up_slider_offset + allocation->x;
736
      gtk_widget_size_allocate (path_bar->priv->up_slider_button, &child_allocation);
737

738 739 740
      needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->up_slider_button) == FALSE;
      gtk_widget_set_child_visible (path_bar->priv->up_slider_button, TRUE);
      gtk_widget_show_all (path_bar->priv->up_slider_button);
741 742 743

      if (direction == GTK_TEXT_DIR_LTR)
        down_slider_offset += path_bar->priv->slider_width;
744 745
    }
  else
746
    {
747 748
      needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->up_slider_button) == TRUE;
      gtk_widget_set_child_visible (path_bar->priv->up_slider_button, FALSE);
749
    }
750 751 752
      
  if (need_sliders)
    {
753
      child_allocation.width = path_bar->priv->slider_width;
754
      child_allocation.x = down_slider_offset + allocation->x;
755
      
756
      gtk_widget_size_allocate (path_bar->priv->down_slider_button, &child_allocation);
757

758 759 760
      needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->down_slider_button) == FALSE;
      gtk_widget_set_child_visible (path_bar->priv->down_slider_button, TRUE);
      gtk_widget_show_all (path_bar->priv->down_slider_button);
761 762 763
      gtk_path_bar_update_slider_buttons (path_bar);
    }
  else
764
    {
765 766
      needs_reorder |= gtk_widget_get_child_visible (path_bar->priv->down_slider_button) == TRUE;
      gtk_widget_set_child_visible (path_bar->priv->down_slider_button, FALSE);
767
    }
768

769 770
  if (needs_reorder)
    child_ordering_changed (path_bar);
771 772
}

773
static void
774
gtk_path_bar_style_updated (GtkWidget *widget)
775
{
776
  GTK_WIDGET_CLASS (gtk_path_bar_parent_class)->style_updated (widget);
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794

  gtk_path_bar_check_icon_theme (GTK_PATH_BAR (widget));
}

static void
gtk_path_bar_screen_changed (GtkWidget *widget,
			     GdkScreen *previous_screen)
{
  if (GTK_WIDGET_CLASS (gtk_path_bar_parent_class)->screen_changed)
    GTK_WIDGET_CLASS (gtk_path_bar_parent_class)->screen_changed (widget, previous_screen);

  /* We might nave a new settings, so we remove the old one */
  if (previous_screen)
    remove_settings_signal (GTK_PATH_BAR (widget), previous_screen);

  gtk_path_bar_check_icon_theme (GTK_PATH_BAR (widget));
}

795 796 797 798 799 800 801 802 803 804 805 806 807 808
static gboolean
gtk_path_bar_scroll (GtkWidget      *widget,
		     GdkEventScroll *event)
{
  switch (event->direction)
    {
    case GDK_SCROLL_RIGHT:
    case GDK_SCROLL_DOWN:
      gtk_path_bar_scroll_down (GTK_PATH_BAR (widget));
      break;
    case GDK_SCROLL_LEFT:
    case GDK_SCROLL_UP:
      gtk_path_bar_scroll_up (GTK_PATH_BAR (widget));
      break;
Benjamin Otte's avatar
Benjamin Otte committed
809 810
    case GDK_SCROLL_SMOOTH:
      break;
811 812 813 814 815
    }

  return TRUE;
}

816 817 818
static void
gtk_path_bar_add (GtkContainer *container,
		  GtkWidget    *widget)
819

820 821 822 823
{
  gtk_widget_set_parent (widget, GTK_WIDGET (container));
}

824 825 826 827
static void
gtk_path_bar_remove_1 (GtkContainer *container,
		       GtkWidget    *widget)
{
828
  gboolean was_visible = gtk_widget_get_visible (widget);
829 830 831 832 833
  gtk_widget_unparent (widget);
  if (was_visible)
    gtk_widget_queue_resize (GTK_WIDGET (container));
}

834 835 836 837 838 839 840 841 842
static void
gtk_path_bar_remove (GtkContainer *container,
		     GtkWidget    *widget)
{
  GtkPathBar *path_bar;
  GList *children;

  path_bar = GTK_PATH_BAR (container);

843
  if (widget == path_bar->priv->up_slider_button)
844 845
    {
      gtk_path_bar_remove_1 (container, widget);
846
      path_bar->priv->up_slider_button = NULL;
847 848 849
      return;
    }

850
  if (widget == path_bar->priv->down_slider_button)
851 852
    {
      gtk_path_bar_remove_1 (container, widget);
853
      path_bar->priv->down_slider_button = NULL;
854 855
      return;
    }
856

857
  children = path_bar->priv->button_list;
858 859
  while (children)
    {
860
      if (widget == BUTTON_DATA (children->data)->button)
861
	{
862
	  gtk_path_bar_remove_1 (container, widget);
863
	  path_bar->priv->button_list = g_list_remove_link (path_bar->priv->button_list, children);
864
	  g_list_free (children);
865
	  return;
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
	}
      
      children = children->next;
    }
}

static void
gtk_path_bar_forall (GtkContainer *container,
		     gboolean      include_internals,
		     GtkCallback   callback,
		     gpointer      callback_data)
{
  GtkPathBar *path_bar;
  GList *children;

  g_return_if_fail (callback != NULL);
  path_bar = GTK_PATH_BAR (container);

884
  children = path_bar->priv->button_list;
885 886 887
  while (children)
    {
      GtkWidget *child;
888
      child = BUTTON_DATA (children->data)->button;
889 890 891 892 893
      children = children->next;

      (* callback) (child, callback_data);
    }

894 895
  if (path_bar->priv->up_slider_button)
    (* callback) (path_bar->priv->up_slider_button, callback_data);
896

897 898
  if (path_bar->priv->down_slider_button)
    (* callback) (path_bar->priv->down_slider_button, callback_data);
899 900
}

901 902 903 904 905 906 907
static GtkWidgetPath *
gtk_path_bar_get_path_for_child (GtkContainer *container,
                                 GtkWidget    *child)
{
  GtkPathBar *path_bar = GTK_PATH_BAR (container);
  GtkWidgetPath *path;

908
  path = _gtk_widget_create_path (GTK_WIDGET (path_bar));
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924

  if (gtk_widget_get_visible (child) &&
      gtk_widget_get_child_visible (child))
    {
      GtkWidgetPath *sibling_path;
      GList *visible_children;
      GList *l;
      int pos;

      /* 1. Build the list of visible children, in visually left-to-right order
       * (i.e. independently of the widget's direction).  Note that our
       * button_list is stored in innermost-to-outermost path order!
       */

      visible_children = NULL;

925 926 927
      if (gtk_widget_get_visible (path_bar->priv->down_slider_button) &&
          gtk_widget_get_child_visible (path_bar->priv->down_slider_button))
        visible_children = g_list_prepend (visible_children, path_bar->priv->down_slider_button);
928

929
      for (l = path_bar->priv->button_list; l; l = l->next)
930 931 932 933 934 935 936 937
        {
          ButtonData *data = l->data;

          if (gtk_widget_get_visible (data->button) &&
              gtk_widget_get_child_visible (data->button))
            visible_children = g_list_prepend (visible_children, data->button);
        }

938 939 940
      if (gtk_widget_get_visible (path_bar->priv->up_slider_button) &&
          gtk_widget_get_child_visible (path_bar->priv->up_slider_button))
        visible_children = g_list_prepend (visible_children, path_bar->priv->up_slider_button);
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976

      if (gtk_widget_get_direction (GTK_WIDGET (path_bar)) == GTK_TEXT_DIR_RTL)
        visible_children = g_list_reverse (visible_children);

      /* 2. Find the index of the child within that list */

      pos = 0;

      for (l = visible_children; l; l = l->next)
        {
          GtkWidget *button = l->data;

          if (button == child)
            break;

          pos++;
        }

      /* 3. Build the path */

      sibling_path = gtk_widget_path_new ();

      for (l = visible_children; l; l = l->next)
        gtk_widget_path_append_for_widget (sibling_path, l->data);

      gtk_widget_path_append_with_siblings (path, sibling_path, pos);

      g_list_free (visible_children);
      gtk_widget_path_unref (sibling_path);
    }
  else
    gtk_widget_path_append_for_widget (path, child);

  return path;
}

977
static void
978
gtk_path_bar_scroll_down (GtkPathBar *path_bar)
979
{
980
  GtkAllocation allocation, button_allocation;
981
  GList *list;
982
  GList *down_button = NULL;
983
  gint space_available;
984

985
  if (path_bar->priv->ignore_click)
986
    {
987
      path_bar->priv->ignore_click = FALSE;
988 989 990
      return;   
    }

991
  if (gtk_widget_get_child_visible (BUTTON_DATA (path_bar->priv->button_list->data)->button))
992 993 994 995 996
    {
      /* Return if the last button is already visible */
      return;
    }

997 998
  gtk_widget_queue_resize (GTK_WIDGET (path_bar));

999 1000
  /* We find the button at the 'down' end that we have to make
   * visible */
1001
  for (list = path_bar->priv->button_list; list; list = list->next)
1002
    {
1003
      if (list->next && gtk_widget_get_child_visible (BUTTON_DATA (list->next->data)->button))
1004 1005 1006 1007 1008 1009
	{
	  down_button = list;
	  break;
	}
    }

1010 1011 1012 1013
  gtk_widget_get_allocation (GTK_WIDGET (path_bar), &allocation);
  gtk_widget_get_allocation (BUTTON_DATA (down_button->data)->button, &button_allocation);

  space_available = (allocation.width
1014
		     - 2 * path_bar->priv->slider_width
1015
                     - button_allocation.width);
1016
  path_bar->priv->first_scrolled_button = down_button;
1017 1018 1019
  
  /* We have space_available free space that's not being used.  
   * So we walk down from the end, adding buttons until we use all free space.
1020
   */
1021
  while (space_available > 0)
1022
    {
1023
      path_bar->priv->first_scrolled_button = down_button;
1024 1025 1026
      down_button = down_button->next;
      if (!down_button)
	break;
1027
      space_available -= button_allocation.width;
1028 1029 1030 1031
    }
}

static void
1032
gtk_path_bar_scroll_up (GtkPathBar *path_bar)
1033 1034 1035
{
  GList *list;

1036
  if (path_bar->priv->ignore_click)
1037
    {
1038
      path_bar->priv->ignore_click = FALSE;
1039 1040 1041
      return;   
    }

1042
  list = g_list_last (path_bar->priv->button_list);
1043 1044 1045 1046 1047 1048 1049

  if (gtk_widget_get_child_visible (BUTTON_DATA (list->data)->button))
    {
      /* Return if the first button is already visible */
      return;
    }

1050 1051
  gtk_widget_queue_resize (GTK_WIDGET (path_bar));

1052
  for ( ; list; list = list->prev)
1053
    {
1054
      if (list->prev && gtk_widget_get_child_visible (BUTTON_DATA (list->prev->data)->button))
1055
	{
1056 1057 1058
	  if (list->prev == path_bar->priv->fake_root)
	    path_bar->priv->fake_root = NULL;
	  path_bar->priv->first_scrolled_button = list;
1059 1060 1061 1062 1063
	  return;
	}
    }
}

1064 1065 1066 1067 1068
static gboolean
gtk_path_bar_scroll_timeout (GtkPathBar *path_bar)
{
  gboolean retval = FALSE;

1069
  if (path_bar->priv->timer)
1070
    {
1071
      if (path_bar->priv->scrolling_up)
1072
	gtk_path_bar_scroll_up (path_bar);
1073
      else if (path_bar->priv->scrolling_down)
1074
	gtk_path_bar_scroll_down (path_bar);
1075

1076
      if (path_bar->priv->need_timer) 
1077
	{
1078
	  path_bar->priv->need_timer = FALSE;
1079

1080
	  path_bar->priv->timer = gdk_threads_add_timeout (TIMEOUT_REPEAT * SCROLL_DELAY_FACTOR,
1081 1082
					   (GSourceFunc)gtk_path_bar_scroll_timeout,
					   path_bar);
1083
          g_source_set_name_by_id (path_bar->priv->timer, "[gtk+] gtk_path_bar_scroll_timeout");
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
	}
      else
	retval = TRUE;
    }

  return retval;
}

static void 
gtk_path_bar_stop_scrolling (GtkPathBar *path_bar)
{
1095
  if (path_bar->priv->timer)
1096
    {
1097 1098 1099
      g_source_remove (path_bar->priv->timer);
      path_bar->priv->timer = 0;
      path_bar->priv->need_timer = FALSE;
1100 1101 1102
    }
}

1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
static gboolean
gtk_path_bar_slider_up_defocus (GtkWidget      *widget,
                                    GdkEventButton *event,
                                    GtkPathBar     *path_bar)
{
  GList *list;
  GList *up_button = NULL;

  if (event->type != GDK_FOCUS_CHANGE)
    return FALSE;

1114
  for (list = g_list_last (path_bar->priv->button_list); list; list = list->prev)
1115 1116 1117 1118 1119 1120 1121 1122 1123
    {
      if (gtk_widget_get_child_visible (BUTTON_DATA (list->data)->button))
        {
          up_button = list;
          break;
        }
    }

  /* don't let the focus vanish */
1124 1125
  if ((!gtk_widget_is_sensitive (path_bar->priv->up_slider_button)) ||
      (!gtk_widget_get_child_visible (path_bar->priv->up_slider_button)))
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
    gtk_widget_grab_focus (BUTTON_DATA (up_button->data)->button);

  return FALSE;
}

static gboolean
gtk_path_bar_slider_down_defocus (GtkWidget      *widget,
                                    GdkEventButton *event,
                                    GtkPathBar     *path_bar)
{
  GList *list;
  GList *down_button = NULL;

  if (event->type != GDK_FOCUS_CHANGE)
    return FALSE;

1142
  for (list = path_bar->priv->button_list; list; list = list->next)
1143 1144 1145 1146 1147 1148 1149 1150 1151
    {
      if (gtk_widget_get_child_visible (BUTTON_DATA (list->data)->button))
        {
          down_button = list;
          break;
        }
    }

  /* don't let the focus vanish */
1152 1153
  if ((!gtk_widget_is_sensitive (path_bar->priv->down_slider_button)) ||
      (!gtk_widget_get_child_visible (path_bar->priv->down_slider_button)))
1154 1155 1156 1157 1158
    gtk_widget_grab_focus (BUTTON_DATA (down_button->data)->button);

  return FALSE;
}

1159 1160 1161 1162 1163
static gboolean
gtk_path_bar_slider_button_press (GtkWidget      *widget, 
				  GdkEventButton *event,
				  GtkPathBar     *path_bar)
{
1164
  if (event->type != GDK_BUTTON_PRESS || event->button != GDK_BUTTON_PRIMARY)
1165 1166
    return FALSE;

1167
  path_bar->priv->ignore_click = FALSE;
1168

1169
  if (widget == path_bar->priv->up_slider_button)
1170
    {
1171 1172
      path_bar->priv->scrolling_down = FALSE;
      path_bar->priv->scrolling_up = TRUE;
1173
      gtk_path_bar_scroll_up (path_bar);
1174
    }
1175
  else if (widget == path_bar->priv->down_slider_button)
1176
    {
1177 1178
      path_bar->priv->scrolling_up = FALSE;
      path_bar->priv->scrolling_down = TRUE;
1179
      gtk_path_bar_scroll_down (path_bar);
1180
    }
1181

1182
  if (!path_bar->priv->timer)
1183
    {
1184
      path_bar->priv->need_timer = TRUE;
1185
      path_bar->priv->timer = gdk_threads_add_timeout (TIMEOUT_INITIAL,
1186 1187
				       (GSourceFunc)gtk_path_bar_scroll_timeout,
				       path_bar);
1188
      g_source_set_name_by_id (path_bar->priv->timer, "[gtk+] gtk_path_bar_scroll_timeout");
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
    }

  return FALSE;
}

static gboolean
gtk_path_bar_slider_button_release (GtkWidget      *widget, 
				    GdkEventButton *event,
				    GtkPathBar     *path_bar)
{
  if (event->type != GDK_BUTTON_RELEASE)
    return FALSE;

1202
  path_bar->priv->ignore_click = TRUE;
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
  gtk_path_bar_stop_scrolling (path_bar);

  return FALSE;
}

static void
gtk_path_bar_grab_notify (GtkWidget *widget,
			  gboolean   was_grabbed)
{
  if (!was_grabbed)
    gtk_path_bar_stop_scrolling (GTK_PATH_BAR (widget));
}

static void
gtk_path_bar_state_changed (GtkWidget    *widget,
			    GtkStateType  previous_state)
{
1220
  if (!gtk_widget_is_sensitive (widget))
1221 1222 1223 1224
    gtk_path_bar_stop_scrolling (GTK_PATH_BAR (widget));
}


1225 1226 1227 1228 1229 1230
/* Changes the icons wherever it is needed */
static void
reload_icons (GtkPathBar *path_bar)
{
  GList *list;

1231
  if (path_bar->priv->root_icon)
1232
    {
1233
      cairo_surface_destroy (path_bar->priv->root_icon);
1234
      path_bar->priv->root_icon = NULL;
1235
    }
1236
  if (path_bar->priv->home_icon)
1237
    {
1238
      cairo_surface_destroy (path_bar->priv->home_icon);
1239
      path_bar->priv->home_icon = NULL;
1240
    }
1241
  if (path_bar->priv->desktop_icon)
1242
    {
1243
      cairo_surface_destroy (path_bar->priv->desktop_icon);
1244
      path_bar->priv->desktop_icon = NULL;
1245 1246
    }

1247
  for (list = path_bar->priv->button_list; list; list = list->next)
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
    {
      ButtonData *button_data;
      gboolean current_dir;

      button_data = BUTTON_DATA (list->data);
      if (button_data->type != NORMAL_BUTTON)
	{
	  current_dir = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button));
	  gtk_path_bar_update_button_appearance (path_bar, button_data, current_dir);
	}
    }
  
}

static void
change_icon_theme (GtkPathBar *path_bar)
{
  gint width, height;

1267
  if (gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height))
1268
    path_bar->priv->icon_size = MAX (width, height);
1269
  else
1270
    path_bar->priv->icon_size = FALLBACK_ICON_SIZE;
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283

  reload_icons (path_bar);
}
/* Callback used when a GtkSettings value changes */
static void
settings_notify_cb (GObject    *object,
		    GParamSpec *pspec,
		    GtkPathBar *path_bar)
{
  const char *name;

  name = g_param_spec_get_name (pspec);

1284
  if (strcmp (name, "gtk-icon-theme-name") == 0)
1285 1286 1287 1288 1289 1290 1291 1292
    change_icon_theme (path_bar);
}

static void
gtk_path_bar_check_icon_theme (GtkPathBar *path_bar)
{
  GtkSettings *settings;

Tristan Van Berkom's avatar