Activity tutorial: Difference between revisions
(Explain what a xo file is.) |
(class is deprecated; use exec = sugar-activity) |
||
(101 intermediate revisions by 53 users not shown) | |||
Line 1: | Line 1: | ||
{{dated}} |
|||
The tutorial explains step by step how to create the [http://www.gnome.org/~marco/HelloWorld-1.xo Hello World activity bundle]. |
|||
For up to date information on creating Activities see http://www.flossmanuals.net/make-your-own-sugar-activities/ |
|||
Create the bundle directory structure. |
|||
{{Translations}} |
|||
hello.activity |
|||
{{Developers}} |
|||
hello.activity/activity |
|||
<< [[Tutorials]] |
|||
This tutorial explains step by step how to create the Hello World Activity bundle. You can [http://divieira.googlepages.com/HelloWorld-1.xo download a completed .xo package], though the package will not exactly match the below contents. |
|||
Write the activity.info file, to describe your bundle in the activity sub-directory (i.e. hello.activity/activity/activity.info). The [[Activity Bundles]] specification explain in detail the meaning of each field. |
|||
This tutorial assumes you have read the [[Developers|Developer's Manual]], have [[Developers/Setup|installed a Sugar development environment]] and wish to use the [[Developers/Setup#Python/PyGTK|PyGTK]] development approach (the standard approach to developing activities for the OLPC). |
|||
== Getting started == |
|||
*Create the bundle directory structure: |
|||
mkdir -p HelloWorldActivity.activity/activity |
|||
*Write the <tt>activity.info</tt> file, to describe your bundle in the activity sub-directory (e.g. <tt>HelloWorldActivity.activity/activity/activity.info</tt>). The [[Activity Bundles]] specification explain in detail the meaning of each field. |
|||
**Note: in a joyride-1525 build, sugar could not locate the icon when I tried this unless I removed the '.svg' extension from the 'icon = activity-helloworld.svg' line. |
|||
{{ Box File | activity.info | 2=<pre> |
|||
[Activity] |
[Activity] |
||
name = HelloWorld |
name = HelloWorld |
||
bundle_id = org.laptop.HelloWorldActivity |
|||
exec = sugar-activity |
exec = sugar-activity HelloWorldActivity.HelloWorldActivity |
||
icon = activity-helloworld |
icon = activity-helloworld |
||
activity_version = 1 |
activity_version = 1 |
||
host_version = 1 |
|||
show_launcher = yes |
show_launcher = yes |
||
</pre> |
|||
}} |
|||
*Design an icon for your activity by following the instructions on [[Making_Sugar_Icons | making icons for Sugar]] and place it in the activity sub-directory. The file name should match the icon file name specified in the info file (e.g. <tt>activity-helloworld.svg</tt>). The contents of the SVG file will look something like: |
|||
'''NOTE: Due to API changes, in a newer sugar environment replace''' |
|||
exec = sugar-activity-factory HelloWorldActivity.HelloWorldActivity |
|||
'''with''' |
|||
class = HelloWorldActivity.HelloWorldActivity |
|||
Design an icon for your activity, according to the [[Sugar_Icon_Format|icon format]] and place it in the activity sub-directory. The file name should match the one specified in the info "activity-helloworld.svg". |
|||
{{ Box File | activity-helloworld.svg | 2=<pre> |
|||
<?xml version="1.0" encoding="UTF-8"?> |
<?xml version="1.0" encoding="UTF-8"?> |
||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" |
||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ |
|||
<!ENTITY stroke_color "#666666"> |
|||
<!ENTITY fill_color "#FFFFFF"> |
<!ENTITY fill_color "#FFFFFF"> |
||
<!ENTITY stroke_color "#000000"> |
|||
]> |
]> |
||
<svg xmlns="http://www.w3.org/2000/svg" width=" |
<svg xmlns="http://www.w3.org/2000/svg" width="55" height="55"> |
||
<rect x=" |
<rect x="5" y="5" width="45" height="45" |
||
style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3.5"/> |
|||
</svg> |
</svg> |
||
</pre> |
|||
}} |
|||
Write the setup.py script in the top level directory ( |
*Write the <tt>setup.py</tt> script in the top level directory (e.g. <tt>HelloWorldActivity.activity/setup.py</tt>), which in most cases will look like this: |
||
{{ Box File | setup.py | 2=<pre> |
|||
#!/usr/bin/env python |
#!/usr/bin/env python |
||
from sugar.activity import bundlebuilder |
from sugar.activity import bundlebuilder |
||
bundlebuilder.start() |
|||
if __name__ == "__main__": |
|||
</pre> |
|||
bundlebuilder.start() |
|||
}} |
|||
A more advanced version, which supports building activity bundles without Sugar installed, looks like this: |
|||
Code your activity. Module and class names should match those specified in the exec field of the info. That is, the exec must be specified as a direct dotted path to the class name. The top-level is the hello.activity directory, so for the activity.info file above, we specify a top-level module named HelloWorldActivity.HelloWorldActivity (please note that the use of uppercase names in module names is considered poor Python style, feel free to use an activity name with more standard style names). |
|||
{{ Box File | setup.py | 2=<pre> |
|||
#!/usr/bin/env python |
|||
try: |
|||
from sugar.activity import bundlebuilder |
|||
bundlebuilder.start() |
|||
except ImportError: |
|||
import os |
|||
os.system("find ./ | sed 's,^./,HelloWorldActivity.activity/,g' > MANIFEST") |
|||
os.system('rm HelloWorldActivity.xo') |
|||
os.chdir('..') |
|||
os.system('zip -r HelloWorldActivity.xo HelloWorldActivity.activity') |
|||
os.system('mv HelloWorldActivity.xo ./HelloWorldActivity.activity') |
|||
os.chdir('HelloWorldActivity.activity') |
|||
</pre> |
|||
}} |
|||
*Code your activity in Python. The name you specified in the <tt>.info</tt> file as "<tt>class</tt>" is the name of the class which runs your code. For the <tt>activity.info</tt> file above, we specify a top-level module named <tt>HelloWorldActivity.HelloWorldActivity</tt> (please note that the use of uppercase names in module names is considered poor [[Python Style Guide|Python style]], feel free to use an activity name with more standard style names). |
|||
{{ Box File | HelloWorldActivity.py | 2=<pre> |
|||
from sugar.activity import activity |
|||
import logging |
import logging |
||
from sugar.activity.Activity import Activity |
|||
import sys, os |
import sys, os |
||
import gtk |
import gtk |
||
class HelloWorldActivity(Activity): |
class HelloWorldActivity(activity.Activity): |
||
# This is a callback function. The data arguments are ignored |
|||
# in this example. More on callbacks below. |
|||
def hello(self, widget, data=None): |
def hello(self, widget, data=None): |
||
logging.info('Hello World') |
logging.info('Hello World') |
||
def __init__(self): |
def __init__(self, handle): |
||
print "running activity init", handle |
|||
Activity.__init__(self) |
|||
activity.Activity.__init__(self, handle) |
|||
print "activity running" |
|||
# Creates the Toolbox. It contains the Activity Toolbar, which is the |
|||
# bar that appears on every Sugar window and contains essential |
|||
# functionalities, such as the 'Collaborate' and 'Close' buttons. |
|||
toolbox = activity.ActivityToolbox(self) |
|||
self.set_toolbox(toolbox) |
|||
toolbox.show() |
|||
# Creates a new button with the label "Hello World". |
# Creates a new button with the label "Hello World". |
||
self.button = gtk.Button("Hello World") |
self.button = gtk.Button("Hello World") |
||
# When the button receives the "clicked" signal, it will call the |
# When the button receives the "clicked" signal, it will call the |
||
# function hello() passing it None as its argument. The hello() |
# function hello() passing it None as its argument. The hello() |
||
# function is defined above. |
# function is defined above. |
||
self.button.connect("clicked", self.hello, None) |
self.button.connect("clicked", self.hello, None) |
||
# |
# Set the button to be our canvas. The canvas is the main section of |
||
# every Sugar Window. It fills all the area below the toolbox. |
|||
self.add(self.button) |
|||
self.set_canvas(self.button) |
|||
# The final step is to display this newly created widget. |
# The final step is to display this newly created widget. |
||
self.button.show() |
self.button.show() |
||
print "AT END OF THE CLASS" |
|||
self.set_title('Hello World') |
|||
</pre> |
|||
}} |
|||
The above file is called <tt>HelloWorldActivity.py</tt> |
|||
*Create a <tt>MANIFEST</tt> (e.g. <tt>HelloWorldActivity.activity/MANIFEST</tt>), containing the list of the files (relative to the directory that the MANIFEST is in) to include in the package. (Note: Be sure '''not''' to leave blank lines at the end of the file.) This script does that in linux (run it from within the HellowWorldActivity.activity directory): |
|||
'''NOTE: Due to API changes, in a newer sugar environment your file will need to begin as such:''' |
|||
cd HelloWorldActivity.activity |
|||
import logging |
|||
find . -type f | sed 's,^./,,g' > MANIFEST |
|||
from sugar.activity import activity |
|||
import sys, os |
|||
import gtk |
|||
class HelloWorldActivity(activity.Activity): |
|||
# This is a callback function. The data arguments are ignored |
|||
# in this example. More on callbacks below. |
|||
def hello(self, widget, data=None): |
|||
logging.info('Hello World') |
|||
def __init__(self, handle): |
|||
activity.Activity.__init__(self, handle) |
|||
*Your directory structure should now look like this: |
|||
Create a MANIFEST, containing the list of the files to include in the package. (Note: Be sure not to leave blank lines at the end of the file.) |
|||
HelloWorldActivity.activity/ |
|||
HelloWorldActivity.activity/setup.py |
|||
HelloWorldActivity.activity/activity |
|||
HelloWorldActivity.activity/activity/activity.info |
|||
HelloWorldActivity.activity/activity/activity-helloworld.svg |
|||
HelloWorldActivity.activity/HelloWorldActivity.py |
|||
HelloWorldActivity.activity/MANIFEST |
|||
*Make sure that all your python files have the required permissions to be used. |
|||
HelloWorldActivity.py |
|||
chmod a+x setup.py |
|||
chmod a+x HelloWorldActivity.py |
|||
Setup your bundle for development |
*Setup your bundle for development (must be user olpc when you do this) to become user olpc, type: su - olpc |
||
If you are prompted for a password, trying using: su |
|||
./setup.py dev |
|||
python setup.py dev |
|||
If you now run sugar the activity icon should be visible on the frame. You can edit the code in your bundle directory, it will be picked up when sugar is restarted. |
|||
This just creates a symlink to your activity folder in <tt>~/Activities</tt>, so that Sugar can find your activity. |
|||
Create a xo package to distribute your bundle. (An xo file is essentially a zip file built from the MANIFEST with some extra metadata, like a JAR file; in the future we expect to be able to sign these too.) |
|||
*Restart Sugar using Ctrl-Alt-Erase and your activity will appear in the interface! (NOTE: By default, the Home view shows only the favorite activities. You should press Ctrl+2 or go the right-upper corner and change to the List View) |
|||
./setup.py dist |
|||
*Run your activity, and if there are errors use the [[Log]] viewer activity to see what went wrong. |
|||
== Running == |
|||
If you now run sugar the activity icon should be visible on the frame. (You have to restart sugar to get it to pick up the change if you just installed it. Hit <tt>ctrl-alt-erase</tt>.) |
|||
You can also edit the code in your bundle directory directly. Note that the first time your Activity is launched, it leaves a process around even if you close the window, so you must kill the <tt>sugar-activity-factory</tt> to get it to reload when you click again. |
|||
== Distribution == |
|||
Create an <tt>.xo</tt> package to distribute your bundle. (An <tt>.xo</tt> file is essentially a zip file built from the MANIFEST with some extra metadata, like a JAR file. It also has some localization ability, and in the future we expect to be able to sign these too.) The bundle name is automatically generated from the '<tt>name</tt>' and '<tt>activity_version</tt>' values found in the <tt>activity.info</tt> file, separated by a dash, with a <tt>.xo</tt> extension. |
|||
./setup.py dist_xo |
|||
To install the xo on a laptop you can use the installer script. |
To install the xo on a laptop you can use the installer script. |
||
Line 107: | Line 162: | ||
sugar-install-bundle HelloWorld-1.xo |
sugar-install-bundle HelloWorld-1.xo |
||
== Trouble Shooting == |
|||
XXX Explain what the -1 suffix means. |
|||
You can find application logs in /home/olpc/.sugar/default/logs. If the sample fails to compile, sugar will show you the icon in the circle but remain forever at the "Starting..." tag when you hover your mouse over it. You'll have to restart sugar with <ctrl-alt-erase> in order to remove the icon. You can find the cause of your trouble in the the log named for the "service-name" in your activity.info file, in this case "org.laptop.HelloWorldActivity". |
|||
== See also == |
|||
* [[Activity bundles]] |
|||
* [[Hacking Sugar]] |
|||
* [[Localization]] -- you will need to localize your activity to make it accessible to users of the OLPC |
|||
* [[Game development HOWTO]] |
|||
* [[Textedit Activity]] - simple text editor to support development and testing on the Xo |
|||
[[Category:Sugar]] |
[[Category:Sugar]] |
||
[[Category:HowTo]] |
[[Category:HowTo]] |
||
[[Category: |
[[Category:Developers]] |
Latest revision as of 16:36, 17 January 2014
For up to date information on creating Activities see http://www.flossmanuals.net/make-your-own-sugar-activities/
<< Tutorials
This tutorial explains step by step how to create the Hello World Activity bundle. You can download a completed .xo package, though the package will not exactly match the below contents.
This tutorial assumes you have read the Developer's Manual, have installed a Sugar development environment and wish to use the PyGTK development approach (the standard approach to developing activities for the OLPC).
Getting started
- Create the bundle directory structure:
mkdir -p HelloWorldActivity.activity/activity
- Write the activity.info file, to describe your bundle in the activity sub-directory (e.g. HelloWorldActivity.activity/activity/activity.info). The Activity Bundles specification explain in detail the meaning of each field.
- Note: in a joyride-1525 build, sugar could not locate the icon when I tried this unless I removed the '.svg' extension from the 'icon = activity-helloworld.svg' line.
File: activity.info |
[Activity] name = HelloWorld bundle_id = org.laptop.HelloWorldActivity exec = sugar-activity HelloWorldActivity.HelloWorldActivity icon = activity-helloworld activity_version = 1 host_version = 1 show_launcher = yes |
- Design an icon for your activity by following the instructions on making icons for Sugar and place it in the activity sub-directory. The file name should match the icon file name specified in the info file (e.g. activity-helloworld.svg). The contents of the SVG file will look something like:
File: activity-helloworld.svg |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ <!ENTITY stroke_color "#666666"> <!ENTITY fill_color "#FFFFFF"> ]> <svg xmlns="http://www.w3.org/2000/svg" width="55" height="55"> <rect x="5" y="5" width="45" height="45" style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3.5"/> </svg> |
- Write the setup.py script in the top level directory (e.g. HelloWorldActivity.activity/setup.py), which in most cases will look like this:
File: setup.py |
#!/usr/bin/env python from sugar.activity import bundlebuilder bundlebuilder.start() |
A more advanced version, which supports building activity bundles without Sugar installed, looks like this:
File: setup.py |
#!/usr/bin/env python try: from sugar.activity import bundlebuilder bundlebuilder.start() except ImportError: import os os.system("find ./ | sed 's,^./,HelloWorldActivity.activity/,g' > MANIFEST") os.system('rm HelloWorldActivity.xo') os.chdir('..') os.system('zip -r HelloWorldActivity.xo HelloWorldActivity.activity') os.system('mv HelloWorldActivity.xo ./HelloWorldActivity.activity') os.chdir('HelloWorldActivity.activity') |
- Code your activity in Python. The name you specified in the .info file as "class" is the name of the class which runs your code. For the activity.info file above, we specify a top-level module named HelloWorldActivity.HelloWorldActivity (please note that the use of uppercase names in module names is considered poor Python style, feel free to use an activity name with more standard style names).
File: HelloWorldActivity.py |
from sugar.activity import activity import logging import sys, os import gtk class HelloWorldActivity(activity.Activity): def hello(self, widget, data=None): logging.info('Hello World') def __init__(self, handle): print "running activity init", handle activity.Activity.__init__(self, handle) print "activity running" # Creates the Toolbox. It contains the Activity Toolbar, which is the # bar that appears on every Sugar window and contains essential # functionalities, such as the 'Collaborate' and 'Close' buttons. toolbox = activity.ActivityToolbox(self) self.set_toolbox(toolbox) toolbox.show() # Creates a new button with the label "Hello World". self.button = gtk.Button("Hello World") # When the button receives the "clicked" signal, it will call the # function hello() passing it None as its argument. The hello() # function is defined above. self.button.connect("clicked", self.hello, None) # Set the button to be our canvas. The canvas is the main section of # every Sugar Window. It fills all the area below the toolbox. self.set_canvas(self.button) # The final step is to display this newly created widget. self.button.show() print "AT END OF THE CLASS" |
The above file is called HelloWorldActivity.py
- Create a MANIFEST (e.g. HelloWorldActivity.activity/MANIFEST), containing the list of the files (relative to the directory that the MANIFEST is in) to include in the package. (Note: Be sure not to leave blank lines at the end of the file.) This script does that in linux (run it from within the HellowWorldActivity.activity directory):
cd HelloWorldActivity.activity find . -type f | sed 's,^./,,g' > MANIFEST
- Your directory structure should now look like this:
HelloWorldActivity.activity/ HelloWorldActivity.activity/setup.py HelloWorldActivity.activity/activity HelloWorldActivity.activity/activity/activity.info HelloWorldActivity.activity/activity/activity-helloworld.svg HelloWorldActivity.activity/HelloWorldActivity.py HelloWorldActivity.activity/MANIFEST
- Make sure that all your python files have the required permissions to be used.
chmod a+x setup.py chmod a+x HelloWorldActivity.py
- Setup your bundle for development (must be user olpc when you do this) to become user olpc, type: su - olpc
If you are prompted for a password, trying using: su
python setup.py dev
This just creates a symlink to your activity folder in ~/Activities, so that Sugar can find your activity.
- Restart Sugar using Ctrl-Alt-Erase and your activity will appear in the interface! (NOTE: By default, the Home view shows only the favorite activities. You should press Ctrl+2 or go the right-upper corner and change to the List View)
- Run your activity, and if there are errors use the Log viewer activity to see what went wrong.
Running
If you now run sugar the activity icon should be visible on the frame. (You have to restart sugar to get it to pick up the change if you just installed it. Hit ctrl-alt-erase.)
You can also edit the code in your bundle directory directly. Note that the first time your Activity is launched, it leaves a process around even if you close the window, so you must kill the sugar-activity-factory to get it to reload when you click again.
Distribution
Create an .xo package to distribute your bundle. (An .xo file is essentially a zip file built from the MANIFEST with some extra metadata, like a JAR file. It also has some localization ability, and in the future we expect to be able to sign these too.) The bundle name is automatically generated from the 'name' and 'activity_version' values found in the activity.info file, separated by a dash, with a .xo extension.
./setup.py dist_xo
To install the xo on a laptop you can use the installer script.
sugar-install-bundle HelloWorld-1.xo
Trouble Shooting
You can find application logs in /home/olpc/.sugar/default/logs. If the sample fails to compile, sugar will show you the icon in the circle but remain forever at the "Starting..." tag when you hover your mouse over it. You'll have to restart sugar with <ctrl-alt-erase> in order to remove the icon. You can find the cause of your trouble in the the log named for the "service-name" in your activity.info file, in this case "org.laptop.HelloWorldActivity".
See also
- Activity bundles
- Hacking Sugar
- Localization -- you will need to localize your activity to make it accessible to users of the OLPC
- Game development HOWTO
- Textedit Activity - simple text editor to support development and testing on the Xo