~ubuntu-branches/ubuntu/vivid/thunar/vivid

« back to all changes in this revision

Viewing changes to .pc/menu-icon-tweaks.patch/thunar/thunar-location-buttons.c

  • Committer: Package Import Robot
  • Author(s): Jackson Doak
  • Date: 2014-04-05 08:22:40 UTC
  • Revision ID: package-import@ubuntu.com-20140405082240-b3iiyypyyo3uliy3
Tags: 1.6.3-1ubuntu5
* Add git-save-keyboard-shortcuts.patch. LP: #1186846
  - Keyboard shortcuts save when changed rather than when thunar is closed
* Add menu-icon-tweaks.patch. LP: #1271861
  - Don't use generic folder icons for open with default application
  - Add icons for open in new tab, new window
* Add git-force-toolbr-icons.patch
  - Fix for "Home" and "Open Parent" icons going missing from toolbar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id$ */
 
2
/*-
 
3
 * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
 
4
 * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify it
 
7
 * under the terms of the GNU General Public License as published by the Free
 
8
 * Software Foundation; either version 2 of the License, or (at your option)
 
9
 * any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
14
 * more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License along with
 
17
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
18
 * Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 *
 
20
 * Based on code written by Jonathan Blandford <jrb@gnome.org> for
 
21
 * Red Hat, Inc.
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif
 
27
 
 
28
#include <thunar/thunar-application.h>
 
29
#include <thunar/thunar-clipboard-manager.h>
 
30
#include <thunar/thunar-create-dialog.h>
 
31
#include <thunar/thunar-gio-extensions.h>
 
32
#include <thunar/thunar-gobject-extensions.h>
 
33
#include <thunar/thunar-gtk-extensions.h>
 
34
#include <thunar/thunar-location-button.h>
 
35
#include <thunar/thunar-location-buttons.h>
 
36
#include <thunar/thunar-location-buttons-ui.h>
 
37
#include <thunar/thunar-private.h>
 
38
#include <thunar/thunar-properties-dialog.h>
 
39
 
 
40
 
 
41
 
 
42
#define THUNAR_LOCATION_BUTTONS_SCROLL_TIMEOUT  (200)
 
43
 
 
44
 
 
45
 
 
46
/* Property identifiers */
 
47
enum
 
48
{
 
49
  PROP_0,
 
50
  PROP_CURRENT_DIRECTORY,
 
51
  PROP_SELECTED_FILES,
 
52
  PROP_UI_MANAGER,
 
53
};
 
54
 
 
55
 
 
56
 
 
57
static void           thunar_location_buttons_component_init            (ThunarComponentIface       *iface);
 
58
static void           thunar_location_buttons_navigator_init            (ThunarNavigatorIface       *iface);
 
59
static void           thunar_location_buttons_location_bar_init         (ThunarLocationBarIface     *iface);
 
60
static void           thunar_location_buttons_finalize                  (GObject                    *object);
 
61
static void           thunar_location_buttons_get_property              (GObject                    *object,
 
62
                                                                         guint                       prop_id,
 
63
                                                                         GValue                     *value,
 
64
                                                                         GParamSpec                 *pspec);
 
65
static void           thunar_location_buttons_set_property              (GObject                    *object,
 
66
                                                                         guint                       prop_id,
 
67
                                                                         const GValue               *value,
 
68
                                                                         GParamSpec                 *pspec);
 
69
static GtkUIManager  *thunar_location_buttons_get_ui_manager            (ThunarComponent            *component);
 
70
static void           thunar_location_buttons_set_ui_manager            (ThunarComponent            *component,
 
71
                                                                         GtkUIManager               *ui_manager);
 
72
static ThunarFile    *thunar_location_buttons_get_current_directory     (ThunarNavigator            *navigator);
 
73
static void           thunar_location_buttons_set_current_directory     (ThunarNavigator            *navigator,
 
74
                                                                         ThunarFile                 *current_directory);
 
75
static void           thunar_location_buttons_unmap                     (GtkWidget                  *widget);
 
76
static void           thunar_location_buttons_size_request              (GtkWidget                  *widget,
 
77
                                                                         GtkRequisition             *requisition);
 
78
static void           thunar_location_buttons_size_allocate             (GtkWidget                  *widget,
 
79
                                                                         GtkAllocation              *allocation);
 
80
static void           thunar_location_buttons_state_changed             (GtkWidget                  *widget,
 
81
                                                                         GtkStateType                previous_state);
 
82
static void           thunar_location_buttons_grab_notify               (GtkWidget                  *widget,
 
83
                                                                         gboolean                    was_grabbed);
 
84
static void           thunar_location_buttons_add                       (GtkContainer               *container,
 
85
                                                                         GtkWidget                  *widget);
 
86
static void           thunar_location_buttons_remove                    (GtkContainer               *container,
 
87
                                                                         GtkWidget                  *widget);
 
88
static void           thunar_location_buttons_forall                    (GtkContainer               *container,
 
89
                                                                         gboolean                    include_internals,
 
90
                                                                         GtkCallback                 callback,
 
91
                                                                         gpointer                    callback_data);
 
92
static GtkWidget     *thunar_location_buttons_make_button               (ThunarLocationButtons      *buttons,
 
93
                                                                         ThunarFile                 *file);
 
94
static void           thunar_location_buttons_remove_1                  (GtkContainer               *container,
 
95
                                                                         GtkWidget                  *widget);
 
96
static gboolean       thunar_location_buttons_scroll_timeout            (gpointer                    user_data);
 
97
static void           thunar_location_buttons_scroll_timeout_destroy    (gpointer                    user_data);
 
98
static void           thunar_location_buttons_stop_scrolling            (ThunarLocationButtons      *buttons);
 
99
static void           thunar_location_buttons_update_sliders            (ThunarLocationButtons      *buttons);
 
100
static gboolean       thunar_location_buttons_slider_button_press       (GtkWidget                  *button,
 
101
                                                                         GdkEventButton             *event,
 
102
                                                                         ThunarLocationButtons      *buttons);
 
103
static gboolean       thunar_location_buttons_slider_button_release     (GtkWidget                  *button,
 
104
                                                                         GdkEventButton             *event,
 
105
                                                                         ThunarLocationButtons      *buttons);
 
106
static void           thunar_location_buttons_scroll_left               (GtkWidget                  *button,
 
107
                                                                         ThunarLocationButtons      *buttons);
 
108
static void           thunar_location_buttons_scroll_right              (GtkWidget                  *button,
 
109
                                                                         ThunarLocationButtons      *buttons);
 
110
static void           thunar_location_buttons_clicked                   (ThunarLocationButton       *button,
 
111
                                                                         gboolean                    open_in_tab,
 
112
                                                                         ThunarLocationButtons      *buttons);
 
113
static void           thunar_location_buttons_context_menu              (ThunarLocationButton       *button,
 
114
                                                                         GdkEventButton             *event,
 
115
                                                                         ThunarLocationButtons      *buttons);
 
116
static void           thunar_location_buttons_gone                      (ThunarLocationButton       *button,
 
117
                                                                         ThunarLocationButtons      *buttons);
 
118
static void           thunar_location_buttons_action_create_folder      (GtkAction                  *action,
 
119
                                                                         ThunarLocationButtons      *buttons);
 
120
static void           thunar_location_buttons_action_down_folder        (GtkAction                  *action,
 
121
                                                                         ThunarLocationButtons      *buttons);
 
122
static void           thunar_location_buttons_action_empty_trash        (GtkAction                  *action,
 
123
                                                                         ThunarLocationButtons      *buttons);
 
124
static void           thunar_location_buttons_action_open               (GtkAction                  *action,
 
125
                                                                         ThunarLocationButtons      *buttons);
 
126
static void           thunar_location_buttons_action_open_in_new_tab    (GtkAction                  *action,
 
127
                                                                         ThunarLocationButtons      *buttons);
 
128
static void           thunar_location_buttons_action_open_in_new_window (GtkAction                  *action,
 
129
                                                                         ThunarLocationButtons      *buttons);
 
130
static void           thunar_location_buttons_action_paste_into_folder  (GtkAction                  *action,
 
131
                                                                         ThunarLocationButtons      *buttons);
 
132
static void           thunar_location_buttons_action_properties         (GtkAction                  *action,
 
133
                                                                         ThunarLocationButtons      *buttons);
 
134
 
 
135
 
 
136
 
 
137
struct _ThunarLocationButtonsClass
 
138
{
 
139
  GtkContainerClass __parent__;
 
140
};
 
141
 
 
142
struct _ThunarLocationButtons
 
