[фичреквест] Биндинг функций Razor-Qt на горячие клавиши

119 views
Skip to first unread message

Alexander Shmakov

unread,
Jan 3, 2013, 7:20:12 AM1/3/13
to razor...@googlegroups.com
Хотел написать в багтрекер, но не могу сформулировать грамотно на английском.

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

Например "показать меню приложений" (которое по правому клику на рабочем столе выскакивает, за него razor-desktop отвечает же?). для конфигураций без razor-panel, но со сторонним "доком" типа AWN это будет очень даже неплохо (у меня как раз сейчас такая ситуация - приходится сворачивать все приложения чтобы добраться до меню рабочего стола, т.к другого тупо нет)
Или "сон", "отключение питания", "перезагрузка" (razor-power это умеет). Было бы шикарно выключать и перезагружаться по хоткею, не вызывая razor-power...
В общем-то смысл в этом один - минимизировать количество бесполезных телодвижений для выполнения конкретной задачи.
Конечно, это можно реализовать и сторонними костылями, но ЗАЧЕМ? когда в разоре уже все готово к этому, но тупо не реализовано :(

Александр Соколов

unread,
Jan 3, 2013, 11:03:33 AM1/3/13
to razor...@googlegroups.com
Вначале конкретные ответы, а потом поделюсь наболевшим. 

Часть первая, конкретная.

Багреквсты надо писать на конкретные клавиши, т.е. в твоем случае на показ меню раб. стола. Скопом это не сделать, в каждой программе надо дописывать, хоть и не много. 
Про "сон", "отключение питания", "перезагрузка", здесь немного другая ситуация т.к. razor-power не запущен во время сеанса, то здесь надо биндить клавишу на запуск программы. И тут на сцену выходит, он ... (звучит барабанная дробь) ... razor-power. У него есть опции в командной строке как раз для этого.
Usage: razor-power
  or:  razor-power --check ACTION
  or:  razor-power ACTION
The first variant starts the GUI interface.
The second variant checks is the action can be performed.
The third variant executes the ACTION without the GUI.

Actions:
  logout            Close the current user session.
  hibernate         Hibernate the computer
  reboot            Reboot the computer
  shutdown, halt    Shutdown the computer
  suspend           Suspend the computer

т.е можно повесить клавишу на команду "razor-power reboot"  и радоваться. Но есть одно но, у меня не получилось привязаться к кнопке питания (смотри вторую часть)


Часть вторая, с мыслью по древу.

Текущее состояние с глобальными горячими клавишами (ГК) мне не нравиться. 

Во первых он глюный. В интернетах гуляют 2 версии ГК, одна - выдранная из PSI, вторая кусок libqxt. Первая работает лучше, но у нее лицензия не совместима с нашей, ЕМНИП то-же GNU, но несовместимая с нашей.  Мы используем вторую, у нее с лицензией проблем нет, но она откровенно глючит, например у меня перестают ГК работать если капс нажат. 

Во вторых сама реализация ГК в иксах кривая. Нет возможности узнать зарегистрирована ли уже клавиша и если да то кем. Т.е. нормального менеджера клавиш сделать не получается. Кстати это причина почему Qt-шники не включают ГК в Qt.

Есть у меня идея, на довольно смутная, давайте все вместе подумаем, может что-то красивое придумаем, а потом можно будет и реализовать. В общем идея такая:
Вся регистрация клавиш через D-Bus. Есть одна программа-сервер которая отвечает за все ГК, реально он регистрирует клавиши на себя, сервер имеет стандартный D-Bus интерфейс. Когда сторонняя программа хочет зарегистрировать клавишу, она дергает D-Bus метод сервера и передает туда 
  1. код клавиши (скорее всего в текстовом виде, что-то вроде "ALT+F2")
  2. и свой дбас метод который надо дернуть в случае нажатия хоткея (вот здесь я  пока не придумал в каком виде это передавать)
  3. также надо передать текстовое описание на человеческом языке, для отображения в диспетчере ГК, что-то вроде "Следующий трек в проигрывателе XXX". Здесь не понятно что делать с переводами.
Пока не совсем понятно, как определять что программа уже закрылась и клавиша свободна, возможно просто по отсутствию ветки в D-Bus-е. 

Отдельный вариант, регистрации это ГК для запуска программы, здесь по сути меняется пункт 2 на путь к бинарнику или desktop файлу. Но надо для этого делать отдельную функцию регистрации, или в первом случае параметр будет dbus:/bla-bla а во втором run:/usr/bin/foo. Что удобнее, что понятнее, не знаю.

Сервер не должен зависеть от тулкита, я думаю за основу можно взять xbindkeys и дописать к нему D-Busd адаптер на чистом С или С++, что там использует xbindkeys.
Если протокол получиться удобный и понятный, можно пропихнуть его в freedesktop, и сервер как эталонную реализацию. Возможно через несколько лет остальные подтянуться и будет меньше бардака. 

Приветствуются любые идеи, примеры аналогичных реализаций (у KDE есть в DBus-е ветка org.kde.KGlobalAccel на я с ходу не смог найти документацию на этот интерфейс), в общем любые мысли. 



3 января 2013 г., 16:20 пользователь Alexander Shmakov <uno...@gmail.com> написал:



--
Best regards,
Alexander.

Uno

unread,
Jan 6, 2013, 10:59:20 AM1/6/13
to razor...@googlegroups.com
хм, не думал что все так печально. В принципе, мне нравится твоя идея для реализации.
по поводу интерфейса и передаваемых параметров:
1) нормально
2) если программы будут регистрироваться в едином пространстве dbus разора для хоткеев, то можно просто передавать в виде ${program_name}.${action} (через точку). А отдельный метод будет преобразовывать это в валидный вызов.
Не думаю что это сложно (хоть я и не программировал никогда с использованием dbus)
3) а в чем проблема с переводами? может я чего не понимаю?


4 января 2013 г., 3:03 пользователь Александр Соколов <sokol...@gmail.com> написал:

Александр Соколов

unread,
Jan 7, 2013, 10:56:44 AM1/7/13
to razor...@googlegroups.com
Прошу прощения за долгое молчание, праздники, я в интернете набегами.

6 января 2013 г., 19:59 пользователь Uno <uno...@gmail.com> написал:

