Оконный менеджер Qtile
QTile это tiling оконный менеджер написанный полностью на Python
. Основные его плюсы состоят в том что написан на Python
и вроде как сейчас активно развивается. Конфиг тоже пишется на Python
, поэтому для человека знакомого с данным языком проблем с конфигурацией не должно быть.
Установить Qtile
можно из git
репозитория, репозиториев дистрибутивов, с помощью питоновский утилит pip
и easy_install
, а так же и из исходных кодов.
Если вы ставили Qtile
из репозитория дистрибутива, то на экране login должен быть доступен сеанс Qtile
, в него и загружаемся.
Пока у вас нету своего конфига, будет работать DefaltConfig. Можно сохранить его в ~/.config/qtile/config.py
и начать править.
Переключение между рабочими столами происходит по кнопке
CMD+буква+(a, s, d, f, u, i, o, p)
Запуск терминала
CMD+Enter
Что бы запустить любой приложение, можно нажать CMD+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()
),
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()
),
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"))
Key([mod], "Tab", lazy.nextlayout())
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()
),
]
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 = dict(
border_normal='#808080',
border_width=1,
)
layouts
, но документация как всегда не успевает за разработчиками, так что лучше все посмотреть в git
layouts = [
layout.Max(),
layout.MonadTall(**border),
layout.Matrix(**border)
]
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')