Показаны сообщения с ярлыком qtile. Показать все сообщения
Показаны сообщения с ярлыком qtile. Показать все сообщения

вторник, 3 июня 2014 г.

Оконный менеджер Qtile

QTile это tiling оконный менеджер написанный полностью на Python. Основные его плюсы состоят в том что написан на Python и вроде как сейчас активно развивается. Конфиг тоже пишется на Python, поэтому для человека знакомого с данным языком проблем с конфигурацией не должно быть.
Установить Qtile можно из git репозитория, репозиториев дистрибутивов, с помощью питоновский утилит pip и easy_install, а так же и из исходных кодов.
Если вы ставили Qtile из репозитория дистрибутива, то на экране login должен быть доступен сеанс Qtile, в него и загружаемся.
Пока у вас нету своего конфига, будет работать DefaulConfig. Можно сохранить его в ~/.config/qtile/config.py и начать править.
 Переключение между рабочими столами происходит по кнопке WinKey+буква(a, s, d, f, u, i, o, p)
Запуск терминала Winkey+Enter
Что бы запустить любой приложение, можно нажать WinKey+r, появится строка ввода, куда надо вводить имя программы для запуска.
Завершение Qtile по нажатию WinKey+Ctrl+q.
Перезагрузка Qtile по нажатию WinKey+Ctrl+r. (удобно пока экспериментируешь с конфигом)

По сути, это все что вам необходимо для того что бы начать создавать свой конфиг. На сайте разработчика есть небольшая документация, в которой освещены основные моменты настройки. Я описывать тоже самое не будет, просто приведу свой конфиг.
Разберем не которые детали:

выставляем клавиши
mod = "mod4"
alt = "mod1"

Управление музыкой через mpc
    Key([mod], "Home", lazy.spawn("mpc toggle")),
    Key([mod], "End", lazy.spawn("mpc stop")),
    Key([mod], "Page_Down", lazy.spawn("mpc next")),
    Key([mod], "Delete", lazy.spawn("mpc prev")),
    Key(
        [mod], "m",
        lazy.spawn(
            """
            mpc playlist | dmenu -l 10  |\
            xargs -I '{}' sh -c "mpc playlist \
            | grep -rne '{}' | awk -F: '{print \$1}'" \
            | xargs -I '{}' sh -c "test -n '{}' && mpc play '{}'"
            """)
    ),

закрыть текущее окно
    Key(
        [mod], "w",
        lazy.window.kill()
    ),
поднимаем спрятавшееся окно наружу(grave -  это клавиша ~)
    Key(
        [alt], "grave",
        lazy.window.bring_to_front()
    ),

переключение на следующее окно в группе(полезно когда какой-нибудь всплывающее окно ушло за задний фон)
    Key(
        [alt], "Tab",
        lazy.group.next_window()),

Переключение между группами
    Key(
        [mod], "Left",
        lazy.group.prevgroup()
    ),
    Key(
        [mod], "Right",
        lazy.group.nextgroup()
    ),
переключение между слоями
    Key(
        [mod], "h",
        lazy.layout.previous()
    ),
    Key(
        [mod], "l",
        lazy.layout.next()
    ),
    Key(
        [mod], "j",
        lazy.layout.up()
    ),
    Key(
        [mod], "k",
        lazy.layout.down()
    ),

переключить окно в плавающее(не обходимо для окон работающий не навесь экран, например диалоги)
    Key(
        [mod], "f",
        lazy.window.toggle_floating()
    ),
различные переключения и изменения размеров для разных layout. проще попробовать самому.
    Key(
        [mod, "shift"], "space",
        lazy.layout.rotate(),
        lazy.layout.flip(),              # xmonad-tall
        ),
    Key(
        [mod, "shift"], "k",
        lazy.layout.shuffle_up(),         # Stack, xmonad-tall
        ),
    Key(
        [mod, "shift"], "j",
        lazy.layout.shuffle_down(),       # Stack, xmonad-tall
        ),
    Key(
        [mod, "control"], "l",
        lazy.layout.add(),                # Stack
        lazy.layout.increase_ratio(),     # Tile
        lazy.layout.maximize(),           # xmonad-tall
        ),
    Key(
        [mod, "control"], "h",
        lazy.layout.delete(),             # Stack
        lazy.layout.decrease_ratio(),     # Tile
        lazy.layout.normalize(),          # xmonad-tall
        ),
    Key(
        [mod, "control"], "k",
        lazy.layout.shrink(),             # xmonad-tall
        lazy.layout.decrease_nmaster(),   # Tile
        ),
    Key(
        [mod, "control"], "j",
        lazy.layout.grow(),               # xmonad-tall
        lazy.layout.increase_nmaster(),   # Tile
        ), 