хм, не думал что все так печально. В принципе, мне нравится твоя идея для реализации.
по поводу интерфейса и передаваемых параметров:
1) нормально
2) если программы будут регистрироваться в едином пространстве dbus разора для хоткеев, то можно просто передавать в виде ${program_name}.${action} (через точку). А отдельный метод будет преобразовывать это в валидный вызов.
Не думаю что это сложно (хоть я и не программировал никогда с использованием dbus)
Это не стандартно, я сейчас подумал, что надо сделать синтаксис похожим на dbus-send. 
3) а в чем проблема с переводами? может я чего не понимаю?
Либо программа при регистрации записывает только один перевод для текущего языка, но тогда нельзя будет запустить "LANG=fr_FR hotkey-manager". Или программа должна передавать полный список переводов для всех языков, но это как-то бредов. 



--
Best regards,
Alexander.

Uno

unread,
Jan 7, 2013, 11:24:20 AM1/7/13
to razor...@googlegroups.com
Прошу прощения за долгое молчание, праздники, я в интернете набегами.

Да все ок, та же картина :)
 
Это не стандартно, я сейчас подумал, что надо сделать синтаксис похожим на dbus-send. 
 
Ну да, нестандартно, но когда сообщение писал - тоже смотрел на dbus-send
В принципе там то же самое что я сказал, но с тройным дублированием ветки куда слать событие, а так как она у нас одна, то я просто хотел упростить начальный синтаксис и генерить заключительный запрос отдельно.
Хотя да, тут лучше работать со стандартной схемой вызова dbus-send и не городить razor-specified костыли.

Либо программа при регистрации записывает только один перевод для текущего языка, но тогда нельзя будет запустить "LANG=fr_FR hotkey-manager". Или программа должна передавать полный список переводов для всех языков, но это как-то бредов. 

Да, бредово. Так что я за первый вариант реализации. Конечно, может быть несколько неудобно, но это скорее частный случай, чем постоянная практика. А как известно, на каждый частный случай воркэраунд не напишешь ;)

Александр Соколов

unread,
Jan 7, 2013, 12:03:55 PM1/7/13
to razor...@googlegroups.com


7 января 2013 г., 20:24 пользователь Uno <uno...@gmail.com> написал:

Прошу прощения за долгое молчание, праздники, я в интернете набегами.

Да все ок, та же картина :)
 
Это не стандартно, я сейчас подумал, что надо сделать синтаксис похожим на dbus-send. 
 
Ну да, нестандартно, но когда сообщение писал - тоже смотрел на dbus-send
В принципе там то же самое что я сказал, но с тройным дублированием ветки куда слать событие, а так как она у нас одна, то я просто хотел упростить начальный синтаксис и генерить заключительный запрос отдельно.
Хотя да, тут лучше работать со стандартной схемой вызова dbus-send и не городить razor-specified костыли.
Здесь ты не понял, здесь не одна ветка. Здесь передается путь к дбас-функции внешней программы. Т.е. кода плеер хочет зарарегать клавишу он вызовет функцию с такими примерно аргументами
  • Alt+P (клавиша)
  • org.mpris.clementine/Player/org.freedesktop.MediaPlayer/Play (путь к вызываемой функции)
  • Start playing
  • Начать воспроизведение 
А когда нажмут Alt+P сервер дернет org.mpris.clementine/Player/org.freedesktop.MediaPlayer/Play


Либо программа при регистрации записывает только один перевод для текущего языка, но тогда нельзя будет запустить "LANG=fr_FR hotkey-manager". Или программа должна передавать полный список переводов для всех языков, но это как-то бредов. 

Да, бредово. Так что я за первый вариант реализации. Конечно, может быть несколько неудобно, но это скорее частный случай, чем постоянная практика. А как известно, на каждый частный случай воркэраунд не напишешь ;)



--
Best regards,
Alexander.

Kuzma Shapran

unread,
Jan 7, 2013, 2:32:26 PM1/7/13
to razor...@googlegroups.com
В принципе, тематика мне очень интересна, я бы взялся реализовать. Возражений, надеюсь, нет?

Сейчас спешу на работу. Вечерком набросаю сюда свои идеи.

Uno

unread,
Jan 7, 2013, 4:45:44 PM1/7/13
to razor...@googlegroups.com
ну да, видимо не так понял. Сейчас дошло.
Да, концепция нормальная :)
только перевод наверное лучше один оставить, по текущей локали.
А то 100500 переводов каждый раз передавать не очень наверное будет.


8 января 2013 г., 4:03 пользователь Александр Соколов <sokol...@gmail.com> написал:

Kuzma Shapran

unread,
Jan 8, 2013, 3:02:43 AM1/8/13
to razor...@googlegroups.com
Итак мысли вслух (в общем-то почти всё это уже здесь звучало):

Программа, которая желает использовать глобальные клавиши линкуется с библиотекой, которая есть суть прослойка на dbus. Кроме этого либа запускает демона, если тот еще не запущен (избавляет от необходимости запускать через сессию разора и не привязываемся к DE).

