Se non scrivo da un po su questo blog non è per pigrizia o perché ho deciso di abbandonarlo ma perché martedì mi sono laureato e da allora non ho proprio acceso il pc. Sto dedicando tutto il mio tempo a suonare e a godermi qualche giorno di meritato riposo. Credo che continuerò ancora per qualche tempo, ma prima o poi mi deciderò a riprendere le mie normali attività. Rimanete connessi!
26 maggio, 2007
14 maggio, 2007
Python Cairo e le glass window
Chi non conosce il lavoro di njpatel? Ormai i suoi avant window navigator e affinity sono noti ai più. Le sue idee sono innovative è apprezzate da molti bloggers. In questo post non voglio solo esaltare le sue produzioni (anche perché arriverei molto in ritardo in questo) ma voglio spingermi un po oltre per spiegare il modo di operare per ottenere risultati visivi simili ma utilizzando il nostro amato pitone.
A chi non sapesse a cosa mi riferisco, rimando a questo post sul blog di njpatel. Notate le trasperenze della finestra e gli altri widget inseriti normalmente al suo interno.
Come faccio ad ottenere un risultato simile in python?
#!/usr/bin/env python
import gtk
import cairo
if gtk.pygtk_version < (2, 10, 0):
print 'Questo esempio ha bisogno delle PyGtk >= 2.10'
raise SystemExit
def hex2float(hex):
ret = []
for i in range(4):
ic = int(hex[i])
ret.append( ic / 255.0 )
return ret
class TransparentWindow(gtk.Window):
__gsignals__ = {
'expose-event': 'override',
'screen-changed': 'override',
}
def __init__(self):
gtk.Window.__init__(self)
# Indichiamo alle GTK che vogliammo disegnare noi lo sfondo.
self.set_app_paintable(True)
# non vogliamo le decorazioni del window manager
self.set_decorated(False)
# usiamo il segnale button-press-event per permettere
# il "click e trascina" sulla finestra. Ricordiamo
# che non stiamo utilizzando i classici decoratori
# del window manager e non gestendo qeusto segnale
# non sarebbe possibile spostare la finestraself.add_events(gtk.gdk.BUTTON_PRESS_MASK)self.connect('button-press-event', self.on_button_press)
# Inizializziamo lo schermo
self.do_screen_changed()
def on_button_press(self, widget, event):
self.begin_move_drag(
event.button,
int(event.x_root),
int(event.y_root),
event.time)
def render_rect(self, cr, x, y, w, h, o):
# Crea un rettangolo con i bordi arrotondati
x0 = x
y0 = y
rect_width = w
rect_height = h
radius = 10 + o
x1 = x0 + rect_width
y1 = y0 + rect_height
cr.move_to(x0, y0 + radius)
cr.curve_to(x0, y0, x0, y0, x0 + radius, y0)
cr.line_to(x1 - radius, y0)
cr.curve_to(x1, y0, x1, y0, x1, y0 + radius)
cr.line_to(x1 , y1)
cr.line_to (x0 , y1)
cr.close_path()
def do_expose_event(self, event):
cr = self.window.cairo_create()
if self.supports_alpha:
cr.set_source_rgba(1.0, 1.0, 1.0, 0.0)
else:
cr.set_source_rgb(1.0, 1.0, 1.0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
(width, height) = self.get_size()
cr.move_to(0, 0)
cr.set_line_width(1.0)
cr.set_operator(cairo.OPERATOR_OVER)
pat = cairo.LinearGradient(0.0, 0.0, 0.0, height)
ex_list = [0xA1, 0xA8, 0xBB, 0xEC]
col = hex2float(ex_list)
pat.add_color_stop_rgba(0.0, col[0], col[1], col[2], col[3])
ex_list = [0x14, 0x1E, 0x3C, 0xF3]
col = hex2float(ex_list)
pat.add_color_stop_rgba(1.0, col[0], col[1], col[2], col[3])
self.render_rect(cr, 0, 0, width, height, 10)
cr.set_source(pat)
cr.fill()
# bordo luminoso
ex_list = [0xFF, 0xFF, 0xFF, 0x4e]
col = hex2float(ex_list)
cr.set_source_rgba(col[0], col[1], col[2], col[3])
self.render_rect(cr, 1.5, 1.5, width - 3 , height - 3, 10)
cr.stroke()
# bordo
ex_list = [0x00, 0x15, 0x1F, 0xe0]
col = hex2float(ex_list)
cr.set_source_rgba(col[0], col[1], col[2], col[3])
self.render_rect(cr, 0.5, 0.5, width - 1 , height - 1, 10)
cr.stroke()
ex_list = [0xFF, 0xFF, 0xFF, 0xFF]
col = hex2float(ex_list)
cr.set_source_rgba(col[0], col[1], col[2], col[3])
self.render_rect(cr, 0, 0, width , height, 10)
cr.stroke()
pat = cairo.LinearGradient(0.0, 0.0, 0.0, height)
cr.set_source(pat)
ex_list = [0xFF, 0xFF, 0xFF, 0xbb]
col = hex2float(ex_list)
pat.add_color_stop_rgba(0.0, col[0], col[1], col[2], col[3])
ex_list = [0x00, 0x00, 0x10, 0xaa]
col = hex2float(ex_list)
pat.add_color_stop_rgba(0.2, col[0], col[1], col[2], col[3])
self.render_rect(cr, 0, 0, width, 20, 10)
cr.fill()
# chiediamo esplicitamente ai figli di disegnarsi
# Se non lo facessimo non sarebbero visualizzati
# i widgets aggiunti alla TransparentWindow
children = self.get_children()
for c in children:
self.propagate_expose(c, event)
def do_screen_changed(self, old_screen=None):
screen = self.get_screen()
if self.is_composited():
print 'Il tuo schermo supporta il canale alpha!'
colormap = screen.get_rgba_colormap()
self.supports_alpha = True
else:
print 'Il tuo schermo non supporta il canale alpha! Il composite\
manager e\' attivo?'
colormap = screen.get_rgb_colormap()
self.supports_alpha = False
self.set_colormap(colormap)
class CoolAlpha:
def __init__(self):
window = TransparentWindow()
window.resize(400, 400)
eb = gtk.EventBox()
eb.set_visible_window(False)
eb.set_border_width(12)
window.add(eb)
main_box = gtk.VBox(False, 12)
eb.add(main_box)
hbox = gtk.HBox(False, 6)
main_box.pack_start(hbox, False)
button = gtk.Button()
button.set_relief(gtk.RELIEF_NONE)
button.connect("clicked", gtk.main_quit)
icon_box = gtk.HBox(False, 0)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_CLOSE,
gtk.ICON_SIZE_MENU)
icon_box.pack_start(image, False)
button.add(icon_box)
hbox.pack_end(button, False)
sw = gtk.ScrolledWindow()
sw.set_property("border-width", 20)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.textview = gtk.TextView()
self.textview.set_editable(False)
self.textview.set_cursor_visible(False)
sw.add(self.textview)
main_box.pack_start(sw, True)
window.show_all()
def set_text(self, text):
buf = self.textview.get_buffer()
buf.set_text(text)
if __name__ == '__main__':
a = CoolAlpha()
a.set_text("prova")
gtk.main()
Questo esempio è in gran parte una traduzione del codice in linguaggio c di affinity di njpatel con qualche piccolo ritocco da parte mia come l'inclusione del pulsante di chiusura in alto a destra e la textview centrale. Eseguendo l'esempio otterrete:
In genere le gtk non vengono usate per costruire finestre troppo "esotiche" e c'è un buon motivo per questo, ovvero mantenere la consistenza delle applicazioni sul desktop. Quindi nonostante queste finestre possono apparire molto belle a vedersi, il mio consiglio e di non abusarne ma utilizzarle in modo da ottenere una buona integrazione con il resto del desktop per non fare apparire la nostra applicazione come un "alieno".
13 maggio, 2007
Vmware Server su Ubuntu Feisty
Vi piace provare le nuove distro magari in beta o volete fare sperimentazioni di programmazione in rete ma non avete a disposizione i pc per farlo? La soluzione c'è e si chiama virtualizzazione. Vmware server è un software gratuito (non open source purtroppo) che dalla versione feisty è impacchettato e disponibile nei repository di software commerciale di canonical.
Installazione
Per installare vmware server è necessario prima di tutto abilitare i repository "non liberi" di canonical:
deb http://archive.canonical.com/ubuntu feisty-commercial main"Per farlo è possibile utilizzare synaptic o editare manualmente il file /etc/apt/sources.list
A questo punto è possibile installare il software usanto il comando:
sudo apt-get install vmware-serverL'installazione vi richiederà un codice di attivazione che potete ottenere gratuitamente sul sito di vmware
10 maggio, 2007
Baby e ybab: uno script python per usare i dizionari babylon
E' da tanto che non scrivo? Lo so ma fra qualche giorno se tutto procede come previsto dovrei laurearmi quindi il tempo da dedicare al blog è praticamente inesistente. Appena tutto sarà finito tornerò a sviluppare cGmail e a postarvi gli studi su python e tutto il resto. Per ora, per non lasciarvi proprio a bocca asciutta, vi propongo un piccolo "bocconcino" che ho sviluppato qualche tempo fa e che potrebbe risultare utile (o quantomeno potrebbe essere uno spunto) a qualcuno di voi. Si tratta di un semplice script (indovinate in che linguaggio? . . . Bravi :) ) che interroga il database dei dizionari babylon, si presenta come Firefox 2 e poi interpreta l'html per tirare fuori le informazioni sul lemma ricercato.
Il codice python
Come lo installo?
#! /usr/bin/env python
import urllib2
import re
import sys
from sgmllib import SGMLParser
red='\033[0;31m'
RED='\033[1;31m'
blue='\033[0;34m'
BLUE='\033[1;34m'
cyan='\033[0;36m'
CYAN='\033[1;36m'
NC='\033[0m'
ROWLEN = 60
class Parser(SGMLParser):
def __init__(self):
SGMLParser.__init__(self)
self.must_print = False
def reset(self):
SGMLParser.reset(self)
def write(self, data):
sys.stdout.write(data)
sys.stdout.flush()
def start_div(self, attrs):
for attr, value in attrs:
if attr == "class":
if value == "term":
self.write(RED + '\n')
self.must_print = True
if value == "definition":
self.must_print = True
def end_div(self):
self.must_print = False
self.write(NC)
def handle_data(self, data):
if not self.must_print: return
if data.strip() == "": return
tmp = data.strip()
tmp = data.replace('\n', '')
count = len(tmp)
if count > ROWLEN:
pieces = count / ROWLEN
for i in range(pieces):
l = ROWLEN * i
u = ROWLEN * (i + 1)
self.write(tmp[l:u] + '\n')
else:
self.write(tmp + '\n')
def http_req(url, data):
req = urllib2.Request(url, data)
req.add_header('User-Agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20061201 Firefox/2.0.0.4 (Ubuntu-feisty)')
req.add_header('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7')
req.add_header('Accept', 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5')
stream = urllib2.urlopen(req)
out = stream.read()
stream.close()
return out
def usage():
print "Usage: baby parola\n";
def search(word, lang):
out = http_req('http://info.babylon.com/onlinebox.cgi',
'rt=ol&tid=pop&uil=EN&cid=CD1&term='+word+'&tl='+lang)
return out
if __name__ == "__main__":
import os
args = sys.argv[1:]
if args[0] == None:
usage()
sys.exit(1)
word = args[0]
out = ""
appname = os.path.basename(sys.argv[0])
print appname
if appname == "baby":
out = search(word, "EN")
elif appname == "ybab":
out = search(word, "IT")
p = Parser()
p.feed(out)
p.close()
Copiate ed incollate il codice in un file che chiamerete baby (Attenzione: il nome è importante). Date i permessi di esecuzione al file e copiatelo in una directory inclusa nel vostro path (ad esempio /usr/local/bin). A questo punto create un link simbolico al file con nome ybab. Esempio di tutti i passaggi (supponiamo che avete salvato lo script di cui sopra su un file di nome baby sul vostro desktop):
sudo cp ~/Desktop/baby /usr/local/bin
sudo chmod +x /usr/local/bin/baby
sudo ln -s /usr/local/bin/baby /usr/local/bin/ybab
Come si usa?
L'uso è semplicissimo. Invocando baby [lemma_da_cerare] verrà considerata come lingua target l'inglese, invocando invece ybab [lemma_da_cercare] verrà considerato come target l'italiano.
Esempio:
Purtroppo per alcuni lemmi l'output non è così pulito (ci sarebbe da migliorare il parser, suggerimenti sono ben accetti. Io non mi ci sono dedicato più di tanto)
$ ybab glad
ybab
glad
agg.
felice, contento, lieto; gioioso
s.
gladiolo (fiore)
GLAD
CONTENTO. LIETO. FELICE. ALLIETARE. RALLEGRARE. GLADIOL
Come funziona
Le informazioni che seguono sono piuttosto tecniche. Se vi interessa solo il programmino e non sapere come funziona potete tranquillamente evitare di proseguire nella lettura.
Lo script utilizza la urllib2 di python per fare una semplice richiesta al sito di babylon. Per conoscere l'esatto URL da interrogare e i parametri da passargli è necessario studiarsi un po il sito, conoscere un minimo di programmazione web, sapere come funzionano le form ed avere un po di pazienza. Una volta noto il meccanismo di interrogazione utilizzato dal sito in questione, il resto è "semplice". In questo caso l'output della richiesta http, viene "parsato" (passatemi il termine) dall'apposito parser che utilizza la libreria sgmllib. Un aspetto interessante dello script è il modo che utilizza per cambiare la sua funzionalità (in questo caso la lingua target). Ricordiamo che il primo parametro passato ad un programma è sempre il suo nome. Quindi distinguendo il nome del primo parametro è possibile effettuare operazioni diverse
. In questo caso se il programma viene invocato come baby viene utilizzata la lingua inglese, mentre invocato come ybab quella italiana.
29 aprile, 2007
pygtk: un About Dialog con link cliccabile
Creare un about dialog con link di riferimento cliccabile è una di quelle cose che vediamo in molte applicazioni ma per la quale non è semplice trovare documentazione a riguardo.
Scoprire come fare per me non è stato semplicissimo e quindi ho pensato che una soluzione pronta potrebbe essere di aiuto a qualcuno.
Cosa stiamo per realizzare
Ciò che ci apprestiamo a realizzare è un dialogo di informazione come quello che potete vedere in figura:
Da notarsi che il link è cliccabile e cliccandoci sopra verrà aperto un browser che vi porterà guarda caso proprio a quell'indirizzo :) Le librerie gtk (e i rispettivi bindings per python) mettono a disposizione un apposito widget per creare i dialoghi di informazione. Il widget in questione permette di settare facilmente il nome dell'applicazione, la versione, gli autori, la licenza, i traduttori e altre cosette interessanti. Stranamente però non permette di impostare in modo altrettanto semplice un url che risponda al click del mouse. Per farlo è necessario utilizzare la funzione gtk.about_dialog_set_url_hook e indicare una callback da richiamare quando l'utente clicca sul link. La callback in questione dovrà poi occuparsi di creare un nuovo processo per lanciare il browser.
Il codice python
import gtk
import subprocess
def on_url(d, link, data):
subprocess.Popen(["firefox", "http://linubuntu.blogspot.com"])
gtk.about_dialog_set_url_hook(on_url, None)
def create_dialog():
dlg = gtk.AboutDialog()
dlg.set_version("0.1")
dlg.set_name("app")
dlg.set_license("Puoi fare di questo software quello che ti pare")
dlg.set_authors(["redgun"])
dlg.set_website("http://linubuntu.blogspot.com")
def close(w, res):
if res == gtk.RESPONSE_CANCEL:
w.hide()
dlg.connect("response", close)
return dlg
if __name__ == "__main__":
dlg = create_dialog()
dlg.run()
Ricordate che la finestra di dialogo di suo non risponde al click sul pulsante chiudi ma sarà necessario impostare una funzione di callback per il segnale response come nel codice.
27 aprile, 2007
Una chicca da Fedora 7
Era da tanto che non mi interessavo alla mia vecchia distribuzione (vedi qui). Oggi noto su ditsrowatch che è uscita la versione test 4 di Fedora 7. Dalle note di rilascio scopro che adesso anche fedora usa il sistema a live cd installabile, che non ha ancora abbandonato yum (credo che non esista un gestore di pacchetti peggiore), e che usa un nuovo tema di icone. Ok, mi dico, vediamo questo tema e cerco uno screenshot. Trovo questo:
Le icone sono carine ma un'altra cosa mi colpisce: la finestra delle preferenze si sviluppa su due livelli, un piccolo colpo di genio a mio parere.
Questa credo sia un ottima soluzione per il menù delle preferenze. L'altra opportunità sarebbe il centro di controllo gnome, ma la trovo poco funzionale. Il centro di controllo non è così immediato come i menù. Ecco come compare invece il menù delle preferenze sul mio desktop:
Decisamente meglio quello di fedora. Per una volta devo bastonare Ubuntu eh eh :)
P.S. Oggi blogger sembra avere qualche problema e a volte non compaiono gli articoli recenti e i commenti recenti del blog. Mi scuso per l'inconveniente.
23 aprile, 2007
Ubuntu Feisty: Impressioni d'uso
Ormai uso Feisty da circa un mesetto e a questo punto posso esprimere le mie valutazioni.
La mia storia con linux
Ho iniziato ad usare linux all'epoca della Mandrake 8 (poco prima avevo provato una SuSE [non ricordo quale versione]). Ho abbandonato Mandrake per una RedHat 9 sulla quale ho iniziato le "sperimentazioni serie", dalla ricompilazione del kernel, allo studio e modifica del processo di avvio, alla configurazione manuale di devices all'epoca del kernel 2.4 un po esotici come il bluetooth etc. Ho usato fedora fino alla versione 3 che ho abbandonato perché condividevo poco la sua politica, alla ricerca di una distribuzione che fosse semplice per l'uso quotidiano ma abbastanza aperta da regalarmi succulenti momenti di puro e gudurioso hacking, e mi sono fermato su ubuntu dapper.
Da allora non ho mai più installato un'altra distro. Ubuntu mi piace, amo persino il famoso marrone cacchina tanto contestato, il suo simbolo e tutto il resto.
Mai quanto con la Feisty però avevo avuto la sensazione di puro godimento nell'utilizzo del computer, il senso di quasi morboso piacere nel cliccare ed osservare come un bimbo le barre del progresso colorarsi, il pesce wanda nuotare nel pannello, le finestre fluttuanti danzare sulle loro trasparenze. Il tutto nella consapevolezza della libertà, della libera divulgazione delle conoscenze di un sistema aperto che cresce grazie a noi utenti verso la direzione che noi indichiamo e che nessun altro ci impone.
Ubuntu: la distro perfetta
Ubuntu è quasi perfetta. Mancano solo alcuni piccoli accorgimenti. Stupidaggini come qualche icona vecchiotta ed inconsistente qua e la (vedi menù giochi), qualche piccolo bug sporadico e altre piccolezze.
La prova di ciò è l'interessamento sempre crescente da parte degli utenti per questa distro. Ubuntu Feisty ha stupito anche i suoi stessi sviluppatori quando i mega server che ospitano ubuntu.com e canonical.com erano praticamente irraggiungibili nel giorno del rilascio. Forse avete notato che il sito di ubuntu è stato sostituito per qualche ora con una pagina statica per cercare di diminuire il carico sui servers. Insomma sarà per questo Vista che sembra non riscuotere molto successo, sarà per la consapevolezza di una alternativa che inizia a fare breccia nelle menti ma la comunità di Ubuntu inizia ad ottenere un peso consistente nel palcoscenico mondiale e io non posso che esserne felice!
Buon ubuntu a tutti!
19 aprile, 2007
Un modulo python per gestire le chiavi in gconf
Aggiornamento: ho aggiornato il modulo che è ora una classe ed include il metodo clean_section
L'ambiente desktop gnome mette a disposizione un ottimo sistema per memorizzare le impostazioni delle sue applicazioni: gconf.
Come funziona gconf?
Gconf è un sistema per la memorizzazione delle configurazioni basato su XML. La configurazione è contenuta in un albero ed ogni applicazione può costruire un suo sottoalbero nel quale memorizzare le proprie impostazioni. Gconf è composto da un demone (gconfd), che si occupa di notificare le applicazioni di eventuali modifiche alla loro configurazione (magari fatte da una applicazione esterna come gconf-editor) e di mantenere una cache dei valori in modo che le applicazioni non siano costrette a dover rifare il parsing del file XML ogni volta, e da un insieme di librerie che rendono semplice l'accesso all'albero gconf.
Come posso accedere/creare chiavi gconf con python?
Usare gconf da python è veramente semplice anche se un minimo di astrazione in più non fa certo male. Per questo vi voglio riportare un piccolo modulo python che permette di comprendere l'uso di gconf oltre che semplificare il processo di creazione/accesso/modifica delle chiavi.
Il codice python
import gtk
import gconf
class MyGconf:
def __init__(self, appname):
self.basedir = "/apps/" + appname
self.client = gconf.client_get_default()
def add_section(self, name, keys):
"""
Aggiunge una sottodirectory a self.basedir e la riempie
con le chiavi specificate nel dizionario keys
"""
dir = self.basedir + "/" + name + "/"
for key, value in keys.iteritems():
path = dir + key
self.client.set_string(path, value)
def clean_section(self, name):
"""
cosa potrebbe mai fare questo metodo :)
"""
dir = self.basedir + "/" + name
self.client.recursive_unset(dir, 0)
def get_sections(self):
"""
Ritorna una tupla contenente l'elenco delle sezioni
contenute in self.basedir
"""
return self.client.all_dirs(self.basedir)
def get_key(self, name):
"""
Ritorna il valore di una specifica chiave.
name deve essere un percorso relativo a self.basedir
"""
path = self.basedir + "/" + name
return self.client.get_string(path)
def set_key(self, name, value):
"""
Imposta il valore della chiave name a value
"""
path = self.basedir + "/" + name
self.client.set_string(path, value)
if __name__ == "__main__":
mg = MyGconf("myapp")
params = {
"test": "test value",
"test2" : "test2 value"
}
mg.add_section("mydir", params)
mg.add_section("mydir2", {"test": "value"})
print mg.get_key("mydir/test")
print mg.get_sections()
mg.set_key("mydir/test", "new value")
print mg.get_key("mydir/test")
mg.remove_section("mydir")
Il codice dovrebbe essere autoescplicativo ;)