143
{
 
144
  GtkContainer __parent__;
 
145
 
 
146
  GtkActionGroup    *action_group;
 
147
  GtkUIManager      *ui_manager;
 
148
  guint              ui_merge_id;
 
149
 
 
150
  GtkWidget         *left_slider;
 
151
  GtkWidget         *right_slider;
 
152
 
 
153
  ThunarFile        *current_directory;
 
154
 
 
155
  gint               slider_width;
 
156
  gboolean           ignore_click : 1;
 
157
 
 
158
  GList             *list;
 
159
  GList             *fake_root_button;
 
160
  GList             *first_scrolled_button;
 
161
 
 
162
  guint              scroll_timeout_id;
 
163
};
 
164
 
 
165
 
 
166
 
 
167
static GQuark thunar_file_quark = 0;
 
168
 
 
169
 
 
170
 
 
171
static const GtkActionEntry action_entries[] =
 
172
{
 
173
  { "location-buttons-down-folder", NULL, "Down Folder", "<alt>Down", NULL, G_CALLBACK (thunar_location_buttons_action_down_folder), },
 
174
  { "location-buttons-context-menu", NULL, "Context Menu", NULL, "", NULL, },
 
175
  { "location-buttons-open", GTK_STOCK_OPEN, N_("_Open"), "", NULL, G_CALLBACK (thunar_location_buttons_action_open), },
 
176
  { "location-buttons-open-in-new-tab", NULL, N_("Open in New Tab"), "", NULL, G_CALLBACK (thunar_location_buttons_action_open_in_new_tab), },
 
177
  { "location-buttons-open-in-new-window", NULL, N_("Open in New Window"), "", NULL, G_CALLBACK (thunar_location_buttons_action_open_in_new_window), },
 
178
  { "location-buttons-create-folder", NULL, N_("Create _Folder..."), "", NULL, G_CALLBACK (thunar_location_buttons_action_create_folder), },
 
179
  { "location-buttons-empty-trash", NULL, N_("_Empty Trash"), "", N_("Delete all files and folders in the Trash"), G_CALLBACK (thunar_location_buttons_action_empty_trash), },
 
180
  { "location-buttons-paste-into-folder", GTK_STOCK_PASTE, N_("Paste Into Folder"), "", NULL, G_CALLBACK (thunar_location_buttons_action_paste_into_folder), },
 
181
  { "location-buttons-properties", GTK_STOCK_PROPERTIES, N_("_Properties..."), "", NULL, G_CALLBACK (thunar_location_buttons_action_properties), },
 
182
};
 
183
 
 
184
 
 
185
 
 
186
G_DEFINE_TYPE_WITH_CODE (ThunarLocationButtons, thunar_location_buttons, GTK_TYPE_CONTAINER,
 
187
    G_IMPLEMENT_INTERFACE (THUNAR_TYPE_NAVIGATOR, thunar_location_buttons_navigator_init)
 
188
    G_IMPLEMENT_INTERFACE (THUNAR_TYPE_COMPONENT, thunar_location_buttons_component_init)
 
189
    G_IMPLEMENT_INTERFACE (THUNAR_TYPE_LOCATION_BAR, thunar_location_buttons_location_bar_init))
 
190
 
 
191
 
 
192
 
 
193
static void
 
194
thunar_location_buttons_class_init (ThunarLocationButtonsClass *klass)
 
195
{
 
196
  GtkContainerClass *gtkcontainer_class;
 
197
  GtkWidgetClass    *gtkwidget_class;
 
198
  GObjectClass      *gobject_class;
 
199
 
 
200
  gobject_class = G_OBJECT_CLASS (klass);
 
201
  gobject_class->finalize = thunar_location_buttons_finalize;
 
202
  gobject_class->get_property = thunar_location_buttons_get_property;
 
203
  gobject_class->set_property = thunar_location_buttons_set_property;
 
204
 
 
205
  gtkwidget_class = GTK_WIDGET_CLASS (klass);
 
206
  gtkwidget_class->unmap = thunar_location_buttons_unmap;
 
207
  gtkwidget_class->size_request = thunar_location_buttons_size_request;
 
208
  gtkwidget_class->size_allocate = thunar_location_buttons_size_allocate;
 
209
  gtkwidget_class->state_changed = thunar_location_buttons_state_changed;
 
210
  gtkwidget_class->grab_notify = thunar_location_buttons_grab_notify;
 
211
 
 
212
  gtkcontainer_class = GTK_CONTAINER_CLASS (klass);
 
213
  gtkcontainer_class->add = thunar_location_buttons_add;
 
214
  gtkcontainer_class->remove = thunar_location_buttons_remove;
 
215
  gtkcontainer_class->forall = thunar_location_buttons_forall;
 
216
 
 
217
  /* Override ThunarNavigator's properties */
 
218
  g_object_class_override_property (gobject_class, PROP_CURRENT_DIRECTORY, "current-directory");
 
219
 
 
220
  /* Override ThunarComponent's properties */
 
221
  g_object_class_override_property (gobject_class, PROP_SELECTED_FILES, "selected-files");
 
222
  g_object_class_override_property (gobject_class, PROP_UI_MANAGER, "ui-manager");
 
223
 
 
224
  /**
 
225
   * ThunarLocationButtons:spacing:
 
226
   *
 
227
   * The amount of space between the path buttons.
 
228
   **/
 
229
  gtk_widget_class_install_style_property (gtkwidget_class,
 
230
                                           g_param_spec_int ("spacing",
 
231
                                                             _("Spacing"),
 
232
                                                             _("The amount of space between the path buttons"),
 
233
                                                             0, G_MAXINT, 3,
 
234
                                                             G_PARAM_READABLE));
 
235
 
 
236
  thunar_file_quark = g_quark_from_static_string ("button-thunar-file");
 
237
}
 
238
 
 
239
 
 
240
 
 
241
static void
 
242
thunar_location_buttons_component_init (ThunarComponentIface *iface)
 
243
{
 
244
  iface->get_selected_files = (gpointer) exo_noop_null;
 
245
  iface->set_selected_files = (gpointer) exo_noop;
 
246
  iface->get_ui_manager = thunar_location_buttons_get_ui_manager;
 
247
  iface->set_ui_manager = thunar_location_buttons_set_ui_manager;
 
248
}
 
249
 
 
250
 
 
251
 
 
252
static void
 
253
thunar_location_buttons_navigator_init (ThunarNavigatorIface *iface)
 
254
{
 
255
  iface->get_current_directory = thunar_location_buttons_get_current_directory;
 
256
  iface->set_current_directory = thunar_location_buttons_set_current_directory;
 
257
}
 
258
 
 
259
 
 
260
 
 
261
static void
 
262
thunar_location_buttons_location_bar_init (ThunarLocationBarIface *iface)
 
263
{
 
264
  iface->accept_focus = (gpointer) exo_noop_false;
 
265
  iface->is_standalone = (gpointer) exo_noop_true;
 
266
}
 
267
 
 
268
 
 
269
 
 
270
static void
 
271
thunar_location_buttons_init (ThunarLocationButtons *buttons)
 
272
{
 
273
  GtkWidget *arrow;
 
274
 
 
275
  /* setup the action group for the location buttons */
 
276
  buttons->action_group = gtk_action_group_new ("ThunarLocationButtons");
 
277
  gtk_action_group_set_translation_domain (buttons->action_group, GETTEXT_PACKAGE);
 
278
  gtk_action_group_add_actions (buttons->action_group, action_entries, G_N_ELEMENTS (action_entries), buttons);
 
279
 
 
280
  gtk_widget_set_has_window (GTK_WIDGET (buttons), FALSE);
 
281
  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (buttons), FALSE);
 
282
 
 
283
  buttons->left_slider = gtk_button_new ();
 
284
  g_signal_connect (G_OBJECT (buttons->left_slider), "button-press-event", G_CALLBACK (thunar_location_buttons_slider_button_press), buttons);
 
285
  g_signal_connect (G_OBJECT (buttons->left_slider), "button-release-event", G_CALLBACK (thunar_location_buttons_slider_button_release), buttons);
 
286
  g_signal_connect (G_OBJECT (buttons->left_slider), "clicked", G_CALLBACK (thunar_location_buttons_scroll_left), buttons);
 
287
  gtk_container_add (GTK_CONTAINER (buttons), buttons->left_slider);
 
288
  gtk_widget_show (buttons->left_slider);
 
289
 
 
290
  arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_OUT);
 
291
  gtk_container_add (GTK_CONTAINER (buttons->left_slider), arrow);
 
292
  gtk_widget_show (arrow);
 
