Warto było napisać artykuł o Bluetile by dowiedzieć się o PyTyle. Bo jest to niemal dokładnie takie narzędzie, jakiego szukałem - mechanizm automatycznego rozmieszczania okien który w pełni zgodnie współistnieje nie tylko z Gnome ale i z Compizem (a także z wieloma innymi menedżerami okien) i po prostu dodaje automatyczne rozmieszczanie okienek tam, gdzie sobie tego zażyczę, niczego poza tym nie psując.
Jak to działa
Celem PyTyle jest kafelkowanie okien, czyli automatyczne rozmieszczanie ich na desktopie tak, by się nie nakrywały i dzieliły przestrzeń w ustalony sposób. Jednak - w przeciwieństwie do Bluetile, XMonad, awesome i podobnych narzędzi - nie jest ono pełnym menedżerem okien.
PyTyle uruchamia się jako dodatkowy program, korzystający z usług właściwego menedżera okien (Compiza, Openboksa, Fluxboksa, ...). Obserwuje wydarzenia na desktopie (pojawianie się i znikanie okien) i reaguje na nie, nakazując właściwemu menedżerowi okien odpowiednie reorganizacje (przesuwanie, zmienianie wielkości). Działa zatem podobnie do opisywanego wcześniej Devil's Pie, tyle że ma inny cel.
Ciekawostka: przy uruchamianiu nowego programu albo rozwijaniu okna z paska niekiedy da się przez ułamek sekundy zauważyć je w nieskafelkowanym położeniu, zanim PyTyle je złapie i przemieści.
Dzięki temu używanie PyTyle nie wymaga pożegnania się z ulubioną skórką Gnome i przydatnymi efektami Compiza, dalej działają skróty klawiszowe i zachowania myszy, dalej można korzystać z trybu focus follow mouse (dla mnie ważne) itp. Po prostu jest to nadal to samo Gnome z Compizem, co poprzednio, tylko okna same się układają.
Czerwone krechy powyżej nie mają żadnego sensu ale są efektem działania wtyczki Annotate, zostawiłem je jako wizualny dowód działania compizowego plugina.
Podobnie jak Bluetile, PyTyle jest włączane selektywnie, dla wybranych desktopów, można je zatem wykorzystywać na życzenie tylko tam, gdzie jest przydatne (a aktywizacja lub wyłączenie to wciśnięcie pojedynczego skrótu klawiszowego). Przy tym nie psuje wizualizacji obecności okien na wielu desktopach.
Jedyne, czego - w porównaniu z Bluetile - troszkę brakuje, to jakieś okno sygnalizujące czy PyTyle jest aktywne, czy nie, a jeśli tak, który layout układa. No i trzeba zapamiętać kilka skrótów klawiszowych. Ani jedno, ani drugie, nie jest jednak szczególnie bolesne.
Instalacja
PyTyle jest skryptem napisanym w Pythonie i oczywiście wymaga, by
Python był zainstalowany. Z mniej typowych bibliotek wymaga obecności
python-xlib
:
$ sudo apt-get install python-xlib
Sam program spakietowany niestety nie jest ale instaluje się prosto. Źródła można pobrać ze strony PyTyle na sourceforge (chodzi o plik pytyle-0.7.4.tar.gz i rozpakować:
$ tar xzvf ~/Download/PyTyle/pytyle-0.7.4.tar.gz $ cd pytyle-0.7.4
ja wolałem sklonować repozytorium źródłowe (co ułatwi ewentualne aktualizacje lub zgłaszanie patchy):
$ git clone git://pytyle.git.sourceforge.net/gitroot/pytyle/pytyle $ cd pytyle
Efekt obu sposobów jest w tej chwili ten sam.
Nie przepadam za zaśmiecaniem systemowych katalogów, dlatego zainstalowałem sobie skrypt przy pomocy mkvirtualenv:
$ mkvirtualenv pytyle $ python setup.py install
ale oczywiście można też instalować systemowo:
$ python setup.py install
I to już wszystko.
Testowe uruchomienie
Otworzyłem terminal i uruchomiłem PyTyle:
workon pytyle pytyle &
Efektów na razie nie było, bo skrypt domyślnie jest nieaktywny....
Po wciśnięciu Alt-a
ułożył okna na bieżącym desktopie,
umieszczając jedno z nich (główne) z lewej strony, a pozostałe
rozmieszczając z prawej:
Następnie Alt-z
pozwala zmieniać układy okien.
Oprócz powyższego (główne okno w lewej połówce ekranu, reszta
dzieli pionowo prawą) mamy też podział poziomy z późniejszym
cięciem na pionowe paski:
hybrydę poziomo-pionową:
maksymalizację głównego okna na cały ekran:
i tryb w którym główne okno zajmuje większość ekranu a z pozostałych widać tylko belki tytułowe:
Alt-u
wyłącza kafelkowanie i przywraca swobodny układ okien.
Te, które były uruchomione przed aktywacją kafelkowania, mają
przywracaną pozycję z tego momentu, otwarte później zachowują się
różnie (ale zwykle powiększają swój rozmiar).
Kilka dalszych skrótów pozwalających stroić układ okien na ekranie:
Alt-A
(powtórnie) - reperuje układ okien (można go popsuć próbując przeciągania czy przesuwania)Alt-H
- zmniejsza powierzchnię przeznaczoną dla okna głównego (przy pionowym layoucie sprawia, że lewe okno jest trochę węższe), można to wciskać wielokrotnieAlt-L
- operacja odwrotna, tj. zwiększenie powierzchni okna głównego,Alt-.
- zwiększenie ilości okien w przestrzeni okna głównego (zamiast jednego okna na całą lewą stronę ekranu, możemy mieć tam dwa czy trzy),
- Alt-, - zmniejszenie ilości okien w przestrzeni okna głównego.
Są też skróty nawigacyjne:
Alt-Enter
- uczynienie głównym aktualnie aktywnego (mającego focus) okna,Alt-M
- przeniesienie focusu do okna głównego,Alt-J
/Alt-K
- przeniesienie focusu do poprzedniego/następnego okna
... i parę innych, o których dalej, w tym dość ważny Alt-Q
przeładowujący konfigurację.
Uwaga: przy pracy pod Compizem nie działają skróty związane z przerzucaniem okien na inne desktopy (familia Screen focus). Nie są potrzebne, poprawnie działają mi Win-strzałki zamapowane
przy pomocy pluginu Put - o czym pisałem w artykule o Compizie.
Zmiana skrótów klawiszowych i inne korekty konfiguracji
Powyższe skróty klawiszowe mi się nie podobają, gryzą się z otwieraniem menu i skrótami w niektórych aplikacjach z których korzystam. Od kiedy używam compizowych skrótów wolę rezerwować dla operacji związanych z layoutem okien klawisz Win.
Na szczęście w przypadku PyTyle nie ma problemu z rekonfiguracją.
Przy pierwszym uruchomieniu program tworzy plik
~/.config/pytyle/pytylerc
(dokładniej - $XDG_CONFIG_HOME/pytyle/pytylerc
), edytując
który można pozmieniać skróty klawiszowe a także trochę innych ustawień programu.
Jest to po prostu skrypt pythonowy, wygodnie edytuje się go w edytorze kolorującym i wcinającym składnię pythona.
Po przeanalizowaniu skrótów które zdefiniowałem sobie tutaj i tutaj zdecydowałem się na następujące:
Win-A
- włącz kafelkowanie na bieżącym desktopie (mnemotechnika - Awesome),Win-Shift-A
- wyłącz kafelkowanie,Win-Ctrl-A
- zmień layout na następny,Win-<
- zmniejsz okno główne,Win->
- zwiększ okno główne,Win-.
- więcej okien w strefie okna głównego,Win-,
- mniej okien w strefie okna głównego,Win-Enter
- zrób z aktywnego okna okno główne,Win-N
- iteruj kolejne okna jako główne (Next to master),Win-G
- przenieś focus do głównego (Go to master),Win-J
/Win-K
- przenieś focus do poprzedniego/następnego,Alt-Win-J
/Alt-Win-K
- zamień aktywne okno miejscami z poprzednim/następnym,Win-Q
- przeładuj konfigurację.
Jak widać w większości wypadków po prostu zamieniłem Alt na Win,
jedynie włączanie/wyłączanie/zmianę layoutu spiąłem z jednym i tym
samym klawiszem A
a do zwężania/poszerzania okna głównego użyłem <
i >
.
W pliku pytylerc
wygląda to następująco (jedyna subtelność: Win-<
to tak naprawdę Win-Shift-przecinek
, podobnie Win->
to
Win-Shift-kropka
, przynajmniej na mojej klawiaturze):
Config.KEYMAP = { # This will enable and tile the current *screen*. # It will also re-tile when pressed. You can # only access the rest of the key bindings if # you've enabled tiling on the current screen. # (Although I'm thinking of changing this for # screen[0-2]_focus.) 'Super-A': 'tile.default', # Examples of how you can bind specific tiling # layouts to certain keys. #'Alt-Ctrl-H': 'tile.Horizontal', #'Alt-Ctrl-M': 'tile.Maximal', #'Alt-Ctrl-C': 'tile.Cascade', # This will disable and untile the current # *screen*. PyTyle tries to remember the original # positions and sizes of all tiled windows, # although it isn't quite perfect yet. (Specifically, # if you have more than one screen.) #'Alt-U': 'untile', 'Shift-Super-A': 'untile', # This will cycle through all available tiling # algorithms. By default, there are currently only # two: Vertical and Horizontal. (If you know Python, # I have made it stupidly easy to add tiling # algorithms. Check out the core Tile.py, and then # Tilers/TileDefault.py which provides common methods # to both Tilers/Horizontal.py and Tilers/Vertical.py.) #'Super-Z': 'cycle_tiler', 'Super-Ctrl-A': 'cycle_tiler', # Reloads the configuration file. Make changes to your # config file, and have them applied immediately by # calling this without having to restart PyTyle. 'Super-Q': 'reload', # This is a hard reset of the current screen. It will # force a re-tile and refresh PyTyle's image of the # current screen. It will keep the same tiling # algorithm, however. 'Alt-Shift-Super-space': 'reset', # This will cycle all slave windows through the # master area. (If there is more than one master # window, it will use the first master window.) #'Alt-C': 'cycle', 'Super-N': 'cycle', # The following three will simply put *focus* on to # the last active window of the specified screen. # Remember, these currently only work properly if # tiling is enabled on the screen. #'Alt-W': 'screen0_focus', #'Alt-E': 'screen1_focus', #'Alt-R': 'screen2_focus', # The following three will move the currently focused # window to the specified screen. #'Alt-Shift-W': 'screen0_put', #'Alt-Shift-E': 'screen1_put', #'Alt-Shift-R': 'screen2_put', # The following two will increase and decrease the master # area. Depending on the tiling algorithm, these could # be irrelevant or do different things. (For instance, # in the Vertical layout, it will change the master area # width, and in the Horizontal layout, it will change the # master area height.) #'Alt-H': 'master_decrease', #'Alt-L': 'master_increase', #'Super-<': 'master_decrease', 'Super-Shift-comma': 'master_decrease', #'Super->': 'master_increase', 'Super-Shift-period': 'master_increase', # The following two will increase and decrease the number # of master windows. This will allow you to easily configure # a grid layout dynamically, among other things. 'Super-period': 'add_master', 'Super-comma': 'remove_master', # This will make the currently active window the master. 'Super-Return': 'make_active_master', # This will move focus to the master window (or the first # master window if there are more than one). #'Alt-M': 'win_master', 'Super-G': 'win_master', # This will close the currently focused window. You do # *NOT* need to use this to close windows. It is only # included here for completeness. (In other words, you # can close a window any way you like, minimize to # tray, etc.) #'Alt-Shift-C': 'win_close', # The following two will cycle focus to the previous or # next windows. (The algorithm for this is determined # by the current tiling layout.) 'Super-J': 'win_previous', 'Super-K': 'win_next', # The following two will switch the current window with # the previous or next window. 'Super-Shift-J': 'switch_previous', 'Super-Shift-K': 'switch_next', # This is a debugging binding that shows some information # about the current desktop. It's only useful if you're # running PyTyle from a terminal. #'Alt-D': 'query', 'Super-D': 'query', }
Ponadto zakomentowałem część layoutów, zostawiając sobie tylko
Vertical
(główne okno z lewej), HorizontalRows
(główne okno u
góry, poniżej podział na dwie części) i Maximal
(główne okno na cały
ekran). Używam zresztą niemal wyłącznie tego pierwszego.
Config.MISC = { # This is a list of all available tilers. If a tiler # is not listed here, it cannot be used. They are # loaded when PyTyle starts. 'tilers': ['Vertical', #'Horizontal', 'HorizontalRows', 'Maximal', #'Cascade', ], # ...
Wreszcie, dodałem do ignorowanych okien desktop_window
, jako który
przedstawia się nautilusowe tło (o przyczynach niżej):
Config.FILTER = [ 'gmrun', 'gimp', 'download', 'desktop_window', ]
Uwaga: w razie zrobienia błędu składniowego w pliku pytyle i wciśnięcia restartu konfiguracji, program się składa (a okna po cichu zostają gdzie były, więc nie widać od razu, że coś się stało). Dlatego w trakcie edycji lepiej mieć na oku konsolę w której działa
pytyle
.
Pełny szczegółowy opis wszystkich opcji jest tutaj.
Automatyczne uruchamianie
Wstępnie po prostu dodałem pytyle
do autostartu, tj. odklikałem
System/Preferences/Startup Applications
i dodałem nowy
element uruchamiający
/home/marcink/.virtualenvs/pytyle/bin/pytyle
.
Efekty były bardzo złe. Po pierwsze, program zaczął uwzględniać w
layoucie niewidoczne okno ... tła desktopu. Pusta przestrzeń na
poniższym obrazku jest zarezerwowana dla x-nautilus-desktop
(które
można wypatrzeć w tekście u dołu konsoli z lewej strony):
Ten kłopot rozwiązało dodanie desktop_window
do ignorowanych programów.
Ustalenie co właściwie wpisać okazało się nietrywialne. Co prawdapytyle
ma skrót klawiszowy (domyślnieAlt-D
) po którego wciśnięciu wypisuje listę okien i ich rozmiarów, ale pojawiająca się tam nazwa (x-nautilus-desktop
) nie była rozpoznawana przez filtr ignorowania. Aby zorientować się o co chodzi musiałem zrobić drobną poprawkę w kodziepytyle
- w plikuTileStorage.py
przerobiłem funkcję__str__
na następującą (chodzi o dodaniewinclass
):def __str__(self): ret = 'Master(s):\n' for master in self.get_masters(): ret += '\t%s - %s, %s\n' % (master.title, master.id, str(master.winclass)) # ret += 'Slave(s):\n' for slave in self.get_slaves(): ret += '\t%s - %s, %s\n' % (slave.title, slave.id, str(slave.winclass)) # return ret
Drugi problem był jeszcze poważniejszy. PyTyle przestało rozumieć wirtualne desktopy. Uruchomienie nowego programu - na dowolnym desktopie - przerzucało go na ekran zarządzany przez PyTyle. Podobnie zmiana layoutu lub jego odświeżenie ściągała wszystkie okna z wszystkich wirtualnych ekranów w jedno miejsce.
Pamiętając, że przy uruchamianiu z konsoli wszystko było dobrze,
doszedłem do wniosku, że program po prostu startował za wcześnie (i w
chwili gdy się uruchamiał, budował sobie nieodpowiedni obraz świata).
Zapewne wystarczyłby jakiś sleep
ale zdecydowałem się podejść do
sprawy nieco porządniej i napisałem sobie skrypt ~/bin/pytyle
o
następującej treści:
#!/bin/sh until wmctrl -l | grep '^0x[0-9a-z]* *[0-9]'; do sleep 1 done exec /home/marcink/.virtualenvs/pytyle/bin/pytyle
i po nadaniu mu bitu wykonywalności (chmod a+x ~/bin/pytyle
) to ten skrypt
podpiąłem do autostartu.
Co, faktycznie, rozwiązało wszystkie problemy.
Objaśnienie treści skryptu
Co robi powyższy skrypt? Czeka na pojawienie się dowolnego prawdziwego okna
(co jest pewnym dowodem, że menedżer okien jest już uruchomiony i skonfigurowany)
i dopiero po tym uruchamia pytyle
.
Polecenie wmctrl -l
wypisuje wszystkie aktywne okna, co u mnie wygląda np. tak:
marcink@platon:~$ wmctrl -l 0x0463e6d2 0 platon Tomato 1.28 | polarcloud.com - Mozilla Firefox 0x04400004 0 platon Ubuntu Help Centre 0x01e00003 -1 platon Bottom Expanded Edge Panel 0x01e00037 -1 platon Top Expanded Edge Panel 0x01e0003c -1 platon Right Expanded Edge Panel 0x01a00021 -1 platon x-nautilus-desktop 0x0460009a 0 platon freedesktop.org - Software/wmctrl - Mozilla Firefox 0x03602a96 0 platon emacs23@platon.mekk.waw.pl 0x04200043 0 platon Inbox - Marcin.Kasperski@mekk.waw.pl - Mozilla Thunderbird 0x05000004 0 platon marcink@platon: ~ 0x054001ac 0 platon /home/marcink/Dropbox/ZrzutyEkranowe/pytyle_autostart_bis.png - Shutter
Przepuszczenie jego wyniku przez grep
służy odsianiu nieprawdziwych okien (paneli, desktopu)
i sprawdzeniu, czy cokolwiek pozostało. Jeśli nie, skrypt czeka chwilę i sprawdza ponownie,
jeśli tak, uruchamia pytyle
.
Inne problemy
Przy regularnej pracy zauważyłem jeszcze pojawiający się od czasu do czasu efekt drobnych niedokładności w układzie okien. Chodzi o drobne (kilka-kilkanaście pikseli) dodatkowe luki między oknami lub na dole ekranu:
a także, rzadziej, lekkie nachodzenie okien na siebie, owocujące schowaniem belki tytułowej albo paska statusu:
Nie jestem pewien jakie są przyczyny, mogą być co najmniej dwie (programy mogą być nieco nieposłuszne zaokrąglając swój rozmiar, Compizowe cienie mogą też wiązać się z niedokładnym raportowaniem rozmiaru i położenia).
W praktycznej pracy nie jest to uciążliwe.
Podsumowanie
Przynajmniej przy pracy na sporym monitorze PyTyle jest bardzo przydatne i mam zamiar z niego stale korzystać. W przeciwieństwie do XMonad, Awesome czy nawet Bluetile program nie ma ambicji być pełnym menedżerem okien, robi jedynie tylko to, co jest jego głównym zadaniem - i robi to dobrze. Zarazem - jest nieinwazyjny, pozwala się łatwo wyłączyć a aktywuje się jedynie na żądanie.
Oprócz zautomatyzowanego zarządzania układem ekranu, bardzo
ergonomiczne jest też przenoszenie focusu przy pomocy skrótów (po
sugerowanych przeze mnie zmianach - Win-J
i Win-K
). Przy pracy na
kilka okien jest to szybsze niż łapanie myszy.
Mechanizm ignorowania okien jest wygodny i w pełni skuteczny, np. zawsze kłopotliwy Gimp po prostu uruchamia się poza kontrolą pytyle (nad resztą okien).
Polecam.