Skript nedělá nic jiného, než že vám umožní naklikat si v seznamu sezení dostupných na vašem systému, která z nich se vám v nabídce přihlašovací obrazovky zobrazí a která nikoli. Není to nijak ošetřeno proti blbosti, takže vězte, že když si zakážete všechna sezení, nikam se příště nepřihlásíte. Což nebude problém opravit z konzole. Funguje pro LightDM a GDM.
Jak to funguje
Skript provádí manipulaci s názvy spouštěčů xsessions v adresáři /usr/share/xsessions/ a když položku v okně odškrtnete, prostě k názvu spouštěče přidá koncovku .disabled, čímž ho znefunkční a systém ho neuvidí. A samozřejmě to umí zas vrátit zpět. Pokud se stane, že se po aktualizaci v xsessions objeví duplicitní spouštěč spouštěče dříve zakázaného, bude ten původní (s koncovkou .disabled) po startu skriptu automaticky smazán a uživatel si může sezení zakázat znovu, pokud bude chtít.Níže uvedený skript zkopírujete do souboru pojmenovaného třeba sselector.py a pak ho budete spouštět z terminálu jako root příkazem:
# python sselector.py
z adresáře, kde se skript bude nacházet, jinak zadáte celou cestu a samozřejmě můžete použít sudo pro spuštění s právy roota. Kód je funkční jak pro Python 2, tak i 3
Výsledek bude vypadat podobně jako na obrázku z úvodu (podle toho, jaká prostředí jste si do systému nainstalovali).
sselector.py
#!/usr/bin/env python #-*- coding: UTF-8 -*- # Select sessions which will be available in system login screen import os, sys if not os.geteuid()==0: print('Error: Only root can use this script') sys.exit(1) from gi.repository import Gtk import re path = '/usr/share/xsessions/' regn = re.compile(r'^Name=') regd = re.compile(r'\.disabled$') class SS(Gtk.Window): def __init__(self): super(SS, self).__init__() self.set_position(Gtk.WindowPosition.CENTER) self.set_title('Sessions Selector') self.set_border_width(10) self.connect('destroy', self.quit) vb = Gtk.VBox(False, 0) self.add(vb) lt = Gtk.Label() lt.set_markup('<b>Select Sessions:</b>\n') lt.set_alignment(xalign=0, yalign=0.5) vb.add(lt) lf = self.filter_duplicates([f for f in os.listdir(path) if '.desktop' in f]) lh = [] for f in lf: with open('%s%s' %(path,f), 'r') as d: for l in d: if regn.match(l): nm = l[5:-1] break ln = Gtk.Label(nm) sw = Gtk.CheckButton() if not regd.search(f): sw.set_active(True) sw.connect('notify::active', self.switch, regd.sub('', f)) hb = Gtk.HBox(False, 20) hb.pack_start(ln, False, False, 0) hb.pack_end(sw, False, False, 0) lh.append([nm, hb]) for i in sorted(lh, key=lambda i:i[0].lower()): vb.pack_start(i[1], False, False, 3) self.show_all() def filter_duplicates(self, lf): l = [] for f in [regd.sub('', f) for f in lf]: if not f in l: l.append(f) else: try: os.remove('%s%s.disabled'%(path,f)) except: pass else: lf.remove('%s.disabled'%f) return lf def switch(self, w, e, f): p = '%s/%s' %(path, f) if w.get_active(): os.rename('%s.disabled'%p, p) else: os.rename(p, '%s.disabled'%p) def quit(self, *args): Gtk.main_quit() if __name__ == '__main__': SS() Gtk.main()
sselector.py komentovaný
#!/usr/bin/env python #-*- coding: UTF-8 -*- # Select sessions available in system login screen import os, sys if not os.geteuid()==0: # root má ID 0, pokud skript spustil jiný uživatel, print('Error: Only root can use this script') # vypíšeme chybu sys.exit(1) # a ukončíme program from gi.repository import Gtk import re path = '/usr/share/xsessions/' # adresář, kde jsou umístěné spouštěče jednotlivých sezení regn = re.compile(r'^Name=') # předkompilujeme si regulární výrazy, regd = re.compile(r'\.disabled$') # které budeme potřebovat hledat class SS(Gtk.Window): # třída bude odvozena od Gtk.Window def __init__(self): super(SS, self).__init__() # inicializace # nastavení vlastností okna: self.set_position(Gtk.WindowPosition.CENTER) # Okno se zobrazí uprostřed obrazovky self.set_title('Sessions Selector') # Text, který se zobrazí v záhlaví okna self.set_border_width(10) # Okno bude mít okraj silný 10 bodů self.connect('destroy', self.quit) # pokus o zavření okna vyvolá metodu quit definovanou níže # výrova součástí okna: vb = Gtk.VBox(False, 0) # vytvoří nehomogenní (argument False,vložené objekty nebudou mít stejnou šířku) # vertikální box, do kterého se další grafické objekty skládají na výšku zhora dolu self.add(vb) # box přidáme do okna lt = Gtk.Label() # vytvoří štítek, do kterého budeme moct napsat nadpis lt.set_markup('<b>Select Sessions:</b>\n') # na štítek napíšeme tučný text pomocí značkovacího jazyka pango lt.set_alignment(xalign=0, yalign=0.5) # text se normálně umisťuje doprostřed štítku a my chceme hned od leva vb.add(lt) # štítek přidáme do boxu, který jsme si vytvořili výše lf = self.filter_duplicates([f for f in os.listdir(path) if '.desktop' in f]) # načteme seznam souborů obsahujících koncovku '.desktop' a zbavený duplicit lh = [] # prázdný seznam, do kterého budeme přidávat nalezená sezení for f in lf: # projdeme seznam souborů with open('%s%s' %(path,f), 'r') as d: # každý soubor otevřeme for l in d: # a na jednotlivých řádcích if regn.match(l): # budeme hledat řetězec 'Name=' na začátku (viz kompilace regulárního výrazu výše) nm = l[5:-1] # když najdeme, vyřízneme jen samotné jméno (poslední znak je konec řádku) break # a přerušíme smyčku. tím se zároveň ukončí blok 'with' a soubor se automaticky zavře ln = Gtk.Label(nm) # přpravíme si štítek, na který napíšeme získané jméno sezení sw = Gtk.CheckButton() # vytvoříme zaškrtávátko # sw = Gtk.Switch() # nebo můžeme místo zaškrtávátka vytvořit přepínač pokud se nám líbí víc if not regd.search(f): # pokud jméno souboru nekončí na ".disabled" (viz kompilace regulárního výrazu výše) sw.set_active(True) # přepneme přepínač do aktivní polohy sw.connect('notify::active', self.switch, regd.sub('', f)) # na signál vyvolávaný aktivací přepínače # napojíme metodu switch (definujeme níž), které bude při volání předáno jméno souboru, # ze kterého rovnou odstraníme případnou koncovku ".disabled" hb = Gtk.HBox(False, 20) # dále vytvoříme horizontální box, který nebude homogenní (vložené objekty nebudou mít stejnou šířku) # jednotlivé objekty budou mít mezi sebou 20 bodů hb.pack_start(ln, False, False, 0) # do boxu přidáme štítek se jménem hb.pack_end(sw, False, False, 0) # a vedle přepínač # pack_start()/pack_end() určují, k jakému konci boxu se bude přidaný objekt zarovnávat lh.append([nm, hb]) # do seznamu sezení si přidáme (v seznamu) jméno a vytvořený box # a pokračuje se na další zezení, pokud ještě nějaké zbývá for i in sorted(lh, key=lambda i:i[0].lower()): # nakonec projedeme vytvořený seznam sezení setříděný podle abecedy, # nezávisle na malých/velkých písmenech, položku po položce # key se přiřazuje funkce, jejíž výstupem je klíčový řetězec, podle kterého se bude řadit # protože chceme setřídit seznam, který obsahuje seznamy složené nejen z řeťězců (jsou tam krom jmen i objekty Gtk.HBox) # nelze použít univerzální str.lower(), která by se snažila převést na malá písmena vše (a samozřejmě by řvala). # místo toho použijeme lambda funkci, která vezme aktuální položku seznamu, oddělí jen její prní část obsahující řetězec se jménem # a převede ho na malá písmena. seznam se tedy řadí čistě podle jmen vb.pack_start(i[1], False, False, 3) # pro každou položku seznamu vyjmeme jen box obsahující jméno sezení a přepínač # a přidáme do hlavního vertikálního boxu okna self.show_all() # nakonec poskládané okno necháme zobrazit na monitoru def switch(self, w, e, f): # metoda, která je volána při přepnutí každého přepínače v okně # předávány jsou argumenty 'w' je ukazatel na objekt (přepínač), který volání inicioval, # v 'e' jsou podrobnosti události a v 'f' je jméno souboru, který patří sezení, jehož přepínač volání způsobil p = '%s/%s' %(path, f) # zkompletujeme si celou cestu k souboru if w.get_active(): # zjistíme, jak v jaké poloze je přepínač os.rename('%s.disabled'%p, p) # pokud je zapnutý, přejmenujeme soubor se spouštěčem tak, že mu přidáme koncovku '.disabled' else: os.rename(p, '%s.disabled'%p) # pokud je vypnutý, naopak z názvu koncovku '.disabled' odebereme def filter_duplicates(self, lf): l = [] for f in [regd.sub('', f) for f in lf]: # projdeme seznam souborů zbavených případné koncovky .disable if not f in l: # pokud již položku nemáme v seznamu, l.append(f) # přidáme jí tam else: try: os.remove('%s%s.disabled'%(path,f)) # jinak zkusíme zakázanou variantu duplicitního spouštěče odstranit z disku except: pass else: lf.remove('%s.disabled'%f) # a pokus se to povede, tak i z původního seznamu return lf # upravený seznam vrátíme zpět def quit(self, *args): # tato metoda se volá, když uživatel klikne na křížek pro zavření okna, nebo ostatních pokusech o zavření okna Gtk.main_quit() # jednoduše se přeruší hlavní smyčka Gtk if __name__ == '__main__': # pokud se skript spouští samostatně, ne jako součást jiného skriptu SS() # inicializuje se třída SS Gtk.main() # a spustí se hlavní smyčka Gtk, která čeká na události v aplikaci, aby je zpracovala. bez ní by se okno ani nevykreslilo.
Doufám, že jsou ty komentáře alespoň tak srozumitelné, původní kód jsem doplňoval o eliminaci duplicit, které mohou vzniknout po aktualizaci, kdy se zapíše nový spouštěč, když je ten původní zakázaný a pak to dopisoval do komentované části. Každopádně jsem na svých systémech otestoval funkčnost obou verzí.
Jistě je toho více, co by taková aplikace mohla umět řešit, ale mám zásadnější nedodělky..
Nějaká dokumentace:
http://python-gtk-3-tutorial.readthedocs.org/en/latest/index.html
File "./sselector.py", line 39
OdpovědětVymazatwith open('%s%s' %(path,f), 'r') as d:
^
Hází ti to chybu syntaxe? Pokud máš dostatečně starou verzi Pythonu, myslím, že starší než 2.5, tak musíš použít klasickou konstrukci open/close.. Nebo použít novější Python.
Vymazatpython --version
VymazatPython 2.7.3
Na stejné verzi na Ubuntu 12.04 jsem to psal a násobné přezkoušení kódu zkopírovaného odsud potvrzuje funkčnost. Zajímalo by mě celé znění toho chybového hlášení, na chybu syntaxe to nevypadá.
VymazatPokud tedy nekopíruješ ten komentovaný, tam se mi koukám nějak pomrvilo formátování..
Tak už jsem opravil i tu komentovanou verzi. Díky za upozornění.
Vymazat