293
 
 
294
  buttons->right_slider = gtk_button_new ();
 
295
  g_signal_connect (G_OBJECT (buttons->right_slider), "button-press-event", G_CALLBACK (thunar_location_buttons_slider_button_press), buttons);
 
296
  g_signal_connect (G_OBJECT (buttons->right_slider), "button-release-event", G_CALLBACK (thunar_location_buttons_slider_button_release), buttons);
 
297
  g_signal_connect (G_OBJECT (buttons->right_slider), "clicked", G_CALLBACK (thunar_location_buttons_scroll_right), buttons);
 
298
  gtk_container_add (GTK_CONTAINER (buttons), buttons->right_slider);
 
299
  gtk_widget_show (buttons->right_slider);
 
300
 
 
301
  arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_OUT);
 
302
  gtk_container_add (GTK_CONTAINER (buttons->right_slider), arrow);
 
303
  gtk_widget_show (arrow);
 
304
}
 
305
 
 
306
 
 
307
 
 
308
static void
 
309
thunar_location_buttons_finalize (GObject *object)
 
310
{
 
311
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (object);
 
312
 
 
313
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
314
 
 
315
  /* disconnect from the selected files and the UI manager */
 
316
  thunar_component_set_selected_files (THUNAR_COMPONENT (buttons), NULL);
 
317
  thunar_component_set_ui_manager (THUNAR_COMPONENT (buttons), NULL);
 
318
 
 
319
  /* be sure to cancel the scrolling */
 
320
  thunar_location_buttons_stop_scrolling (buttons);
 
321
 
 
322
  /* release from the current_directory */
 
323
  thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (buttons), NULL);
 
324
 
 
325
  /* release our action group */
 
326
  g_object_unref (G_OBJECT (buttons->action_group));
 
327
 
 
328
  (*G_OBJECT_CLASS (thunar_location_buttons_parent_class)->finalize) (object);
 
329
}
 
330
 
 
331
 
 
332
 
 
333
static void
 
334
thunar_location_buttons_get_property (GObject    *object,
 
335
                                      guint       prop_id,
 
336
                                      GValue     *value,
 
337
                                      GParamSpec *pspec)
 
338
{
 
339
  switch (prop_id)
 
340
    {
 
341
    case PROP_CURRENT_DIRECTORY:
 
342
      g_value_set_object (value, thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (object)));
 
343
      break;
 
344
 
 
345
    case PROP_SELECTED_FILES:
 
346
      g_value_set_boxed (value, thunar_component_get_selected_files (THUNAR_COMPONENT (object)));
 
347
      break;
 
348
 
 
349
    case PROP_UI_MANAGER:
 
350
      g_value_set_object (value, thunar_component_get_ui_manager (THUNAR_COMPONENT (object)));
 
351
      break;
 
352
 
 
353
    default:
 
354
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
355
      break;
 
356
    }
 
357
}
 
358
 
 
359
 
 
360
 
 
361
static void
 
362
thunar_location_buttons_set_property (GObject      *object,
 
363
                                      guint         prop_id,
 
364
                                      const GValue *value,
 
365
                                      GParamSpec   *pspec)
 
366
{
 
367
  switch (prop_id)
 
368
    {
 
369
    case PROP_CURRENT_DIRECTORY:
 
370
      thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (object), g_value_get_object (value));
 
371
      break;
 
372
 
 
373
    case PROP_SELECTED_FILES:
 
374
      thunar_component_set_selected_files (THUNAR_COMPONENT (object), g_value_get_boxed (value));
 
375
      break;
 
376
 
 
377
    case PROP_UI_MANAGER:
 
378
      thunar_component_set_ui_manager (THUNAR_COMPONENT (object), g_value_get_object (value));
 
379
      break;
 
380
 
 
381
    default:
 
382
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
383
      break;
 
384
    }
 
385
}
 
386
 
 
387
 
 
388
 
 
389
static GtkUIManager*
 
390
thunar_location_buttons_get_ui_manager (ThunarComponent *component)
 
391
{
 
392
  return THUNAR_LOCATION_BUTTONS (component)->ui_manager;
 
393
}
 
394
 
 
395
 
 
396
 
 
397
static void
 
398
thunar_location_buttons_set_ui_manager (ThunarComponent *component,
 
399
                                        GtkUIManager    *ui_manager)
 
400
{
 
401
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (component);
 
402
  GError                *error = NULL;
 
403
 
 
404
  /* disconnect from the previous ui manager */
 
405
  if (G_UNLIKELY (buttons->ui_manager != NULL))
 
406
    {
 
407
      /* drop our action group from the previous UI manager */
 
408
      gtk_ui_manager_remove_action_group (buttons->ui_manager, buttons->action_group);
 
409
 
 
410
      /* unmerge our ui controls from the previous UI manager */
 
411
      gtk_ui_manager_remove_ui (buttons->ui_manager, buttons->ui_merge_id);
 
412
 
 
413
      /* drop our reference on the previous UI manager */
 
414
      g_object_unref (G_OBJECT (buttons->ui_manager));
 
415
    }
 
416
 
 
417
  /* activate the new UI manager */
 
418
  buttons->ui_manager = ui_manager;
 
419
 
 
420
  /* connect to the new UI manager */
 
421
  if (G_LIKELY (ui_manager != NULL))
 
422
    {
 
423
      /* we keep a reference on the new manager */
 
424
      g_object_ref (G_OBJECT (ui_manager));
 
425
 
 
426
      /* add our action group to the new manager */
 
427
      gtk_ui_manager_insert_action_group (ui_manager, buttons->action_group, -1);
 
428
 
 
429
      /* merge our UI control items with the new manager */
 
430
      buttons->ui_merge_id = gtk_ui_manager_add_ui_from_string (ui_manager, thunar_location_buttons_ui, thunar_location_buttons_ui_length, &error);
 
431
      if (G_UNLIKELY (buttons->ui_merge_id == 0))
 
432
        {
 
433
          g_error ("Failed to merge ThunarLocationButtons menus: %s", error->message);
 
434
          g_error_free (error);
 
435
        }
 
436
    }
 
437
 
 
438
  /* notify listeners */
 
439
  g_object_notify (G_OBJECT (buttons), "ui-manager");
 
440
}
 
441
 
 
442
 
 
443
 
 
444
static ThunarFile*
 
445
thunar_location_buttons_get_current_directory (ThunarNavigator *navigator)
 
446
{
 
447
  return THUNAR_LOCATION_BUTTONS (navigator)->current_directory;
 
448
}
 
449
 
 
450
 
 
451
 
 
452
static void
 
453
thunar_location_buttons_set_current_directory (ThunarNavigator *navigator,
 
454
                                               ThunarFile      *current_directory)
 
455
{
 
456
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (navigator);
 
457
  ThunarFile            *file_parent;
 
458
  ThunarFile            *file;
 
459
  GtkWidget             *button;
 
460
  GList                 *lp;
 
461
 
 
462
  _thunar_return_if_fail (current_directory == NULL || THUNAR_IS_FILE (current_directory));
 
463
 
 
464
  /* verify that we're not already using the new directory */
 
465
  if (G_UNLIKELY (buttons->current_directory == current_directory))
 
466
    return;
 
467
 
 
468
  /* check if we already have a button for that directory */
 
469
  for (lp = buttons->list; lp != NULL; lp = lp->next)
 
470
    if (thunar_location_button_get_file (lp->data) == current_directory)
 
471
      break;
 
472
 
 
473
  /* if we already have a button for that directory, just activate it */
 
474
  if (G_UNLIKELY (lp != NULL))
 
475
    {
 
476
      /* fake a "clicked" event for that button */
 
477
      thunar_location_button_clicked (THUNAR_LOCATION_BUTTON (lp->data));
 
478
    }
 
479
  else
 
480
    {
 
481
      /* regenerate the button list */
 
482
      if (G_LIKELY (buttons->current_directory != NULL))
 
483
        {
 
484
          g_object_unref (G_OBJECT (buttons->current_directory));
 
485
 
 
486
          /* remove all buttons */
 
487
          while (buttons->list != NULL)
 
488
            gtk_container_remove (GTK_CONTAINER (buttons), buttons->list->data);
 
489
 
 
490
          /* clear the first scrolled and fake root buttons */
 
491
          buttons->first_scrolled_button = NULL;
 
492
          buttons->fake_root_button = NULL;
 
493
        }
 
494
 
 
495
      buttons->current_directory = current_directory;
 
496
 
 
497
      if (G_LIKELY (current_directory != NULL))
 
498
        {
 
499
          g_object_ref (G_OBJECT (current_directory));
 
500
 
 
501
          gtk_widget_push_composite_child ();
 
502
 
 
503
          /* add the new buttons */
 
504
          for (file = current_directory; file != NULL; file = file_parent)
 
505
            {
 
506
              button = thunar_location_buttons_make_button (buttons, file);
 
507
              buttons->list = g_list_append (buttons->list, button);
 
508
              gtk_container_add (GTK_CONTAINER (buttons), button);
 
509
              gtk_widget_show (button);
 
510
 
 
511
              /* use 'Home' as fake root button */
 
512
              if (thunar_file_is_home (file))
 
513
                buttons->fake_root_button = g_list_last (buttons->list);
 
514
 
 
515
              /* continue with the parent (if any) */
 
516
              file_parent = thunar_file_get_parent (file, NULL);
 
517
 
 
518
              if (G_LIKELY (file != current_directory))
 
519
                g_object_unref (G_OBJECT (file));
 
520
            }
 
521
 
 
522
          gtk_widget_pop_composite_child ();
 
523
        }
 
524
    }
 
525
 
 
526
  g_object_notify (G_OBJECT (buttons), "current-directory");
 
527
}
 
