Журнал LinuxFormat - перейти на главную

LXF145:KWin

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
 
Строка 1: Строка 1:
 +
==KWin: Порулим окнами==
  
 +
: '''Коэн Вервлоесем''' не любит таскать окна и с ними валандаться, и рад был узнать, что последняя версия ''KWin'' поддерживает скрипты.
  
[[Изображение:Lxf145-11g-tut-kwin 6.jpg]]
+
[[Изображение:Lxf145-11g-tut-kwin 6.jpg|left|thumb]]
==Скрипты KWin Управляем окнами в KDE 4.6==
+
 
 +
{{Врезка|right|Заголовок=Наш эксперт|Содержание='''Коэн Вервлоесем''' пользуется свободными программами с 2000 года, и ему нравятся те, которые легко автоматизировать.|Ширина=20%}}
  
==KWin: Порулим окнами==
 
===Коэн Вервлоесем не любит таскать окна и с ними валандаться, и рад был узнать, что последняя версия ''KWin'' поддерживает скрипты.===
 
 
В KDE 4.6 оконный менеджер ''KWin'' получил новую прекрасную возможность: интерфейс скриптов. А значит, поведение окон можно настроить по своему вкусу. Пара примеров: все окна, кроме активного, можно затенить; можно сохранять расположение окна «поверх других», пока вы не развернете его и оно не будет считаться обычным окном. Также можно «склеить» два окна: при изменении размера одного размер второго будет автоматически меняться так, чтобы их контуры оставались вместе. Возможности безграничны. В этой статье мы покажем, что можно сделать с помощью скриптов KWin, и после ее прочтения вы сможете написать свои скрипты ''Kwin'' и оптимизировать поведение окон на своем рабочем столе.
 
В KDE 4.6 оконный менеджер ''KWin'' получил новую прекрасную возможность: интерфейс скриптов. А значит, поведение окон можно настроить по своему вкусу. Пара примеров: все окна, кроме активного, можно затенить; можно сохранять расположение окна «поверх других», пока вы не развернете его и оно не будет считаться обычным окном. Также можно «склеить» два окна: при изменении размера одного размер второго будет автоматически меняться так, чтобы их контуры оставались вместе. Возможности безграничны. В этой статье мы покажем, что можно сделать с помощью скриптов KWin, и после ее прочтения вы сможете написать свои скрипты ''Kwin'' и оптимизировать поведение окон на своем рабочем столе.
====Привет, мир====
+
 
Прежде всего следует узнать, где KWin ищет скрипты – а это каталог ~ '''/ .kde4 / share / apps / kwin / scripts /''' . Все файлы с расширениями '''.kwinscript, .kws''' и '''.kwinqs''', у которых установлен бит выполнения, будут распознаны ''KWin'' как файлы скриптов. По умолчанию при запуске KWin выполняет все обнаруженные им скрипты в этом каталоге. Проверим это. Создайте файл '''helloworld.kwinscript''' со следующим содержимым в каталоге '''scripts''':
+
===Привет, мир===
print(“Hello world!”);
+
 
 +
Прежде всего следует узнать, где KWin ищет скрипты – а это каталог ~ '''/.kde4/share/apps/kwin/scripts/''' . Все файлы с расширениями '''.kwinscript, .kws''' и '''.kwinqs''', у которых установлен бит выполнения, будут распознаны ''KWin'' как файлы скриптов. По умолчанию при запуске KWin выполняет все обнаруженные им скрипты в этом каталоге. Проверим это. Создайте файл '''helloworld.kwinscript''' со следующим содержимым в каталоге '''scripts''':
 +
print(“Hello world!”);
  
 
Затем сделайте файл исполняемым:
 
Затем сделайте файл исполняемым:
  
chmod +x ~/.kde4/share/apps/kwin/scripts/helloworld.kwinscript
+
chmod +x ~/.kde4/share/apps/kwin/scripts/helloworld.kwinscript
  
 
Теперь перезагрузите ''KWin'' в ''Konsole''; при этом будет отображаться вывод скрипта, а также некоторая отладочная информация:
 
Теперь перезагрузите ''KWin'' в ''Konsole''; при этом будет отображаться вывод скрипта, а также некоторая отладочная информация:
  
kwin --replace &
+
kwin --replace &
  
 
Если вы не видите слов “Hello world!”, возможно, вы забыли сделать скрипт исполняемым или у вас более старая версия KDE. Также, возможно, вы допустили синтаксическую ошибку; но тогда KWin выдает сообщение об ошибке в консоли. Если все работает, можно двигаться дальше.
 
Если вы не видите слов “Hello world!”, возможно, вы забыли сделать скрипт исполняемым или у вас более старая версия KDE. Также, возможно, вы допустили синтаксическую ошибку; но тогда KWin выдает сообщение об ошибке в консоли. Если все работает, можно двигаться дальше.
  
====Различные объекты====
+
===Различные объекты===
 +
 
 
Язык скриптов ''KWin'' – ECMAScript, стандартизированная версия JavaScript. Если у вас есть опыт программирования на JavaScript, то проблем с написанием скриптов KWin не будет. В дальнейшем мы будем считать, что вы знаете JavaScript, но объясним некоторые основные концепции для тех, у кого есть опыт программирования на других языках, чтобы они не отставали. Прежде всего, знайте, что существуют три вида объектов:
 
Язык скриптов ''KWin'' – ECMAScript, стандартизированная версия JavaScript. Если у вас есть опыт программирования на JavaScript, то проблем с написанием скриптов KWin не будет. В дальнейшем мы будем считать, что вы знаете JavaScript, но объясним некоторые основные концепции для тех, у кого есть опыт программирования на других языках, чтобы они не отставали. Прежде всего, знайте, что существуют три вида объектов:
'''Инициализируемые [instantiable]''' Они создаются с помощью конструкции '''var foo = new Foo()''';. Объектов такого типа можно создавать сколько угодно.
+
* '''Инициализируемые [instantiable]''' Они создаются с помощью конструкции '''var foo = new Foo()''';. Объектов такого типа можно создавать сколько угодно.
'''Одиночные [singleton]''' Для этих объектов существует только один экземпляр заданного типа. Их нельзя создавать самим, но они предоставляются автоматически в скриптах ''Kwin''.
+
* '''Одиночные [singleton]''' Для этих объектов существует только один экземпляр заданного типа. Их нельзя создавать самим, но они предоставляются автоматически в скриптах ''Kwin''.
'''Плавающие [floating]''' Для этих объектов существует множество экземпляров заданного типа, но их нельзя создавать самим: они получаются в качестве возвращаемого значения метода.
+
* '''Плавающие [floating]''' Для этих объектов существует множество экземпляров заданного типа, но их нельзя создавать самим: они получаются в качестве возвращаемого значения метода.
  
 
Скрипты ''KWin'' управляются событиями: ''KWin'' генерирует определенные события, с которыми можно связать функции, вызываемые при наступлении события. Этот подход – ключ к изменению поведения программы согласно своим потребностям: нужно просто назначить собственные функции подходящим событиям. Следующий пример прояснит это:
 
