Xfce

Subdomains
 

Preview: Browsing SFTP with Thunar

  • June 16, 2009
  • Jannis Pohlmann

It feels like I'm finally getting somewhere. My GIO migration branch of Thunar now generates thumbnails using the D-Bus service provided by Tumbler (which is still in development but almost ready for a release). It has no references to ThunarVFS anymore, except for one function required by Thunarx, the Thunar extension library. The next step will be to prepare thunarx-2 with a ThunarVFS-free API. All plugins shipped with Thunar itself need to be updated. ThunarVFS will be moved out of the Thunar tarball and into its own, so that applications depending on it will still work. And then we only need to fork the HAL based volume monitor from GVfs and of course thunar-volman needs to be rewritten on top of GIO ...

Anyway, just a few moments ago, I did something I thought is worth sharing: I browsed one of our servers remotely over SFTP! Mounting still needs to be done from the terminal but after that, you can simply type in the SSH or SFTP URI and it will display its contents. Thumbnails are generated over D-Bus. Here's a screenshot:

Update

Thunar can now mount remote URIs on demand:

FTP browsing also works:

Recently in Xfce

  • June 11, 2009
  • Jérôme Guelfucci

This is just a short post with what happened recently in Xfce.

  • Xfce4 Power Manager 0.8.0 was released. I did not have time yet to test it, but it looks promising.
  • Jannis Pohlmann and Stephan Arts drafted a release process for Xfce. It still needs to be discussed, but it already looks great. Expect some progress on this once the migration to git is done.
  • Brian Tarricone worked a lot on the git migration, things are almost settled.
  • Jannis Pohlmann is making some awesome progress on Thunar. He developped Tumbler, a D-Bus thumbnailing service based on the thumbnail management D-Bus specification, to replace the old thumbnailing code. A video shows how his first experimental implementation behaves.
  • Nick Schermer made a lot of progress on Xfce4 Panel, fixing and lot of bugs and improving performances. His code can be found on git.xfce.org.
  • Stephan Arts has improved the git version of Ristretto a lot: it works, supports basic printing and features a new improved user interface.
  • It seems that Colin Leroy will be the maintainer of Xfce4 Weather Plugin from now on. Welcome!
  • Mike Massonnet rewrote Xfce4 Notes Plugin in Vala, and improved and lot of things at the same time. Expect a release soon.
  • Ali Abdallah, the developper of Xfce4 Power Manager, added a new Goodie to the SVN. Parole is a Gstreamer based media player. I did not test it, so I cannot say more...

News Update

  • June 4, 2009
  • Jannis Pohlmann

A lot of things are going on lately and it turns out I'm way to busy to update my weblog on a regular basis. So, this is just a short post to keep you all updated.

Last two weeks

  • I took a new student job at the university, at the Institute of Theoretical Computer Science, which I love most. I'll be working on haplotyping algorithms.
  • I went to Barcelona and had a great time at the Ubuntu Developer Summit overall. Stephan and I were very productive. One evening during dinner we discussed our development and release process and later started writing it down. The result is a beautiful document that still needs a bit of polishing. I hope it'll serve as a good foundation for the development and release process of Xfce in the future. Several others commented on it and it looks like we'll give the proposed concept a shot after we've switched to git and all that.
  • Even though the week in Barcelona was great for Xfce, I was disappointed with how it went with regards to the cooperation between Xubuntu and Xfce. I talked it through with Stephan and after I got back, I resigned from my position as the Xubuntu Xfce4 Liaison.