528
 
 
529
 
 
530
 
 
531
static void
 
532
thunar_location_buttons_unmap (GtkWidget *widget)
 
533
{
 
534
  /* be sure to stop the scroll timer before the buttons are unmapped */
 
535
  thunar_location_buttons_stop_scrolling (THUNAR_LOCATION_BUTTONS (widget));
 
536
 
 
537
  /* do the real unmap */
 
538
  (*GTK_WIDGET_CLASS (thunar_location_buttons_parent_class)->unmap) (widget);
 
539
}
 
540
 
 
541
 
 
542
 
 
543
static void
 
544
thunar_location_buttons_size_request (GtkWidget      *widget,
 
545
                                      GtkRequisition *requisition)
 
546
{
 
547
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (widget);
 
548
  GtkRequisition         child_requisition;
 
549
  GList                 *lp;
 
550
  gint                   spacing;
 
551
 
 
552
  gtk_widget_style_get (GTK_WIDGET (buttons),
 
553
                        "spacing", &spacing,
 
554
                        NULL);
 
555
 
 
556
  requisition->width = 0;
 
557
  requisition->height = 0;
 
558
 
 
559
  /* calculate the size of the biggest button */
 
560
  for (lp = buttons->list; lp != NULL; lp = lp->next)
 
561
    {
 
562
      gtk_widget_size_request (GTK_WIDGET (lp->data), &child_requisition);
 
563
      requisition->width = MAX (child_requisition.width, requisition->width);
 
564
      requisition->height = MAX (child_requisition.height, requisition->height);
 
565
    }
 
566
 
 
567
  /* add space for the sliders if we have more than one path */
 
568
  buttons->slider_width = MIN (requisition->height * 2 / 3 + 5, requisition->height);
 
569
  if (buttons->list != NULL && buttons->list->next != NULL)
 
570
    requisition->width += (spacing + buttons->slider_width) * 2;
 
571
 
 
572
  gtk_widget_size_request (buttons->left_slider, &child_requisition);
 
573
  gtk_widget_size_request (buttons->right_slider, &child_requisition);
 
574
 
 
575
  requisition->width += GTK_CONTAINER (widget)->border_width * 2;
 
576
  requisition->height += GTK_CONTAINER (widget)->border_width * 2;
 
577
 
 
578
  widget->requisition = *requisition;
 
579
}
 
580
 
 
581
 
 
582
 
 
583
static void
 
584
thunar_location_buttons_size_allocate (GtkWidget     *widget,
 
585
                                       GtkAllocation *allocation)
 
586
{
 
587
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (widget);
 
588
  GtkTextDirection       direction;
 
589
  GtkAllocation          child_allocation;
 
590
  GtkWidget             *child;
 
591
  gboolean               need_sliders = FALSE;
 
592
  gboolean               reached_end;
 
593
  GList                 *first_button;
 
594
  GList                 *lp;
 
595
  gint                   left_slider_offset = 0;
 
596
  gint                   right_slider_offset = 0;
 
597
  gint                   allocation_width;
 
598
  gint                   border_width;
 
599
  gint                   slider_space;
 
600
  gint                   spacing;
 
601
  gint                   width;
 
602
 
 
603
  widget->allocation = *allocation;
 
604
 
 
605
  /* if no path is set, we don't have to allocate anything */
 
606
  if (G_UNLIKELY (buttons->list == NULL))
 
607
    return;
 
608
 
 
609
  gtk_widget_style_get (GTK_WIDGET (buttons), "spacing", &spacing, NULL);
 
610
 
 
611
  direction = gtk_widget_get_direction (widget);
 
612
  border_width = GTK_CONTAINER (buttons)->border_width;
 
613
  allocation_width = allocation->width - 2 * border_width;
 
614
 
 
615
  /* check if we need to display the sliders */
 
616
  if (G_LIKELY (buttons->fake_root_button != NULL))
 
617
    width = buttons->slider_width + spacing;
 
618
  else
 
619
    width = 0;
 
620
 
 
621
  for (lp = buttons->list; lp != NULL; lp = lp->next)
 
622
    {
 
623
      width += GTK_WIDGET (lp->data)->requisition.width + spacing;
 
624
      if (lp == buttons->fake_root_button)
 
625
        break;
 
626
    }
 
627
 
 
628
  if (width <= allocation_width)
 
629
    {
 
630
      if (G_LIKELY (buttons->fake_root_button != NULL))
 
631
        first_button = buttons->fake_root_button;
 
632
      else
 
633
        first_button = g_list_last (buttons->list);
 
634
    }
 
635
  else
 
636
    {
 
637
      slider_space = 2 * (spacing + buttons->slider_width);
 
638
 
 
639
      if (buttons->first_scrolled_button != NULL)
 
640
        first_button = buttons->first_scrolled_button;
 
641
      else
 
642
        first_button = buttons->list;
 
643
      need_sliders = TRUE;
 
644
 
 
645
      /* To see how much space we have, and how many buttons we can display.
 
646
       * We start at the first button, count forward until hit the new
 
647
       * button, then count backwards.
 
648
       */
 
649
      width = GTK_WIDGET (first_button->data)->requisition.width;
 
650
      for (lp = first_button->prev, reached_end = FALSE; lp != NULL && !reached_end; lp = lp->prev)
 
651
        {
 
652
          child = lp->data;
 
653
          if (width + child->requisition.width + spacing + slider_space > allocation_width)
 
654
            reached_end = TRUE;
 
655
          else if (lp == buttons->fake_root_button)
 
656
            break;
 
657
          else
 
658
            width += child->requisition.width + spacing;
 
659
        }
 
660
 
 
661
      while (first_button->next != NULL && !reached_end)
 
662
        {
 
663
          child = first_button->data;
 
664
          if (width + child->requisition.width + spacing + slider_space > allocation_width)
 
665
            {
 
666
              reached_end = TRUE;
 
667
            }
 
668
          else
 
669
            {
 
670
              width += child->requisition.width + spacing;
 
671
              if (first_button == buttons->fake_root_button)
 
672
                break;
 
673
              first_button = first_button->next;
 
674
            }
 
675
        }
 
676
    }
 
677
 
 
678
  /* Now we allocate space to the buttons */
 
679
  child_allocation.y = allocation->y + border_width;
 
680
  child_allocation.height = MAX (1, allocation->height - border_width * 2);
 
681
 
 
682
  if (G_UNLIKELY (direction == GTK_TEXT_DIR_RTL))
 
683
    {
 
684
      child_allocation.x = allocation->x + allocation->width - border_width;
 
685
      if (need_sliders || buttons->fake_root_button != NULL)
 
686
        {
 
687
          child_allocation.x -= spacing + buttons->slider_width;
 
688
          left_slider_offset = allocation->width - border_width - buttons->slider_width;
 
689
        }
 
690
    }
 
691
  else
 
692
    {
 
693
      child_allocation.x = allocation->x + border_width;
 
694
      if (need_sliders || buttons->fake_root_button != NULL)
 
695
        {
 
696
          left_slider_offset = border_width;
 
697
          child_allocation.x += spacing + buttons->slider_width;
 
698
        }
 
699
    }
 
700
 
 
701
  for (lp = first_button; lp != NULL; lp = lp->prev)
 
702
    {
 
703
      child = lp->data;
 
704
 
 
705
      child_allocation.width = child->requisition.width;
 
706
      if (G_UNLIKELY (direction == GTK_TEXT_DIR_RTL))
 
707
        child_allocation.x -= child_allocation.width;
 
708
 
 
709
      /* check to see if we don't have any more space to allocate buttons */
 
710
      if (need_sliders && direction == GTK_TEXT_DIR_RTL)
 
711
        {
 
712
          if (child_allocation.x - spacing - buttons->slider_width < widget->allocation.x + border_width)
 
713
            break;
 
714
        }
 
715
      else if (need_sliders && direction == GTK_TEXT_DIR_LTR)
 
716
        {
 
717
          if (child_allocation.x + child_allocation.width + spacing + buttons->slider_width > widget->allocation.x + border_width + allocation_width)
 
718
            break;
 
719
        }
 
720
 
 
721
      gtk_widget_set_child_visible (GTK_WIDGET (lp->data), TRUE);
 
722
      gtk_widget_size_allocate (child, &child_allocation);
 
723
 
 
724
      if (direction == GTK_TEXT_DIR_RTL)
 
725
        {
 
726
          child_allocation.x -= spacing;
 
727
          right_slider_offset = border_width;
 
728
        }
 
729
      else
 
730
        {
 
731
          child_allocation.x += child_allocation.width + spacing;
 
732
          right_slider_offset = allocation->width - border_width - buttons->slider_width;
 
733
        }
 
734
    }
 
735
 
 
736
  /* now we go hide all the buttons that don't fit */
 
737
  for (; lp != NULL; lp = lp->prev)
 
738
    gtk_widget_set_child_visible (GTK_WIDGET (lp->data), FALSE);
 
739
  for (lp = first_button->next; lp != NULL; lp = lp->next)
 
740
    gtk_widget_set_child_visible (GTK_WIDGET (lp->data), FALSE);
 
741
 
 
742
  if (need_sliders || buttons->fake_root_button != NULL)
 
743
    {
 
744
      child_allocation.width = buttons->slider_width;
 
745
      child_allocation.x = left_slider_offset + allocation->x;
 
746
      gtk_widget_size_allocate (buttons->left_slider, &child_allocation);
 
747
      gtk_widget_set_child_visible (buttons->left_slider, TRUE);
 
748
      gtk_widget_show_all (buttons->left_slider);
 
749
 
 
750
      thunar_location_buttons_update_sliders (buttons);
 
751
    }
 
752
  else
 
753
    {
 
754
      gtk_widget_set_child_visible (buttons->left_slider, FALSE);
 
755
    }
 
756
 
 
757
  if (need_sliders)
 
758
    {
 
759
      child_allocation.width = buttons->slider_width;
 
760
      child_allocation.x = right_slider_offset + allocation->x;
 
761
      gtk_widget_size_allocate (buttons->right_slider, &child_allocation);
 
762
      gtk_widget_set_child_visible (buttons->right_slider, TRUE);
 
763
      gtk_widget_show_all (buttons->right_slider);
 
764
 
 
765
      thunar_location_buttons_update_sliders (buttons);
 
766
    }
 
767
  else
 
768
    {
 
769
      gtk_widget_set_child_visible (buttons->right_slider, FALSE);
 
770
    }
 
771
}
 