Скрипты ''KWin'' управляются событиями: ''KWin'' генерирует определенные события, с которыми можно связать функции, вызываемые при наступлении события. Этот подход – ключ к изменению поведения программы согласно своим потребностям: нужно просто назначить собственные функции подходящим событиям. Следующий пример прояснит это:
Строка 32: Строка 36:
 
  });
 
  });
  
Объект workspace здесь – одиночный; у него есть множество событий, инициируемых на уровне системы. Это основной источник событий в ''KWin'', и вы будете пользоваться им во многих скриптах для инициализации взаимодействия с оконным менеджером. Например, событие '''clientMinimized''', которым мы здесь воспользовались, возникает каждый раз при сворачивании окна. С помощью метода connect мы связываем с этим событием функцию. В данном случае функция безымянная; ей передается один параметр, клиент (представляющий собой окно, плавающий объект). В этой функции мы выводим сообщение о том, что клиент свернут, и применяем метод '''caption()''' объекта-клиента для получения заголовка окна. Сохраните этот скрипт, сделайте его исполняемым, перезагрузите ''KWin'' в ''Konsole'' и наблюдайте за выводом команды  
+
Объект workspace здесь – одиночный; у него есть множество событий, инициируемых на уровне системы. Это основной источник событий в ''KWin'', и вы будете пользоваться им во многих скриптах для инициализации взаимодействия с оконным менеджером. Например, событие '''clientMinimized''', которым мы здесь воспользовались, возникает каждый раз при сворачивании окна. С помощью метода connect мы связываем с этим событием функцию. В данном случае функция безымянная; ей передается один параметр, клиент (представляющий собой окно, плавающий объект). В этой функции мы выводим сообщение о том, что клиент свернут, и применяем метод '''caption()''' объекта-клиента для получения заголовка окна. Сохраните этот скрипт, сделайте его исполняемым, перезагрузите ''KWin'' в ''Konsole'' и наблюдайте за выводом команды при сворачивании окна. Безымянной функцией пользоваться не обязательно. Следующий код эквивалентен предыдущему:
при сворачивании окна. Безымянной функцией пользоваться не обязательно. Следующий код эквивалентен предыдущему:
+
 
  function printCaption(client) {
 
  function printCaption(client) {
 
  print(“Minimized: [“ + client.caption() + “]”);
 
  print(“Minimized: [“ + client.caption() + “]”);
Строка 41: Строка 44:
 
Если функция у вас небольшая и используется только в одном месте, она может быть безымянной: меньше набора кода. Однако, когда функция разрастается или нужно вызывать ее в нескольких местах, лучше определить ее явно, чтобы код оставался понятным.
 
Если функция у вас небольшая и используется только в одном месте, она может быть безымянной: меньше набора кода. Однако, когда функция разрастается или нужно вызывать ее в нескольких местах, лучше определить ее явно, чтобы код оставался понятным.
  
====Методы и свойства====
+
[[Изображение:Lxf145-11g-tut-kwin 1.jpg|thumb|Когда вы заменяете KWin в Konsole, вы получаете всю информацию, которую вывели]]
 +
 
 +
===Методы и свойства===
 +
 
 
Добыть информацию об окнах можно и не дожидаясь наступления определенного события – для этого достаточно воспользоваться методами и свойствами. Метод – это функция, у которой есть возвращаемое значение. У объекта каждого типа есть несколько заданных методов. Например, для получения списка всех клиентов можно воспользоваться методом getAllClients() объекта workspace, который возвращает массив всех клиентов:
 
Добыть информацию об окнах можно и не дожидаясь наступления определенного события – для этого достаточно воспользоваться методами и свойствами. Метод – это функция, у которой есть возвращаемое значение. У объекта каждого типа есть несколько заданных методов. Например, для получения списка всех клиентов можно воспользоваться методом getAllClients() объекта workspace, который возвращает массив всех клиентов:
 
  var clients = workspace.getAllClients();
 
  var clients = workspace.getAllClients();
Строка 50: Строка 56:
 
Здесь мы создаем инициализируемый объект '''clients''' – в нем хранится массив всех клиентов. Затем в цикле '''for''' мы перебираем клиентов и выводим их заголовки. Размер массива мы можем получить с помощью свойства '''length'''.
 
Здесь мы создаем инициализируемый объект '''clients''' – в нем хранится массив всех клиентов. Затем в цикле '''for''' мы перебираем клиентов и выводим их заголовки. Размер массива мы можем получить с помощью свойства '''length'''.
  
Если вы захотите написать собственный скрипт, загляните в документацию по API скриптов ''KWin'' на [[http: / / rohanprabhu.com / files / kwsapi.html]]. На этой странице приведен список всех объектов, которые KWin распознает в своих скриптах – например, '''workspace, toplevel, client, clientgroup, windowinfo и config'''. Для каждого объекта в документации приведен список всех событий, методов и свойств с коротким описанием их назначения. Эта информация поможет вам понять, чего именно можно достичь с помощью скриптов. Нужно знать, что '''toplevel''' — родительский класс по отношению к '''client''', поэтому все методы объектов '''toplevel''' также применимы к объектам клиентов.
+
Если вы захотите написать собственный скрипт, загляните в документацию по API скриптов ''KWin'' на http://rohanprabhu.com/files/kwsapi.html. На этой странице приведен список всех объектов, которые KWin распознает в своих скриптах – например, '''workspace, toplevel, client, clientgroup, windowinfo и config'''. Для каждого объекта в документации приведен список всех событий, методов и свойств с коротким описанием их назначения. Эта информация поможет вам понять, чего именно можно достичь с помощью скриптов. Нужно знать, что '''toplevel''' — родительский класс по отношению к '''client''', поэтому все методы объектов '''toplevel''' также применимы к объектам клиентов.
 +
 
 +
[[Изображение:Lxf145-11g-tut-kwin 2.jpg.jpeg|thumb|Склейте окна навсегда с помощью скрипта KWin, и вам незачем будет насильственно совмещать их контуры.]]
 +
 
 +
===Склеиваем окна вместе===
  
====Склеиваем окна вместе====
 
 
В принципе, ваших знаний уже достаточно для того, чтобы менять поведение окон по своему вкусу с помощью ''KWin''. Чтобы придать вам вдохновения, приведем простой, но полезный пример: этот скрипт предназначен web-разработчикам, желающим, чтобы консоль ошибок всегда показывалась поверх главного окна ''Firefox'' и они видели бы в нем все ошибки и предупреждения. Вот как он выглядит:
 
В принципе, ваших знаний уже достаточно для того, чтобы менять поведение окон по своему вкусу с помощью ''KWin''. Чтобы придать вам вдохновения, приведем простой, но полезный пример: этот скрипт предназначен web-разработчикам, желающим, чтобы консоль ошибок всегда показывалась поверх главного окна ''Firefox'' и они видели бы в нем все ошибки и предупреждения. Вот как он выглядит:
 
  var main_present = 0;
 
  var main_present = 0;
Строка 92: Строка 101:
  
 
Код начинается с объявления некоторых переменных: мы объявляем переменные для хранения главного окна и консоли окна ошибок. Мы также объявляем переменные '''main''' и '''console''', которые будут содержать ссылки на клиентов главного окна и окна консоли ошибок. Затем мы определяем две вспомогательных функции для получения ширины и высоты экрана рабочего стола. В функции '''adjustMain''' мы изменяем ширину главного окна так, чтобы оно располагалось прямо под окном консоли ошибок.
 
Код начинается с объявления некоторых переменных: мы объявляем переменные для хранения главного окна и консоли окна ошибок. Мы также объявляем переменные '''main''' и '''console''', которые будут содержать ссылки на клиентов главного окна и окна консоли ошибок. Затем мы определяем две вспомогательных функции для получения ширины и высоты экрана рабочего стола. В функции '''adjustMain''' мы изменяем ширину главного окна так, чтобы оно располагалось прямо под окном консоли ошибок.
 +
 +
{{Врезка|right|Заголовок=Скорая помощь|Содержание=При проверке скрипта ''KWin'' для просмотра значений переменных, особенно заголовка клиента, класса windowclass и имени окна, в целях отладки пользуйтесь командой print.|Ширина=20%}}
 +
 +
{{Врезка|left|Заголовок=Скрипты в других оконных менеджерах|Содержание=''KWin'' – не единственный оконный менеджер, позволяющий изменять поведение окон с помощью скриптов. Многие из так называемых «мозаичных» оконных менеджеров полностью поддерживают скрипты. Например, оконный менеджер ''Awesome'' допускает значительное расширение с помощью языка программирования Lua и обладает обширным и хорошо задокументированным API, с помощью которого можно тонко изменить поведение всех окон. Тот же подход использует ''Xmonad'', но он написан на Haskell, чисто функциональном языке программирования, который не слишком просто освоить.
 +
 +
Существует несколько сторонних программ, которые «подцепляются» к оконному менеджеру и предоставляют вам контроль за местоположением и параметрами окон. Многие из них используют спецификацию расширенных подсказок оконного менеджера (Extended Window Manager Hints – EWMH), которой следует большинство популярных файловых менеджеров, в том числе ''KWin, Metacity, Awesome, Xmonad и Openbox''. Например, существует программа ''Devil’s Pie'', которая считывает скрипты, позволяющие вам задавать правила для своих любимых приложений.
 +
 +
Команда '''wmctrl''' также предоставляет вам полный контроль над своими окнами, и она прекрасно подходит для использования в собственных скриптах оболочки. И если вам удобнее писать скрипты в ''Bash'', чем программы на JavaScript, '''wmctrl''' определенно лучший выбор.|Ширина=20%}}
  
 
Большая часть кода – безымянная функция, которая будет вызываться при каждом при наступлении события '''clientAdded'''. Сначала мы записываем информацию об окне в переменную '''z.''' '''Windowinf'''o — объект, дающий доступ к обширной низкоуровневой информации ''X Window'' об окне. В данном случае нас интересуют класс windowclass и имя окна: с их помощью мы определим, является ли клиентом ''Firefox'' и какое это окно: у каждого окна браузера его классом '''windowclass''' является '''Firefox'''. Кроме того, наш код отличает главное окно от консоли ошибок по значению имени '''windowclass: Navigator и Error Console''' соответственно.
 
Большая часть кода – безымянная функция, которая будет вызываться при каждом при наступлении события '''clientAdded'''. Сначала мы записываем информацию об окне в переменную '''z.''' '''Windowinf'''o — объект, дающий доступ к обширной низкоуровневой информации ''X Window'' об окне. В данном случае нас интересуют класс windowclass и имя окна: с их помощью мы определим, является ли клиентом ''Firefox'' и какое это окно: у каждого окна браузера его классом '''windowclass''' является '''Firefox'''. Кроме того, наш код отличает главное окно от консоли ошибок по значению имени '''windowclass: Navigator и Error Console''' соответственно.
  
Таким образом, при каждом добавлении нового клиента мы проверяем, является ли он консолью ошибок Firefox или главным окном браузера. В первом случае мы располагаем окно в левом верхнем углу экрана и задаем ему ширину по умолчанию в 200 пикселей. Затем мы смотрим, есть ли главное окно, и если есть, также изменяем его размер. С другой стороны, если только что добавленный клиент главное окно, мы также меняем его размер, если консоль уже есть.
+
Таким образом, при каждом добавлении нового клиента мы проверяем, является ли он консолью ошибок Firefox или главным окном браузера. В первом случае мы располагаем окно в левом верхнем углу экрана и задаем ему ширину по умолчанию в 200  
 +
 
 +
{{Врезка|right|Заголовок=Пинг-понг с вашими окнами|Содержание=Для иллюстрации возможностей скриптов ''KWin'' Рохан Прабху даже написал пинг-понг в скрипте ''KWin''. Не то чтобы было сильно удобно, когда окна летают по экрану, но это хороший пример, с которым вам непременно стоит познакомиться.
 +
 
 +
Со страницы http://rohanprabhu.com/?p=56, установите скрипт в каталог скриптов ''KWin'' и сделайте его исполняемым, затем перезагрузите ''KWin в Konsole'', после чего скрипт в ''Konsole'' попросит вас выбрать клавиши управления.
 +
 
 +
Например, можно устроить войну браузеров, выбрав своей ракеткой ''Firefox'', а ракеткой компьютера ''Chrome или Konqueror''. Затем выберите другое окно в качестве мяча, а в окне Konsole вы увидите счет матча.
 +
 
 +
[[Изображение:Lxf145-11g-tut-kwin 4.jpeg|thumb|Война браузеров в виде пинг-понга на вашем рабочем столе.]]
 +
|Ширина=20%}}
 +
 
 +
===События для конкретных клиентов===
  
====События для конкретных клиентов====
 
 
Впрочем, можно сделать и лучше: нельзя ли нам автоматически изменять размер главного окна при изменении размера окна консоли, чтобы они всегда были «приклеены» друг к другу? Для этого свяжем безымянную функцию с событием '''clientMoved''', генерируемым для консоли. Добавьте следующие строки в конец кода, который выполняется при добавлении окна консоли (до } else if…):
 
Впрочем, можно сделать и лучше: нельзя ли нам автоматически изменять размер главного окна при изменении размера окна консоли, чтобы они всегда были «приклеены» друг к другу? Для этого свяжем безымянную функцию с событием '''clientMoved''', генерируемым для консоли. Добавьте следующие строки в конец кода, который выполняется при добавлении окна консоли (до } else if…):
  
