1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2
3 nemo-merged-directory.c: Subclass of NemoDirectory to implement the
4 virtual merged directory.
5
6 Copyright (C) 1999, 2000 Eazel, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public
19 License along with this program; if not, write to the
20 Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
21 Boston, MA 02110-1335, USA.
22
23 Author: Darin Adler <darin@bentspoon.com>
24 */
25
26 #include <config.h>
27 #include "nemo-merged-directory.h"
28
29 #include "nemo-directory-private.h"
30 #include "nemo-directory-notify.h"
31 #include "nemo-file.h"
32 #include <eel/eel-glib-extensions.h>
33 #include <gtk/gtk.h>
34
35 struct NemoMergedDirectoryDetails {
36 GList *directories;
37 GList *directories_not_done_loading;
38 GHashTable *callbacks;
39 GHashTable *monitors;
40 };
41
42 typedef struct {
43 NemoMergedDirectory *merged;
44 NemoDirectoryCallback callback;
45 gpointer callback_data;
46
47 NemoFileAttributes wait_for_attributes;
48 gboolean wait_for_file_list;
49
50 GList *non_ready_directories;
51 GList *merged_file_list;
52 } MergedCallback;
53
54 typedef struct {
55 NemoMergedDirectory *merged;
56
57 gboolean monitor_hidden_files;
58 NemoFileAttributes monitor_attributes;
59 } MergedMonitor;
60
61 enum {
62 ADD_REAL_DIRECTORY,
63 REMOVE_REAL_DIRECTORY,
64 LAST_SIGNAL
65 };
66
67 static guint signals[LAST_SIGNAL] = { 0 };
68
69 G_DEFINE_TYPE (NemoMergedDirectory, nemo_merged_directory,
70 NEMO_TYPE_DIRECTORY);
71
72 static guint
merged_callback_hash(gconstpointer merged_callback_as_pointer)73 merged_callback_hash (gconstpointer merged_callback_as_pointer)
74 {
75 const MergedCallback *merged_callback;
76
77 merged_callback = merged_callback_as_pointer;
78 return GPOINTER_TO_UINT (merged_callback->callback)
79 ^ GPOINTER_TO_UINT (merged_callback->callback_data);
80 }
81
82 static gboolean
merged_callback_equal(gconstpointer merged_callback_as_pointer,gconstpointer merged_callback_as_pointer_2)83 merged_callback_equal (gconstpointer merged_callback_as_pointer,
84 gconstpointer merged_callback_as_pointer_2)
85 {
86 const MergedCallback *merged_callback, *merged_callback_2;
87
88 merged_callback = merged_callback_as_pointer;
89 merged_callback_2 = merged_callback_as_pointer_2;
90
91 return merged_callback->callback == merged_callback_2->callback
92 && merged_callback->callback_data == merged_callback_2->callback_data;
93 }
94
95 static void
merged_callback_destroy(MergedCallback * merged_callback)96 merged_callback_destroy (MergedCallback *merged_callback)
97 {
98 g_assert (merged_callback != NULL);
99 g_assert (NEMO_IS_MERGED_DIRECTORY (merged_callback->merged));
100
101 g_list_free (merged_callback->non_ready_directories);
102 nemo_file_list_free (merged_callback->merged_file_list);
103 g_free (merged_callback);
104 }
105
106 static void
merged_callback_check_done(MergedCallback * merged_callback)107 merged_callback_check_done (MergedCallback *merged_callback)
108 {
109 /* Check if we are ready. */
110 if (merged_callback->non_ready_directories != NULL) {
111 return;
112 }
113
114 /* Remove from the hash table before sending it. */
115 g_hash_table_remove (merged_callback->merged->details->callbacks, merged_callback);
116
117 /* We are ready, so do the real callback. */
118 (* merged_callback->callback) (NEMO_DIRECTORY (merged_callback->merged),
119 merged_callback->merged_file_list,
120 merged_callback->callback_data);
121
122 /* And we are done. */
123 merged_callback_destroy (merged_callback);
124 }
125
126 static void
merged_callback_remove_directory(MergedCallback * merged_callback,NemoDirectory * directory)127 merged_callback_remove_directory (MergedCallback *merged_callback,
128 NemoDirectory *directory)
129 {
130 merged_callback->non_ready_directories = g_list_remove
131 (merged_callback->non_ready_directories, directory);
132 merged_callback_check_done (merged_callback);
133 }
134
135 static void
directory_ready_callback(NemoDirectory * directory,GList * files,gpointer callback_data)136 directory_ready_callback (NemoDirectory *directory,
137 GList *files,
138 gpointer callback_data)
139 {
140 MergedCallback *merged_callback;
141
142 g_assert (NEMO_IS_DIRECTORY (directory));
143 g_assert (callback_data != NULL);
144
145 merged_callback = callback_data;
146 g_assert (g_list_find (merged_callback->non_ready_directories, directory) != NULL);
147
148 /* Update based on this call. */
149 merged_callback->merged_file_list = g_list_concat
150 (merged_callback->merged_file_list,
151 nemo_file_list_copy (files));
152
153 /* Check if we are ready. */
154 merged_callback_remove_directory (merged_callback, directory);
155 }
156
157 static void
merged_call_when_ready(NemoDirectory * directory,NemoFileAttributes file_attributes,gboolean wait_for_file_list,NemoDirectoryCallback callback,gpointer callback_data)158 merged_call_when_ready (NemoDirectory *directory,
159 NemoFileAttributes file_attributes,
160 gboolean wait_for_file_list,
161 NemoDirectoryCallback callback,
162 gpointer callback_data)
163 {
164 NemoMergedDirectory *merged;
165 MergedCallback search_key, *merged_callback;
166 GList *node;
167
168 merged = NEMO_MERGED_DIRECTORY (directory);
169
170 /* Check to be sure we aren't overwriting. */
171 search_key.callback = callback;
172 search_key.callback_data = callback_data;
173 if (g_hash_table_lookup (merged->details->callbacks, &search_key) != NULL) {
174 g_warning ("tried to add a new callback while an old one was pending");
175 return;
176 }
177
178 /* Create a merged_callback record. */
179 merged_callback = g_new0 (MergedCallback, 1);
180 merged_callback->merged = merged;
181 merged_callback->callback = callback;
182 merged_callback->callback_data = callback_data;
183 merged_callback->wait_for_attributes = file_attributes;
184 merged_callback->wait_for_file_list = wait_for_file_list;
185 for (node = merged->details->directories; node != NULL; node = node->next) {
186 merged_callback->non_ready_directories = g_list_prepend
187 (merged_callback->non_ready_directories, node->data);
188 }
189
190 /* Put it in the hash table. */
191 g_hash_table_insert (merged->details->callbacks,
192 merged_callback, merged_callback);
193
194 /* Handle the pathological case where there are no directories. */
195 if (merged->details->directories == NULL) {
196 merged_callback_check_done (merged_callback);
197 }
198
199 /* Now tell all the directories about it. */
200 for (node = merged->details->directories; node != NULL; node = node->next) {
201 nemo_directory_call_when_ready
202 (node->data,
203 merged_callback->wait_for_attributes,
204 merged_callback->wait_for_file_list,
205 directory_ready_callback, merged_callback);
206 }
207 }
208
209 static void
merged_cancel_callback(NemoDirectory * directory,NemoDirectoryCallback callback,gpointer callback_data)210 merged_cancel_callback (NemoDirectory *directory,
211 NemoDirectoryCallback callback,
212 gpointer callback_data)
213 {
214 NemoMergedDirectory *merged;
215 MergedCallback search_key, *merged_callback;
216 GList *node;
217
218 merged = NEMO_MERGED_DIRECTORY (directory);
219
220 /* Find the entry in the table. */
221 search_key.callback = callback;
222 search_key.callback_data = callback_data;
223 merged_callback = g_hash_table_lookup (merged->details->callbacks, &search_key);
224 if (merged_callback == NULL) {
225 return;
226 }
227
228 /* Remove from the hash table before working with it. */
229 g_hash_table_remove (merged_callback->merged->details->callbacks, merged_callback);
230
231 /* Tell all the directories to cancel the call. */
232 for (node = merged_callback->non_ready_directories; node != NULL; node = node->next) {
233 nemo_directory_cancel_callback
234 (node->data,
235 directory_ready_callback, merged_callback);
236 }
237 merged_callback_destroy (merged_callback);
238 }
239
240 static void
build_merged_callback_list(NemoDirectory * directory,GList * file_list,gpointer callback_data)241 build_merged_callback_list (NemoDirectory *directory,
242 GList *file_list,
243 gpointer callback_data)
244 {
245 GList **merged_list;
246
247 merged_list = callback_data;
248 *merged_list = g_list_concat (*merged_list,
249 nemo_file_list_copy (file_list));
250 }
251
252 /* Create a monitor on each of the directories in the list. */
253 static void
merged_monitor_add(NemoDirectory * directory,gconstpointer client,gboolean monitor_hidden_files,NemoFileAttributes file_attributes,NemoDirectoryCallback callback,gpointer callback_data)254 merged_monitor_add (NemoDirectory *directory,
255 gconstpointer client,
256 gboolean monitor_hidden_files,
257 NemoFileAttributes file_attributes,
258 NemoDirectoryCallback callback,
259 gpointer callback_data)
260 {
261 NemoMergedDirectory *merged;
262 MergedMonitor *monitor;
263 GList *node;
264 GList *merged_callback_list;
265
266 merged = NEMO_MERGED_DIRECTORY (directory);
267
268 /* Map the client to a unique value so this doesn't interfere
269 * with direct monitoring of the directory by the same client.
270 */
271 monitor = g_hash_table_lookup (merged->details->monitors, client);
272 if (monitor != NULL) {
273 g_assert (monitor->merged == merged);
274 } else {
275 monitor = g_new0 (MergedMonitor, 1);
276 monitor->merged = merged;
277 g_hash_table_insert (merged->details->monitors,
278 (gpointer) client, monitor);
279 }
280 monitor->monitor_hidden_files = monitor_hidden_files;
281 monitor->monitor_attributes = file_attributes;
282
283 /* Call through to the real directory add calls. */
284 merged_callback_list = NULL;
285 for (node = merged->details->directories; node != NULL; node = node->next) {
286 nemo_directory_file_monitor_add
287 (node->data, monitor,
288 monitor_hidden_files,
289 file_attributes,
290 build_merged_callback_list, &merged_callback_list);
291 }
292 if (callback != NULL) {
293 (* callback) (directory, merged_callback_list, callback_data);
294 }
295 nemo_file_list_free (merged_callback_list);
296 }
297
298 static void
merged_monitor_destroy(NemoMergedDirectory * merged,MergedMonitor * monitor)299 merged_monitor_destroy (NemoMergedDirectory *merged, MergedMonitor *monitor)
300 {
301 GList *node;
302
303 /* Call through to the real directory remove calls. */
304 for (node = merged->details->directories; node != NULL; node = node->next) {
305 nemo_directory_file_monitor_remove (node->data, monitor);
306 }
307
308 g_free (monitor);
309 }
310
311 /* Remove the monitor from each of the directories in the list. */
312 static void
merged_monitor_remove(NemoDirectory * directory,gconstpointer client)313 merged_monitor_remove (NemoDirectory *directory,
314 gconstpointer client)
315 {
316 NemoMergedDirectory *merged;
317 MergedMonitor *monitor;
318
319 merged = NEMO_MERGED_DIRECTORY (directory);
320
321 /* Map the client to the value used by the earlier add call. */
322 monitor = g_hash_table_lookup (merged->details->monitors, client);
323 if (monitor == NULL) {
324 return;
325 }
326 g_hash_table_remove (merged->details->monitors, client);
327
328 merged_monitor_destroy (merged, monitor);
329 }
330
331 static void
merged_force_reload(NemoDirectory * directory)332 merged_force_reload (NemoDirectory *directory)
333 {
334 NemoMergedDirectory *merged;
335 GList *node;
336
337 merged = NEMO_MERGED_DIRECTORY (directory);
338
339 /* Call through to the real force_reload calls. */
340 for (node = merged->details->directories; node != NULL; node = node->next) {
341 nemo_directory_force_reload (node->data);
342 }
343 }
344
345 /* Return true if any directory in the list does. */
346 static gboolean
merged_contains_file(NemoDirectory * directory,NemoFile * file)347 merged_contains_file (NemoDirectory *directory,
348 NemoFile *file)
349 {
350 NemoMergedDirectory *merged;
351 GList *node;
352
353 merged = NEMO_MERGED_DIRECTORY (directory);
354
355 for (node = merged->details->directories; node != NULL; node = node->next) {
356 if (nemo_directory_contains_file (node->data, file)) {
357 return TRUE;
358 }
359 }
360 return FALSE;
361 }
362
363 /* Return true only if all directories in the list do. */
364 static gboolean
merged_are_all_files_seen(NemoDirectory * directory)365 merged_are_all_files_seen (NemoDirectory *directory)
366 {
367 NemoMergedDirectory *merged;
368 GList *node;
369
370 merged = NEMO_MERGED_DIRECTORY (directory);
371
372 for (node = merged->details->directories; node != NULL; node = node->next) {
373 if (!nemo_directory_are_all_files_seen (node->data)) {
374 return FALSE;
375 }
376 }
377 return TRUE;
378 }
379
380 /* Return true if any directory in the list does. */
381 static gboolean
merged_is_not_empty(NemoDirectory * directory)382 merged_is_not_empty (NemoDirectory *directory)
383 {
384 NemoMergedDirectory *merged;
385 GList *node;
386
387 merged = NEMO_MERGED_DIRECTORY (directory);
388
389 for (node = merged->details->directories; node != NULL; node = node->next) {
390 if (nemo_directory_is_not_empty (node->data)) {
391 return TRUE;
392 }
393 }
394 return FALSE;
395 }
396
397 static GList *
merged_get_file_list(NemoDirectory * directory)398 merged_get_file_list (NemoDirectory *directory)
399 {
400 GList *dirs_file_list, *merged_dir_file_list = NULL;
401 GList *dir_list;
402 GList *cur_node;
403
404 dirs_file_list = NULL;
405 dir_list = NEMO_MERGED_DIRECTORY (directory)->details->directories;
406
407 for (cur_node = dir_list; cur_node != NULL; cur_node = cur_node->next) {
408 NemoDirectory *cur_dir;
409
410 cur_dir = NEMO_DIRECTORY (cur_node->data);
411 dirs_file_list = g_list_concat (dirs_file_list,
412 nemo_directory_get_file_list (cur_dir));
413 }
414
415 merged_dir_file_list = NEMO_DIRECTORY_CLASS
416 (nemo_merged_directory_parent_class)->get_file_list (directory);
417
418 return g_list_concat (dirs_file_list, merged_dir_file_list);
419 }
420
421 static void
forward_files_added_cover(NemoDirectory * real_directory,GList * files,gpointer callback_data)422 forward_files_added_cover (NemoDirectory *real_directory,
423 GList *files,
424 gpointer callback_data)
425 {
426 nemo_directory_emit_files_added (NEMO_DIRECTORY (callback_data), files);
427 }
428
429 static void
forward_files_changed_cover(NemoDirectory * real_directory,GList * files,gpointer callback_data)430 forward_files_changed_cover (NemoDirectory *real_directory,
431 GList *files,
432 gpointer callback_data)
433 {
434 nemo_directory_emit_files_changed (NEMO_DIRECTORY (callback_data), files);
435 }
436
437 static void
done_loading_callback(NemoDirectory * real_directory,NemoMergedDirectory * merged)438 done_loading_callback (NemoDirectory *real_directory,
439 NemoMergedDirectory *merged)
440 {
441 merged->details->directories_not_done_loading = g_list_remove
442 (merged->details->directories_not_done_loading, real_directory);
443 if (merged->details->directories_not_done_loading == NULL) {
444 nemo_directory_emit_done_loading (NEMO_DIRECTORY (merged));
445 }
446 }
447
448 static void
monitor_add_directory(gpointer key,gpointer value,gpointer callback_data)449 monitor_add_directory (gpointer key,
450 gpointer value,
451 gpointer callback_data)
452 {
453 MergedMonitor *monitor;
454
455 monitor = value;
456 nemo_directory_file_monitor_add
457 (NEMO_DIRECTORY (callback_data), monitor,
458 monitor->monitor_hidden_files,
459 monitor->monitor_attributes,
460 forward_files_added_cover, monitor->merged);
461 }
462
463 static void
merged_add_real_directory(NemoMergedDirectory * merged,NemoDirectory * real_directory)464 merged_add_real_directory (NemoMergedDirectory *merged,
465 NemoDirectory *real_directory)
466 {
467 g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged));
468 g_return_if_fail (NEMO_IS_DIRECTORY (real_directory));
469 g_return_if_fail (!NEMO_IS_MERGED_DIRECTORY (real_directory));
470 g_return_if_fail (g_list_find (merged->details->directories, real_directory) == NULL);
471
472 /* Add to our list of directories. */
473 nemo_directory_ref (real_directory);
474 merged->details->directories = g_list_prepend
475 (merged->details->directories, real_directory);
476 merged->details->directories_not_done_loading = g_list_prepend
477 (merged->details->directories_not_done_loading, real_directory);
478
479 g_signal_connect_object (real_directory, "done_loading",
480 G_CALLBACK (done_loading_callback), merged, 0);
481
482 /* FIXME bugzilla.gnome.org 45084: The done_loading part won't work for the case where
483 * we have no directories in our list.
484 */
485
486 /* Add the directory to any extant monitors. */
487 g_hash_table_foreach (merged->details->monitors,
488 monitor_add_directory,
489 real_directory);
490 /* FIXME bugzilla.gnome.org 42541: Do we need to add the directory to callbacks too? */
491
492 g_signal_connect_object (real_directory, "files_added",
493 G_CALLBACK (forward_files_added_cover), merged, 0);
494 g_signal_connect_object (real_directory, "files_changed",
495 G_CALLBACK (forward_files_changed_cover), merged, 0);
496 }
497
498 void
nemo_merged_directory_add_real_directory(NemoMergedDirectory * merged,NemoDirectory * real_directory)499 nemo_merged_directory_add_real_directory (NemoMergedDirectory *merged,
500 NemoDirectory *real_directory)
501 {
502 g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged));
503 g_return_if_fail (NEMO_IS_DIRECTORY (real_directory));
504 g_return_if_fail (!NEMO_IS_MERGED_DIRECTORY (real_directory));
505
506 /* Quietly do nothing if asked to add something that's already there. */
507 if (g_list_find (merged->details->directories, real_directory) != NULL) {
508 return;
509 }
510
511 g_signal_emit (merged, signals[ADD_REAL_DIRECTORY], 0, real_directory);
512 }
513
514 GList *
nemo_merged_directory_get_real_directories(NemoMergedDirectory * merged)515 nemo_merged_directory_get_real_directories (NemoMergedDirectory *merged)
516 {
517 return g_list_copy (merged->details->directories);
518 }
519
520 static void
merged_callback_remove_directory_cover(gpointer key,gpointer value,gpointer callback_data)521 merged_callback_remove_directory_cover (gpointer key,
522 gpointer value,
523 gpointer callback_data)
524 {
525 merged_callback_remove_directory
526 (value, NEMO_DIRECTORY (callback_data));
527 }
528
529 static void
monitor_remove_directory(gpointer key,gpointer value,gpointer callback_data)530 monitor_remove_directory (gpointer key,
531 gpointer value,
532 gpointer callback_data)
533 {
534 nemo_directory_file_monitor_remove
535 (NEMO_DIRECTORY (callback_data), value);
536 }
537
538 static void
real_directory_notify_files_removed(NemoDirectory * real_directory)539 real_directory_notify_files_removed (NemoDirectory *real_directory)
540 {
541 GList *files, *l;
542
543 files = nemo_directory_get_file_list (real_directory);
544
545 for (l = files; l; l = l->next) {
546 NemoFile *file;
547 char *uri;
548
549 file = NEMO_FILE (l->data);
550 uri = nemo_file_get_uri (file);
551 nemo_file_unref (file);
552
553 l->data = uri;
554 }
555
556 if (files) {
557 nemo_directory_notify_files_removed_by_uri (files);
558 }
559
560 g_list_free_full (files, g_free);
561 }
562
563 static void
merged_remove_real_directory(NemoMergedDirectory * merged,NemoDirectory * real_directory)564 merged_remove_real_directory (NemoMergedDirectory *merged,
565 NemoDirectory *real_directory)
566 {
567 g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged));
568 g_return_if_fail (NEMO_IS_DIRECTORY (real_directory));
569 g_return_if_fail (g_list_find (merged->details->directories, real_directory) != NULL);
570
571 /* Since the real directory will be going away, act as if files were removed */
572 real_directory_notify_files_removed (real_directory);
573
574 /* Remove this directory from callbacks and monitors. */
575 eel_g_hash_table_safe_for_each (merged->details->callbacks,
576 merged_callback_remove_directory_cover,
577 real_directory);
578 g_hash_table_foreach (merged->details->monitors,
579 monitor_remove_directory,
580 real_directory);
581
582 /* Disconnect all the signals. */
583 g_signal_handlers_disconnect_matched
584 (real_directory, G_SIGNAL_MATCH_DATA,
585 0, 0, NULL, NULL, merged);
586
587 /* Remove from our list of directories. */
588 merged->details->directories = g_list_remove
589 (merged->details->directories, real_directory);
590 merged->details->directories_not_done_loading = g_list_remove
591 (merged->details->directories_not_done_loading, real_directory);
592 nemo_directory_unref (real_directory);
593 }
594
595 void
nemo_merged_directory_remove_real_directory(NemoMergedDirectory * merged,NemoDirectory * real_directory)596 nemo_merged_directory_remove_real_directory (NemoMergedDirectory *merged,
597 NemoDirectory *real_directory)
598 {
599 g_return_if_fail (NEMO_IS_MERGED_DIRECTORY (merged));
600
601 /* Quietly do nothing if asked to remove something that's not there. */
602 if (g_list_find (merged->details->directories, real_directory) == NULL) {
603 return;
604 }
605
606 g_signal_emit (merged, signals[REMOVE_REAL_DIRECTORY], 0, real_directory);
607 }
608
609 static void
merged_monitor_destroy_cover(gpointer key,gpointer value,gpointer callback_data)610 merged_monitor_destroy_cover (gpointer key,
611 gpointer value,
612 gpointer callback_data)
613 {
614 merged_monitor_destroy (callback_data, value);
615 }
616
617 static void
merged_callback_destroy_cover(gpointer key,gpointer value,gpointer callback_data)618 merged_callback_destroy_cover (gpointer key,
619 gpointer value,
620 gpointer callback_data)
621 {
622 merged_callback_destroy (value);
623 }
624
625 static void
merged_finalize(GObject * object)626 merged_finalize (GObject *object)
627 {
628 NemoMergedDirectory *merged;
629
630 merged = NEMO_MERGED_DIRECTORY (object);
631
632 g_hash_table_foreach (merged->details->monitors,
633 merged_monitor_destroy_cover, merged);
634 g_hash_table_foreach (merged->details->callbacks,
635 merged_callback_destroy_cover, NULL);
636
637 g_hash_table_destroy (merged->details->callbacks);
638 g_hash_table_destroy (merged->details->monitors);
639 nemo_directory_list_free (merged->details->directories);
640 g_list_free (merged->details->directories_not_done_loading);
641
642 G_OBJECT_CLASS (nemo_merged_directory_parent_class)->finalize (object);
643 }
644
645 static void
nemo_merged_directory_init(NemoMergedDirectory * merged)646 nemo_merged_directory_init (NemoMergedDirectory *merged)
647 {
648 merged->details = G_TYPE_INSTANCE_GET_PRIVATE (merged, NEMO_TYPE_MERGED_DIRECTORY,
649 NemoMergedDirectoryDetails);
650 merged->details->callbacks = g_hash_table_new
651 (merged_callback_hash, merged_callback_equal);
652 merged->details->monitors = g_hash_table_new (NULL, NULL);
653 }
654
655 static void
nemo_merged_directory_class_init(NemoMergedDirectoryClass * class)656 nemo_merged_directory_class_init (NemoMergedDirectoryClass *class)
657 {
658 NemoDirectoryClass *directory_class;
659
660 directory_class = NEMO_DIRECTORY_CLASS (class);
661
662 G_OBJECT_CLASS (class)->finalize = merged_finalize;
663
664 directory_class->contains_file = merged_contains_file;
665 directory_class->call_when_ready = merged_call_when_ready;
666 directory_class->cancel_callback = merged_cancel_callback;
667 directory_class->file_monitor_add = merged_monitor_add;
668 directory_class->file_monitor_remove = merged_monitor_remove;
669 directory_class->force_reload = merged_force_reload;
670 directory_class->are_all_files_seen = merged_are_all_files_seen;
671 directory_class->is_not_empty = merged_is_not_empty;
672 /* Override get_file_list so that we can return a list that includes
673 * the files from each of the directories in NemoMergedDirectory->details->directories.
674 */
675 directory_class->get_file_list = merged_get_file_list;
676
677 class->add_real_directory = merged_add_real_directory;
678 class->remove_real_directory = merged_remove_real_directory;
679
680 g_type_class_add_private (class, sizeof (NemoMergedDirectoryDetails));
681
682 signals[ADD_REAL_DIRECTORY]
683 = g_signal_new ("add_real_directory",
684 G_TYPE_FROM_CLASS (class),
685 G_SIGNAL_RUN_LAST,
686 G_STRUCT_OFFSET (NemoMergedDirectoryClass,
687 add_real_directory),
688 NULL, NULL,
689 g_cclosure_marshal_VOID__POINTER,
690 G_TYPE_NONE, 1, G_TYPE_POINTER);
691 signals[REMOVE_REAL_DIRECTORY]
692 = g_signal_new ("remove_real_directory",
693 G_TYPE_FROM_CLASS (class),
694 G_SIGNAL_RUN_LAST,
695 G_STRUCT_OFFSET (NemoMergedDirectoryClass,
696 remove_real_directory),
697 NULL, NULL,
698 g_cclosure_marshal_VOID__POINTER,
699 G_TYPE_NONE, 1, G_TYPE_POINTER);
700 }
701