запуск различных программ
    Key(
        [mod], "n",
        lazy.spawn("firefox")
        ),
    Key(
        [mod], "d",
        lazy.spawn("subl")
        ),

    Key(
        [mod], "u",
        lazy.spawn("uzbl-tabbed")
        ),
    Key([mod], "Return", lazy.spawn("urxvt")), 
переключение на следующий layout
Key([mod], "Tab",    lazy.nextlayout()),
запуск приложение через dmenu
    Key(
        [mod], "space",
        lazy.spawn(
            "dmenu_run -fn 'Terminus:size=8' -nb '#000000' -nf '#fefefe'")
    ),
настройка громкости
    Key(
        [mod], "equal",
        lazy.spawn("amixer -c 0 -q set Master 2dB+")
    ),
    Key(
        [mod], "minus",
        lazy.spawn("amixer -c 0 -q set Master 2dB-")
    ),
управление мышкой
 mouse = [
    Drag(
        [mod], "Button1",
        lazy.window.set_position_floating(),
        start=lazy.window.get_position()
    ),
    Drag(
        [mod], "Button3",
        lazy.window.set_size_floating(),
        start=lazy.window.get_size()
    ),
    Click(
        [mod], "Button2",
        lazy.window.bring_to_front()
    ),
]
задаем рабочие столы. У меня это клавиши от 1 до 0. Для переключение нажимаем клавишу mod + номер. Для переноса окна на другой стол, mod+shift+номер
groups = [Group(str(i)) for i in (1, 2, 3, 4, 5, 6, 7, 8, 9, 0)]
for i in groups:
    keys.append(Key([mod], i.name, lazy.group[i.name].toscreen()))
    keys.append(
        Key(
            [mod, "shift"], i.name, lazy.window.togroup(i.name),
            lazy.group[i.name].toscreen()))
настраиваем border для окон
border = dict(
    border_normal='#808080',
    border_width=1,
)
задаем какие будем использоваться layouts. Здесь можно почитать про встроенные layouts, но документация как всегда не успевает за разработчиками, так что лучше все посмотреть в git
layouts = [
    layout.Max(),
    layout.MonadTall(**border),
    layout.Matrix(**border)
]
теперь задаем наш экран. у меня один монитор, поэтому screen один. Можно настраивать поведение при нескольких мониторах. В нашем мониторе создаем Bar и задаем что на необходимо там видеть. Опять же, вот тут про встроенные виджеты или тут в исходных кодах.
В вкратце, у меня используется GroupBox - отображает рабочие столы, WindowName - отображает заголовок текущего окна, Notify - типа статусной строки, Systray - системный трай, KeyboardLayout - раскладка клавиатуры, Volume - громкость, BitcoinTicker - все ясно, и часы. У  каждого виджета есть свои настройки, более подробно в исходнике виджета.
screens = [
    Screen(
        top=bar.Bar(
            [
                widget.GroupBox(margin_y=1,
                                margin_x=1,
                                borderwidth=1,
                                padding=1,),
                widget.WindowName(foreground="a0a0a0",),
                widget.Notify(),
                widget.Systray(),
                widget.KeyboardLayout(configured_keyboards=["us", "ru"]),
                widget.Volume(foreground="70ff70",),
                widget.BitcoinTicker(currency="rub", format="{buy}"),
                widget.Clock(foreground="a0a0a0",
                             fmt="%H:%M %d.%m.%Y",),
            ],
            18,
        ),
    ),
]
эти хуки необходимы для того что бы некоторые всплывающие окна и диалоги автоматом переключались в режим floating и не открывались во весь экран
@hook.subscribe.client_new
def dialogs(window):
    if (window.window.get_wm_type() == 'dialog'
            or window.window.get_wm_transient_for()):
        window.floating = True


