Desktops, etc.
Man, it's been awhile since I blogged. I meant to keep putting up a monthly Xfce desktop, share some tips, talk about the latest Gentoo work, etc. And then real life got in the way.
Laptop
I killed yet another piece of hardware when updating my Thinkpad R61i on Friday. I've been sick this whole week, so I had some free time. The laptop hadn't been updated since early February, so there were 176 packages, including the big move to GCC 4.3, which necessitated a system rebuild. Unfortunately, I left the battery in while the system was on AC power for the compiling work. I guess the heat must have built up too much, because the battery got fried. Got the dreaded "battery light flashes amber rapidly" error. So now I only have the extended-life battery, which is heavier and bulkier.
Add that to the list of hardware that compiling Gentoo has killed over the years. The list includes another battery, an external power brick, an internal PSU, two motherboards, two RAM sticks, one RAM slot, two hard drives, and a fan. I'm really on a roll, here.
I still can't find a replacement battery for less than $90, even on eBay, so I may hold off. What I did do was order two more gigs of RAM, to bring the total up to 4GB. Only cost $40 at Amazon, free shipping. Why the RAM? While updating, I ran into the dreaded OOM-killer! The GCC 4.3 compile uses more than the 2GB available and it aborted the merge. This was with nothing else running, too. So be warned: if GCC dies when you move to 4.3, back off on your MAKEOPTS. I had to adjust mine from -j3
to -j2
while compiling GCC and glibc.
Also, while I was updating my whole system, I decided to move the rest of my X/kernel stack to ~arch, as I wanted the new Intel KMS/GEM/UXA hotness. This necessitated using ~arch xf86-video-intel and Mesa, as well as ~arch gentoo-sources, as 2.6.29 has some needed code not present in 2.6.28. I discovered that while this part of the graphical stack was just fine for KMS and fast graphical login, xorg-server-1.5.3 resulted in hard lockups as soon as I opened any windows. I had to grab xorg-server-1.6, libXfont, and randrproto from the X11 overlay in order to get a usable environment. It works great! No more lockups.
So, how much of an improvement is the new stack over what was available in February? I'll let the following numbers speak for themselves. These are the median-high numbers recorded. For the old stack, the numbers varied from 48FPS to 59FPS. For the new stack, from 489FPS to 504FPS. Sync to vblank and vsync have never been enabled.
xorg-server-1.5.3-r1, libdrm-2.4.4, xf86-video-intel-2.6.1, mesa-7.3, gentoo-sources-2.6.27-r8
$ glxgears Failed to initialize GEM. Falling back to classic. 292 frames in 5.0 seconds = 58.272 FPS
xorg-server-1.6, libdrm-2.4.6, xf86-video-intel-2.6.3-r1, mesa-7.4, gentoo-sources-2.6.29-r1
$ glxgears 2516 frames in 5.0 seconds = 503.174 FPS
Now, the usual caveat about glxgears not being a good benchmarking tool applies here. However, it is useful for relative comparison from one version to the next. And as you can see, it's an order of magnitude better. I notice that stuff is drawn much smoother; there's less flickering especially when shifting Terminal windows around. And I haven't hardly begun to tweak my system for best UXA performance. KMS is nice and smooth; it happens pretty quick in the boot process. No more flickering, just fast loading of SLiM and then Xfce.
My xorg.conf is pretty minimal; the only changes I've specified for the Intel driver section are these:
Option "FramebufferCompression" "false" Option "AccelMethod" "UXA" Option "Tiling" "false" Option "EnablePageFlip" "true"
There are probably some other things I should add for maximum performance, so I'll have to spend several more days hunting for 'em. But out-of-the-box, I'm extremely impressed with the current X stack.
Now all I need is smooth full-screen Flash video performance . . .
Xfce 4.6
The other thing I put on the laptop was Xfce 4.6.1. Decided that as long as my core graphics stack is part ~arch, it wouldn't hurt to try out the latest and greatest Xfce hotness. Now that some outstanding bugs were fixed from 4.6.0 (including a remote security bug, and an icons issue), I thought it'd be worth it. It's pretty slick. The desktop environment is initialized a bit faster than even a fully tweaked 4.4.3.
About the only outstanding issue I have with it is that there is no graphical menu editor. At first, I couldn't get a satisfactory menu even editing the XML file by hand; it was just too different from the old one. So my menu was cluttered with useless toplevel entries, such as Web Browser, File Manager, and so on. Fortunately, Mike pointed me to the solution, so now all offending stuff has been cleared out. Right now my menu works just fine, so I only really need a graphical menu editor for convenience's sake.
I really like 4.6 a lot. The artwork packaged with it is outstanding; I'm using one of the stock backgrounds because it's just that sexy.
Xfce 4.6 is a smash hit, so well done, guys. Very well done. And there's even more good stuff planned for the future. There's a great interview on Planet Xfce with one of the core developers. He discusses some of the exciting stuff coming down the pipe for Thunar, so make sure to read it.
Gentoo
I've been rather quiet on the Gentoo front for the last three months, because life in the outside world has a way of unexpectedly intruding on me. I've been on devaway since February while I try to get stuff into some semblance of order. Sadly, however, I've had to do much more documentation work than I originally scheduled, which keeps cutting into my plans for other areas. I've made a bunch of bugfixes and commits over the last couple of weeks especially. One of the most visible changes is in the Get Gentoo page, putting the automated weekly builds at the top. The handbooks will be updated, too, but they require a tremendous overhaul, so I'll need all the resources of my fellow GDP members to accomplish that. If I can get 'em, that is.
One of the other things I like to do is find some interesting little-known application, determine its usefulness, then hack up an ebuild for it. It's really good practice, actually.
Out of all the applications I've written and updated ebuilds for, the only one that's got me stumped is WordGrinder. I've been in contact with WordGrinder's upstream author, who's a really helpful guy, but I still can't get the ebuild working. While compiling and installing by hand works great, something happens during the compile phase as run by Portage where it violates the sandbox, killing the merge.
Plus, given the pmfile used by the package, it doesn't really respect a user's CFLAGS/CHOST and related configuration. That has to be altered somehow, so I've been trying to work out a similar solution to the one used by our dev-lang/lua
ebuilds. No real luck there, but it's not my first priority. What I really want to do is have the merge workin' with Portage. So it's an interesting, informative, occasionally frustrating learning process.
Anyway, take a look at all the stuff in there. I recently reorganized the ebuilds by category/package, instead of dumping everything into a single directory. Some of these have since moved into Portage sometime after I wrote the ebuild for 'em, and some (like Songbird and WordGrinder) are works in progress. I've run into quite a few nifty apps; places like GnomeFiles are excellent resources. Most of the stuff in here I discovered on GnomeFiles, and a lot of the packages on the website are simple enough that it's just a few minutes' work to hack up an ebuild.
Thunar/GIO – Quick Status Report
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:
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 Clipman Plugin 1.0.0
This post is about the latest release of Xfce Clipman Plugin, a Clipboard Manager for the Xfce desktop. I turn it more technical than for end-users. I hope people interested into GTK+, GObjects or Xfce panel plugins will like to read it. The release is going to happen very soon now.The first major change concerns the plugin being entirely rewritten by using GObjects and Xfconf, this means cleaner, better understandable, maintainable code, etc. There is the "main function" (for sack of clarity) and four objects. A collector which listens to clipboard changes and put them in the history, the history is also an object, a menu (on top of GtkMenu) that displays the history and allows to clear it, and finally another object which is part of a new feature for the clipboard manager.
Now having my objects it's just about instantiating them in the main function and binding them to Xfconf. If there is something missing in an object it is just about modifying a particular aspect of it.
The goal of using Xfconf is to have a less cluttered code for settings, and to make good use of property bindings against the objects. For instance, the object History has a maximum count of items, and being bind against Xfconf, it is possible to run an external command with xfconf-query to change that setting, without having to call a public setter function. Binding a property is a one function call.
Following this major change is the settings dialog. I have written it from scratch with Glade, a UI designer for GTK+, by which I can easily modify and beautify the dialog without having to fight with lines of code several hours a day. In fact it takes a few seconds to change a label and up to 5 minutes to design a goddamn dialog. Glade makes an increased use of memory however, but stop thinking of this when you know you have 1MB times 1000 installed on your system — I have currently 1GB on a netbook and 2GB on a quite-fanless Atom-based workstation but I use only around 300MB in general. If you still fear about having an application that uses only 2 but 5MB with Glade, well I can't help you! From what I have read, the built-in UI designer of GTK+, named GtkBuilder, needs less memory, but the Glade to GtkBuilder conversions are going to happen with Xfce 4.8.
Now about the new feature introduced into this major release. It is called "Actions" which is the fourth object by the way. An action is a match between a text selection and regexes to let you execute specific commands. For example the action "Image" can match text with image filenames and let you choose commands between "View with Ristretto" and "Edit with Gimp". I wrote something simple in the settings dialog to add new actions that is inspired from the Thunar User Custom Actions interface.
Finally, I made other changes that are more geeky than useful, like I made a bundle out of the plugin. The plugin is now installed under the binary directory instead of the common place holder for panel plugins but can still be added inside a panel with the "Add Item" menu action. As you might understand, it can be executed as well now, and if you do so it will run inside the notification area. An item is installed in the applications menu to be able to start it (under the category Utility), and as it is possible to run outside the panel, I added a autostart file.
That's it already. If you have questions, don't mind. If you wanna discuss the Actions/regex feature go ahead. More importantly, I hope you'll take a glimpse at the code.
If you are interested into panel plugins, have a look at the wiki. The panel plugins amongst the goodies are a good way to get to know code and start with something.
Update: ANN: xfce4-clipman-plugin version 1.0.0 released
Xfce developers, Jannis Pohlmann
Jannis 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.
Xfce 4.6.1 to be released soon
Stephan Arts started to tag Xfce 4.6, this bug fix release should be available in the next few days.
This release fixes a lot of bugs introduced in Xfce 4.6 and also comes with updated/improved translations.
Writing Your Own GIO Jobs
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.
The prettiest of the *buntu’s is coming
Ubuntu’s brownish/orangy theme has been the target of much criticism. What is often forgotten is that one of its derivatives has been looking very good for quite a while now: Xubuntu. A complete visual overhaul for the upcoming version 9.04 is all set to continue this trend.
Pasi Lallinaho, picking up the baton from Jozsef Mak, leverages Xfce’s extensive theming capabilities to provide a coherent look and feel with wonderful new themes.
Update: This article previously contained a paragraph about a new GTK theme, but unfortunately, that didn’t make it in in time, meaning the visual overhaul is now “just” a new wallpaper, login window theme and icon theme, so scrap the part about extensive theming capabilities
The theme for the login screen pictures a misty forest set next to a lake, in Xubuntu’s characteristic colour scheme.
Then there is the gorgeous new wallpaper, bearing a watermark of the Xubuntu logo on a canvas of the same defining shades of blue.
To complement it all, the GNOME-Colors icon theme is included. GNOME-Colors is a very complete theme, including a wide range of good-looking icons that very well match the rest of Xubuntu’s artwork.
Of course, a release this pretty deserves some buzz – if not for the great looks, then at least for the host of new features, such as the new version of Xfce – and you can help! If you own a website or blog, you can include a countdown banner with the following HTML code:
<a href="http://xubuntu.org/" title="Learn more about Xubuntu..."><img src="http://xubuntu.org/xubuntu-static/jaunty-countdown/" alt="Countdown to Xubuntu (xubuntu.org) 9.04, by Pasi Lallinaho"></a>
Alternatively, if you are a member of a forum or other online community, you can include it in your signature, forum posts or other places you’d like to promote Xubuntu, with the following BBCode:
[url=http://xubuntu.org/][img]http://xubuntu.org/xubuntu-static/jaunty-countdown/[/img][/url]
Of course, the countdown banner, too, was created by Pasi in the style of the new Xubuntu desktop.