Part 2 of finding documentation for developing gnome shell extensions; Part 1 is here.
You can't always find documentation online. For example, Meta (imports.gi.Meta
) doesn't have documentation online.
Or perhaps you just want more details on the specific GNOME Javascript implementation of the C functions. Or there's a function listed on the page that you can't seem to find on the GNOME Javascript side.
Then, I recommend you look at the corresponding .gir
file for your library, for example Meta-3.0.gir
.
A gir
file defines the binding between the C functions and the Javascript functions. They're used to define bindings between languages.
If you look inside a gir
file, you'll see it just looks like an XML file.
In this post I'll cover a few things:
- Getting information from the raw
gir
file - Where to find
gir
files, and convertingtypelib
togir
- Compiling the
gir
file into HTML documentation. - Summary
Getting information from the gir
file
Looking for signals in a gir
file
To quickly look for signals in a gir
file, you can just grep
for glib:signal
like so:
grep 'glib:signal' Meta-3.0.gir
# will give me a list of signals in the Meta library.
# ... (lots of signals)
<glib:signal name="workspace-changed" when="last">
</glib:signal>
# ... (lots more signals)
In the example above I wanted to see what signals the Meta
library provided and in particular was after the workspace-changed
signal.
You can then go into the gir file and see that the workspace-changed
signal belongs to the Meta.Screen
class, so if I want to monitor workspace changes I have to do:
global.screen.connect('workspace-changed', myFunction);
(This is an example of a useful signal that is not used anywhere in the gnome-shell javascript files, so I wouldn't have known about it otherwise). Note - many of the global.*
objects (global.screen
, global.display
, ...) are Meta objects.
Methods not available on the javascript side
Often you'll find that a function that is documented and available on the C side, but you can't seem to find it on the javascript side.
For example, suppose I want to get the current Metacity theme. I see that there's a function meta_theme_get_current
that will do what I want, but when I try Meta.Theme.get_current()
, I found out that .get_current()
is not a function!
Looking in the gir
file:
<record name="Theme" c:type="MetaTheme" disguised="1">
.... (more functions in between) ...
<function name="get_current"
c:identifier="meta_theme_get_current"
introspectable="0">
<return-value>
<type name="Theme" c:type="MetaTheme*"/>
</return-value>
</function>
See the introspectable="0"
? that means you can't get it from the javascript side. Too bad (time to pester the mailing list/find another way around it).
Where to find gir
files/Converting typelib
files to gir
Great, so we now know about looking into gir
files for more information. But where do we find these gir
files?
Most of them live in /usr/share/gir-1.0
. Often they will not appear there until you install the relevant dev or gir package (for example if you want Wnck-[version].gir
on Ubuntu you need to install the gir[girversion]-wnck-[version]
package (e.g. gir1.0-wnck-1.0
), of the libwnck-devel
package on Fedora).
Chances are you don't have many gir files in /usr/share/gir-1.0
. Don't despair!
A gir
file is really a human-readable version of a typelib
file (a bit like what gschema.xml
is to gschema.compiled
).
Have a look in /usr/lib/girepository-1.0
. You will see a huge number of .typelib
files. (Maybe /usr/lib
64/girepository-1.0
for 64bit machines).
Everything in here can be imported in GJS through imports.gi.[name]
.
Some of them are not there (e.g. Meta, Shell, St) because they are considered "private". This means if you run gjs
on the command line, you will not be able to find them. However, you can find their typelib files here:
/usr/lib/gnome-shell
(Shell, St)/usr/lib/mutter
(Meta)
So, how do we convert typelib
files to human-readable gir
files?
Use the g-ir-*
tools. These are a collection of tools for generating gir
or typelib
files from source and converting between the two.
We will be using g-ir-generate
.
If you do not have these tools installed already (I think from GNOME 3.4+ on they come packaged with gnome-shell), you can install them in the gobject-introspection
package (Ubuntu), or on Fedora 16 they were in gobject-introspection-devel
. Or you could just get the source from github.
To create a gir
from a typelib (for example Meta):
g-ir-generate /usr/lib/mutter/Meta-3.0.typelib > Meta-3.0.gir
And voila! A gir
file for Meta!
Sometimes g-ir-generate
will complain about not being able to find various other typelibs, for example if you try to generate Shell-0.1.gir
from the typelib:
[mathematicalcoffee ~]$ g-ir-generate /usr/lib/gnome-shell/Shell-0.1.typelib
** (g-ir-generate:9599): ERROR **: failed to load typelib: Typelib file for namespace 'St', version '1.0' not found
Trace/breakpoint trap (core dumped)
In this case it's trying to find St-1.0.typelib
, which is one of those "private" ones in /usr/lib/gnome-shell
, so you can include it using the --includedir
argument (it also needs to find Meta-3.0.typelib
in /usr/lib/mutter
; I think by default just /usr/lib/girepository-1.0
is included):
[mathematicalcoffee ~]$ g-ir-generate --includedir=/usr/lib/gnome-shell \
--includedir=/usr/lib/mutter /usr/lib/gnome-shell/Shell-0.1.typelib > Shell-0.1.gir
And that works.
Generating HTML documentation from gir
files
It's easier to use some form of documentation than wading through the gir
files all the time.
Here is how to generate HTML documentation from the gir
files (you use g-ir-doc-tool
):
mkdir mutter-docs
g-ir-doc-tool Meta-3.0.gir -o mutter-docs
Then turn the output (yelp files) into HTML (or you could just use the yelp files if you prefer):
yelp-build html mutter-docs
Then load index.html in a browser and you have some basic browsable documentation, complete with a list of signals (so if you click on the Meta.Screen page it has a list of signals you can connect to, although it is a bit sparse on explanation).
Notes:
- If you can find the documentation online, use that instead. The generated documentation is often quite sparse/no explanations.
- Sometimes
g-ir-doc-tool
complains about repository versions being unsupported. You can go into thegir
file and modify the line<repository version="1.0"
to<repository version="1.2"
and it will then generate the documentation (not sure if anything is affected by that) - Sometimes
g-ir-doc-tool
complains about not being able to find thegir
files of other libraries it depends on. You have to generate them and make sure they're in/usr/share/gir-1.0
(it doesn't seem to support an--includedir
argument likeg-ir-generate
does).
Summary
When looking for documentation:
- First look on developer.gnome.org
Otherwise generate some documentation from the
gir
file (/usr/share/gir-1.0
,/usr/lib/mutter
,/usr/lib/gnome-shell
):g-ir-doc-tool /path/to/gir -o /path/to/output/directory yelp-build html /path/to/output/directory
If you can't find the
gir
file, find thetypelib
file and convert it togir
first (/usr/lib/girepository-1.0
):g-ir-generate /path/to/typelib > /path/to/output/filename # use --includedir=/path/to/typelib/folder if need be
Hope that helps! Feedback welcome.
I did :
ReplyDeleteg-ir-generate /usr/lib64/gnome-shell/St-1.0.typelib and generated a gir file .
How to use this file for imports now.
The St import was priavte and hence gave error while running the HelloWorld.extension.js in Gnome
Can you please tell to use the generated gir file for St import
I'm not sure I understand what you want. Do you mean you are trying to do
ReplyDeleteconst St = imports.gi.St;
and it is not finding the library to import?
St is a private library as you mention, and so the above will only work from a gnome-shell extension and not from any other process (even the prefs widget won't be able to find it).
If you are running `gjs` on a javascript file manually you can tell it to include /usr/lib64/gnome-shell so that it will find the file, like
gjs -I /usr/lib64/gnome-shell myFile.js
Why don't you send me an email with some more details as to what you are trying to do.
What id can i mail you ?
DeleteActually i have made a fedora 17 VM on my RHEL machine and trying to create a HelloWorld (to start with )extension on Gnome shell .
This is what i did :
gnome-shell-extension-tool -c
Name should be a very short (ideally descriptive) string.
Examples are: "Click To Focus", "Adblock", "Shell Window Shrinker".
Name: "Hello World"
Description is a single-sentence explanation of what your extension does.
Examples are: "Make windows visible on click", "Block advertisement popups"
"Animate windows shrinking on minimize"
Description: Hello world Description
Uuid is a globally-unique identifier for your extension.
This should be in the format of an email address (foo.bar@extensions.example.com), but
need not be an actual email address, though it's a good idea to base the uuid on your
email address. For example, if your email address is janedoe@example.com, you might
use an extension title clicktofocus@janedoe.example.com.
Uuid [_Gnome_Program_@localhost.localdomain]: HelloWorld@localhost.localdomain
Created extension in '/home/shveta/.local/share/gnome-shell/extensions/Gnome_Program_@localhost.localdomain'
[shveta@localhost ~]$ cd .local/share/gnome-shell/extensions/
[shveta@localhost extensions]$ gjs -I /usr/lib64/gnome-shell/St-1.0.typelib -c HelloWrold@localhost.localdomain/extension.js
JS ERROR: !!! Exception was: SyntaxError: missing ; before statement
JS ERROR: !!! lineNumber = '1'
JS ERROR: !!! fileName = '""'
JS ERROR: !!! stack = '""'
JS ERROR: !!! message = '"missing ; before statement"'
SyntaxError: missing ; before statement
Initially i was getting St unable to import but now i included it (the way you suggested) in the command . Now i am getting this synatx error.
The extension.js file looks like :
[shveta@localhost extensions]$ cat HelloWorld@localhost.localdomain/extension.js
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
let text, button;
function _hideHello() {
Main.uiGroup.remove_actor(text);
text = null;
}
function _showHello() {
if (!text) {
text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
Main.uiGroup.add_actor(text);
}
text.opacity = 255;
let monitor = Main.layoutManager.primaryMonitor;
text.set_position(Math.floor(monitor.width / 2 - text.width / 2),
Math.floor(monitor.height / 2 - text.height / 2));
Tweener.addTween(text,
{ opacity: 0,
time: 2,
transition: 'easeOutQuad',
onComplete: _hideHello });
}
function init() {
button = new St.Bin({ style_class: 'panel-button',
reactive: true,
can_focus: true,
x_fill: true,
y_fill: false,
track_hover: true });
let icon = new St.Icon({ icon_name: 'system-run',
icon_type: St.IconType.SYMBOLIC,
style_class: 'system-status-icon' });
button.set_child(icon);
button.connect('button-press-event', _showHello);
}
function enable() {
Main.panel._rightBox.insert_child_at_index(button, 0);
}
function disable() {
Main.panel._rightBox.remove_child(button);
}
Since its a VM i am not able to run the extension using ALT+F2
Please let me know if you can help.
Thanks
Email me at mathematical.coffee@gmail.com
ReplyDeleteGNOME shell extensions shouldn't be run from the command line. Do
gnome-shell-extension-tool -e [your extension's UUID]
to enable the extension, and then *restart* gnome-shell to have it run (if not with Alt+F2 'r', then do gnome-shell --replace in a terminal).
OK i tried that too but was not able to see the output on screen at all..
ReplyDeleteThen installed gnome-tweak-tool to enable the extension and i could see an icon on the top right.
then did gnome-shell --replace and clicked the icon ,
I could see the output then..
Thanks a lot for your help.
Nice. Very helpful thanks!
ReplyDelete