2 # -*- coding: utf-8 -*-
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
16 # str name : nom du pointeur
17 # int id : id du pointeur
18 # SlavePointer slaves[] : tableau contenant la liste des slaves
20 def __init__(self
, name
, id):
25 def add_slave(self
, slave
):
26 self
.slaves
.append(slave
)
28 # cette classe défini les souris esclaves des pointeurs
31 # str name : nom de la souris
32 # int id : id de la souris
34 def __init__(self
, name
, 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
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
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"
52 # fermeture de la fenetre
53 def on_mainWindow_destroy(self
, widget
):
56 # au clic sur le bouton recharger
57 def on_toolbutton_refresh_clicked(self
, widget
):
60 # au clic sur le bouton fichier>quitter
61 def on_imagemenuitem_quit_activate(self
, widget
):
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()
78 print "Erreur : aucun nom donné au pointeur"
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"
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
)
90 print "Impossible de creer le pointeur "+name
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)
104 print "Impossible de supprimer le pointeur "+id
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()
117 # recupere la liste de xinput
119 # on efface tous les masters
121 # on recupere la liste avec la commande xinput list
122 liste
= os
.popen("xinput list --short")
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]))
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"))
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
155 # affiche dans la fenêtre la liste des pointeurs
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
164 treestore
= gtk
.TreeStore(str)
166 # A present ajoutons des donnees : 4 lignes ayant 3 lignes filles
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)
199 def fonct_rappel_deposer(self
, treeview
, contexte
, x
, y
, selection
, info
, dateur
):
200 depot_info
= treeview
.get_dest_row_at_pos(x
, y
)
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)
208 print "Impossible d'effectuer l'attachement"
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__":