At the moment

  • I've started to implement the so-called thumbnail management D-Bus specification. My implementation is called Tumbler and it will hopefully start serving thumbnails for other apps soon. I'm planning to use it in Thunar, Stephan has expressed interest in using it in Ristretto and when discussing the specification and the existing hildon-thumbnail implementation, Philip van Hoof told me that Hildon/Nokia might be interested in dropping hildon-thumbnail in favor of Tumbler if it's flexible enough. I'm working on it as much as I can and I'm hoping to do a release within the next few weeks.
  • I'm still working on the Transifex installation for Xfce. It's already running but I still need to import all the projects, releases and of course create accounts for maintainers automatically.
  • The migration of Xfce to Git is still work in progress. Brian has most of the repository issues sorted out and is now waiting for me to finish the commit mail script. I have two or three possible implementations lying around but I need to have a look at that again.
  • Jim needs the documentation repository next week, so I'm about to set it up.
  • Our Buildbot server has arrived in Sweden. Today I set up the firewall. Samual is taking care of setting up the Buildbot host VM and other things. We're considering to move a lot of the services not related to development (like the Xfce websites) into separate VMs on that server too, in order to make the current server a development-only machine.

Besides that I'm trying to catch up with the work and personal stuff that piled up while I was away last week. And I really should go and sleep.

Another Thunar/GIO Status Update

  • May 1, 2009
  • Jannis Pohlmann

I'm more or less done with migrating the volume management code in Thunar to GIO. As of today there's not a single reference to ThunarVfsVolume or ThunarVfsVolume manager in Thunar anymore. While that is pretty neat and another thing I can mark as (almost) done, there are a few quirks also:

  • There's no way to find out whether a volume is removable or not. Actually, there are APIs for that but they don't seem to yield reasonable results for any of my USB and DVD drives.
  • GIO doesn't handle repeatedly issued mount requests too well. If you try mounting a DVD volume several times in a row, you'll end up G_IO_ERROR_FAILED errors exposing private D-Bus error messages. That's nothing the user should be bothered with but unfortunately there's no way to avoid this. G_IO_ERROR_FAILED is an error type you normally want to display. I think in this case raising a G_IO_ERROR_PENDING would be more appropriate.

So what's next? I'll just pick the list from my last post because I'm lazy:

  • Move the thumbnail related code into exo.
  • Load ThunarFile objects asynchronously. This will be a pain. A lot of functions will have to be split up to fit into the asynchronous concept.
  • Migrate Thunarx to GIO.
  • Migrate thunar-volman to GIO.
  • Integrate functionality similar to Gigolo (remote/virtual places management) into the file manager.
  • Write GNOME-independent GIO extensions for volume management and the trash.

I'm not so sure I want to load ThunarFiles asynchronously. It'll only work in some situations anyway. However, the possibility of the loading process blocking the GUI is quite high, especially with remote mounts. I guess the next thing I'll work on (next week) is moving thumbnailing out of Thunar and into exo.