@hook.subscribe.client_new
def vue_tools(window):
    if((window.window.get_wm_class() == (
        'sun-awt-X11-XWindowPeer', 'tufts-vue-VUE')
            and window.window.get_wm_hints()['window_group'] != 0)
            or (window.window.get_wm_class() == (
                'sun-awt-X11-XDialogPeer', 'tufts-vue-VUE'))):
        window.floating = True


@hook.subscribe.client_new
def idle_dialogues(window):
    if((window.window.get_name() == 'Search Dialog') or
      (window.window.get_name() == 'Module') or
      (window.window.get_name() == 'Goto') or
      (window.window.get_name() == 'IDLE Preferences')):
        window.floating = True


@hook.subscribe.client_new
def libreoffice_dialogues(window):
    if ((window.window.get_wm_class() == (
        'VCLSalFrame', 'libreoffice-calc')) or
            (window.window.get_wm_class() == (
                'VCLSalFrame', 'LibreOffice 3.4'))):
        window.floating = True
а здесь мы создаем метод для запуск программ и описываем программы которые необходимо запускать при старте qtile
def is_running(process):
    s = subprocess.Popen(["ps", "axw"], stdout=subprocess.PIPE)
    for x in s.stdout:
        if re.search(process, x):
            return True
    return False


def execute_once(process):
    if not is_running(process):
        return subprocess.Popen(process.split())


@hook.subscribe.startup
def startup():
    execute_once("nm-applet")
    execute_once("synergy")
    execute_once("feh --bg-fill /home/pavel/Pictures/arch.png")
    execute_once(
        'setxkbmap -layout us,ru -option grp:caps_toggle,grp_led:scroll')

Переключение трека в mpd через dmenu и mpc

Если вы пользуетесь MPD  и не хотите постоянно держать запущенным какой-нибудь клиент, типа Sonata, для переключения треков, то можно повесить на hotkey вот такой простой скрипт
mpc playlist | dmenu -l 10  | xargs -I '{}' sh -c "mpc playlist | grep -rne '{}' | awk -F:  '{print \$1}'"  | xargs -I '{}' sh -c "test -n '{}'&& mpc play '{}'"
получаем текущей playlist
mpc playlist
и выводим его с помощью dmenu(вертикально, 10 строчек)
dmenu -l 10
посылаем выбранный трек
xargs -I '{}' sh -c 
фильтруем playlist по выбранному треку и выставляем номер строки данного трека
mpc playlist | grep -rne '{}' 
оставляем только номер трека
awk -F:  '{print \$1}'"
проверяем что трек был выбран. В случае если нажали Esc, трек не надо переключать. Запускаем выбранные трек
xargs -I '{}' sh -c "test -n '{}'&& mpc play '{}'"

У меня в Qtile hotkey выглядит вот так:

Key(
        [mod], "m",
        lazy.spawn(
            """
            mpc playlist | dmenu -l 10  |\
            xargs -I '{}' sh -c "mpc playlist \
            | grep -rne '{}' | awk -F: '{print \$1}'" \
            | xargs -I '{}' sh -c "test -n '{}' && mpc play '{}'"
            """)
    ),
Переключение вперед/назад/стоп
Key([mod], "Home", lazy.spawn("mpc toggle")),
Key([mod], "End", lazy.spawn("mpc stop")),
Key([mod], "Page_Down", lazy.spawn("mpc next")),
Key([mod], "Delete", lazy.spawn("mpc prev")),




среда, 26 сентября 2012 г.

Виджет раскладки клавиатуры в QTile

    В Qtile мне очень не хватало аплета отображающего текущую раскладку клавиатуры и поэтому я решил озадачиться этим вопросам. В прошлой статье я описал как получить текущую раскладку клавиатуры в Python, теперь осталось прикрутить это к qtile.
Что оказалось совсем не сложно сделать. За основу я взял виджет часов, который является TextBox'ом. Весь Qtile у меня находить в директории
 /usr/local/lib/python2.7/dist-packages/libqtile/  
