Documentation

Un article de Screenlets.

Sommaire

Développeurs

Screenlets API

Une documentation de l'API est disponible en ligne à l'adresse http://screenlets.org//Documentation/index.html here

Soumettre un patch / Amélioration du coeur

Vous pouvez facilementsoumettre une amélioration et aider à corriger des bugs en envoyant un email à helder.fraga@hotmail.com. Une TODO list est disponible si vous ne savez pas où commencer http://bazaar.launchpad.net/~screenlets-dev/screenlets/trunk/files

Où et comment obtenir la version de développement ?

Le code source de screenlets est hebergé par launchpad. Vous pouvez y télécharger et installer la dernière version de développement en utilisant cette comande

mkdir screenlets-trunk

cd screenlets-trunk

bzr branch http://bazaar.launchpad.net/~screenlets-dev/screenlets/trunk

cd trunk

python setup.py install

Pour mette à jour simplement :

cd screenlets-trunk

bzr pull 

(Il faut au préalable installer le logiciel 'bzr'):


Quelques informations sur screenlets

Controleurs inclus

Les Screenlets peuvent être controlés en utilisant quelques variables définies dans l'API telles que self.scale, self.width, self.x. Par exemple pour déplacer le screenlet à 100 px de la gauche de l'écran, un simple self.x = 100 fera l'affaire.

Dessin

Les Screenlets sont habituellement dessiné en utilisant PyCairo, mais vous pouvez également utiliser des widget GTK. Il faut se méfier parce que les widgets GTK ne se redimensionnent pas de la même façon que les dessins Cairo, Il sera nécessaire d'implémenter un redimensionnement pour ces widgets.

Thèmes

Les thèmes Screenlets sont trés facilement modifiables. Il est possible de développer un thème de trois manières différentes

  1. En utilisant le controleur de thèmes inclus en utilisant les fonctions comme draw_rectangle , draw_triangle , draw_shadow , draw_line , draw_circle...
  1. En créant des images pour générer des thèmes.
  1. En utilisant une combinaison des deux dernières techniques

Est-il facile de créer son propre Screenlet?

L'API est relativement facile à utiliser, mais le moyen le plus rapide pour créer un nouveau screenlet est de se baser surun screenlet existant et de l'éditer. Le screenlet Exemple fournit avec le paquet de base est idéal pour cela. Tous les autres screenlets peuvent vous servir. Ce projet est opensource et les sources sont là aussi pour ça.


Débuter

Structure des fichiers

Your screenlet folder should look like this

Clock/ClockScreenlet.py Clock/icon.png or icon.svg Clock/themes/defaut/ (containing the default skin)

Sarting the python file

First we do the basic imports
import screenlets 
from screenlets.options import StringOption , BoolOption , IntOption , FileOption , DirectoryOption , ListOption , AccountOption , TimeOption , FontOption, ColorOption , ImageOption
We import some more stuff
import gobject
import gtk
Lets start the base class
class ExampleScreenlet (screenlets.Screenlet):
	"""A simple example of how to create a Screenlet"""
Lets set some global vars
	__name__	= 'ExampleScreenlet' #Name of the screenlet followed by "Screenlet"
	__version__	= '0.1'
	__author__	= 'My name here'
	__desc__	= __doc__	# set description to docstring of class
Lets set some other global vars that we need
	test_text = 'Hi.. im a screenlet'
	demo_text = ''
	demo_number = ''
	int_example = 1
	bool_example = True
	time_example =  (7, 30, 0)
	account_example =  ('','')
	color_example =(0.0, 0.0, 0.0, 1)
	font_example = "Sans Medium 5"
	image_example = ''
	file_example = ''
	directory_example = ''
	list_example = ('','')
	hover = False
Call super
	def __init__ (self, **keyword_args):
		screenlets.Screenlet.__init__(self, width=200, height=200, 
			uses_theme=True, **keyword_args)
Set the default theme
		self.theme_name = "default"
Add menu items or configurable settings
		self.add_options_group('Example', 'This is an example of ' +\
			' editable options within an OptionGroup ...')
		# add editable option to the group
		self.add_option(StringOption('Example','test_text',			# attribute-name
			self.test_text,						# default-value
			'Test-Text', 						# widget-label
			'The Test-Text option for this Screenlet ...'	# description
			))

		self.add_option(BoolOption('Example','bool_example', 
			self.bool_example, 'Option group bool', 
			'Example options group using bool'))

		self.add_option(TimeOption('Example','time_example', self.time_example, 
 			'Option group time', 'Example options group using time'))

		self.add_option(IntOption('Example','int_example', 
			self.int_example, 'Option group integer', 
			'Example options group using integer', 
			min=0, max=5000))

		self.add_option(FontOption('Example','font_example', 
			self.font_example, 'Option group font', 
			'Example options group using font'))

		self.add_option(ColorOption('Example','color_example', 
			self.color_example, 'Option group color', 
			'Example options group using color'))

		self.add_option(AccountOption('Example','account_example',self.account_example,
			'Option group account','Using keyring encryption'))
		self.add_option(ImageOption('Example','image_example', self.image_example, 
			'Option group Image', 'Example options group using Image')) 

		self.add_option(FileOption('Example','file_example', self.file_example, 
			'Option group file', 'Example options group using file')) 

		self.add_option(DirectoryOption('Example','directory_example', self.directory_example, 
			'Option group directory', 'Example options group using directory')) 

		self.add_option(ListOption('Example','list_example', self.list_example, 
			'Option group list', 'Example options group using list')) 