Oh, by the way, here are some boring stats of my work in the past four weeks:

 thunar/Makefile.am                      |   44 +-
 thunar/main.c                           |    8 +
 thunar/thunar-abstract-icon-view.c      |    4 -
 thunar/thunar-application.c             |  655 +++++++--------
 thunar/thunar-application.h             |   25 +-
 thunar/thunar-chooser-button.c          |  131 +--
 thunar/thunar-chooser-dialog.c          |  232 +++---
 thunar/thunar-chooser-model.c           |  450 +++-------
 thunar/thunar-chooser-model.h           |   23 +-
 thunar/thunar-clipboard-manager.c       |   53 +-
 thunar/thunar-clipboard-manager.h       |    3 +-
 thunar/thunar-create-dialog.c           |  155 ++--
 thunar/thunar-create-dialog.h           |   25 +-
 thunar/thunar-dbus-service.c            |   47 +-
 thunar/thunar-debug.c                   |    4 -
 thunar/thunar-deep-count-job.c          |  373 ++++++++
 thunar/thunar-deep-count-job.h          |   48 +
 thunar/thunar-details-view.c            |   20 -
 thunar/thunar-dialogs.c                 |  100 ++-
 thunar/thunar-dialogs.h                 |   42 +-
 thunar/thunar-dnd.c                     |   21 +-
 thunar/thunar-enum-types.c              |   57 ++
 thunar/thunar-enum-types.h              |   56 ++
 thunar/thunar-file.c                    | 1455 +++++++++++++++++++++++--------
 thunar/thunar-file.h                    |  309 ++-----
 thunar/thunar-folder.c                  |  192 +++--
 thunar/thunar-gio-extensions.c          |  355 ++++++++
 thunar/thunar-gio-extensions.h          |   63 ++
 thunar/thunar-gtk-extensions.c          |    4 -
 thunar/thunar-icon-factory.c            |   13 +-
 thunar/thunar-io-jobs-util.c            |  139 +++
 thunar/thunar-io-jobs-util.h            |   36 +
 thunar/thunar-io-jobs.c                 | 1074 +++++++++++++++++++++++
 thunar/thunar-io-jobs.h                 |   54 ++
 thunar/thunar-io-scan-directory.c       |  123 +++
 thunar/thunar-io-scan-directory.h       |   37 +
 thunar/thunar-job.c                     | 1001 +++++++++++++++++++++
 thunar/thunar-job.h                     |  112 +++
 thunar/thunar-launcher.c                |  521 +++++++-----
 thunar/thunar-list-model.c              |  155 ++--
 thunar/thunar-location-button.c         |   29 +-
 thunar/thunar-location-buttons.c        |   31 +-
 thunar/thunar-location-entry.c          |  151 +++-
 thunar/thunar-marshal.list              |    4 +
 thunar/thunar-metafile.c                |   42 +-
 thunar/thunar-metafile.h                |    5 +-
 thunar/thunar-path-entry.c              |   65 +-
 thunar/thunar-permissions-chooser.c     |  263 +++---
 thunar/thunar-preferences-dialog.c      |  103 +--
 thunar/thunar-preferences.c             |   71 +-
 thunar/thunar-progress-dialog.c         |  152 ++--
 thunar/thunar-progress-dialog.h         |    7 +-
 thunar/thunar-properties-dialog.c       |  108 ++--
 thunar/thunar-renamer-dialog.c          |   20 +-
 thunar/thunar-renamer-model.c           |   11 +-
 thunar/thunar-sendto-model.c            |  196 ++---
 thunar/thunar-shortcuts-icon-renderer.c |   45 +-
 thunar/thunar-shortcuts-model.c         |  433 +++++-----
 thunar/thunar-shortcuts-view.c          |  594 +++++++++----
 thunar/thunar-simple-job.c              |  223 +++++
 thunar/thunar-simple-job.h              |   64 ++
 thunar/thunar-size-label.c              |   81 +-
 thunar/thunar-standard-view.c           |  212 +++---
 thunar/thunar-templates-action.c        |    7 +-
 thunar/thunar-text-renderer.c           |   19 -
 thunar/thunar-transfer-job.c            |  888 +++++++++++++++++++
 thunar/thunar-transfer-job.h            |   60 ++
 thunar/thunar-trash-action.c            |    9 +-
 thunar/thunar-tree-model.c              |  280 ++++---
 thunar/thunar-tree-view.c               |  730 ++++++++++------
 thunar/thunar-user.c                    |  833 ++++++++++++++++++
 thunar/thunar-user.h                    |   88 ++
 thunar/thunar-util.c                    |  105 ++-
 thunar/thunar-util.h                    |   16 +-
 thunar/thunar-window.c                  |  274 +++---
 75 files changed, 10491 insertions(+), 3947 deletions(-)

The overall size of the patch is 844kb already.

Thunar/GIO – Quick Status Report

  • April 23, 2009
  • Jannis Pohlmann

I've started hacking on the migration of Thunar to GIO on April 9th. In about 61 commits, I've reduced the original number of ThunarVFS references in the Thunar source code dramatically. The most important and probably most time-consuming part of this work is only mentioned briefly on those pages: rewriting all recursive copy/move/trash/restore/chmod/chgrp/chown jobs -- by now most of the jobs have been rewritten based on GIO and the new ThunarJob framework ... and Thunar still works (for me at least)!

All in all, I suppose that about a third of the implementation work is done. Ok, maybe just a quarter, but an important one. I now have a very good overview over the source code and I'm almost done with one of the most critical parts of the migration.

If you want to know how that looks like for me, here's a screenshot:

Lunar Linux 20090423

These are the most important/big things that are still waiting for me:

  • Replace ThunarVFSVolumeManager with GFileMonitor. Volume management is a large and complex subsystem of both ThunarVFS and GIO.
  • Load ThunarFile objects asynchronously. This will be a pain. A lot of functions will have to be split up to fit into the asynchronous concept.
  • Move the thumbnail related code into exo

These two are a bit out of scope but very important nonetheless:

  • Integrate functionality similar to Gigolo (remote/virtual places management) into the file manager.
  • Write GNOME-independent GIO extensions for volume management and the trash.

On a side node: Xubuntu 9.04 is available as of today! Go and grab it if you're interested in a nice distro based on Xfce. If you're interested in the Xubuntu development, you'll be able to meet Stephan, several Xubuntu folks and me at the Ubuntu Developer Summit in Barcelona from May 25th-29th. I'm very excited already!

Xfce developers, Jannis Pohlmann

  • April 14, 2009
  • Jérôme Guelfucci

Jannis PohlmannJannis Pohlmann, one of the core Xfce developers, kindly accepted to answer my questions on his involvement in the Xfce project and his plans for Xfce 4.8. Thank you for the time you gave Jannis!

Could you please introduce yourself?

I'm Jannis, an almost 24-year-old computer science student living in Lübeck, Germany. Besides hacking on Xfce in my free time, I am 100% addicted to music. I listen to Black and Doom/Stoner/Post Metal mostly and played drums and bass in two local bands until recently. I also had a darkroom and created b/w photographs for a few years but somehow I've lost touch with that.

Anyway, summer lurks around the corner and that means a lot of sunny days with barbecues and relaxing at the beach ahead of us. Enjoying those days could also be seen as some kind of hobby ... maybe ;)

What is your role in the Xfce community?

I'm the current maintainer or co-maintainer of several core components of Xfce, like the mixer, the menu library and Thunar. I also administrate the Goodies project which is our platform for Xfce extensions and programs which are not part of the core desktop. Not to forget, I am the so-called Xubuntu Xfce4 Liaison which means that I'm the main mediator between Xubuntu and Xfce.

What did you work on for Xfce 4.6?

Way too much ;) . I wrote libxfce4menu, a library for displaying installed applications in a structured fashion, based on the freedesktop.org menu specification. I also rewrote the mixer on top of GStreamer and the application finder, based on a re-design Jasper Huijsmans (the former panel maintainer) came up with. Last but not least, I did a lot of work on the 4.6 settings dialogs, mainly xfwm4 and the keyboard stuff, and of course fixed bugs where I could.

What do you think about Xfce 4.6? Are you pleased with? What do you think could be improved?

4.6 is a great release in many ways. Several neglected components have been rewritten, improved or replaced. With xfconf and the improved session manager Xfce as a platform has definitely gained potential. We've received a lot of overwhelming feedback and press for the release.

I see 4.6 more as an intermediate release though. By introducing xfconf and libxfce4menu we've changed a lot of the underlying infrastructure. So much in fact that the release was delayed for more than six months. As a result, there is a number of very young features in 4.6 which give the release a bit of an experimental touch. A lot of things need more polishing. And, as usual, there are also a few issues for which we don't have a solution yet.

What are you going to work on for Xfce 4.8?

Keeping in mind that our goal is to have a shorter release cycle (we've had ~10 months in mind but we haven't really made any plans yet ... that's just typical for us ...), I'll mostly concentrate on Thunar and libxfce4menu. I am currently migrating Thunar to GIO which I'll hopefully finish in time for 4.8. libxfce4menu is lacking menu merging support in 4.6 and is undergoing a redesign at the moment. Last but not least, the mixer panel plugin needs some love.

What is GIO and what is the aim of porting Thunar to GIO?

GIO is a filesystem abstraction layer. It provides a high-level API to accessing directories, files and volumes. It's been part of GLib since 2.16. Thunar has something similar called ThunarVFS which is in some aspects less powerful than GIO.

Migrating Thunar to GIO has several reasons: ThunarVFS is an additional library in the stack while GIO is part of GLib already. Dropping ThunarVFS means less maintainance work for us. And, as already mentioned, GIO has features that ThunarVFS does not have.

The personal goal I have is to write a so called "Studienarbeit" about the migration. That's an around 30 pages thesis students have to write at German universities as a preparation for the real diploma thesis (which is an equivalent to the master's thesis). The process can be followed on my wiki.