виджеты во вложеной директории widget
Класс виджета часов выглядит следующим образом:
import datetime
from .. import hook, bar, manager
import base

class Clock(base._TextBox):
    """
        A simple but flexible text-based clock.
    """
    defaults = manager.Defaults(
        ("font", "Arial", "Clock font"),
        ("fontsize", None, "Clock pixel size. Calculated if None."),
        ("padding", None, "Clock padding. Calculated if None."),
        ("background", "000000", "Background colour"),
        ("foreground", "ffffff", "Foreground colour")
    )
    def __init__(self, fmt="%H:%M", width=bar.CALCULATED, **config):
        """
            - fmt: A Python datetime format string.

            - width: A fixed width, or bar.CALCULATED to calculate the width
            automatically (which is recommended).
        """
        self.fmt = fmt
        base._TextBox.__init__(self, " ", width, **config)

    def _configure(self, qtile, bar):
        base._TextBox._configure(self, qtile, bar)
        self.timeout_add(1, self.update)

    def update(self):
        now = datetime.datetime.now().strftime(self.fmt)
        if self.text != now:
            self.text = now
            self.bar.draw()
        return True

Как видно в методе update производиться присвоение значения текстового поля, в _configure прописывается обновлять виджет каждую секунду, что для нас является очень полезным. Скопируем данный класс под именем kblayout.py. Это и будет наш новый виджет. Так же в директорию с виджетами необходимо скопировать класс который занимется получением текущей раскладки клавиатуры из прошлой статьи под именем kb.py.
После изменения kblayout.py получаем:
from .. import hook, bar, manager
import base
import subprocess
from kb import kb


class kblayout(base._TextBox):
    """
        A simple but flexible text-based kblayout.
    """
    defaults = manager.Defaults(
        ("font", "Arial", "kblayout font"),
        ("fontsize", None, "kblayout pixel size. Calculated if None."),
        ("padding", None, "kblayout padding. Calculated if None."),
        ("background", "000000", "Background colour"),
        ("foreground", "ffffff", "Foreground colour")
    )

    def __init__(self, width=bar.CALCULATED, **config):
        base._TextBox.__init__(self, "ru", width, **config)

    def _configure(self, qtile, bar):
        base._TextBox._configure(self, qtile, bar)
        self.timeout_add(1, self.update)

    def update(self):
        k = kb()
        l = k.curkb()
        if self.text != l:
            self.text = l
            self.bar.draw()
        return True

    Тут у меня вылезлал какая то проблема с gobject, который используется в qtile, которую я так и не смог решить, но смог ее обойти. Для этого в kb.py добавляем строку
del sys.modules['gobject']
получается
import sys
import os
import subprocess
os.environ['GI_TYPELIB_PATH'] =\
    'libxklavier:' + os.environ.get('GI_TYPELIB_PATH', '')

del sys.modules['gobject']
from gi.repository import Xkl, Gdk, GdkX11


class kb():

    def __init__(self):
        display = GdkX11.x11_get_default_xdisplay()
        self.engine = Xkl.Engine.get_instance(display)

    def curkb(self):
        t = subprocess.check_output(["xset", "-q"])
        num = int(t.splitlines()[1].split()[9][4])
        groups = self.engine.get_groups_names()
        if (len(groups) > num):
            return str(groups[int(num)])[:2]
        else:
            return "Err"

k = kb()
print k.curkb()


 И в классе виджета mpriswidget.py за меняем строку
import gobject

на
from gi.repository import Xkl, Gdk, GdkX11

Теперь проблем не должно возникнуть. Осталось прописать наш виджет в файл __init__.py директории widget
from kblayout import kblayout
и прописать наш виджет в своем конфиге qtile - ~/.config/qtile/config.py
У меня это выглядит вот так:
screens = [
    Screen(
        top=bar.Bar([widget.GroupBox(
            borderwidth=2, font='Consolas', fontsize=13,
            padding=1, margin_x=1, margin_y=1),
            widget.Sep(),
            widget.WindowName(
                font='Consolas', fontsize=13, margin_x=6),
            widget.Sep(),
            widget.Battery(
                font='Consolas', fontsize=13, margin_x=6,
                energy_now_file="charge_now",
                energy_full_file="charge_full",
                power_now_file="current_now"),
            widget.Sep(),
            widget.Systray(),
            widget.kblayout(font='Consolas', fontsize=13, padding=6),
            widget.Sep(),
            widget.Clock(
                '%H:%M:%S %d.%m.%Y',
                font='Consolas', fontsize=13, padding=6), ], 24,),
    ),
]