Строка 107: Строка 134:
  
 
Разница между тем, что мы делали раньше, и тем, что делаем сейчас, в том, что '''clientMoved''' — событие, генерируемое не на уровне системы для объекта workspace с клиентом в качестве параметра, а для конкретного клиента; в данном случае, для окна консоли. И когда мы связываем безымянную функцию с этим событием, функции не нужен клиент в качестве параметра, потому что мы уже знаем, что это за клиент. В результате при каждом перемещении (в том числе и при изменении размеров) окна консоли положение главного окна изменяется соответствующим образом.
 
Разница между тем, что мы делали раньше, и тем, что делаем сейчас, в том, что '''clientMoved''' — событие, генерируемое не на уровне системы для объекта workspace с клиентом в качестве параметра, а для конкретного клиента; в данном случае, для окна консоли. И когда мы связываем безымянную функцию с этим событием, функции не нужен клиент в качестве параметра, потому что мы уже знаем, что это за клиент. В результате при каждом перемещении (в том числе и при изменении размеров) окна консоли положение главного окна изменяется соответствующим образом.
 +
 
Однако иногда было бы интересно распознать клиента внутри функции. В данном случае нужно указать объект следующим образом:
 
Однако иногда было бы интересно распознать клиента внутри функции. В данном случае нужно указать объект следующим образом:
  
