=== jsjgruber_ is now known as jsjgruber | ||
=== callaghan_ is now known as callaghan | ||
codingenesis | what is ubuntu classroom chat ?? | 08:47 |
---|---|---|
codingenesis | can anyone give a light on it ?? | 08:47 |
nigelb | codingenesis: https://wiki.ubuntu.com/Classroom would be helpful | 08:50 |
codingenesis | i would definitely like to be a part of it.. | 08:51 |
codingenesis | how can i join ?? | 08:51 |
devcalais | are there scheduled discussion/classrooms in here? if so, where can I access a timetable? | 12:00 |
nigelb | devcalais: You can see the schedule in the Calender. | 12:02 |
nigelb | The link to the calender is in the topic | 12:02 |
devcalais | Cheers. :) | 12:13 |
conscioususer | 14:08 | |
smitpatel | Hello all .. I apologize if this query isn't posted on right channel. After I upgraded to 11.10 I got this msg in recovery mode "var/run/dbus/system_bus_socket connection refused" and I am unable to login in my a/c. | 15:01 |
smitpatel | Someone please help me out | 15:01 |
=== dpm is now known as dpm_ | ||
=== Wilczek_ is now known as Wilczek | ||
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || Event: App Developer Week - Current Session: Creating an App Developer Website: developer.ubuntu.com - Instructors: dpm, johnoxton | ||
ClassBot | Logs for this session will be available at http://irclogs.ubuntu.com/2011/09/08/%23ubuntu-classroom.html following the conclusion of the session. | 16:01 |
dpm | Welcome everyone to Day 4 of the Ubuntu App Developer Week! | 16:01 |
dpm | ok, so let's get started, shall we? | 16:02 |
=== shadeslayer_ is now known as shadeslayer | ||
dpm | So hi everyone | 16:03 |
dpm | Again, welcome to Ubuntu App Developer Week and to this session about the App Developer _site_ | 16:03 |
dpm | My name is David Planella, and I work on the Community team at Canonical as the Ubuntu Translations Coordinator | 16:03 |
dpm | While still working on translations, this cycle I've been spending some time on the app developer side of things, | 16:04 |
dpm | that is, contributing to the goal of making Ubuntu a target platform for application developers, | 16:04 |
dpm | so that they can easily create or port software in Ubuntu and they can publish it and distribute it to and grow our increasing user base. | 16:04 |
dpm | My main area of focus has been so far developer.ubuntu.com, of which we're going to talk today, | 16:05 |
dpm | and for this I've had the pleasure of working with the awesome web design team at Canonical. | 16:05 |
dpm | Co-presenting this session and representing them we've got the luxury of having John Oxton, | 16:05 |
dpm | who's recently joined Canonical and has been doing fantastic work in shaping up the site | 16:05 |
dpm | But I'll let him introduce himself best | 16:06 |
* dpm hands the mike to johnoxton | 16:06 | |
johnoxton | Hi everyone, as David said, my name is John Oxton and I am a user experience architect on the web team at Canonical. I have been with the company for a few months and this is my first assignment. | 16:06 |
johnoxton | I will be using the word ‘we’ quite a lot as we go along and this is just a shortcut to represent a group of very busy people (inside and outside Canonical) who have given their time generously to this project, not because they have to but because they care about it deeply and believe it to be very important to the future success of Ubuntu. In that light my contributions to this project really are very | 16:07 |
johnoxton | to theirs. | 16:07 |
johnoxton | Ok, enough with the Oscar acceptance speech, let’s get on! | 16:07 |
johnoxton | As has been mentioned the goal of this site is to help get more and better apps into the Ubuntu Software Centre. | 16:07 |
johnoxton | From the developer.ubuntu.com website point of view that is an interesting challenge and not one we can possibly hope achieve in one step. | 16:08 |
johnoxton | Where to begin? | 16:09 |
johnoxton | The first question really is what is an ‘app’ anyway? Is LibreOffice an app? Is Mozilla’s Thunderbird an app? What about Chromium? Skype? Firefox? | 16:09 |
johnoxton | Well the answer is yes and each a very good one but also advanced and relatively mature and, importantly, already on Ubuntu. | 16:09 |
johnoxton | The point being, for this upcoming release we aren’t really targeting developers of these kinds of apps because they are already working it out. | 16:09 |
johnoxton | Of course, nor is the aim to exclude them. | 16:10 |
johnoxton | Instead we want to start a dialogue with individuals, or small teams, with an “itch to scratch” | 16:10 |
johnoxton | or small indie developers/companies who are already making small, useful, or just plain cool, apps for other platforms. | 16:11 |
johnoxton | With that in mind we shaped two personas, and the journeys we’d expect them to make, to reflect these sorts of developers | 16:11 |
johnoxton | and began sketching ideas about how we thought we could encourage and support them through the app development lifecycle. | 16:11 |
johnoxton | For those who’ve never encountered personas, here is a brief summary from UX mag: | 16:12 |
johnoxton | “A persona represents a cluster of users who exhibit similar behavioral patterns in their purchasing decisions, use of technology or products, customer service preferences, lifestyle choices, and the like." | 16:12 |
johnoxton | You can find out more at http://uxmag.com/design/personas-the-foundation-of-a-great-user-experience | 16:13 |
* dpm mentions: before I forget, please feel free to ask any questions throughout the session, prepending them with QUESTION: on the #ubuntu-classroom-chat channel | 16:13 | |
johnoxton | So with personas firmly in our head, this is what we sketched: http://madebymake.com/ | 16:14 |
johnoxton | To access the site: Username: developer and Password: ubuntu | 16:14 |
johnoxton | Please keep in mind that our focus here was on the structure of the navigation and the general concept of the site so the visual design seen here is in no way representative of the finished site. | 16:14 |
johnoxton | Feel free to click around, most pages are present; I’ll grab a much needed cup of tea whilst you do. | 16:14 |
johnoxton | Anyway, with that done we hired an independent research company to help us test this prototype. | 16:17 |
johnoxton | We did this because we needed someone neutral to help us really dig for what was good and what was not so good. | 16:17 |
johnoxton | From there we recruited a cross-section of ‘app developers’ who were developing for a variety of platforms; some professionally, some in their spare time. | 16:18 |
johnoxton | We ran them through the prototype you have seen, asking them about their expectations before they clicked through to different pages | 16:19 |
johnoxton | and also talking to them about their usual app development workflow to see if the site could be truly useful to them. | 16:19 |
johnoxton | David, meanwhile, ran an in-depth survey to give us some quantitative data to support or challenge what our qualitative research was suggesting. | 16:19 |
johnoxton | These sessions and the survey were incredibly important. They challenged all of the assumptions we had made and helped us verify that our personas were even closely matching reality. | 16:20 |
johnoxton | In short the response to our first prototype was fairly unanimous: We like where you are going but this isn’t right. | 16:20 |
johnoxton | It also started to hint that our personas were close but not quite close enough. | 16:20 |
johnoxton | With the first round of testing complete we went back to the drawing board and considered everything we’d learnt. | 16:20 |
johnoxton | So what did we learn? | 16:20 |
johnoxton | What came back consistently was: marketing sucks, so just stop it. I just want to ‘Get started’, tell me how to proceed. | 16:21 |
johnoxton | Give me an ‘Hello World!’ app to play with and I want really good documentation. | 16:21 |
johnoxton | Oh, and packaging, I don’t like thinking about packaging if I can help it. | 16:21 |
johnoxton | Just ‘Get started’, hmmmm, this is where things get challenging. | 16:21 |
johnoxton | Linux, and therefore Ubuntu, prides itself on having a rich, flexible development environment | 16:21 |
johnoxton | which is great but also has the potential for confusion for people just starting out | 16:22 |
johnoxton | On the back of the findings we felt we really ought to be a little more decisive and dare to be a little opinionated because without that the site won’t have the clarity it needs to attract developers to the platform. | 16:22 |
johnoxton | Thankfully the springboard for that was already in place in the form of Quickly (https://wiki.ubuntu.com/Quickly) | 16:22 |
johnoxton | and after much debate, for now at least, we’ve put it up front. | 16:22 |
johnoxton | We have stated that THIS is the way to get going when developing for Ubuntu. | 16:23 |
johnoxton | We are aware that this might be a somewhat controversial decision to make and we have been careful to show that there are other options | 16:23 |
johnoxton | but Quickly delivers a route in and a good one as it elegantly stitches together classic, and very powerful, Linux development tools. | 16:23 |
johnoxton | Very importantly it also helps with packaging. | 16:23 |
johnoxton | Something our research has suggested is that whilst great apps are being written for Ubuntu they aren’t making it all the way into the Software Centre. | 16:24 |
johnoxton | Packaging seems to be part of what’s stopping that happening | 16:24 |
johnoxton | Thinking about Quickly, and the tools it brings together, helps shape our content strategy for another important area of the site: Resources | 16:24 |
johnoxton | ... or Reference... or Documentation (we’re still trying to decide what we should call this section). | 16:24 |
johnoxton | Whatever it ends up being called, the potential for this section of the site is enormous and our research suggests it is an area that really could improve the success rate of apps hitting the Software Centre. | 16:24 |
johnoxton | But there is a problem. | 16:25 |
johnoxton | There’s so much content for this section, generally, but it’s all over the place, it’s not well organised in one authoritative spot. | 16:25 |
johnoxton | On the flip side there’s not enough of the right content to help those people who are just getting started; or if there is it’s a real struggle to find it. | 16:25 |
johnoxton | Getting this section right in one hit is impossible without a bigger discussion with developers. | 16:26 |
johnoxton | So we’ve scoped it carefully and our message will be clear: We need help with this! | 16:26 |
johnoxton | Which is where you come in. To begin with let’s keep things simple and engage with you, the community, around a single topic and from there build up the infrastructure we need to make this site something truly special. | 16:26 |
johnoxton | So what next? | 16:26 |
johnoxton | Before we get to that I just want to share a couple more rough sketches with you so you can, hopefully, see the difference the testing made to how we approached the flow of the site. | 16:27 |
johnoxton | and so far they've tested pretty well: | 16:27 |
johnoxton | http://dl.dropbox.com/u/24134/developer/Home.jpg | 16:27 |
johnoxton | http://dl.dropbox.com/u/24134/developer/getstarted.jpg | 16:27 |
johnoxton | http://dl.dropbox.com/u/24134/developer/resources.jpg | 16:27 |
johnoxton | This really has been a very quick skip and a hop through a quite detailed process and I’ve had to boil it down to what I think is the essence of it because I want to leave space for Q&A. | 16:29 |
johnoxton | Suffice to say, the site will go live fairly soon and, once it does, we start listening and we start talking. | 16:29 |
johnoxton | When we launch, we consider it the beginning of something, not the end. This is when the UX processes really start to kick in. | 16:29 |
johnoxton | As I said, I am still fairly new to Canonical and still have to get to know the Ubuntu community better and I need to work out the best ways to collect qualitative feedback and turn it into something actionable. | 16:29 |
johnoxton | I will be talking this through with David, and others, as time goes on. | 16:30 |
johnoxton | My first step, though, is to try and plan a workshop at the upcoming UDS | 16:31 |
johnoxton | so we can investigate any issues that come up in detail, with the aim of coming up with some big themes on which to base future work as well as how we engage with developers in an ongoing discussion about *their* site. | 16:31 |
johnoxton | Meanwhile, I hope you will enjoy your new developer site and find it useful when it launches. | 16:31 |
johnoxton | You can see my notes here: http://pastebin.com/8wwHufVs | 16:31 |
johnoxton | Thank you. | 16:31 |
dpm | Awesome, thanks John | 16:32 |
dpm | Now you can see how much work is involved behind the planning and creating the concept of such a site | 16:32 |
dpm | I'll continue from here on. I see there is a question already, so I'll handle that | 16:33 |
dpm | in the meantime, if you've got any other questions so far, feel free to ask | 16:33 |
ClassBot | paglia_s asked: in some words how does quickly work? which languages does it support and which design library (gtk, qt...) ? | 16:33 |
dpm | well, the first thing to understand here is that quickly is just a wrapper | 16:34 |
dpm | quickly helps us adding the glue to all of the tools we've decided to recommend for developing in Ubuntu | 16:35 |
dpm | as such, quickly puts together python, gtk, debian packaging, bzr, launchpad and a few more | 16:36 |
dpm | so quickly is a command line tool that provides easy commands to perform actions which otherwhise would be more complicated | 16:37 |
dpm | in other words, it hides the complexity for the developer, who can then just worry about coding | 16:37 |
dpm | So just to give an example, to package an app, if you've started a project with quickly, in most cases running the 'quickly package' command will be enough | 16:38 |
dpm | rather than having to read tons of documentation and learn how to package | 16:38 |
ClassBot | tau141 asked: why does ubuntu recommend PyGtk for creating Applications? | 16:38 |
dpm | I was expecting that one :) | 16:39 |
dpm | There are many, many good technologies in the open source world and while that is an asset, we do want to make an opinonated choice on the tools we recommend | 16:40 |
dpm | Right now python + gtk + debian packaging are the best options to a) provide full integration with the Ubuntu Platform (talk unity, indicators, notification, etc) and b) support the application's full lifecycle | 16:41 |
dpm | we want to make it easy for developers to create their apps and publish them in the Software Center | 16:41 |
dpm | and for that, we cannot support all technologies and have to concentrate on one we recommend | 16:42 |
dpm | right now pygtk (or probably pygi in the near future) is the best option | 16:42 |
dpm | which does not mean that when other tools mature or provide better integration with the platform we will not review that choice | 16:43 |
dpm | so in short: that's the decision we've done now, but we will continue exploring the options that allow Ubuntu being the best platform of choice for app developers | 16:43 |
ClassBot | tomalan asked: The PyGTK-Project was cancelledin april, are you sure you don't mean the PyGobject-Introspection? | 16:44 |
dpm | good point. I mentioned just before that pygtk might need to be reworded to pygi in the near future :) | 16:44 |
dpm | afaik quickly has not yet been ported to use gobject introspection | 16:45 |
dpm | but it's just a minor detail, whenever it does, we'll make sure to update the site's wording | 16:45 |
dpm | ok, so if there are no more questions, let me continue with the rest of the session | 16:46 |
dpm | While John mentioned the next Ubuntu Developer Summit (UDS) and future plans, at the _last _ UDS we already devoted a session to discuss the developer site, | 16:46 |
dpm | and what you'll be seeing very soon is the result of that work, | 16:47 |
dpm | carried out mainly by the web design team with the help of many other folks at Canonical | 16:47 |
dpm | One thing I want to stress is that this is just the beginning | 16:47 |
dpm | The App Developer Site is just one part (and a key one) of the overall app developer strategy that we're fleshing out as we speak | 16:47 |
dpm | This cycle you'll have noticed many of the visible pieces coming together: | 16:48 |
dpm | * Jonathan Lange becoming the Developer Program Specialist, | 16:48 |
dpm | * the release of the MyApps online portal to streamline the process of submitting apps and get them published in the Software Centre, | 16:48 |
dpm | * more apps flowing into the Software Centre... | 16:48 |
dpm | You should definitely check out the log of Jonathan Lange's session last Monday | 16:49 |
dpm | where he delivered an overview of the vision and the strategy for app development in Ubuntu | 16:49 |
dpm | Also Anthony Lenton and Stéphane Graber talked about different aspects of submitting applications through MyApps last Tuesday | 16:49 |
dpm | You'll find it all here: https://wiki.ubuntu.com/UbuntuAppDeveloperWeek/Timetable | 16:49 |
dpm | And finally, to wrap up the topic with good coverage from all sides, John Pugh will talk about the business side, that is, | 16:49 |
dpm | how Canonical makes money from commercial applications to become a sustainable business and better support the development of Ubuntu | 16:50 |
dpm | In short, we want to put Ubuntu on the app development map. | 16:50 |
dpm | We want to provide a top level experience through a platform that makes it easy for developers to create applications and distribute them to millions. | 16:50 |
ClassBot | There are 10 minutes remaining in the current session. | 16:50 |
dpm | We're laying out a set of solid foundations for that goal, and we're going to build upon them | 16:50 |
dpm | Developer.ubuntu.com will be a place to present developers with a clear journey that will guide them through the process of creating and publishing applications for Ubuntu. | 16:50 |
dpm | Along the way, they will find all the resources that will enable them to make the right design decisions and direct them to the infromation they need in a clear and consistent manner. | 16:51 |
dpm | And another important purpose of the site will be to become the starting point to build an app developer community. | 16:51 |
dpm | As such, this upcoming release is what we could consider the first iteration of developer.ubuntu.com. | 16:52 |
dpm | By Oneiric's release we'll have a site that we can be proud to direct app developers to, with a place that not only is up to the Ubuntu design standards, | 16:52 |
dpm | but also to provide application developers the information they need to get started writing applications in Ubuntu. | 16:52 |
dpm | That is the primary goal of that iteration, but we are aware that this will not be enough, and that the site will need to evolve and to grow | 16:52 |
dpm | So we will need your help to use it, to participate with your feedback and be part of this effort to make Ubuntu the platform of choice for application development and distribution. | 16:53 |
dpm | And with this, I think that's all we wanted to cover | 16:54 |
dpm | I hope you found our presentation useful, and if you've got any questions, feel free to ask now | 16:54 |
dpm | we've still got a few minutes to answer a few | 16:54 |
ClassBot | There are 5 minutes remaining in the current session. | 16:55 |
ClassBot | tau141 asked: so we can help by using it and by givin our feedback! is there any other way to help? | 16:58 |
johnoxton | I think it would be really useful for those who are developing an app or have developed an app to write about their experiences | 16:59 |
johnoxton | or start writing tutorials and letting us know about them | 16:59 |
johnoxton | I think the resources/reference/documentation section would benefit hugely from content like this | 17:00 |
johnoxton | and of course when we go live | 17:00 |
johnoxton | look out for bugs and let us know! | 17:00 |
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || Event: App Developer Week - Current Session: Rapid App Development with Quickly - Instructors: mterry | ||
dpm | So if there are no more questions, the last bit is just to thank you for your participation and hope you've enjoyed the session! :-) | 17:00 |
ClassBot | Logs for this session will be available at http://irclogs.ubuntu.com/2011/09/08/%23ubuntu-classroom.html following the conclusion of the session. | 17:00 |
mterry | Hello, everyone! | 17:01 |
mterry | Thanks to dpm and johnoxton for the awesome session | 17:01 |
mterry | Mine piggybacks on that by giving more information about quickly | 17:01 |
mterry | I'm a maintainer of quickly and will give a brief overview of what it is, how to use it | 17:01 |
mterry | Please ask questions in the chatroom, I'll try to answer them | 17:02 |
mterry | So first, here's a link for the wiki page of quickly: https://wiki.ubuntu.com/Quickly | 17:02 |
mterry | Quickly is at its heart a templating system. It is designed to give a user a quick start of sample code and allow you to modify it easily and quickly(!) into a full program | 17:03 |
mterry | It has a lot of boiler plate code that gets you started, and commands to simplify common application tasks like packaging it up, saving to bzr, publishing to users in a PPA | 17:04 |
mterry | It's designed, as is developer.ubuntu.com, to make opinionated choices about technologies (which makes the task of teaching new users a lot easier -- just teach one thing) | 17:04 |
mterry | But since new quickly templates can be written, new sets of opinionated choices are easy too | 17:05 |
mterry | For example, someone might one day write a Kubuntu template, to make app dev on Kubuntu easier | 17:05 |
mterry | And lastly, quickly is supposed to make app dev on Ubuntu fun, by letting the user focus on the good stuff, not the boring administrative stuff | 17:06 |
mterry | In 11.04, we have four templates: ubuntu-application, ubuntu-cli, ubuntu-flash-game, ubuntu-pygame | 17:06 |
mterry | ubuntu-application is PyGTK based to make graphical apps | 17:06 |
mterry | ubuntu-cli is Python based for making command line apps | 17:06 |
mterry | ubuntu-flash-game is like it sounds, you drop a flash file into place and quickly handles the rest | 17:07 |
mterry | ubuntu-pygame is pygame based, which is a Python library for making games easy | 17:07 |
mterry | There was a question last session about why PyGTK and not GObject Introspection | 17:07 |
mterry | We'd like to use PyGI, but due to technical details (it's difficult to automatically guess dependencies then), we haven't made that jump yet | 17:08 |
mterry | Hopefully we will during the 12.04 cycle | 17:08 |
mterry | Our goals for 11.10 are rather modest, focusing just on some outstanding bugs | 17:08 |
mterry | OK, enough intro. Let's do something! | 17:09 |
mterry | You can install it easily enough by running: "sudo apt-get install quickly" | 17:09 |
mterry | This will install all sorts of programming goodies | 17:09 |
mterry | Once installed, try running "quickly create ubuntu-application test-project" | 17:10 |
mterry | The 'create' is the command to quickly to say "start a project", the 'ubuntu-application' tells which kind of project, and the last argument names the project | 17:10 |
mterry | You'll now have a folder called "test-project" with a bunch of files | 17:11 |
mterry | It will also open a window | 17:11 |
mterry | This is what your project looks like already! It has a window, menubar, etc | 17:11 |
mterry | This will all be easy to change, but it's a quick start, something to modify | 17:12 |
mterry | So why don't we try doing that | 17:12 |
mterry | We'll look into changing the UI a bit | 17:12 |
mterry | Run "quickly design" to open Glade, which is a graphical UI builder | 17:12 |
mterry | Using glade well is a whole 'nother talk, but if you have any questions, I'll be happy to answer them | 17:13 |
mterry | For now, just note that you can select things, change properties on the right, and add new widgets from the toolbox on the left | 17:13 |
mterry | Quickly automatically hooks your Glade UI files together with your code | 17:14 |
mterry | I'll give a brief overview of what you can do in Glade | 17:14 |
mterry | Layout in Glade (and in GTK in general) is done via Boxes (like VBox or HBox) that arrange them in rows or columns | 17:15 |
mterry | You can change a widget's position in a box in the properties dialog (2nd packing tab) | 17:15 |
mterry | The packing tab is where you can adjust a lot of the layout of a widget. The first tab is where you control specific widget functionality (like the text on a label, etc) | 17:16 |
mterry | OK, so enough Glade. | 17:16 |
mterry | I'll briefly mention here, to learn more about quickly, you can also run "quickly help" to get an overview of commands | 17:16 |
mterry | Or you can run "quickly tutorial" to get a more complete tutorial that you can walk through at your own pace | 17:17 |
mterry | That will walk you through creating a full app | 17:17 |
mterry | Back to my overview, another important command is "quickly add dialog dialog-name" | 17:18 |
mterry | Let's say you want to add a quit-confirmation dialog or something | 17:18 |
mterry | By running the above command, quickly will generate a new Glade file and a new Python file to handle any special code you may want for the dialog | 17:19 |
mterry | After running the command, you may want to close out Glade and reopen it with "quickly design" to open the new Glade file that you just created | 17:19 |
mterry | Now to use that new dialog from code, open your code with "quickly edit" | 17:20 |
mterry | This opens all your Python files in the gedit text editor | 17:20 |
mterry | You can open your new dialog from existing code by doing something as simple as "from project_name.DialogName import DialogName" | 17:21 |
mterry | Then creating new dialogs with DialogName() | 17:22 |
mterry | Another thing Quickly makes easy for you is signals | 17:22 |
mterry | Whenever a user clicks on a button, starts typing in a field, or closes a window, a signal is generated inside GTK | 17:23 |
mterry | If you want to run some code in response to an action, you need to add a signal handler in code | 17:23 |
mterry | Normally, this is a bit tricky to coordinate between Glade's files and Python's files | 17:23 |
mterry | But Quickly will automatically join widgets in Glade to Python code if you name your signal handler correctly | 17:24 |
mterry | Let's say you want to do something in response to a widget you named "button1" being clicked | 17:24 |
mterry | Open the widget window's Python file, and add a function called "on_button1_clicked(self, widget, data=None)" | 17:24 |
mterry | The trick is to name it on_WIDGETNAME_SIGNALNAME | 17:25 |
mterry | And Quickly will find it and join it up | 17:25 |
mterry | Another thing to note about Quickly is how your code is even organized | 17:25 |
mterry | I've talked about opening a window's Python file, but what does that mean? | 17:26 |
mterry | You'll have three subfolders in your project folder | 17:26 |
mterry | One is "bin", one is "project_name", and the last is "project_name_lib" | 17:26 |
mterry | Quickly 'owns' files in bin and project_name_lib | 17:26 |
mterry | 'bin' holds a wrapper that Quickly uses to find the rest of your files once it's installed on disk | 17:27 |
mterry | 'project_name_lib' holds a bunch of convenience boiler plate code that Quickly provides. But you shouldn't modify it, as Quickly may update that code on you | 17:27 |
mterry | The real goods are in the 'project_name' folder | 17:27 |
mterry | There you'll find a file with some utility code (like command line argument handling) and a file for each window in your project | 17:28 |
mterry | And a file for your preferences | 17:28 |
mterry | The wrapper will create ProjectWindow class, and that's the entry point to your program | 17:29 |
mterry | If you wanted to take an existing project and drop it into a Quickly shell project, or even wanted to start with a Quickly project but not really use any of the code, the only actual requirement is that you have a ProjectWindow class | 17:29 |
mterry | Once that code runs, you can do whatever you like | 17:30 |
mterry | Another thing Quickly does for you is use a logging framework | 17:30 |
mterry | You'll see existing code use log calls | 17:30 |
mterry | Run your project ("quickly run") in verbose mode ("quickly run -- --verbose") to see the log output | 17:31 |
mterry | When debugging, you can add new log calls (or just use plain old print statements) | 17:31 |
mterry | Another, more precise, method of debugging is to use the command line python debugger pdb | 17:32 |
mterry | Acts like gdb but for python | 17:32 |
mterry | I've not used it a bunch (print statements tend to be quicker and easier) | 17:32 |
mterry | But if you have a really tough bug, pdb can be a help | 17:32 |
mterry | OK, so let's say you have your app, version 1.0 | 17:33 |
mterry | You'll want to start being able to release it | 17:33 |
mterry | In general, there are three levels of testing a finished program: (1) locally, by the developer, (2) a wider, but still limited, group of testers, and (3) everyone (an actual release) | 17:34 |
mterry | Quickly will help with all 3 | 17:34 |
mterry | But before we create any packages at all, let's set up a bit of metadata about your project | 17:35 |
mterry | Add your name and email to the AUTHORS file that Quickly created for yu | 17:35 |
mterry | you | 17:35 |
mterry | Also define a license for your project with "quickly license BSD" or similar. | 17:35 |
mterry | GPL-3 is the default | 17:35 |
mterry | So no need to run anything if that suits you fine | 17:35 |
mterry | Open the project-name.desktop.in file in your project directory too | 17:36 |
mterry | It has a Categories line that you can edit to adjust where in the menu structure it will show up | 17:36 |
mterry | See defined categories here: http://standards.freedesktop.org/menu-spec/latest/apa.html | 17:36 |
mterry | And finally, edit setup.py in your project directory | 17:36 |
mterry | Near the bottom are some metadata bits like description, website, author name again | 17:37 |
mterry | With all that in place, let's make a package! | 17:37 |
mterry | For local testing by you yourself, "quickly package" will create a package | 17:37 |
mterry | It will create it in the directory above your project folder | 17:37 |
mterry | So install it with "sudo dpkg -i ../test-project_0.1_all.deb" or some such | 17:38 |
mterry | Then it should appear in your menu | 17:38 |
mterry | And be runnable from the Terminal with "test-project" | 17:38 |
mterry | Once you think it seems alright, you're ready to distribute to the rest of your testers | 17:38 |
mterry | This involves a PPA | 17:38 |
mterry | A Personal Package Archive | 17:39 |
mterry | In your Launchpad account, you can create new PPAs | 17:39 |
mterry | First you need SSH and GPG keys, explained in the Launchpad help: | 17:39 |
mterry | https://help.launchpad.net/YourAccount/CreatingAnSSHKeyPair | 17:39 |
mterry | https://help.launchpad.net/YourAccount/ImportingYourPGPKey | 17:39 |
mterry | Also set DEBEMAIL and DEBFULLNAME in .bashrc, the same as what was in your GPG key | 17:40 |
mterry | And then run ". ~/.bashrc" to pick up the new settings in your current Terminal | 17:40 |
mterry | (that's a period as a command) | 17:41 |
mterry | Just a bash trick to run a script in the current environment | 17:41 |
mterry | For instructions on actually creating a PPA: https://help.launchpad.net/Packaging/PPA | 17:41 |
mterry | Phew | 17:41 |
mterry | With that all set up, all you need to do to publish a new testing version of your project is "quickly share" | 17:42 |
mterry | This will package up your current code and put it in your PPA | 17:42 |
mterry | It will pick its own version (though you can provide one, see "quickly help share") | 17:42 |
mterry | The version used will be based on the last release | 17:43 |
mterry | It won't increment the actual version number, but just a version suffix | 17:43 |
mterry | Since it's just a testing package | 17:43 |
mterry | If you want to make a full release to the wider public, use "quickly release" | 17:44 |
mterry | It helps to have a project created in Launchpad and associated with your quickly project | 17:44 |
mterry | (use "quickly configure lp-project project-name" for that) | 17:44 |
mterry | Then Quickly can automatically make project release announcements for you | 17:45 |
ClassBot | dpm asked: I've been reading the quickly help, and I'm still not sure I get it: what's the difference between the 'quickly share' and 'quickly release' commands? | 17:45 |
mterry | So "share" uses a version suffix like -public1 | 17:46 |
mterry | It releases into your PPA, but that's it | 17:46 |
mterry | "release" will actually increment your main version number to something like 11.09 | 17:46 |
mterry | (These version changes can be overridden on the command line) | 17:47 |
mterry | Release will also, if a Launchpad project is associated, make a release announcement and close the milestone | 17:47 |
mterry | So there isn't *much* difference, more of a semantic one. Release just does a few thing extra | 17:48 |
mterry | I also recommend using different PPAs for "sharing" and "releasing" | 17:48 |
mterry | You can specify a ppa with "quickly share --ppa mterry/testing" for example | 17:48 |
mterry | That way, you can have a "testing" PPA and a "stable" PPA | 17:48 |
mterry | So it's good to get in the mental habit of thinking that there are two types of publishing | 17:49 |
mterry | One for testers, one for everyone | 17:49 |
mterry | I suppose there's one more level of publishing actually | 17:50 |
mterry | And that's to the Software Center | 17:50 |
mterry | Quickly has a few tools to help you prepare your app for the Software Center (whether it's a free or proprietary one) | 17:50 |
mterry | There is the "submitubuntu" command | 17:50 |
ClassBot | There are 10 minutes remaining in the current session. | 17:50 |
mterry | This will publish to a PPA just as "release" does | 17:51 |
mterry | But it will do some of the legwork to prepare the package for the App Review process | 17:51 |
mterry | Notably, it will install everything into /opt | 17:51 |
mterry | And it will set some bits of packaging metadata up like "where is the app screenshot" and such | 17:51 |
mterry | You can prepare a local deb with such changes by using "quickly package --extras" | 17:52 |
=== wangerin1 is now known as wangerin | ||
mterry | See https://wiki.ubuntu.com/AppReviews for more information about such requirements | 17:52 |
mterry | That's all I had prepared! | 17:53 |
mterry | I'm happy to answer Quickly questions if ya'll have any | 17:53 |
ClassBot | There are 5 minutes remaining in the current session. | 17:55 |
ClassBot | MDesigner asked: what resources do you recommend for learning Glade and Python, specifically geared toward Ubuntu/Unity development? | 17:56 |
mterry | Heh, well, the previous session was on developer.ubuntu.com | 17:56 |
mterry | That aims to be the answer to that question | 17:57 |
mterry | It already has some content, but it's hoped to flesh that out a bit | 17:57 |
mterry | For example, I'll be writing a tutorial for it on how to integrate Ubuntu One Files in your app using Python (I also have a talk on that tomorrow) | 17:57 |
mterry | For learning Python in general, Dive into Python is a great resource | 17:58 |
mterry | Google that and you'll get results | 17:58 |
mterry | I'm not sure there are great tutorials out there for Glade specifically | 17:58 |
mterry | For Unity integration, http://unity.ubuntu.com/ has some info. Like http://unity.ubuntu.com/projects/appindicators/ has links for documentation | 18:00 |
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || Event: App Developer Week - Current Session: Developing with Freeform Design Surfaces: GooCanvas and PyGame - Instructors: rickspencer3 | ||
ClassBot | Logs for this session will be available at http://irclogs.ubuntu.com/2011/09/08/%23ubuntu-classroom.html following the conclusion of the session. | 18:00 |
rickspencer3 | sooo | 18:02 |
rickspencer3 | hi everybody | 18:02 |
rickspencer3 | you just missed my best stff | 18:02 |
rickspencer3 | I was talking in teh wrong channel for the last 2 minutes :) | 18:03 |
rickspencer3 | so, let's try again ... | 18:03 |
rickspencer3 | Hello all. Today I will discuss 2 of the APIs that I have used to have a lot of fun with programming for Ubuntnu. | 18:03 |
rickspencer3 | These APIs are GooCanvas and PyGame. They are both similar in the sense that they provide you with a 2d surface on which you can construct interactive GUIs for your users. | 18:03 |
rickspencer3 | seriously, I have had tons of fun writing apps with thes over the years | 18:03 |
rickspencer3 | However, I fonud them to have different strengths and weaknesses. If you choose the correct API it will be more easy and more fun to write yoru app. | 18:04 |
rickspencer3 | so, why goocanvas or pygame at all? | 18:04 |
rickspencer3 | A typical desktop app is composed of widgets that a user is used to. Like buttons, entry boxes, and such. | 18:04 |
rickspencer3 | For these desktop apps, I strongly recommend sticking with PyGtk for the time being. | 18:04 |
rickspencer3 | like the next year, I think | 18:04 |
rickspencer3 | PyGtk is the way to go for what I call "boxy" apps | 18:05 |
rickspencer3 | I use pygtk all the time | 18:05 |
rickspencer3 | However, sometimes part of an app, or pretty much a whole app, won't need buttons and lists and entry boxes, but will need to display, modify, or animate images, drawings, etc... | 18:05 |
rickspencer3 | Sometimes in response to user input, sometimes not. | 18:05 |
rickspencer3 | My goal for this session is to help you choose the right API for those kinds of apps, and to get you started with them. | 18:05 |
rickspencer3 | please ask questions at any time | 18:05 |
rickspencer3 | I will check for questions often | 18:05 |
rickspencer3 | I'll start with GooCanvas because I already did a session on this last year, so there is lots of material. | 18:06 |
rickspencer3 | https://wiki.ubuntu.com/UbuntuOpportunisticDeveloperWeek/GooCanvas | 18:06 |
rickspencer3 | basically, I shall copy and past from there, answering quetsions as I go | 18:06 |
rickspencer3 | thoguh I may skip some to leave room for pygame | 18:07 |
rickspencer3 | So what is a goocanvas? | 18:07 |
rickspencer3 | A goocanvas is a 2d composing surface | 18:07 |
rickspencer3 | You can use it to make pretty much any kind of image | 18:07 |
rickspencer3 | It's kind of like an api around a drawing program | 18:08 |
rickspencer3 | So you can have a ton of fun using a goocanvas, because you are pretty much freed from the constraints of a widget library in creating your UI | 18:08 |
rickspencer3 | goocanvas is cairo under the covers | 18:08 |
rickspencer3 | and is designed to easily integrate into your gtk app | 18:08 |
rickspencer3 | So let's add a goocanvas to a pygtk app | 18:08 |
rickspencer3 | Add it just like a normal pygtk widget | 18:09 |
rickspencer3 | #set up the goo canvas | 18:09 |
rickspencer3 | self.goo_canvas = goocanvas.Canvas() self.goo_canvas.set_size_request(640, 480) self.goo_canvas.show() | 18:09 |
rickspencer3 | tada! | 18:09 |
rickspencer3 | you have a goocanvas | 18:09 |
rickspencer3 | Be sure to set the size, otherwise it defaults to 1000,1000, it does not default to the size alloted to it in your window. | 18:09 |
rickspencer3 | Handle window resizing to resize your goocanvas as well | 18:09 |
rickspencer3 | !! | 18:09 |
rickspencer3 | the goocanvas won't automatically change size if it's container changes size | 18:10 |
rickspencer3 | For example, if your goocanvas is in a VBox, you can do this: | 18:10 |
rickspencer3 | rect = self.builder.get_object("vbox2").get_allocation() self.goo_canvas.set_bounds(0,0,rect.width,rect.height) | 18:10 |
rickspencer3 | remember the root item for your goocanvas, you'll need it later often self.root = self.goo_canvas.get_root_item() | 18:10 |
rickspencer3 | The "root" is like the root of an item tree in XML | 18:10 |
rickspencer3 | So now that we have a goocanvas, we need to add "Items" to it. | 18:10 |
rickspencer3 | Anything that can be added to a goocanvas is an Item. It get's it's capabilities by inheriting from ItemSimple, and by implementing the Item interface. | 18:10 |
rickspencer3 | Let's add an item to the goocanvas to get a look at how it works in general. | 18:11 |
rickspencer3 | We'll start by adding an image. | 18:11 |
rickspencer3 | First, you need to get a gtk.pixbux for your image: | 18:11 |
rickspencer3 | pb = gtk.gdk.pixbuf_new_from_file(path) | 18:11 |
rickspencer3 | Then you calculate where you want the image to show on the goocanvas. You'll need a top and a left to place most items on a goo canvas. | 18:11 |
rickspencer3 | For example, to center the image, I do this: | 18:11 |
rickspencer3 | cont_left, cont_top, cont_right, cont_bottom = self.goo_canvas.get_bounds() img_w = pb.get_width() img_h = pb.get_height() img_left = (cont_right - img_w)/2 img_top = (cont_bottom - img_h)/2 | 18:11 |
rickspencer3 | it's a bit hard to read, I guess | 18:11 |
rickspencer3 | but I basically just calculated the pixel center of the goocanvas | 18:12 |
rickspencer3 | and stored the "bounds" that the calculation returned | 18:12 |
rickspencer3 | Now I am ready to create the item. | 18:12 |
rickspencer3 | Note that I create the Item, but there is nothing like goocanvas.add(item) rather, when you create the item, you set it's parent property. | 18:12 |
rickspencer3 | The parent property is the root of the goocanvas | 18:12 |
rickspencer3 | This is why I remember the root | 18:12 |
rickspencer3 | goocanvas.Image(pixbuf=pb,parent=self.root, x=img_left,y=img_top) | 18:12 |
rickspencer3 | This basic pattern is how you add all other types of items. | 18:13 |
rickspencer3 | decide where to put the item, and set it's parent property to the root of the goocanvas. | 18:13 |
rickspencer3 | To remove the item from the goocanvas, you don't tell the goocanvas to remove it | 18:13 |
rickspencer3 | rather you tell the item to remove itself | 18:13 |
rickspencer3 | item.remove() | 18:13 |
rickspencer3 | any questions at all so far? | 18:13 |
rickspencer3 | In a moment, I'll go on to discuss the types of things that you can add to a goocanvas | 18:14 |
rickspencer3 | In my mind, there are really 3 types of items | 18:14 |
rickspencer3 | normal items that you add to draw the stuff you want | 18:14 |
rickspencer3 | this includes: | 18:14 |
rickspencer3 | Ellipse, Image, Path, Polyline, Rect, and Text | 18:14 |
rickspencer3 | the second type is for layout | 18:15 |
rickspencer3 | Layout and gruop items include: | 18:15 |
rickspencer3 | Group, Grid, and Table | 18:15 |
rickspencer3 | then finally, | 18:15 |
rickspencer3 | there is also Widget. Widget is pretty cool. | 18:15 |
rickspencer3 | You can add a gtk widget to your goocanvas, but note that it will live in a world seperate from the goocanvas | 18:15 |
rickspencer3 | In other words, gtk.Widgets won't be rendered if you create images form our goocanvas and such | 18:15 |
rickspencer3 | However, this is a cool way to add in situ editing to your goocanvas | 18:15 |
rickspencer3 | We'll just be talking about normal items for the rest of this class though | 18:15 |
rickspencer3 | So what are some of the things that you do with an item? Well, you compose with it. So you scale it, move it, rotate it, change it's z-order and such | 18:15 |
rickspencer3 | For a lot of things that you want to do with an item, you use set_property and get_property | 18:16 |
rickspencer3 | For example, to set the a might make a Text item like this: | 18:16 |
rickspencer3 | txt = goocanvas.Text(parent=self.root,text="some text", x=100, y=100, fill_color=self.ink_color) | 18:16 |
rickspencer3 | then change the text in it like this: | 18:16 |
rickspencer3 | txt.set_property("text","new text") | 18:16 |
rickspencer3 | Let's look at colors for a moment. There are generally two color properties to work with, stork-color, and fill-color | 18:16 |
rickspencer3 | If you've ever used a tool ink inkscape, this will make sense you to | 18:16 |
rickspencer3 | for something like a rect, stroke-color is the outline of the rectangle, and fill-color is the inside of the rectangle | 18:16 |
rickspencer3 | any questions so far? | 18:17 |
rickspencer3 | okay, moving on | 18:17 |
rickspencer3 | You can move, rotate, resize, and skew items | 18:17 |
rickspencer3 | The APIs for doing this are intuitive, imho | 18:17 |
rickspencer3 | To grow something by 10% | 18:17 |
rickspencer3 | item.scale(1.1,1.1) | 18:17 |
rickspencer3 | And to shrink it a bit: | 18:17 |
rickspencer3 | item.scale(.9,.9) | 18:17 |
rickspencer3 | Note that the items always consider themeselves to be their original size and orientation, so doing this will cause an item to grow twice: item.scale(1.1,1.1) item.scale(1.1,1.1) | 18:18 |
rickspencer3 | Now, when you start rotating and skewing items, some pretty confusing stuff can start happening | 18:18 |
rickspencer3 | Essentially, an item tracks it's own coordinate system, and doesn't much care about the goocanvas's coordinate system | 18:18 |
rickspencer3 | So if you rotate an item, for example, the coordinate systems are totally out of whack | 18:18 |
rickspencer3 | So if you pass the x/ys to an item based on the canvas's coordinate system, it can get waaaay out of whack | 18:18 |
rickspencer3 | Fortunately, goocanvas has some functions on it that just do these transforms for me | 18:19 |
rickspencer3 | let's say I catch a mouse click event on an item | 18:19 |
rickspencer3 | and I want to know where on the item the click happened | 18:19 |
rickspencer3 | well, the click coordinate are reported in the goocanvas's coordinate system, so I need to do a quick calculation to determine where the click happened on the item: | 18:19 |
rickspencer3 | e_x, e_y = self.goo_canvas.convert_to_item_space(self.selected_item,event.x,event.y) | 18:19 |
rickspencer3 | 18:19 | |
rickspencer3 | so, I used all of these facilities and more to make Photobomb | 18:19 |
rickspencer3 | you can check out Photobomb if you want to see some of the things that you can do with a GooCanvas | 18:20 |
rickspencer3 | Photobomb is essentially an image editor | 18:20 |
rickspencer3 | that made it a good candidate for GooCanvas | 18:20 |
rickspencer3 | however, I've also written games | 18:20 |
rickspencer3 | and PyGame is a better API for that | 18:20 |
rickspencer3 | before I go on to PyGame, any questions on Googcanvas? | 18:21 |
rickspencer3 | GooCanvas* | 18:21 |
ClassBot | bUbu87 asked: how do you work with svg and gooCanvas? is there a simple way to load an svg to a canvas and keep it scaled all the time? | 18:21 |
rickspencer3 | indeed! | 18:21 |
rickspencer3 | there are shapes and paths that are all described with svg | 18:21 |
rickspencer3 | I've actually exported content from InkScape into a Goocanvas in the past | 18:22 |
rickspencer3 | let's look at paths and clipping for an example | 18:22 |
rickspencer3 | A path is essentially a "squiggle" | 18:22 |
rickspencer3 | It is defiened by a string that gets parsed into x,y coords, and then drawn with a bezier curve formula applied | 18:22 |
rickspencer3 | ^for those not totally familiar with svg | 18:22 |
rickspencer3 | here is a string that described a scribble: | 18:22 |
rickspencer3 | line_data = "M 4.0 4.0C4.0 4.0 5.0 4.0 5.0 4.0 5.0 4.0 6.0 4.0 6.0 3.0 10.0 1.0 13.0 2.0 9.0 15.0 6.0 36.0 28.0 11.0 28.0 11.0 29.0 11.0 33.0 12.0 33.0 15.0 32.0 19.0 27.0 51.0 27.0 53.0 27.0 54.0 27.0 54.0 27.0 54.0 36.0 49.0 37.0 49.0" | 18:22 |
rickspencer3 | then I can make a path out of this: | 18:22 |
rickspencer3 | path = goocanvas.Path(data=line_data, parent=self.root, line_width=self.ink_width, stroke_color=self.ink_color) | 18:22 |
rickspencer3 | so this will draw the path in the goocancas | 18:23 |
rickspencer3 | Now, a path is also useful because you can use it to clip another object | 18:23 |
rickspencer3 | You don't use a path object for this, just the string item.set_property("clip-path",line_data) | 18:23 |
rickspencer3 | shall I move on to PyGame? | 18:23 |
rickspencer3 | I put the Pygame notes here: | 18:24 |
rickspencer3 | https://wiki.ubuntu.com/UbuntuOpportunisticDeveloperWeek/PyGame | 18:24 |
rickspencer3 | PyGame is an API that is also for 2d surfaces. | 18:24 |
rickspencer3 | It is best for applications where there is a lot of updating of animation without user input (especially as it uses blitting). | 18:24 |
rickspencer3 | It has a set of baseclasses that make it easier to manage and change teh state of objects. | 18:24 |
rickspencer3 | It also has collision detection routines, which is very useful in game programming. | 18:24 |
rickspencer3 | So, net/net if you are doing something that is a game, or game-like, you're likely to want to use pygame, not GooCanvas | 18:25 |
rickspencer3 | pygame has fairly good reference documentation here: http://pygame.org/docs/ref/index.html | 18:25 |
rickspencer3 | There are also lots of tutorials available on the web. However, it's important to note that I use pygame a bit differently than they do in the typical tutorials. | 18:25 |
rickspencer3 | ^^WARNING WARNING^^ | 18:25 |
rickspencer3 | Tutorials typically have you create a pygame window to display you game in, and then create a loop with a pygame clock object. | 18:25 |
rickspencer3 | I don't do it this way anymore. Now I prefer to embed a pygame surface into a Gtk app. This has some benefits to me: | 18:25 |
rickspencer3 | I can use menus for the GUI for things like starting games, pausing etc... | 18:26 |
rickspencer3 | I can use dialog boxes for things like hight scores or collecting information from users | 18:26 |
rickspencer3 | If you try to do these things from within a pygame loop, the gtk.main lool clashes with your pygame loop, and everything is just really hard to use. | 18:26 |
rickspencer3 | So, for the approach I take, I have three samples that you can look at at your leisure: | 18:26 |
rickspencer3 | 1. sample_game code: | 18:26 |
rickspencer3 | http://bazaar.launchpad.net/~rick-rickspencer3/+junk/pygame-pygtk-example/view/head:/game.py | 18:26 |
rickspencer3 | blog posting: | 18:26 |
rickspencer3 | http://theravingrick.blogspot.com/2011/08/using-pygame-in-pygtk-app.html | 18:26 |
rickspencer3 | This is the simplest code that I could make to demonstrate how to embed pygame and handle input. | 18:27 |
rickspencer3 | 18:27 | |
rickspencer3 | 2. jumper: | 18:27 |
rickspencer3 | http://bazaar.launchpad.net/~rick-rickspencer3/+junk/jumper/view/head:/jumper/JumperWindow.py | 18:27 |
rickspencer3 | This is only slightly more complex. It show how animate a sprite by changing the image, and show collision detection and playing a sound. | 18:27 |
rickspencer3 | 18:27 | |
rickspencer3 | 3. smashies: | 18:27 |
rickspencer3 | http://bazaar.launchpad.net/~rick-rickspencer3/+junk/smashies/files/head:/smashies/ | 18:27 |
rickspencer3 | This is a full blown game which I have almost completed. I'm considering selling it in the software center when I am done. This one handles all the complexity of lives, scores, pausing, etc... | 18:27 |
rickspencer3 | 18:27 | |
rickspencer3 | smashies is essentially an asteroids clone | 18:27 |
rickspencer3 | I'm stilling thinking of a good name, and I need to replace some artwork | 18:27 |
rickspencer3 | anywho ... | 18:28 |
rickspencer3 | For this tutorial, we'll focus on jumper since it has an animated Sprite. | 18:28 |
rickspencer3 | before I dive in, any general questions about PyGame? | 18:28 |
rickspencer3 | okee let's go | 18:28 |
rickspencer3 | The overall approach is simple | 18:28 |
rickspencer3 | 1. set up a drawing area in Gtk Window | 18:28 |
rickspencer3 | 2. add pygame sprites to it | 18:29 |
rickspencer3 | 3. handle keyboard input from the gtk window | 18:29 |
rickspencer3 | 4. periodically call an update function to: | 18:29 |
rickspencer3 | a. update the data for the sprites | 18:29 |
rickspencer3 | b. update the view | 18:29 |
rickspencer3 | c. detect collisions and respond to them | 18:29 |
rickspencer3 | A game typically needs a background image. I put a background image and the other images and sounds in the data/media directory. Once you get the background image painting, it means you've got the main part of the game set up. So, we'll go through this part with patience. | 18:30 |
rickspencer3 | ^note that jumper is a Quickly app | 18:30 |
rickspencer3 | I put all the code in JumperWindow, so it's easy to see in one place. | 18:30 |
rickspencer3 | let's start making it work | 18:30 |
rickspencer3 | You need to import 3 modules: | 18:30 |
rickspencer3 | import pygame | 18:30 |
rickspencer3 | import os | 18:30 |
rickspencer3 | import gobject | 18:30 |
rickspencer3 | You'll see why you need these each in turn. | 18:31 |
rickspencer3 | First we want to create a a pygame.Image object to hold the background. Once we have that, we can use pygame functions to paint it. | 18:31 |
=== Odd-rationale_ is now known as Odd-rationale | ||
rickspencer3 | Since Jumper is a Quickly app, it I can use "get_media_file" to load it. | 18:31 |
rickspencer3 | I mean load it from the disk | 18:31 |
rickspencer3 | So I make the background in these 2 lines of code in the finish_initializing function: | 18:31 |
rickspencer3 | bg_image = get_media_file("background.png") | 18:31 |
rickspencer3 | self.background = pygame.image.load(bg_image) | 18:31 |
rickspencer3 | Before I use it, I have to set up the pygame environment though. I do this by adding a gtk.DrawingArea to the gtk.Window, and telling the os module to use the windows xid as a drawing surface. | 18:31 |
rickspencer3 | You can't just do that in the finish_initializing function, though. This is because drawingarea1 may not actually have an xid yet. This is easy to handle by connecting to the drawing area's "realize" signal. At that point, it will have an xid, and you can set up the environment. | 18:32 |
rickspencer3 | basically, you need to make sure that the drawingarea has been put on the screen, otherwise, it has no xid | 18:32 |
rickspencer3 | So, connect to the signal in finish initalizing: | 18:32 |
rickspencer3 | self.ui.drawingarea1.connect("realize",self.realized) | 18:32 |
rickspencer3 | and then write the self.realized function: | 18:32 |
rickspencer3 | def realized(self, widget, data=None): | 18:32 |
rickspencer3 | os.putenv('SDL_WINDOWID', str(self.ui.drawingarea1.window.xid)) | 18:32 |
rickspencer3 | pygame.init() | 18:32 |
rickspencer3 | pygame.display.set_mode((300, 300), 0, 0) | 18:32 |
rickspencer3 | self.screen = pygame.display.get_surface() | 18:32 |
rickspencer3 | This function intializes pygame, and also create a pygame.Screen object that you need for drawing. | 18:33 |
rickspencer3 | so now we have a Gtk.DrawingArea ready to be a PyGame surface | 18:33 |
rickspencer3 | any questions before I show how to put the game background on it? | 18:33 |
rickspencer3 | ok, moving on | 18:34 |
rickspencer3 | So now that the drawing area is set up as a pygame surface, we need to actually draw to it. | 18:34 |
rickspencer3 | Actually, we'll want to periodically update the drawing so that it appears animated. So we want to update it over and over again. | 18:35 |
rickspencer3 | So after setting up pygame in tghe realized function, add a gobject timeout to recurringly call a function to update the game: | 18:35 |
rickspencer3 | gobject.timeout_add(200, self.update_game) | 18:35 |
rickspencer3 | the funciton update_game will be called every 200 millliseconds. For a real game, you might want to make it update more often. | 18:35 |
rickspencer3 | So, now we need write the udpate_game function. Eventually it will do a lot more, but for now, it will just tell the game to draw. So we need to write the draw_game function as well. | 18:35 |
rickspencer3 | def update_game(self): | 18:35 |
rickspencer3 | self.draw_game() | 18:35 |
rickspencer3 | return True | 18:35 |
rickspencer3 | def draw_game(self): | 18:35 |
rickspencer3 | self.screen.blit(self.background, [0,0]) | 18:35 |
rickspencer3 | pygame.display.flip() | 18:35 |
rickspencer3 | Note that update_game returns True. This is important, because if it returns anything else, gobject will stop calling it. | 18:35 |
rickspencer3 | Looking at draw_game a little more, the first line tells the Screen object to "blit" the background. This means to only update the parts that have changed. | 18:36 |
rickspencer3 | This keeps the game from flickering on slower systems. We also pass in x/y coordinates to tell it to update the whole background. | 18:36 |
rickspencer3 | This doesn't paint to the screen yet, though. It just prepares it in memory. | 18:36 |
rickspencer3 | You can call blit a whole bunch of times for different sprites, but until you call pygame.display.flip() they won't actually be painted to the screen. | 18:36 |
rickspencer3 | In this way, the screen only gets update once, and the animation is smooth. | 18:36 |
rickspencer3 | Now if you run the game, you should see the background painted. | 18:37 |
rickspencer3 | before I go on to animating a sprite, any questions? | 18:37 |
* rickspencer3 drums fingers | 18:37 | |
* rickspencer3 scratches head | 18:38 | |
* rickspencer3 twiddles thumbs | 18:38 | |
rickspencer3 | ok | 18:38 |
rickspencer3 | At this point you have a drawing surface set up, and you are drawing to it in a loop. | 18:38 |
rickspencer3 | Now let's add an animated sprite. | 18:38 |
rickspencer3 | I put 2 png's in the data/media director. One called "guy1.png" and called "guy2.png". We will animate the game by swapping these images back and forth every time the game paints. | 18:38 |
rickspencer3 | WARNING: I am doing something very wrong! | 18:38 |
rickspencer3 | Jumper loads the images as needed from disk. In a real game, this is a bad idea. This is a bad idea because that takes IO time, which can slow the game down. | 18:38 |
rickspencer3 | DON'T DO IT THIS WAY!!! | 18:39 |
rickspencer3 | It's better to load all the images and sounds at once when the game loads. See smashies for how I do that in the __init__.py file. | 18:39 |
rickspencer3 | anyway | 18:39 |
rickspencer3 | I mentioned before that pygame has some useful base classes. One of those base classes is called "Sprite" which is a really old game programming term. | 18:39 |
rickspencer3 | When adding an object to your game, it's best to derive from sprite. It's easier to manage the data for a sprite that way, and also there are useful pygame functions that expect a Sprite object. | 18:39 |
rickspencer3 | So, first create the sprite class and an initialization function: | 18:39 |
rickspencer3 | class Guy(pygame.sprite.Sprite): | 18:39 |
rickspencer3 | def __init__(self): | 18:39 |
rickspencer3 | pygame.sprite.Sprite.__init__(self) | 18:39 |
rickspencer3 | self.animation_stage = 1 | 18:39 |
rickspencer3 | self.x = 35 | 18:39 |
rickspencer3 | self.y = 180 | 18:39 |
rickspencer3 | self.direction = 0 | 18:39 |
rickspencer3 | Next, we'll write a function called "update". You'll see in a bit why it's important to call it "update". | 18:40 |
rickspencer3 | For this function, check which animation stage to use, and then use that image: | 18:40 |
rickspencer3 | def update(self): | 18:40 |
rickspencer3 | img = get_media_file("""guy%i.png""" % self.animation_stage) | 18:40 |
rickspencer3 | self.image = pygame.image.load(img) | 18:40 |
rickspencer3 | ^remember don't do it like this | 18:40 |
rickspencer3 | ^load the image from disk once at the beginning fo the program | 18:40 |
rickspencer3 | Next, you need to set the "rect" for the Sprite. The rect will be used in any collision detection functions you might use: | 18:40 |
rickspencer3 | self.rect = self.image.get_rect() | 18:40 |
rickspencer3 | self.rect.x = self.x | 18:40 |
rickspencer3 | self.rect.y = self.y | 18:40 |
rickspencer3 | Finally, update the animation stage. | 18:41 |
rickspencer3 | self.animation_stage += 1 | 18:41 |
rickspencer3 | if self.animation_stage > 2: | 18:41 |
rickspencer3 | self.animation_stage = 1 | 18:41 |
rickspencer3 | Now you just need to a "Guy" to your background. | 18:41 |
rickspencer3 | First, create a guy in the finish_initializing function. | 18:41 |
rickspencer3 | self.guy = Guy() | 18:41 |
rickspencer3 | Since a game will have a lot of sprites, it's easiest to manage sprites as a group | 18:41 |
rickspencer3 | There is a pygame class for this called a SpriteGroup, which you create by called RenderUpdates. | 18:41 |
rickspencer3 | So, crate a SpriteGroup and the guy to it: | 18:41 |
rickspencer3 | self.sprites =pygame.sprite.RenderUpdates() | 18:41 |
rickspencer3 | self.sprites.add(self.guy) | 18:41 |
rickspencer3 | Remember when we created the update_game function? | 18:42 |
rickspencer3 | Now you can see how useful the SpriteGroup is. | 18:42 |
rickspencer3 | You can call "update" on the sprite group, and it will in turn call update on every sprite in it. So add that call to the update_game function: | 18:43 |
rickspencer3 | self.sprites.update() | 18:43 |
rickspencer3 | Now, you also need to tell the Guy to draw. That's easy too with the SpriteGroup. Add this line to draw_game function: | 18:43 |
rickspencer3 | self.sprites.draw(self.screen) | 18:43 |
rickspencer3 | Now when you run the game, each tick the guy will swap images, and it will look like it's moving. | 18:43 |
* rickspencer3 phew | 18:43 | |
rickspencer3 | ok, almost done | 18:44 |
rickspencer3 | any questions? | 18:44 |
rickspencer3 | WARNING | 18:44 |
rickspencer3 | Note that I handle keyboard and mouse input very differently than they describe in most pygame tutorials | 18:44 |
rickspencer3 | Responding to keyboard input is really easy, because you can just use gtk events. | 18:44 |
rickspencer3 | I have found that you need to attach to the key events for the window, not the drawing area. | 18:44 |
rickspencer3 | So, to make the guy jump when the user clicks the space bar, I make a key_press_event signal handler, that calls "jump()" on the guy: | 18:45 |
rickspencer3 | def key_pressed(self, widget, event, data=None): | 18:45 |
rickspencer3 | if event.keyval == 32: | 18:45 |
rickspencer3 | self.guy.jump() | 18:45 |
rickspencer3 | You can look at the jump and update functions in the Guy class to see how a jump was implemented. | 18:45 |
rickspencer3 | you can track mouse events, key up events, etc.. this way too | 18:45 |
rickspencer3 | Pygame also has functions for joysticks and stuff, but I haven't used that | 18:46 |
rickspencer3 | So, that's the essence of creating an animated sprite, which gets you a lot of the way toward making a game. | 18:46 |
rickspencer3 | We don't have time to delve into everything, but I did want to touch on collisions. | 18:46 |
rickspencer3 | Assuming that you've added another sprite called self.apple that tries to hit the guy, you can use one of the many pygame collision detection functions in every call to update_game to see if the apple hit the guy: | 18:46 |
rickspencer3 | if pygame.sprite.collide_rect(self.guy,self.apple): | 18:46 |
rickspencer3 | self.guy.kill() | 18:46 |
rickspencer3 | BELIEVE ME | 18:46 |
rickspencer3 | you don't want to write your own collision detection routines | 18:46 |
rickspencer3 | there are lots of good functions | 18:47 |
rickspencer3 | ones that compare whole groups of sprites, for example | 18:47 |
rickspencer3 | If you set the rect for your Sprite subclass, functions like this work well, and are easy. | 18:47 |
rickspencer3 | I also mentioned sounds. | 18:47 |
rickspencer3 | Pygame has a really rich set of sound functions. | 18:47 |
rickspencer3 | The easiest thing to demo is playing a sound from a file, like this: | 18:47 |
rickspencer3 | sound_path = get_media_file("beep_1.wav") | 18:47 |
rickspencer3 | sound = pygame.mixer.Sound(sound_path) | 18:47 |
rickspencer3 | sound.play() | 18:47 |
rickspencer3 | .... | 18:48 |
rickspencer3 | and | 18:48 |
rickspencer3 | that's everything I prepared for this session | 18:48 |
rickspencer3 | I'm happy to take some questions | 18:48 |
rickspencer3 | or maybe everyone is busy playing smashies right now | 18:48 |
ClassBot | There are 10 minutes remaining in the current session. | 18:50 |
rickspencer3 | thanks ClassBot | 18:51 |
ClassBot | There are 5 minutes remaining in the current session. | 18:55 |
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || Event: App Developer Week - Current Session: Making your app appear in the Indicators - Instructors: tedg | ||
ClassBot | Logs for this session will be available at http://irclogs.ubuntu.com/2011/09/08/%23ubuntu-classroom.html following the conclusion of the session. | 19:00 |
tedg | Howdy folks. | 19:01 |
tedg | My name is Ted and I work at the Canonical Desktop Experience team. | 19:02 |
tedg | Specifically I work with the various indicators, I like to joke that "I control the upper right corner of your screen" ;-) | 19:02 |
tedg | But, that's really not the case. | 19:02 |
tedg | Really what we do is expose the functionality that is in the system to the user. | 19:03 |
tedg | *and* probably more importantly, the information that comes from applications. | 19:03 |
tedg | This session is about getting that information out of the applications and handing it up to the indicators. | 19:03 |
tedg | We're going to cover quickly a few different ways, and then I'll take questions as long as you guys have 'em to go more in depth. | 19:04 |
tedg | Specifically, I'm going to cover messaging menu, application indicator and the sound menu. | 19:04 |
tedg | So, let's get started. | 19:04 |
tedg | I'm going to start with the messaging menu because it's the oldest (and I couldn't figure out any other ordering that made sense) | 19:05 |
tedg | The spec for the messaging menu is here: https://wiki.ubuntu.com/MessagingMenu | 19:05 |
tedg | I think what makes the most sense to look there is at the rationale. | 19:05 |
tedg | It's a menu that is designed to handle human-to-human communication in an aggregated way. | 19:05 |
tedg | It's like you communicate with people in a variety of ways, but not all of those need icons on your panel. | 19:06 |
tedg | So if you're looking at an application that does that, how do you integrate? | 19:06 |
tedg | You use libindicate, which allows your application to indicate on dbus that you have messages. | 19:06 |
tedg | libindicate hides all the dbus stuff, so you don't need to worry about that, it's more about representing the info you have. | 19:07 |
tedg | So where is it? The source for the library itself is at http://launchpad.net/libindicate | 19:07 |
tedg | It has both the client and the server, but chances are you'll only need one of those. | 19:07 |
tedg | And that's the server. | 19:07 |
tedg | The client is used by the menu itself, and put into a single library so they always remain consistent | 19:08 |
tedg | Let's look at an example in Python: http://bazaar.launchpad.net/~indicator-applet-developers/libindicate/trunk/view/head:/examples/im-client.py#L58 | 19:08 |
tedg | This is a simple "IM Client" | 19:08 |
tedg | thought it really only makes a single entry in the messaging menu. | 19:09 |
tedg | And it tells the messaging menu that it's really Empathy. | 19:09 |
tedg | I don't recommend lying in your code :-) | 19:09 |
tedg | As we look at that example you can see that the code grabs the default server and sets some properties on it. | 19:10 |
tedg | The most significant here is the desktop file as we use that to get a bunch of information like the icon and name of the application out of there. | 19:10 |
tedg | Your application probably already has a desktop file, just throw the path to it in there. | 19:10 |
tedg | Then it creates an indicator. These are the items under your application in the messaging menu. | 19:11 |
tedg | This one is a time based one as you see the time gets set there. | 19:11 |
tedg | But there can also be count based for applications like e-mail programs that have mailboxes. | 19:11 |
tedg | There are design guide lines for how various applications should integrate. | 19:12 |
tedg | https://wiki.ubuntu.com/MessagingMenu#How_applications_should_integrate_with_the_messaging_menu | 19:12 |
tedg | Obviously that doesn't cover all applications, but it should be enough to get you started. | 19:12 |
tedg | You can also set properties like whether the envelope changes color or not as well. | 19:13 |
tedg | And sort the various items. | 19:13 |
tedg | There is also the ability to put custom menu items on the menu, but I'm not going to go into that today unless there are some questions. | 19:14 |
tedg | Second up is application indicators. | 19:14 |
tedg | You can find out some about the design of those guys here: https://wiki.ubuntu.com/DesktopExperienceTeam/ApplicationIndicators | 19:14 |
tedg | And a bit about their rationale. | 19:15 |
tedg | One of the things that they're targeting is allowing applications that are long running and need to put status of some type on the panel, to do so in a consistent way. | 19:15 |
tedg | The way that we've chose is an icon (possibly with a label) and a menu. | 19:15 |
tedg | This allows the entire top of the screen to behave like a menu bar. | 19:16 |
tedg | Application indicators are based on the KDE Status Notifier Item spec, but to create one you can just use libappindicator. | 19:16 |
tedg | http://launchpad.net/libappindicator/ | 19:17 |
tedg | This is a small library that implements the KSNI spec over dbus and provides an easy way to support it in your application. | 19:17 |
tedg | It also provides an internal fallback to using the status area on desktops that don't support KSNI. | 19:17 |
tedg | So you don't have to do that fallback in your application manually. | 19:17 |
tedg | For those who are already familiar with libappindicator, we've got some new features this cycle. | 19:18 |
=== tyler is now known as Guest71989 | ||
tedg | First off, it's now it's own library. Which will hopefully ease its adoption by other distros. | 19:18 |
tedg | There's no need to pull in the entire indicator stack just for providing libappindicator. | 19:19 |
tedg | We're also supporting actions on middle click. | 19:19 |
tedg | This is a tricky one, as we don't want to create undiscoverable functionality. | 19:19 |
tedg | So what we've done is allow for a menu item that's already in the menu to be specified to receive middle click events. | 19:19 |
tedg | This way that functionality is always available, and visible, to the user. | 19:20 |
tedg | But power users can get some quick access to it if they choose. | 19:20 |
tedg | We have some design guidlines for the app indicators. | 19:20 |
tedg | https://wiki.ubuntu.com/CustomStatusMenuDesignGuidelines | 19:20 |
tedg | The important thing to remember, is that app indicators aren't the end all be all of what you want. | 19:21 |
tedg | There's been a long tradition in computing of doing stuff like this for every application, but that doesn't mean it's right :-) | 19:21 |
tedg | We'd love it if people would integrate with the other category indicators (messaging, sound, etc.) before building their own. | 19:21 |
tedg | Also, for many applications, launcher integration makes more sense. | 19:21 |
tedg | (I believe Jason just talked about that, no?) | 19:22 |
tedg | So remember all of those options before you choose an applicaiton indicator | 19:22 |
tedg | Now, if you do, it's easy to do :-) | 19:22 |
tedg | Here's a simple client, that does everything possible (except middle click) http://bazaar.launchpad.net/~indicator-applet-developers/libappindicator/trunk/view/head:/example/simple-client-vala.vala | 19:23 |
tedg | Now it's a bit more complex than you need really. | 19:23 |
tedg | As it has dynamic items and changes status, but it does show you the full spectrum of possibilities. | 19:23 |
tedg | There's a C version as well | 19:24 |
tedg | http://bazaar.launchpad.net/~indicator-applet-developers/libappindicator/trunk/view/head:/example/simple-client.c | 19:24 |
tedg | The most important part is here: | 19:24 |
tedg | http://bazaar.launchpad.net/~indicator-applet-developers/libappindicator/trunk/view/head:/example/simple-client.c#L160 | 19:24 |
tedg | Where it creates the new object. | 19:24 |
tedg | It has a name and an icon. | 19:24 |
tedg | And a category. | 19:25 |
tedg | Then you build up a standard GTK menu, and you set it here: http://bazaar.launchpad.net/~indicator-applet-developers/libappindicator/trunk/view/head:/example/simple-client.c#L226 | 19:25 |
tedg | Your menu doesn't need to be as long. | 19:25 |
tedg | But it's neat to see the things you can do there. | 19:25 |
tedg | As far as signals go, you can just attach to the standard GTK ones on the menu items. | 19:25 |
tedg | libappindicator will synthesize them for you. | 19:26 |
tedg | So there's nothing to learn other than standard GTK menus. | 19:26 |
tedg | So while the example is longer, there's only those two critical spots. | 19:27 |
tedg | Okay, just checking my notes... think I got everything :-) | 19:27 |
tedg | Last up is the newest in our bunch, the sound menu. | 19:28 |
tedg | The sound menu takes care of all your sound related stuff. | 19:29 |
tedg | Again it uses a standard protocol, MPRIS, but we've provided a smaller library that implements the critical functionality. | 19:29 |
tedg | In this case, it is a couple of interfaces in libunity. | 19:29 |
tedg | http://launchpad.net/libunity | 19:29 |
tedg | There's no need for you to learn DBus or MPRIS, you can ust use the MusicPlayer interface there. | 19:30 |
tedg | http://bazaar.launchpad.net/~unity-team/libunity/trunk/view/head:/src/unity-sound-menu.vala#L61 | 19:30 |
tedg | It provides your basic setting of playlists and getting signals for play/pause/next/prev type controls. | 19:30 |
tedg | So as soon as you set up one of those objects, your application will get a full music player control in the sound menu. | 19:31 |
tedg | Just like Rhythmbox or Banshee. | 19:31 |
tedg | It doesn't matter if you're getting the sound off the web, or local files, or how you get the music. | 19:31 |
tedg | That's up to you :-) | 19:31 |
tedg | Let's look at an example | 19:32 |
tedg | here's a "TypicalPlayer" object | 19:32 |
tedg | http://bazaar.launchpad.net/~unity-team/libunity/trunk/view/head:/test/vala/test-mpris-backend-server.vala#L23 | 19:32 |
tedg | You can see how it sets the metadata for the song | 19:32 |
tedg | And even the album art | 19:33 |
tedg | And create a playlist as well. | 19:33 |
tedg | The typical player then sets up signals for the various buttons. | 19:33 |
tedg | This is part of the test suite, so it doesn't implement all of the backend for this. | 19:33 |
tedg | But it provides a good show of how you can connect into the object. | 19:34 |
tedg | You'll also see on line 56: http://bazaar.launchpad.net/~unity-team/libunity/trunk/view/head:/test/vala/test-mpris-backend-server.vala#L56 | 19:34 |
tedg | That it builds a small menu for custom items like setting your preference for the song. | 19:34 |
tedg | This can help with something like a Pandora client, where we want more information quickly available to the user. | 19:34 |
tedg | These are standard menu items so you can make them check boxes, radio buttons, or what ever you wish. | 19:35 |
tedg | There's not a whole lot of magic there, but that's largely because libunity takes care of all of that for you :-) | 19:35 |
tedg | Lastly, I wanted to talk about the TODO list a little if this interested you but you didn't have an application specifically that you wanted to work on. | 19:36 |
tedg | One of the big things that we did in this cycle was ensure that we had GObject Introspection bindings for all the indicator libs. | 19:36 |
tedg | We'd like to drop all the hand coded ones. | 19:37 |
tedg | But to do that we need all the applications currently using them in non-C languages to port over. | 19:37 |
tedg | So if you're interested in helping out, we'd love some help there. | 19:37 |
tedg | Also, we need to port the various examples over to using the GI bindings. | 19:37 |
tedg | To make it easier for new people coming in to using them. | 19:38 |
tedg | So, that's the end of my notes on the various ways for applications to integrate with the indicators. | 19:38 |
tedg | I hope that gives everyone a good introduction to the possibilities | 19:39 |
tedg | Does anyone have questions or want me to dive deeper into any of the topics? | 19:39 |
tedg | Great! Thanks everyone. | 19:41 |
tedg | Come grab me in #ayatana if you think of anything later | 19:42 |
ClassBot | There are 10 minutes remaining in the current session. | 19:50 |
ClassBot | There are 5 minutes remaining in the current session. | 19:55 |
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || Event: App Developer Week - Current Session: Will it Blend? Python Libraries for Desktop Integration - Instructors: conscioususer | ||
ClassBot | Logs for this session will be available at http://irclogs.ubuntu.com/2011/09/08/%23ubuntu-classroom.html following the conclusion of the session. | 20:00 |
* conscioususer clears throat | 20:01 | |
conscioususer | Hi folks! | 20:01 |
conscioususer | My name is Marcelo Hashimoto and I am the developer of Polly, a Twitter client designed for multiple columns of multiple accounts. (https://launchpad.net/polly) | 20:01 |
conscioususer | Polly is being written in Python, with the GTK+ toolkit for the graphical interface, and uses many libraries commonly present in Ubuntu applications. | 20:01 |
conscioususer | This session is not about Polly itself, but about some of those libraries and their underlying concepts. | 20:02 |
conscioususer | In particular, libraries that help you to integrate your application with the desktop. | 20:02 |
conscioususer | === DESKTOP INTEGRATION | 20:02 |
conscioususer | So what exactly do I mean by "desktop integration"? | 20:02 |
conscioususer | Informally, it is simply the noble attitude of "playing nice with others around you". :) | 20:03 |
conscioususer | When you develop an application, you must always remember that it will not be used in a completely independent way. | 20:03 |
conscioususer | It will be used as part of a big ecosystem. | 20:03 |
conscioususer | So it is important to blend well inside this ecosystem, to minimize the amount of different behaviors that the end user needs to learn. | 20:03 |
conscioususer | In Ubuntu this means striving for two things: | 20:03 |
=== bUbu87 is now known as black_puppydog | ||
conscioususer | - consistency between different applications in a desktop environment | 20:04 |
conscioususer | - consistency across different desktop environments | 20:04 |
conscioususer | Ubuntu, by default, uses the GNOME environment with Unity. But alternatives like KDE and XFCE are one click away in the Software Center. | 20:04 |
conscioususer | So you should not forget the users who prefer these alternatives. | 20:04 |
conscioususer | And it's important to emphasize that, when I talk about consistency, I'm *not* only talking about visuals! In fact, visuals are only a small part of this presentation. | 20:04 |
conscioususer | Everything will be clearer when I start giving concrete examples, so let's get on with it. :) | 20:05 |
conscioususer | === PRELIMINARIES | 20:05 |
conscioususer | Before starting, please download the tarball in http://ubuntuone.com/p/1Gzy/ | 20:05 |
conscioususer | (for those reading the transcript, I'll keep the tarball online, no worries) | 20:06 |
conscioususer | This tarball has some images I will reference here, and a text file with references that I will cite with [NUMBER]. | 20:06 |
conscioususer | Those references are not meant to be read now, only later if you are interested in more information. | 20:06 |
conscioususer | There are also some Python files that will not be used directly, but are there for you to play and modify as you want after the session. | 20:06 |
conscioususer | The hands-on during the session will be on the Python interactive shell (simply execute "python" in the terminal and you will be on it) | 20:06 |
conscioususer | Commands to be given to the shell will be prefixed by >>> | 20:07 |
conscioususer | === OVERVIEW | 20:07 |
conscioususer | The session is divided in three parts, each one answering a question that inevitably arises in many applications: | 20:07 |
conscioususer | 1 - "How do I send notifications to the user?" | 20:07 |
conscioususer | 2 - "Where do I place files read or written by my application?" | 20:07 |
conscioususer | 3 - "What do I use to store sensitive information?" | 20:08 |
conscioususer | and answering, of course, in a way that strives to blend well with the desktop that the user is currently using. | 20:08 |
conscioususer | Like I mentioned before, some of you might be surprised with those topics, because the word "integration" is usually associated with visuals. | 20:08 |
conscioususer | But the truth is, if you use one of the most widely used toolkits, like Qt and GTK, visuals are almost a non-issue nowadays thanks to the efforts of the developers of those toolkits. | 20:08 |
conscioususer | If you open the images (warning: shameless self-promotion coming) | 20:09 |
conscioususer | polly-ubuntu-unity.png | 20:09 |
conscioususer | polly-ubuntu-shell.png | 20:09 |
conscioususer | polly-ubuntu-kubuntu.png | 20:09 |
conscioususer | polly-ubuntu-xubuntu.png | 20:09 |
conscioususer | you will see Polly visually integrated with four different environments (GNOME+Unity, GNOME-Shell, KDE and XFCE) | 20:09 |
conscioususer | I did not write a single line of code that had the specific goal of reaching this visual integration. | 20:10 |
conscioususer | Those four environments simply know what to do with GTK applications. | 20:10 |
conscioususer | So visuals will not be the main focus. | 20:10 |
conscioususer | All that said, the first part does have *some* visual elements involved. | 20:11 |
conscioususer | Any questions so far? | 20:11 |
conscioususer | Ok, so let's begin! | 20:12 |
conscioususer | === PART 1: HOW DO I SEND NOTIFICATIONS TO THE USER? | 20:12 |
conscioususer | I'm going to start with a quick hands-on example, and explain the concepts involved later. | 20:13 |
=== narfnarf is now known as dingens | ||
conscioususer | For this part, you need to have the package gir1.2-notify-0.7 installed. | 20:13 |
conscioususer | This package comes in a default Natty/Oneiric install, actually. | 20:13 |
conscioususer | If you don't, do "sudo apt-get install gir1.2-notify-0.7" | 20:13 |
conscioususer | And those of you who attended Dmitry Shachnev's session yesterday are already familiar with the Notify library I'm going to use. | 20:13 |
conscioususer | With the package installed, please open the Python shell and enter: | 20:13 |
conscioususer | >>> from gi.repository import Notify | 20:13 |
conscioususer | This will load the library we will use, the Python bindings for libnotify. | 20:14 |
conscioususer | Before sending a notification, we should identify our application, for logging purposes: | 20:14 |
conscioususer | >>> Notify.init('test') | 20:14 |
conscioususer | You should've received a "True" in response to this command, meaning that the identification was accepted. | 20:14 |
conscioususer | Now we are ready to build a notification: | 20:16 |
conscioususer | >>> notification = Notify.Notification.new('Test', 'Hello World!', 'start-here') | 20:16 |
conscioususer | The first parameter is the title of the notification, the second is the body text, and the third is the name of the icon you want the notification to use. | 20:16 |
conscioususer | You can change them at will. | 20:16 |
conscioususer | If I'm going too fast, for example if someone is still downloading a dependency, please let me know. | 20:16 |
conscioususer | Ok, moving on... | 20:17 |
conscioususer | The notification is now built, but it was not sent yet. Before sending it, we can set some details. | 20:17 |
conscioususer | For example, we can set the urgency level of this notification: | 20:17 |
conscioususer | >>> notification.set_urgency(Notify.Urgency.LOW) | 20:17 |
conscioususer | In Ubuntu, non-urgent notifications are not shown when you are seeing a fullscreen video, among other things. | 20:17 |
conscioususer | You could also set an arbitrary image to be an icon. | 20:18 |
conscioususer | But let's not waste too much time on details. :) If you are ready, then let's pop the notification already: | 20:18 |
conscioususer | >>> notification.show() | 20:18 |
conscioususer | So, did you see a notification bubble popping up in your desktop? | 20:18 |
conscioususer | This notification is completely consistent with other notifications from Ubuntu, like network connection and instant messages. | 20:18 |
conscioususer | Not only on visuals, but also on behavior. | 20:19 |
conscioususer | You didn't have to explicitly code this consistency, all the code did was say "hey, desktop environment, whichever you are, please show this notification here!" | 20:19 |
conscioususer | And the environment took care of the rest. | 20:19 |
conscioususer | You can execute this code in other enviornments, and it will work similarly. See the image | 20:19 |
conscioususer | notify.png | 20:20 |
conscioususer | It will obey the guidelines of those environments. For example, in XFCE you can click to close, while in Ubuntu+Unity you can't by design | 20:20 |
conscioususer | Now that we are warmed up, I will dive a little bit into a very important question that is under the hood of what we just did. | 20:21 |
conscioususer | What exactly this library does? Is it a huge pile of "ifs" and "elses", that does different things for each environment? | 20:21 |
conscioususer | Thank goodness no, because that would mean the library depends on core libraries of all those environments, greatly increasing the dependencies of your app if you wanted to use it. | 20:21 |
conscioususer | No, it's actually much more elegant than that, thanks to the concept of | 20:21 |
conscioususer | === SPECIFICATIONS | 20:22 |
conscioususer | A specification is basically a set of idioms and protocols, specifically designed to be environment-independent. | 20:22 |
conscioususer | In the case of notifications, this means a "common language" that is the only thing that notification senders and notifications receivers need to know. | 20:22 |
conscioususer | Specifications represent the foundation of a lot of integration you currently see in your system. | 20:22 |
conscioususer | For example, if you peek /usr/share/applications in your system, you will see a monolothic folder with .desktop files for all the applications installed. | 20:22 |
conscioususer | How this monolithic folder becomes neatly categorized menus in GNOME, KDE, XFCE, etc.? | 20:23 |
conscioususer | It's thanks to the Desktop Entry Specification [2] and Desktop Menu Specification [3] that specify how .desktop files have to be written, and their contents mean wrt categorization. | 20:23 |
conscioususer | Another example | 20:23 |
conscioususer | The library libdbusmenu provides a common language through which applications can send menus to each other. | 20:23 |
conscioususer | This library is what allows implementing the global menu you see in | 20:23 |
conscioususer | polly-ubuntu-unity.png | 20:23 |
conscioususer | polly-kubuntu.png | 20:24 |
conscioususer | without the need of Qt-specific code or special conditions inside Polly. | 20:24 |
conscioususer | A lot of those specifications are written by the community effort in freedesktop.org [1], though other sources exist. | 20:24 |
conscioususer | If you are curious on knowing more, the specification for notifications used by libnotify can be seen in [4]. | 20:24 |
conscioususer | libnotify represents an ideal situation for a specification | 20:24 |
conscioususer | It has been adopted by the most popular environments and is so high-level that app developers don't even need to know that the specification exists. | 20:24 |
conscioususer | the library API is high-level, I mean | 20:25 |
conscioususer | It's like that old cliche from martial arts movies. | 20:25 |
conscioususer | You know that an specification has been mastered when you don't have to use it. :) | 20:25 |
conscioususer | But sometimes it's not so clean, even when a specification exists. | 20:25 |
conscioususer | Which brings us to the next topic. | 20:25 |
conscioususer | === PART 2: WHERE DO I PLACE FILES READ OR WRITTEN BY MY APPLICATION? | 20:26 |
conscioususer | Before I continue, any questions? | 20:26 |
* conscioususer waits a bit... | 20:26 | |
conscioususer | ok, let's move on | 20:27 |
=== jrgifford_ is now known as jrgifford | ||
conscioususer | When your application starts to become a little more complex than helloworlding, it is highly possible that at some point you will need to read and write files. | 20:27 |
conscioususer | Those can usually be categorized in three types: configuration files, data files, and cache files. | 20:27 |
conscioususer | The question is, where should you put them? | 20:27 |
conscioususer | A lot of applications simply create a .APPNAME folder in the user's home, but that's usually considered bad practice. | 20:27 |
conscioususer | First, because it clutters the home folder. | 20:27 |
conscioususer | Second, because separating files by type first can be more useful. | 20:28 |
conscioususer | For example, if all cache files of all applications are in the same folder, desktop cleaners know they can safely delete this folder for a full app-independent cache cleanup. | 20:28 |
conscioususer | Also, file indexers can be programmed to ignore the entire folder if they want. | 20:28 |
conscioususer | But of course, you can only avoid this if environments follow the same guidelines for where placing those types. | 20:28 |
conscioususer | I guess you know the direction I'm going, right? :) | 20:29 |
conscioususer | Base Directory Specification [5] | 20:29 |
conscioususer | This specification establishes the environment variables that define where files of a certain type should be placed. | 20:29 |
conscioususer | You can check them right now. | 20:29 |
conscioususer | In the Python interpreter enter | 20:29 |
conscioususer | >>> import os | 20:29 |
conscioususer | >>> print os.environ['XDG_DATA_DIRS'] | 20:29 |
conscioususer | This will print the content of the XDG_DATA_DIRS variable, which is a list of paths separated by colons. | 20:30 |
conscioususer | This list contains the paths where data files are expected to be, in order of priority. | 20:30 |
conscioususer | you can also try 'XDG_DATA_HOME', for example | 20:31 |
conscioususer | which is the path for the specific user | 20:31 |
conscioususer | Now, parsing this string is not particularly difficult, but it is annoying to reinvent this wheel for every application you write. | 20:31 |
conscioususer | So instead, you can use the PyXDG library. | 20:31 |
conscioususer | It also comes by default in Natty/Oneiric. | 20:31 |
conscioususer | If you don't have it, just do "sudo apt-get install python-xdg" | 20:31 |
conscioususer | Now, in the Python interpreter, enter | 20:32 |
conscioususer | >>> from xdg import BaseDirectory | 20:32 |
conscioususer | The BaseDirectory class takes care of all reading and parsing of the spec environment variables for you. | 20:32 |
conscioususer | For example, all you need to do to access data paths is to use the variable | 20:32 |
conscioususer | >>> BaseDirectory.xdg_data_dirs | 20:33 |
conscioususer | which has all paths in a neat Python list, ready to be used. | 20:33 |
conscioususer | If you want to know more details about using this library, I recommend you to read [5] and also entering in the interpreter | 20:33 |
conscioususer | >>> help(BaseDirectory) | 20:33 |
conscioususer | (type 'q' to leave help mode) | 20:33 |
conscioususer | As you can see, in this case the app developer is much closer to the metal than on the notifications case. He actually needs to know some details about the specification. | 20:34 |
conscioususer | The reason is simple: what is done once you know the paths is highly application-dependent. | 20:34 |
conscioususer | Some use data folders to store icons, others to store databases. | 20:34 |
conscioususer | Some applications don't use caching at all. | 20:34 |
conscioususer | And so on. | 20:34 |
conscioususer | So higher-level interfaces wouldn't really help much. | 20:34 |
conscioususer | But the specification itself is very short and easy to understand. | 20:34 |
conscioususer | And the integration is worth the effort. | 20:35 |
conscioususer | Are there any questions about the usage of python-xdg? | 20:35 |
conscioususer | I can wait a bit. :) | 20:35 |
conscioususer | Ok | 20:36 |
conscioususer | Time to wrap part 2 | 20:36 |
conscioususer | The only storage that the Base Directory specification does not cover is the storage of sensitive information. | 20:36 |
conscioususer | Which brings us to the third part. | 20:37 |
conscioususer | === WHAT DO I USE TO STORE SENSITIVE INFORMATION? | 20:37 |
conscioususer | If you application stores sensitive info like passwords, it is usually considered a security flaw to store them in plain text. | 20:37 |
conscioususer | (I say "usually" because it's not that much of a big deal if you live alone and use a computer that is never connected to the internet, for example) | 20:37 |
conscioususer | That's why desktop environments provide keyrings, which are encrypted storages unlocked by a master password or at login. | 20:37 |
conscioususer | For example, | 20:37 |
conscioususer | GNOME has GNOME-Keyring, while KDE has KWallet. | 20:37 |
conscioususer | G-K is widely used by GNOME apps, like Empathy, Evolution, networkmanager... | 20:38 |
conscioususer | But now here comes the bad news | 20:38 |
conscioususer | For the moment, there are no specifications on storage for sensitive information. | 20:38 |
conscioususer | freedesktop.org has a draft, but is still in progress [6] | 20:38 |
conscioususer | So these two keyrings use different idioms. | 20:38 |
conscioususer | which is a very bad thing for developers who want cross-environment applications. | 20:38 |
conscioususer | Usually, the only way to ensure cross-environment in this case is implementing directly in your code | 20:40 |
conscioususer | And now here comes the good news: the python-keyring library | 20:41 |
conscioususer | Basically, an awesome developer has bad that for you! | 20:41 |
conscioususer | (sudo apt-get install python-keyring) | 20:41 |
conscioususer | (this one does *not* come in a default Ubuntu install) | 20:41 |
conscioususer | This library does all the dirty work of finding out which keyring should be used according to the environment you are on. | 20:42 |
conscioususer | It supports GNOME-Keyring, KWallet and also Windows and OSX keyrings (though I never tested it for those last two) | 20:42 |
conscioususer | And wraps this in a surprisingly elegant API. | 20:42 |
conscioususer | Really | 20:42 |
conscioususer | Let's go back to the interpreter | 20:42 |
conscioususer | Did you all install python-keyring already? | 20:43 |
conscioususer | Ops | 20:45 |
conscioususer | before I continue, I should make an observation | 20:46 |
conscioususer | it seems that XDG_DATA_HOME is not found in os.environ | 20:46 |
conscioususer | strangely, its entry works in xdg.BaseDirectory and it is on the spec | 20:47 |
conscioususer | I'll investigate this later, sorry about that | 20:47 |
conscioususer | Anyway | 20:47 |
conscioususer | Let's go back to the interpreter and load the library: | 20:47 |
conscioususer | >>> import keyring | 20:47 |
conscioususer | Now let's store a dummy password in the keyring | 20:48 |
conscioususer | >>> keyring.set_password('appname', 'myusername', 'mypassword') | 20:48 |
conscioususer | (I think the strings are all self-explanatory) | 20:48 |
conscioususer | If you are using GNOME, you can see the password stored in Seahorse, type "seahorse" in the terminal or look in the applications for System > Passwords & Encryption | 20:48 |
conscioususer | It is labeled with the generic name of 'network password' (IIRC next installments of python-keyring will try to use a better naming scheme) | 20:48 |
conscioususer | Did you find it? :) | 20:49 |
conscioususer | Now let's retrieve it | 20:49 |
conscioususer | >>> print keyring.get_password('appname', 'myusername') | 20:50 |
conscioususer | Yep. | 20:50 |
conscioususer | It's *that* simple. | 20:50 |
ClassBot | There are 10 minutes remaining in the current session. | 20:50 |
conscioususer | That's not really much to talk about the library really, it is specifically designed to be easy to talk about. :) | 20:51 |
conscioususer | Of course, you lose some particular flexibility from GNOME-Keyring or KWallet, but for most applications those wouldn't be used. | 20:51 |
conscioususer | For simple account storage, python-keyring suffices and only occupies a couple of lines of code in your app. | 20:52 |
conscioususer | It's really convenient | 20:52 |
conscioususer | Well, I think it's time for me to wrap up. | 20:52 |
conscioususer | Hopefully this session was helpful for you to make the first steps into integrating your app in Ubuntu transparently | 20:52 |
conscioususer | Or, better saying, playing nice with others around you. :) | 20:52 |
conscioususer | Are there any questions? | 20:52 |
conscioususer | On the XDG_DATA_HOME issue | 20:53 |
conscioususer | I guess this precisely why using python-xdg is convenient. :) | 20:53 |
conscioususer | It works around this kind of problem. | 20:53 |
conscioususer | You can play with the files I gave in the tarball, and modify them to experiment with the libraries. | 20:55 |
conscioususer | I purposefully chose some libraries with technically simple APIs, as I wanted to dedicate part of this session to talk about the concept of specifications themselves. | 20:55 |
ClassBot | There are 5 minutes remaining in the current session. | 20:55 |
conscioususer | Ok, I guess that's pretty much it. :) | 20:57 |
conscioususer | Thank you very much for listening, and for attending today's sessions. | 20:57 |
conscioususer | Hope we have a nice last appdev day tomorrow. :) | 20:58 |
=== ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || | ||
nigelb | pleia2: solved the kernel oops? ;) | 21:10 |
pleia2 | heh, no | 21:10 |
nigelb | we gave up for the night. Part of the problem was 32-bit binaries on 64-bit machine. BUt still - yay for ruined night's sleep. | 21:12 |
nigelb | 3 AM \o/ | 21:12 |
=== Guest87485 is now known as gord |
Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!