вторник, 14 августа 2012 г.

Tiling windows managers

    Tiling windows manager - это фреймовый оконный менеджер, который разбивает рабочее пространство на взаимно не пересекающиеся прямоугольные области. Таким образом у вас ни когда не будет пересекающихся окон, все окна всегда будут на виду. При такой оконному менеджере более активно приходиться пользоваться рабочими столами. Фреймовый оконный менеджер позволяет полность избавить от мышки!
Выглядит примерно так
    Была когда то в прошлом у меня попытка перейти на данный вид оконного менеджера, но она не увенчалась успехом, толи я был не готово, толи менеджеры тогда были еще сыроваты.
    В очередной раз устав от Unity, от ее тормозов, да и вообще непригодному для работы окружению. Я ни чего не имею против Unity на домашнем компьютере, она вполне сносно справляеться с просмотром фильмов и серфингом в интернете. Да и жене попроще. Но на рабочем месте должна быть максимально фунциональная и быстра стреда. Unity  в качестве такой не годиться.
    Сперва были попытки перейти на Gnome 3. Которые не увенчались успехом, так как Gnome 3, это тот же Unity, только вид сбоку.
    Дальше я попробовал XUbuntu, затем чистый XFCE, на котором я просидел достаточно долго и в общем он меня устаивал, но чего то все равно не хватало.
    И как то наткнулся в статье на информацию что в Google некоторые сотрудники используют Ubuntu, но предпочитают использовать Xmonad, вместо Unity. Оказалось что Xmonad, это Tiling WM. И я решил попробовать что же это такой Tiling WM.
    На Ubuntu Xmonad ставиться с ходу из репозитория, в списке сессий появляется два новых пункта, Xmonad и Xmoad with Gnome. Xmonad with Gnome помоему у меня сразу не заработал, а Xmonad запустился и показал мне чистый рабочий стол. Оказывается это все! Можно было начинать работать. Только надо знать кучу хоткеев и написать не мало конфигов. Ну так просто я не был готов сдаться... Нашел как прикрутить к нему gnome-panel. Даже можно unity-2d-panel прикрутить, но оно того не стоит. На самом деле, после первых часов работы в Xmonad я был в восторге от идеи Tiling WM и от Xmonad. Благодаря легковесности Xmonad на моем не очень сильном ноуте, все начала просто летать. Оперативка свободна, проц отдыхает. Вот только это gnome-panel нагружает систему. Но есть Xmobar, которые я так и не попробовал. И вот после полудня работы, понял что кое что мне хотелось бы донастроить. А так как Xmonad написан на Haskell, то и конфиг у него представляет из себя Haskell программу. А изучать синтаксис Haskell мне совсем не хотелось. Возможно там все просто, но я ленивый. Мой друг параллельно со мной начал изучать тему Tiling WM, по моей рекомендации поставил Xmonad, но на отрез отказался ставить дополнительно к нему gnome-panel. Попытался привзять это все к Unity, что оказалось не так посто. Это получилось только у одного чувака, который для этого правил код Unity. Затем, друган пробовал поставить Xmobar, что вроде как у него даже получилось, но он все равно остался не  удовлетворен.
    И следующим шагом была установка Awesome, второго из двух самых популярных Tiling WM. Awesome сразу оказался более дружелюбным, так как после устаноки сразу все себе нес бар, к которому легко прикручивались апплеты погоды, сети, почты и т.п. Awesome в свою очередь требовал редактирования конфигов на языке Lua. Что опять же меня совсем не обрадовало. Хотя по Awesome полно русскоязычной документации. Но глядя на эти WM написанные на Haskell и на Lua, я подумал, было бы превосходно поставить WM написанный на моем любимом Python. И к моему счастью оказалось что такой Tiling WM  есть - QTile. О котором и будет следующая заметка.