Демон регистрирует на себя горячие клавиши и при нажатии дергает метод интерфейса либы. Т.е. на каждую функцию (типа плэй или стоп для плэера) есть свой интерфейс на dbus`е.

При регистрации хоткея прога передаёт демону: string hotkey, string callback_interface_name, string localised_description

При регистрации возможен вариант конфликта, когда хоткей уже используется. В этом случае демон запоминает этот запрос, но не будет его дергать (хотя как альтернатива - можно выполнять несколько действий параллельно по одному хоткею).

Кроме того демон даёт специальный интерфейс для просмотра и редактирования зарегистрированных хоткеев. Будет специальная UI прога для сего. Через неё можно будет:
- посмотреть какие хоткеи к чему привязаны
- поменять(!) хоткеи (в этом случае демон должен через dbus и либу известить зареганную прогу о смене хоткея, чтоб, например, та у себя в UI его отобразила и в настройках сохранила)
- отменить хоткеи - по сути назначить <null>
- добавить кастомные хоткеи - которые будут просто делать запуск приложений (через эту плюшку можно также вызывать внешнюю dbus-send, а можно конечно вызов dbus методов оформить в демоне внутренне чтоб быстрее было).

Пока вижу две проблемы:
1. Есть клиент этой системы неожиданно падает - демон должен об этом узнать. Насколько я помню, для этого клиент должен зарегать dbus сервис, тогда dbus пошлет всем (и демону тоже) сигнал disconnected.
2. Возможен конфликт с другими программами, которые не пользуются этой системой.

P.S. писать dbus интерфейс на чистом C или C++ дело, увы, муторное и запутанное. Qt в качестве прослойки рулит.

P.P.S. уже было сказано, но повторюсь: текстовое описание команды надо передавать только в одном, текущем, переводе. Так как всё проиходит runtime и нигде не сохраняется, то париться всеми языками не надо.

Я всё правильно подытожил?

Александр Соколов

unread,
Jan 9, 2013, 4:19:43 AM1/9/13
to razor...@googlegroups.com
В целом правильно, но есть несколько замечаний.


вторник, 8 января 2013 г., 12:02:43 UTC+4 пользователь Kuzma Shapran написал:
Итак мысли вслух (в общем-то почти всё это уже здесь звучало):

Программа, которая желает использовать глобальные клавиши линкуется с библиотекой, которая есть суть прослойка на dbus. Кроме этого либа запускает демона, если тот еще не запущен (избавляет от необходимости запускать через сессию разора и не привязываемся к DE).
Нет, отдельный сервер нужен, и придется запускать его при старте. Ведь кроме биндинга dbus есть еще "хоткеи - которые будут просто делать запуск приложений", возможна ситуация что я  настроил хоткей на запуск калькулятора, других хоткеев нет. Тогда после рестарта, сервер не будет запущен, и мой хоткей не обработается.


Демон регистрирует на себя горячие клавиши и при нажатии дергает метод интерфейса либы. Т.е. на каждую функцию (типа плэй или стоп для плэера) есть свой интерфейс на dbus`е.

При регистрации хоткея прога передаёт демону: string hotkey, string callback_interface_name, string localised_description
Два описания, одно на инглише, второе локализованное. Причем первое поле обязательное, второе может быть пустым. Это некоторая защита от криворуких программистов, которые тупо забьют текст на своем языке.

При регистрации возможен вариант конфликта, когда хоткей уже используется. В этом случае демон запоминает этот запрос, но не будет его дергать (хотя как альтернатива - можно выполнять несколько действий параллельно по одному хоткею).
Надо подумать, есть несколько вариантов (во всех примерах программа А уже зарегистрировала хоткей, теперь программа Б пытается его перерегистрировать)
  1.  Хоткей вешается на Б, после закрытия Б, восстанавливается привязка к А. Так сейчас работают хоткеи в Х-ах. Наверное это предпочтительный вариант, по крайней мере поведение привычное.
  2.  Хоткей остается на А, после закрытия А, устанавливается привязка к Б.
  3. Тупо возвращаем false, и пусть программа сама разбирается. Мне этот вариант не нравиться - возникает куча вопросов:
    1. А если приложению, вот по зарез, нужно перерегистрировать хоткей. Что добавлять параметр "force"?
    2. Как приложение Б узнает, что А закрылось и можно по новой регистрировать хоткей?
  4. Параллельная работа, IMHO это странное поведение, и вызовет кучу не очевидных вопросов.
В общем мне нравиться первый вариант - он наиболее логичен. 


Кроме того демон даёт специальный интерфейс для просмотра и редактирования зарегистрированных хоткеев. Будет специальная UI прога для сего. Через неё можно будет:
- посмотреть какие хоткеи к чему привязаны
- поменять(!) хоткеи (в этом случае демон должен через dbus и либу известить зареганную прогу о смене хоткея, чтоб, например, та у себя в UI его отобразила и в настройках сохранила)
- отменить хоткеи - по сути назначить <null>
Для отмены лучше сделать отдельные функции.
 
- добавить кастомные хоткеи - которые будут просто делать запуск приложений (через эту плюшку можно также вызывать внешнюю dbus-send, а можно конечно вызов dbus методов оформить в демоне внутренне чтоб быстрее было).

Пока вижу две проблемы:
1. Есть клиент этой системы неожиданно падает - демон должен об этом узнать. Насколько я помню, для этого клиент должен зарегать dbus сервис, тогда dbus пошлет всем (и демону тоже) сигнал disconnected.
Если клиент " неожиданно падает", то он не может ничего послать. Я думаю можно проверять наличие ветки которую зарегистрировали
  1. При нажатии клавиши
  2. При запросе "а зарегистрирована ли такая клавиша" 
  3. При запросе списка всех хоткеев.
  
2. Возможен конфликт с другими программами, которые не пользуются этой системой.

P.S. писать dbus интерфейс на чистом C или C++ дело, увы, муторное и запутанное. Qt в качестве прослойки рулит.
На Qt конечно удобнее, но судя по этому -http://www.matthew.ath.cx/misc/dbus и на сях не безумно сложно. Как ты думаешь, куда нас пошлют гномовцы если мы им предложим использовать сервер на Qt? А вся фишка от этого будет если сделать это стандартом.
В качестве прототипа Qt подходит, но потом придется переписывать без тулкита.

Kuzma Shapran

unread,
Jan 9, 2013, 5:31:10 AM1/9/13
to razor...@googlegroups.com


On Wednesday, 9 January 2013 22:19:43 UTC+13, Александр Соколов wrote:
В целом правильно, но есть несколько замечаний.


вторник, 8 января 2013 г., 12:02:43 UTC+4 пользователь Kuzma Shapran написал:
Итак мысли вслух (в общем-то почти всё это уже здесь звучало):

Программа, которая желает использовать глобальные клавиши линкуется с библиотекой, которая есть суть прослойка на dbus. Кроме этого либа запускает демона, если тот еще не запущен (избавляет от необходимости запускать через сессию разора и не привязываемся к DE).
Нет, отдельный сервер нужен, и придется запускать его при старте. Ведь кроме биндинга dbus есть еще "хоткеи - которые будут просто делать запуск приложений", возможна ситуация что я  настроил хоткей на запуск калькулятора, других хоткеев нет. Тогда после рестарта, сервер не будет запущен, и мой хоткей не обработается.

Точно! Как-то упустил такой сценарий.



