Gtk+ Recent files updates



Hi all.

It's been a while since I sent any news on the recent files stuff, and
since a revision is planned, I've thought about writing down a little
overview on the whole code base, and (hopefully) get some replies back.

The code, for the people that haven't noticed and/or haven't cared,
lives in libegg, under the bookmarkfile [the parser object] and
recentchooser [the manager and the widgetry] directories; it has been
splitted in two not only for convenience, but because the former belongs
to GLib and the latter to GTK.


BookmarkFile
============
bookmarkfile/eggbookmarkfile.h
bookmarkfile/eggbookmarkfile.c

EggBookmarkFile is the parser object for bookmark files - hence the
name; it's a conveniently modelled around GKeyFile, even though the API
is more specialised, since the file format it's not general like the key
file.  Basically, is a big (4000+ lines[6]) parser for a sub-class of
the XBEL (XML Bookmark Exchange Language) 1.0 specification, called the
Desktop Bookmark Specification[1].  The spec is present in CVS, as a
DocBook document and a DTD.  The Desktop Bookmark specification aims to
resolve a bunch of problems - and one of them is the recently used files
list; it adds more meta-data to the current recent-files spec[2], and by
using XBEL it also allows more interoperability with other projects.

The EggBookmarkFile object is a parser and a writer: you can load files,
change them and write them back; originally, it featured a locking
mechanism in order to guarantee atomicity while reading and writing -
this has been removed, due to the portability issues file locking has;
the applications should ensure that no other operation is going on while
reading/writing a bookmark file[3].

RecentManager
=============
recentchooser/eggrecentmanager.h
recentchooser/eggrecentmanager.c

This is the object controlling the list of recently used stuff; when I
say stuff, I mean everything that can be addressed by a URI and has a
MIME type.  It's a simple object, poll()-ing the storage file
($HOME/.recently-used.xbel) twice per second, checking for changes and
emitting a signal in case any change was found.

You add stuff to the list it holds by using a URI and by passing the
required meta-data yourself; the meta-data is:

  * an optional user defined name;
  * an optional user defined description;
  * the MIME type of the resource pointed by the URI;
  * an optional list of groups to which the resource belongs;
  * the name of the application that is registering the URI;
  * the command line used by the application to open the URI;
  * whether the resource should be private;

There's a convenience API for inferring all this stuff, too, especially
the MIME type of the resource; important caveat: this works only on
local URI - but if you are dealing with non local URI you should already
be using gnome-vfs, get the document's MIME type from gnome-vfs, and you
could pass it by yourself.

The EggRecentManager object really doesn't do much more than adding and
getting back stuff to the list - and optionally purge the list; if you
want to see what's inside it, you must use the EggRecentInfo object -
which is a container of all the meta-data bound to a URI inside the
"recently used" list.  The EggRecentInfo object is mainly a proxy to the
low-level EggBookmarkFile parser, but it also act as a convenience API
in order to get stuff from the meta-data, like the icon bound to its
MIME type or the short version of the resource name.


RecentChooser
=============
recentchooser/eggrecentchooser.[ch]
recentchooser/eggrecentchooserutils.[ch]
recentchooser/eggrecentchooserprivate.h
recentchooser/eggrecentfilter.[ch]

A GTypeInterface, which should be implemented by every widget showing a
list of recently used documents.  It offers some convenience methods,
properties and signals, much like the GtkFileChooser interface.

Available sorting methods are: None, Most Recently Used (first), Least
Recently Used (first) and Custom; the latter uses a custom sorting
function.

Filtering is done using a RecentFilter object, which behaves like the
GtkFileFilter object of the file chooser; it simply adds three more
properties: "age", filtering on the days elapsed since the last change
of a document inside the list; "application", filtering on the name of
the application that has registered a document inside the list; and
"group", filtering on a group name to which a document belongs to.
Custom filtering is supported, too.


RecentChooserWidget, RecentChooserDialog, RecentChooserMenu
===========================================================
recentchooser/eggrecentchooserdefault.[ch]
recentchooser/eggrecentchooserwidget.[ch]
recentchooser/eggrecentchooserdialog.[ch]
recentchooser/eggrecentchoosermenu.[ch]

More or less simple widgetry: an embeddable widget, similar to the
"document history" used in GIMP; a dialog embedding that widget; a menu,
to be used as a sub-menu for a GtkMenuItem or as the drop-down menu for
a GtkMenuToolButton.  Two more stand-alone widgets are planned: a
RecentChooserButton and a RecentChooserInline widget, to be embedded
into a GtkMenu like the EggRecentViewGtk object; also, integration with
the GtkUIManager is planned, in form of a "<recent-items/>" place-holder
(with an optional "limit" property which controls the size of the list).


Merging plans
=============
The plan is to merge the parser code into GLib as soon as possible: this
week or next one.  The code still needs a bit of polishing, namely the
removal of dead/debug/profiling code, which will be kept only in libegg
for further optimization[4]; also, I'd like to add the ISO 8601 related
functions into GLib[5] before merging, since it would shave off some
more lines of code[6].

In the mean time, the desktop bookmark specification will be pushed to
the XDG list, and I'll try to have it formally blessed by fd.o.

After that, the RecentManager and the widgets should be merged into GTK,
and we could deprecate the infamous recent-files code in libegg.  There
already is a porting guide (see below), which could easily be merged
into the GTK documentation.


Informations
============
More informations and a porting guide from the old RecentFiles code can
be found on the wiki:

  http://live.gnome.org/RecentFilesAndBookmarks

+++

Comments?  Questions?

+++

[1] http://devel.emmanuelebassi.net/papers/bookmark-spec.html
[2] one other reason for the existence of the BookmarkFile is to have a
common API for reading and writing "shortcuts" inside the file chooser,
nautilus and the panel - and make it available to anyone else wanting to
access those shortcuts inside their applications; relevant bugs are
#147434 and #157377:
  http://bugzilla.gnome.org/show_bug.cgi?id=147434
  http://bugzilla.gnome.org/show_bug.cgi?id=157377
also, see the http://live.gnome.org/DesktopPlaces page on the wiki.
[3] this is not entirely accurate: we use g_file_get_contents() and
g_file_set_contents() for reading from, and writing to a file,
respectively; thus, some degrees of atomicity are guaranteed, especially
when writing, but for better or worse the user is in charge of
preventing concurrent accesses while reading/writing a bookmark file.
[4] The optimization of the BookmarkFile code was done in the last
months, and I blogged about it here:
  http://log.emmanuelebassi.net/archives/2005/09/profiling-gmarkup/
  http://log.emmanuelebassi.net/archives/2005/10/profiling-gmarkup-2/
  http://log.emmanuelebassi.net/archives/2005/11/profiling-gmarkup-3/
in short: reading a ~1.0MB file requires with the current code half a
second, semi-cold cache.
[5] see bug #335425:
  http://bugzilla.gnome.org/show_bug.cgi?id=335425
[6] The actual lines of code are in the order of ~3500: as it is, the
BookmarkFile code has nearly 300 lines of debug/profiling code
conditionally compiled in, plus many redundant checks.

Ciao,
Emmanuele.

-- 
Emmanuele Bassi - <ebassi gmail com>
Log: http://log.emmanuelebassi.net




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]