]> git.pld-linux.org Git - packages/gnome-desktop.git/blob - gnome-desktop-recently-used-apps.patch
- fixes: http://bugzilla.gnome.org/show_bug.cgi?id=516103
[packages/gnome-desktop.git] / gnome-desktop-recently-used-apps.patch
1 diff -urN ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-item.c ./libgnome-desktop/egg-recent-item.c
2 --- ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-item.c 1969-12-31 19:00:00.000000000 -0500
3 +++ ./libgnome-desktop/egg-recent-item.c        2006-05-08 16:18:44.000000000 -0400
4 @@ -0,0 +1,426 @@
5 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 +/*
7 + * This program is free software; you can redistribute it and/or modify
8 + * it under the terms of the GNU General Public License as
9 + * published by the Free Software Foundation; either version 2 of the
10 + * License, or (at your option) any later version.
11 + *
12 + * This program is distributed in the hope that it will be useful,
13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 + * GNU General Public License for more details.
16 + *
17 + * You should have received a copy of the GNU General Public License
18 + * along with this program; if not, write to the Free Software
19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20 + *
21 + * Authors:
22 + *   James Willcox <jwillcox@cs.indiana.edu>
23 + */
24 +
25 +
26 +#include <stdio.h>
27 +#include <string.h>
28 +#include <glib.h>
29 +#include <libgnomevfs/gnome-vfs.h>
30 +#include <libgnomevfs/gnome-vfs-mime-utils.h>
31 +#include "egg-recent-item.h"
32 +
33 +
34 +
35 +EggRecentItem *
36 +egg_recent_item_new (void)
37 +{
38 +       EggRecentItem *item;
39 +
40 +       item = g_new (EggRecentItem, 1);
41 +
42 +       item->groups = NULL;
43 +       item->private_data = FALSE;
44 +       item->uri = NULL;
45 +       item->mime_type = NULL;
46 +       item->mime_type_is_explicit = FALSE;
47 +
48 +       item->refcount = 1;
49 +
50 +       return item;
51 +}
52 +
53 +static void
54 +egg_recent_item_free (EggRecentItem *item)
55 +{
56 +       if (item->uri)
57 +               g_free (item->uri);
58 +
59 +       if (item->mime_type)
60 +               g_free (item->mime_type);
61 +
62 +       if (item->groups) {
63 +               g_list_foreach (item->groups, (GFunc)g_free, NULL);
64 +               g_list_free (item->groups);
65 +               item->groups = NULL;
66 +       }
67 +
68 +       g_free (item);
69 +}
70 +
71 +EggRecentItem *
72 +egg_recent_item_ref (EggRecentItem *item)
73 +{
74 +       item->refcount++;
75 +       return item;
76 +}
77 +
78 +EggRecentItem *
79 +egg_recent_item_unref (EggRecentItem *item)
80 +{
81 +       item->refcount--;
82 +
83 +       if (item->refcount == 0) {
84 +               egg_recent_item_free (item);
85 +       }
86 +
87 +       return item;
88 +}
89 +
90 +
91 +EggRecentItem * 
92 +egg_recent_item_new_from_uri (const gchar *uri)
93 +{
94 +       EggRecentItem *item;
95 +
96 +       g_return_val_if_fail (uri != NULL, NULL);
97 +
98 +       item = egg_recent_item_new ();
99 +
100 +       if (!egg_recent_item_set_uri (item ,uri)) {
101 +               egg_recent_item_free (item);
102 +               return NULL;
103 +       }
104 +       
105 +       return item;
106 +}
107 +
108 +static void
109 +egg_recent_item_update_mime_type (EggRecentItem *item)
110 +{
111 +       if (!item->mime_type_is_explicit) {
112 +               g_free (item->mime_type);
113 +               item->mime_type = NULL;
114 +
115 +               if (item->uri)
116 +                       item->mime_type = gnome_vfs_get_mime_type (item->uri);
117 +
118 +               if (!item->mime_type)
119 +                       item->mime_type = g_strdup (GNOME_VFS_MIME_TYPE_UNKNOWN);
120 +       }
121 +}
122 +
123 +gboolean
124 +egg_recent_item_set_uri (EggRecentItem *item, const gchar *uri)
125 +{
126 +       gchar *utf8_uri;
127 +
128 +       /* if G_BROKEN_FILENAMES is not set, this should succede */
129 +       if (g_utf8_validate (uri, -1, NULL)) {
130 +               item->uri = gnome_vfs_make_uri_from_input (uri);
131 +       } else {
132 +               utf8_uri = g_filename_to_utf8 (uri, -1, NULL, NULL, NULL);
133 +
134 +               if (utf8_uri == NULL) {
135 +                       g_warning ("Couldn't convert URI to UTF-8");
136 +                       return FALSE;
137 +               }
138 +
139 +               if (g_utf8_validate (utf8_uri, -1, NULL)) {
140 +                       item->uri = gnome_vfs_make_uri_from_input (utf8_uri);
141 +               } else {
142 +                       g_free (utf8_uri);
143 +                       return FALSE;
144 +               }
145 +
146 +               g_free (utf8_uri);
147 +       }
148 +
149 +       return TRUE;
150 +}
151 +
152 +gchar * 
153 +egg_recent_item_get_uri (const EggRecentItem *item)
154 +{
155 +       return g_strdup (item->uri);
156 +}
157 +
158 +G_CONST_RETURN gchar * 
159 +egg_recent_item_peek_uri (const EggRecentItem *item)
160 +{
161 +       return item->uri;
162 +}
163 +
164 +gchar * 
165 +egg_recent_item_get_uri_utf8 (const EggRecentItem *item)
166 +{
167 +       /* this could fail, but it's not likely, since we've already done it
168 +        * once in set_uri()
169 +        */
170 +       return g_filename_to_utf8 (item->uri, -1, NULL, NULL, NULL);
171 +}
172 +
173 +gchar *
174 +egg_recent_item_get_uri_for_display (const EggRecentItem *item)
175 +{
176 +       return gnome_vfs_format_uri_for_display (item->uri);
177 +}
178 +
179 +/* Stolen from gnome_vfs_make_valid_utf8() */
180 +static char *
181 +make_valid_utf8 (const char *name)
182 +{
183 +       GString *string;
184 +       const char *remainder, *invalid;
185 +       int remaining_bytes, valid_bytes;
186 +
187 +       string = NULL;
188 +       remainder = name;
189 +       remaining_bytes = name ? strlen (name) : 0;
190 +
191 +       while (remaining_bytes != 0) {
192 +               if (g_utf8_validate (remainder, remaining_bytes, &invalid))
193 +                       break;
194 +
195 +               valid_bytes = invalid - remainder;
196 +
197 +               if (string == NULL)
198 +                       string = g_string_sized_new (remaining_bytes);
199 +
200 +               g_string_append_len (string, remainder, valid_bytes);
201 +               g_string_append_c (string, '?');
202 +
203 +               remaining_bytes -= valid_bytes + 1;
204 +               remainder = invalid + 1;
205 +       }
206 +
207 +       if (string == NULL)
208 +               return g_strdup (name);
209 +
210 +       g_string_append (string, remainder);
211 +/*     g_string_append (string, _(" (invalid file name)")); */
212 +       g_assert (g_utf8_validate (string->str, -1, NULL));
213 +
214 +       return g_string_free (string, FALSE);
215 +}
216 +
217 +static gchar *
218 +get_uri_shortname_for_display (GnomeVFSURI *uri)
219 +{
220 +       gchar    *name; 
221 +       gboolean  validated;
222 +
223 +       validated = FALSE;
224 +       name = gnome_vfs_uri_extract_short_name (uri);
225 +       
226 +       if (name == NULL)
227 +       {
228 +               name = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_PASSWORD);
229 +       }
230 +       else if (g_ascii_strcasecmp (uri->method_string, "file") == 0)
231 +       {
232 +               gchar *text_uri;
233 +               gchar *local_file;
234 +               text_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_PASSWORD);
235 +               local_file = gnome_vfs_get_local_path_from_uri (text_uri);
236 +               
237 +               if (local_file != NULL)
238 +               {
239 +                       g_free (name);
240 +                       name = g_filename_display_basename (local_file);
241 +                       validated = TRUE;
242 +               }
243 +               
244 +               g_free (local_file);
245 +               g_free (text_uri);
246 +       } 
247 +       else if (!gnome_vfs_uri_has_parent (uri)) 
248 +       {
249 +               const gchar *method;
250 +               
251 +               method = uri->method_string;
252 +               
253 +               if (name == NULL ||
254 +                   strcmp (name, GNOME_VFS_URI_PATH_STR) == 0) 
255 +               {
256 +                       g_free (name);
257 +                       name = g_strdup (method);
258 +               } 
259 +               else 
260 +               {
261 +                       gchar *tmp;
262 +                       
263 +                       tmp = name;
264 +                       name = g_strdup_printf ("%s: %s", method, name);
265 +                       g_free (tmp);
266 +               }
267 +       }
268 +
269 +       if (!validated && !g_utf8_validate (name, -1, NULL)) 
270 +       {
271 +               gchar *utf8_name;
272 +               
273 +               utf8_name = make_valid_utf8 (name);
274 +               g_free (name);
275 +               name = utf8_name;
276 +       }
277 +
278 +       return name;
279 +}
280 +
281 +/**
282 + * egg_recent_item_get_short_name:
283 + * @item: an #EggRecentItem
284 + *
285 + * Computes a valid UTF-8 string that can be used as the name of the item in a
286 + * menu or list.  For example, calling this function on an item that refers to
287 + * "file:///foo/bar.txt" will yield "bar.txt".
288 + *
289 + * Return value: A newly-allocated string in UTF-8 encoding; free it with
290 + * g_free().
291 + **/
292 +gchar *
293 +egg_recent_item_get_short_name (const EggRecentItem *item)
294 +{
295 +       GnomeVFSURI *uri;
296 +       gchar *short_name;
297 +
298 +       g_return_val_if_fail (item != NULL, NULL);
299 +
300 +       if (item->uri == NULL)
301 +               return NULL;
302 +
303 +       uri = gnome_vfs_uri_new (item->uri);
304 +       if (uri == NULL)
305 +               return NULL;
306 +
307 +       short_name = get_uri_shortname_for_display (uri);
308 +
309 +       gnome_vfs_uri_unref (uri);
310 +
311 +       return short_name;
312 +}
313 +
314 +void 
315 +egg_recent_item_set_mime_type (EggRecentItem *item, const gchar *mime)
316 +{
317 +       g_free (item->mime_type);
318 +       item->mime_type = NULL;
319 +
320 +       if (mime && mime[0]) {
321 +               item->mime_type_is_explicit = TRUE;
322 +               item->mime_type             = g_strdup (mime);
323 +       } else {
324 +               item->mime_type_is_explicit = FALSE;
325 +       }
326 +}
327 +
328 +gchar * 
329 +egg_recent_item_get_mime_type (EggRecentItem *item)
330 +{
331 +       egg_recent_item_update_mime_type (item);
332 +
333 +       return g_strdup (item->mime_type);
334 +}
335 +
336 +void 
337 +egg_recent_item_set_timestamp (EggRecentItem *item, time_t timestamp)
338 +{
339 +       if (timestamp == (time_t) -1)
340 +               time (&timestamp);
341 +
342 +       item->timestamp = timestamp;
343 +}
344 +
345 +time_t 
346 +egg_recent_item_get_timestamp (const EggRecentItem *item)
347 +{
348 +       return item->timestamp;
349 +}
350 +
351 +G_CONST_RETURN GList *
352 +egg_recent_item_get_groups (const EggRecentItem *item)
353 +{
354 +       return item->groups;
355 +}
356 +
357 +gboolean
358 +egg_recent_item_in_group (const EggRecentItem *item, const gchar *group_name)
359 +{
360 +       GList *tmp;
361 +
362 +       tmp = item->groups;
363 +       while (tmp != NULL) {
364 +               gchar *val = (gchar *)tmp->data;
365 +               
366 +               if (strcmp (group_name, val) == 0)
367 +                       return TRUE;
368 +
369 +               tmp = tmp->next;
370 +       }
371 +       
372 +       return FALSE;
373 +}
374 +
375 +void
376 +egg_recent_item_add_group (EggRecentItem *item, const gchar *group_name)
377 +{
378 +       g_return_if_fail (group_name != NULL);
379 +
380 +       if (!egg_recent_item_in_group (item, group_name))
381 +               item->groups = g_list_append (item->groups, g_strdup (group_name));
382 +}
383 +
384 +void
385 +egg_recent_item_remove_group (EggRecentItem *item, const gchar *group_name)
386 +{
387 +       GList *tmp;
388 +
389 +       g_return_if_fail (group_name != NULL);
390 +
391 +       tmp = item->groups;
392 +       while (tmp != NULL) {
393 +               gchar *val = (gchar *)tmp->data;
394 +               
395 +               if (strcmp (group_name, val) == 0) {
396 +                       item->groups = g_list_remove (item->groups,
397 +                                                     val);
398 +                       g_free (val);
399 +                       break;
400 +               }
401 +
402 +               tmp = tmp->next;
403 +       }
404 +}
405 +
406 +void
407 +egg_recent_item_set_private (EggRecentItem *item, gboolean priv)
408 +{
409 +       item->private_data = priv;
410 +}
411 +
412 +gboolean
413 +egg_recent_item_get_private (const EggRecentItem *item)
414 +{
415 +       return item->private_data;
416 +}
417 +
418 +GType
419 +egg_recent_item_get_type (void)
420 +{
421 +       static GType boxed_type = 0;
422 +       
423 +       if (!boxed_type) {
424 +               boxed_type = g_boxed_type_register_static ("EggRecentItem",
425 +                                       (GBoxedCopyFunc)egg_recent_item_ref,
426 +                                       (GBoxedFreeFunc)egg_recent_item_unref);
427 +       }
428 +       
429 +       return boxed_type;
430 +}
431 diff -urN ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-item.h ./libgnome-desktop/egg-recent-item.h
432 --- ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-item.h 1969-12-31 19:00:00.000000000 -0500
433 +++ ./libgnome-desktop/egg-recent-item.h        2006-05-08 16:18:44.000000000 -0400
434 @@ -0,0 +1,80 @@
435 +
436 +#ifndef __EGG_RECENT_ITEM_H__
437 +#define __EGG_RECENT_ITEM_H__
438 +
439 +#include <time.h>
440 +#include <glib.h>
441 +#include <glib-object.h>
442 +
443 +G_BEGIN_DECLS
444 +
445 +#define EGG_TYPE_RECENT_ITEM       (egg_recent_item_get_type ())
446 +
447 +#define EGG_RECENT_ITEM_LIST_UNREF(list) \
448 +       g_list_foreach (list, (GFunc)egg_recent_item_unref, NULL); \
449 +       g_list_free (list);
450 +
451 +typedef struct _EggRecentItem EggRecentItem;
452 +
453 +struct _EggRecentItem {
454 +       /* do not access any of these directly */
455 +       gchar *uri;
456 +       gchar *mime_type;
457 +       time_t timestamp;
458 +
459 +       gboolean private_data;
460 +
461 +       GList *groups;
462 +       
463 +       int refcount;
464 +
465 +       guint mime_type_is_explicit : 1;
466 +};
467 +
468 +GType          egg_recent_item_get_type (void) G_GNUC_CONST;
469 +
470 +/* constructors */
471 +EggRecentItem * egg_recent_item_new (void);
472 +
473 +EggRecentItem *        egg_recent_item_ref (EggRecentItem *item);
474 +EggRecentItem *        egg_recent_item_unref (EggRecentItem *item);
475 +
476 +/* automatically fetches the mime type, etc */
477 +EggRecentItem * egg_recent_item_new_from_uri (const gchar *uri);
478 +
479 +gboolean egg_recent_item_set_uri (EggRecentItem *item, const gchar *uri);
480 +gchar * egg_recent_item_get_uri (const EggRecentItem *item);
481 +gchar * egg_recent_item_get_uri_utf8 (const EggRecentItem *item);
482 +gchar * egg_recent_item_get_uri_for_display (const EggRecentItem *item);
483 +gchar * egg_recent_item_get_short_name (const EggRecentItem *item);
484 +
485 +void egg_recent_item_set_mime_type (EggRecentItem *item, const gchar *mime);
486 +gchar * egg_recent_item_get_mime_type (EggRecentItem *item);
487 +
488 +void egg_recent_item_set_timestamp (EggRecentItem *item, time_t timestamp);
489 +time_t egg_recent_item_get_timestamp (const EggRecentItem *item);
490 +
491 +G_CONST_RETURN gchar *egg_recent_item_peek_uri (const EggRecentItem *item);
492 +
493 +
494 +/* groups */
495 +G_CONST_RETURN GList *  egg_recent_item_get_groups (const EggRecentItem *item);
496 +
497 +gboolean       egg_recent_item_in_group (const EggRecentItem *item,
498 +                                          const gchar *group_name);
499 +
500 +void           egg_recent_item_add_group (EggRecentItem *item,
501 +                                           const gchar *group_name);
502 +
503 +void           egg_recent_item_remove_group (EggRecentItem *item,
504 +                                              const gchar *group_name);
505 +
506 +void           egg_recent_item_set_private (EggRecentItem *item,
507 +                                             gboolean priv);
508 +
509 +gboolean       egg_recent_item_get_private (const EggRecentItem *item);
510 +
511 +
512 +G_END_DECLS
513 +
514 +#endif /* __EGG_RECENT_ITEM_H__ */
515 diff -urN ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-model-multi.c ./libgnome-desktop/egg-recent-model-multi.c
516 --- ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-model-multi.c  1969-12-31 19:00:00.000000000 -0500
517 +++ ./libgnome-desktop/egg-recent-model-multi.c 2006-05-08 17:03:13.000000000 -0400
518 @@ -0,0 +1,1990 @@
519 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
520 +/*
521 + * This program is free software; you can redistribute it and/or modify
522 + * it under the terms of the GNU General Public License as
523 + * published by the Free Software Foundation; either version 2 of the
524 + * License, or (at your option) any later version.
525 + *
526 + * This program is distributed in the hope that it will be useful,
527 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
528 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
529 + * GNU General Public License for more details.
530 + *
531 + * You should have received a copy of the GNU General Public License
532 + * along with this program; if not, write to the Free Software
533 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
534 + *
535 + * Authors:
536 + *   James Willcox <jwillcox@cs.indiana.edu>
537 + */
538 +
539 +#ifdef HAVE_CONFIG_H
540 +#include <config.h>
541 +#endif
542 +
543 +#include <stdio.h>
544 +#include <string.h>
545 +#include <errno.h>
546 +#include <stdlib.h>
547 +#include <unistd.h>
548 +#include <fcntl.h>
549 +#include <sys/time.h>
550 +#include <sys/stat.h>
551 +#include <time.h>
552 +#include <gtk/gtk.h>
553 +#include <libgnomevfs/gnome-vfs.h>
554 +#include <libgnomevfs/gnome-vfs-mime-utils.h>
555 +#include <gconf/gconf-client.h>
556 +#include "egg-recent-model-multi.h"
557 +#include "egg-recent-item.h"
558 +
559 +#define EGG_RECENT_MODEL_MULTI_DEFAULT_FILE_PATH ".recently-used"
560 +#define EGG_RECENT_MODEL_MULTI_BUFFER_SIZE 8192
561 +
562 +#define EGG_RECENT_MODEL_MULTI_MAX_ITEMS 500
563 +#define EGG_RECENT_MODEL_MULTI_DEFAULT_LIMIT 10
564 +#define EGG_RECENT_MODEL_MULTI_TIMEOUT_LENGTH 200
565 +#define EGG_RECENT_MODEL_MULTI_POLL_TIME 3
566 +
567 +/* needed for Darwin */
568 +#if !HAVE_DECL_LOCKF
569 +int lockf (int filedes, int function, off_t size);
570 +#endif
571 +
572 +#define EGG_RECENT_MODEL_MULTI_KEY_DIR "/desktop/gnome/recent_files"
573 +#define EGG_RECENT_MODEL_MULTI_DEFAULT_LIMIT_KEY EGG_RECENT_MODEL_MULTI_KEY_DIR "/default_limit"
574 +#define EGG_RECENT_MODEL_MULTI_EXPIRE_KEY EGG_RECENT_MODEL_MULTI_KEY_DIR "/expire"
575 +
576 +struct _EggRecentModelMultiPrivate {
577 +       GSList *mime_filter_values;     /* list of mime types we allow */
578 +       GSList *group_filter_values;    /* list of groups we allow */
579 +       GSList *scheme_filter_values;   /* list of URI schemes we allow */
580 +
581 +       EggRecentModelMultiSort sort_type; /* type of sorting to be done */
582 +
583 +       int limit;                      /* soft limit for length of the list */
584 +       int expire_days;                /* number of days to hold an item */
585 +
586 +       char *path;                     /* path to the file we store stuff in */
587 +
588 +       GHashTable *monitors;
589 +
590 +       GnomeVFSMonitorHandle *monitor;
591 +
592 +       GConfClient *client;
593 +       gboolean use_default_limit;
594 +
595 +       guint limit_change_notify_id;
596 +       guint expiration_change_notify_id;
597 +
598 +       guint changed_timeout;
599 +       guint poll_timeout;
600 +       time_t last_mtime;
601 +};
602 +
603 +/* signals */
604 +enum {
605 +       CHANGED,
606 +       LAST_SIGNAL
607 +};
608 +
609 +static GType model_signals[LAST_SIGNAL] = { 0 };
610 +
611 +/* properties */
612 +enum {
613 +       PROP_BOGUS,
614 +       PROP_MIME_FILTERS,
615 +       PROP_GROUP_FILTERS,
616 +       PROP_SCHEME_FILTERS,
617 +       PROP_SORT_TYPE,
618 +       PROP_LIMIT,
619 +       PROP_FILE_PATH
620 +};
621 +
622 +typedef struct {
623 +       GSList *states;
624 +       GList *items;
625 +       EggRecentItem *current_item;
626 +} ParseInfo;
627 +
628 +typedef enum {
629 +       STATE_START,
630 +       STATE_RECENT_FILES,
631 +       STATE_RECENT_ITEM,
632 +       STATE_URI,
633 +       STATE_MIME_TYPE,
634 +       STATE_TIMESTAMP,
635 +       STATE_PRIVATE,
636 +       STATE_GROUPS,
637 +       STATE_GROUP
638 +} ParseState;
639 +
640 +typedef struct {
641 +       EggRecentModelMulti *model;
642 +       GList *list;
643 +} ChangedData;
644 +
645 +#define TAG_RECENT_FILES "RecentFiles"
646 +#define TAG_RECENT_ITEM "RecentItem"
647 +#define TAG_URI "URI"
648 +#define TAG_MIME_TYPE "Mime-Type"
649 +#define TAG_TIMESTAMP "Timestamp"
650 +#define TAG_PRIVATE "Private"
651 +#define TAG_GROUPS "Groups"
652 +#define TAG_GROUP "Group"
653 +
654 +static void start_element_handler (GMarkupParseContext *context,
655 +                             const gchar *element_name,
656 +                             const gchar **attribute_names,
657 +                             const gchar **attribute_values,
658 +                             gpointer user_data,
659 +                             GError **error);
660 +
661 +static void end_element_handler (GMarkupParseContext *context,
662 +                           const gchar *element_name,
663 +                           gpointer user_data,
664 +                           GError **error);
665 +
666 +static void text_handler (GMarkupParseContext *context,
667 +                    const gchar *text,
668 +                    gsize text_len,
669 +                    gpointer user_data,
670 +                    GError **error);
671 +
672 +static void error_handler (GMarkupParseContext *context,
673 +                     GError *error,
674 +                     gpointer user_data);
675 +
676 +static GMarkupParser parser = {start_element_handler, end_element_handler,
677 +                       text_handler,
678 +                       NULL,
679 +                       error_handler};
680 +
681 +static GObjectClass *parent_class;
682 +
683 +static void egg_recent_model_multi_clear_mime_filter (EggRecentModelMulti *model);
684 +static void egg_recent_model_multi_clear_group_filter (EggRecentModelMulti *model);
685 +static void egg_recent_model_multi_clear_scheme_filter (EggRecentModelMulti *model);
686 +
687 +static GObjectClass *parent_class;
688 +
689 +static gboolean
690 +egg_recent_model_multi_string_match (const GSList *list, const gchar *str)
691 +{
692 +       const GSList *tmp;
693 +
694 +       if (list == NULL || str == NULL)
695 +               return TRUE;
696 +
697 +       tmp = list;
698 +       
699 +       while (tmp) {
700 +               if (g_pattern_match_string (tmp->data, str))
701 +                       return TRUE;
702 +               
703 +               tmp = tmp->next;
704 +       }
705 +
706 +       return FALSE;
707 +}
708 +
709 +static gboolean
710 +egg_recent_model_multi_write_raw (EggRecentModelMulti *model, FILE *file,
711 +                             const gchar *content)
712 +{
713 +       int len;
714 +       int fd;
715 +       struct stat sbuf;
716 +
717 +       rewind (file);
718 +
719 +       len = strlen (content);
720 +       fd = fileno (file);
721 +
722 +       if (fstat (fd, &sbuf) < 0)
723 +               g_warning ("Couldn't stat XML document.");
724 +
725 +       if ((off_t)len < sbuf.st_size) {
726 +               ftruncate (fd, len);
727 +       }
728 +
729 +       if (fputs (content, file) == EOF)
730 +               return FALSE;
731 +
732 +#ifndef G_OS_WIN32
733 +       fsync (fd);
734 +#endif
735 +       rewind (file);
736 +
737 +       return TRUE;
738 +}
739 +
740 +static GList *
741 +egg_recent_model_multi_delete_from_list (GList *list,
742 +                                      const gchar *uri)
743 +{
744 +       GList *tmp;
745 +
746 +       if (!uri)
747 +               return list;
748 +
749 +       tmp = list;
750 +
751 +       while (tmp) {
752 +               EggRecentItem *item = tmp->data;
753 +               GList         *next;
754 +
755 +               next = tmp->next;
756 +
757 +               if (!strcmp (egg_recent_item_peek_uri (item), uri)) {
758 +                       egg_recent_item_unref (item);
759 +
760 +                       list = g_list_remove_link (list, tmp);
761 +                       g_list_free_1 (tmp);
762 +               }
763 +
764 +               tmp = next;
765 +       }
766 +
767 +       return list;
768 +}
769 +
770 +static void
771 +egg_recent_model_multi_add_new_groups (EggRecentItem *item,
772 +                                EggRecentItem *upd_item)
773 +{
774 +       const GList *tmp;
775 +
776 +       tmp = egg_recent_item_get_groups (upd_item);
777 +
778 +       while (tmp) {
779 +               char *group = tmp->data;
780 +
781 +               if (!egg_recent_item_in_group (item, group))
782 +                       egg_recent_item_add_group (item, group);
783 +
784 +               tmp = tmp->next;
785 +       }
786 +}
787 +
788 +static gboolean
789 +egg_recent_model_multi_update_item (GList *items, EggRecentItem *upd_item)
790 +{
791 +       GList      *tmp;
792 +       const char *uri;
793 +
794 +       uri = egg_recent_item_peek_uri (upd_item);
795 +
796 +       tmp = items;
797 +
798 +       while (tmp) {
799 +               EggRecentItem *item = tmp->data;
800 +
801 +               if (gnome_vfs_uris_match (egg_recent_item_peek_uri (item), uri)) {
802 +                       egg_recent_item_set_timestamp (item, (time_t) -1);
803 +
804 +                       egg_recent_model_multi_add_new_groups (item, upd_item);
805 +
806 +                       return TRUE;
807 +               }
808 +
809 +               tmp = tmp->next;
810 +       }
811 +
812 +       return FALSE;
813 +}
814 +
815 +static gchar *
816 +egg_recent_model_multi_read_raw (EggRecentModelMulti *model, FILE *file)
817 +{
818 +       GString *string;
819 +       char buf[EGG_RECENT_MODEL_MULTI_BUFFER_SIZE];
820 +
821 +       rewind (file);
822 +
823 +       string = g_string_new (NULL);
824 +       while (fgets (buf, EGG_RECENT_MODEL_MULTI_BUFFER_SIZE, file)) {
825 +               string = g_string_append (string, buf);
826 +       }
827 +
828 +       rewind (file);
829 +
830 +       return g_string_free (string, FALSE);
831 +}
832 +
833 +
834 +
835 +static ParseInfo *
836 +parse_info_init (void)
837 +{
838 +       ParseInfo *retval;
839 +       
840 +       retval = g_new0 (ParseInfo, 1);
841 +       retval->states = g_slist_prepend (NULL, STATE_START);
842 +       retval->items = NULL;
843 +       
844 +       return retval;
845 +}
846 +
847 +static void
848 +parse_info_free (ParseInfo *info)
849 +{
850 +       g_slist_free (info->states);
851 +       g_free (info);
852 +}
853 +
854 +static void
855 +push_state (ParseInfo  *info,
856 +            ParseState  state)
857 +{
858 +  info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state));
859 +}
860 +
861 +static void
862 +pop_state (ParseInfo *info)
863 +{
864 +  g_return_if_fail (info->states != NULL);
865 +
866 +  info->states = g_slist_remove (info->states, info->states->data);
867 +}
868 +
869 +static ParseState
870 +peek_state (ParseInfo *info)
871 +{
872 +  g_return_val_if_fail (info->states != NULL, STATE_START);
873 +
874 +  return GPOINTER_TO_INT (info->states->data);
875 +}
876 +
877 +#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
878 +
879 +static gboolean
880 +valid_element (ParseInfo    *info,
881 +              int           valid_parent_state,
882 +              const gchar  *element_name,
883 +              const gchar  *valid_element,
884 +              GError      **error)
885 +{
886 +       if (peek_state (info) != valid_parent_state) {
887 +             g_set_error (error,
888 +                          G_MARKUP_ERROR,
889 +                          G_MARKUP_ERROR_INVALID_CONTENT,
890 +                          "Unexpected tag '%s', tag '%s' expected",
891 +                          element_name, valid_element);
892 +             return FALSE;
893 +       }
894 +
895 +       return TRUE;
896 +}
897 +
898 +static void
899 +start_element_handler (GMarkupParseContext *context,
900 +                             const gchar *element_name,
901 +                             const gchar **attribute_names,
902 +                             const gchar **attribute_values,
903 +                             gpointer user_data,
904 +                             GError **error)
905 +{
906 +       ParseInfo *info = (ParseInfo *)user_data;
907 +
908 +       if (ELEMENT_IS (TAG_RECENT_FILES))
909 +               push_state (info, STATE_RECENT_FILES);
910 +       else if (ELEMENT_IS (TAG_RECENT_ITEM)) {
911 +               if (valid_element (info, STATE_RECENT_FILES,
912 +                                  TAG_RECENT_ITEM, TAG_RECENT_FILES, error)) {
913 +                       info->current_item = egg_recent_item_new ();
914 +                       push_state (info, STATE_RECENT_ITEM);
915 +               }
916 +       } else if (ELEMENT_IS (TAG_URI)) {
917 +               if (valid_element (info, STATE_RECENT_ITEM,
918 +                                  TAG_URI, TAG_RECENT_ITEM, error)) {
919 +                       push_state (info, STATE_URI);
920 +               }
921 +       } else if (ELEMENT_IS (TAG_MIME_TYPE)) {
922 +               if (valid_element (info, STATE_RECENT_ITEM,
923 +                                  TAG_MIME_TYPE, TAG_RECENT_ITEM, error)) {
924 +                       push_state (info, STATE_MIME_TYPE);
925 +               }
926 +       } else if (ELEMENT_IS (TAG_TIMESTAMP)) {
927 +               if (valid_element (info, STATE_RECENT_ITEM,
928 +                                  TAG_TIMESTAMP, TAG_RECENT_ITEM, error)) {
929 +                       push_state (info, STATE_TIMESTAMP);
930 +               }
931 +       } else if (ELEMENT_IS (TAG_PRIVATE)) {
932 +               if (valid_element (info, STATE_RECENT_ITEM,
933 +                                  TAG_PRIVATE, TAG_RECENT_ITEM, error)) {
934 +                       push_state (info, STATE_PRIVATE);
935 +                       egg_recent_item_set_private (info->current_item, TRUE);
936 +               }
937 +       } else if (ELEMENT_IS (TAG_GROUPS)) {
938 +               if (valid_element (info, STATE_RECENT_ITEM,
939 +                                  TAG_GROUPS, TAG_RECENT_ITEM, error)) {
940 +                       push_state (info, STATE_GROUPS);
941 +               }
942 +       } else if (ELEMENT_IS (TAG_GROUP)) {
943 +               if (valid_element (info, STATE_GROUPS,
944 +                                  TAG_GROUP, TAG_GROUPS, error)) {
945 +                       push_state (info, STATE_GROUP);
946 +               }
947 +       }
948 +}
949 +
950 +static gint
951 +list_compare_func_mru (gpointer a, gpointer b)
952 +{
953 +       EggRecentItem *item_a = (EggRecentItem *)a;
954 +       EggRecentItem *item_b = (EggRecentItem *)b;
955 +
956 +       return item_a->timestamp < item_b->timestamp;
957 +}
958 +
959 +static gint
960 +list_compare_func_lru (gpointer a, gpointer b)
961 +{
962 +       EggRecentItem *item_a = (EggRecentItem *)a;
963 +       EggRecentItem *item_b = (EggRecentItem *)b;
964 +
965 +       return item_a->timestamp > item_b->timestamp;
966 +}
967 +
968 +
969 +
970 +static void
971 +end_element_handler (GMarkupParseContext *context,
972 +                           const gchar *element_name,
973 +                           gpointer user_data,
974 +                           GError **error)
975 +{
976 +       ParseInfo *info = (ParseInfo *)user_data;
977 +
978 +       switch (peek_state (info)) {
979 +               case STATE_RECENT_ITEM:
980 +                       if (!info->current_item) {
981 +                               g_warning ("No recent item found\n");
982 +                               break;
983 +                       }
984 +
985 +                       if (!info->current_item->uri) {
986 +                               g_warning ("Invalid item found\n");
987 +                               break;
988 +                       }
989 +                               
990 +                       info->items = g_list_prepend (info->items,
991 +                                                     info->current_item);
992 +                       info->current_item = NULL;
993 +                       break;
994 +               default:
995 +                       break;
996 +       }
997 +
998 +       pop_state (info);
999 +}
1000 +
1001 +static void
1002 +text_handler (GMarkupParseContext *context,
1003 +                    const gchar *text,
1004 +                    gsize text_len,
1005 +                    gpointer user_data,
1006 +                    GError **error)
1007 +{
1008 +       ParseInfo *info = (ParseInfo *)user_data;
1009 +       gchar *value;
1010 +
1011 +       value = g_strndup (text, text_len);
1012 +
1013 +       switch (peek_state (info)) {
1014 +               case STATE_START:
1015 +               case STATE_RECENT_FILES:
1016 +               case STATE_RECENT_ITEM:
1017 +               case STATE_PRIVATE:
1018 +               case STATE_GROUPS:
1019 +               break;
1020 +               case STATE_URI:
1021 +                       egg_recent_item_set_uri (info->current_item, value);
1022 +               break;
1023 +               case STATE_MIME_TYPE:
1024 +                       egg_recent_item_set_mime_type (info->current_item, value);
1025 +               break;
1026 +               case STATE_TIMESTAMP:
1027 +                       egg_recent_item_set_timestamp (info->current_item,
1028 +                                                        (time_t)atoi (value));
1029 +               break;
1030 +               case STATE_GROUP:
1031 +                       egg_recent_item_add_group (info->current_item,
1032 +                                                    text);
1033 +               break;
1034 +       }
1035 +
1036 +       g_free (value);
1037 +}
1038 +
1039 +static void
1040 +error_handler (GMarkupParseContext *context,
1041 +                     GError *error,
1042 +                     gpointer user_data)
1043 +{
1044 +       g_warning ("Error in parse: %s", error->message);
1045 +}
1046 +
1047 +static void
1048 +egg_recent_model_multi_enforce_limit (GList *list, int limit)
1049 +{
1050 +       int len;
1051 +       GList *end;
1052 +
1053 +       /* limit < 0 means unlimited */
1054 +       if (limit <= 0)
1055 +               return;
1056 +
1057 +       len = g_list_length (list);
1058 +
1059 +       if (len > limit) {
1060 +               GList *next;
1061 +
1062 +               end = g_list_nth (list, limit-1);
1063 +               next = end->next;
1064 +
1065 +               end->next = NULL;
1066 +
1067 +               EGG_RECENT_ITEM_LIST_UNREF (next);
1068 +       }
1069 +}
1070 +
1071 +static GList *
1072 +egg_recent_model_multi_sort (EggRecentModelMulti *model, GList *list)
1073 +{
1074 +       switch (model->priv->sort_type) {
1075 +               case EGG_RECENT_MODEL_MULTI_SORT_MRU:
1076 +                       list = g_list_sort (list,
1077 +                                       (GCompareFunc)list_compare_func_mru);   
1078 +               break;
1079 +               case EGG_RECENT_MODEL_MULTI_SORT_LRU:
1080 +                       list = g_list_sort (list,
1081 +                                       (GCompareFunc)list_compare_func_lru);
1082 +               break;
1083 +               case EGG_RECENT_MODEL_MULTI_SORT_NONE:
1084 +               break;
1085 +       }
1086 +
1087 +       return list;
1088 +}
1089 +
1090 +static gboolean
1091 +egg_recent_model_multi_group_match (EggRecentItem *item, GSList *groups)
1092 +{
1093 +       GSList *tmp;
1094 +
1095 +       tmp = groups;
1096 +
1097 +       while (tmp != NULL) {
1098 +               const gchar * group = (const gchar *)tmp->data;
1099 +
1100 +               if (egg_recent_item_in_group (item, group))
1101 +                       return TRUE;
1102 +
1103 +               tmp = tmp->next;
1104 +       }
1105 +
1106 +       return FALSE;
1107 +}
1108 +
1109 +static GList *
1110 +egg_recent_model_multi_filter (EggRecentModelMulti *model, GList *list)
1111 +{
1112 +       GList *newlist = NULL;
1113 +       GList *l;
1114 +       gchar *mime_type;
1115 +       gchar *uri;
1116 +
1117 +       g_return_val_if_fail (list != NULL, NULL);
1118 +
1119 +       for (l = list; l != NULL ; l = l->next) {
1120 +               EggRecentItem *item = (EggRecentItem *) l->data;
1121 +               gboolean pass_mime_test = FALSE;
1122 +               gboolean pass_group_test = FALSE;
1123 +               gboolean pass_scheme_test = FALSE;
1124 +
1125 +               g_assert (item != NULL);
1126 +               
1127 +               uri = egg_recent_item_get_uri (item);
1128 +
1129 +               /* filter by mime type */
1130 +               if (model->priv->mime_filter_values != NULL) {
1131 +                       mime_type = egg_recent_item_get_mime_type (item);
1132 +
1133 +                       if (egg_recent_model_multi_string_match
1134 +                                       (model->priv->mime_filter_values,
1135 +                                        mime_type))
1136 +                               pass_mime_test = TRUE;
1137 +
1138 +                       g_free (mime_type);
1139 +               } else
1140 +                       pass_mime_test = TRUE;
1141 +
1142 +               /* filter by group */
1143 +               if (pass_mime_test && model->priv->group_filter_values != NULL) {
1144 +                       if (egg_recent_model_multi_group_match
1145 +                                       (item, model->priv->group_filter_values))
1146 +                               pass_group_test = TRUE;
1147 +               } else if (egg_recent_item_get_private (item)) {
1148 +                       pass_group_test = FALSE;
1149 +               } else
1150 +                       pass_group_test = TRUE;
1151 +
1152 +               /* filter by URI scheme */
1153 +               if (pass_mime_test && pass_group_test &&
1154 +                   model->priv->scheme_filter_values != NULL) {
1155 +                       gchar *scheme;
1156 +                       
1157 +                       scheme = gnome_vfs_get_uri_scheme (uri);
1158 +
1159 +                       if (egg_recent_model_multi_string_match
1160 +                               (model->priv->scheme_filter_values, scheme))
1161 +                               pass_scheme_test = TRUE;
1162 +
1163 +                       g_free (scheme);
1164 +               } else
1165 +                       pass_scheme_test = TRUE;
1166 +
1167 +               if (pass_mime_test && pass_group_test && pass_scheme_test)
1168 +                       newlist = g_list_prepend (newlist, item);
1169 +               else
1170 +                       egg_recent_item_unref (item);
1171 +
1172 +               g_free (uri);
1173 +       }
1174 +
1175 +       g_list_free (list);
1176 +
1177 +       return g_list_reverse (newlist);
1178 +}
1179 +
1180 +
1181 +
1182 +#if 0
1183 +static void
1184 +egg_recent_model_multi_monitor_list_cb (GnomeVFSMonitorHandle *handle,
1185 +                              const gchar *monitor_uri,
1186 +                              const gchar *info_uri,
1187 +                              GnomeVFSMonitorEventType event_type,
1188 +                              gpointer user_data)
1189 +{
1190 +       EggRecentModelMulti *model;
1191 +
1192 +       model = EGG_RECENT_MODEL_MULTI (user_data);
1193 +
1194 +       if (event_type == GNOME_VFS_MONITOR_EVENT_DELETED) {
1195 +               egg_recent_model_multi_delete (model, monitor_uri);
1196 +               g_hash_table_remove (model->priv->monitors, monitor_uri);
1197 +       }
1198 +}
1199 +
1200 +
1201 +
1202 +static void
1203 +egg_recent_model_multi_monitor_list (EggRecentModelMulti *model, GList *list)
1204 +{
1205 +       GList *tmp;
1206 +
1207 +       tmp = list;
1208 +       while (tmp) {
1209 +               EggRecentItem *item = (EggRecentItem *)tmp->data;
1210 +               GnomeVFSMonitorHandle *handle;
1211 +               GnomeVFSResult res;
1212 +               gchar *uri;
1213 +
1214 +               tmp = tmp->next;
1215 +               
1216 +               uri = egg_recent_item_get_uri (item);
1217 +               if (g_hash_table_lookup (model->priv->monitors, uri)) {
1218 +                       /* already monitoring this one */
1219 +                       g_free (uri);
1220 +                       continue;
1221 +               }
1222 +
1223 +               res = gnome_vfs_monitor_add (&handle, uri,
1224 +                                            GNOME_VFS_MONITOR_FILE,
1225 +                                            egg_recent_model_multi_monitor_list_cb,
1226 +                                            model);
1227 +               
1228 +               if (res == GNOME_VFS_OK)
1229 +                       g_hash_table_insert (model->priv->monitors, uri, handle);
1230 +               else
1231 +                       g_free (uri);
1232 +       }
1233 +}
1234 +#endif
1235 +
1236 +
1237 +static gboolean
1238 +egg_recent_model_multi_changed_timeout (EggRecentModelMulti *model)
1239 +{
1240 +       model->priv->changed_timeout = 0;
1241 +
1242 +       egg_recent_model_multi_changed (model);
1243 +
1244 +       return FALSE;
1245 +}
1246 +
1247 +static void
1248 +egg_recent_model_multi_monitor_cb (GnomeVFSMonitorHandle *handle,
1249 +                              const gchar *monitor_uri,
1250 +                              const gchar *info_uri,
1251 +                              GnomeVFSMonitorEventType event_type,
1252 +                              gpointer user_data)
1253 +{
1254 +       EggRecentModelMulti *model;
1255 +
1256 +       g_return_if_fail (user_data != NULL);
1257 +       g_return_if_fail (EGG_IS_RECENT_MODEL_MULTI (user_data));
1258 +       model = EGG_RECENT_MODEL_MULTI (user_data);
1259 +
1260 +       if (event_type == GNOME_VFS_MONITOR_EVENT_CHANGED ||
1261 +           event_type == GNOME_VFS_MONITOR_EVENT_CREATED ||
1262 +           event_type == GNOME_VFS_MONITOR_EVENT_DELETED) {
1263 +               if (model->priv->changed_timeout > 0) {
1264 +                       g_source_remove (model->priv->changed_timeout);
1265 +               }
1266 +
1267 +               model->priv->changed_timeout = g_timeout_add (
1268 +                       EGG_RECENT_MODEL_MULTI_TIMEOUT_LENGTH,
1269 +                       (GSourceFunc)egg_recent_model_multi_changed_timeout,
1270 +                       model);
1271 +       }
1272 +}
1273 +
1274 +static gboolean
1275 +egg_recent_model_multi_poll_timeout (gpointer user_data)
1276 +{
1277 +       EggRecentModelMulti *model;
1278 +       struct stat stat_buf;
1279 +       int stat_res;
1280 +
1281 +       model = EGG_RECENT_MODEL_MULTI (user_data);
1282 +       stat_res = stat (model->priv->path, &stat_buf);
1283 +
1284 +       if (!stat_res && stat_buf.st_mtime &&  
1285 +           stat_buf.st_mtime != model->priv->last_mtime) {
1286 +               model->priv->last_mtime = stat_buf.st_mtime;
1287 +               
1288 +               if (model->priv->changed_timeout > 0)
1289 +                       g_source_remove (model->priv->changed_timeout);
1290 +               
1291 +               model->priv->changed_timeout = g_timeout_add (
1292 +                       EGG_RECENT_MODEL_MULTI_TIMEOUT_LENGTH,
1293 +                       (GSourceFunc)egg_recent_model_multi_changed_timeout,
1294 +                       model);
1295 +       }
1296 +       return TRUE;
1297 +}
1298 +
1299 +static void
1300 +egg_recent_model_multi_monitor (EggRecentModelMulti *model, gboolean should_monitor)
1301 +{
1302 +       if (should_monitor && model->priv->monitor == NULL) {
1303 +               char *uri;
1304 +               GnomeVFSResult result;
1305 +
1306 +               uri = gnome_vfs_get_uri_from_local_path (model->priv->path);
1307 +
1308 +               result = gnome_vfs_monitor_add (&model->priv->monitor,
1309 +                                               uri,
1310 +                                               GNOME_VFS_MONITOR_FILE,
1311 +                                               egg_recent_model_multi_monitor_cb,
1312 +                                               model);
1313 +
1314 +               g_free (uri);
1315 +
1316 +               /* if the above fails, don't worry about it.
1317 +                * local notifications will still happen
1318 +                */
1319 +               if (result == GNOME_VFS_ERROR_NOT_SUPPORTED) {
1320 +                       if (model->priv->poll_timeout > 0)
1321 +                               g_source_remove (model->priv->poll_timeout);
1322 +                       
1323 +                       model->priv->poll_timeout = g_timeout_add (
1324 +                               EGG_RECENT_MODEL_MULTI_POLL_TIME * 1000,
1325 +                               egg_recent_model_multi_poll_timeout,
1326 +                               model);
1327 +               }
1328 +
1329 +       } else if (!should_monitor && model->priv->monitor != NULL) {
1330 +               gnome_vfs_monitor_cancel (model->priv->monitor);
1331 +               model->priv->monitor = NULL;
1332 +       }
1333 +}
1334 +
1335 +static void
1336 +egg_recent_model_multi_set_limit_internal (EggRecentModelMulti *model, int limit)
1337 +{
1338 +       model->priv->limit = limit;
1339 +
1340 +       if (limit <= 0)
1341 +               egg_recent_model_multi_monitor (model, FALSE);
1342 +       else {
1343 +               egg_recent_model_multi_monitor (model, TRUE);
1344 +               egg_recent_model_multi_changed (model);
1345 +       }
1346 +}
1347 +
1348 +static GList *
1349 +egg_recent_model_multi_read (EggRecentModelMulti *model, FILE *file)
1350 +{
1351 +       GList *list=NULL;
1352 +       gchar *content;
1353 +       GMarkupParseContext *ctx;
1354 +       ParseInfo *info;
1355 +       GError *error;
1356 +
1357 +       content = egg_recent_model_multi_read_raw (model, file);
1358 +
1359 +       if (strlen (content) <= 0) {
1360 +               g_free (content);
1361 +               return NULL;
1362 +       }
1363 +
1364 +       info = parse_info_init ();
1365 +       
1366 +       ctx = g_markup_parse_context_new (&parser, 0, info, NULL);
1367 +       
1368 +       error = NULL;
1369 +       if (!g_markup_parse_context_parse (ctx, content, strlen (content), &error)) {
1370 +               g_warning ("Error while parsing the .recently-used file: %s\n",
1371 +                          error->message);
1372 +               
1373 +               g_error_free (error);
1374 +               parse_info_free (info);
1375 +
1376 +               return NULL;
1377 +       }
1378 +
1379 +       error = NULL;
1380 +       if (!g_markup_parse_context_end_parse (ctx, &error)) {
1381 +               g_warning ("Unable to complete parsing of the .recently-used file: %s\n",
1382 +                          error->message);
1383 +               
1384 +               g_error_free (error);
1385 +               g_markup_parse_context_free (ctx);
1386 +               parse_info_free (info);
1387 +
1388 +               return NULL;
1389 +       }
1390 +       
1391 +       list = g_list_reverse (info->items);
1392 +
1393 +       g_markup_parse_context_free (ctx);
1394 +       parse_info_free (info);
1395 +       g_free (content);
1396 +
1397 +       return list;
1398 +}
1399 +
1400 +
1401 +static gboolean
1402 +egg_recent_model_multi_write (EggRecentModelMulti *model, FILE *file, GList *list)
1403 +{
1404 +       GString *string;
1405 +       gchar *data;
1406 +       EggRecentItem *item;
1407 +       const GList *groups;
1408 +       int i;
1409 +       int ret;
1410 +       
1411 +       string = g_string_new ("<?xml version=\"1.0\"?>\n");
1412 +       string = g_string_append (string, "<" TAG_RECENT_FILES ">\n");
1413 +
1414 +       i=0;
1415 +       while (list) {
1416 +               gchar *uri;
1417 +               gchar *mime_type;
1418 +               gchar *escaped_uri;
1419 +               time_t timestamp;
1420 +               item = (EggRecentItem *)list->data;
1421 +
1422 +
1423 +               uri = egg_recent_item_get_uri_utf8 (item);
1424 +               escaped_uri = g_markup_escape_text (uri,
1425 +                                                   strlen (uri));
1426 +               g_free (uri);
1427 +
1428 +               mime_type = egg_recent_item_get_mime_type (item);
1429 +               timestamp = egg_recent_item_get_timestamp (item);
1430 +               
1431 +               string = g_string_append (string, "  <" TAG_RECENT_ITEM ">\n");
1432 +
1433 +               g_string_append_printf (string,
1434 +                               "    <" TAG_URI ">%s</" TAG_URI ">\n", escaped_uri);
1435 +
1436 +               if (mime_type)
1437 +                       g_string_append_printf (string,
1438 +                               "    <" TAG_MIME_TYPE ">%s</" TAG_MIME_TYPE ">\n", mime_type);
1439 +               else
1440 +                       g_string_append_printf (string,
1441 +                               "    <" TAG_MIME_TYPE "></" TAG_MIME_TYPE ">\n");
1442 +
1443 +               
1444 +               g_string_append_printf (string,
1445 +                               "    <" TAG_TIMESTAMP ">%d</" TAG_TIMESTAMP ">\n", (int)timestamp);
1446 +
1447 +               if (egg_recent_item_get_private (item))
1448 +                       string = g_string_append (string,
1449 +                                       "    <" TAG_PRIVATE "/>\n");
1450 +
1451 +               /* write the groups */
1452 +               string = g_string_append (string,
1453 +                               "    <" TAG_GROUPS ">\n");
1454 +               groups = egg_recent_item_get_groups (item);
1455 +
1456 +               if (groups == NULL && egg_recent_item_get_private (item))
1457 +                       g_warning ("Item with URI \"%s\" marked as private, but"
1458 +                                  " does not belong to any groups.\n", uri);
1459 +               
1460 +               while (groups) {
1461 +                       const gchar *group = (const gchar *)groups->data;
1462 +                       gchar *escaped_group;
1463 +
1464 +                       escaped_group = g_markup_escape_text (group, strlen(group));
1465 +
1466 +                       g_string_append_printf (string,
1467 +                                       "      <" TAG_GROUP ">%s</" TAG_GROUP ">\n",
1468 +                                       escaped_group);
1469 +
1470 +                       g_free (escaped_group);
1471 +
1472 +                       groups = groups->next;
1473 +               }
1474 +               
1475 +               string = g_string_append (string, "    </" TAG_GROUPS ">\n");
1476 +
1477 +               string = g_string_append (string,
1478 +                               "  </" TAG_RECENT_ITEM ">\n");
1479 +
1480 +               g_free (mime_type);
1481 +               g_free (escaped_uri);
1482 +
1483 +               list = list->next;
1484 +               i++;
1485 +       }
1486 +
1487 +       string = g_string_append (string, "</" TAG_RECENT_FILES ">");
1488 +
1489 +       data = g_string_free (string, FALSE);
1490 +
1491 +       ret = egg_recent_model_multi_write_raw (model, file, data);
1492 +
1493 +       g_free (data);
1494 +
1495 +       return ret;
1496 +}
1497 +
1498 +static FILE *
1499 +egg_recent_model_multi_open_file (EggRecentModelMulti *model,
1500 +                           gboolean        for_writing)
1501 +{
1502 +       FILE *file;
1503 +       mode_t prev_umask;
1504 +       
1505 +       file = fopen (model->priv->path, "r+");
1506 +       if (file == NULL && for_writing) {
1507 +               /* be paranoid */
1508 +               prev_umask = umask (077);
1509 +
1510 +               file = fopen (model->priv->path, "w+");
1511 +
1512 +               umask (prev_umask);
1513 +
1514 +               g_return_val_if_fail (file != NULL, NULL);
1515 +       }
1516 +
1517 +       return file;
1518 +}
1519 +
1520 +static gboolean
1521 +egg_recent_model_multi_lock_file (FILE *file)
1522 +{
1523 +#ifdef HAVE_LOCKF
1524 +       int fd;
1525 +       gint    try = 5;
1526 +
1527 +       rewind (file);
1528 +       fd = fileno (file);
1529 +
1530 +       /* Attempt to lock the file 5 times,
1531 +        * waiting a random interval (< 1 second) 
1532 +        * in between attempts.
1533 +        * We should really be doing asynchronous
1534 +        * locking, but requires substantially larger
1535 +        * changes.
1536 +        */
1537 +       
1538 +       while (try > 0)
1539 +       {
1540 +               int rand_interval;
1541 +
1542 +               if (lockf (fd, F_TLOCK, 0) == 0)
1543 +                       return TRUE;
1544 +
1545 +               rand_interval = 1 + (int) (10.0 * rand()/(RAND_MAX + 1.0));
1546 +                        
1547 +               g_usleep (100000 * rand_interval);
1548 +
1549 +               --try;
1550 +       }
1551 +
1552 +       return FALSE;
1553 +#else
1554 +       return TRUE;
1555 +#endif /* HAVE_LOCKF */
1556 +}
1557 +
1558 +static gboolean
1559 +egg_recent_model_multi_unlock_file (FILE *file)
1560 +{
1561 +#ifdef HAVE_LOCKF
1562 +       int fd;
1563 +
1564 +       rewind (file);
1565 +       fd = fileno (file);
1566 +
1567 +       return (lockf (fd, F_ULOCK, 0) == 0) ? TRUE : FALSE;
1568 +#else
1569 +       return TRUE;
1570 +#endif /* HAVE_LOCKF */
1571 +}
1572 +
1573 +static void
1574 +egg_recent_model_multi_finalize (GObject *object)
1575 +{
1576 +       EggRecentModelMulti *model = EGG_RECENT_MODEL_MULTI (object);
1577 +
1578 +       if (model->priv->changed_timeout > 0) {
1579 +               g_source_remove (model->priv->changed_timeout);
1580 +       }
1581 +
1582 +       egg_recent_model_multi_monitor (model, FALSE);
1583 +
1584 +
1585 +       g_slist_foreach (model->priv->mime_filter_values,
1586 +                        (GFunc) g_pattern_spec_free, NULL);
1587 +       g_slist_free (model->priv->mime_filter_values);
1588 +       model->priv->mime_filter_values = NULL;
1589 +
1590 +       g_slist_foreach (model->priv->scheme_filter_values,
1591 +                        (GFunc) g_pattern_spec_free, NULL);
1592 +       g_slist_free (model->priv->scheme_filter_values);
1593 +       model->priv->scheme_filter_values = NULL;
1594 +
1595 +       g_slist_foreach (model->priv->group_filter_values,
1596 +                        (GFunc) g_free, NULL);
1597 +       g_slist_free (model->priv->group_filter_values);
1598 +       model->priv->group_filter_values = NULL;
1599 +
1600 +
1601 +       if (model->priv->limit_change_notify_id)
1602 +               gconf_client_notify_remove (model->priv->client,
1603 +                                           model->priv->limit_change_notify_id);
1604 +       model->priv->expiration_change_notify_id = 0;
1605 +
1606 +       if (model->priv->expiration_change_notify_id)
1607 +               gconf_client_notify_remove (model->priv->client,
1608 +                                           model->priv->expiration_change_notify_id);
1609 +       model->priv->expiration_change_notify_id = 0;
1610 +
1611 +       g_object_unref (model->priv->client);
1612 +       model->priv->client = NULL;
1613 +
1614 +
1615 +       g_free (model->priv->path);
1616 +       model->priv->path = NULL;
1617 +       
1618 +       g_hash_table_destroy (model->priv->monitors);
1619 +       model->priv->monitors = NULL;
1620 +
1621 +       if (model->priv->poll_timeout > 0)
1622 +               g_source_remove (model->priv->poll_timeout);
1623 +       model->priv->poll_timeout =0;
1624 +
1625 +       g_free (model->priv);
1626 +
1627 +       parent_class->finalize (object);
1628 +}
1629 +
1630 +static void
1631 +egg_recent_model_multi_set_property (GObject *object,
1632 +                              guint prop_id,
1633 +                              const GValue *value,
1634 +                              GParamSpec *pspec)
1635 +{
1636 +       EggRecentModelMulti *model = EGG_RECENT_MODEL_MULTI (object);
1637 +
1638 +       switch (prop_id)
1639 +       {
1640 +               case PROP_MIME_FILTERS:
1641 +                       if (model->priv->mime_filter_values != NULL)
1642 +                               egg_recent_model_multi_clear_mime_filter (model);
1643 +                       
1644 +                       model->priv->mime_filter_values =
1645 +                               (GSList *)g_value_get_pointer (value);
1646 +               break;
1647 +
1648 +               case PROP_GROUP_FILTERS:
1649 +                       if (model->priv->group_filter_values != NULL)
1650 +                               egg_recent_model_multi_clear_group_filter (model);
1651 +                       
1652 +                       model->priv->group_filter_values =
1653 +                               (GSList *)g_value_get_pointer (value);
1654 +               break;
1655 +
1656 +               case PROP_SCHEME_FILTERS:
1657 +                       if (model->priv->scheme_filter_values != NULL)
1658 +                               egg_recent_model_multi_clear_scheme_filter (model);
1659 +                       
1660 +                       model->priv->scheme_filter_values =
1661 +                               (GSList *)g_value_get_pointer (value);
1662 +               break;
1663 +
1664 +               case PROP_SORT_TYPE:
1665 +                       model->priv->sort_type = g_value_get_int (value);
1666 +               break;
1667 +
1668 +               case PROP_FILE_PATH:
1669 +                       model->priv->path = g_strdup_printf (
1670 +                               "%s/%s",
1671 +                               g_get_home_dir (),
1672 +                               g_value_get_string (value)
1673 +                       );
1674 +                       egg_recent_model_multi_monitor (model, TRUE);
1675 +               break;
1676 +
1677 +               case PROP_LIMIT:
1678 +                       egg_recent_model_multi_set_limit (model,
1679 +                                               g_value_get_int (value));
1680 +               break;
1681 +
1682 +               default:
1683 +                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1684 +               break;
1685 +       }
1686 +}
1687 +
1688 +static void
1689 +egg_recent_model_multi_get_property (GObject *object,
1690 +                              guint prop_id,
1691 +                              GValue *value,
1692 +                              GParamSpec *pspec)
1693 +{
1694 +       EggRecentModelMulti *model = EGG_RECENT_MODEL_MULTI (object);
1695 +
1696 +       switch (prop_id)
1697 +       {
1698 +               case PROP_MIME_FILTERS:
1699 +                       g_value_set_pointer (value, model->priv->mime_filter_values);
1700 +               break;
1701 +
1702 +               case PROP_GROUP_FILTERS:
1703 +                       g_value_set_pointer (value, model->priv->group_filter_values);
1704 +               break;
1705 +
1706 +               case PROP_SCHEME_FILTERS:
1707 +                       g_value_set_pointer (value, model->priv->scheme_filter_values);
1708 +               break;
1709 +
1710 +               case PROP_SORT_TYPE:
1711 +                       g_value_set_int (value, model->priv->sort_type);
1712 +               break;
1713 +
1714 +               case PROP_FILE_PATH:
1715 +                       g_value_set_string (value, model->priv->path);
1716 +               break;
1717 +
1718 +               case PROP_LIMIT:
1719 +                       g_value_set_int (value, model->priv->limit);
1720 +               break;
1721 +
1722 +               default:
1723 +                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1724 +               break;
1725 +       }
1726 +}
1727 +
1728 +static void
1729 +egg_recent_model_multi_class_init (EggRecentModelMultiClass * klass)
1730 +{
1731 +       GObjectClass *object_class;
1732 +
1733 +       parent_class = g_type_class_peek_parent (klass);
1734 +
1735 +       parent_class = g_type_class_peek_parent (klass);
1736 +
1737 +       object_class = G_OBJECT_CLASS (klass);
1738 +       object_class->set_property = egg_recent_model_multi_set_property;
1739 +       object_class->get_property = egg_recent_model_multi_get_property;
1740 +       object_class->finalize     = egg_recent_model_multi_finalize;
1741 +
1742 +       model_signals[CHANGED] = g_signal_new ("changed",
1743 +                       G_OBJECT_CLASS_TYPE (object_class),
1744 +                       G_SIGNAL_RUN_LAST,
1745 +                       G_STRUCT_OFFSET (EggRecentModelMultiClass, changed),
1746 +                       NULL, NULL,
1747 +                       g_cclosure_marshal_VOID__POINTER,
1748 +                       G_TYPE_NONE, 1,
1749 +                       G_TYPE_POINTER);
1750 +
1751 +       
1752 +       g_object_class_install_property (object_class,
1753 +                                        PROP_MIME_FILTERS,
1754 +                                        g_param_spec_pointer ("mime-filters",
1755 +                                        "Mime Filters",
1756 +                                        "List of mime types to be allowed.",
1757 +                                        G_PARAM_READWRITE));
1758 +       
1759 +       g_object_class_install_property (object_class,
1760 +                                        PROP_GROUP_FILTERS,
1761 +                                        g_param_spec_pointer ("group-filters",
1762 +                                        "Group Filters",
1763 +                                        "List of groups to be allowed.",
1764 +                                        G_PARAM_READWRITE));
1765 +
1766 +       g_object_class_install_property (object_class,
1767 +                                        PROP_SCHEME_FILTERS,
1768 +                                        g_param_spec_pointer ("scheme-filters",
1769 +                                        "Scheme Filters",
1770 +                                        "List of URI schemes to be allowed.",
1771 +                                        G_PARAM_READWRITE));
1772 +
1773 +       g_object_class_install_property (object_class,
1774 +                                        PROP_SORT_TYPE,
1775 +                                        g_param_spec_int ("sort-type",
1776 +                                        "Sort Type",
1777 +                                        "Type of sorting to be done.",
1778 +                                        0, EGG_RECENT_MODEL_MULTI_SORT_NONE,
1779 +                                        EGG_RECENT_MODEL_MULTI_SORT_MRU,
1780 +                                        G_PARAM_READWRITE));
1781 +
1782 +       g_object_class_install_property (object_class,
1783 +                                        PROP_FILE_PATH,
1784 +                                        g_param_spec_string ("file-path",
1785 +                                        "File Path",
1786 +                                        "File path relative to $HOME.",
1787 +                                        EGG_RECENT_MODEL_MULTI_DEFAULT_FILE_PATH,
1788 +                                        G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1789 +
1790 +       g_object_class_install_property (object_class,
1791 +                                        PROP_LIMIT,
1792 +                                        g_param_spec_int ("limit",
1793 +                                        "Limit",
1794 +                                        "Max number of items allowed.",
1795 +                                        -1, EGG_RECENT_MODEL_MULTI_MAX_ITEMS,
1796 +                                        EGG_RECENT_MODEL_MULTI_DEFAULT_LIMIT,
1797 +                                        G_PARAM_READWRITE));
1798 +
1799 +       klass->changed = NULL;
1800 +}
1801 +
1802 +
1803 +
1804 +static void
1805 +egg_recent_model_multi_limit_changed (GConfClient *client, guint cnxn_id,
1806 +                               GConfEntry *entry, gpointer user_data)
1807 +{
1808 +       EggRecentModelMulti *model;
1809 +       GConfValue *value;
1810 +
1811 +       model = EGG_RECENT_MODEL_MULTI (user_data);
1812 +
1813 +       g_return_if_fail (model != NULL);
1814 +
1815 +       if (model->priv->use_default_limit == FALSE)
1816 +               return; /* ignore this key */
1817 +
1818 +       /* the key was unset, and the schema has apparently failed */
1819 +       if (entry == NULL)
1820 +               return;
1821 +
1822 +       value = gconf_entry_get_value (entry);
1823 +
1824 +       if (value->type != GCONF_VALUE_INT) {
1825 +               g_warning ("Expected GConfValue of type integer, "
1826 +                          "got something else");
1827 +       }
1828 +
1829 +
1830 +       egg_recent_model_multi_set_limit_internal (model, gconf_value_get_int (value));
1831 +}
1832 +
1833 +static void
1834 +egg_recent_model_multi_expiration_changed (GConfClient *client, guint cnxn_id,
1835 +                                    GConfEntry *entry, gpointer user_data)
1836 +{
1837 +
1838 +}
1839 +
1840 +static void
1841 +egg_recent_model_multi_init (EggRecentModelMulti * model)
1842 +{
1843 +       if (!gnome_vfs_init ()) {
1844 +               g_warning ("gnome-vfs initialization failed.");
1845 +               return;
1846 +       }
1847 +       
1848 +
1849 +       model->priv = g_new0 (EggRecentModelMultiPrivate, 1);
1850 +
1851 +       model->priv->mime_filter_values   = NULL;
1852 +       model->priv->group_filter_values  = NULL;
1853 +       model->priv->scheme_filter_values = NULL;
1854 +       
1855 +       model->priv->client = gconf_client_get_default ();
1856 +       gconf_client_add_dir (model->priv->client, EGG_RECENT_MODEL_MULTI_KEY_DIR,
1857 +                             GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
1858 +
1859 +       model->priv->limit_change_notify_id =
1860 +                       gconf_client_notify_add (model->priv->client,
1861 +                                                EGG_RECENT_MODEL_MULTI_DEFAULT_LIMIT_KEY,
1862 +                                                egg_recent_model_multi_limit_changed,
1863 +                                                model, NULL, NULL);
1864 +
1865 +       model->priv->expiration_change_notify_id =
1866 +                       gconf_client_notify_add (model->priv->client,
1867 +                                                EGG_RECENT_MODEL_MULTI_EXPIRE_KEY,
1868 +                                                egg_recent_model_multi_expiration_changed,
1869 +                                                model, NULL, NULL);
1870 +
1871 +       model->priv->expire_days = gconf_client_get_int (
1872 +                                       model->priv->client,
1873 +                                       EGG_RECENT_MODEL_MULTI_EXPIRE_KEY,
1874 +                                       NULL);
1875 +                                       
1876 +#if 0
1877 +       /* keep this out, for now */
1878 +       model->priv->limit = gconf_client_get_int (
1879 +                                       model->priv->client,
1880 +                                       EGG_RECENT_MODEL_MULTI_DEFAULT_LIMIT_KEY, NULL);
1881 +       model->priv->use_default_limit = TRUE;
1882 +#endif
1883 +       model->priv->limit = EGG_RECENT_MODEL_MULTI_DEFAULT_LIMIT;
1884 +       model->priv->use_default_limit = FALSE;
1885 +
1886 +       model->priv->monitors = g_hash_table_new_full (
1887 +                                       g_str_hash, g_str_equal,
1888 +                                       (GDestroyNotify) g_free,
1889 +                                       (GDestroyNotify) gnome_vfs_monitor_cancel);
1890 +
1891 +       model->priv->monitor = NULL;
1892 +       model->priv->poll_timeout = 0;
1893 +       model->priv->last_mtime = 0;
1894 +}
1895 +
1896 +
1897 +/**
1898 + * egg_recent_model_multi_new:
1899 + * @sort:  the type of sorting to use
1900 + * @limit:  maximum number of items in the list
1901 + *
1902 + * This creates a new EggRecentModelMulti object.
1903 + *
1904 + * Returns: a EggRecentModelMulti object
1905 + */
1906 +EggRecentModelMulti *
1907 +egg_recent_model_multi_new (EggRecentModelMultiSort sort)
1908 +{
1909 +       return egg_recent_model_multi_new_with_file_path (sort, EGG_RECENT_MODEL_MULTI_DEFAULT_FILE_PATH);
1910 +}
1911 +
1912 +EggRecentModelMulti *
1913 +egg_recent_model_multi_new_with_file_path (EggRecentModelMultiSort sort, const gchar *file_path)
1914 +{
1915 +       EggRecentModelMulti *model;
1916 +
1917 +       if (! file_path)
1918 +               file_path = EGG_RECENT_MODEL_MULTI_DEFAULT_FILE_PATH;
1919 +
1920 +       model = EGG_RECENT_MODEL_MULTI (g_object_new (egg_recent_model_multi_get_type (),
1921 +                                 "sort-type", sort, "file-path", file_path, NULL));
1922 +
1923 +       g_return_val_if_fail (model, NULL);
1924 +
1925 +       return model;
1926 +}
1927 +
1928 +/**
1929 + * egg_recent_model_multi_add_full:
1930 + * @model:  A EggRecentModelMulti object.
1931 + * @item:  A EggRecentItem
1932 + *
1933 + * This function adds an item to the list of recently used URIs.
1934 + *
1935 + * Returns: gboolean
1936 + */
1937 +gboolean
1938 +egg_recent_model_multi_add_full (EggRecentModelMulti * model, EggRecentItem *item)
1939 +{
1940 +       FILE *file;
1941 +       GList *list = NULL;
1942 +       gboolean ret = FALSE;
1943 +       gboolean updated = FALSE;
1944 +       char *uri;
1945 +       time_t t;
1946 +       
1947 +       g_return_val_if_fail (model != NULL, FALSE);
1948 +       g_return_val_if_fail (EGG_IS_RECENT_MODEL_MULTI (model), FALSE);
1949 +
1950 +       uri = egg_recent_item_get_uri (item);
1951 +       if (strncmp (uri, "recent-files://", strlen ("recent-files://")) == 0) {
1952 +               g_free (uri);
1953 +               return FALSE;
1954 +       } else {
1955 +               g_free (uri);
1956 +       }
1957 +
1958 +       file = egg_recent_model_multi_open_file (model, TRUE);
1959 +       g_return_val_if_fail (file != NULL, FALSE);
1960 +
1961 +       time (&t);
1962 +       egg_recent_item_set_timestamp (item, t);
1963 +
1964 +       if (egg_recent_model_multi_lock_file (file)) {
1965 +
1966 +               /* read existing stuff */
1967 +               list = egg_recent_model_multi_read (model, file);
1968 +
1969 +               /* if it's already there, we just update it */
1970 +               updated = egg_recent_model_multi_update_item (list, item);
1971 +
1972 +               if (!updated) {
1973 +                       list = g_list_prepend (list, item);
1974 +
1975 +                       egg_recent_model_multi_enforce_limit (list,
1976 +                                               EGG_RECENT_MODEL_MULTI_MAX_ITEMS);
1977 +               }
1978 +
1979 +               /* write new stuff */
1980 +               if (!egg_recent_model_multi_write (model, file, list))
1981 +                       g_warning ("Write failed: %s", strerror (errno));
1982 +
1983 +               if (!updated)
1984 +                       list = g_list_remove (list, item);
1985 +
1986 +               EGG_RECENT_ITEM_LIST_UNREF (list);
1987 +               ret = TRUE;
1988 +       } else {
1989 +               g_warning ("Failed to lock:  %s", strerror (errno));
1990 +               fclose (file);
1991 +               return FALSE;
1992 +       }
1993 +
1994 +       if (!egg_recent_model_multi_unlock_file (file))
1995 +               g_warning ("Failed to unlock: %s", strerror (errno));
1996 +
1997 +       fclose (file);
1998 +
1999 +       if (model->priv->monitor == NULL) {
2000 +               /* since monitoring isn't working, at least give a
2001 +                * local notification
2002 +                */
2003 +               egg_recent_model_multi_changed (model);
2004 +       }
2005 +
2006 +       return ret;
2007 +}
2008 +
2009 +/**
2010 + * egg_recent_model_multi_add:
2011 + * @model:  A EggRecentModelMulti object.
2012 + * @uri:  A string URI
2013 + *
2014 + * This function adds an item to the list of recently used URIs.
2015 + *
2016 + * Returns: gboolean
2017 + */
2018 +gboolean
2019 +egg_recent_model_multi_add (EggRecentModelMulti *model, const gchar *uri)
2020 +{
2021 +       EggRecentItem *item;
2022 +       gboolean ret = FALSE;
2023 +
2024 +       g_return_val_if_fail (model != NULL, FALSE);
2025 +       g_return_val_if_fail (uri != NULL, FALSE);
2026 +
2027 +       item = egg_recent_item_new_from_uri (uri);
2028 +
2029 +       g_return_val_if_fail (item != NULL, FALSE);
2030 +
2031 +       ret = egg_recent_model_multi_add_full (model, item);
2032 +
2033 +       egg_recent_item_unref (item);
2034 +
2035 +       return ret;
2036 +}
2037 +
2038 +
2039 +
2040 +/**
2041 + * egg_recent_model_multi_delete:
2042 + * @model:  A EggRecentModelMulti object.
2043 + * @uri: The URI you want to delete.
2044 + *
2045 + * This function deletes a URI from the file of recently used URIs.
2046 + *
2047 + * Returns: gboolean
2048 + */
2049 +gboolean
2050 +egg_recent_model_multi_delete (EggRecentModelMulti * model, const gchar * uri)
2051 +{
2052 +       FILE *file;
2053 +       GList *list;
2054 +       unsigned int length;
2055 +       gboolean ret = FALSE;
2056 +
2057 +       g_return_val_if_fail (model != NULL, FALSE);
2058 +       g_return_val_if_fail (EGG_IS_RECENT_MODEL_MULTI (model), FALSE);
2059 +       g_return_val_if_fail (uri != NULL, FALSE);
2060 +
2061 +       file = egg_recent_model_multi_open_file (model, TRUE);
2062 +       g_return_val_if_fail (file != NULL, FALSE);
2063 +
2064 +       if (egg_recent_model_multi_lock_file (file)) {
2065 +               list = egg_recent_model_multi_read (model, file);
2066 +
2067 +               if (list == NULL)
2068 +                       goto out;
2069 +
2070 +               length = g_list_length (list);
2071 +
2072 +               list = egg_recent_model_multi_delete_from_list (list, uri);
2073 +               
2074 +               if (length == g_list_length (list)) {
2075 +                       /* nothing was deleted */
2076 +                       EGG_RECENT_ITEM_LIST_UNREF (list);
2077 +               } else {
2078 +                       egg_recent_model_multi_write (model, file, list);
2079 +                       EGG_RECENT_ITEM_LIST_UNREF (list);
2080 +                       ret = TRUE;
2081 +
2082 +               }
2083 +       } else {
2084 +               g_warning ("Failed to lock:  %s", strerror (errno));
2085 +               return FALSE;
2086 +       }
2087 +
2088 +out:
2089 +               
2090 +       if (!egg_recent_model_multi_unlock_file (file))
2091 +               g_warning ("Failed to unlock: %s", strerror (errno));
2092 +
2093 +       fclose (file);
2094 +
2095 +       g_hash_table_remove (model->priv->monitors, uri);
2096 +
2097 +       if (model->priv->monitor == NULL && ret) {
2098 +               /* since monitoring isn't working, at least give a
2099 +                * local notification
2100 +                */
2101 +               egg_recent_model_multi_changed (model);
2102 +       }
2103 +
2104 +       return ret;
2105 +}
2106 +
2107 +
2108 +/**
2109 + * egg_recent_model_multi_get_list:
2110 + * @model:  A EggRecentModelMulti object.
2111 + *
2112 + * This function gets the current contents of the file
2113 + *
2114 + * Returns: a GList
2115 + */
2116 +GList *
2117 +egg_recent_model_multi_get_list (EggRecentModelMulti *model)
2118 +{
2119 +       FILE *file;
2120 +       GList *list = NULL;
2121 +
2122 +       file = egg_recent_model_multi_open_file (model, FALSE);
2123 +       if (file == NULL)
2124 +               return NULL;
2125 +       
2126 +       if (egg_recent_model_multi_lock_file (file))
2127 +               list = egg_recent_model_multi_read (model, file);
2128 +       else {
2129 +               g_warning ("Failed to lock:  %s", strerror (errno));
2130 +               fclose (file);
2131 +               return NULL;
2132 +       }
2133 +
2134 +       if (!egg_recent_model_multi_unlock_file (file))
2135 +               g_warning ("Failed to unlock: %s", strerror (errno));
2136 +
2137 +       if (list != NULL) {
2138 +               list = egg_recent_model_multi_filter (model, list);
2139 +               list = egg_recent_model_multi_sort (model, list);
2140 +
2141 +               egg_recent_model_multi_enforce_limit (list, model->priv->limit);
2142 +       }
2143 +
2144 +       fclose (file);
2145 +
2146 +       return list;
2147 +}
2148 +
2149 +
2150 +
2151 +/**
2152 + * egg_recent_model_multi_set_limit:
2153 + * @model:  A EggRecentModelMulti object.
2154 + * @limit:  The maximum length of the list
2155 + *
2156 + * This function sets the maximum length of the list.  Note:  This only affects
2157 + * the length of the list emitted in the "changed" signal, not the list stored
2158 + * on disk.
2159 + *
2160 + * Returns:  void
2161 + */
2162 +void
2163 +egg_recent_model_multi_set_limit (EggRecentModelMulti *model, int limit)
2164 +{
2165 +       model->priv->use_default_limit = FALSE;
2166 +
2167 +       egg_recent_model_multi_set_limit_internal (model, limit);
2168 +}
2169 +
2170 +/**
2171 + * egg_recent_model_multi_get_limit:
2172 + * @model:  A EggRecentModelMulti object.
2173 + *
2174 + * This function gets the maximum length of the list. 
2175 + *
2176 + * Returns:  int
2177 + */
2178 +int
2179 +egg_recent_model_multi_get_limit (EggRecentModelMulti *model)
2180 +{
2181 +       return model->priv->limit;
2182 +}
2183 +
2184 +
2185 +/**
2186 + * egg_recent_model_multi_clear:
2187 + * @model:  A EggRecentModelMulti object.
2188 + *
2189 + * This function clears the contents of the file
2190 + *
2191 + * Returns: void
2192 + */
2193 +void
2194 +egg_recent_model_multi_clear (EggRecentModelMulti *model)
2195 +{
2196 +       FILE *file;
2197 +       int fd;
2198 +
2199 +       file = egg_recent_model_multi_open_file (model, TRUE);
2200 +       g_return_if_fail (file != NULL);
2201 +
2202 +       fd = fileno (file);
2203 +
2204 +       if (egg_recent_model_multi_lock_file (file)) {
2205 +               ftruncate (fd, 0);
2206 +       } else {
2207 +               g_warning ("Failed to lock:  %s", strerror (errno));
2208 +               return;
2209 +       }
2210 +
2211 +       if (!egg_recent_model_multi_unlock_file (file))
2212 +               g_warning ("Failed to unlock: %s", strerror (errno));
2213 +
2214 +       fclose (file);
2215 +       
2216 +       if (model->priv->monitor == NULL) {
2217 +               /* since monitoring isn't working, at least give a
2218 +                * local notification
2219 +                */
2220 +               egg_recent_model_multi_changed (model);
2221 +       }
2222 +}
2223 +
2224 +static void
2225 +egg_recent_model_multi_clear_mime_filter (EggRecentModelMulti *model)
2226 +{
2227 +       g_return_if_fail (model != NULL);
2228 +
2229 +       if (model->priv->mime_filter_values != NULL) {
2230 +               g_slist_foreach (model->priv->mime_filter_values,
2231 +                                (GFunc) g_pattern_spec_free, NULL);
2232 +               g_slist_free (model->priv->mime_filter_values);
2233 +               model->priv->mime_filter_values = NULL;
2234 +       }
2235 +}      
2236 +
2237 +/**
2238 + * egg_recent_model_multi_set_filter_mime_types:
2239 + * @model:  A EggRecentModelMulti object.
2240 + *
2241 + * Sets which mime types are allowed in the list.
2242 + *
2243 + * Returns: void
2244 + */
2245 +void
2246 +egg_recent_model_multi_set_filter_mime_types (EggRecentModelMulti *model,
2247 +                              ...)
2248 +{
2249 +       va_list valist;
2250 +       GSList *list = NULL;
2251 +       gchar *str;
2252 +
2253 +       g_return_if_fail (model != NULL);
2254 +
2255 +       egg_recent_model_multi_clear_mime_filter (model);
2256 +
2257 +       va_start (valist, model);
2258 +
2259 +       str = va_arg (valist, gchar*);
2260 +
2261 +       while (str != NULL) {
2262 +               list = g_slist_prepend (list, g_pattern_spec_new (str));
2263 +
2264 +               str = va_arg (valist, gchar*);
2265 +       }
2266 +
2267 +       va_end (valist);
2268 +
2269 +       model->priv->mime_filter_values = list;
2270 +}
2271 +
2272 +static void
2273 +egg_recent_model_multi_clear_group_filter (EggRecentModelMulti *model)
2274 +{
2275 +       g_return_if_fail (model != NULL);
2276 +
2277 +       if (model->priv->group_filter_values != NULL) {
2278 +               g_slist_foreach (model->priv->group_filter_values, (GFunc)g_free, NULL);
2279 +               g_slist_free (model->priv->group_filter_values);
2280 +               model->priv->group_filter_values = NULL;
2281 +       }
2282 +}
2283 +
2284 +/**
2285 + * egg_recent_model_multi_set_filter_groups:
2286 + * @model:  A EggRecentModelMulti object.
2287 + *
2288 + * Sets which groups are allowed in the list.
2289 + *
2290 + * Returns: void
2291 + */
2292 +void
2293 +egg_recent_model_multi_set_filter_groups (EggRecentModelMulti *model,
2294 +                              ...)
2295 +{
2296 +       va_list valist;
2297 +       GSList *list = NULL;
2298 +       gchar *str;
2299 +
2300 +       g_return_if_fail (model != NULL);
2301 +
2302 +       egg_recent_model_multi_clear_group_filter (model);
2303 +       
2304 +       va_start (valist, model);
2305 +
2306 +       str = va_arg (valist, gchar*);
2307 +
2308 +       while (str != NULL) {
2309 +               list = g_slist_prepend (list, g_strdup (str));
2310 +
2311 +               str = va_arg (valist, gchar*);
2312 +       }
2313 +
2314 +       va_end (valist);
2315 +
2316 +       model->priv->group_filter_values = list;
2317 +}
2318 +
2319 +static void
2320 +egg_recent_model_multi_clear_scheme_filter (EggRecentModelMulti *model)
2321 +{
2322 +       g_return_if_fail (model != NULL);
2323 +
2324 +       if (model->priv->scheme_filter_values != NULL) {
2325 +               g_slist_foreach (model->priv->scheme_filter_values,
2326 +                               (GFunc) g_pattern_spec_free, NULL);
2327 +               g_slist_free (model->priv->scheme_filter_values);
2328 +               model->priv->scheme_filter_values = NULL;
2329 +       }
2330 +}
2331 +
2332 +/**
2333 + * egg_recent_model_multi_set_filter_uri_schemes:
2334 + * @model:  A EggRecentModelMulti object.
2335 + *
2336 + * Sets which URI schemes (file, http, ftp, etc) are allowed in the list.
2337 + *
2338 + * Returns: void
2339 + */
2340 +void
2341 +egg_recent_model_multi_set_filter_uri_schemes (EggRecentModelMulti *model, ...)
2342 +{
2343 +       va_list valist;
2344 +       GSList *list = NULL;
2345 +       gchar *str;
2346 +
2347 +       g_return_if_fail (model != NULL);
2348 +
2349 +       egg_recent_model_multi_clear_scheme_filter (model);
2350 +       
2351 +       va_start (valist, model);
2352 +
2353 +       str = va_arg (valist, gchar*);
2354 +
2355 +       while (str != NULL) {
2356 +               list = g_slist_prepend (list, g_pattern_spec_new (str));
2357 +
2358 +               str = va_arg (valist, gchar*);
2359 +       }
2360 +
2361 +       va_end (valist);
2362 +
2363 +       model->priv->scheme_filter_values = list;
2364 +}
2365 +
2366 +/**
2367 + * egg_recent_model_multi_set_sort:
2368 + * @model:  A EggRecentModelMulti object.
2369 + * @sort:  A EggRecentModelMultiSort type
2370 + *
2371 + * Sets the type of sorting to be used.
2372 + *
2373 + * Returns: void
2374 + */
2375 +void
2376 +egg_recent_model_multi_set_sort (EggRecentModelMulti *model,
2377 +                            EggRecentModelMultiSort sort)
2378 +{
2379 +       g_return_if_fail (model != NULL);
2380 +       
2381 +       model->priv->sort_type = sort;
2382 +}
2383 +
2384 +/**
2385 + * egg_recent_model_multi_changed:
2386 + * @model:  A EggRecentModelMulti object.
2387 + *
2388 + * This function causes a "changed" signal to be emitted.
2389 + *
2390 + * Returns: void
2391 + */
2392 +void
2393 +egg_recent_model_multi_changed (EggRecentModelMulti *model)
2394 +{
2395 +       GList *list = NULL;
2396 +
2397 +       if (model->priv->limit > 0) {
2398 +               list = egg_recent_model_multi_get_list (model);
2399 +               /* egg_recent_model_multi_monitor_list (model, list); */
2400 +       
2401 +               g_signal_emit (G_OBJECT (model), model_signals[CHANGED], 0,
2402 +                              list);
2403 +       }
2404 +
2405 +       if (list)
2406 +               EGG_RECENT_ITEM_LIST_UNREF (list);
2407 +}
2408 +
2409 +static void
2410 +egg_recent_model_multi_remove_expired_list (EggRecentModelMulti *model, GList *list)
2411 +{
2412 +       time_t current_time;
2413 +       time_t day_seconds;
2414 +
2415 +       time (&current_time);
2416 +       day_seconds = model->priv->expire_days*24*60*60;
2417 +
2418 +       while (list != NULL) {
2419 +               EggRecentItem *item = list->data;
2420 +               time_t timestamp;
2421 +
2422 +               timestamp = egg_recent_item_get_timestamp (item);
2423 +
2424 +               if ((timestamp+day_seconds) < current_time) {
2425 +                       gchar *uri = egg_recent_item_get_uri (item);
2426 +                       egg_recent_model_multi_delete (model, uri);
2427 +
2428 +                       g_strdup (uri);
2429 +               }
2430 +
2431 +               list = list->next;
2432 +       }
2433 +}
2434 +
2435 +
2436 +/**
2437 + * egg_recent_model_multi_remove_expired:
2438 + * @model:  A EggRecentModelMulti object.
2439 + *
2440 + * Goes through the entire list, and removes any items that are older than
2441 + * the user-specified expiration period.
2442 + *
2443 + * Returns: void
2444 + */
2445 +void
2446 +egg_recent_model_multi_remove_expired (EggRecentModelMulti *model)
2447 +{
2448 +       FILE *file;
2449 +       GList *list=NULL;
2450 +
2451 +       g_return_if_fail (model != NULL);
2452 +
2453 +       file = egg_recent_model_multi_open_file (model, FALSE);
2454 +       if (file == NULL)
2455 +               return;
2456 +       
2457 +       if (egg_recent_model_multi_lock_file (file)) {
2458 +               list = egg_recent_model_multi_read (model, file);
2459 +               
2460 +       } else {
2461 +               g_warning ("Failed to lock:  %s", strerror (errno));
2462 +               return;
2463 +       }
2464 +
2465 +       if (!egg_recent_model_multi_unlock_file (file))
2466 +               g_warning ("Failed to unlock: %s", strerror (errno));
2467 +
2468 +       if (list != NULL) {
2469 +               egg_recent_model_multi_remove_expired_list (model, list);
2470 +               EGG_RECENT_ITEM_LIST_UNREF (list);
2471 +       }
2472 +
2473 +       fclose (file);
2474 +}
2475 +
2476 +/**
2477 + * egg_recent_model_multi_get_type:
2478 + *
2479 + * This returns a GType representing a EggRecentModelMulti object.
2480 + *
2481 + * Returns: a GType
2482 + */
2483 +GType
2484 +egg_recent_model_multi_get_type (void)
2485 +{
2486 +       static GType egg_recent_model_multi_type = 0;
2487 +
2488 +       if(!egg_recent_model_multi_type) {
2489 +               static const GTypeInfo egg_recent_model_multi_info = {
2490 +                       sizeof (EggRecentModelMultiClass),
2491 +                       NULL, /* base init */
2492 +                       NULL, /* base finalize */
2493 +                       (GClassInitFunc)egg_recent_model_multi_class_init, /* class init */
2494 +                       NULL, /* class finalize */
2495 +                       NULL, /* class data */
2496 +                       sizeof (EggRecentModelMulti),
2497 +                       0,
2498 +                       (GInstanceInitFunc) egg_recent_model_multi_init
2499 +               };
2500 +
2501 +               egg_recent_model_multi_type = g_type_register_static (G_TYPE_OBJECT,
2502 +                                                       "EggRecentModelMulti",
2503 +                                                       &egg_recent_model_multi_info, 0);
2504 +       }
2505 +
2506 +       return egg_recent_model_multi_type;
2507 +}
2508 +
2509 diff -urN ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-model-multi.h ./libgnome-desktop/egg-recent-model-multi.h
2510 --- ../gnome-desktop-2.12.2-pristine/libgnome-desktop/egg-recent-model-multi.h  1969-12-31 19:00:00.000000000 -0500
2511 +++ ./libgnome-desktop/egg-recent-model-multi.h 2006-05-08 16:48:27.000000000 -0400
2512 @@ -0,0 +1,81 @@
2513 +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2514 +#ifndef __EGG_RECENT_MODEL_MULTI_H__
2515 +#define __EGG_RECENT_MODEL_MULTI_H__
2516 +
2517 +#include "egg-recent-item.h"
2518 +
2519 +G_BEGIN_DECLS
2520 +
2521 +#define EGG_TYPE_RECENT_MODEL_MULTI            (egg_recent_model_multi_get_type ())
2522 +#define EGG_RECENT_MODEL_MULTI(obj)            G_TYPE_CHECK_INSTANCE_CAST (obj, EGG_TYPE_RECENT_MODEL_MULTI, EggRecentModelMulti)
2523 +#define EGG_RECENT_MODEL_MULTI_CLASS(klass)    G_TYPE_CHECK_CLASS_CAST (klass, EGG_TYPE_RECENT_MODEL_MULTI, EggRecentModelMultiClass)
2524 +#define EGG_IS_RECENT_MODEL_MULTI(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, egg_recent_model_multi_get_type ())
2525 +
2526 +typedef struct _EggRecentModelMulti        EggRecentModelMulti;
2527 +typedef struct _EggRecentModelMultiPrivate EggRecentModelMultiPrivate;
2528 +typedef struct _EggRecentModelMultiClass   EggRecentModelMultiClass;
2529 +
2530 +struct _EggRecentModelMulti {
2531 +       GObject                parent_instance;
2532 +
2533 +       EggRecentModelMultiPrivate *priv;
2534 +};
2535 +
2536 +struct _EggRecentModelMultiClass {
2537 +       GObjectClass parent_class;
2538 +                       
2539 +       void (*changed) (EggRecentModelMulti *model, GList *list);
2540 +};
2541 +
2542 +typedef enum {
2543 +       EGG_RECENT_MODEL_MULTI_SORT_MRU,
2544 +       EGG_RECENT_MODEL_MULTI_SORT_LRU,
2545 +       EGG_RECENT_MODEL_MULTI_SORT_NONE
2546 +} EggRecentModelMultiSort;
2547 +
2548 +
2549 +/* Standard group names */
2550 +#define EGG_RECENT_GROUP_LAUNCHERS "Launchers"
2551 +
2552 +
2553 +GType    egg_recent_model_multi_get_type     (void);
2554 +
2555 +/* constructors */
2556 +EggRecentModelMulti * egg_recent_model_multi_new                (EggRecentModelMultiSort sort);
2557 +EggRecentModelMulti * egg_recent_model_multi_new_with_file_path (EggRecentModelMultiSort sort, const gchar *file_path);
2558 +
2559 +/* public methods */
2560 +void     egg_recent_model_multi_set_filter_mime_types (EggRecentModelMulti *model,
2561 +                                                  ...);
2562 +
2563 +void     egg_recent_model_multi_set_filter_groups (EggRecentModelMulti *model, ...);
2564 +
2565 +void     egg_recent_model_multi_set_filter_uri_schemes (EggRecentModelMulti *model,
2566 +                                                  ...);
2567 +
2568 +void     egg_recent_model_multi_set_sort (EggRecentModelMulti *model,
2569 +                                     EggRecentModelMultiSort sort);
2570 +
2571 +gboolean egg_recent_model_multi_add_full (EggRecentModelMulti *model,
2572 +                                     EggRecentItem *item);
2573 +
2574 +gboolean egg_recent_model_multi_add         (EggRecentModelMulti *model,
2575 +                                     const gchar *uri);
2576 +
2577 +gboolean egg_recent_model_multi_delete   (EggRecentModelMulti *model,
2578 +                                     const gchar *uri);
2579 +
2580 +void egg_recent_model_multi_clear        (EggRecentModelMulti *model);
2581 +
2582 +GList * egg_recent_model_multi_get_list  (EggRecentModelMulti *model);
2583 +
2584 +void egg_recent_model_multi_changed      (EggRecentModelMulti *model);
2585 +
2586 +void egg_recent_model_multi_set_limit    (EggRecentModelMulti *model, int limit);
2587 +int  egg_recent_model_multi_get_limit    (EggRecentModelMulti *model);
2588 +
2589 +void egg_recent_model_multi_remove_expired (EggRecentModelMulti *model);
2590 +
2591 +G_END_DECLS
2592 +
2593 +#endif /* __EGG_RECENT_MODEL_MULTI_H__ */
2594 diff -urN ../gnome-desktop-2.12.2-pristine/libgnome-desktop/gnome-desktop-item.c ./libgnome-desktop/gnome-desktop-item.c
2595 --- ../gnome-desktop-2.12.2-pristine/libgnome-desktop/gnome-desktop-item.c      2005-11-04 03:43:42.000000000 -0500
2596 +++ ./libgnome-desktop/gnome-desktop-item.c     2006-05-08 17:07:23.000000000 -0400
2597 @@ -59,6 +59,9 @@
2598  #include <gtk/gtk.h>
2599  #endif
2600  
2601 +#include "egg-recent-item.h"
2602 +#include "egg-recent-model-multi.h"
2603 +
2604  #define sure_string(s) ((s)!=NULL?(s):"")
2605  
2606  struct _GnomeDesktopItem {
2607 @@ -128,6 +131,8 @@
2608                                      const char        *uri,
2609                                      GError           **error);
2610  
2611 +static void update_recently_used_apps (const GnomeDesktopItem *item);
2612 +
2613  static int
2614  readbuf_getc (ReadBuf *rb)
2615  {
2616 @@ -2091,6 +2096,8 @@
2617                              (flags & GNOME_DESKTOP_ITEM_LAUNCH_APPEND_PATHS),
2618                              error);
2619  
2620 +       update_recently_used_apps (item);
2621 +
2622         return ret;
2623  }
2624  
2625 @@ -4095,3 +4102,22 @@
2626  
2627         return q;
2628  }
2629 +
2630 +static void
2631 +update_recently_used_apps (const GnomeDesktopItem *item)
2632 +{
2633 +       EggRecentModelMulti *model;
2634 +
2635 +
2636 +       if (! item)
2637 +               return;
2638 +
2639 +       model = egg_recent_model_multi_new_with_file_path (EGG_RECENT_MODEL_MULTI_SORT_MRU, ".recently-used-apps");
2640 +
2641 +       if (! model)
2642 +               return;
2643 +
2644 +       egg_recent_model_multi_add (model, gnome_desktop_item_get_location (item));
2645 +
2646 +       g_object_unref (G_OBJECT (model));
2647 +}
2648 Files ../gnome-desktop-2.12.2-pristine/libgnome-desktop/.gnome-desktop-item.c.swp and ./libgnome-desktop/.gnome-desktop-item.c.swp differ
2649 diff -urN ../gnome-desktop-2.12.2-pristine/libgnome-desktop/Makefile.am ./libgnome-desktop/Makefile.am
2650 --- ../gnome-desktop-2.12.2-pristine/libgnome-desktop/Makefile.am       2004-11-18 12:42:53.000000000 -0500
2651 +++ ./libgnome-desktop/Makefile.am      2006-05-08 16:55:25.000000000 -0400
2652 @@ -16,9 +16,13 @@
2653  
2654  noinst_PROGRAMS = test-ditem test-hint test-ditem-edit
2655  
2656 -libgnome_desktop_2_la_SOURCES = \
2657 -       gnome-desktop-item.c    \
2658 -       gnome-ditem-edit.c      \
2659 +libgnome_desktop_2_la_SOURCES =                \
2660 +       gnome-desktop-item.c            \
2661 +       gnome-ditem-edit.c              \
2662 +       egg-recent-item.h               \
2663 +       egg-recent-item.c               \
2664 +       egg-recent-model-multi.h        \
2665 +       egg-recent-model-multi.c        \
2666         gnome-hint.c
2667  
2668  libgnome_desktop_2_la_LIBADD = \
This page took 0.425421 seconds and 3 git commands to generate.