What features will this bring for users?

GIO itself will not bring any new features. However, GIO can be extended easily to support virtual/remote filesystems. There is a set of extensions called GVfs which supports SFTP, HTTP, FTP, SMB and other protocols. Unfortunately it has a few GNOME dependencies, so it is up to you to decide whether you want to use it. People could as well write their own extension for whatever protocol they need - if they want to.

What will be the influence on performances?

I know that many people fear bloat. GIO is already being used by GTK+, so by dropping ThunarVFS we can probably make Thunar even lighter than it is today. As opposed to ThunarVFS, GIO has an asynchronous API which may help in making Thunar more responsive in some situations.

Do you plan to implement new features apart from the GIO related ones?

Definitely. Not too many though. Migrating Thunar to GIO is a lot of work on its own already. My plans include a shared progress dialog for file operations, a more user-friendly side pane, inspired by this post from Hylke and a user-friendly way to manage "places" (such as remote locations).

What does GDesktopmenu (previously known as libxfce4menu) provide?

libxfce4menu (or gdesktopmenu in the future) is an implementation of the freedesktop.org menu specification. It provides applications with an easy way to list all installed applications in a structured manner, like for the applications menu.

What are your plans for Xfce 4.8? Will users be able to customize their menu easily?

Yes. As mentioned earlier libxfce4menu in 4.6 lacks support for menu merging which is an essential feature required by menu editors. In 4.8 this will be fully supported.

I'm now working together with Travis Watkins from Alacarte who has expressed interest in the 4.8 API I presented on my blog a while ago. We're planning to add a nice menu editing API to the library so that it'll be *very* easy to write menu editors. It looks like Alacarte will be the first editor to use it.

Any others future plans ? Something else to add ?

Yeah. Thanks again to everyone who donated money for our Buildbot server! We're currently waiting for the missing components to arrive so that we can set it up. Samuel Verstraete, together with the Coreboot team, did a great job in getting hardware virtualization to work on the server, so we'll hopefully see Buildbot running very soon.

Edit: sorry, I found forgotten a question which I just added.

Writing Your Own GIO Jobs

  • April 7, 2009
  • Jannis Pohlmann

After having moved into a new apartment I'm now back at working on my thesis about Thunar. There are a few things which are solved very differently in GIO than in ThunarVFS. One of them is the way jobs are handled. A job basically is a task which may take a while to run and thus is executed in a separate thread (so it doesn't block the GUI).

ThunarVFS has a framework called ThunarVfsJob. It lets you create different kinds of jobs e.g. for changing file permissions recursively or for computing the total number of files and the total size of a directory. These jobs report back to the GUI thread using signals such as "new-files" (when new files are added and need to picked up by the GUI) or "progress".

GIO has something similar ... but it's not so obvious how it works. When I tried to figure out how to migrate ThunarVfsJob to GIO I thought: hey, GIO must have something like this already! It contains several job-like functions such as g_file_copy_async() after all.

So here's what I found out after spending some time on reading gfile.c and glocalfile.c: there is a job framework in GIO ... but it's hidden behind easy-to-use asynchronous functions. It's based on GCancellable, GAsyncResult and a bunch of callback types. It uses GIOScheduler internally to glue everything together to something that is actually pretty convenient (but still kinda tricky).

So, what do you need in orderto write your own jobs in the GIO style?

First of all, you need an example task. I picked counting files and computing the total size of a directory to understand how it works. What we want is an asynchronous function which does exactly that and uses a callback to report the progress back to the GUI thread ... just like g_file_copy_async() does.

First of all, you define the callback type and two functions for starting the job (sync and async version):

