Features/GTK3/Porting/GetBooks

From Sugar Labs
< Features‎ | GTK3‎ | Porting
Jump to navigation Jump to search

This page is being performed while I'm porting Get Books Activity to Gtk3.

There is a ticket with some useful information that I'm using on the porting and to keep tracking this port. Besides, this wiki page will be useful to write some code snippets about what are the difficulties that I'm having on the port and maybe can be useful for someone else.

Steps that you should follow to Port an Activity to Gtk3

  1. Read the Sugar Official Wiki
  2. Read the specific Sugar Wiki Page that talks about how to porting. Please, follow those steps and if you have a suggestion about the process you can contact with us and let us know.
  3. Comment on IRC about the Activity that you are going to Port (#sugar on irc.freenode.net)
  4. Run this script that will convert automatically things as much as it can. This is to avoid some stressful manually conversions that a "simple script" can do using sed :)
  5. Convert all the from sugar.* import to from sugar3.* import using this script
  6. Follow the Code Guidelines during all the porting process
  7. Remove all things related with old toolbar support. They are no longer maintained
  8. Write comments on the code, by adding # README:, # TODO: and # FIXME: explaining what are the problems that you are having with that chunk of code. Put a link if it's necessary
  9. If you are considering to fix some pep8 or pylint errors/warnings, please create two separate patch files (one for the port and one for the pylint/pep8 changes). If we follow this way it is easier to check the port patches, if not the information about the port itself it's difficult to follow
  10. Keep reading this wiki page to find out more things that you should do

Tips and Tricks

Create a "new" activity from the git version

It's really useful to keep the "original" version of the Activity that we are porting to know how it was working before the port. Sometimes you find an strange behaviour on the ported version of the activity and you think that you don't touch that part of the code or that the change shouldn't affect it. In these cases it's good to run the "original" version and test how it worked before the port.

I asked to the Sugar Developers mailing list about how to do this and they told me that I should change the bundle_id. In fact, we have to change the bundle_id and the name from the activity/activity.info file. I used:

name = Get Books Gtk3
bundle_id = git.GetBooksActivity

After this, you should run the build and dev setup commands:

cd get-books
python setup.py dev
python setup.py build

Now, you will see two Get Books activities: one called just "Get Books" and another one called "Get Books Gtk3".

Script to list all the enumeration

There is an script that list all the Gtk methods and it's useful to know the new name and from where it comes from. For example:

[humitos@michifus get-books]$ python pygi-enumerate.py | grep get_selection
Gtk.AccelLabel.get_selection_bounds() (instance method)
Gtk.Editable.get_selection_bounds() (instance method)
Gtk.Entry.get_selection_bounds() (instance method)
Gtk.IconView.get_selection_mode() (instance method)
Gtk.Label.get_selection_bounds() (instance method)
Gtk.SelectionData.get_selection() (instance method)
Gtk.SpinButton.get_selection_bounds() (instance method)
Gtk.TextBuffer.get_selection_bound() (instance method)
Gtk.TextBuffer.get_selection_bounds() (instance method)
Gtk.TreeView.get_selection() (instance method)
[humitos@michifus get-books]$

Use the same keyboard and mouse

If you have an XO, I'm sure you want to take a look at this...

Use Extended Python debugger

There is a library called epdb and it's useful to inspect the code while the Activity is running. I'm using this module when I'm not sure about the type of an object or I can test some different things that the code says in some point. So, I installed this package on my Fedora 17 by running this command

sudo yum install python-epdb

After that I put some trace point in the code where I can stop and make my tests by doing this:

import epdb;epdb.set_trace()

Finally I run Get Books Activity from the Terminal Activity to be able to write some code on a shell. This is the command that I use:

sugar-launch org.laptop.sugar.GetBooksActivity

See also Development Team/Debugging.

Check logs with multitail

Here is a really useful command to open new logs automatically: User:Humitos/MultiTail


Use the pygobject code as example

pygobject is what we use to make Gtk3 activities. So, it's really useful to take a look at the code examples that are there. Even more, you can run some demo application that show how to use something specific about the library.

  • Clone the code:
git clone git://git.gnome.org/pygobject
Screenshot from 2012-06-14 13-26-50.png
  • Run an example
cd pygobject
cd demos/gtk-demo/demos
python pixbuf.py
  • Grep the code to search for something useful
cd pygobject
git grep GdkPixbuf

Monitoring DBus

Not sure how this command works, but it can give us an interesting information. If you run this command and plug an USB drive you will see useful information

dbus-monitor --system

Code Snippets

On this section I will explain all the things that I had to do manually and took me some time to find out. Some of them are really simple but time-consuming so the idea is to reduce that time as much as we can.

Migrate custom signals

If you have defined custom gtk objects with custom signal you should migrate them to the new way to do this.