Демон регистрирует на себя горячие клавиши и при нажатии дергает метод интерфейса либы. Т.е. на каждую функцию (типа плэй или стоп для плэера) есть свой интерфейс на dbus`е.

При регистрации хоткея прога передаёт демону: string hotkey, string callback_interface_name, string localised_description
Два описания, одно на инглише, второе локализованное. Причем первое поле обязательное, второе может быть пустым. Это некоторая защита от криворуких программистов, которые тупо забьют текст на своем языке.

Я всё же это вижу как registerHotkey(playback_hotkey, playback_hotkey_interface, tr("playback"));  Т.е. требования такие же как к локализации интерфейса.
А от паталогической криворукости абсолютной защиты, увы, не бывает.


При регистрации возможен вариант конфликта, когда хоткей уже используется. В этом случае демон запоминает этот запрос, но не будет его дергать (хотя как альтернатива - можно выполнять несколько действий параллельно по одному хоткею).
Надо подумать, есть несколько вариантов (во всех примерах программа А уже зарегистрировала хоткей, теперь программа Б пытается его перерегистрировать)

Так как это центраизовано через демон - то он просто дернёт несколько клиентов - в моём экспериментальном прототипе вызов нескольких клиентов через dBus уже работает.
  1.  Хоткей вешается на Б, после закрытия Б, восстанавливается привязка к А. Так сейчас работают хоткеи в Х-ах. Наверное это предпочтительный вариант, по крайней мере поведение привычное.
  2.  Хоткей остается на А, после закрытия А, устанавливается привязка к Б.
  3. Тупо возвращаем false, и пусть программа сама разбирается. Мне этот вариант не нравиться - возникает куча вопросов:
    1. А если приложению, вот по зарез, нужно перерегистрировать хоткей. Что добавлять параметр "force"?
    2. Как приложение Б узнает, что А закрылось и можно по новой регистрировать хоткей?
  4. Параллельная работа, IMHO это странное поведение, и вызовет кучу не очевидных вопросов.
В общем мне нравиться первый вариант - он наиболее логичен. 

М-да... тут возможен разброд и шатания. Ибо я пока склонен к варианту 4.
 
Кроме того демон даёт специальный интерфейс для просмотра и редактирования зарегистрированных хоткеев. Будет специальная UI прога для сего. Через неё можно будет:
- посмотреть какие хоткеи к чему привязаны
- поменять(!) хоткеи (в этом случае демон должен через dbus и либу известить зареганную прогу о смене хоткея, чтоб, например, та у себя в UI его отобразила и в настройках сохранила)
- отменить хоткеи - по сути назначить <null>
Для отмены лучше сделать отдельные функции.

Не проблема.
 
 
- добавить кастомные хоткеи - которые будут просто делать запуск приложений (через эту плюшку можно также вызывать внешнюю dbus-send, а можно конечно вызов dbus методов оформить в демоне внутренне чтоб быстрее было).

Пока вижу две проблемы:
1. Есть клиент этой системы неожиданно падает - демон должен об этом узнать. Насколько я помню, для этого клиент должен зарегать dbus сервис, тогда dbus пошлет всем (и демону тоже) сигнал disconnected.
Если клиент " неожиданно падает", то он не может ничего послать. Я думаю можно проверять наличие ветки которую зарегистрировали

Обнаружение падения клиента уже тоже работает. 
  1. При нажатии клавиши
  2. При запросе "а зарегистрирована ли такая клавиша" 
  3. При запросе списка всех хоткеев.
  
2. Возможен конфликт с другими программами, которые не пользуются этой системой.

P.S. писать dbus интерфейс на чистом C или C++ дело, увы, муторное и запутанное. Qt в качестве прослойки рулит.
На Qt конечно удобнее, но судя по этому -http://www.matthew.ath.cx/misc/dbus и на сях не безумно сложно. Как ты думаешь, куда нас пошлют гномовцы если мы им предложим использовать сервер на Qt? А вся фишка от этого будет если сделать это стандартом.
В качестве прототипа Qt подходит, но потом придется переписывать без тулкита.

Согласен. Отработать алгоритм на Qt, потом портировать на чистый C (не С++) - чтоб и гномовцы радовались.

Александр Соколов

unread,
Jan 9, 2013, 8:50:44 AM1/9/13
to razor...@googlegroups.com


9 января 2013 г., 14:31 пользователь Kuzma Shapran <leaf.o...@gmail.com> написал:



On Wednesday, 9 January 2013 22:19:43 UTC+13, Александр Соколов wrote:
В целом правильно, но есть несколько замечаний.


вторник, 8 января 2013 г., 12:02:43 UTC+4 пользователь Kuzma Shapran написал:
Итак мысли вслух (в общем-то почти всё это уже здесь звучало):

Программа, которая желает использовать глобальные клавиши линкуется с библиотекой, которая есть суть прослойка на dbus. Кроме этого либа запускает демона, если тот еще не запущен (избавляет от необходимости запускать через сессию разора и не привязываемся к DE).
Нет, отдельный сервер нужен, и придется запускать его при старте. Ведь кроме биндинга dbus есть еще "хоткеи - которые будут просто делать запуск приложений", возможна ситуация что я  настроил хоткей на запуск калькулятора, других хоткеев нет. Тогда после рестарта, сервер не будет запущен, и мой хоткей не обработается.

Точно! Как-то упустил такой сценарий.



Демон регистрирует на себя горячие клавиши и при нажатии дергает метод интерфейса либы. Т.е. на каждую функцию (типа плэй или стоп для плэера) есть свой интерфейс на dbus`е.

При регистрации хоткея прога передаёт демону: string hotkey, string callback_interface_name, string localised_description
Два описания, одно на инглише, второе локализованное. Причем первое поле обязательное, второе может быть пустым. Это некоторая защита от криворуких программистов, которые тупо забьют текст на своем языке.

Я всё же это вижу как registerHotkey(playback_hotkey, playback_hotkey_interface, tr("playback"));  Т.е. требования такие же как к локализации интерфейса.
А от паталогической криворукости абсолютной защиты, увы, не бывает.
Я плясал от desktop файла там пары Name и Name[ru], Description и Description[ru]. Там правда переводов может быть множество. Ладно, это не самое главное, добавить еще один параметр, и хранить его принципиально ничего не меняет. Вот с логикой перекрытия другое дело (см следующий пункт).
 