772
 
 
773
 
 
774
 
 
775
static void
 
776
thunar_location_buttons_state_changed (GtkWidget   *widget,
 
777
                                       GtkStateType previous_state)
 
778
{
 
779
  if (!gtk_widget_is_sensitive (widget))
 
780
    thunar_location_buttons_stop_scrolling (THUNAR_LOCATION_BUTTONS (widget));
 
781
}
 
782
 
 
783
 
 
784
 
 
785
static void
 
786
thunar_location_buttons_grab_notify (GtkWidget *widget,
 
787
                                     gboolean   was_grabbed)
 
788
{
 
789
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (widget);
 
790
 
 
791
  if (!was_grabbed)
 
792
    thunar_location_buttons_stop_scrolling (buttons);
 
793
}
 
794
 
 
795
 
 
796
 
 
797
static void
 
798
thunar_location_buttons_add (GtkContainer *container,
 
799
                             GtkWidget    *widget)
 
800
{
 
801
  gtk_widget_set_parent (widget, GTK_WIDGET (container));
 
802
}
 
803
 
 
804
 
 
805
 
 
806
static void
 
807
thunar_location_buttons_remove (GtkContainer *container,
 
808
                                GtkWidget    *widget)
 
809
{
 
810
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (container);
 
811
  GList                 *lp;
 
812
 
 
813
  if (widget == buttons->left_slider)
 
814
    {
 
815
      thunar_location_buttons_remove_1 (container, widget);
 
816
      buttons->left_slider = NULL;
 
817
      return;
 
818
    }
 
819
  else if (widget == buttons->right_slider)
 
820
    {
 
821
      thunar_location_buttons_remove_1 (container, widget);
 
822
      buttons->right_slider = NULL;
 
823
      return;
 
824
    }
 
825
 
 
826
  for (lp = buttons->list; lp != NULL; lp = lp->next)
 
827
    if (widget == GTK_WIDGET (lp->data))
 
828
      {
 
829
        thunar_location_buttons_remove_1 (container, widget);
 
830
        buttons->list = g_list_remove_link (buttons->list, lp);
 
831
        g_list_free (lp);
 
832
        return;
 
833
      }
 
834
}
 
835
 
 
836
 
 
837
 
 
838
static void
 
839
thunar_location_buttons_forall (GtkContainer *container,
 
840
                                gboolean      include_internals,
 
841
                                GtkCallback   callback,
 
842
                                gpointer      callback_data)
 
843
{
 
844
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (container);
 
845
  GtkWidget             *child;
 
846
  GList                 *lp;
 
847
 
 
848
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
849
  _thunar_return_if_fail (callback != NULL);
 
850
 
 
851
  for (lp = buttons->list; lp != NULL; )
 
852
    {
 
853
      child = GTK_WIDGET (lp->data);
 
854
      lp = lp->next;
 
855
 
 
856
      (*callback) (child, callback_data);
 
857
    }
 
858
 
 
859
  if (buttons->left_slider != NULL && include_internals)
 
860
    (*callback) (buttons->left_slider, callback_data);
 
861
 
 
862
  if (buttons->right_slider != NULL && include_internals)
 
863
    (*callback) (buttons->right_slider, callback_data);
 
864
}
 
865
 
 
866
 
 
867
 
 
868
static GtkWidget*
 
869
thunar_location_buttons_make_button (ThunarLocationButtons *buttons,
 
870
                                     ThunarFile            *file)
 
871
{
 
872
  GtkWidget *button;
 
873
 
 
874
  /* allocate the button */
 
875
  button = thunar_location_button_new ();
 
876
 
 
877
  /* connect to the file */
 
878
  thunar_location_button_set_file (THUNAR_LOCATION_BUTTON (button), file);
 
879
 
 
880
  /* the current directory is active */
 
881
  thunar_location_button_set_active (THUNAR_LOCATION_BUTTON (button), (file == buttons->current_directory));
 
882
 
 
883
  /* connect signal handlers */
 
884
  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (thunar_location_buttons_clicked), buttons);
 
885
  g_signal_connect (G_OBJECT (button), "gone", G_CALLBACK (thunar_location_buttons_gone), buttons);
 
886
  g_signal_connect (G_OBJECT (button), "context-menu", G_CALLBACK (thunar_location_buttons_context_menu), buttons);
 
887
 
 
888
  return button;
 
889
}
 
890
 
 
891
 
 
892
 
 
893
static void
 
894
thunar_location_buttons_remove_1 (GtkContainer *container,
 
895
                                  GtkWidget    *widget)
 
896
{
 
897
  gboolean need_resize = gtk_widget_get_visible (widget);
 
898
  gtk_widget_unparent (widget);
 
899
  if (G_LIKELY (need_resize))
 
900
    gtk_widget_queue_resize (GTK_WIDGET (container));
 
901
}
 
902
 
 
903
 
 
904
 
 
905
static gboolean
 
906
thunar_location_buttons_scroll_timeout (gpointer user_data)
 
907
{
 
908
  ThunarLocationButtons *buttons = THUNAR_LOCATION_BUTTONS (user_data);
 
909
 
 
910
  GDK_THREADS_ENTER ();
 
911
 
 
912
  if (gtk_widget_has_focus (buttons->left_slider))
 
913
    thunar_location_buttons_scroll_left (buttons->left_slider, buttons);
 
914
  else if (gtk_widget_has_focus (buttons->right_slider))
 
915
    thunar_location_buttons_scroll_right (buttons->right_slider, buttons);
 
916
 
 
917
  GDK_THREADS_LEAVE ();
 
918
 
 
919
  return TRUE;
 
920
}
 