Строка 118: Строка 146:
 
Таким образом наша безымянная функция получает доступ к клиенту, генерирующему событие, в данном случае – через переменную клиента. Здесь нам это не нужно, поскольку мы знаем, что функция вызывается только для окна консоли, но если функция будет вызываться различными клиентами, нам понадобится переменная, чтобы их различать.
 
Таким образом наша безымянная функция получает доступ к клиенту, генерирующему событие, в данном случае – через переменную клиента. Здесь нам это не нужно, поскольку мы знаем, что функция вызывается только для окна консоли, но если функция будет вызываться различными клиентами, нам понадобится переменная, чтобы их различать.
  
====Файл настройки скрипта====
+
{{Врезка|right|Заголовок=Вкладки|Содержание=Здесь мы работали только с отдельными окнами, но с помощью объекта clientgroup можно получить доступ к вкладкам. Чтобы создать новую группу вкладок, просто объявите переменную '''var group = new ClientGroup(client)'''; где '''client''' – первое окно, которое вы хотите добавить. Остальные окна можно добавить с помощью функции '''clientgroup.add''', удалить – с помощью метода clientgroup.remove, удалить все – с помощью метода '''clientgroup.removeAll'''.
Если вы хотите задавать для файла скрипта настройки, просто создайте файл с тем же именем, но с расширением '''.kwscfg''' в каталоге ~ '''/ .kde4 / share / apps / kwin / scripts /''' . Этот файл должен иметь формат INI-файла с парами '''ключ–значение''' в следующем виде:
+
 
+
consoleHeight=200
+
Как вы видите, в этом файле настройки мы задаем ширину по умолчанию для окна консоли из нашего скрипта «склеивания» окон. Теперь нам остается только воспользоваться этим значением в скрипте, изменив объявление переменной '''console_height''' следующим образом:
+
 
+
var console_height = config.get(“consoleHeight”);
+
 
+
Здесь используется одиночный объект '''config,''' и в дальнейшем, если в скрипте нужно использовать некоторые заданные значения, лучше задавать их в файле настройки и получать в своем скрипте функцией '''config.get.''' Вы всегда можете захотеть изменить эти значения, и проще и менее рискованно сделать это в файле настройки, чем вторгаясь в код.
+
 
+
Если в файле настройки больше одной пары ключ –значение, можно получить их так же, как в этом примере, но также можно вызвать '''config.get()''' без параметров и получить все ключи и значения в ассоциативном массиве. Или с помощью вызова '''config.get(“key1”, “key2”, “key3”''') можно получить ассоциативный массив заданных ключей и их значений.
+
 
+
Если в файле настройки нужно проверить только наличие ключа, воспользуйтесь вызовом '''config.exists(“key”)'''. При отладке можно воспользоваться методом '''config.loaded''', который вернет '''tru'''e, если файл настройки был найден и загружен, и '''false''' в противном случае. Учтите, что у каждого скрипта ''KWi''n есть доступ только к своему файлу настройки.
+
 
+
====Что дальше?====
+
{{Врезка|right|Содержание=[[ Изображение:Lxf145-11g-tut-kwin 1.jpg|300px]] Когда вы заменяете KWin в Konsole, вы получаете всю информацию, которую вывели|Ширина=300px}}
+
Поддержка скриптов в ''KWin'' все еще находится на начальном уровне, и это ясно из отсутствия многих событий, методов и свойств, способных представлять интерес. Например, у объекта
+
'''client''' есть методы '''isShade()''' и '''isShadeable(''') для определения, затенен ли клиент и можно ли его затенить, но нет метода setShade(), чтобы изменить состояние затененности клиента. У объекта клиента также есть метод '''isMaximizable()''' и событие '''maximizeSet''', которое генерируется при разворачивании окна, но (все еще) нельзя программно развернуть клиента, например, методом setMaximize().
+
Это означает что на практике при появлении той или иной идеи вы часто не сможете ее воплотить, потому что скрипты не поддерживают необходимых вам функций. Но не забывайте, что это первая версия KDE с поддержкой ''KWin''. В следующих версиях непременно появятся новые функции, и вы в конце концов сможете автоматизировать почти все свои задачи управления окнами в KDE. Управление событиями и тот факт, что скрипты KWin можно писать на обычном JavaScript, делают их доступными большому количеству пользователей.
+
 