При регистрации возможен вариант конфликта, когда хоткей уже используется. В этом случае демон запоминает этот запрос, но не будет его дергать (хотя как альтернатива - можно выполнять несколько действий параллельно по одному хоткею).
Надо подумать, есть несколько вариантов (во всех примерах программа А уже зарегистрировала хоткей, теперь программа Б пытается его перерегистрировать)

Так как это центраизовано через демон - то он просто дернёт несколько клиентов - в моём экспериментальном прототипе вызов нескольких клиентов через dBus уже работает.
  1.  Хоткей вешается на Б, после закрытия Б, восстанавливается привязка к А. Так сейчас работают хоткеи в Х-ах. Наверное это предпочтительный вариант, по крайней мере поведение привычное.
  2.  Хоткей остается на А, после закрытия А, устанавливается привязка к Б.
  3. Тупо возвращаем false, и пусть программа сама разбирается. Мне этот вариант не нравиться - возникает куча вопросов:
    1. А если приложению, вот по зарез, нужно перерегистрировать хоткей. Что добавлять параметр "force"?
    2. Как приложение Б узнает, что А закрылось и можно по новой регистрировать хоткей?
  4. Параллельная работа, IMHO это странное поведение, и вызовет кучу не очевидных вопросов.
В общем мне нравиться первый вариант - он наиболее логичен. 

М-да... тут возможен разброд и шатания. Ибо я пока склонен к варианту 4.
Не знаю, не знаю. А если не нужно параллельное выполнение? Как будет это выглядеть, программа Б будет разрегистрировать А, а потом прописывать себя? А обратно кто будет вешать? И как это будет выглядеть в менеджере?

С другой стороны и в 1-ом варианте есть проблемы. Вот я ручками настроил хоткей, и запустил программу Б, а у нее по дефолту используется этот хоткей, и что мои настройки по боку? А во 2-ом обратная проблема, если работает Б, то как мне перерегистрировать хоткей из менеджера?
 
Возможно нужны 2 уровня настроек, ручные и автоматические. Давай подумаем.

 
Кроме того демон даёт специальный интерфейс для просмотра и редактирования зарегистрированных хоткеев. Будет специальная UI прога для сего. Через неё можно будет:
- посмотреть какие хоткеи к чему привязаны
- поменять(!) хоткеи (в этом случае демон должен через dbus и либу известить зареганную прогу о смене хоткея, чтоб, например, та у себя в UI его отобразила и в настройках сохранила)
- отменить хоткеи - по сути назначить <null>
Для отмены лучше сделать отдельные функции.

Не проблема.
 
 
- добавить кастомные хоткеи - которые будут просто делать запуск приложений (через эту плюшку можно также вызывать внешнюю dbus-send, а можно конечно вызов dbus методов оформить в демоне внутренне чтоб быстрее было).

Пока вижу две проблемы:
1. Есть клиент этой системы неожиданно падает - демон должен об этом узнать. Насколько я помню, для этого клиент должен зарегать dbus сервис, тогда dbus пошлет всем (и демону тоже) сигнал disconnected.
Если клиент " неожиданно падает", то он не может ничего послать. Я думаю можно проверять наличие ветки которую зарегистрировали

Обнаружение падения клиента уже тоже работает. 
  1. При нажатии клавиши
  2. При запросе "а зарегистрирована ли такая клавиша" 
  3. При запросе списка всех хоткеев.
  
2. Возможен конфликт с другими программами, которые не пользуются этой системой.

P.S. писать dbus интерфейс на чистом C или C++ дело, увы, муторное и запутанное. Qt в качестве прослойки рулит.
На Qt конечно удобнее, но судя по этому -http://www.matthew.ath.cx/misc/dbus и на сях не безумно сложно. Как ты думаешь, куда нас пошлют гномовцы если мы им предложим использовать сервер на Qt? А вся фишка от этого будет если сделать это стандартом.
В качестве прототипа Qt подходит, но потом придется переписывать без тулкита.

Согласен. Отработать алгоритм на Qt, потом портировать на чистый C (не С++) - чтоб и гномовцы радовались.
Гномовцам в принцепе по барабану, по сути для клиентов АПИ это dbus интерфейс. А если и писать биндинг для клиента, то это так, фишка для удобства не более. 
Т.е. в идеале есть стандарт на dbus интерфейс и эталонный сервер, без привязки к тулкитам и клиент дергающий dbus. Нно при желании можно использовать любой сервер, и приложение на любом тулките, главное чтоб их поведение совпадало со стандартом.




--
Best regards,
Alexander.

Kuzma Shapran

unread,
Jan 9, 2013, 2:59:37 PM1/9/13
to razor...@googlegroups.com


On Thursday, 10 January 2013 02:50:44 UTC+13, Александр Соколов wrote:


9 января 2013 г., 14:31 пользователь Kuzma Shapran <leaf.o...@gmail.com> написал:


On Wednesday, 9 January 2013 22:19:43 UTC+13, Александр Соколов wrote:
В целом правильно, но есть несколько замечаний.


вторник, 8 января 2013 г., 12:02:43 UTC+4 пользователь Kuzma Shapran написал:
Итак мысли вслух (в общем-то почти всё это уже здесь звучало):

Программа, которая желает использовать глобальные клавиши линкуется с библиотекой, которая есть суть прослойка на dbus. Кроме этого либа запускает демона, если тот еще не запущен (избавляет от необходимости запускать через сессию разора и не привязываемся к DE).
Нет, отдельный сервер нужен, и придется запускать его при старте. Ведь кроме биндинга dbus есть еще "хоткеи - которые будут просто делать запуск приложений", возможна ситуация что я  настроил хоткей на запуск калькулятора, других хоткеев нет. Тогда после рестарта, сервер не будет запущен, и мой хоткей не обработается.

Точно! Как-то упустил такой сценарий.