921
 
 
922
 
 
923
 
 
924
static void
 
925
thunar_location_buttons_scroll_timeout_destroy (gpointer user_data)
 
926
{
 
927
  THUNAR_LOCATION_BUTTONS (user_data)->scroll_timeout_id = 0;
 
928
}
 
929
 
 
930
 
 
931
 
 
932
static void
 
933
thunar_location_buttons_stop_scrolling (ThunarLocationButtons *buttons)
 
934
{
 
935
  if (buttons->scroll_timeout_id != 0)
 
936
    g_source_remove (buttons->scroll_timeout_id);
 
937
}
 
938
 
 
939
 
 
940
 
 
941
static void
 
942
thunar_location_buttons_update_sliders (ThunarLocationButtons *buttons)
 
943
{
 
944
  GtkWidget *button;
 
945
 
 
946
  if (G_LIKELY (buttons->list != NULL))
 
947
    {
 
948
      button = GTK_WIDGET (buttons->list->data);
 
949
      if (gtk_widget_get_child_visible (button))
 
950
        {
 
951
          gtk_widget_set_sensitive (buttons->right_slider, FALSE);
 
952
          thunar_location_buttons_stop_scrolling (buttons);
 
953
        }
 
954
      else
 
955
        {
 
956
          gtk_widget_set_sensitive (buttons->right_slider, TRUE);
 
957
        }
 
958
 
 
959
      button = GTK_WIDGET (g_list_last (buttons->list)->data);
 
960
      if (gtk_widget_get_child_visible (button) && buttons->fake_root_button == NULL)
 
961
        {
 
962
          gtk_widget_set_sensitive (buttons->left_slider, FALSE);
 
963
          thunar_location_buttons_stop_scrolling (buttons);
 
964
        }
 
965
      else
 
966
        {
 
967
          gtk_widget_set_sensitive (buttons->left_slider, TRUE);
 
968
        }
 
969
    }
 
970
}
 
971
 
 
972
 
 
973
 
 
974
static gboolean
 
975
thunar_location_buttons_slider_button_press (GtkWidget             *button,
 
976
                                             GdkEventButton        *event,
 
977
                                             ThunarLocationButtons *buttons)
 
978
{
 
979
  if (!gtk_widget_has_focus (button))
 
980
    gtk_widget_grab_focus (button);
 
981
 
 
982
  if (event->type != GDK_BUTTON_PRESS || event->button != 1)
 
983
    return FALSE;
 
984
 
 
985
  buttons->ignore_click = FALSE;
 
986
 
 
987
  if (button == buttons->left_slider)
 
988
    thunar_location_buttons_scroll_left (button, buttons);
 
989
  else if (button == buttons->right_slider)
 
990
    thunar_location_buttons_scroll_right (button, buttons);
 
991
 
 
992
  if (G_LIKELY (buttons->scroll_timeout_id == 0))
 
993
    {
 
994
      buttons->scroll_timeout_id = g_timeout_add_full (G_PRIORITY_LOW, THUNAR_LOCATION_BUTTONS_SCROLL_TIMEOUT,
 
995
                                                       thunar_location_buttons_scroll_timeout, buttons,
 
996
                                                       thunar_location_buttons_scroll_timeout_destroy);
 
997
    }
 
998
 
 
999
  return FALSE;
 
1000
}
 
1001
 
 
1002
 
 
1003
 
 
1004
static gboolean
 
1005
thunar_location_buttons_slider_button_release (GtkWidget             *button,
 
1006
                                               GdkEventButton        *event,
 
1007
                                               ThunarLocationButtons *buttons)
 
1008
{
 
1009
  if (event->type == GDK_BUTTON_RELEASE)
 
1010
    {
 
1011
      thunar_location_buttons_stop_scrolling (buttons);
 
1012
      buttons->ignore_click = TRUE;
 
1013
    }
 
1014
 
 
1015
  return FALSE;
 
1016
}
 
1017
 
 
1018
 
 
1019
 
 
1020
static void
 
1021
thunar_location_buttons_scroll_left (GtkWidget             *button,
 
1022
                                     ThunarLocationButtons *buttons)
 
1023
{
 
1024
  GList *lp;
 
1025
 
 
1026
  if (G_UNLIKELY (buttons->ignore_click))
 
1027
    {
 
1028
      buttons->ignore_click = FALSE;
 
1029
      return;
 
1030
    }
 
1031
 
 
1032
  gtk_widget_queue_resize (GTK_WIDGET (buttons));
 
1033
 
 
1034
  for (lp = g_list_last (buttons->list); lp != NULL; lp = lp->prev)
 
1035
    if (lp->prev != NULL && gtk_widget_get_child_visible (GTK_WIDGET (lp->prev->data)))
 
1036
      {
 
1037
        if (lp->prev == buttons->fake_root_button)
 
1038
          buttons->fake_root_button = NULL;
 
1039
        buttons->first_scrolled_button = lp;
 
1040
        break;
 
1041
      }
 
1042
}
 
1043
 
 
1044
 
 
1045
 
 
1046
static void
 
1047
thunar_location_buttons_scroll_right (GtkWidget             *button,
 
1048
                                      ThunarLocationButtons *buttons)
 
1049
{
 
1050
  GtkTextDirection direction;
 
1051
  GList           *right_button = NULL;
 
1052
  GList           *left_button = NULL;
 
1053
  GList           *lp;
 
1054
  gint             space_available;
 
1055
  gint             space_needed;
 
1056
  gint             border_width;
 
1057
  gint             spacing;
 
1058
 
 
1059
  if (G_UNLIKELY (buttons->ignore_click))
 
1060
    {
 
1061
      buttons->ignore_click = FALSE;
 
1062
      return;
 
1063
    }
 
1064
 
 
1065
  gtk_widget_style_get (GTK_WIDGET (buttons),
 
1066
                        "spacing", &spacing,
 
1067
                        NULL);
 
1068
 
 
1069
  gtk_widget_queue_resize (GTK_WIDGET (buttons));
 
1070
 
 
1071
  border_width = GTK_CONTAINER (buttons)->border_width;
 
1072
  direction = gtk_widget_get_direction (GTK_WIDGET (buttons));
 
1073
 
 
1074
  /* find the button at the 'right' end that we have to make visible */
 
1075
  for (lp = buttons->list; lp != NULL; lp = lp->next)
 
1076
    if (lp->next != NULL && gtk_widget_get_child_visible (GTK_WIDGET (lp->next->data)))
 
1077
      {
 
1078
        right_button = lp;
 
1079
        break;
 
1080
      }
 
1081
 
 
1082
  /* find the last visible button on the 'left' end */
 
1083
  for (lp = g_list_last (buttons->list); lp != NULL; lp = lp->prev)
 
1084
    if (gtk_widget_get_child_visible (GTK_WIDGET (lp->data)))
 
1085
      {
 
1086
        left_button = lp;
 
1087
        break;
 
1088
      }
 
1089
 
 
1090
  space_needed = GTK_WIDGET (right_button->data)->allocation.width + spacing;
 
1091
  if (direction == GTK_TEXT_DIR_RTL)
 
1092
    {
 
1093
      space_available = buttons->right_slider->allocation.x - GTK_WIDGET (buttons)->allocation.x;
 
1094
    }
 
1095
  else
 
1096
    {
 
1097
      space_available = (GTK_WIDGET (buttons)->allocation.x + GTK_WIDGET (buttons)->allocation.width - border_width)
 
1098
                      - (buttons->right_slider->allocation.x + buttons->right_slider->allocation.width);
 
1099
    }
 
1100
 
 
1101
  /* We have space_available extra space that's not being used.  We
 
1102
   * need space_needed space to make the button fit.  So we walk down
 
1103
   * from the end, removing buttons until we get all the space we
 
1104
   * need.
 
1105
   */
 
1106
  while (space_available < space_needed)
 
1107
    {
 
1108
      space_available += GTK_WIDGET (left_button->data)->allocation.width + spacing;
 
1109
      left_button = left_button->prev;
 
1110
      buttons->first_scrolled_button = left_button;
 
1111
    }
 
1112
}
 
1113
 
 
1114
 
 
1115
 
 
1116
static void
 
1117
thunar_location_buttons_clicked (ThunarLocationButton  *button,
 
1118
                                 gboolean               open_in_tab,
 
1119
                                 ThunarLocationButtons *buttons)
 
1120
{
 
1121
  ThunarFile *directory;
 
1122
  GList      *lp;
 
1123
 
 
1124
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTON (button));
 
