Visualizzazione post con etichetta Programmare. Mostra tutti i post
Visualizzazione post con etichetta Programmare. Mostra tutti i post

lunedì 2 gennaio 2017

Primi esperimenti di desklet in Cinnamon


Dopo qualche settimana di smanettamenti (e smadonnamenti!) vari sono riuscito ad ottenere qualche prototipo funzionante di desklet per cinnamon.

La prima cosa che mi viene da dire è che è veramente difficile riuscire a raccapezzarsi tra tutte le librerie usabili, quali sono le funzioni e come si usano!

Questo perchè il linguaggio usato per l'implementazione dei desklet è il JavaScript, mentre la documentazione delle librerie richiamabili è generata dal codice C, con la possibilità di essere richiamate da codice python o altri linguaggi. Come si immagina la situazione è veramente complessa.

La storia è che sono state inventate delle interfacce per chiamare queste librerie scritte in C dal JavaScript (o da altri linguaggi), raccolte sotto il nome di GObject Introspection.

La documentazione di queste librerie segue lo standard C, per cui ad esempio la funzione
ClutterActor *gtk_clutter_embed_get_stage (GtkClutterEmbed *embed);
va invocata in JavaScript come
const GtkClutter = imports.gi.GtkClutter;
this._clutterEmbed = new GtkClutter.Embed();
this._gtkEmbedActor = this._clutterEmbed.get_stage();
per cui la prima parte del nome della funzione gtk_clutter rappresenta la libreria da importare: GtkClutter; mentre l'oggetto GtkClutterEmbed diventa GtkClutter.Embed; e l'ultima parte del nome della funzione rappresenta come va chiamata la funzione (get_stage); tra l'altro in C non ci sono gli oggetti mentre in JavaScript la funzione viene invocata sull'istanza (this._clutterEmbed).


Documentazione


Un ottimo post che spiega una desklet di tipo hello world è disponibile qui.

Una fonte preziosa di informazioni è quella ufficiale di linuxmint (i creatori di Cinnamon).
 
Un'altra ottima fonte di informazioni è il pacchetto devhelp, che contiene offline un sacco di reference utili; si installa con il comando
 sudo apt install devhelp cinnamon-doc

 

Un esempio


Andando al sodo, ecco un codice di esempio che stampa un'immagine:

il file comune metadata.json:
{
 "uuid": "videoDesk@zac",
 "name": "Video Desklet",
 "description": "Show video streams on your desktop",
 "icon": "",
 "prevent-decorations": false,
 "max-instances": "100",
 "dangerous": false
}

il file desklet.js:
const Desklet = imports.ui.desklet;
const St = imports.gi.St;
const Clutter = imports.gi.Clutter;

function VideoDesk(metadata, desklet_id)
{
 this._init(metadata, desklet_id);
}

VideoDesk.prototype =
{
 __proto__: Desklet.Desklet.prototype,

 _init: function(metadata, desklet_id)
 {
  Desklet.Desklet.prototype._init.call(this, metadata, desklet_id);

  this.window = new St.Bin();

  let imgFilename = '/home/zac/Progetti/videoDesk/image.png';
  this._clutterTexture = new Clutter.Texture({keep_aspect_ratio: true});
  this._clutterTexture.set_from_file(imgFilename)

  this._clutterBox = new Clutter.Box();
  this._binLayout = new Clutter.BinLayout();
  this._clutterBox.set_layout_manager(this._binLayout);
  this._clutterBox.set_width(this.metadata["width"]);
  this._clutterBox.add_actor(this._clutterTexture);
  this.window.add_actor(this._clutterBox);

  this.setContent(this.window);
 }
}

function main(metadata, desklet_id)
{
 return new VideoDesk(metadata, desklet_id);
}



Un trucco pratico


Durante l'implementaizone lancio spesso il desklet per verificare che la sintassi dei comandi che sto scrivendo sia corretta. Un'opzione è quella di aggiungere e rimuovere in continuazione il nostro desklet dal desktop. Ma ho trovato molto più comodo e veloce usare il compilatore di JavaScript di Cinnamon (il cjs). Tra l'altro ho impostato l'editor Scite a lanciarlo ogni volta che premo F5 per cui l'esecuzione e visualizzazione degli errori è ancora più veloce.

In scite la configurazione per la compilazione automatica si ottiene aggiungendo al file di configurazione la linea
command.go.*.js=cjs $(FileNameExt)
il codice del file di test (che mostra un filmato):

#!/usr/bin/cjs