+
Рохан Прабху [Rohan Prabhu], главный разработчик поддержки скриптов ''KWin'', написал руководство, доступное в его блоге: [[http: / / rohanprabhu.com / ?p=116]]. В нем он пишет скрипт, сохраняющий положение окна «поверх всех окон», пока оно не развернуто. Когда окно разворачиваются, оно становится обычным, и его можно накрыть другими окнами, когда оно развернуто. Когда окно неразвернуто, скрипт снова автоматически располагает его «поверх всех окон».
+
 
+
Прабху регулярно пишет о различных аспектах написания скриптов ''KWin'' в своем блоге; ознакомиться с этими записями можно по ссылке [[http: / / rohanprabhu.com / ?tag=kwin_scripting]]. С его блогом, документацией по API и вдохновением, которое, надеюсь, у вас появилось, у вас есть все необходимое для успешного программирования...
+
 
+
----
+
{{Врезка|right|Содержание=[[Изображение:Lxf145-11g-tut-kwin 2.jpg.jpeg|300px]]Склейте окна навсегда с помощью скрипта KWin, и вам незачем будет насильственно совмещать их контуры.|Ширина=300px}}
+
Наш эксперт
+
Коэн Вервлоесем
+
пользуется свободными программами с 2000 года, и ему нравятся те, которые легко автоматизировать.
+
 
+
== «Добыть информацию об окнах можно и не дожидаясь события.»
+
Скрипты в других оконных менеджерах ==
+
''KWin'' – не единственный оконный менеджер, позволяющий изменять поведение окон с помощью скриптов. Многие из так называемых «мозаичных» оконных менеджеров полностью поддерживают скрипты. Например, оконный менеджер ''Awesome'' допускает значительное расширение с помощью языка программирования Lua и обладает обширным и хорошо задокументированным API, с помощью которого можно тонко изменить поведение всех окон. Тот же подход использует ''Xmonad'', но он написан на Haskell, чисто функциональном языке программирования, который не слишком просто освоить.
+
Существует несколько сторонних программ, которые «подцепляются» к оконному менеджеру и предоставляют вам контроль за местоположением и параметрами окон. Многие из них используют спецификацию расширенных подсказок оконного менеджера (Extended Window Manager Hints – EWMH), которой следует большинство популярных файловых менеджеров, в том числе ''KWin, Metacity, Awesome, Xmonad и Openbox''. Например, существует программа ''Devil’s Pie'', которая считывает скрипты, позволяющие вам задавать правила для своих любимых приложений.
+
 
+
Команда '''wmctrl''' также предоставляет вам полный контроль над своими окнами, и она прекрасно подходит для использования в собственных скриптах оболочки. И если вам удобнее писать скрипты в ''Bash'', чем программы на JavaScript, '''wmctrl''' определенно лучший выбор.
+
 
+
 
+
 
+
 
+
[[Изображение:Lxf145-11g-tut-kwin 3.jpg|Lxf145-11g-tut-kwin 3.jpg]]
+
 
+
==Скорая помощь==
+
При проверке скрипта ''KWin'' для просмотра значений переменных, особенно заголовка клиента, класса windowclass и имени окна, в целях отладки пользуйтесь командой print.
+
 
+
===Вкладки===
+
Здесь мы работали только с отдельными окнами, но с помощью объекта clientgroup можно получить доступ к вкладкам. Чтобы создать новую группу вкладок, просто объявите переменную '''var group = new ClientGroup(client)'''; где '''client''' – первое окно, которое вы хотите добавить. Остальные окна можно добавить с помощью функции '''clientgroup.add''', удалить – с помощью метода clientgroup.remove, удалить все – с помощью метода '''clientgroup.removeAll'''.
+
  
 
У объекта clientgroup есть множество интересных методов для работы с клиентами в группе. Например: '''clientgroup.clients''' возвращает массив всех клиентов, являющихся членами группы; с помощью '''clientgroup.contains(client)''' можно проверить, является ли конкретный клиент членом группы.
 
У объекта clientgroup есть множество интересных методов для работы с клиентами в группе. Например: '''clientgroup.clients''' возвращает массив всех клиентов, являющихся членами группы; с помощью '''clientgroup.contains(client)''' можно проверить, является ли конкретный клиент членом группы.
  
'''Clientgroup.indexOf(client)''' возвращает положение клиента в группе вкладок, а пользуясь '''clientgroup.mov'''e, можно переместить окно клиента в другое положение. Таким образом, с помощью объекта '''clientgroup''' можно написать собственный оконный менеджер с вкладками поверх ''KWin''.
+
'''Clientgroup.indexOf(client)''' возвращает положение клиента в группе вкладок, а пользуясь '''clientgroup.mov'''e, можно переместить окно клиента в другое положение. Таким образом, с помощью объекта '''clientgroup''' можно написать собственный оконный менеджер с вкладками поверх ''KWin''.|Ширина=20%}}
  
Пропустили номер? Узнайте на с. 104, как получить его прямо сейчас.
+
===Файл настройки скрипта===
  
 +
Если вы хотите задавать для файла скрипта настройки, просто создайте файл с тем же именем, но с расширением '''.kwscfg''' в каталоге ~ '''/.kde4/share/apps/kwin/scripts/''' . Этот файл должен иметь формат INI-файла с парами '''ключ–значение''' в следующем виде:
  