1125
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1126
 
 
1127
  /* determine the directory associated with the clicked button */
 
1128
  directory = thunar_location_button_get_file (button);
 
1129
 
 
1130
  /* open in tab */
 
1131
  if (open_in_tab)
 
1132
    {
 
1133
      thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (buttons), directory);
 
1134
      return;
 
1135
    }
 
1136
 
 
1137
  /* disconnect from previous current directory (if any) */
 
1138
  if (G_LIKELY (buttons->current_directory != NULL))
 
1139
    g_object_unref (G_OBJECT (buttons->current_directory));
 
1140
 
 
1141
  /* setup the new current directory */
 
1142
  buttons->current_directory = directory;
 
1143
 
 
1144
  /* take a reference on the new directory (if any) */
 
1145
  if (G_LIKELY (directory != NULL))
 
1146
    g_object_ref (G_OBJECT (directory));
 
1147
 
 
1148
  /* check if the button is visible on the button bar */
 
1149
  if (!gtk_widget_get_child_visible (GTK_WIDGET (button)))
 
1150
    {
 
1151
      /* scroll to the button */
 
1152
      buttons->first_scrolled_button = g_list_find (buttons->list, button);
 
1153
      gtk_widget_queue_resize (GTK_WIDGET (buttons));
 
1154
 
 
1155
      /* we may need to reset the fake_root_button */
 
1156
      if (G_LIKELY (buttons->fake_root_button != NULL))
 
1157
        {
 
1158
          /* check if the fake_root_button is before the first_scrolled_button (from right to left) */
 
1159
          for (lp = buttons->list; lp != NULL && lp != buttons->first_scrolled_button; lp = lp->next)
 
1160
            if (lp == buttons->fake_root_button)
 
1161
              {
 
1162
                /* reset the fake_root_button */
 
1163
                buttons->fake_root_button = NULL;
 
1164
                break;
 
1165
              }
 
1166
        }
 
1167
    }
 
1168
 
 
1169
  /* update all buttons */
 
1170
  for (lp = buttons->list; lp != NULL; lp = lp->next)
 
1171
    {
 
1172
      /* determine the directory for this button */
 
1173
      button = THUNAR_LOCATION_BUTTON (lp->data);
 
1174
      directory = thunar_location_button_get_file (button);
 
1175
 
 
1176
      /* update the location button state (making sure to not recurse with the "clicked" handler) */
 
1177
      g_signal_handlers_block_by_func (G_OBJECT (button), thunar_location_buttons_clicked, buttons);
 
1178
      thunar_location_button_set_active (button, directory == buttons->current_directory);
 
1179
      g_signal_handlers_unblock_by_func (G_OBJECT (button), thunar_location_buttons_clicked, buttons);
 
1180
    }
 
1181
 
 
1182
  /* notify the surrounding module that we want to change to a different directory.  */
 
1183
  thunar_navigator_change_directory (THUNAR_NAVIGATOR (buttons), buttons->current_directory);
 
1184
}
 
1185
 
 
1186
 
 
1187
 
 
1188
static void
 
1189
thunar_location_buttons_gone (ThunarLocationButton  *button,
 
1190
                              ThunarLocationButtons *buttons)
 
1191
{
 
1192
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTON (button));
 
1193
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1194
  _thunar_return_if_fail (g_list_find (buttons->list, button) != NULL);
 
1195
 
 
1196
  /* drop all buttons up to the button that emitted the "gone" signal */
 
1197
  while (buttons->list->data != button)
 
1198
    gtk_widget_destroy (buttons->list->data);
 
1199
 
 
1200
  /* drop the button itself */
 
1201
  gtk_widget_destroy (GTK_WIDGET (button));
 
1202
}
 
1203
 
 
1204
 
 
1205
 
 
1206
static void
 
1207
thunar_location_buttons_context_menu (ThunarLocationButton  *button,
 
1208
                                      GdkEventButton        *event,
 
1209
                                      ThunarLocationButtons *buttons)
 
1210
{
 
1211
  ThunarClipboardManager *clipboard;
 
1212
  const gchar            *display_name;
 
1213
  ThunarFile             *file;
 
1214
  GtkAction              *action;
 
1215
  GtkWidget              *menu;
 
1216
 
 
1217
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1218
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTON (button));
 
1219
 
 
1220
  /* determine the file for the button */
 
1221
  file = thunar_location_button_get_file (button);
 
1222
  if (G_LIKELY (file != NULL))
 
1223
    {
 
1224
      /* we cannot popup the context menu without an ui manager */
 
1225
      if (G_LIKELY (buttons->ui_manager != NULL))
 
1226
        {
 
1227
          /* determine the display name of the file */
 
1228
          display_name = thunar_file_get_display_name (file);
 
1229
 
 
1230
          /* be sure to keep a reference on the navigation bar */
 
1231
          g_object_ref (G_OBJECT (buttons));
 
1232
 
 
1233
          /* grab a reference on the clipboard manager for this display */
 
1234
          clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (GTK_WIDGET (buttons)));
 
1235
 
 
1236
          /* setup the "Open" action */
 
1237
          action = gtk_action_group_get_action (buttons->action_group, "location-buttons-open");
 
1238
          thunar_gtk_action_set_tooltip (action, _("Open \"%s\" in this window"), display_name);
 
1239
          g_object_set_qdata_full (G_OBJECT (action), thunar_file_quark, g_object_ref (G_OBJECT (file)), (GDestroyNotify) g_object_unref);
 
1240
          gtk_action_set_sensitive (action, (file != buttons->current_directory));
 
1241
 
 
1242
          /* setup the "Open in New Window" action */
 
1243
          action = gtk_action_group_get_action (buttons->action_group, "location-buttons-open-in-new-window");
 
1244
          thunar_gtk_action_set_tooltip (action, _("Open \"%s\" in a new window"), display_name);
 
1245
          g_object_set_qdata_full (G_OBJECT (action), thunar_file_quark, g_object_ref (G_OBJECT (file)), (GDestroyNotify) g_object_unref);
 
1246
 
 
1247
          /* setup the "Open in New Tab" action */
 
1248
          action = gtk_action_group_get_action (buttons->action_group, "location-buttons-open-in-new-tab");
 
1249
          thunar_gtk_action_set_tooltip (action, _("Open \"%s\" in a new tab"), display_name);
 
1250
          g_object_set_qdata_full (G_OBJECT (action), thunar_file_quark, g_object_ref (G_OBJECT (file)), (GDestroyNotify) g_object_unref);
 
1251
 
 
1252
          /* setup the "Create Folder..." action */
 
1253
          action = gtk_action_group_get_action (buttons->action_group, "location-buttons-create-folder");
 
1254
          thunar_gtk_action_set_tooltip (action, _("Create a new folder in \"%s\""), display_name);
 
1255
          g_object_set_qdata_full (G_OBJECT (action), thunar_file_quark, g_object_ref (G_OBJECT (file)), (GDestroyNotify) g_object_unref);
 
1256
          gtk_action_set_sensitive (action, thunar_file_is_writable (file));
 
1257
          gtk_action_set_visible (action, !thunar_file_is_trashed (file));
 
1258
 
 
1259
          /* setup the "Empty Trash" action */
 
1260
          action = gtk_action_group_get_action (buttons->action_group, "location-buttons-empty-trash");
 
1261
          gtk_action_set_visible (action, (thunar_file_is_root (file) && thunar_file_is_trashed (file)));
 
1262
          gtk_action_set_sensitive (action, (thunar_file_get_size (file) > 0));
 
1263
 
 
1264
          /* setup the "Paste Into Folder" action */
 
1265
          action = gtk_action_group_get_action (buttons->action_group, "location-buttons-paste-into-folder");
 
1266
          thunar_gtk_action_set_tooltip (action, _("Move or copy files previously selected by a Cut or Copy command into \"%s\""), display_name);
 
1267
          g_object_set_qdata_full (G_OBJECT (action), thunar_file_quark, g_object_ref (G_OBJECT (file)), (GDestroyNotify) g_object_unref);
 
1268
          gtk_action_set_sensitive (action, thunar_clipboard_manager_get_can_paste (clipboard));
 
1269
 
 
1270
          /* setup the "Properties..." action */
 
1271
          action = gtk_action_group_get_action (buttons->action_group, "location-buttons-properties");
 
1272
          thunar_gtk_action_set_tooltip (action, _("View the properties of the folder \"%s\""), display_name);
 
1273
          g_object_set_qdata_full (G_OBJECT (action), thunar_file_quark, g_object_ref (G_OBJECT (file)), (GDestroyNotify) g_object_unref);
 
1274
 
 
1275
          /* run the menu on the screen on the buttons' screen */
 
1276
          menu = gtk_ui_manager_get_widget (buttons->ui_manager, "/location-buttons-context-menu");
 
1277
          thunar_gtk_menu_run (GTK_MENU (menu), GTK_WIDGET (buttons), NULL, NULL, event->button, event->time);
 
1278
 
 
1279
          /* cleanup */
 
1280
          g_object_unref (G_OBJECT (buttons));
 
1281
          g_object_unref (G_OBJECT (clipboard));
 
1282
        }
 
