(not so) Final news
It has been a long time since my last post, but I've been a bit busy working some rough corners with the menu generation stuff.
Since my last report, many things have moved on, let's summarize them:
- I committed the initial Desktop plugin which resembles the standard planar desktop experience. While actually it's a bit limited, it does the job for now including vertical scrolling capabilities and supports multiple tabs. It supports three file categories in the desktop ( namely: ".desktop" files, directories and regular files (detected through their MIME type)). After getting rid of the infamous 666 (i'll tell you about it later), another problem was resolved. Now external jars can be included in the classpath for a SceneManagerPlugin before it's loaded, so I can access another tools that already live in the lg3d-incubator, which allows, for example, to open a directory using some of the available 3D file managers. This let my desktop thing to open directories that reside within it inside a well suited app.
- I worked for a long period in menu generation, mainly because my lack of solid xml knowledge, but also for some complex algorithms that finally resulted much easier. One of this refer to the way to process rulesets in an xml tree. As usually happens with trees, most algorithms are better expressed as recursive systems, but they also require a deep understand of the problem as a whole and as a part, so I needed a quite long period to get to it while finally the solution was quite simple and of course elegant (I will dedicate an article on it soon). Another interesting point with the parsing of the xml applications file is the concept of Merging, which wasn't a hard task, but also took more than I expected just because I'm so lazy that I needed like 4 days to realize that I was passing the wrong Node to a given method (I must say in my defense that there are many Nodes in the menu tree ;).
- Well, even with that hard corners, I was able to parse the full file, merge it with the other necesary files and generate the needed events, but I found a total showstopper when the StartMenu code almost completly ignored the events I was sending to it. This is still a problem (see Issue 678) and after a lot of unproductive debugging I decided to freeze the menu stuff and move to another things...
- ...In my last TODO list, there was a dark element (reflected in Issue 666) which refered to classpath problems when trying to load a SceneManagerPlugin from a jar file located in the ext/app directory. I left this concrete issue down in the tasks stack because I focused in the menu stuff, but after my another lock-up, it looked like a good moment to look at this again, which was a nice idea, because as soon as I started looking at the SceneManagerPluginConfig (the class responsible from creating a SceneManagePlugin from an xml object) I saw clear that it was only needed to add a property to add new elements to the classpath, before the SceneManagerPlugin is loaded. I needed a way to modify the classpath during runtime, a simple search gave me the answer, a cool hack that hijacks the accessor protection to call a protected method in java.net.URLClassLoader from my own package, isn't it cool?. After some cleanup, my patch has been included in the lg3d-core, which makes for my very first direct code contribution to the core ;) (Given that now I have very clear how to integrate a SceneManagerPlugin or a normal Frame3D in the incubator i'm planning to write an article on this topic for the The looking glass developer's blog, stay tuned there).
These are the things I've worked on for the last weeks, it has been a bit stressing to get locked in what later was revealed as dumb
issues, but anyway finally things seems to go working (apart from the StartMenu issue). Now i'll focus on creating a more elaborated desktop system, because I don't like the planar one (it's too classical). Of course there is a lot of bug haunting out there, and i've to study too.
PS: You may have noticed that the title of this post includes the "not so" prefix, this is because i'm not over yet with this stuff, it needs (a lot) more work, and I want to do it. Thanks for reading up to this small place !!
SoC biweek report #1
Things I've done
This interface defines methods to obtain some parameters that are common to all the possible file types the system must handle (.desktop files, directories and MIME based files). This interface defines methods to get the name of the entry, a name for the icon of the file and an actionPerformed method. More info on the three possible types follow (all this classes implement the DesktopEntry interface):
- .desktop file support (FileDesktopEntry)
- I've created a class that can load a .desktop file, identifying the possible categories it can hold and storing all the keys stored in the file within the corresponding category.As some keys in the file can be interniotalized using "[locale]" suffixes, so the methods that retrieve values for keys in a desktop file can also receive a Locale parameter. This way, the getName method from DesktopEntry returns a localized name for the file and getIcon obtains it's info from within the .desktop file, as actionPerformed does.
- directory support (DirectoryDesktopEntry)
- For directories we don't have to care about localization, just return directory name on getName and "directory" for the icon name. I tried to invoke fm3d to open the folder from the actionPerformed method but it didn't work (I have it in my TODO list)
- MIME support (MimeDesktopEntry)
- This one has been challenging as there doesn't seem to be a reliable way to obtain mime types in Java. I searched all over the net and all I found or was incomplete and buggy (dieyng with some file types) or just didn't identify most file types. So, i've been forced to go down freedesktop MIME database specification and do my own implementation that for now works quite well (but still resides in my TODO list). The disadvantage is that it needs to access some files that are only present on linux, enoguh for now, but i'll have to work on this issue at least for Solaris sometime (another TODO). Also the name isn't localized for this files, just file name, and the icon name is set to the mime type.
Icon theme support
All that DesktopEntryInterface files return a name for the icon that doesn't contain any path (except forr the FileDesktopEntry that can eventually return an absolute path) in it, and no file extension. There is another specification that defines how to locate icons in the system. Based on this specs i've also created an IconTheme class and an IconFinder one, with the later using the former to find an icon for a requested name and size. The IconFinder provides methods to find the icon for a name or for a mime type.
Once we can create a DesktopEntry for any file and obtain an URL for the icon of that file, we can create a Container3D derived class that just needs a Pseudo3DIcon to have 3d icon and a DesktopIconLabel to show the name (TODO: Make icon label readable in all contexts). I also add some event listeners to highlight the label on mouse hover and to execute the DesktopEntry#actionPerformed() method on double click.
The objective of this stage in my SoC2006 experience is to build a "pluggable" SceneManagerPlugin (SMP) to handle the user ~/Desktop folder (and other ones at user pleasure) and keep it at hand. With this objective I created DesktopPlugin, an SMP that handles classes implementing another interface called DesktopPluginInterface (DPI). This DPI defines methods to populate the desktop, fit it to screen and obtain the plugin root (Maybe I should make DPI extend SMP and add those methods to it, this way the desktop plugin can be selected directly from the lgcfg file... or add a new property like "lg3d.desktop.pluginclass"...or...).
This LayoutManager3D is supposed to lay the components it receives in a number of rows and columns with a given spacing, and also allow them to be moved within a limited region (never out of rows or columns). Well, it does that things, but is incomplete and doesn't support more elements than nrows*ncols (really it neither constrain the movement to a limited space).(BIG_TODO: Substitute this layout manager by InfinityScrollableLayout:+info, down in the TODO section)
This is the first desktop plugin i've created. The idea is simple, put the folders selected by the user in a classical tabbed panel. This panel is scaled down and moved to the corner of the screen to avoid disturbing user workflow, and when the user moves the moves over it, it grows to 90% of screen size (TODO: and should move opened apps back) so user can select any icon on it (TODO:after an actionPerformed on some icon, the panel should shrink to the corner again). In this plugin there are three main components (Container3D):
- panelComp: This container holds the common backpanel for all the tabs. Tha backpanel is wrapped by a detachable BranchGroup so I can substitute it on fitScreen.
- iconsContainer: For each tab to show one Container3D is added to iconsContainer after filling it with DesktopIcon(s). Each of them uses the MatrixReorderableLayout (to be substituted).
- shortcutsContainer: Using the HorizontalReorderableLayout, this Container3D is filled with TabShortcut objects (one for each tab) which are linked to the corresponding tab in the iconsContainer through a Hashtable. That TabShortcut class has a method to highllight it, and has a listener on MouseClickedEvent so it can notify the TabbedDesktopPlugin that it has gained the focus so it can highlight the correct one and show only the icons of it (whose container is taken from the named hashtable).
TODO next 2weeks
- code cleanup
- invoke some file manager on directory actionPerformed
- after an actionPerformed on some icon, the panel should shrink to the corner again
- refine MIME detection
- refine icon search
- Make icon label readable in all contexts
- Substitute MatrixReorderableLayout by InfinityScrollableLayout (this new layout will receive rowspacing, colspacing, heightlimit and widthlimit and will hide elements outside the limits. When this happens (icons out of limits) it should add scrolling buttons to let the user see icons outside).
- code cleanup (wops, it seems I must do a lot of code cleanup)
(This doesn't include work I haven't started yet)
- boost performance on load
- resolve issue with classpath when moved on incubator (+info)
- work on Solaris MIME detection
- When TabbedDesktopPlugin is scaled up it should move pre-opened applications back in the Z axis to avoid intersections, just like normal Frame3D apps do.(possible?)
I'm probably forgeting something but I must stop digressing now ;)
One video to play
I just created one little
flash video using wink
to show what i've done till now, still needs refinements, text is ugly but it's somehow nice (it's 14MB, expect some slowness)(Wink died if I disabled the overlayed cursor, so it's there ;)
Any feedback/ideas are more than welcome
First screenshot ever
I've been working today to get something visual to post in this blog, and something has come up.
Looks nice, doesn't it?
The code is insane and text alignment is not correct, but you can see some localization going on in the Kdevelop icon.
As you can see folders are also recognized and i'm working to integrate a mime recognizer to put icons for the files that are neither ".desktop" nor directories.
The layout is static for now, so I must work a way to make it reorderable. One possibilty would be to use a quite usual desktop approach:
- Let user freely move icons on desktop, limiting him to not take icons out-of-screen.
- Allow user to set icons to stay where they are left or to snap to grid.
More to come...
Basic directories in specs
There is another specification in freedesktop that indicates where are located the files, that are refered in other specifications, in the user disk. The following table shows the possible environment variables that are refered in other specs, the value to be used for each of them if they are not present, or empty, and a short description of their meaning:
|Environment Variable||Default value||Meaning|
|$XDG_DATA_HOME||$HOME/.local/share||base directory relative to which user specific data files should be stored|
|$XDG_DATA_DIRS||/usr/local/share/:/usr/share/||preference-ordered set of base directories to search for data files in addition to the $XDG_DATA_HOME base directory|
|$XDG_CONFIG_HOME||$HOME/.config||base directory relative to which user specific configuration files should be stored|
|$XDG_CONFIG_DIRS||/etc/xdg||base directory relative to which user specific configuration files should be stored|
|$XDG_CACHE_HOME||$HOME/.cache||base directory relative to which user specific non-essential data files should be stored|
Anyway they won't be necessary until we begin with the menu stuff.
.desktop files internationalization
In my last post I spoke about the basic format of .desktop files. If you remember, this files where composed of two elements, one the category header and the other key/value pairs that holded multiple information about the associated Desktop Entry.
Specification includes means to localize certain keys in the file so it may contain information to be shown to the user (i.e. name, description,...) that must be localized, this are the keys wich value type is declared as localestring.
The approach is easy, we have one "primary" key that holds the default localized value (normally in english) and then add more keys with the same name suffixed with the corresponding POSIX locale in brackets. For example we should have the key
with the keys
Name[ca]=Editor del menú
following it. If the current locale is not found in the file, the default key must be used.
The way this entries are encoded (ISO-8859-1, UTF-8,...) comes defined in the .desktop file using the Encoding required key. This key can take two possible values : UTF-8 of Legacy-Mixed. While the later is deprecated, it's still possible to find it (I think) in some systems, so let's see how it works.
When the Legacy-Mixed mode is active for a file, localized keys are encoded using old style encoding (ie not UTF-8). In this files the POSIX Locale that's used to identify each localized key is used to determine the encoding. Following table shows what encodings correspond to each Locale :
||br ca da de en es eu fi fr gl it nl no pt sv wa|
||cs hr hu pl ro sk sl sq sr|
||lt lv mi|
( Table directly copied from the standard )
Encodings that are marked with an asterisk are very rare and are not supported by the GNU C library, so maybe they are neither supported by Java. Anyway, as they are so rare and the legacy mode is to be extincted it doesn't look like a problem to really care about.
Basic .desktop file format
The .desktop files are the basic entities that are used to build the desktop and the menu in freedesktop.org specification. These are plain text files with "group" headers of the form [GROUP_NAME], where delimiters [ and ] obviusly cannot be contained within GROUP_NAME, and pairs of keys and values with different meanings and restrictions that we'll see in another posts. All the pairs found right after a group header belongs to this group, so pairs are categorized in each desktop entry. Every valid .desktop file must start with the same group, namely [Desktop Entry].
The specification includes also classical bash-style comments (lines starting with #) that are to be ignored by implementations. Specs also indicate that implementations must ignore and preserve items they can't handle, wich gives us the posibility of adding some homegrown properties for the files (Z-Depth, DefaultIconAnimation...), we'll see later on.
Each key/value, so called entry, in the file should have the format:
With spaces trimmed from the beginning and the end of the Key and the Value, and using = as delimiter (can't be used inside a key/value). There are some escape sequences supported in the entries: \s (space), \n (newline), \t (tabulator), \r (carriage return) and \\ (backslash). Some keys can have multiple values that should be separated by a semicolon, and ended by one ; also. To put a semicolon in a single value it has to be escaped \; .
Value types are constrained to : string, localestring, regexp, boolean (true/false) and numeric values, from which the strings are ASCII characters and localestring are UTF-8 encoded values (except if something called Legacy-Mixed Encoding is enabled, but we'll talk about it in another post).
Well, I have finally been accepted for the Google
's Summer of Code
2006 to create an implementation of the freedesktop standards for menu&desktop regeneration into the Project Looking Glass
(You can take a look at my proposal here
First I would like to thank all guys at LG3D that considered me good enough to work with them once again (I also participated in last year's SoC), so Hideya, Deron, Paul, Krishna, Radek and whoever participated in ranking:
This goes also to Google itself and to all people there that are so patient with hot-young-hormones
(namely,at least, Chris DiBona, Greg Stein and Leslie Hawthorn)
PS: Expect some updates soon in this blog