{{Врезка|right|Содержание=[[Изображение:Lxf145-11g-tut-kwin 4.jpeg|Lxf145-11g-tut-kwin 4.jpeg]]Война браузеров в виде пинг-понга на вашем рабочем столе.|300px]] Когда вы заменяете KWin в Konsole, вы получаете всю информацию, которую вывели|Ширина=300px}}
+
consoleHeight=200
  
 +
Как вы видите, в этом файле настройки мы задаем ширину по умолчанию для окна консоли из нашего скрипта «склеивания» окон. Теперь нам остается только воспользоваться этим значением в скрипте, изменив объявление переменной '''console_height''' следующим образом:
  
 +
var console_height = config.get(“consoleHeight”);
  
===Пинг-понг с вашими окнами===
+
Здесь используется одиночный объект '''config,''' и в дальнейшем, если в скрипте нужно использовать некоторые заданные значения, лучше задавать их в файле настройки и получать в своем скрипте функцией '''config.get.''' Вы всегда можете захотеть изменить эти значения, и проще и менее рискованно сделать это в файле настройки, чем вторгаясь в код.
  
Для иллюстрации возможностей скриптов ''KWin'' Рохан Прабху даже написал пинг-понг в скрипте ''KWin''. Не то чтобы было сильно удобно, когда окна летают по экрану, но это хороший пример, с которым вам непременно стоит познакомиться.
+
Если в файле настройки больше одной пары ключ –значение, можно получить их так же, как в этом примере, но также можно вызвать '''config.get()''' без параметров и получить все ключи и значения в ассоциативном массиве. Или с помощью вызова '''config.get(“key1”, “key2”, “key3”''') можно получить ассоциативный массив заданных ключей и их значений.
Со страницы [[http: / / rohanprabhu.com /?p=56]], установите скрипт в каталог скриптов ''KWin'' и сделайте его исполняемым, затем перезагрузите ''KWin в Konsole'', после чего скрипт в ''Konsole'' попросит вас выбрать клавиши управления.
+
  
Например, можно устроить войну браузеров, выбрав своей ракеткой ''Firefox'', а ракеткой компьютера – ''Chrome или Konqueror''. Затем выберите другое окно в качестве мяча, а в окне Konsole вы увидите счет матча.
+
Если в файле настройки нужно проверить только наличие ключа, воспользуйтесь вызовом '''config.exists(“key”)'''. При отладке можно воспользоваться методом '''config.loaded''', который вернет '''tru'''e, если файл настройки был найден и загружен, и '''false''' в противном случае. Учтите, что у каждого скрипта ''KWi''n есть доступ только к своему файлу настройки.
  
 +
{{Врезка|left|Заголовок=Скорая помощь|Содержание=При проверке сложных скриптов ''KWin'' проявляйте осторожность. Например, если вы сделаете ошибку в поведении активных окон, вы даже не сможете вернуться в ''Konsole'', чтобы перезагрузить программу.|Ширина=20%}}
  
 +
===Что дальше?===
  
 +
Поддержка скриптов в ''KWin'' все еще находится на начальном уровне, и это ясно из отсутствия многих событий, методов и свойств, способных представлять интерес. Например, у объекта '''client''' есть методы '''isShade()''' и '''isShadeable(''') для определения, затенен ли клиент и можно ли его затенить, но нет метода setShade(), чтобы изменить состояние затененности клиента. У объекта клиента также есть метод '''isMaximizable()''' и событие '''maximizeSet''', которое генерируется при разворачивании окна, но (все еще) нельзя программно развернуть клиента, например, методом setMaximize().
  
 +
Это означает что на практике при появлении той или иной идеи вы часто не сможете ее воплотить, потому что скрипты не поддерживают необходимых вам функций. Но не забывайте, что это первая версия KDE с поддержкой ''KWin''. В следующих версиях непременно появятся новые функции, и вы в конце концов сможете автоматизировать почти все свои задачи управления окнами в KDE. Управление событиями и тот факт, что скрипты KWin можно писать на обычном JavaScript, делают их доступными большому количеству пользователей.
  
 +
Рохан Прабху [Rohan Prabhu], главный разработчик поддержки скриптов ''KWin'', написал руководство, доступное в его блоге: http://rohanprabhu.com/?p=116. В нем он пишет скрипт, сохраняющий положение окна «поверх всех окон», пока оно не развернуто. Когда окно разворачиваются, оно становится обычным, и его можно накрыть другими окнами, когда оно развернуто. Когда окно неразвернуто, скрипт снова автоматически располагает его «поверх всех окон».
  
 
+
Прабху регулярно пишет о различных аспектах написания скриптов ''KWin'' в своем блоге; ознакомиться с этими записями можно по ссылке http://rohanprabhu.com/?tag=kwin_scripting. С его блогом, документацией по API и вдохновением, которое, надеюсь, у вас появилось, у вас есть все необходимое для успешного программирования...
 
+
 
+
 
+
[[Изображение:Lxf145-11g-tut-kwin 3.jpg|Lxf145-11g-tut-kwin 3.jpg]]
+
 
+
 
+
====Скорая помощь====
+
При проверке сложных скриптов ''KWin'' проявляйте осторожность. Например, если вы сделаете ошибку в поведении активных окон, вы даже не сможете вернуться в ''Konsole'', чтобы перезагрузить программу.
+

Текущая версия на 20:17, 10 июля 2014

Содержание

[править] KWin: Порулим окнами

Коэн Вервлоесем не любит таскать окна и с ними валандаться, и рад был узнать, что последняя версия KWin поддерживает скрипты.
Lxf145-11g-tut-kwin 6.jpg


В KDE 4.6 оконный менеджер KWin получил новую прекрасную возможность: интерфейс скриптов. А значит, поведение окон можно настроить по своему вкусу. Пара примеров: все окна, кроме активного, можно затенить; можно сохранять расположение окна «поверх других», пока вы не развернете его и оно не будет считаться обычным окном. Также можно «склеить» два окна: при изменении размера одного размер второго будет автоматически меняться так, чтобы их контуры оставались вместе. Возможности безграничны. В этой статье мы покажем, что можно сделать с помощью скриптов KWin, и после ее прочтения вы сможете написать свои скрипты Kwin и оптимизировать поведение окон на своем рабочем столе.

[править] Привет, мир