The Public API

typedef void (*GFileCountProgressCallback) (goffset  current_num_files,
                                            goffset  current_num_bytes,
                                            gpointer user_data);

static gboolean 
g_file_deep_count (GFile                     *file,
                   GCancellable              *cancellable,
                   GFileCountProgressCallback progress_callback,
                   gpointer                   progress_callback_data,
                   GError                   **error);

 static void
 g_file_deep_count_async (GFile                     *file,
                          int                        io_priority,
                          GCancellable              *cancellable,
                          GFileCountProgressCallback progress_callback,
                          gpointer                   progress_callback_data,
                          GAsyncReadyCallback        callback,
                          gpointer                   callback_data);

The Implementation

All the function g_file_deep_count_async() will do is to create a GSimpleAsyncResult, put the callback information into it and then tell the GIOScheduler to run the job. Here's how that looks like:

static void 
g_file_deep_count_async (GFile                     *file,
                         int                        io_priority,
                         GCancellable              *cancellable,
                         GFileCountProgressCallback progress_callback,
                         gpointer                   progress_callback_data,
                         GAsyncReadyCallback        callback,
                         gpointer                   callback_data)
{
  GSimpleAsyncResult *result;
  DeepCountAsyncData *data;

  g_return_if_fail (G_IS_FILE (file));

  data = g_new0 (DeepCountAsyncData, 1);
  data->file = g_object_ref (file);
  data->progress_cb = progress_callback;
  data->progress_cb_data = progress_callback_data;

  result = g_simple_async_result_new (G_OBJECT (file), 
                                      callback,
                                      callback_data, 
                                      g_file_deep_count_async);
  g_simple_async_result_set_op_res_gpointer (result, 
                                             data, 
                                             (GDestroyNotify) deep_count_async_data_free); 

  g_io_scheduler_push_job (deep_count_async_thread,
                           result, 
                           g_object_unref, 
                           io_priority, 
                           cancellable);
}

DeepCountAsyncData is a simple struct which needs no further explanation, I think. First data with callback and user data information is added to the GSimpleAsyncResult and then the job is added to the GIOScheduler. As you can see, there is another function involved: deep_count_async_thread. This is the function which runs in a separate thread and does most of the work (well, not quite ... but almost). Here's how it looks like:

static gboolean
deep_count_async_thread (GIOSchedulerJob *job,
                         GCancellable    *cancellable,
                         gpointer         user_data)
{
  GSimpleAsyncResult *res;
  DeepCountAsyncData *data;
  gboolean            result;
  GError             *error = NULL;

  res = user_data;
  data = g_simple_async_result_get_op_res_gpointer (res);

  data->job = job;
  result = g_file_deep_count (data->file, 
                              cancellable, 
                              data->progress_cb != NULL ? deep_count_async_progress_callback : NULL, 
                              data, 
                              &error);

  if (data->progress_cb != NULL)
    g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc) gtk_false, NULL, NULL);

  if (!result && error != NULL)
    {
      g_simple_async_result_set_from_error (res, error);
      g_error_free (error);
    }

  g_simple_async_result_complete_in_idle (res);

  return FALSE;
}

As you can see it runs the synchronous function g_file_deep_count() and makes sure the progress callback is called at least once. It does one more thing though: it defines it's own progress callback: deep_count_async_progress_callback. This is required for the real progress callback to be called inside the GUI thread. This is the code for the internal callback:

static gboolean
deep_count_async_progress_in_main (gpointer user_data)
{
  ProgressData       *progress = user_data;
  DeepCountAsyncData *data = progress->data;

  data->progress_cb (progress->current_num_files, 
                     progress->current_num_bytes, 
                     data->progress_cb_data);

  return FALSE;
}

static void
deep_count_async_progress_callback (goffset  current_num_files,
                                    goffset  current_num_bytes,
                                    gpointer user_data)
{
  DeepCountAsyncData *data = user_data;
  ProgressData       *progress;

  progress = g_new (ProgressData, 1);
  progress->data = data;
  progress->current_num_files = current_num_files;
  progress->current_num_bytes = current_num_bytes;

  g_io_scheduler_job_send_to_mainloop_async (data->job, 
                                             deep_count_async_progress_in_main, 
                                             progress, 
                                             g_free);
}