const Lang = imports.lang;
const Gtk = imports.gi.Gtk;
const Gst = imports.gi.Gst;
const Clutter = imports.gi.Clutter;
const ClutterGst = imports.gi.ClutterGst;
const GtkClutter = imports.gi.GtkClutter;

ClutterGst.init(null, null);

const Application = new Lang.Class({
 //A Class requires an explicit Name parameter. This is the Class Name.
 Name: 'Application',

 //create the application
 _init: function() {
  this.application = new Gtk.Application();

   //connect to 'activate' and 'startup' signals to handlers.
   this.application.connect('activate', Lang.bind(this, this._onActivate));
   this.application.connect('startup', Lang.bind(this, this._onStartup));
 },

 //create the UI
 _buildUI: function() {
  this._window = new Gtk.ApplicationWindow({ application: this.application, title: "Hello World!" });
  this._window.set_default_size(200, 200);
  this.label = new Gtk.Label({ label: "Hello World" });

  this.player = new ClutterGst.Playback();
  this.player.set_filename("/home/zac/Scrivania/test.mov");

  this._content = new ClutterGst.Aspectratio();
  this._content.set_player(this.player);

  this._clutterBox = new Clutter.Box();
  this._binLayout = new Clutter.BinLayout();
  this._clutterBox.set_layout_manager(this._binLayout);
  this._clutterBox.set_width(300);
  this._clutterBox.set_height(100);
  this._clutterBox.set_content(this._content);

  this._clutterEmbed = new GtkClutter.Embed();
  this._gtkEmbedActor = this._clutterEmbed.get_stage();
  this._gtkEmbedActor.add_actor(this._clutterBox);

  this._window.add(this._clutterEmbed);

  this.player.set_playing(true);
 },

 //handler for 'activate' signal
 _onActivate: function() {
  //show the window and all child widgetsq
  this._window.show_all();
 },

 //handler for 'startup' signal
 _onStartup: function() {
  this._buildUI();
 },

});

//run the application
let app = new Application();
app.application.run(ARGV);

Il prossimo passo è aprire un repository su GitHub dove piazzare il codice dei miei esperimenti, nel frattempo, buona programmazione!

venerdì 11 luglio 2014

SVN e Nemo


Ho da poco installato sul portatile l'ultima versione di linux mint, la 17, versione Cinnamon.

Pulizia e funzionalità caratterizzano questa distribuzione, anche se la velocità di esecuzione è la stessa di ubuntu.

Ho avuto l'esigenza di installare un client svn, e, abituato alla comodità della gui e dell'integrazione con il file manager offerta da TortoiseSVN, ho cercato una soluzione equivalente per Nemo, il file manager che mi sono trovato preinstallato.

La solzuone trovata è RabbitVCS, per il quale è stato creato un plug-in per Nemo che si chiama nemo-rabbitvcs (da comando apt-get install).

Il problema è che non tutte le dipendenze sono state sistemate bene per questo pacchetto per cui, se non dovesse funzionare, assicurarsi di aver installato i seguenti pacchetti:

  • nemo-rabbitvcs
  • python-nemo
  • rabbitvcs-core
  • python-simplejson

L'ultimo che segno in grassetto è il pacchetto mancante che mi ha fatto impazzire, ed è il motivo che mi ha spinto a scrivere questo post; le dipendenze effettivamente non sono indicate bene, e sui siti internet si fa menzione solo dei primi tre pacchetti che ho riportato: per scoprire che mancava l'ultimo pacchetto, ho lanciato nemo da linea di comando e ho analizzato l'output che dava un warning.

domenica 6 ottobre 2013

Programma per la visualizzazione di note condivise


E' da un po' di tempo che sto avendo la fantasia di scrivere un programma per la visualizzazione di note condivise, che permetta di scriversi velocemente una nota, un url, una checklist, e di condividerlo tra i vari dispositivi che quotidianamente usiamo, nella fattispecie il PC di casa con linux, quello dell'ufficio con windows, un telefonino con android.

Ho deciso quindi di scrivere quali potrebbero essere le caratteristiche di un programma di questo tipo, prendendo spunto da internet:
  • uso del servizio Dropbox per la sincronizzazione
  • uso della formattazione markdown: discussione alla libreria di sviluppo cosigliata

Avevo anche trovato un nome: Mark down oltre che indicare il tipo di formattazione, vuol dire appuntarsi, per cui un nome carino in italiano "appuntarsi note" diventa MarkDownNotes.