Прежде всего следует узнать, где KWin ищет скрипты – а это каталог ~ /.kde4/share/apps/kwin/scripts/ . Все файлы с расширениями .kwinscript, .kws и .kwinqs, у которых установлен бит выполнения, будут распознаны KWin как файлы скриптов. По умолчанию при запуске KWin выполняет все обнаруженные им скрипты в этом каталоге. Проверим это. Создайте файл helloworld.kwinscript со следующим содержимым в каталоге scripts:

print(“Hello world!”);

Затем сделайте файл исполняемым:

chmod +x ~/.kde4/share/apps/kwin/scripts/helloworld.kwinscript

Теперь перезагрузите KWin в Konsole; при этом будет отображаться вывод скрипта, а также некоторая отладочная информация:

kwin --replace &

Если вы не видите слов “Hello world!”, возможно, вы забыли сделать скрипт исполняемым или у вас более старая версия KDE. Также, возможно, вы допустили синтаксическую ошибку; но тогда KWin выдает сообщение об ошибке в консоли. Если все работает, можно двигаться дальше.

[править] Различные объекты

Язык скриптов KWin – ECMAScript, стандартизированная версия JavaScript. Если у вас есть опыт программирования на JavaScript, то проблем с написанием скриптов KWin не будет. В дальнейшем мы будем считать, что вы знаете JavaScript, но объясним некоторые основные концепции для тех, у кого есть опыт программирования на других языках, чтобы они не отставали. Прежде всего, знайте, что существуют три вида объектов:

  • Инициализируемые [instantiable] Они создаются с помощью конструкции var foo = new Foo();. Объектов такого типа можно создавать сколько угодно.
  • Одиночные [singleton] Для этих объектов существует только один экземпляр заданного типа. Их нельзя создавать самим, но они предоставляются автоматически в скриптах Kwin.
  • Плавающие [floating] Для этих объектов существует множество экземпляров заданного типа, но их нельзя создавать самим: они получаются в качестве возвращаемого значения метода.

Скрипты KWin управляются событиями: KWin генерирует определенные события, с которыми можно связать функции, вызываемые при наступлении события. Этот подход – ключ к изменению поведения программы согласно своим потребностям: нужно просто назначить собственные функции подходящим событиям. Следующий пример прояснит это:

workspace.clientMinimized.connect(function(client) {
print(“Minimized: [“ + client.caption() + “]”);
});

Объект workspace здесь – одиночный; у него есть множество событий, инициируемых на уровне системы. Это основной источник событий в KWin, и вы будете пользоваться им во многих скриптах для инициализации взаимодействия с оконным менеджером. Например, событие clientMinimized, которым мы здесь воспользовались, возникает каждый раз при сворачивании окна. С помощью метода connect мы связываем с этим событием функцию. В данном случае функция безымянная; ей передается один параметр, клиент (представляющий собой окно, плавающий объект). В этой функции мы выводим сообщение о том, что клиент свернут, и применяем метод caption() объекта-клиента для получения заголовка окна. Сохраните этот скрипт, сделайте его исполняемым, перезагрузите KWin в Konsole и наблюдайте за выводом команды при сворачивании окна. Безымянной функцией пользоваться не обязательно. Следующий код эквивалентен предыдущему:

function printCaption(client) {
print(“Minimized: [“ + client.caption() + “]”);
}
workspace.clientMinimized.connect(printCaption);

Если функция у вас небольшая и используется только в одном месте, она может быть безымянной: меньше набора кода. Однако, когда функция разрастается или нужно вызывать ее в нескольких местах, лучше определить ее явно, чтобы код оставался понятным.

(thumbnail)
Когда вы заменяете KWin в Konsole, вы получаете всю информацию, которую вывели

[править] Методы и свойства

Добыть информацию об окнах можно и не дожидаясь наступления определенного события – для этого достаточно воспользоваться методами и свойствами. Метод – это функция, у которой есть возвращаемое значение. У объекта каждого типа есть несколько заданных методов. Например, для получения списка всех клиентов можно воспользоваться методом getAllClients() объекта workspace, который возвращает массив всех клиентов:

var clients = workspace.getAllClients();
for(var i = 0; i < clients.length; i++) {
print(“[“ + clients[i].caption() + “]”);
}

Здесь мы создаем инициализируемый объект clients – в нем хранится массив всех клиентов. Затем в цикле for мы перебираем клиентов и выводим их заголовки. Размер массива мы можем получить с помощью свойства length.

Если вы захотите написать собственный скрипт, загляните в документацию по API скриптов KWin на http://rohanprabhu.com/files/kwsapi.html. На этой странице приведен список всех объектов, которые KWin распознает в своих скриптах – например, workspace, toplevel, client, clientgroup, windowinfo и config. Для каждого объекта в документации приведен список всех событий, методов и свойств с коротким описанием их назначения. Эта информация поможет вам понять, чего именно можно достичь с помощью скриптов. Нужно знать, что toplevel — родительский класс по отношению к client, поэтому все методы объектов toplevel также применимы к объектам клиентов.

(thumbnail)
Склейте окна навсегда с помощью скрипта KWin, и вам незачем будет насильственно совмещать их контуры.

[править] Склеиваем окна вместе

В принципе, ваших знаний уже достаточно для того, чтобы менять поведение окон по своему вкусу с помощью KWin. Чтобы придать вам вдохновения, приведем простой, но полезный пример: этот скрипт предназначен web-разработчикам, желающим, чтобы консоль ошибок всегда показывалась поверх главного окна Firefox и они видели бы в нем все ошибки и предупреждения. Вот как он выглядит:

var main_present = 0;
var console_present = 0;
var console_height = 200;
var main;
var console;
function viewportHeight() {
return (workspace.dimensions().h)/(workspace.desktopGridSize().h);
}
function viewportWidth() {
return (workspace.dimensions().w)/(workspace.desktopGridSize().w);
}
function adjustMain() {
var geom = console.geometry();
main.move(0, geom.height);
main.resize(viewportWidth(), viewportHeight() - geom.height);
}
workspace.clientAdded.connect(function(client) {
var z = client.getWindowInfo();
if(z.windowClassClass == “Firefox”) {
if(client.caption() == “Error Console”) {
console = client;
console_present = 1;
console.move(0, 0);
console.resize(viewportWidth(), console_height);
if(main_present == 1) {
adjustMain();
}
} else if(z.windowClassName == “Navigator”) {
main = client;
main_present = 1;
if(console_present == 1) {
adjustMain();
}
}
}
});