deep_count_async_progress_callback() is called from within the job thread. It then tells the scheduler to call deep_count_async_progress_in_main from the GUI thread. And finally deep_count_async_progress_in_main calls the real progress callback e.g. to update the GUI.

Now you still haven't seen any code related to counting files and computing the total file size of a directory ... let's get to that now. Here's the synchronous deep count function which is called from within the job thread:

static gboolean  
g_file_deep_count (GFile                     *file,
                   GCancellable              *cancellable,
                   GFileCountProgressCallback progress_callback,
                   gpointer                   progress_callback_data,
                   GError                   **error)
{
  ProgressData data = {
    .data = NULL,
    .current_num_files = 0,
    .current_num_bytes = 0,
  };

  g_return_val_if_fail (G_IS_FILE (file), FALSE); 

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  return g_file_real_deep_count (file, 
                                 cancellable, 
                                 progress_callback, 
                                 progress_callback_data, 
                                 &data, 
                                 error);
}

Damn ... it still doesn't do any real work! Ok, but this time there's no big rat-tail of nested function calls anymore, I promise. There's just one function left: g_file_real_deep_count(). Before we can call it, however, g_file_deep_count() has to initialize the progress data. After that we can call g_file_real_deep_count() recursively and do something useful. Here we go:

static gboolean
g_file_real_deep_count (GFile                     *file,
                        GCancellable              *cancellable,
                        GFileCountProgressCallback progress_callback,
                        gpointer                   progress_callback_data,
                        ProgressData              *progress_data,
                        GError                   **error)
{
  GFileEnumerator *enumerator;
  GFileInfo       *info;
  GFileInfo       *child_info;
  GFile           *child;
  gboolean         success = TRUE;
  
  g_return_val_if_fail (G_IS_FILE (file), FALSE);
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  info = g_file_query_info (file, 
                            "standard::*", 
                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 
                            cancellable, 
                            error);

  if (g_cancellable_is_cancelled (cancellable))
    return FALSE;

  if (info == NULL)
    return FALSE;

  progress_data->current_num_files += 1;
  progress_data->current_num_bytes += g_file_info_get_size (info);

  if (progress_callback != NULL)
    {
      /* Here we call the internal callback */
      progress_callback (progress_data->current_num_files, 
                         progress_data->current_num_bytes, 
                         progress_callback_data);
    }

  if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
    {
      enumerator = g_file_enumerate_children (file, 
                                              "standard::*", 
                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 
                                              cancellable, 
                                              error);
    
      if (!g_cancellable_is_cancelled (cancellable))
        {
          if (enumerator != NULL)
            {
              while (!g_cancellable_is_cancelled (cancellable) && success)
                {
                  child_info = g_file_enumerator_next_file (enumerator, 
                                                            cancellable, 
                                                            error);

                  if (g_cancellable_is_cancelled (cancellable))
                    break;

                  if (child_info == NULL)
                    {
                      if (*error != NULL)
                        success = FALSE;
                      break;
                    }

                  child = g_file_resolve_relative_path (file, g_file_info_get_name (child_info));
                  success = success && g_file_real_deep_count (child, 
                                                               cancellable, 
                                                               progress_callback, 
                                                               progress_callback_data, 
                                                               progress_data, 
                                                               error);
                  g_object_unref (child);
                  g_object_unref (child_info);
                }

              g_object_unref (enumerator);
            }
        }
    }

  g_object_unref (info);

  return !g_cancellable_is_cancelled (cancellable) && success;
}

And that's it. We can now compute the number of files and the total size of a directory recursively using a GCancellable and one or two callbacks. All of this is done using threads, so you don't have to worry about blocking your GUI main loop.

If you want to see this in action, visit the job framework page in my thesis wiki and download deepcount.c and the Makefile.