Ma durante la ricerca di informazioni al riguardo, ho scoperto che tutte queste non sembrano delle idee troppo originali:

Quello che noto è che ci sono un bel po' di applicazioni per IOS ma niente per desktop e/o android, per cui insisto nella mia fantasia. L'utente può prescindere dall'usare il mio programma, perchè la modifica delle note è ottenuta mediante un qualsiasi editor di testo, e la sincronizzazione mediante dropbox.

Il valore aggiunto sarebbe quindi fornito dalle seguenti caratteristiche:
  • cross-platform: windows/linux/android
  • un'icona nella traybar per aprire/chiudere tutte le note, inserire una nuova nota (nella versione desktop)
  • la possibilità di associare una data alla nota in modo da fornire una sorta di promemoria
  • collegamento con google calendar?
  • ?
vedremo...

domenica 5 settembre 2010

Clone di Tortoise SVN per Linux Ubuntu

Una buona alternativa sotto linux di Tortoise SVN è sicuramente RabbitVCS.

Per installarlo in Ubuntu bisogna eseguire il comando:
sudo add-apt-repository ppa:rabbitvcs/ppa
poi andare in Gestore Pacchetti, premere il tasto Aggiorna, poi selezionare il pacchetto rabbitvcs-nautlius ed applicare. Per attivare le nuove funzionalità è necessario riavviare la sessione.

Se tutto è andato a buon fine, cliccando con il tasto destro su una cartella dovrebbe uscire questo menù con le nuove funzionalità evidenziate in rosso:

sabato 17 aprile 2010

Aprire un progetto su SourceForge



Per poter cominciare a lavorare seriamente al mio progetto di media center, ho deciso di usare un servizio di hosting gratuito per progetti open source.

La scelta era tra launchpad, savannah e sourceforge, e la scelta è ricaduta su quest ultimo per i seguenti motivi:
  • launchpad: usa bazaar come sistema di gestione del codice, che però non conosco e non mi andava di studiare
  • savannah: non sono del tutto sicuro che il mio progetto faccia uso al 100% di free software (mame? mldonkey? mplayer?) e non mi va di verificare
  • sourceforge: mi ha convinto la prima voce di questa pagina: code hosting con SVN che era proprio quello che cercavo

Creazione di un progetto su SourceForge

La prima cosa da fare per creare un progetto è registrare un account; sourceforge accetta login con openid (ne ho uno con google), ma bisogna comunque immettere dei dati.

Dopodichè si passa alla creazione del progetto, nome, descrizione, e più in dettaglio le caratteristiche tipo: licenza, categoria, parole chiave, linguaggio ed altro (qui il tutorial ufficiale).

Dopo aver inserito i dati del progetto, si passa all'upload di un po' di codice.

Ho preparato un archivio contenente il codice python, le immagini ed un file README con delle informazioni base del progetto; questo archivio l'ho caricato tra i file di progetto di sf usando l'interfaccia web.

Da ricordarsi di aggiungere uno o più screenshot del progetto: nel tag Develop, alla voce Screenshots (vedi immagine seguente) si apre la schermata per la loro gestione: selezionare la voce Admin per uploadare le schermate.


Controllo del codice

Tra i vari servizi, sourceforge fornisce un repository SVN del progetto.

Per poter scaricare il codice il comando è
svn co https://atlantismc.svn.sourceforge.net/svnroot/atlantismc atlantismc

Per aggiungere file e cartelle il comando è
svn add main.py README main.mnu data

Per finalizzare l'aggiunta (o la modifica) il comando è
svn commit
usando come utente e password quelle fornite all'atto della registrazione.

Tutti questi comandi svn vanno lanciati nella stessa cartella di progetto.

Il repository SVN è browsabile anche via web all'URL:

Ecco la pagina del progetto che ho appena registrato:

Buon coding!

martedì 30 giugno 2009

Atlantide Media Center: menù di partenza

Un po' di brainstorming per il media center:
  • ogni menù ha una voce 'setup' che permette di configurare gli aspetti di quel menù, come ad esempio il percorso dove trovare i file multimediali, o il comando da impostare per riprodurli
  • ogni menù ha una voce 'indietro' ('esci' su quello principale)
  • dati possono essere directory e file, che si possono rinominare, cancellare, copiare, spostare; si possono creare directory nuove
  • se evidenziata una cartella, ti dice il numero di file e la data del più recente
  • se evidenziato un file ti dice dimensione, data e lunghezza (e magari copertina e info IMDB o equivalente italiano!)
  • nel menù 'Guarda TV' la funzione 'Setup' attiva la funzione di popolamento dei canali, e il comando per la visualizzazione dei canali stessi
  • i programmi registrati vanno in 'Registra TV', si possono poi spostare a piacere; in quel menù sono presenti le programmazioni