You should replace this:

from gobject import signal_new, TYPE_INT, TYPE_STRING, TYPE_BOOLEAN, \
TYPE_PYOBJECT, TYPE_NONE, SIGNAL_RUN_LAST
signal_new('extlistview-modified', gtk.TreeView, SIGNAL_RUN_LAST, TYPE_NONE,
            ())

by adding the signal definition inside the object that you are creating using the __gsignals__ dictionary like this (in this case Gtk.TreeView is the class that our object inherits):

from gi.repository import GObject
class ExtListView(Gtk.TreeView):
    __gsignals__ = {
      'extlistview-modified': (GObject.SignalFlags.RUN_LAST, None,
                             ()),
       }

The last argument of the signal definition are the argument types that the callback will receive. For example, that tuple could be (str, int) if the callback receives two arguments, a string and an integer (first and second argument position)

Access to the Window instance

sugar3.activity.Activity doesn't have the window attribute anymore instead of this it has the .get_window() method that do the same thing. So, you should change all the occurrences of them.

Change the mouse cursor

The window attribute that I mention before is used to set the mouse cursor. This is used when the activity is working on the background (maybe searching something on the Internet) and we want to show a work in progress cursor for example.

The old way to set the cursor is:

self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))

And it should be replaced by the new one:

from gi.repository import Gdk
self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH))

In that case we are creating a new instance of Gdk.Cursor every time that this chunk of code is called. I think that we could define all the cursor used by the Activity once at the beginning of the file maybe. We should discuss about this.

Use Gtk.Box instead Gtk.HBox / Gtk.VBox | Gtk.HSeparator / Gtk.VSeparator

As its documentation says, Gtk.VBox and Gtk.HBox have been deprecated. So, we should use Gtk.Box instead them. Replacing:

self.list_box = gtk.HBox()

by:

self.list_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)

and,

self.list_box = gtk.VBox()

by:

self.list_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

The same happens with Gtk.Separator: link to the documentation

Using Pixbuf

As I said, this is what I did, but maybe is not the correct way to do it or there is a better way. I think that if we are porting an Activity we can take advantage of this and improve the code. manuq told me that the image handling now is done with Cairo, so we should port that to cairo. Although, I didn't do this because I consider that the image handling done in Get Books is really simple and we don't have the necessity to use Cairo here.

So, what I did is keep using Pixbuf with Gtk3 version of the Activity. We need to replace and import some things:

from gi.repository import GdkPixbuf

Replace:

gtk.gdk.PixbufLoader()

by:

GdkPixbuf.PixbufLoader()

and,

gtk.gdk.pixbuf_new_from_file(file_path)

by:

GdkPixbuf.Pixbuf.new_from_file(file_path)

and,

gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,
               pixbuf.get_has_alpha(),
               pixbuf.get_bits_per_sample(),
               image_width, image_height)

by:

GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB,
                     pixbuf.get_has_alpha(),
                     pixbuf.get_bits_per_sample(),
                     image_width, image_height)

note the .new and the colorspace in the replacement.

and,

gtk.gdk.INTERP_BILINEAR

by:

GdkPixbuf.InterpType.BILINEAR


Save the GdkPixbuf into a buffer

This was very difficult to find out. The gtk2 version of the code was using pixbuf.save_to_callback to save the Image on the Journal's Preview Entry but that function no longer exist in Gtk3. So, I found a similar one called pixbuf.save_to_callbackv that I couldn't find out how to use it. Even more, I realized that this function call another callback function that doesn't do so much. Reading I found an alternative (and easier) way to do this using pibuxf.save_to_bufferv:

succes, data = pixbuf2.save_to_bufferv('png', [], [])

Notes

There are some things that I realized while I was doing the port. I will mention them here:

self.treemodel = Gtk.ListStore(GObject.TYPE_STRING)
self.treemodel = Gtk.ListStore(str)

Missing / Problematic things (not ported yet)

  • [DONE] When a book is downloaded, the cover is not saved in the Journal Entry
  • [DONE] Switch the results to Internet Archive doesn't work
  • [ALTERNATIVE] When the "generic book image" is shown (at the bottom left), the gray color used to fill it is not the same as the background. I changed the color with is the GdkPixbuf filled to match with the darker one (style.COLOR_BUTTON_GREY) because I couldn't find how to fill the alpha of the "generic_cover.png" with the old color (style.COLOR_PANEL_GREY): http://bugs.sugarlabs.org/ticket/3723
  • [DONE] I'm not sure what is org.freedesktop.UDisks.Device for? I don't understand it very well but I had to remove it because it was failing. I replaced this by GIO
  • The Catalogs column title is bigger than the other column titles
  • Right clicking on the column titles doesn't show the Gtk.Menu popup

Theme related things

References / Useful links