Демон регистрирует на себя горячие клавиши и при нажатии дергает метод интерфейса либы. Т.е. на каждую функцию (типа плэй или стоп для плэера) есть свой интерфейс на dbus`е.

При регистрации хоткея прога передаёт демону: string hotkey, string callback_interface_name, string localised_description
Два описания, одно на инглише, второе локализованное. Причем первое поле обязательное, второе может быть пустым. Это некоторая защита от криворуких программистов, которые тупо забьют текст на своем языке.

Я всё же это вижу как registerHotkey(playback_hotkey, playback_hotkey_interface, tr("playback"));  Т.е. требования такие же как к локализации интерфейса.
А от паталогической криворукости абсолютной защиты, увы, не бывает.
Я плясал от desktop файла там пары Name и Name[ru], Description и Description[ru]. Там правда переводов может быть множество. Ладно, это не самое главное, добавить еще один параметр, и хранить его принципиально ничего не меняет. Вот с логикой перекрытия другое дело (см следующий пункт).

В конце концов добавить или убрать ещё строку - алгоритма все
 
 


При регистрации возможен вариант конфликта, когда хоткей уже используется. В этом случае демон запоминает этот запрос, но не будет его дергать (хотя как альтернатива - можно выполнять несколько действий параллельно по одному хоткею).
Надо подумать, есть несколько вариантов (во всех примерах программа А уже зарегистрировала хоткей, теперь программа Б пытается его перерегистрировать)

Так как это центраизовано через демон - то он просто дернёт несколько клиентов - в моём экспериментальном прототипе вызов нескольких клиентов через dBus уже работает.
  1.  Хоткей вешается на Б, после закрытия Б, восстанавливается привязка к А. Так сейчас работают хоткеи в Х-ах. Наверное это предпочтительный вариант, по крайней мере поведение привычное.
  2.  Хоткей остается на А, после закрытия А, устанавливается привязка к Б.
  3. Тупо возвращаем false, и пусть программа сама разбирается. Мне этот вариант не нравиться - возникает куча вопросов:
    1. А если приложению, вот по зарез, нужно перерегистрировать хоткей. Что добавлять параметр "force"?
    2. Как приложение Б узнает, что А закрылось и можно по новой регистрировать хоткей?
  4. Параллельная работа, IMHO это странное поведение, и вызовет кучу не очевидных вопросов.
В общем мне нравиться первый вариант - он наиболее логичен. 

М-да... тут возможен разброд и шатания. Ибо я пока склонен к варианту 4.
Не знаю, не знаю. А если не нужно параллельное выполнение? Как будет это выглядеть, программа Б будет разрегистрировать А, а потом прописывать себя? А обратно кто будет вешать? И как это будет выглядеть в менеджере?

С другой стороны и в 1-ом варианте есть проблемы. Вот я ручками настроил хоткей, и запустил программу Б, а у нее по дефолту используется этот хоткей, и что мои настройки по боку? А во 2-ом обратная проблема, если работает Б, то как мне перерегистрировать хоткей из менеджера?

Вот для этого случая есть возможность изменить настройки со стороны демона.
Т.е. где-то так:
1. прога А регит Alt-F1 на себя (действие help)
2. прога Б регит Alt-F1 на себя
3. юзер нажимает Alt-F1 и обе проги реагируют
4. юзер офигевает и желает изменить ситуацию в корне
5. юзер открывает гуй от демона и видит в табличке две привязки на Alt-F1
6. юзер меняет привязку проги А с Alt-F1 на Alt-F2
7. демон шлёт уведомление в прогу А, что её хоткей на действие help теперь будет привязан к Alt-F2
8. прога А сохраняет новый хоткей в своём конфиге и меняет, к примеру, текст в пункте меню
9. юзер проверяет новые привязки и остаётся доволен
10. юзер перезапускает прогу А
11. прога А при запуске вычитывает из конфига хоткей Alt-F2 на действие и регает его у демона.
12. конфликта нет, юзер всё ещё доволен

Кстати! только что вспомнил где есть множественные привязки к клавишам - QtCreator. Он просто подсвечивает их красным, правда в случае конфликта он вообще ничего не делает :-(
  
Возможно нужны 2 уровня настроек, ручные и автоматические. Давай подумаем.

 
Кроме того демон даёт специальный интерфейс для просмотра и редактирования зарегистрированных хоткеев. Будет специальная UI прога для сего. Через неё можно будет:
- посмотреть какие хоткеи к чему привязаны
- поменять(!) хоткеи (в этом случае демон должен через dbus и либу известить зареганную прогу о смене хоткея, чтоб, например, та у себя в UI его отобразила и в настройках сохранила)
- отменить хоткеи - по сути назначить <null>
Для отмены лучше сделать отдельные функции.

Не проблема.
 
 
- добавить кастомные хоткеи - которые будут просто делать запуск приложений (через эту плюшку можно также вызывать внешнюю dbus-send, а можно конечно вызов dbus методов оформить в демоне внутренне чтоб быстрее было).

Пока вижу две проблемы:
1. Есть клиент этой системы неожиданно падает - демон должен об этом узнать. Насколько я помню, для этого клиент должен зарегать dbus сервис, тогда dbus пошлет всем (и демону тоже) сигнал disconnected.
Если клиент " неожиданно падает", то он не может ничего послать. Я думаю можно проверять наличие ветки которую зарегистрировали

Обнаружение падения клиента уже тоже работает. 
  1. При нажатии клавиши
  2. При запросе "а зарегистрирована ли такая клавиша" 
  3. При запросе списка всех хоткеев.
  
2. Возможен конфликт с другими программами, которые не пользуются этой системой.

P.S. писать dbus интерфейс на чистом C или C++ дело, увы, муторное и запутанное. Qt в качестве прослойки рулит.
На Qt конечно удобнее, но судя по этому -http://www.matthew.ath.cx/misc/dbus и на сях не безумно сложно. Как ты думаешь, куда нас пошлют гномовцы если мы им предложим использовать сервер на Qt? А вся фишка от этого будет если сделать это стандартом.
В качестве прототипа Qt подходит, но потом придется переписывать без тулкита.

Согласен. Отработать алгоритм на Qt, потом портировать на чистый C (не С++) - чтоб и гномовцы радовались.
Гномовцам в принцепе по барабану, по сути для клиентов АПИ это dbus интерфейс. А если и писать биндинг для клиента, то это так, фишка для удобства не более. 
Т.е. в идеале есть стандарт на dbus интерфейс и эталонный сервер, без привязки к тулкитам и клиент дергающий dbus. Нно при желании можно использовать любой сервер, и приложение на любом тулките, главное чтоб их поведение совпадало со стандартом.

Написать стандарт это конечно хорошо, но вот к примеру есть стандарт C++11, но, увы, он местами только на бумаге.
Я посмотрю как там дружба у dBus`а и чистого C и если всё не очень страшно - напишу демон и либу на C с минимумом завиимостей от других либ.
 