1283
    }
 
1284
}
 
1285
 
 
1286
 
 
1287
 
 
1288
static void
 
1289
thunar_location_buttons_action_create_folder (GtkAction             *action,
 
1290
                                              ThunarLocationButtons *buttons)
 
1291
{
 
1292
  ThunarApplication *application;
 
1293
  ThunarFile        *directory;
 
1294
  GList              path_list;
 
1295
  gchar             *name;
 
1296
 
 
1297
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1298
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1299
 
 
1300
  /* determine the directory for the action */
 
1301
  directory = g_object_get_qdata (G_OBJECT (action), thunar_file_quark);
 
1302
  if (G_UNLIKELY (directory == NULL))
 
1303
    return;
 
1304
 
 
1305
  /* ask the user to enter a name for the new folder */
 
1306
  name = thunar_show_create_dialog (GTK_WIDGET (buttons), 
 
1307
                                    "inode/directory", 
 
1308
                                    _("New Folder"), 
 
1309
                                    _("Create New Folder"));
 
1310
  if (G_LIKELY (name != NULL))
 
1311
    {
 
1312
      /* fake the path list */
 
1313
      path_list.data = g_file_resolve_relative_path (thunar_file_get_file (directory), name);
 
1314
      path_list.next = path_list.prev = NULL;
 
1315
 
 
1316
      /* launch the operation */
 
1317
      application = thunar_application_get ();
 
1318
      thunar_application_mkdir (application, GTK_WIDGET (buttons), &path_list, NULL);
 
1319
      g_object_unref (G_OBJECT (application));
 
1320
 
 
1321
      /* release the path */
 
1322
      g_object_unref (path_list.data);
 
1323
 
 
1324
      /* release the file name */
 
1325
      g_free (name);
 
1326
    }
 
1327
}
 
1328
 
 
1329
 
 
1330
 
 
1331
static void
 
1332
thunar_location_buttons_action_down_folder (GtkAction             *action,
 
1333
                                            ThunarLocationButtons *buttons)
 
1334
{
 
1335
  GList *lp;
 
1336
 
 
1337
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1338
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1339
 
 
1340
  /* lookup the active button */
 
1341
  for (lp = buttons->list; lp != NULL; lp = lp->next)
 
1342
    if (thunar_location_button_get_active (lp->data))
 
1343
      {
 
1344
        /* check if we have a folder below that one */
 
1345
        if (G_LIKELY (lp->prev != NULL))
 
1346
          {
 
1347
            /* enter that folder */
 
1348
            thunar_location_button_clicked (lp->prev->data);
 
1349
          }
 
1350
 
 
1351
        break;
 
1352
      }
 
1353
}
 
1354
 
 
1355
 
 
1356
 
 
1357
static void
 
1358
thunar_location_buttons_action_empty_trash (GtkAction             *action,
 
1359
                                            ThunarLocationButtons *buttons)
 
1360
{
 
1361
  ThunarApplication *application;
 
1362
 
 
1363
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1364
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1365
 
 
1366
  /* launch the operation */
 
1367
  application = thunar_application_get ();
 
1368
  thunar_application_empty_trash (application, GTK_WIDGET (buttons), NULL);
 
1369
  g_object_unref (G_OBJECT (application));
 
1370
}
 
1371
 
 
1372
 
 
1373
 
 
1374
static void
 
1375
thunar_location_buttons_action_open (GtkAction             *action,
 
1376
                                     ThunarLocationButtons *buttons)
 
1377
{
 
1378
  ThunarFile *directory;
 
1379
 
 
1380
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1381
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1382
 
 
1383
  /* determine the directory for the action */
 
1384
  directory = g_object_get_qdata (G_OBJECT (action), thunar_file_quark);
 
1385
  if (G_LIKELY (directory != NULL && thunar_file_is_directory (directory)))
 
1386
    {
 
1387
      /* open the folder in this window */
 
1388
      thunar_navigator_change_directory (THUNAR_NAVIGATOR (buttons), directory);
 
1389
    }
 
1390
}
 
1391
 
 
1392
 
 
1393
 
 
1394
static void
 
1395
thunar_location_buttons_action_open_in_new_tab (GtkAction             *action,
 
1396
                                                ThunarLocationButtons *buttons)
 
1397
{
 
1398
  ThunarFile *directory;
 
1399
 
 
1400
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1401
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1402
 
 
1403
  /* determine the directory for the action */
 
1404
  directory = g_object_get_qdata (G_OBJECT (action), thunar_file_quark);
 
1405
  if (G_LIKELY (directory != NULL))
 
1406
    {
 
1407
      /* open tab in thsi window */
 
1408
      thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (buttons), directory);
 
1409
    }
 
1410
}
 
1411
 
 
1412
 
 
1413
 
 
1414
static void
 
1415
thunar_location_buttons_action_open_in_new_window (GtkAction             *action,
 
1416
                                                   ThunarLocationButtons *buttons)
 
1417
{
 
1418
  ThunarApplication *application;
 
1419
  ThunarFile        *directory;
 
1420
 
 
1421
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1422
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1423
 
 
1424
  /* determine the directory for the action */
 
1425
  directory = g_object_get_qdata (G_OBJECT (action), thunar_file_quark);
 
1426
  if (G_LIKELY (directory != NULL))
 
1427
    {
 
1428
      /* open a new window for the directory */
 
1429
      application = thunar_application_get ();
 
1430
      thunar_application_open_window (application, directory, gtk_widget_get_screen (GTK_WIDGET (buttons)), NULL);
 
1431
      g_object_unref (G_OBJECT (application));
 
1432
    }
 
1433
}
 
1434
 
 
1435
 
 
1436
 
 
1437
static void
 
1438
thunar_location_buttons_action_paste_into_folder (GtkAction             *action,
 
1439
                                                  ThunarLocationButtons *buttons)
 
1440
{
 
1441
  ThunarClipboardManager *clipboard;
 
1442
  ThunarFile             *directory;
 
1443
 
 
1444
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1445
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1446
 
 
1447
  /* determine the directory for the action */
 
1448
  directory = g_object_get_qdata (G_OBJECT (action), thunar_file_quark);
 
1449
  if (G_LIKELY (directory != NULL))
 
1450
    {
 
1451
      /* paste files from the clipboard to the folder represented by this button */
 
1452
      clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (GTK_WIDGET (buttons)));
 
1453
      thunar_clipboard_manager_paste_files (clipboard, thunar_file_get_file (directory), GTK_WIDGET (buttons), NULL);
 
1454
      g_object_unref (G_OBJECT (clipboard));
 
1455
    }
 
1456
}
 
1457
 
 
1458
 
 
1459
 
 
1460
static void
 
1461
thunar_location_buttons_action_properties (GtkAction             *action,
 
1462
                                           ThunarLocationButtons *buttons)
 
1463
{
 
1464
  ThunarFile *directory;
 
1465
  GtkWidget  *toplevel;
 
1466
  GtkWidget  *dialog;
 
1467
 
 
1468
  _thunar_return_if_fail (THUNAR_IS_LOCATION_BUTTONS (buttons));
 
1469
  _thunar_return_if_fail (GTK_IS_ACTION (action));
 
1470
 
 
1471
  /* determine the directory for the action */
 
1472
  directory = g_object_get_qdata (G_OBJECT (action), thunar_file_quark);
 
1473
  if (G_LIKELY (directory != NULL))
 
1474
    {
 
1475
      /* determine the toplevel window */
 
1476
      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (buttons));
 
1477
      if (G_LIKELY (toplevel != NULL && gtk_widget_get_toplevel (toplevel)))
 
1478
        {
 
1479
          /* popup the properties dialog */
 
1480
          dialog = thunar_properties_dialog_new (GTK_WINDOW (toplevel));
 
1481
          thunar_properties_dialog_set_file (THUNAR_PROPERTIES_DIALOG (dialog), directory);
 
1482
          gtk_widget_show (dialog);
 
1483
        }
 
1484
    }
 
1485
}
 
1486