The event handlers
	def on_after_set_atribute(self,name, value):
		"""Called after setting screenlet atributes"""
		print name + ' is going to change from ' + str(value)
		pass

	def on_before_set_atribute(self,name, value):
		"""Called before setting screenlet atributes"""
		print name + ' has changed to ' + str(value)
		pass


	def on_create_drag_icon (self):
		"""Called when the screenlet's drag-icon is created. You can supply
		your own icon and mask by returning them as a 2-tuple."""
		return (None, None)

	def on_composite_changed(self):
		"""Called when composite state has changed"""
		pass

	def on_drag_begin (self, drag_context):
		"""Called when the Screenlet gets dragged."""
		pass
	
	def on_drag_enter (self, drag_context, x, y, timestamp):
		"""Called when something gets dragged into the Screenlets area."""
		pass
	
	def on_drag_leave (self, drag_context, timestamp):
		"""Called when something gets dragged out of the Screenlets area."""
		pass

	def on_drop (self, x, y, sel_data, timestamp):
		"""Called when a selection is dropped on this Screenlet."""
		return False
		
	def on_focus (self, event):
		"""Called when the Screenlet's window receives focus."""
		pass
	
	def on_hide (self):
		"""Called when the Screenlet gets hidden."""
		pass
	
	def on_init (self):
		"""Called when the Screenlet's options have been applied and the 
		screenlet finished its initialization. If you want to have your
		Screenlet do things on startup you should use this handler."""
		print 'i just got started'
		# add  menu items from xml file
		self.add_default_menuitems(DefaultMenuItem.XML)
		# add menu item
		self.add_menuitem("at_runtime", "A")
		# add default menu items
		self.add_default_menuitems()


	def on_key_down(self, keycode, keyvalue, event):
		"""Called when a keypress-event occured in Screenlet's window."""
		key = gtk.gdk.keyval_name(event.keyval)
		
		if key == "Return" or key == "Tab":
			screenlets.show_message(self, 'This is the ' + self.__name__ +'\n' + 'It is installed in ' + self.__path__)
	
	def on_load_theme (self):
		"""Called when the theme is reloaded (after loading, before redraw)."""
		pass
	
	def on_menuitem_select (self, id):
		"""Called when a menuitem is selected."""
		if id == "at_runtime":
			screenlets.show_message(self, 'This is an example on a menu created at runtime')
		if id == "at_xml":
			screenlets.show_message(self, 'This is an example on a menu created in the menu.xml')
		pass
	
	def on_mouse_down (self, event):
		"""Called when a buttonpress-event occured in Screenlet's window. 
		Returning True causes the event to be not further propagated."""
	    
		return False
	
	def on_mouse_enter (self, event):
		"""Called when the mouse enters the Screenlet's window."""
	        self.theme.show_tooltip("this is a tooltip , it is set to shows on mouse hover",self.x+self.mousex,self.y+self.mousey)
		self.hover = True
		print 'mouse is over me'
		
	def on_mouse_leave (self, event):
		"""Called when the mouse leaves the Screenlet's window."""
		self.theme.hide_tooltip()
		self.hover = False
		print 'mouse leave'

	def on_mouse_move(self, event):
		"""Called when the mouse moves in the Screenlet's window."""
		self.redraw_canvas()
		pass

	def on_mouse_up (self, event):
		"""Called when a buttonrelease-event occured in Screenlet's window. 
		Returning True causes the event to be not further propagated."""
		return False
	
	def on_quit (self):
		"""Callback for handling destroy-event. Perform your cleanup here!"""
		screenlets.show_question(self, 'Do you like screenlets?')
		return True
		
	def on_realize (self):
		""""Callback for handling the realize-event."""
	
	def on_scale (self):
		"""Called when Screenlet.scale is changed."""
		pass
	
	def on_scroll_up (self):
		"""Called when mousewheel is scrolled up (button4)."""
		pass

	def on_scroll_down (self):
		"""Called when mousewheel is scrolled down (button5)."""
		pass
	
	def on_show (self):
		"""Called when the Screenlet gets shown after being hidden."""
		pass
	
	def on_switch_widget_state (self, state):
		"""Called when the Screenlet enters/leaves "Widget"-state."""
		pass
	
	def on_unfocus (self, event):
		"""Called when the Screenlet's window loses focus."""
		pass
	
	def on_draw (self, ctx):
                """In here we load the theme"""
		# if theme is loaded
		if self.theme:
			# set scale rel. to scale-attribute
			ctx.scale(self.scale, self.scale)
			ctx.set_source_rgba(self.color_example[2], self.color_example[1], self.color_example[0],0.4)	
			if self.hover:
				self.theme.draw_rounded_rectangle(ctx,0,0,20,self.width,self.height)
			self.draw_circle(ctx,0,0,self.width,self.height)
			# TEST: render example-bg into context (either PNG or SVG)
			self.theme.render(ctx, 'example-bg')
			ctx.set_source_rgba( self.color_example[0], self.color_example[1], self.color_example[2],self.color_example[3])
			self.draw_text(ctx, self.test_text, 0, 0, self.font_example , 10,self.width,pango.ALIGN_LEFT)
			self.draw_line(ctx,0,40,self.width,0,1)
			self.draw_text(ctx, 'timer - ' + str(self.number), 0, 130, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, self.theme_name, 0, 50, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, 'mouse x ' + str(self.mousex ) + ' \n mouse y ' + str(self.mousey ) , 0, 170, self.font_example , 10,self.width,pango.ALIGN_LEFT)


			# render svg-file
			#self.theme['example-bg.svg'].render_cairo(ctx)
			# render png-file
			#ctx.set_source_surface(self.theme['example-test.png'], 0, 0)
			#ctx.paint()
	
	def on_draw_shape (self, ctx):
		self.on_draw(ctx)