--
Best regards,
Alexander.

Kuzma Shapran

unread,
Jan 9, 2013, 3:00:52 PM1/9/13
to razor...@googlegroups.com
случайно зацепил кнопку "Post"

вместо "В конце концов добавить или убрать ещё строку - алгоритма все" читать:
"В конце концов добавить или убрать ещё строку - алгоритма всей схемы это не поменяет"

TI_Eugene

unread,
Jan 9, 2013, 10:47:51 PM1/9/13
to Razor-qt ru
Что-то как-то сильно хиитро...
И вот это вот "пользователь офигевает" не нравится.
Не надо пользователю офигевать

> ...
>
> продолжение >>

Kuzma Shapran

unread,
Jan 10, 2013, 5:33:47 AM1/10/13
to razor...@googlegroups.com
Можно сделать это поведение управляемым через опции демона. Что-то типа:
--multiple-hotkeys=< first | last | all >

Где `first` значит: вызывать событие той проги, которая первая зарегала хоткей. Если она закрылась - следующей в списке. В общем, FIFO, т.е. очередь.
В варианте `last` - последняя зареганная прога имеет преимущество - это LIFO, он же стэк.
И, наконец, `all` - все проги равноправные.

С дефолтным `first` или `last`, поскольку, я вижу, только мне одному нравится `all`.

Александр Соколов

unread,
Jan 10, 2013, 5:51:42 AM1/10/13
to razor...@googlegroups.com
Я то же считаю, что алгоритм работы должен быть прзрачным и очевидным.
Ты какой алгоритм предлагаешь?

10 января 2013 г., 7:47 пользователь TI_Eugene <ti.e...@gmail.com> написал:

Что-то как-то сильно хиитро...
И вот это вот "пользователь офигевает" не нравится.
Не надо пользователю офигевать



--
Best regards,
Alexander.

TI_Eugene

unread,
Jan 10, 2013, 6:54:22 AM1/10/13
to Razor-qt ru
Если речь о _глобальных_ хоткеях - то надо просто запрещать приложению
назначать занятый хоткей.
Ну и видеть список занятых хоткеев.
Дальше юзверь пусть сам разруливает - или в текущем прилоожении
(которое заняло откей) - или в новом.

On 10 янв, 14:51, Александр Соколов <sokolof...@gmail.com> wrote:
> Я то же считаю, что алгоритм работы должен быть прзрачным и очевидным.
> Ты какой алгоритм предлагаешь?
>

> 10 января 2013 г., 7:47 пользователь TI_Eugene <ti.eug...@gmail.com>написал:

Kuzma Shapran

unread,
Jan 11, 2013, 3:37:00 AM1/11/13
to razor...@googlegroups.com


On Friday, 11 January 2013 00:54:22 UTC+13, TI_Eugene wrote:
Если речь о _глобальных_ хоткеях - то надо просто запрещать приложению
назначать занятый хоткей.

Т.е. first
 
Ну и видеть список занятых хоткеев.
Дальше юзверь пусть сам разруливает - или в текущем прилоожении
(которое заняло откей) - или в новом.

На текущий момент в прототипе я добился:
* подключение клиентов к демону;
* обнаружение исчезновения клиента (завершение программы или падение - неважно) - демон освобождает занятые хоткеи;
* обнаружение исчезновения демона - клиенты ждут появления нового демона и регистрируются заново.
* переключение поведения first/last/all в демоне на лету.

Однако, если демон был перезапущен, то есть шанс, что клиенты подключатся в другом порядке и если был включени режим first или last, то хоткей может уйти в другую прогу, не ту, что реагировала на хоткей до перезагрузки демона.

Если в случае конфликтов ручками в UI демона выбирать прогу, которую дёргать, то это опять же до перезапуска демона…

Kuzma Shapran

unread,
Jan 11, 2013, 3:39:29 AM1/11/13
to razor...@googlegroups.com
Кстати, а как дружить с KGlobalAccel и что там в гноме?

Теоретически, можно скопировать и продублировать API от KGlobalAccel и держать всё в одном демоне… но сами понимаете это гораздо бОльший кусок работы…

Kuzma Shapran

unread,
Feb 15, 2013, 10:33:17 PM2/15/13
to razor...@googlegroups.com
Процесс идёт, контора пишет.

Итак, что имеется на сегодня:
1. Отлаженный демон, который писан на чистом C++, но(!) у него есть одна проблема с асинхронностью.
  Посему:
  а) Я портирую демона на QtDBus
  б) Позже допишу собственный C++ dbus-wrapper и портирую демон и на него - будет эталонный демон не привязанный к DE

Почему собственный dbus-wrapper?
Потому что из существующих решений:
* C dbus - это мучение.
* dbus-c++ - используется сейчас, но у него проблемы с асинхронностью и он не компилит dbus properties clang`ом. Кроме того пришлось вставлять костыли после генерации xml->cpp чтобы знать отправителя сообщения. Костыли писаны на Perl, втаскивать Perl в Razor как зависимость не хочется.
* dbus-cxx - не даёт отправителя сообщения и нет возможности прикрутить костыли.
* QtDBus - хорош всем, но не годится для эталонного демона.
* И наконец glib-dbus (или как там его) - идеологически не верный путь ;-)

Начат GUI для управления всей кухней.
И останется сделать только либу, для использования в модулях Razor`а.

Uno

unread,
Feb 16, 2013, 6:32:20 AM2/16/13
to razor...@googlegroups.com
хорошая новость! :) 
ждем с нетерпением ;)


16 февраля 2013 г., 14:33 пользователь Kuzma Shapran <leaf.o...@gmail.com> написал:

--
Вы получили это сообщение, поскольку подписаны на группу Razor-qt ru.
 
Чтобы отказаться от подписки на эту группу и перестать получать из нее сообщения, отправьте электронное письмо на адрес razor-qt-ru...@googlegroups.com.
Подробнее о функциях можно узнать на странице https://groups.google.com/groups/opt_out.
 
 