E ora un po' di codice python...

#!/usr/bin/python
########################################################
# Note sul nome delle variabili e funzioni :
# iniziano tutte con una sequenza che indica il tipo
#
# i = intero
# s = surface
# str = stringa
# font = font
# r = rect
########################################################
# Imports
########################################################
import pygame, sys, os
from pygame.locals import *
########################################################
# Inizializzazione variabili
########################################################
pygame.init()
iiResolution = (800, 600)
fontDefault = pygame.font.Font(None, 36)
# set screen resolution
pygame.display.set_mode(iiResolution, 0, 32)
sScreen = pygame.display.get_surface()
strBackgroundFile = os.path.join(".","Atlantis_by_aksu.jpg")
sBackground = pygame.image.load(strBackgroundFile)
strCurrentMenu = os.path.join(".","main.mnu")
########################################################
# Functions
########################################################
def drawMenu(menuFile, iSelected):
# Disegna il contenuto del menuFile ed evidenzia il selected
global sForeground, fontDefault
##################################
file = open(menuFile, 'r')
i=0
centerx = sForeground.get_rect().centerx
offsy = sForeground.get_rect().centery/2
for line in file:
line = line.replace ( "\n", "" )
sText = fontDefault.render(line, 1, (255, 255, 255))
rText = sText.get_rect()
rText.centerx = centerx
rText.y = i*32+offsy
if i == iSelected:
rText2 = rText.inflate(118,4)
rText2.centerx = centerx
sBox = pygame.Surface.convert_alpha(pygame.Surface((rText2.width, rText2.height)))
sBox.fill((0, 255, 255, 100))
sForeground.blit(sBox, rText2)
sForeground.blit(sText, rText)
i=i+1
# Setup string
sText = fontDefault.render("Setup", 1, (255, 255, 255))
rText = sText.get_rect()
rText.centerx = sForeground.get_rect().centerx
rText.y = i*32+offsy
sForeground.blit(sText, rText)
# Exit/back string
i=i+1
sText = fontDefault.render("Exit", 1, (255, 255, 255))
rText = sText.get_rect()
rText.centerx = sForeground.get_rect().centerx
rText.y = i*32+offsy
sForeground.blit(sText, rText)
##################################
def input(events):
# Gestisce gli eventi di input
global iItemSelected
##################################
for event in events:
if event.type == KEYDOWN:
if event.key == K_UP:
iItemSelected -= 1
elif event.key == K_DOWN:
iItemSelected += 1
elif event.key == K_ESCAPE:
sys.exit(0)
else:
print event
########################################################
# Main
########################################################
iItemSelected =0

# Main loop
while True:
sForeground = pygame.transform.scale(sBackground, iiResolution)
input(pygame.event.get())
pygame.display.flip()
drawMenu(strCurrentMenu, iItemSelected)
sScreen.blit(sForeground, (0,0))

domenica 28 giugno 2009

Atlantide Media Center: prime prove

Nell'ottica di implementare un front-end grafico per la mia linux-box, sto studiando il python e pygame.

Questo è il risultato di un paio d'ore di smanettamento:

#!/usr/bin/python

import pygame, sys, os

from pygame.locals import *

screenwidth = 800
screenheight = 600

pygame.init()

# set screen resolution
pygame.display.set_mode((screenwidth, screenheight))#, pygame.FULLSCREEN)
screen = pygame.display.get_surface()

back_file_name = os.path.join(".","Atlantis_by_aksu.jpg")
back_surface = pygame.image.load(back_file_name)

font = pygame.font.Font(None, 36)
text = font.render("Guarda un film", 1, (255, 255, 255))
textpos = text.get_rect()
textpos.centerx = back_surface.get_rect().centerx
back_surface.blit(text, textpos)

fore_surface = pygame.transform.scale(back_surface, (screenwidth, screenheight))

screen.blit(fore_surface, (0,0))

pos = 0,0

def input(events):
for event in events:
if event.type == MOUSEBUTTONDOWN:
sys.exit(0)
elif event.type == MOUSEMOTION:
global pos
pos = pygame.mouse.get_pos()
screen.blit(back_surface, (pos[0],pos[1]))
else:
print event

# Main loop
while True:
input(pygame.event.get())
pygame.display.flip()