updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / gtk-xinput / gtk-xinput.py
blob52560720afeb6fb21799575bf6f8d479894c67a0
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
4 import pygtk
5 pygtk.require("2.0")
6 import gtk
7 import os
9 # ce programme permet de gérer les pointeurs facilement à l'aide de xinput sans passer par le terminal
10 # écrit par Hugo Denisse, sous liscence GPL
12 # cette classe défini les pointeurs affichés à l'écrans
13 # ces pointeurs contiennent des "slaves" qui sont les souris associées à ces pointeurs
15 # variables membre :
16 # str name : nom du pointeur
17 # int id : id du pointeur
18 # SlavePointer slaves[] : tableau contenant la liste des slaves
19 class MasterPointer:
20 def __init__(self, name, id):
21 self.name=name
22 self.id = id
23 self.slaves = []
25 def add_slave(self, slave):
26 self.slaves.append(slave)
28 # cette classe défini les souris esclaves des pointeurs
30 # variables membre :
31 # str name : nom de la souris
32 # int id : id de la souris
33 class SlavePointer:
34 def __init__(self, name, id):
35 self.name=name
36 self.id = id
37 # cette classe permet d'afficher à l'écran la liste des pointeurs, mais aussi de modifier cette liste
38 # elle gère donc la partie graphique et la partie liée à xinput
40 # variables membre :
41 # gtk.Builder interface : fenêtre du programme
42 # gtk.TreeView treeview : arborescence des pointeurs affichée
43 # MasterPointer masters[] : tableau contenant la liste des pointeurs
44 class Window:
45 def __init__(self):
46 self.interface = gtk.Builder()
47 self.interface.add_from_file('gtk-xinput.glade')
48 self.interface.connect_signals(self)
49 self.treeview="no_treeview_yet"
50 self.refresh()
52 # fermeture de la fenetre
53 def on_mainWindow_destroy(self, widget):
54 gtk.main_quit()
56 # au clic sur le bouton recharger
57 def on_toolbutton_refresh_clicked(self, widget):
58 self.refresh()
60 # au clic sur le bouton fichier>quitter
61 def on_imagemenuitem_quit_activate(self, widget):
62 gtk.main_quit()
64 # au clic sur le bouton aide>à propos
65 def on_imagemenuitem_about_activate(self, widget):
66 self.interface.get_object("aboutdialog").run()
67 self.interface.get_object("aboutdialog").hide()
69 # au clic sur le bouton ajouter
70 def on_toolbutton_add_clicked(self, widget):
71 self.interface.get_object("dialog_add").run()
72 self.interface.get_object("dialog_add").hide()
74 # au clic sur le bouton ajouter de la fenetre de dialogue ajouter
75 def on_button_add_clicked(self, widget):
76 name = self.interface.get_object("entry_add").get_text()
77 if(name==""):
78 print "Erreur : aucun nom donné au pointeur"
79 return
81 # on vérifie qu'il n'ya que des lettres ou chiffres dans le nom
82 if(os.popen("echo '"+name+"' |sed 's/[0-Z]*//g'").readlines()[0].rstrip()!=""):
83 print "Erreur : nom du pointeur invalide"
84 return
86 print "Ajout du pointeur "+name
87 # on execute la commande d'insertion et on recupere la valeur du exit pour voir si il y a une erreur
88 err = os.system("xinput create-master "+name)
89 if(err):
90 print "Impossible de creer le pointeur "+name
91 else:
92 self.refresh()
94 # au clic sur le bouton supprimer
95 def on_toolbutton_remove_clicked(self, widget):
96 # on recupere la ligne selectionnée sous forme de tuple (TreeModel, TreeIter)
97 selected_line = self.treeview.get_selection().get_selected()
98 # on recupere la valeur affichée sur cette ligne
99 selected_line = selected_line[0].get_value(selected_line[1],0)
100 id = os.popen("echo '"+selected_line+"' |cut -d= -f2 | sed 's/)//g'").readlines()[0].rstrip()
101 # on execute la commande d'insertion et on recupere la valeur du exit pour voir si il y a une erreur
102 err = os.system("xinput remove-master "+id)
103 if(err):
104 print "Impossible de supprimer le pointeur "+id
105 else:
106 self.refresh()
109 # retourne le nom et l'id trouvés à partir de la chaine passée en argument
110 def get_name_and_id(self, line):
111 name = os.popen('echo "'+line+"\" | sed 's/⎡ //' | sed 's/⎜ ↳ //' | sed 's/∼ //' | cut -f1")
112 name = name.readlines()[0].rstrip()
113 id = os.popen('echo "'+line+'" | cut -d= -f2 | cut -f1')
114 id = id.readlines()[0].rstrip()
115 return (name,id)
117 # recupere la liste de xinput
118 def refresh(self):
119 # on efface tous les masters
120 self.masters = []
121 # on recupere la liste avec la commande xinput list
122 liste = os.popen("xinput list --short")
123 nbMasterCreated = 0
124 for line in liste.readlines():
125 # si la ligne lue parle d'un master pointer
126 if(line.__contains__("[master pointer")):
127 data=self.get_name_and_id(line)
128 # on creer un nouveau master
129 self.masters.append(MasterPointer(data[0],data[1]))
130 nbMasterCreated+=1
131 # si la ligne lue parle d'un slave pointer
132 if(line.__contains__("[slave pointer")):
133 data=self.get_name_and_id(line)
134 slave = SlavePointer(data[0],data[1])
135 # on creer un nouveau slave dans le dernier master créé
136 self.masters[nbMasterCreated-1].add_slave(slave)
137 # si la ligne lue parle des slaves sans masters
138 if(line.__contains__("[floating slave]")):
139 # si le master servant à contenir les slaves n'existe pas on le creer
140 if(self.masters[nbMasterCreated-1].id!="floating"):
141 self.masters.append(MasterPointer("Souris sans pointeur","floating"))
142 nbMasterCreated+=1
143 data=self.get_name_and_id(line)
144 slave = SlavePointer(data[0],data[1])
145 # on creer un nouveau slave dans le dernier master créé
146 self.masters[nbMasterCreated-1].add_slave(slave)
148 # on affiche les noms et id des masters et de leurs slaves
149 for master in self.masters:
150 print "master : name="+master.name+", id="+master.id
151 for slave in master.slaves:
152 print "slave : name="+slave.name+", id="+slave.id
153 self.show_list()
155 # affiche dans la fenêtre la liste des pointeurs
156 def show_list(self):
157 # on récupere la zone réservée à l'affichage
158 zone = self.interface.get_object("scrolledwindow")
159 if(self.treeview!="no_treeview_yet"):
160 zone.remove(self.treeview)
162 # Creation d'un TreeStore avec une colonne de type chaine, pour servir
163 # de modele
164 treestore = gtk.TreeStore(str)
166 # A present ajoutons des donnees : 4 lignes ayant 3 lignes filles
167 # chacune
168 for i in range(self.masters.__len__()):
169 m_iter = treestore.append(None, [self.masters[i].name+" (id="+self.masters[i].id+")"])
170 for j in range(self.masters[i].slaves.__len__()):
171 treestore.append(m_iter, [self.masters[i].slaves[j].name+" (id="+self.masters[i].slaves[j].id+")"])
173 # creation du TreeView en utilisant notre TreeStore
174 self.treeview = gtk.TreeView(treestore)
175 # on autorise le drag'n'drop
176 self.treeview.enable_model_drag_dest([('text/plain', 0, 0)],gtk.gdk.ACTION_MOVE)
177 self.treeview.connect("drag-data-received", self.fonct_rappel_deposer)
178 self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, [('text/plain', 0, 0)],gtk.gdk.ACTION_COPY)
179 self.treeview.connect("drag-data-get", self.fonct_rappel_glisser)
181 # creation du TreeViewColumn pour afficher les donnees
182 tvcolumn = gtk.TreeViewColumn('Liste des pointeurs')
183 # on place tvcolumn dans notre TreeView
184 self.treeview.append_column(tvcolumn)
185 # creation d'un CellRendererText pour afficher les donnees
186 cell = gtk.CellRendererText()
187 # on place cell dans le TreeViewColumn et on lui permet de s'etirer
188 tvcolumn.pack_start(cell, True)
189 # reglage de l'attribut "text" de cell sur la colonne 0 - recupere le
190 # texte dans cette colonne du TreeStore
191 tvcolumn.add_attribute(cell, 'text', 0)
192 self.treeview.expand_all()
193 #self.treeview.set_visible(True)
194 # on ajoute le treeview dans l'interface
195 zone.add(self.treeview)
196 #zone.set_visible(True)
197 zone.show_all();
199 def fonct_rappel_deposer(self, treeview, contexte, x, y, selection, info, dateur):
200 depot_info = treeview.get_dest_row_at_pos(x, y)
201 if(depot_info):
202 chemin, position = depot_info
203 # on récupère l'id du master dans lequel on vient de déposer
204 id = self.masters[chemin[0]].id
205 print "attaching "+self.source_id+" to "+id
206 err = os.system("xinput reattach "+self.source_id+" "+id)
207 if(err):
208 print "Impossible d'effectuer l'attachement"
209 else:
210 self.refresh()
212 def fonct_rappel_glisser(self, treeview, contexte, selection, info, dateur):
213 treeselection = treeview.get_selection()
214 modele, iter = treeselection.get_selected()
215 texte = modele.get_value(iter, 0)
216 self.source_id = os.popen("echo '"+texte+"' |cut -d= -f2 | sed 's/)//g'").readlines()[0].rstrip()
218 if __name__ == "__main__":
219 Window()
220 gtk.main()