Александр Соколов

unread,
Feb 16, 2013, 11:58:22 AM2/16/13
to razor...@googlegroups.com
Я тут размышлял про GUI для настройки привязок. Сейчас получается, что только запущенные программы просят регистрировать хоткеи, соответственно и пользователь у видит только клавиши для запущенных программ. Еще хуже, что настройки будут отличаться в зависимости от того, что в данный момент запущено. Я когда писал бумагу, почитал про автозапуск программ через DBus (http://techbase.kde.org/Development/Tutorials/D-Bus/Autostart_Services http://raphael.slinckx.net/blog/documents/dbus-tutorial) Так вот идея такая, каждая программа устанавливает свой .desktop файл с описанием своих хоткеекв. Что-то вроде:
/usr/share/hotkeys
[D-BUS Hotkeys]
Name=Clementine
GenericName=Clementine Music Player
GenericName[ru]=Музыкальный проигрывателеь Clementine
Comment=Plays music and last.fm streams
Comment[ru]=Играет музыку и потоки с last.fm

[MediaPlay]
GenericName=Start Clementine
GenericName[ru]=Запустить Clementine
Command=D-Bus команда

[MediaNext]
GenericName=Next track Clementine
GenericName[ru]=Запустить Clementine
Command=D-Bus команда
Depends=MediaPlay

[MediaPrevious]
...

Может быть несколько претендентов на клавишу, скажем clementine и vlc. Когда пользователь запустит управлялку хоткеями, он увидит несколько альтернатив для клавиши Play, и сможет выбрать ту программу которую он хочет запускать при нажатии мультимедийной клавиши. А если он хочет, то сможет настроить еще одну, скажем если он оставил просто MediaPlay для clementine, то VLC он может назначить Ctrl+MediaPlay, причем ему не надо вбивать команду руками, он может выбрать ее из списка который построиться на базе этих файлов.

Есть пара вещей, которые не до конца еще не ясны.
  1. Дефолтные приоритеты, проблема очень похожа на приоритеты для mime. Удачного решения для маймов нет, KDE для использует поле InitialPreference в desktop файле, gnome использует отдельный файл в котором перечислены все программы. Оба решения не идеальны, но гномовское вообще отстой. Если ничего лучше не придумаем можно использовать InitialPreference в наших файлах.
  2. Некоторые клавиши не имеют смысла без других, так глупо иметь MediaNext привязанным к vlc, если MediaPlay привязана к clementine. Я добавил поле Depends, т.е. они должны как то быть согласованы, но точно логику я пока не представляю, давайте все вместе думу думать.

Я не знаю насколько мое предложение ломает твои наработки, уж извини. 

Ну, что народ скажет?

-- 
Best regards,
Alexander.

Kuzma Shapran

unread,
Feb 17, 2013, 3:32:31 PM2/17/13
to razor...@googlegroups.com
Сейчас есть 3 типа хоткеев:
1). Родные от программ, которые пользуются либой - они, в общем, динамичные. Когда хоткей изменен из общего GUI, демон отсылает уведомление проге. Изначальная регистрация идёт от проги.
2). Созданные пользователем для запуска программ и аналогичные
3). Созданные пользователем для дерганья любых функций на DBus с сигнатурой void function(void); (в будущем - любые аргументы, ну или хотя бы простые типы кроме массивов, структур и словарей)

Проще всего допилить сюда:
Когда к демону коннектится нативный клиент (пункт 1 выше) то все его хоткеи запоминаются и позже, когда клиента отсутствует, демон всёё равно помнит его хоткеи, но они рисуются в GUI как не активные.
Как различать что это тот же самый клиент? Есть как минимум 2 решения:
1). Если прога использует на DBus`е кастомное имя сервиса - использовать его и хоткеи этого клиента будут запомнены, иначе - это одноразовый клиент.
2). Более гибкое решение - при коннекте к демону клиент сообщает своё уникальное имя и описание:
void registerClient(string uniqueName, string humanReadableDescription)
если клиент не зарегался - это опять же клиент на один коннект, его хоткеи не останутся видимыми в GUI после исчезновения клиента.
Почему решение №2 лучше - потому что кастомное имя сервиса может использоваться для других целей. А здесь всё чётко и логично, никаких двойных смыслов.

Что касается примера с Clemetine и VLC - они оба не родные, и вряд ли когда станут. Родные клиенты - это в первую очередь модули Razor`а, позже - проги заточенные под Razor, но это пока далёкое и светлое будущее.
Итак, 2 неродных клиента (тип 3 из самого первого списка наверху) желают привязаться к один и тем же хоткеям:
Обычно люди не пользуются одновременно несколькими плэерами, а если пользуются, то аудио плэер на паузе пока чел смотрит видео. Это значит что если оба присутствуют, то видео плэер в приоритете. Решение простое:
Регим нужные клавишы на обоих, ставя VLC выше по списку и убеждаемся что в случае конфликтных хоткеев демон будет дергать только первого присутствующего.
Что имеем: Юзер нажал Media_Play
Если нет ни VLC, ни Clementine - ничего не происходит. логично
Если нет VLC, но есть Clementine - демон пытается дернуть VLC, но такого на DBus`е нет, пробует Clementine - и о чудо это срабатывает.
Если есть VLC - демону удается дернуть его и дальше он ничего не пытается делать.
Можно даже пойти дальше и третьим действием добавить запуск Clementine. Т.е. когда нет ни VLC, ни Clementine, то запускается Clementine.

Короче всё решается порядком в котором хоткеи зареганы и режимом демона - по умолчанию он идёт по списку сверху вниз до первого срабатывания. (тип 2 из списка наверху срабатывает всегда - я не думаю, то стоит возиться и проверять код выхода, или что если прога всё ещё работает через секунду после запуска.)
Порядок привязок сохраняется при перезагрузке. Нативные клиенты односеансовики могут приконнектиться только после вычитки конфига, а потому имеют низший приоритет.

Kuzma Shapran

unread,
Feb 17, 2013, 3:41:01 PM2/17/13
to razor...@googlegroups.com
Позже можно будет добавить в GUI выбор проги для запуска из глобального меню программ - примерно как в KDE работает open with ...
Reply all
Reply to author
Forward
0 new messages