Lets add the screenlet to session
if __name__ == "__main__":
	# create new session
	import screenlets.session
	screenlets.session.create_session(ExampleScreenlet)


Builtin drawing funtion
                        ctx.scale(self.scale, self.scale)
			ctx.set_source_rgba(self.color_example[2], self.color_example[1], self.color_example[0],0.4)	
			if self.hover:
				self.draw_rounded_rectangle(ctx,0,0,20,self.width,self.height)
			self.draw_circle(ctx,0,0,self.width,self.height)
			# TEST: render example-bg into context (either PNG or SVG)
			self.theme.render(ctx, 'example-bg')
			ctx.set_source_rgba( self.color_example[0], self.color_example[1], self.color_example[2],self.color_example[3])
			self.draw_text(ctx, self.test_text, 0, 0, self.font_example , 10,self.width,pango.ALIGN_LEFT)
			self.draw_line(ctx,0,40,self.width,0,1)
			self.draw_text(ctx, 'timer - ' + str(self.number), 0, 130, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, self.theme_name, 0, 50, self.font_example , 10, self.width,pango.ALIGN_LEFT)

			self.draw_text(ctx, 'mouse x ' + str(self.mousex ) + ' \n mouse y ' + str(self.mousey ) , 0, 170, self.font_example , 10,self.width,pango.ALIGN_LEFT)


			# render svg-file
			#self.theme['example-bg.svg'].render_cairo(ctx)
			# render png-file
			#ctx.set_source_surface(self.theme['example-test.png'], 0, 0)
			#ctx.paint()


So where do i start?

i sugest you get the template screenlet and start coding from there

Codding Rules

 *A Screenlet's classname must end on "Screenlet" (e.g. ClockScreenlet)
 *Not more than 80 chars per line (where possible).
 *Tabs are 4 char-wide "\t"-characters.
 *Classes MUST have a documentation-string.
 *After class-headers's documentation, one separating line.
 *Internal attributes MUST start with TWO leading underscores.
 *Editable options NEVER have leading underscores.
 *All functions that are no inherited event-handlers MUST have a documentation-string.
 *Constructors of Screenlet-subclasses must implement the **keyword_args parameter as last argument to their __init__-function.
 *All screenlet-files MUST have the name of the Screenlet-classes they contain (with a .py-extension).
 *All Screenlets MUST have a head-comment containing license/author note,
 *Screenlets need to be placed into a directory named like the Screenlet's class (without trailing "Screenlet"). This directory may contain a "themes"-directory where the Screenlet's themes are stored. It may also contain other files (of course).
 *Screenlets should supply an icon named "icon.svg" or "icon.png" within their directory.
 *When possible set the width and height of the screenlet matching the background theme image , to avoid confusion
 *Always call super before anything else ... of course
 *Never call exit() or sys.exit().But if you need to check the utils.is_manager_running_me() and only call the exit() if that returns false 

Avoiding memory leaks

Old versions of screenlets suffered from memory leaks expecilly in the way they draw text , to avoid this use the built in draw_text function. Also remember to clean all your variables to avoid memory leaks

Packaging a screenlet

use the screenlets-packager tool to package your screenlet for release (e.g.):

 screenlets-packager ~/.screenlets/Weather

Finding a host for your package

One suggestion ,post your screenlet on www.gnome-look.org under the screenlet section , gnome-look provides you to upload your content there , so it will remain in their servers forever , and your screenlet will be safe and backed up, then you can post it on www.screenlets.org and provide the download link from gnome-look