Thursday, April 26, 2012

Gnome shell - Part 2

I haven't really written an awful lot on this. Time demands and all of that.

There's a few things which I'm finding kind of limiting with gnome-shell. I'm guessing by the sudden popularity of this blog (I'm suddenly getting around twice as many hits than I was before) lots of people are finding the same problems.

Documentation is a little thin on the ground.

There's the ST library - a wrapper around gtk. This is one of the very few things in gnome shell with some documentation. Unfortunately I'm finding it quite restrictive. I'll get to that a little later.

There's another really cool blog which is where I'm getting most of my information from. In this post though, I'm going to go with an itch that I had. I decided to "fix" one of the extensions that I installed.

There's a bunch of extensions under a rather odd name of "Frippery". They're a series of extensions to make gnome-shell look more like a gnome 2 desktop. Personally I've ALWAYS customized my desktop to my liking. I could never see the point of 2 bars for example and so would cram everything into one bar. Much like Gnome shell does.

Anyway, the extension I'm looking at is the applications menu. Below is a screenshot (stolen from another page due to not being able to figure out how to take a screenshot while the menu is open).

What's wrong with it? Notice the Other and Programming menus? On my system I have nothing installed under those categories and yet they still show up.

To download the source, click here.

I've kind of thrown it on a site (lack of a site really) of mine so that you can download it and follow along with the alterations I'm making.

So download the source and then extract it to ~/.local/share/gnome-shell/extensions


You should now have a directory in there called:
Applications_Menu@rmy.pobox.com

So in my last gnome-shell post we learnt that extension.js contains all of the interesting bits (well okay - not ALL of the interesting bits but for today's purposes, it's the only file we're going to look at).

Truth be told, the extension feels like it's in a bit of a mess to me. There are bits taken from other files (those found in /usr/share/gnome-shell/js/ui). It's acknowledged when this has happened. The problem I have with it is that the programming styles feel ... inconsistent.


Open that file - this is where it's all going to get just a little hinky. I'm not going to provide you with line numbers or anything. Instead, it's probably better if you get to know the file.

The first thing to notice is that javascript doesn't have classes - not exactly. Instead everything is an object and the differentiation is made between single use objects and multiple use objects. Personally, I would rather define a class and use it as a template. Still, it's a preference rather than "the" correct way.

This file seems to kind of agree with me and has used prototypes - the closest thing that I've found classes in javascript. Look through the source. You'll find the ApplicationsMenuButton. Defined as:

function ApplicaitonsMenuButton() {
  this._init();
}


ApplicationsMenuButton.prototype = {
...


Look at the method names - scroll down and look for the right indentation. You'll see:
_init
_onButtonPress
_containerGetPreferredWidth
_containerGetPreferredHeight
_containerAllocate
_loadCategory
_buildSections
_buildMenu
_rebuildMenu
_showDialog
getSettings
setSettings
enable
disable


Educated guesses again - _buildSections sounds like the bit that will let us exclude categories we don't need to see.


_buildSections: function() {

   // Stolen from appDisplay.js
   var tree = this._appSystem.get_tree();
   var root = tree.get_root_directory();


   var iter = root.iter();
   var nextType;
   var i = 0;


   var sections = [];
   while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
       if (nextType == GMenu.TreeItemType.DIRECTORY) {
           var dir = iter.get_directory();
           if (dir.get_is_nodisplay())
               continue;
           var appList = [];
           this._loadCategory(dir, appList);
           sections.push({ name: dir.get_name(),
                           apps: appList });
           i++;
       }
    }


    return sections;
},

The bit that we're going to focus on is the "sections.push" bit. We're looking at a stack - you can push (put something onto) and pop (take things out of and retrieve the value) values, or in the case of javascript, objects into and out of a stack.

By this point we've got the bits of information we need. A category name and an application list (stored in appList). So to avoid showing the categories we don't want, we just have to change that piece of code to:

if (appList.length > 0){
    sections.push({ name: dir.get_name(),
                    apps: appList });
}

Reload gnome-shell (hit alt-F2 and type in 'r' followed by enter) and the applications menu will now not show those categories without applications associated to them.

The next bit I noticed was that my System menu isn't in alphabetical order. What a hassle... So we need to sort the appList before putting it into "sections". This is fairly trivial (though it took me about an hour to figure it out given that I'm new to javascript). That code above changes to:

if (appList.length > 0) {
    appList.sort( function(a,b) {return a.get_name()>b.get_name()} );
    sections.push({ name: dir.get_name(),
                    apps: appList });
}

I'm not done with this extension yet. I've been having a play with icons to see whether I'm able to get icons showing against the categories... Anyone know why this doesn't work?

No comments:

Post a Comment