Код начинается с объявления некоторых переменных: мы объявляем переменные для хранения главного окна и консоли окна ошибок. Мы также объявляем переменные main и console, которые будут содержать ссылки на клиентов главного окна и окна консоли ошибок. Затем мы определяем две вспомогательных функции для получения ширины и высоты экрана рабочего стола. В функции adjustMain мы изменяем ширину главного окна так, чтобы оно располагалось прямо под окном консоли ошибок.



Большая часть кода – безымянная функция, которая будет вызываться при каждом при наступлении события clientAdded. Сначала мы записываем информацию об окне в переменную z. Windowinfo — объект, дающий доступ к обширной низкоуровневой информации X Window об окне. В данном случае нас интересуют класс windowclass и имя окна: с их помощью мы определим, является ли клиентом Firefox и какое это окно: у каждого окна браузера его классом windowclass является Firefox. Кроме того, наш код отличает главное окно от консоли ошибок по значению имени windowclass: Navigator и Error Console соответственно.

Таким образом, при каждом добавлении нового клиента мы проверяем, является ли он консолью ошибок Firefox или главным окном браузера. В первом случае мы располагаем окно в левом верхнем углу экрана и задаем ему ширину по умолчанию в 200


[править] События для конкретных клиентов

Впрочем, можно сделать и лучше: нельзя ли нам автоматически изменять размер главного окна при изменении размера окна консоли, чтобы они всегда были «приклеены» друг к другу? Для этого свяжем безымянную функцию с событием clientMoved, генерируемым для консоли. Добавьте следующие строки в конец кода, который выполняется при добавлении окна консоли (до } else if…):

console.clientMoved.connect(function() {
if(main_present == 1) {
adjustMain();
}
});

Разница между тем, что мы делали раньше, и тем, что делаем сейчас, в том, что clientMoved — событие, генерируемое не на уровне системы для объекта workspace с клиентом в качестве параметра, а для конкретного клиента; в данном случае, для окна консоли. И когда мы связываем безымянную функцию с этим событием, функции не нужен клиент в качестве параметра, потому что мы уже знаем, что это за клиент. В результате при каждом перемещении (в том числе и при изменении размеров) окна консоли положение главного окна изменяется соответствующим образом.

Однако иногда было бы интересно распознать клиента внутри функции. В данном случае нужно указать объект следующим образом:

console.clientMoved.connect(client, function() {
if(main_present == 1) {
adjustMain();
print(client.caption() + “ is moved”);
}
});

Таким образом наша безымянная функция получает доступ к клиенту, генерирующему событие, в данном случае – через переменную клиента. Здесь нам это не нужно, поскольку мы знаем, что функция вызывается только для окна консоли, но если функция будет вызываться различными клиентами, нам понадобится переменная, чтобы их различать.


[править] Файл настройки скрипта

Если вы хотите задавать для файла скрипта настройки, просто создайте файл с тем же именем, но с расширением .kwscfg в каталоге ~ /.kde4/share/apps/kwin/scripts/ . Этот файл должен иметь формат INI-файла с парами ключ–значение в следующем виде:

consoleHeight=200

Как вы видите, в этом файле настройки мы задаем ширину по умолчанию для окна консоли из нашего скрипта «склеивания» окон. Теперь нам остается только воспользоваться этим значением в скрипте, изменив объявление переменной console_height следующим образом:

var console_height = config.get(“consoleHeight”);

Здесь используется одиночный объект config, и в дальнейшем, если в скрипте нужно использовать некоторые заданные значения, лучше задавать их в файле настройки и получать в своем скрипте функцией config.get. Вы всегда можете захотеть изменить эти значения, и проще и менее рискованно сделать это в файле настройки, чем вторгаясь в код.

Если в файле настройки больше одной пары ключ –значение, можно получить их так же, как в этом примере, но также можно вызвать config.get() без параметров и получить все ключи и значения в ассоциативном массиве. Или с помощью вызова config.get(“key1”, “key2”, “key3”) можно получить ассоциативный массив заданных ключей и их значений.

Если в файле настройки нужно проверить только наличие ключа, воспользуйтесь вызовом config.exists(“key”). При отладке можно воспользоваться методом config.loaded, который вернет true, если файл настройки был найден и загружен, и false в противном случае. Учтите, что у каждого скрипта KWin есть доступ только к своему файлу настройки.


[править] Что дальше?

Поддержка скриптов в KWin все еще находится на начальном уровне, и это ясно из отсутствия многих событий, методов и свойств, способных представлять интерес. Например, у объекта client есть методы isShade() и isShadeable() для определения, затенен ли клиент и можно ли его затенить, но нет метода setShade(), чтобы изменить состояние затененности клиента. У объекта клиента также есть метод isMaximizable() и событие maximizeSet, которое генерируется при разворачивании окна, но (все еще) нельзя программно развернуть клиента, например, методом setMaximize().

Это означает что на практике при появлении той или иной идеи вы часто не сможете ее воплотить, потому что скрипты не поддерживают необходимых вам функций. Но не забывайте, что это первая версия KDE с поддержкой KWin. В следующих версиях непременно появятся новые функции, и вы в конце концов сможете автоматизировать почти все свои задачи управления окнами в KDE. Управление событиями и тот факт, что скрипты KWin можно писать на обычном JavaScript, делают их доступными большому количеству пользователей.

Рохан Прабху [Rohan Prabhu], главный разработчик поддержки скриптов KWin, написал руководство, доступное в его блоге: http://rohanprabhu.com/?p=116. В нем он пишет скрипт, сохраняющий положение окна «поверх всех окон», пока оно не развернуто. Когда окно разворачиваются, оно становится обычным, и его можно накрыть другими окнами, когда оно развернуто. Когда окно неразвернуто, скрипт снова автоматически располагает его «поверх всех окон».

Прабху регулярно пишет о различных аспектах написания скриптов KWin в своем блоге; ознакомиться с этими записями можно по ссылке http://rohanprabhu.com/?tag=kwin_scripting. С его блогом, документацией по API и вдохновением, которое, надеюсь, у вас появилось, у вас есть все необходимое для успешного программирования...

Персональные инструменты
купить
подписаться
Яндекс.Метрика