Bug Summary

File:ctk/ctkpathbar.c
Warning:line 1131, column 28
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'down_button')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkpathbar.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-170037-43636-1 -x c ctkpathbar.c
1/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2/* ctkpathbar.c
3 * Copyright (C) 2004 Red Hat, Inc., Jonathan Blandford <jrb@gnome.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "config.h"
20
21#include "ctkpathbar.h"
22
23#include <string.h>
24
25#include "ctkbox.h"
26#include "ctkcssnodeprivate.h"
27#include "ctkdnd.h"
28#include "ctkdragsource.h"
29#include "ctkicontheme.h"
30#include "ctkimage.h"
31#include "ctkintl.h"
32#include "ctklabel.h"
33#include "ctkmain.h"
34#include "ctkmarshalers.h"
35#include "ctksettings.h"
36#include "ctktogglebutton.h"
37#include "ctkwidgetpath.h"
38#include "ctkwidgetprivate.h"
39
40struct _CtkPathBarPrivate
41{
42 CtkFileSystem *file_system;
43 GFile *root_file;
44 GFile *home_file;
45 GFile *desktop_file;
46
47 /* List of running GCancellable. When we cancel one, we remove it from this list.
48 * The pathbar cancels all outstanding cancellables when it is disposed.
49 *
50 * In code that queues async I/O operations:
51 *
52 * - Obtain a cancellable from the async I/O APIs, and call add_cancellable().
53 *
54 * To cancel a cancellable:
55 *
56 * - Call cancel_cancellable().
57 *
58 * In async I/O callbacks:
59 *
60 * - Check right away if g_cancellable_is_cancelled(): if true, just
61 * g_object_unref() the cancellable and return early (also free your
62 * closure data if you have one).
63 *
64 * - If it was not cancelled, call cancellable_async_done(). This will
65 * unref the cancellable and unqueue it from the pathbar's outstanding
66 * cancellables. Do your normal work to process the async result and free
67 * your closure data if you have one.
68 */
69 GList *cancellables;
70
71 GCancellable *get_info_cancellable;
72
73 GIcon *root_icon;
74 GIcon *home_icon;
75 GIcon *desktop_icon;
76
77 CdkWindow *event_window;
78
79 GList *button_list;
80 GList *first_scrolled_button;
81 GList *fake_root;
82 CtkWidget *up_slider_button;
83 CtkWidget *down_slider_button;
84 guint settings_signal_id;
85 gint16 slider_width;
86 gint16 button_offset;
87 guint timer;
88 guint slider_visible : 1;
89 guint need_timer : 1;
90 guint ignore_click : 1;
91 guint scrolling_up : 1;
92 guint scrolling_down : 1;
93};
94
95enum {
96 PATH_CLICKED,
97 LAST_SIGNAL
98};
99
100typedef enum {
101 NORMAL_BUTTON,
102 ROOT_BUTTON,
103 HOME_BUTTON,
104 DESKTOP_BUTTON
105} ButtonType;
106
107#define BUTTON_DATA(x)((ButtonData *)(x)) ((ButtonData *)(x))
108
109#define SCROLL_DELAY_FACTOR5 5
110#define TIMEOUT_INITIAL500 500
111#define TIMEOUT_REPEAT50 50
112
113static guint path_bar_signals [LAST_SIGNAL] = { 0 };
114
115/* Icon size for if we can't get it from the theme */
116#define FALLBACK_ICON_SIZE16 16
117
118typedef struct _ButtonData ButtonData;
119
120struct _ButtonData
121{
122 CtkWidget *button;
123 ButtonType type;
124 char *dir_name;
125 GFile *file;
126 CtkWidget *image;
127 CtkWidget *label;
128 GCancellable *cancellable;
129 guint ignore_changes : 1;
130 guint file_is_hidden : 1;
131};
132/* This macro is used to check if a button can be used as a fake root.
133 * All buttons in front of a fake root are automatically hidden when in a
134 * directory below a fake root and replaced with the "<" arrow button.
135 */
136#define BUTTON_IS_FAKE_ROOT(button)((button)->type == HOME_BUTTON) ((button)->type == HOME_BUTTON)
137
138G_DEFINE_TYPE_WITH_PRIVATE (CtkPathBar, ctk_path_bar, CTK_TYPE_CONTAINER)static void ctk_path_bar_init (CtkPathBar *self); static void
ctk_path_bar_class_init (CtkPathBarClass *klass); static GType
ctk_path_bar_get_type_once (void); static gpointer ctk_path_bar_parent_class
= ((void*)0); static gint CtkPathBar_private_offset; static void
ctk_path_bar_class_intern_init (gpointer klass) { ctk_path_bar_parent_class
= g_type_class_peek_parent (klass); if (CtkPathBar_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkPathBar_private_offset
); ctk_path_bar_class_init ((CtkPathBarClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_path_bar_get_instance_private
(CtkPathBar *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkPathBar_private_offset)))); } GType ctk_path_bar_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_path_bar_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_path_bar_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
ctk_container_get_type ()), g_intern_static_string ("CtkPathBar"
), sizeof (CtkPathBarClass), (GClassInitFunc)(void (*)(void))
ctk_path_bar_class_intern_init, sizeof (CtkPathBar), (GInstanceInitFunc
)(void (*)(void)) ctk_path_bar_init, (GTypeFlags) 0); { {{ CtkPathBar_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (CtkPathBarPrivate
)); };} } return g_define_type_id; }
139
140static void ctk_path_bar_finalize (GObject *object);
141static void ctk_path_bar_dispose (GObject *object);
142static void ctk_path_bar_realize (CtkWidget *widget);
143static void ctk_path_bar_unrealize (CtkWidget *widget);
144static void ctk_path_bar_get_preferred_width (CtkWidget *widget,
145 gint *minimum,
146 gint *natural);
147static void ctk_path_bar_get_preferred_height (CtkWidget *widget,
148 gint *minimum,
149 gint *natural);
150static void ctk_path_bar_map (CtkWidget *widget);
151static void ctk_path_bar_unmap (CtkWidget *widget);
152static void ctk_path_bar_size_allocate (CtkWidget *widget,
153 CtkAllocation *allocation);
154static void ctk_path_bar_add (CtkContainer *container,
155 CtkWidget *widget);
156static void ctk_path_bar_remove (CtkContainer *container,
157 CtkWidget *widget);
158static void ctk_path_bar_forall (CtkContainer *container,
159 gboolean include_internals,
160 CtkCallback callback,
161 gpointer callback_data);
162static gboolean ctk_path_bar_scroll (CtkWidget *widget,
163 CdkEventScroll *event);
164static void ctk_path_bar_scroll_up (CtkPathBar *path_bar);
165static void ctk_path_bar_scroll_down (CtkPathBar *path_bar);
166static void ctk_path_bar_stop_scrolling (CtkPathBar *path_bar);
167static gboolean ctk_path_bar_slider_up_defocus (CtkWidget *widget,
168 CdkEventButton *event,
169 CtkPathBar *path_bar);
170static gboolean ctk_path_bar_slider_down_defocus (CtkWidget *widget,
171 CdkEventButton *event,
172 CtkPathBar *path_bar);
173static gboolean ctk_path_bar_slider_button_press (CtkWidget *widget,
174 CdkEventButton *event,
175 CtkPathBar *path_bar);
176static gboolean ctk_path_bar_slider_button_release(CtkWidget *widget,
177 CdkEventButton *event,
178 CtkPathBar *path_bar);
179static void ctk_path_bar_grab_notify (CtkWidget *widget,
180 gboolean was_grabbed);
181static void ctk_path_bar_state_changed (CtkWidget *widget,
182 CtkStateType previous_state);
183static void ctk_path_bar_style_updated (CtkWidget *widget);
184static void ctk_path_bar_screen_changed (CtkWidget *widget,
185 CdkScreen *previous_screen);
186static void ctk_path_bar_check_icon_theme (CtkPathBar *path_bar);
187static void ctk_path_bar_update_button_appearance (CtkPathBar *path_bar,
188 ButtonData *button_data,
189 gboolean current_dir);
190
191static void
192add_cancellable (CtkPathBar *path_bar,
193 GCancellable *cancellable)
194{
195 g_assert (g_list_find (path_bar->priv->cancellables, cancellable) == NULL)do { if (g_list_find (path_bar->priv->cancellables, cancellable
) == ((void*)0)) ; else g_assertion_message_expr ("Ctk", "ctkpathbar.c"
, 195, ((const char*) (__func__)), "g_list_find (path_bar->priv->cancellables, cancellable) == NULL"
); } while (0)
;
196 path_bar->priv->cancellables = g_list_prepend (path_bar->priv->cancellables, cancellable);
197}
198
199static void
200drop_node_for_cancellable (CtkPathBar *path_bar,
201 GCancellable *cancellable)
202{
203 GList *node;
204
205 node = g_list_find (path_bar->priv->cancellables, cancellable);
206 g_assert (node != NULL)do { if (node != ((void*)0)) ; else g_assertion_message_expr (
"Ctk", "ctkpathbar.c", 206, ((const char*) (__func__)), "node != NULL"
); } while (0)
;
207 node->data = NULL((void*)0);
208 path_bar->priv->cancellables = g_list_delete_link (path_bar->priv->cancellables, node);
209}
210
211static void
212cancel_cancellable (CtkPathBar *path_bar,
213 GCancellable *cancellable)
214{
215 drop_node_for_cancellable (path_bar, cancellable);
216 g_cancellable_cancel (cancellable);
217}
218
219static void
220cancellable_async_done (CtkPathBar *path_bar,
221 GCancellable *cancellable)
222{
223 drop_node_for_cancellable (path_bar, cancellable);
224 g_object_unref (cancellable);
225}
226
227static void
228cancel_all_cancellables (CtkPathBar *path_bar)
229{
230 while (path_bar->priv->cancellables)
231 {
232 GCancellable *cancellable = path_bar->priv->cancellables->data;
233 cancel_cancellable (path_bar, cancellable);
234 }
235}
236
237static void
238on_slider_unmap (CtkWidget *widget,
239 CtkPathBar *path_bar)
240{
241 if (path_bar->priv->timer &&
242 ((widget == path_bar->priv->up_slider_button && path_bar->priv->scrolling_up) ||
243 (widget == path_bar->priv->down_slider_button && path_bar->priv->scrolling_down)))
244 ctk_path_bar_stop_scrolling (path_bar);
245}
246
247static void
248ctk_path_bar_init (CtkPathBar *path_bar)
249{
250 CtkStyleContext *context;
251
252 path_bar->priv = ctk_path_bar_get_instance_private (path_bar);
253
254 ctk_widget_init_template (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
);
255
256 /* Add the children manually because CtkPathBar derives from an abstract class,
257 * Glade cannot edit a <template> in ctkpathbar.ui if it's only a CtkContainer.
258 */
259 ctk_container_add (CTK_CONTAINER (path_bar)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_container_get_type ()))))))
, path_bar->priv->up_slider_button);
260 ctk_container_add (CTK_CONTAINER (path_bar)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_container_get_type ()))))))
, path_bar->priv->down_slider_button);
261
262 /* CtkBuilder wont let us connect 'swapped' without specifying the signal's
263 * user data in the .ui file
264 */
265 g_signal_connect_swapped (path_bar->priv->up_slider_button, "clicked",g_signal_connect_data ((path_bar->priv->up_slider_button
), ("clicked"), (((GCallback) (ctk_path_bar_scroll_up))), (path_bar
), ((void*)0), G_CONNECT_SWAPPED)
266 G_CALLBACK (ctk_path_bar_scroll_up), path_bar)g_signal_connect_data ((path_bar->priv->up_slider_button
), ("clicked"), (((GCallback) (ctk_path_bar_scroll_up))), (path_bar
), ((void*)0), G_CONNECT_SWAPPED)
;
267 g_signal_connect_swapped (path_bar->priv->down_slider_button, "clicked",g_signal_connect_data ((path_bar->priv->down_slider_button
), ("clicked"), (((GCallback) (ctk_path_bar_scroll_down))), (
path_bar), ((void*)0), G_CONNECT_SWAPPED)
268 G_CALLBACK (ctk_path_bar_scroll_down), path_bar)g_signal_connect_data ((path_bar->priv->down_slider_button
), ("clicked"), (((GCallback) (ctk_path_bar_scroll_down))), (
path_bar), ((void*)0), G_CONNECT_SWAPPED)
;
269
270 ctk_widget_set_has_window (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
, FALSE(0));
271
272 context = ctk_widget_get_style_context (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
);
273 ctk_style_context_add_class (context, "path-bar");
274 ctk_style_context_add_class (context, CTK_STYLE_CLASS_LINKED"linked");
275
276 path_bar->priv->get_info_cancellable = NULL((void*)0);
277 path_bar->priv->cancellables = NULL((void*)0);
278}
279
280static void
281ctk_path_bar_class_init (CtkPathBarClass *path_bar_class)
282{
283 GObjectClass *gobject_class;
284 CtkWidgetClass *widget_class;
285 CtkContainerClass *container_class;
286
287 gobject_class = (GObjectClass *) path_bar_class;
288 widget_class = (CtkWidgetClass *) path_bar_class;
289 container_class = (CtkContainerClass *) path_bar_class;
290
291 gobject_class->finalize = ctk_path_bar_finalize;
292 gobject_class->dispose = ctk_path_bar_dispose;
293
294 widget_class->get_preferred_width = ctk_path_bar_get_preferred_width;
295 widget_class->get_preferred_height = ctk_path_bar_get_preferred_height;
296 widget_class->realize = ctk_path_bar_realize;
297 widget_class->unrealize = ctk_path_bar_unrealize;
298 widget_class->map = ctk_path_bar_map;
299 widget_class->unmap = ctk_path_bar_unmap;
300 widget_class->size_allocate = ctk_path_bar_size_allocate;
301 widget_class->style_updated = ctk_path_bar_style_updated;
302 widget_class->screen_changed = ctk_path_bar_screen_changed;
303 widget_class->grab_notify = ctk_path_bar_grab_notify;
304 widget_class->state_changed = ctk_path_bar_state_changed;
305 widget_class->scroll_event = ctk_path_bar_scroll;
306
307 container_class->add = ctk_path_bar_add;
308 container_class->forall = ctk_path_bar_forall;
309 container_class->remove = ctk_path_bar_remove;
310 ctk_container_class_handle_border_width (container_class);
311 /* FIXME: */
312 /* container_class->child_type = ctk_path_bar_child_type;*/
313
314 path_bar_signals [PATH_CLICKED] =
315 g_signal_new (I_("path-clicked")g_intern_static_string ("path-clicked"),
316 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
317 G_SIGNAL_RUN_FIRST,
318 G_STRUCT_OFFSET (CtkPathBarClass, path_clicked)((glong) __builtin_offsetof(CtkPathBarClass, path_clicked)),
319 NULL((void*)0), NULL((void*)0),
320 _ctk_marshal_VOID__POINTER_POINTER_BOOLEAN,
321 G_TYPE_NONE((GType) ((1) << (2))), 3,
322 G_TYPE_POINTER((GType) ((17) << (2))),
323 G_TYPE_POINTER((GType) ((17) << (2))),
324 G_TYPE_BOOLEAN((GType) ((5) << (2))));
325
326 /* Bind class to template
327 */
328 ctk_widget_class_set_template_from_resource (widget_class,
329 "/org/ctk/libctk/ui/ctkpathbar.ui");
330
331 ctk_widget_class_bind_template_child_private (widget_class, CtkPathBar, up_slider_button)ctk_widget_class_bind_template_child_full (widget_class, "up_slider_button"
, (0), (CtkPathBar_private_offset + (((glong) __builtin_offsetof
(CtkPathBarPrivate, up_slider_button)))))
;
332 ctk_widget_class_bind_template_child_private (widget_class, CtkPathBar, down_slider_button)ctk_widget_class_bind_template_child_full (widget_class, "down_slider_button"
, (0), (CtkPathBar_private_offset + (((glong) __builtin_offsetof
(CtkPathBarPrivate, down_slider_button)))))
;
333
334 ctk_widget_class_bind_template_callback (widget_class, ctk_path_bar_slider_button_press)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) g_type_check_class_cast ((GTypeClass*) ((widget_class
)), ((ctk_widget_get_type ())))))), "ctk_path_bar_slider_button_press"
, ((GCallback) (ctk_path_bar_slider_button_press)))
;
335 ctk_widget_class_bind_template_callback (widget_class, ctk_path_bar_slider_button_release)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) g_type_check_class_cast ((GTypeClass*) ((widget_class
)), ((ctk_widget_get_type ())))))), "ctk_path_bar_slider_button_release"
, ((GCallback) (ctk_path_bar_slider_button_release)))
;
336 ctk_widget_class_bind_template_callback (widget_class, ctk_path_bar_slider_up_defocus)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) g_type_check_class_cast ((GTypeClass*) ((widget_class
)), ((ctk_widget_get_type ())))))), "ctk_path_bar_slider_up_defocus"
, ((GCallback) (ctk_path_bar_slider_up_defocus)))
;
337 ctk_widget_class_bind_template_callback (widget_class, ctk_path_bar_slider_down_defocus)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) g_type_check_class_cast ((GTypeClass*) ((widget_class
)), ((ctk_widget_get_type ())))))), "ctk_path_bar_slider_down_defocus"
, ((GCallback) (ctk_path_bar_slider_down_defocus)))
;
338 ctk_widget_class_bind_template_callback (widget_class, ctk_path_bar_scroll_up)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) g_type_check_class_cast ((GTypeClass*) ((widget_class
)), ((ctk_widget_get_type ())))))), "ctk_path_bar_scroll_up",
((GCallback) (ctk_path_bar_scroll_up)))
;
339 ctk_widget_class_bind_template_callback (widget_class, ctk_path_bar_scroll_down)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) g_type_check_class_cast ((GTypeClass*) ((widget_class
)), ((ctk_widget_get_type ())))))), "ctk_path_bar_scroll_down"
, ((GCallback) (ctk_path_bar_scroll_down)))
;
340 ctk_widget_class_bind_template_callback (widget_class, on_slider_unmap)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) g_type_check_class_cast ((GTypeClass*) ((widget_class
)), ((ctk_widget_get_type ())))))), "on_slider_unmap", ((GCallback
) (on_slider_unmap)))
;
341}
342
343
344static void
345ctk_path_bar_finalize (GObject *object)
346{
347 CtkPathBar *path_bar;
348
349 path_bar = CTK_PATH_BAR (object)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_path_bar_get_type ()))))))
;
350
351 cancel_all_cancellables (path_bar);
352 ctk_path_bar_stop_scrolling (path_bar);
353
354 g_list_free (path_bar->priv->button_list);
355 g_clear_object (&path_bar->priv->root_file)do { _Static_assert (sizeof *((&path_bar->priv->root_file
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->root_file))) _pp = ((&path_bar
->priv->root_file)); __typeof__ (*((&path_bar->priv
->root_file))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (
g_object_unref) (_ptr); } while (0)
;
356 g_clear_object (&path_bar->priv->home_file)do { _Static_assert (sizeof *((&path_bar->priv->home_file
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->home_file))) _pp = ((&path_bar
->priv->home_file)); __typeof__ (*((&path_bar->priv
->home_file))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (
g_object_unref) (_ptr); } while (0)
;
357 g_clear_object (&path_bar->priv->desktop_file)do { _Static_assert (sizeof *((&path_bar->priv->desktop_file
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->desktop_file))) _pp = ((&path_bar
->priv->desktop_file)); __typeof__ (*((&path_bar->
priv->desktop_file))) _ptr = *_pp; *_pp = ((void*)0); if (
_ptr) (g_object_unref) (_ptr); } while (0)
;
358
359 g_clear_object (&path_bar->priv->root_icon)do { _Static_assert (sizeof *((&path_bar->priv->root_icon
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->root_icon))) _pp = ((&path_bar
->priv->root_icon)); __typeof__ (*((&path_bar->priv
->root_icon))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (
g_object_unref) (_ptr); } while (0)
;
360 g_clear_object (&path_bar->priv->home_icon)do { _Static_assert (sizeof *((&path_bar->priv->home_icon
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->home_icon))) _pp = ((&path_bar
->priv->home_icon)); __typeof__ (*((&path_bar->priv
->home_icon))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (
g_object_unref) (_ptr); } while (0)
;
361 g_clear_object (&path_bar->priv->desktop_icon)do { _Static_assert (sizeof *((&path_bar->priv->desktop_icon
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->desktop_icon))) _pp = ((&path_bar
->priv->desktop_icon)); __typeof__ (*((&path_bar->
priv->desktop_icon))) _ptr = *_pp; *_pp = ((void*)0); if (
_ptr) (g_object_unref) (_ptr); } while (0)
;
362
363 g_clear_object (&path_bar->priv->file_system)do { _Static_assert (sizeof *((&path_bar->priv->file_system
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->file_system))) _pp = ((&path_bar
->priv->file_system)); __typeof__ (*((&path_bar->
priv->file_system))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr
) (g_object_unref) (_ptr); } while (0)
;
364
365 G_OBJECT_CLASS (ctk_path_bar_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), (((GType) ((20) << (2
))))))))
->finalize (object);
366}
367
368/* Removes the settings signal handler. It's safe to call multiple times */
369static void
370remove_settings_signal (CtkPathBar *path_bar,
371 CdkScreen *screen)
372{
373 if (path_bar->priv->settings_signal_id)
374 {
375 CtkSettings *settings;
376
377 settings = ctk_settings_get_for_screen (screen);
378 g_signal_handler_disconnect (settings,
379 path_bar->priv->settings_signal_id);
380 path_bar->priv->settings_signal_id = 0;
381 }
382}
383
384static void
385ctk_path_bar_dispose (GObject *object)
386{
387 CtkPathBar *path_bar = CTK_PATH_BAR (object)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_path_bar_get_type ()))))))
;
388
389 remove_settings_signal (path_bar, ctk_widget_get_screen (CTK_WIDGET (object)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_widget_get_type ()))))))
));
390
391 path_bar->priv->get_info_cancellable = NULL((void*)0);
392 cancel_all_cancellables (path_bar);
393
394 G_OBJECT_CLASS (ctk_path_bar_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), (((GType) ((20) << (2
))))))))
->dispose (object);
395}
396
397/* Size requisition:
398 *
399 * Ideally, our size is determined by another widget, and we are just filling
400 * available space.
401 */
402static void
403ctk_path_bar_get_preferred_width (CtkWidget *widget,
404 gint *minimum,
405 gint *natural)
406{
407 ButtonData *button_data;
408 CtkPathBar *path_bar;
409 GList *list;
410 gint child_height;
411 gint height;
412 gint child_min, child_nat;
413
414 path_bar = CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
;
415
416 *minimum = *natural = 0;
417 height = 0;
418
419 for (list = path_bar->priv->button_list; list; list = list->next)
420 {
421 button_data = BUTTON_DATA (list->data)((ButtonData *)(list->data));
422 ctk_widget_get_preferred_width (button_data->button, &child_min, &child_nat);
423 ctk_widget_get_preferred_height (button_data->button, &child_height, NULL((void*)0));
424 height = MAX (height, child_height)(((height) > (child_height)) ? (height) : (child_height));
425
426 if (button_data->type == NORMAL_BUTTON)
427 {
428 /* Use 2*Height as button width because of ellipsized label. */
429 child_min = MAX (child_min, child_height * 2)(((child_min) > (child_height * 2)) ? (child_min) : (child_height
* 2))
;
430 child_nat = MAX (child_min, child_height * 2)(((child_min) > (child_height * 2)) ? (child_min) : (child_height
* 2))
;
431 }
432
433 *minimum = MAX (*minimum, child_min)(((*minimum) > (child_min)) ? (*minimum) : (child_min));
434 *natural = *natural + child_nat;
435 }
436
437 /* Add space for slider, if we have more than one path */
438 /* Theoretically, the slider could be bigger than the other button. But we're
439 * not going to worry about that now.
440 */
441 path_bar->priv->slider_width = 0;
442
443 ctk_widget_get_preferred_width (path_bar->priv->up_slider_button, &child_min, &child_nat);
444 if (path_bar->priv->button_list && path_bar->priv->button_list->next != NULL((void*)0))
445 {
446 *minimum += child_min;
447 *natural += child_nat;
448 }
449 path_bar->priv->slider_width = MAX (path_bar->priv->slider_width, child_min)(((path_bar->priv->slider_width) > (child_min)) ? (path_bar
->priv->slider_width) : (child_min))
;
450
451 ctk_widget_get_preferred_width (path_bar->priv->down_slider_button, &child_min, &child_nat);
452 if (path_bar->priv->button_list && path_bar->priv->button_list->next != NULL((void*)0))
453 {
454 *minimum += child_min;
455 *natural += child_nat;
456 }
457 path_bar->priv->slider_width = MAX (path_bar->priv->slider_width, child_min)(((path_bar->priv->slider_width) > (child_min)) ? (path_bar
->priv->slider_width) : (child_min))
;
458}
459
460static void
461ctk_path_bar_get_preferred_height (CtkWidget *widget,
462 gint *minimum,
463 gint *natural)
464{
465 ButtonData *button_data;
466 CtkPathBar *path_bar;
467 GList *list;
468 gint child_min, child_nat;
469
470 path_bar = CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
;
471
472 *minimum = *natural = 0;
473
474 for (list = path_bar->priv->button_list; list; list = list->next)
475 {
476 button_data = BUTTON_DATA (list->data)((ButtonData *)(list->data));
477 ctk_widget_get_preferred_height (button_data->button, &child_min, &child_nat);
478
479 *minimum = MAX (*minimum, child_min)(((*minimum) > (child_min)) ? (*minimum) : (child_min));
480 *natural = MAX (*natural, child_nat)(((*natural) > (child_nat)) ? (*natural) : (child_nat));
481 }
482
483 ctk_widget_get_preferred_height (path_bar->priv->up_slider_button, &child_min, &child_nat);
484 *minimum = MAX (*minimum, child_min)(((*minimum) > (child_min)) ? (*minimum) : (child_min));
485 *natural = MAX (*natural, child_nat)(((*natural) > (child_nat)) ? (*natural) : (child_nat));
486
487 ctk_widget_get_preferred_height (path_bar->priv->down_slider_button, &child_min, &child_nat);
488 *minimum = MAX (*minimum, child_min)(((*minimum) > (child_min)) ? (*minimum) : (child_min));
489 *natural = MAX (*natural, child_nat)(((*natural) > (child_nat)) ? (*natural) : (child_nat));
490}
491
492static void
493ctk_path_bar_update_slider_buttons (CtkPathBar *path_bar)
494{
495 if (path_bar->priv->button_list)
496 {
497 CtkWidget *button;
498
499 button = BUTTON_DATA (path_bar->priv->button_list->data)((ButtonData *)(path_bar->priv->button_list->data))->button;
500 if (ctk_widget_get_child_visible (button))
501 {
502 ctk_path_bar_stop_scrolling (path_bar);
503 ctk_widget_set_sensitive (path_bar->priv->down_slider_button, FALSE(0));
504 }
505 else
506 ctk_widget_set_sensitive (path_bar->priv->down_slider_button, TRUE(!(0)));
507
508 button = BUTTON_DATA (g_list_last (path_bar->priv->button_list)->data)((ButtonData *)(g_list_last (path_bar->priv->button_list
)->data))
->button;
509 if (ctk_widget_get_child_visible (button))
510 {
511 ctk_path_bar_stop_scrolling (path_bar);
512 ctk_widget_set_sensitive (path_bar->priv->up_slider_button, FALSE(0));
513 }
514 else
515 ctk_widget_set_sensitive (path_bar->priv->up_slider_button, TRUE(!(0)));
516 }
517}
518
519static void
520ctk_path_bar_map (CtkWidget *widget)
521{
522 cdk_window_show (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
->priv->event_window);
523
524 CTK_WIDGET_CLASS (ctk_path_bar_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), ((ctk_widget_get_type ())))
)))
->map (widget);
525}
526
527static void
528ctk_path_bar_unmap (CtkWidget *widget)
529{
530 ctk_path_bar_stop_scrolling (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
);
531 cdk_window_hide (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
->priv->event_window);
532
533 CTK_WIDGET_CLASS (ctk_path_bar_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), ((ctk_widget_get_type ())))
)))
->unmap (widget);
534}
535
536static void
537ctk_path_bar_realize (CtkWidget *widget)
538{
539 CtkPathBar *path_bar;
540 CtkAllocation allocation;
541 CdkWindow *window;
542 CdkWindowAttr attributes;
543 gint attributes_mask;
544
545 ctk_widget_set_realized (widget, TRUE(!(0)));
546
547 path_bar = CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
;
548 window = ctk_widget_get_parent_window (widget);
549 ctk_widget_set_window (widget, window);
550 g_object_ref (window)((__typeof__ (window)) (g_object_ref) (window));
551
552 ctk_widget_get_allocation (widget, &allocation);
553
554 attributes.window_type = CDK_WINDOW_CHILD;
555 attributes.x = allocation.x;
556 attributes.y = allocation.y;
557 attributes.width = allocation.width;
558 attributes.height = allocation.height;
559 attributes.wclass = CDK_INPUT_ONLY;
560 attributes.event_mask = ctk_widget_get_events (widget);
561 attributes.event_mask |= CDK_SCROLL_MASK;
562 attributes_mask = CDK_WA_X | CDK_WA_Y;
563
564 path_bar->priv->event_window = cdk_window_new (ctk_widget_get_parent_window (widget),
565 &attributes, attributes_mask);
566 ctk_widget_register_window (widget, path_bar->priv->event_window);
567}
568
569static void
570ctk_path_bar_unrealize (CtkWidget *widget)
571{
572 CtkPathBar *path_bar;
573
574 path_bar = CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
;
575
576 ctk_widget_unregister_window (widget, path_bar->priv->event_window);
577 cdk_window_destroy (path_bar->priv->event_window);
578 path_bar->priv->event_window = NULL((void*)0);
579
580 CTK_WIDGET_CLASS (ctk_path_bar_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), ((ctk_widget_get_type ())))
)))
->unrealize (widget);
581}
582
583/* This is a tad complicated
584 */
585static void
586ctk_path_bar_size_allocate (CtkWidget *widget,
587 CtkAllocation *allocation)
588{
589 CtkWidget *child;
590 CtkPathBar *path_bar = CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
;
591 CtkTextDirection direction;
592 CtkAllocation child_allocation;
593 GList *list, *first_button;
594 gint width;
595 gint allocation_width;
596 gboolean need_sliders = TRUE(!(0));
597 gint up_slider_offset = 0;
598 gint down_slider_offset = 0;
599 CtkRequisition child_requisition;
600
601 ctk_widget_set_allocation (widget, allocation);
602
603 if (ctk_widget_get_realized (widget))
604 cdk_window_move_resize (path_bar->priv->event_window,
605 allocation->x, allocation->y,
606 allocation->width, allocation->height);
607
608 /* No path is set; we don't have to allocate anything. */
609 if (path_bar->priv->button_list == NULL((void*)0))
610 {
611 _ctk_widget_set_simple_clip (widget, NULL((void*)0));
612
613 return;
614 }
615
616 direction = ctk_widget_get_direction (widget);
617 allocation_width = allocation->width;
618
619 /* First, we check to see if we need the scrollbars. */
620 if (path_bar->priv->fake_root)
621 width = path_bar->priv->slider_width;
622 else
623 width = 0;
624
625 for (list = path_bar->priv->button_list; list; list = list->next)
626 {
627 child = BUTTON_DATA (list->data)((ButtonData *)(list->data))->button;
628
629 ctk_widget_get_preferred_size (child, &child_requisition, NULL((void*)0));
630
631 width += child_requisition.width;
632 if (list == path_bar->priv->fake_root)
633 break;
634 }
635
636 if (width <= allocation_width)
637 {
638 if (path_bar->priv->fake_root)
639 first_button = path_bar->priv->fake_root;
640 else
641 first_button = g_list_last (path_bar->priv->button_list);
642 }
643 else
644 {
645 gboolean reached_end = FALSE(0);
646 gint slider_space = 2 * path_bar->priv->slider_width;
647
648 if (path_bar->priv->first_scrolled_button)
649 first_button = path_bar->priv->first_scrolled_button;
650 else
651 first_button = path_bar->priv->button_list;
652 need_sliders = TRUE(!(0));
653
654 /* To see how much space we have, and how many buttons we can display.
655 * We start at the first button, count forward until hit the new
656 * button, then count backwards.
657 */
658 /* Count down the path chain towards the end. */
659 ctk_widget_get_preferred_size (BUTTON_DATA (first_button->data)((ButtonData *)(first_button->data))->button,
660 &child_requisition, NULL((void*)0));
661
662 width = child_requisition.width;
663 list = first_button->prev;
664 while (list && !reached_end)
665 {
666 child = BUTTON_DATA (list->data)((ButtonData *)(list->data))->button;
667
668 ctk_widget_get_preferred_size (child, &child_requisition, NULL((void*)0));
669
670 if (width + child_requisition.width + slider_space > allocation_width)
671 reached_end = TRUE(!(0));
672 else if (list == path_bar->priv->fake_root)
673 break;
674 else
675 width += child_requisition.width;
676
677 list = list->prev;
678 }
679
680 /* Finally, we walk up, seeing how many of the previous buttons we can
681 * add */
682 while (first_button->next && !reached_end)
683 {
684 child = BUTTON_DATA (first_button->next->data)((ButtonData *)(first_button->next->data))->button;
685
686 ctk_widget_get_preferred_size (child, &child_requisition, NULL((void*)0));
687
688 if (width + child_requisition.width + slider_space > allocation_width)
689 {
690 reached_end = TRUE(!(0));
691 }
692 else
693 {
694 width += child_requisition.width;
695 if (first_button == path_bar->priv->fake_root)
696 break;
697 first_button = first_button->next;
698 }
699 }
700 }
701
702 /* Now, we allocate space to the buttons */
703 child_allocation.y = allocation->y;
704 child_allocation.height = allocation->height;
705
706 if (direction == CTK_TEXT_DIR_RTL)
707 {
708 child_allocation.x = allocation->x + allocation->width;
709 if (need_sliders || path_bar->priv->fake_root)
710 {
711 child_allocation.x -= path_bar->priv->slider_width;
712 up_slider_offset = allocation->width - path_bar->priv->slider_width;
713 }
714 }
715 else
716 {
717 child_allocation.x = allocation->x;
718 if (need_sliders || path_bar->priv->fake_root)
719 {
720 up_slider_offset = 0;
721 child_allocation.x += path_bar->priv->slider_width;
722 }
723 }
724
725 for (list = first_button; list; list = list->prev)
726 {
727 CtkAllocation widget_allocation;
728 ButtonData *button_data;
729
730 button_data = BUTTON_DATA (list->data)((ButtonData *)(list->data));
731 child = button_data->button;
732
733 ctk_widget_get_preferred_size (child, &child_requisition, NULL((void*)0));
734
735 child_allocation.width = MIN (child_requisition.width,(((child_requisition.width) < (allocation_width - 2 * path_bar
->priv->slider_width)) ? (child_requisition.width) : (allocation_width
- 2 * path_bar->priv->slider_width))
736 allocation_width - 2 * path_bar->priv->slider_width)(((child_requisition.width) < (allocation_width - 2 * path_bar
->priv->slider_width)) ? (child_requisition.width) : (allocation_width
- 2 * path_bar->priv->slider_width))
;
737
738 if (direction == CTK_TEXT_DIR_RTL)
739 child_allocation.x -= child_allocation.width;
740
741 /* Check to see if we've don't have any more space to allocate buttons */
742 if (need_sliders && direction == CTK_TEXT_DIR_RTL)
743 {
744 ctk_widget_get_allocation (widget, &widget_allocation);
745 if (child_allocation.x - path_bar->priv->slider_width < widget_allocation.x)
746 break;
747 }
748 else if (need_sliders && direction == CTK_TEXT_DIR_LTR)
749 {
750 ctk_widget_get_allocation (widget, &widget_allocation);
751 if (child_allocation.x + child_allocation.width + path_bar->priv->slider_width >
752 widget_allocation.x + allocation_width)
753 break;
754 }
755
756 if (child_allocation.width < child_requisition.width)
757 {
758 if (!ctk_widget_get_has_tooltip (child))
759 ctk_widget_set_tooltip_text (child, button_data->dir_name);
760 }
761 else if (ctk_widget_get_has_tooltip (child))
762 ctk_widget_set_tooltip_text (child, NULL((void*)0));
763
764 ctk_widget_set_child_visible (child, TRUE(!(0)));
765 ctk_widget_size_allocate (child, &child_allocation);
766
767 if (direction == CTK_TEXT_DIR_RTL)
768 {
769 down_slider_offset = child_allocation.x - allocation->x - path_bar->priv->slider_width;
770 }
771 else
772 {
773 down_slider_offset += child_allocation.width;
774 child_allocation.x += child_allocation.width;
775 }
776 }
777 /* Now we go hide all the widgets that don't fit */
778 while (list)
779 {
780 child = BUTTON_DATA (list->data)((ButtonData *)(list->data))->button;
781 ctk_widget_set_child_visible (child, FALSE(0));
782 list = list->prev;
783 }
784 for (list = first_button->next; list; list = list->next)
785 {
786 child = BUTTON_DATA (list->data)((ButtonData *)(list->data))->button;
787 ctk_widget_set_child_visible (child, FALSE(0));
788 }
789
790 if (need_sliders || path_bar->priv->fake_root)
791 {
792 child_allocation.width = path_bar->priv->slider_width;
793 child_allocation.x = up_slider_offset + allocation->x;
794 ctk_widget_size_allocate (path_bar->priv->up_slider_button, &child_allocation);
795
796 ctk_widget_set_child_visible (path_bar->priv->up_slider_button, TRUE(!(0)));
797 ctk_widget_show_all (path_bar->priv->up_slider_button);
798
799 if (direction == CTK_TEXT_DIR_LTR)
800 down_slider_offset += path_bar->priv->slider_width;
801 }
802 else
803 {
804 ctk_widget_set_child_visible (path_bar->priv->up_slider_button, FALSE(0));
805 }
806
807 if (need_sliders)
808 {
809 child_allocation.width = path_bar->priv->slider_width;
810 child_allocation.x = down_slider_offset + allocation->x;
811
812 ctk_widget_size_allocate (path_bar->priv->down_slider_button, &child_allocation);
813
814 ctk_widget_set_child_visible (path_bar->priv->down_slider_button, TRUE(!(0)));
815 ctk_widget_show_all (path_bar->priv->down_slider_button);
816 ctk_path_bar_update_slider_buttons (path_bar);
817 }
818 else
819 {
820 ctk_widget_set_child_visible (path_bar->priv->down_slider_button, FALSE(0));
821 }
822
823 _ctk_widget_set_simple_clip (widget, NULL((void*)0));
824}
825
826static void
827ctk_path_bar_style_updated (CtkWidget *widget)
828{
829 CTK_WIDGET_CLASS (ctk_path_bar_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), ((ctk_widget_get_type ())))
)))
->style_updated (widget);
830
831 ctk_path_bar_check_icon_theme (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
);
832}
833
834static void
835ctk_path_bar_screen_changed (CtkWidget *widget,
836 CdkScreen *previous_screen)
837{
838 if (CTK_WIDGET_CLASS (ctk_path_bar_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), ((ctk_widget_get_type ())))
)))
->screen_changed)
839 CTK_WIDGET_CLASS (ctk_path_bar_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_path_bar_parent_class)), ((ctk_widget_get_type ())))
)))
->screen_changed (widget, previous_screen);
840
841 /* We might nave a new settings, so we remove the old one */
842 if (previous_screen)
843 remove_settings_signal (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
, previous_screen);
844
845 ctk_path_bar_check_icon_theme (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
);
846}
847
848static gboolean
849ctk_path_bar_scroll (CtkWidget *widget,
850 CdkEventScroll *event)
851{
852 switch (event->direction)
853 {
854 case CDK_SCROLL_RIGHT:
855 case CDK_SCROLL_DOWN:
856 ctk_path_bar_scroll_down (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
);
857 break;
858 case CDK_SCROLL_LEFT:
859 case CDK_SCROLL_UP:
860 ctk_path_bar_scroll_up (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
);
861 break;
862 case CDK_SCROLL_SMOOTH:
863 break;
864 }
865
866 return TRUE(!(0));
867}
868
869static void
870ctk_path_bar_add (CtkContainer *container,
871 CtkWidget *widget)
872
873{
874 ctk_widget_set_parent (widget, CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
);
875}
876
877static void
878ctk_path_bar_remove_1 (CtkContainer *container,
879 CtkWidget *widget)
880{
881 gboolean was_visible = ctk_widget_get_visible (widget);
882 ctk_widget_unparent (widget);
883 if (was_visible)
884 ctk_widget_queue_resize (CTK_WIDGET (container)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_widget_get_type ()))))))
);
885}
886
887static void
888ctk_path_bar_remove (CtkContainer *container,
889 CtkWidget *widget)
890{
891 CtkPathBar *path_bar;
892 GList *children;
893
894 path_bar = CTK_PATH_BAR (container)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_path_bar_get_type ()))))))
;
895
896 if (widget == path_bar->priv->up_slider_button)
897 {
898 ctk_path_bar_remove_1 (container, widget);
899 path_bar->priv->up_slider_button = NULL((void*)0);
900 return;
901 }
902
903 if (widget == path_bar->priv->down_slider_button)
904 {
905 ctk_path_bar_remove_1 (container, widget);
906 path_bar->priv->down_slider_button = NULL((void*)0);
907 return;
908 }
909
910 children = path_bar->priv->button_list;
911 while (children)
912 {
913 if (widget == BUTTON_DATA (children->data)((ButtonData *)(children->data))->button)
914 {
915 ctk_path_bar_remove_1 (container, widget);
916 path_bar->priv->button_list = g_list_remove_link (path_bar->priv->button_list, children);
917 g_list_free (children);
918 return;
919 }
920
921 children = children->next;
922 }
923}
924
925static void
926ctk_path_bar_forall (CtkContainer *container,
927 gboolean include_internals G_GNUC_UNUSED__attribute__ ((__unused__)),
928 CtkCallback callback,
929 gpointer callback_data)
930{
931 CtkPathBar *path_bar;
932 GList *children;
933
934 g_return_if_fail (callback != NULL)do { if ((callback != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "callback != NULL"); return
; } } while (0)
;
935 path_bar = CTK_PATH_BAR (container)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ctk_path_bar_get_type ()))))))
;
936
937 children = path_bar->priv->button_list;
938 while (children)
939 {
940 CtkWidget *child;
941 child = BUTTON_DATA (children->data)((ButtonData *)(children->data))->button;
942 children = children->next;
943
944 (* callback) (child, callback_data);
945 }
946
947 if (path_bar->priv->up_slider_button)
948 (* callback) (path_bar->priv->up_slider_button, callback_data);
949
950 if (path_bar->priv->down_slider_button)
951 (* callback) (path_bar->priv->down_slider_button, callback_data);
952}
953
954static void
955ctk_path_bar_scroll_down (CtkPathBar *path_bar)
956{
957 CtkAllocation allocation, button_allocation;
958 GList *list;
959 GList *down_button = NULL((void*)0);
960 gint space_available;
961
962 if (path_bar->priv->ignore_click)
963 {
964 path_bar->priv->ignore_click = FALSE(0);
965 return;
966 }
967
968 if (ctk_widget_get_child_visible (BUTTON_DATA (path_bar->priv->button_list->data)((ButtonData *)(path_bar->priv->button_list->data))->button))
969 {
970 /* Return if the last button is already visible */
971 return;
972 }
973
974 ctk_widget_queue_resize (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
);
975
976 /* We find the button at the 'down' end that we have to make
977 * visible */
978 for (list = path_bar->priv->button_list; list; list = list->next)
979 {
980 if (list->next && ctk_widget_get_child_visible (BUTTON_DATA (list->next->data)((ButtonData *)(list->next->data))->button))
981 {
982 down_button = list;
983 break;
984 }
985 }
986
987 ctk_widget_get_allocation (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
, &allocation);
988 ctk_widget_get_allocation (BUTTON_DATA (down_button->data)((ButtonData *)(down_button->data))->button, &button_allocation);
989
990 space_available = (allocation.width
991 - 2 * path_bar->priv->slider_width
992 - button_allocation.width);
993 path_bar->priv->first_scrolled_button = down_button;
994
995 /* We have space_available free space that's not being used.
996 * So we walk down from the end, adding buttons until we use all free space.
997 */
998 while (space_available > 0)
999 {
1000 path_bar->priv->first_scrolled_button = down_button;
1001 down_button = down_button->next;
1002 if (!down_button)
1003 break;
1004 space_available -= button_allocation.width;
1005 }
1006}
1007
1008static void
1009ctk_path_bar_scroll_up (CtkPathBar *path_bar)
1010{
1011 GList *list;
1012
1013 if (path_bar->priv->ignore_click)
1014 {
1015 path_bar->priv->ignore_click = FALSE(0);
1016 return;
1017 }
1018
1019 list = g_list_last (path_bar->priv->button_list);
1020
1021 if (ctk_widget_get_child_visible (BUTTON_DATA (list->data)((ButtonData *)(list->data))->button))
1022 {
1023 /* Return if the first button is already visible */
1024 return;
1025 }
1026
1027 ctk_widget_queue_resize (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
);
1028
1029 for ( ; list; list = list->prev)
1030 {
1031 if (list->prev && ctk_widget_get_child_visible (BUTTON_DATA (list->prev->data)((ButtonData *)(list->prev->data))->button))
1032 {
1033 if (list->prev == path_bar->priv->fake_root)
1034 path_bar->priv->fake_root = NULL((void*)0);
1035 path_bar->priv->first_scrolled_button = list;
1036 return;
1037 }
1038 }
1039}
1040
1041static gboolean
1042ctk_path_bar_scroll_timeout (CtkPathBar *path_bar)
1043{
1044 gboolean retval = FALSE(0);
1045
1046 if (path_bar->priv->timer)
1047 {
1048 if (path_bar->priv->scrolling_up)
1049 ctk_path_bar_scroll_up (path_bar);
1050 else if (path_bar->priv->scrolling_down)
1051 ctk_path_bar_scroll_down (path_bar);
1052
1053 if (path_bar->priv->need_timer)
1054 {
1055 path_bar->priv->need_timer = FALSE(0);
1056
1057 path_bar->priv->timer = cdk_threads_add_timeout (TIMEOUT_REPEAT50 * SCROLL_DELAY_FACTOR5,
1058 (GSourceFunc)ctk_path_bar_scroll_timeout,
1059 path_bar);
1060 g_source_set_name_by_id (path_bar->priv->timer, "[ctk+] ctk_path_bar_scroll_timeout");
1061 }
1062 else
1063 retval = TRUE(!(0));
1064 }
1065
1066 return retval;
1067}
1068
1069static void
1070ctk_path_bar_stop_scrolling (CtkPathBar *path_bar)
1071{
1072 if (path_bar->priv->timer)
1073 {
1074 g_source_remove (path_bar->priv->timer);
1075 path_bar->priv->timer = 0;
1076 path_bar->priv->need_timer = FALSE(0);
1077 }
1078}
1079
1080static gboolean
1081ctk_path_bar_slider_up_defocus (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
1082 CdkEventButton *event,
1083 CtkPathBar *path_bar)
1084{
1085 GList *list;
1086 GList *up_button = NULL((void*)0);
1087
1088 if (event->type != CDK_FOCUS_CHANGE)
1089 return FALSE(0);
1090
1091 for (list = g_list_last (path_bar->priv->button_list); list; list = list->prev)
1092 {
1093 if (ctk_widget_get_child_visible (BUTTON_DATA (list->data)((ButtonData *)(list->data))->button))
1094 {
1095 up_button = list;
1096 break;
1097 }
1098 }
1099
1100 /* don't let the focus vanish */
1101 if ((!ctk_widget_is_sensitive (path_bar->priv->up_slider_button)) ||
1102 (!ctk_widget_get_child_visible (path_bar->priv->up_slider_button)))
1103 ctk_widget_grab_focus (BUTTON_DATA (up_button->data)((ButtonData *)(up_button->data))->button);
1104
1105 return FALSE(0);
1106}
1107
1108static gboolean
1109ctk_path_bar_slider_down_defocus (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
1110 CdkEventButton *event,
1111 CtkPathBar *path_bar)
1112{
1113 GList *list;
1114 GList *down_button = NULL((void*)0);
1
'down_button' initialized to a null pointer value
1115
1116 if (event->type != CDK_FOCUS_CHANGE)
2
Assuming field 'type' is equal to CDK_FOCUS_CHANGE
3
Taking false branch
1117 return FALSE(0);
1118
1119 for (list = path_bar->priv->button_list; list; list = list->next)
1120 {
1121 if (ctk_widget_get_child_visible (BUTTON_DATA (list->data)((ButtonData *)(list->data))->button))
1122 {
1123 down_button = list;
1124 break;
1125 }
1126 }
1127
1128 /* don't let the focus vanish */
1129 if ((!ctk_widget_is_sensitive (path_bar->priv->down_slider_button)) ||
4
Assuming the condition is true
1130 (!ctk_widget_get_child_visible (path_bar->priv->down_slider_button)))
1131 ctk_widget_grab_focus (BUTTON_DATA (down_button->data)((ButtonData *)(down_button->data))->button);
5
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'down_button')
1132
1133 return FALSE(0);
1134}
1135
1136static gboolean
1137ctk_path_bar_slider_button_press (CtkWidget *widget,
1138 CdkEventButton *event,
1139 CtkPathBar *path_bar)
1140{
1141 if (event->type != CDK_BUTTON_PRESS || event->button != CDK_BUTTON_PRIMARY(1))
1142 return FALSE(0);
1143
1144 path_bar->priv->ignore_click = FALSE(0);
1145
1146 if (widget == path_bar->priv->up_slider_button)
1147 {
1148 path_bar->priv->scrolling_down = FALSE(0);
1149 path_bar->priv->scrolling_up = TRUE(!(0));
1150 ctk_path_bar_scroll_up (path_bar);
1151 }
1152 else if (widget == path_bar->priv->down_slider_button)
1153 {
1154 path_bar->priv->scrolling_up = FALSE(0);
1155 path_bar->priv->scrolling_down = TRUE(!(0));
1156 ctk_path_bar_scroll_down (path_bar);
1157 }
1158
1159 if (!path_bar->priv->timer)
1160 {
1161 path_bar->priv->need_timer = TRUE(!(0));
1162 path_bar->priv->timer = cdk_threads_add_timeout (TIMEOUT_INITIAL500,
1163 (GSourceFunc)ctk_path_bar_scroll_timeout,
1164 path_bar);
1165 g_source_set_name_by_id (path_bar->priv->timer, "[ctk+] ctk_path_bar_scroll_timeout");
1166 }
1167
1168 return FALSE(0);
1169}
1170
1171static gboolean
1172ctk_path_bar_slider_button_release (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
1173 CdkEventButton *event,
1174 CtkPathBar *path_bar)
1175{
1176 if (event->type != CDK_BUTTON_RELEASE)
1177 return FALSE(0);
1178
1179 path_bar->priv->ignore_click = TRUE(!(0));
1180 ctk_path_bar_stop_scrolling (path_bar);
1181
1182 return FALSE(0);
1183}
1184
1185static void
1186ctk_path_bar_grab_notify (CtkWidget *widget,
1187 gboolean was_grabbed)
1188{
1189 if (!was_grabbed)
1190 ctk_path_bar_stop_scrolling (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
);
1191}
1192
1193static void
1194ctk_path_bar_state_changed (CtkWidget *widget,
1195 CtkStateType previous_state G_GNUC_UNUSED__attribute__ ((__unused__)))
1196{
1197 if (!ctk_widget_is_sensitive (widget))
1198 ctk_path_bar_stop_scrolling (CTK_PATH_BAR (widget)((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_path_bar_get_type ()))))))
);
1199}
1200
1201
1202/* Changes the icons wherever it is needed */
1203static void
1204reload_icons (CtkPathBar *path_bar)
1205{
1206 GList *list;
1207
1208 g_clear_object (&path_bar->priv->root_icon)do { _Static_assert (sizeof *((&path_bar->priv->root_icon
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->root_icon))) _pp = ((&path_bar
->priv->root_icon)); __typeof__ (*((&path_bar->priv
->root_icon))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (
g_object_unref) (_ptr); } while (0)
;
1209 g_clear_object (&path_bar->priv->home_icon)do { _Static_assert (sizeof *((&path_bar->priv->home_icon
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->home_icon))) _pp = ((&path_bar
->priv->home_icon)); __typeof__ (*((&path_bar->priv
->home_icon))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (
g_object_unref) (_ptr); } while (0)
;
1210 g_clear_object (&path_bar->priv->desktop_icon)do { _Static_assert (sizeof *((&path_bar->priv->desktop_icon
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&path_bar->priv->desktop_icon))) _pp = ((&path_bar
->priv->desktop_icon)); __typeof__ (*((&path_bar->
priv->desktop_icon))) _ptr = *_pp; *_pp = ((void*)0); if (
_ptr) (g_object_unref) (_ptr); } while (0)
;
1211
1212 for (list = path_bar->priv->button_list; list; list = list->next)
1213 {
1214 ButtonData *button_data;
1215 gboolean current_dir;
1216
1217 button_data = BUTTON_DATA (list->data)((ButtonData *)(list->data));
1218 if (button_data->type != NORMAL_BUTTON)
1219 {
1220 current_dir = ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (button_data->button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->button)), ((ctk_toggle_button_get_type (
)))))))
);
1221 ctk_path_bar_update_button_appearance (path_bar, button_data, current_dir);
1222 }
1223 }
1224}
1225
1226static void
1227change_icon_theme (CtkPathBar *path_bar)
1228{
1229 reload_icons (path_bar);
1230}
1231
1232/* Callback used when a CtkSettings value changes */
1233static void
1234settings_notify_cb (GObject *object G_GNUC_UNUSED__attribute__ ((__unused__)),
1235 GParamSpec *pspec,
1236 CtkPathBar *path_bar)
1237{
1238 const char *name;
1239
1240 name = g_param_spec_get_name (pspec);
1241
1242 if (strcmp (name, "ctk-icon-theme-name") == 0)
1243 change_icon_theme (path_bar);
1244}
1245
1246static void
1247ctk_path_bar_check_icon_theme (CtkPathBar *path_bar)
1248{
1249 if (path_bar->priv->settings_signal_id == 0)
1250 {
1251 CtkSettings *settings;
1252
1253 settings = ctk_settings_get_for_screen (ctk_widget_get_screen (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
));
1254 path_bar->priv->settings_signal_id = g_signal_connect (settings, "notify",g_signal_connect_data ((settings), ("notify"), (((GCallback) (
settings_notify_cb))), (path_bar), ((void*)0), (GConnectFlags
) 0)
1255 G_CALLBACK (settings_notify_cb), path_bar)g_signal_connect_data ((settings), ("notify"), (((GCallback) (
settings_notify_cb))), (path_bar), ((void*)0), (GConnectFlags
) 0)
;
1256 }
1257
1258 change_icon_theme (path_bar);
1259}
1260
1261/* Public functions and their helpers */
1262static void
1263ctk_path_bar_clear_buttons (CtkPathBar *path_bar)
1264{
1265 while (path_bar->priv->button_list != NULL((void*)0))
1266 {
1267 ctk_container_remove (CTK_CONTAINER (path_bar)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_container_get_type ()))))))
, BUTTON_DATA (path_bar->priv->button_list->data)((ButtonData *)(path_bar->priv->button_list->data))->button);
1268 }
1269 path_bar->priv->first_scrolled_button = NULL((void*)0);
1270 path_bar->priv->fake_root = NULL((void*)0);
1271}
1272
1273static void
1274button_clicked_cb (CtkWidget *button,
1275 gpointer data)
1276{
1277 ButtonData *button_data;
1278 CtkPathBar *path_bar;
1279 GList *button_list;
1280 gboolean child_is_hidden;
1281 GFile *child_file;
1282
1283 button_data = BUTTON_DATA (data)((ButtonData *)(data));
1284 if (button_data->ignore_changes)
1285 return;
1286
1287 path_bar = CTK_PATH_BAR (ctk_widget_get_parent (button))((((CtkPathBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_widget_get_parent (button))), ((ctk_path_bar_get_type
()))))))
;
1288
1289 button_list = g_list_find (path_bar->priv->button_list, button_data);
1290 g_assert (button_list != NULL)do { if (button_list != ((void*)0)) ; else g_assertion_message_expr
("Ctk", "ctkpathbar.c", 1290, ((const char*) (__func__)), "button_list != NULL"
); } while (0)
;
1291
1292 g_signal_handlers_block_by_func (button,g_signal_handlers_block_matched ((button), (GSignalMatchType)
(G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)0
), (((GCallback) (button_clicked_cb))), (data))
1293 G_CALLBACK (button_clicked_cb), data)g_signal_handlers_block_matched ((button), (GSignalMatchType)
(G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)0
), (((GCallback) (button_clicked_cb))), (data))
;
1294 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_toggle_button_get_type ()))))))
, TRUE(!(0)));
1295 g_signal_handlers_unblock_by_func (button,g_signal_handlers_unblock_matched ((button), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (button_clicked_cb))), (data))
1296 G_CALLBACK (button_clicked_cb), data)g_signal_handlers_unblock_matched ((button), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (button_clicked_cb))), (data))
;
1297
1298 if (button_list->prev)
1299 {
1300 ButtonData *child_data;
1301
1302 child_data = BUTTON_DATA (button_list->prev->data)((ButtonData *)(button_list->prev->data));
1303 child_file = child_data->file;
1304 child_is_hidden = child_data->file_is_hidden;
1305 }
1306 else
1307 {
1308 child_file = NULL((void*)0);
1309 child_is_hidden = FALSE(0);
1310 }
1311
1312 g_signal_emit (path_bar, path_bar_signals [PATH_CLICKED], 0,
1313 button_data->file, child_file, child_is_hidden);
1314}
1315
1316struct SetButtonImageData
1317{
1318 CtkPathBar *path_bar;
1319 ButtonData *button_data;
1320};
1321
1322static void
1323set_button_image_get_info_cb (GCancellable *cancellable,
1324 GFileInfo *info,
1325 const GError *error,
1326 gpointer user_data)
1327{
1328 gboolean cancelled = g_cancellable_is_cancelled (cancellable);
1329 GIcon *icon;
1330 struct SetButtonImageData *data = user_data;
1331
1332 if (cancelled)
1333 {
1334 g_free (data);
1335 g_object_unref (cancellable);
1336 return;
1337 }
1338
1339 g_assert (CTK_IS_PATH_BAR (data->path_bar))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((data->path_bar)); GType __t = ((ctk_path_bar_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ; else g_assertion_message_expr ("Ctk", "ctkpathbar.c"
, 1339, ((const char*) (__func__)), "CTK_IS_PATH_BAR (data->path_bar)"
); } while (0)
;
1340 g_assert (G_OBJECT (data->path_bar)->ref_count > 0)do { if (((((GObject*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data->path_bar)), (((GType) ((20) <<
(2))))))))->ref_count > 0) ; else g_assertion_message_expr
("Ctk", "ctkpathbar.c", 1340, ((const char*) (__func__)), "G_OBJECT (data->path_bar)->ref_count > 0"
); } while (0)
;
1341
1342 g_assert (cancellable == data->button_data->cancellable)do { if (cancellable == data->button_data->cancellable)
; else g_assertion_message_expr ("Ctk", "ctkpathbar.c", 1342
, ((const char*) (__func__)), "cancellable == data->button_data->cancellable"
); } while (0)
;
1343 cancellable_async_done (data->path_bar, cancellable);
1344 data->button_data->cancellable = NULL((void*)0);
1345
1346 if (error)
1347 goto out;
1348
1349 icon = g_file_info_get_symbolic_icon (info);
1350 ctk_image_set_from_gicon (CTK_IMAGE (data->button_data->image)((((CtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data->button_data->image)), ((ctk_image_get_type (
)))))))
, icon, CTK_ICON_SIZE_BUTTON);
1351
1352 switch (data->button_data->type)
1353 {
1354 case HOME_BUTTON:
1355 g_set_object (&data->path_bar->priv->home_icon, icon)(__extension__ ({ _Static_assert (sizeof *(&data->path_bar
->priv->home_icon) == sizeof (icon), "Expression evaluates to false"
); union { char *in; GObject **out; } _object_ptr; _object_ptr
.in = (char *) (&data->path_bar->priv->home_icon
); (void) (0 ? *(&data->path_bar->priv->home_icon
) = (icon), (0) : (0)); (g_set_object) (_object_ptr.out, (GObject
*) icon); }))
;
1356 break;
1357
1358 case DESKTOP_BUTTON:
1359 g_set_object (&data->path_bar->priv->desktop_icon, icon)(__extension__ ({ _Static_assert (sizeof *(&data->path_bar
->priv->desktop_icon) == sizeof (icon), "Expression evaluates to false"
); union { char *in; GObject **out; } _object_ptr; _object_ptr
.in = (char *) (&data->path_bar->priv->desktop_icon
); (void) (0 ? *(&data->path_bar->priv->desktop_icon
) = (icon), (0) : (0)); (g_set_object) (_object_ptr.out, (GObject
*) icon); }))
;
1360 break;
1361
1362 default:
1363 break;
1364 };
1365
1366out:
1367 g_free (data);
1368}
1369
1370static void
1371set_button_image (CtkPathBar *path_bar,
1372 ButtonData *button_data)
1373{
1374 CtkFileSystemVolume *volume;
1375 struct SetButtonImageData *data;
1376
1377 switch (button_data->type)
1378 {
1379 case ROOT_BUTTON:
1380
1381 if (path_bar->priv->root_icon != NULL((void*)0))
1382 {
1383 ctk_image_set_from_gicon (CTK_IMAGE (button_data->image)((((CtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->image)), ((ctk_image_get_type ()))))))
, path_bar->priv->root_icon, CTK_ICON_SIZE_BUTTON);
1384 break;
1385 }
1386
1387 volume = _ctk_file_system_get_volume_for_file (path_bar->priv->file_system, path_bar->priv->root_file);
1388 if (volume == NULL((void*)0))
1389 return;
1390
1391 path_bar->priv->root_icon = _ctk_file_system_volume_get_symbolic_icon (volume);
1392 _ctk_file_system_volume_unref (volume);
1393 ctk_image_set_from_gicon (CTK_IMAGE (button_data->image)((((CtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->image)), ((ctk_image_get_type ()))))))
, path_bar->priv->root_icon, CTK_ICON_SIZE_BUTTON);
1394
1395 break;
1396
1397 case HOME_BUTTON:
1398 if (path_bar->priv->home_icon != NULL((void*)0))
1399 {
1400 ctk_image_set_from_gicon (CTK_IMAGE (button_data->image)((((CtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->image)), ((ctk_image_get_type ()))))))
, path_bar->priv->home_icon, CTK_ICON_SIZE_BUTTON);
1401 break;
1402 }
1403
1404 data = g_new0 (struct SetButtonImageData, 1)((struct SetButtonImageData *) g_malloc0_n ((1), sizeof (struct
SetButtonImageData)))
;
1405 data->path_bar = path_bar;
1406 data->button_data = button_data;
1407
1408 if (button_data->cancellable)
1409 {
1410 cancel_cancellable (path_bar, button_data->cancellable);
1411 }
1412
1413 button_data->cancellable =
1414 _ctk_file_system_get_info (path_bar->priv->file_system,
1415 path_bar->priv->home_file,
1416 "standard::symbolic-icon",
1417 set_button_image_get_info_cb,
1418 data);
1419 add_cancellable (path_bar, button_data->cancellable);
1420 break;
1421
1422 case DESKTOP_BUTTON:
1423 if (path_bar->priv->desktop_icon != NULL((void*)0))
1424 {
1425 ctk_image_set_from_gicon (CTK_IMAGE (button_data->image)((((CtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->image)), ((ctk_image_get_type ()))))))
, path_bar->priv->desktop_icon, CTK_ICON_SIZE_BUTTON);
1426 break;
1427 }
1428
1429 data = g_new0 (struct SetButtonImageData, 1)((struct SetButtonImageData *) g_malloc0_n ((1), sizeof (struct
SetButtonImageData)))
;
1430 data->path_bar = path_bar;
1431 data->button_data = button_data;
1432
1433 if (button_data->cancellable)
1434 {
1435 cancel_cancellable (path_bar, button_data->cancellable);
1436 }
1437
1438 button_data->cancellable =
1439 _ctk_file_system_get_info (path_bar->priv->file_system,
1440 path_bar->priv->desktop_file,
1441 "standard::symbolic-icon",
1442 set_button_image_get_info_cb,
1443 data);
1444 add_cancellable (path_bar, button_data->cancellable);
1445 break;
1446 default:
1447 break;
1448 }
1449}
1450
1451static void
1452button_data_free (ButtonData *button_data)
1453{
1454 if (button_data->file)
1455 g_object_unref (button_data->file);
1456 button_data->file = NULL((void*)0);
1457
1458 g_free (button_data->dir_name);
1459 button_data->dir_name = NULL((void*)0);
1460
1461 button_data->button = NULL((void*)0);
1462
1463 g_free (button_data);
1464}
1465
1466static const char *
1467get_dir_name (ButtonData *button_data)
1468{
1469 return button_data->dir_name;
1470}
1471
1472static void
1473ctk_path_bar_update_button_appearance (CtkPathBar *path_bar,
1474 ButtonData *button_data,
1475 gboolean current_dir)
1476{
1477 const gchar *dir_name = get_dir_name (button_data);
1478 CtkStyleContext *context;
1479
1480 context = ctk_widget_get_style_context (button_data->button);
1481
1482 ctk_style_context_remove_class (context, "text-button");
1483 ctk_style_context_remove_class (context, "image-button");
1484
1485 if (button_data->label != NULL((void*)0))
1486 {
1487 ctk_label_set_text (CTK_LABEL (button_data->label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->label)), ((ctk_label_get_type ()))))))
, dir_name);
1488 if (button_data->image == NULL((void*)0))
1489 ctk_style_context_add_class (context, "text-button");
1490 }
1491
1492 if (button_data->image != NULL((void*)0))
1493 {
1494 set_button_image (path_bar, button_data);
1495 if (button_data->label == NULL((void*)0))
1496 ctk_style_context_add_class (context, "image-button");
1497 }
1498
1499 if (ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (button_data->button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->button)), ((ctk_toggle_button_get_type (
)))))))
) != current_dir)
1500 {
1501 button_data->ignore_changes = TRUE(!(0));
1502 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (button_data->button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->button)), ((ctk_toggle_button_get_type (
)))))))
, current_dir);
1503 button_data->ignore_changes = FALSE(0);
1504 }
1505}
1506
1507static ButtonType
1508find_button_type (CtkPathBar *path_bar,
1509 GFile *file)
1510{
1511 if (path_bar->priv->root_file != NULL((void*)0) &&
1512 g_file_equal (file, path_bar->priv->root_file))
1513 return ROOT_BUTTON;
1514 if (path_bar->priv->home_file != NULL((void*)0) &&
1515 g_file_equal (file, path_bar->priv->home_file))
1516 return HOME_BUTTON;
1517 if (path_bar->priv->desktop_file != NULL((void*)0) &&
1518 g_file_equal (file, path_bar->priv->desktop_file))
1519 return DESKTOP_BUTTON;
1520
1521 return NORMAL_BUTTON;
1522}
1523
1524static void
1525button_drag_data_get_cb (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
1526 CdkDragContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
1527 CtkSelectionData *selection_data,
1528 guint info G_GNUC_UNUSED__attribute__ ((__unused__)),
1529 guint time_ G_GNUC_UNUSED__attribute__ ((__unused__)),
1530 gpointer data)
1531{
1532 ButtonData *button_data;
1533 char *uris[2];
1534
1535 button_data = data;
1536
1537 uris[0] = g_file_get_uri (button_data->file);
1538 uris[1] = NULL((void*)0);
1539
1540 ctk_selection_data_set_uris (selection_data, uris);
1541
1542 g_free (uris[0]);
1543}
1544
1545static ButtonData *
1546make_directory_button (CtkPathBar *path_bar,
1547 const char *dir_name,
1548 GFile *file,
1549 gboolean current_dir,
1550 gboolean file_is_hidden)
1551{
1552 AtkObject *atk_obj;
1553 CtkWidget *child = NULL((void*)0);
1554 ButtonData *button_data;
1555
1556 file_is_hidden = !! file_is_hidden;
1557 /* Is it a special button? */
1558 button_data = g_new0 (ButtonData, 1)((ButtonData *) g_malloc0_n ((1), sizeof (ButtonData)));
1559 button_data->type = find_button_type (path_bar, file);
1560 button_data->button = ctk_toggle_button_new ();
1561 atk_obj = ctk_widget_get_accessible (button_data->button);
1562 ctk_widget_set_focus_on_click (button_data->button, FALSE(0));
1563 ctk_widget_add_events (button_data->button, CDK_SCROLL_MASK);
1564
1565 switch (button_data->type)
1566 {
1567 case ROOT_BUTTON:
1568 button_data->image = ctk_image_new ();
1569 child = button_data->image;
1570 button_data->label = NULL((void*)0);
1571 atk_object_set_name (atk_obj, _("File System Root")((char *) g_dgettext ("ctk30", "File System Root")));
1572 break;
1573 case HOME_BUTTON:
1574 case DESKTOP_BUTTON:
1575 button_data->image = ctk_image_new ();
1576 button_data->label = ctk_label_new (NULL((void*)0));
1577 child = ctk_box_new (CTK_ORIENTATION_HORIZONTAL, 0);
1578 ctk_box_pack_start (CTK_BOX (child)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_box_get_type ()))))))
, button_data->image, FALSE(0), FALSE(0), 0);
1579 ctk_box_pack_start (CTK_BOX (child)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_box_get_type ()))))))
, button_data->label, FALSE(0), FALSE(0), 0);
1580 break;
1581 case NORMAL_BUTTON:
1582 default:
1583 button_data->label = ctk_label_new (NULL((void*)0));
1584 child = button_data->label;
1585 button_data->image = NULL((void*)0);
1586 }
1587
1588 button_data->dir_name = g_strdup (dir_name)g_strdup_inline (dir_name);
1589 button_data->file = g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file));
1590 button_data->file_is_hidden = file_is_hidden;
1591
1592 ctk_container_add (CTK_CONTAINER (button_data->button)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->button)), ((ctk_container_get_type ())))
)))
, child);
1593 ctk_widget_show_all (button_data->button);
1594
1595 ctk_path_bar_update_button_appearance (path_bar, button_data, current_dir);
1596
1597 g_signal_connect (button_data->button, "clicked",g_signal_connect_data ((button_data->button), ("clicked"),
(((GCallback) (button_clicked_cb))), (button_data), ((void*)
0), (GConnectFlags) 0)
1598 G_CALLBACK (button_clicked_cb),g_signal_connect_data ((button_data->button), ("clicked"),
(((GCallback) (button_clicked_cb))), (button_data), ((void*)
0), (GConnectFlags) 0)
1599 button_data)g_signal_connect_data ((button_data->button), ("clicked"),
(((GCallback) (button_clicked_cb))), (button_data), ((void*)
0), (GConnectFlags) 0)
;
1600 g_object_weak_ref (G_OBJECT (button_data->button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button_data->button)), (((GType) ((20) << (2)))
)))))
,
1601 (GWeakNotify) button_data_free, button_data);
1602
1603 ctk_drag_source_set (button_data->button,
1604 CDK_BUTTON1_MASK,
1605 NULL((void*)0), 0,
1606 CDK_ACTION_COPY);
1607 ctk_drag_source_add_uri_targets (button_data->button);
1608 g_signal_connect (button_data->button, "drag-data-get",g_signal_connect_data ((button_data->button), ("drag-data-get"
), (((GCallback) (button_drag_data_get_cb))), (button_data), (
(void*)0), (GConnectFlags) 0)
1609 G_CALLBACK (button_drag_data_get_cb), button_data)g_signal_connect_data ((button_data->button), ("drag-data-get"
), (((GCallback) (button_drag_data_get_cb))), (button_data), (
(void*)0), (GConnectFlags) 0)
;
1610
1611 return button_data;
1612}
1613
1614static gboolean
1615ctk_path_bar_check_parent_path (CtkPathBar *path_bar,
1616 GFile *file)
1617{
1618 GList *list;
1619 GList *current_path = NULL((void*)0);
1620 gboolean need_new_fake_root = FALSE(0);
1621
1622 for (list = path_bar->priv->button_list; list; list = list->next)
1623 {
1624 ButtonData *button_data;
1625
1626 button_data = list->data;
1627 if (g_file_equal (file, button_data->file))
1628 {
1629 current_path = list;
1630 break;
1631 }
1632 if (list == path_bar->priv->fake_root)
1633 need_new_fake_root = TRUE(!(0));
1634 }
1635
1636 if (current_path)
1637 {
1638 if (need_new_fake_root)
1639 {
1640 path_bar->priv->fake_root = NULL((void*)0);
1641 for (list = current_path; list; list = list->next)
1642 {
1643 ButtonData *button_data;
1644
1645 button_data = list->data;
1646 if (BUTTON_IS_FAKE_ROOT (button_data)((button_data)->type == HOME_BUTTON))
1647 {
1648 path_bar->priv->fake_root = list;
1649 break;
1650 }
1651 }
1652 }
1653
1654 for (list = path_bar->priv->button_list; list; list = list->next)
1655 {
1656 ctk_path_bar_update_button_appearance (path_bar,
1657 BUTTON_DATA (list->data)((ButtonData *)(list->data)),
1658 (list == current_path) ? TRUE(!(0)) : FALSE(0));
1659 }
1660
1661 if (!ctk_widget_get_child_visible (BUTTON_DATA (current_path->data)((ButtonData *)(current_path->data))->button))
1662 {
1663 path_bar->priv->first_scrolled_button = current_path;
1664 ctk_widget_queue_resize (CTK_WIDGET (path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((path_bar)), ((ctk_widget_get_type ()))))))
);
1665 }
1666
1667 return TRUE(!(0));
1668 }
1669 return FALSE(0);
1670}
1671
1672
1673struct SetFileInfo
1674{
1675 GFile *file;
1676 GFile *parent_file;
1677 CtkPathBar *path_bar;
1678 GList *new_buttons;
1679 GList *fake_root;
1680 gboolean first_directory;
1681};
1682
1683static void
1684ctk_path_bar_set_file_finish (struct SetFileInfo *info,
1685 gboolean result)
1686{
1687 if (result)
1688 {
1689 GList *l;
1690 CtkCssNode *prev;
1691
1692 ctk_path_bar_clear_buttons (info->path_bar);
1693 info->path_bar->priv->button_list = g_list_reverse (info->new_buttons);
1694 info->path_bar->priv->fake_root = info->fake_root;
1695 prev = ctk_widget_get_css_node (info->path_bar->priv->down_slider_button);
1696
1697 for (l = info->path_bar->priv->button_list; l; l = l->next)
1698 {
1699 CtkWidget *button = BUTTON_DATA (l->data)((ButtonData *)(l->data))->button;
1700 CtkCssNode *node = ctk_widget_get_css_node (button);
1701
1702 ctk_css_node_insert_before (ctk_widget_get_css_node (CTK_WIDGET (info->path_bar)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((info->path_bar)), ((ctk_widget_get_type ()))))))
),
1703 node,
1704 prev);
1705 ctk_container_add (CTK_CONTAINER (info->path_bar)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((info->path_bar)), ((ctk_container_get_type ()))))))
, button);
1706 prev = node;
1707 }
1708 }
1709 else
1710 {
1711 GList *l;
1712
1713 for (l = info->new_buttons; l; l = l->next)
1714 {
1715 ButtonData *button_data;
1716
1717 button_data = BUTTON_DATA (l->data)((ButtonData *)(l->data));
1718 ctk_widget_destroy (button_data->button);
1719 }
1720
1721 g_list_free (info->new_buttons);
1722 }
1723
1724 if (info->file)
1725 g_object_unref (info->file);
1726 if (info->parent_file)
1727 g_object_unref (info->parent_file);
1728
1729 g_free (info);
1730}
1731
1732static void
1733ctk_path_bar_get_info_callback (GCancellable *cancellable,
1734 GFileInfo *info,
1735 const GError *error G_GNUC_UNUSED__attribute__ ((__unused__)),
1736 gpointer data)
1737{
1738 gboolean cancelled = g_cancellable_is_cancelled (cancellable);
1739 struct SetFileInfo *file_info = data;
1740 ButtonData *button_data;
1741 const gchar *display_name;
1742 gboolean is_hidden;
1743
1744 if (cancelled)
1745 {
1746 ctk_path_bar_set_file_finish (file_info, FALSE(0));
1747 g_object_unref (cancellable);
1748 return;
1749 }
1750
1751 g_assert (CTK_IS_PATH_BAR (file_info->path_bar))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((file_info->path_bar)); GType __t = ((ctk_path_bar_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ; else g_assertion_message_expr ("Ctk", "ctkpathbar.c"
, 1751, ((const char*) (__func__)), "CTK_IS_PATH_BAR (file_info->path_bar)"
); } while (0)
;
1752 g_assert (G_OBJECT (file_info->path_bar)->ref_count > 0)do { if (((((GObject*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((file_info->path_bar)), (((GType) ((20) <<
(2))))))))->ref_count > 0) ; else g_assertion_message_expr
("Ctk", "ctkpathbar.c", 1752, ((const char*) (__func__)), "G_OBJECT (file_info->path_bar)->ref_count > 0"
); } while (0)
;
1753
1754 g_assert (cancellable == file_info->path_bar->priv->get_info_cancellable)do { if (cancellable == file_info->path_bar->priv->get_info_cancellable
) ; else g_assertion_message_expr ("Ctk", "ctkpathbar.c", 1754
, ((const char*) (__func__)), "cancellable == file_info->path_bar->priv->get_info_cancellable"
); } while (0)
;
1755 cancellable_async_done (file_info->path_bar, cancellable);
1756 file_info->path_bar->priv->get_info_cancellable = NULL((void*)0);
1757
1758 if (!info)
1759 {
1760 ctk_path_bar_set_file_finish (file_info, FALSE(0));
1761 return;
1762 }
1763
1764 display_name = g_file_info_get_display_name (info);
1765 is_hidden = g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info);
1766
1767 button_data = make_directory_button (file_info->path_bar, display_name,
1768 file_info->file,
1769 file_info->first_directory, is_hidden);
1770 g_clear_object (&file_info->file)do { _Static_assert (sizeof *((&file_info->file)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&file_info->file))) _pp = ((&file_info->file));
__typeof__ (*((&file_info->file))) _ptr = *_pp; *_pp =
((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (0)
;
1771
1772 file_info->new_buttons = g_list_prepend (file_info->new_buttons, button_data);
1773
1774 if (BUTTON_IS_FAKE_ROOT (button_data)((button_data)->type == HOME_BUTTON))
1775 file_info->fake_root = file_info->new_buttons;
1776
1777 /* We have assigned the info for the innermost button, i.e. the deepest directory.
1778 * Now, go on to fetch the info for this directory's parent.
1779 */
1780
1781 file_info->file = file_info->parent_file;
1782 file_info->first_directory = FALSE(0);
1783
1784 if (!file_info->file)
1785 {
1786 /* No parent? Okay, we are done. */
1787 ctk_path_bar_set_file_finish (file_info, TRUE(!(0)));
1788 return;
1789 }
1790
1791 file_info->parent_file = g_file_get_parent (file_info->file);
1792
1793 /* Recurse asynchronously */
1794 file_info->path_bar->priv->get_info_cancellable =
1795 _ctk_file_system_get_info (file_info->path_bar->priv->file_system,
1796 file_info->file,
1797 "standard::display-name,standard::is-hidden,standard::is-backup",
1798 ctk_path_bar_get_info_callback,
1799 file_info);
1800 add_cancellable (file_info->path_bar, file_info->path_bar->priv->get_info_cancellable);
1801}
1802
1803void
1804_ctk_path_bar_set_file (CtkPathBar *path_bar,
1805 GFile *file,
1806 gboolean keep_trail)
1807{
1808 struct SetFileInfo *info;
1809
1810 g_return_if_fail (CTK_IS_PATH_BAR (path_bar))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((path_bar)); GType __t = ((ctk_path_bar_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_PATH_BAR (path_bar)"); return; } } while (0)
;
1811 g_return_if_fail (G_IS_FILE (file))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((file)); GType __t = ((g_file_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "G_IS_FILE (file)"); return; } } while (0)
;
1812
1813 /* Check whether the new path is already present in the pathbar as buttons.
1814 * This could be a parent directory or a previous selected subdirectory.
1815 */
1816 if (keep_trail && ctk_path_bar_check_parent_path (path_bar, file))
1817 return;
1818
1819 info = g_new0 (struct SetFileInfo, 1)((struct SetFileInfo *) g_malloc0_n ((1), sizeof (struct SetFileInfo
)))
;
1820 info->file = g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file));
1821 info->path_bar = path_bar;
1822 info->first_directory = TRUE(!(0));
1823 info->parent_file = g_file_get_parent (info->file);
1824
1825 if (path_bar->priv->get_info_cancellable)
1826 {
1827 cancel_cancellable (path_bar, path_bar->priv->get_info_cancellable);
1828 }
1829
1830 path_bar->priv->get_info_cancellable =
1831 _ctk_file_system_get_info (path_bar->priv->file_system,
1832 info->file,
1833 "standard::display-name,standard::is-hidden,standard::is-backup",
1834 ctk_path_bar_get_info_callback,
1835 info);
1836 add_cancellable (path_bar, path_bar->priv->get_info_cancellable);
1837}
1838
1839/* FIXME: This should be a construct-only property */
1840void
1841_ctk_path_bar_set_file_system (CtkPathBar *path_bar,
1842 CtkFileSystem *file_system)
1843{
1844 const char *home;
1845
1846 g_return_if_fail (CTK_IS_PATH_BAR (path_bar))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((path_bar)); GType __t = ((ctk_path_bar_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_PATH_BAR (path_bar)"); return; } } while (0)
;
1847
1848 g_assert (path_bar->priv->file_system == NULL)do { if (path_bar->priv->file_system == ((void*)0)) ; else
g_assertion_message_expr ("Ctk", "ctkpathbar.c", 1848, ((const
char*) (__func__)), "path_bar->priv->file_system == NULL"
); } while (0)
;
1849
1850 path_bar->priv->file_system = g_object_ref (file_system)((__typeof__ (file_system)) (g_object_ref) (file_system));
1851
1852 home = g_get_home_dir ();
1853 if (home != NULL((void*)0))
1854 {
1855 const gchar *desktop;
1856
1857 path_bar->priv->home_file = g_file_new_for_path (home);
1858 /* FIXME: Need file system backend specific way of getting the
1859 * Desktop path.
1860 */
1861 desktop = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
1862 if (desktop != NULL((void*)0))
1863 path_bar->priv->desktop_file = g_file_new_for_path (desktop);
1864 else
1865 path_bar->priv->desktop_file = NULL((void*)0);
1866 }
1867 else
1868 {
1869 path_bar->priv->home_file = NULL((void*)0);
1870 path_bar->priv->desktop_file = NULL((void*)0);
1871 }
1872 path_bar->priv->root_file = g_file_new_for_path ("/");
1873}
1874
1875/**
1876 * _ctk_path_bar_up:
1877 * @path_bar: a #CtkPathBar
1878 *
1879 * If the selected button in the pathbar is not the furthest button “up” (in the
1880 * root direction), act as if the user clicked on the next button up.
1881 **/
1882void
1883_ctk_path_bar_up (CtkPathBar *path_bar)
1884{
1885 GList *l;
1886
1887 for (l = path_bar->priv->button_list; l; l = l->next)
1888 {
1889 CtkWidget *button = BUTTON_DATA (l->data)((ButtonData *)(l->data))->button;
1890 if (ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_toggle_button_get_type ()))))))
))
1891 {
1892 if (l->next)
1893 {
1894 CtkWidget *next_button = BUTTON_DATA (l->next->data)((ButtonData *)(l->next->data))->button;
1895 button_clicked_cb (next_button, l->next->data);
1896 }
1897 break;
1898 }
1899 }
1900}
1901
1902/**
1903 * _ctk_path_bar_down:
1904 * @path_bar: a #CtkPathBar
1905 *
1906 * If the selected button in the pathbar is not the furthest button “down” (in the
1907 * leaf direction), act as if the user clicked on the next button down.
1908 **/
1909void
1910_ctk_path_bar_down (CtkPathBar *path_bar)
1911{
1912 GList *l;
1913
1914 for (l = path_bar->priv->button_list; l; l = l->next)
1915 {
1916 CtkWidget *button = BUTTON_DATA (l->data)((ButtonData *)(l->data))->button;
1917 if (ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (button)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_toggle_button_get_type ()))))))
))
1918 {
1919 if (l->prev)
1920 {
1921 CtkWidget *prev_button = BUTTON_DATA (l->prev->data)((ButtonData *)(l->prev->data))->button;
1922 button_clicked_cb (prev_button, l->prev->data);
1923 }
1924 break;
1925 }
1926 }
1927}