05 декабря, 2006

Расширяя горизонты

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

Из одной из моих предыдущих заметок неявно следует, что описанные в ней так называемые "scratch-приложения" являются по определению однооконными. И в самом деле, если Вы попробуете в полной мере применить описанную методику к любому многоконному приложению (например, таковыми является большинство jabber-клиентов, в т.ч. gaim и gajim, на примере которых я и буду далее рассуждать), то Вы сразу столкнётесь с проблемой организации его многочисленных окон внутри scratchpad-а. И именно решение этой проблемы я Вам сейчас поведаю. Но сначала отвлечёмся на минуту-другую от линии повествования и посмотрим, как это выглядит в случае, если никаких усилий на этот счёт не прилагать:

  • Либо так: Скриншот 1 - окно со списком контактов находится в одной куче с окнами открытых бесед, что может быть не слишком-то и неудобно (сам так жил долгое время и не сказать чтоб сильно мучался), но уж точно неконцептуально :) А главное - показательный пример для описываемого далее подхода.
  • Либо так: Скриншот 2 - расположение видимо удобно автору, но реализовано оно, как видите, не в scratchpad-е.
  • И третий вариант (скриншот для которого мне не удалось подыскать, да и нет в нём особой необходимости) - ограничить себя любимого использованием исключительно однооконных приложений для некоторых задач, в частности использовать для обмена мгновенными сообщениями centericq.
Если Вам не досуг было вдаваться в технические подробности, то поясню, что scratchpad в Ion3 - лишь специфический фрейм (WFrame), т.е. сущность фактически неделимая. Открыть несколько окон в одном фрейме, безусловно, можно, но только как перекрывающиеся. А вот разделить этот фрейм на несколько других с целью более комфортного расположения окон - уже не удастся. Многие читатели, думаю, чисто интуитивно уже догадались, что для решения этой проблемы нужно всего лишь "превратить" наш фрейм в полноценное рабочее пространство, гибкое до бесконечности. Ну, я всё же не волшебник, да и учиться на него пока не планировал, поэтому "превратить" вряд ли получится. Но вот засунуть одно в другое - это всегда пожалуйста. И Ion3 не был бы самим собой, если бы не позволял этого сделать:

_:attach_new({type="WTiling", name="Instant Messaging"}):goto()

Выполняем внутри соответствующего scratchpad-а это несложное Lua-выражение и получаем полноценное рабочее пространство, которое можно поделить так, как бог на душу положит. Полученные в результате деления фреймы именуем так, как того требует внутренний голос и получаем то, во что можно начинать "раскладывать" окна. В моём случае это выглядит примерно так:


Левый фрейм был назван im_sp_conversation,а правый - im_sp_roster. Думаю, названия говорят сами за себя (расшифрую разве что im - instant messaging и sp - scratchpad) и дополнительный пояснений не требуют. Далее, делаем соответствующие настройки для окон (приведу их как для gaim, так и для gajim - авось кому пригодится):

-- Gajim
--
defwinprop {
class = 'Gajim.py',
instance = 'gajim.py',
role = 'roster',
target = 'im_sp_roster',
winlist_ignore = true,
}

defwinprop {
class = 'Gajim.py',
instance = 'gajim.py',
target = 'im_sp_conversation',
jumpto = true,
winlist_ignore = true,
}

-- Gaim
--
defwinprop {
class = 'Gaim',
instance = 'gaim',
role = 'buddy_list',
target = 'im_sp_roster',
winlist_ignore = true,
}

defwinprop {
class = 'Gaim',
instance = 'gaim',
target = 'im_sp_conversation',
jumpto = true,
winlist_ignore = true,
}


Готово! Получите, распишитесь. Спасибо за внимание. Пора работать.

PS: Я также приводил тут небольшой рецепт, который позволяет закрывать одним универсальным сочетанием клавиш любой активный scratchpad. По объективным причинам данный рецепт не будет работать, если вышеописанным образом породить внутри scratchpad-а другие фреймы.

23 ноября, 2006

От статики к динамике

В целом описав общую картину на моём рабочем месте, я хочу перейти к одной из многочисленных частностей, а именно - к использованию растрового графического редактора GIMP в связке с оконным менеджером Ion3. Интересная деталь - если со многими приложениями приходится буквально "бороться" средствами менеджера окон, чтобы ими было удобно пользоваться, то GIMP, кажется, просто создан для того, чтобы им управлял толковый WM. Эту парочку стоит рассматривать только как взаимовыгодный союз, но не как "ведущего и ведомого".

Во-первых, следует отметить, что основу описываемого мной метода составляет вполне конкретная техническая возможность конкретного менеджера окон (Ion3) - floating split. Где про него почитать я не знаю, но попробовать методом тыка может каждый. Было бы желание. Заранее предупреждаю, что описания того что это такое и как этим пользоваться вы здесь не обнаружите. Речь будет только о конкретном применении.

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

Итак, начнём с главного. С выделения рабочего пространства для GIMP и разбиения его следующим образом:


-----------------------------
| | | |
| 1 | | 4 |
| | | |
|-----| 3 |-----|
| | | |
| 2 | | 5 |
| | | |
-----------------------------

Теперь необходимо задать каждому из пяти получившихся фреймов собственное имя и распределить по фреймам различные окна GIMP. В частности, основную панель инструментов логично разместить во фрейме 1, окно "слои, каналы, ..." - во 2-м. Фреймы 4 и 5 у меня отведены под наиболее часто используемые инструменты (в частности фрейм 4 - это только инструмент кадрирования).

Теперь перейдём к самому главному.
Через контекстное меню фрейма 3 (пункты tiling/float-split/at-left и tiling/float-split/at-right), необходимо сделать левую и правую границы этого фрейма "плавающими". Далее необходимо установить размеры фрейма 3. В этом фрейме у нас будут открываться окна с редактируемыми изображениями, а это означает, что размеры данного фрейма желательно сделать максимально возможными. В данном случае высота фрейма сама по себе максимальна, но только потому, что лично мне хватает двух фреймов для частоиспользуемых инструментов GIMP. Если же у Вас таких инструментов больше - правильным будет расположить их выше и ниже фрейма 3 (по аналогичной технологии). Но это можно сделать чуть позже, пока лучше ограничиться той разметкой, что приведена на схеме. А вот ширину фрейма "3" нужно установить чуть меньше, чем ширина рабочего пространства, а именно - на 5-10 пикселей меньше (как слева, так и справа). При этом, если Вы всё делали правильно, у вас будут почти полностью перекрыты фреймы 1, 2, 4 и 5. Заметьте - они будут перекрыты, но их размеры останутся прежними. И изменение их размеров никак не повлияет на изменение размеров фрейма 3.

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

mod_tiling.set (
{ raise_delay = 0 }
)

Вуаля. Стоит Вам перевести указатель мыши из фрейма с картинкой (фрейм 3) к левой границе экрана - и вы мгновенно окажетесь в окне с инструментами. А как только переведёте "стрелочку" обратно на картинку - она вновь "развернётся" на всю ширину экрана. Кроме того. Вспомните, как "удобно" было пользоваться инструментом кадрирования в каком-нибудь "традиционном" WM. Стоило Вам начать выделение области изображения - откуда ни возьмись вылезало окно, буквально закрывавшее немалую часть изображения, с которым Вы работаете. Бесились? Я тоже. Так укажите этому окну открываться в 4-м фрейме и оно больше никогда не будет Вам мешать, а перейти к нему Вы сможете в любой момент, стоит вам только сдвинуть указатель мыши к правой границе рабочего пространства.

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

А напоследок, обещанные скриншоты (порядок их следования примерно соответствует линии повествования, вроде бы):



Немного идеологии

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

Кстати, об идеале. Когда-то, не так давно, у меня возникло желание написать небольшую (а может даже и не небольшую) статью о том, что же такое в моём понимании "идеальное рабочее место" (разумеется, речь о desktop-окружении моего компьютера) и параллельно поведать о том, как его построить с использованием конкретного набора программных средств (взяв за основу некоторый менеджер окон). Помимо лени, о которой далее, меня долгое время останавливал один единственный, но архиважный факт - ни один из существующих WM не способен был в полной мере стать основой такого вот, если хотите, своеобразного исследования. В какой-то момент таковым чуть не стал PekWM, но не вдаваясь в излишние подробности просто скажу, что и он при ближайшем рассмотрении оказался далёк от искомого. И наконец, после кое-каких скитаний (очередных) я вернулся к любимому и ненаглядному Ion3, потратил некоторое время на доработку конфигов и, вуаля, - получил то, на основе чего уже можно говорить о прямой дороге к идеалу. Впрочем, оставалось ещё одно препятствие - обычная человеческая лень вкупе с тотальной нехваткой свободного времени. Субъективизм и объективность тут слились в какой-то прямо-таки идеальный союз. Но всё же что-то (надо на досуге поразмыслить - а что же именно?) сподвигло меня на попытку сдвинуть дело с мёртвой точки. Писать сразу, с ходу, полноценную статью пока, я думаю, не стоит. А потому, буду потихоньку, шаг за шагом, "раскрывать тему" в кратких заметках по отдельным аспектам (как "идеологическим", так и чисто техническим) на вышеобозначенную тему. Началом этого своеобразного цикла смело можно считать предыдущую заметку.

Итак, обозначим исходную. Я для себя (невольно, как-то само по себе так получилось) разделил используемые приложения на два "класса": те, сеанс работы с которыми (в т.ч. с несколькими из них параллельно) можно считать относительно длительным (например: IDE, графический редактор, браузер) и те, которые играют скорее "обслуживающую" роль и работу с которыми даже сеансом-то назвать трудно, например: словарь, калькулятор, jabber-клиент, музыкальный плеер. Все нюансы подобного деления мне даже сложно чётко сформулировать. Надеюсь, они постепенно проявятся в дальнейшем. А вот какие-никакие имена этим двум классам дать придётся. Первые обзовём бизнес-приложениями. А вторые, с моей лёгкой руки, scratch-applications. Вот только не могу придумать как это по-русски.

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

Что касается бизнес-приложений, то на каждую группу таких приложений выделяется отдельный workspace (рабочее пространство). При таком подходе рабочих пространств у меня набралось 6 штук. При том, что пределом считаю число 10, если получается больше - надо с этим что-то делать. Примером такой группы может быть следующая связка: IDE + терминал для сборки + утилита тестирования + терминал с логами; а иногда группа определяется множеством окон всего одного приложения, например Gimp. В этом случае основным инструментом переключения между "задачами" является переключение между рабочими пространствами, число которых невелико, редко изменяемо, а оттого их нумерацию легко запомнить. При этом хотелось бы подчеркнуть, что переключение происходит не между конкретными приложениями, а между "задачами" или, можно сказать, "деятельностями". Нет смысла переключения на окно IDE, есть только смысл вернуться от написания текста документа к "процессу разработки", причём вернуться в то место (читай - на то окно), на котором процесс был прерван. Таким образом, переключение между рабочими пространствами, а не окнами - это даже не просто средство тупой группировки, в которой чуть проще разобраться, а полноценный инструмент рациональной организации рабочего места.

Теперь о scratch-applications. Суть использования такого рода приложений состоит в том, что пользователь в процессе выполнения основной своей деятельности на рабочем месте (например, программирования) отвлекается на сравнительно короткое время на использование такого приложения (самый яркий пример в данном случае - jabber-клиент). А быстренько "воспользовавшись" - возвращается к основной своей деятельности. Согласитесь, если принять к использованию вышеописанную "идеологию" использования рабочих пространств, то:

  • выделять ещё одно рабочее пространство под ваш jabber-клиент (либо под все scratch-applications в целом) не логично, так как противоречит идее "деятельность рабочее пространство"
  • даже если выделить таковое пространство, то сам факт переключения на него означает "уход" с того рабочего пространства, на котором в данный момент выполняется основная бизнес-деятельность, что также не выглядит логичным
  • бизнес-приложения как правило используются таким образом, чтобы занимать максимальную область рабочего пространства (часто всю доступную область) и поэтому использование традиционных рабочих пространств Ion3 - WTiling - выглядит вполне логичным, в то время как scratch-applications часто не нуждаются в таких размерах окна (вспомните размеры своего словаря или калькулятора и вы со мной согласитесь).
Исходя из этих трёх утверждений получается, что необходимо некоторое специфическое средство управления окнами таких приложений. Но какое? К счастью, в Ion3 оно есть и называется scratchpad. С использованием дополнительного скрипта (toggle_named_scratchpad.lua) таких scratchpad-ов можно сделать произвольное количество и дав каждому соответствующее наименование. И используя наименования распределить по scratchpad-ам все свои scratch-applications. Есть некоторая свобода при распределении приложений по scratchpad-ам, в отличие от ситуации с распределением бизнес-приложений по рабочим пространствам. Связано это с тем, что для перехода к этого рода приложения мы будем использовать принципиально иной способ, о котором чуть позже. К примеру, у меня есть отдельный scratchpad для e-mail-клиента, но htop и conky прекрасно уживаются на одном и том же.

Так что же это за "принципиально иной" способ? Суть в том, что в данном случае целью является не некоторая абстрактная "задача", на которую мы переключаемся путём перехода на соответствующее рабочее пространство, а окно конкретного приложения, имеющее заранее известные характеристики (такие как class, instance и title). И необходимый нам механизм должен был бы искать открытое окно по соответствующим характеристикам и активировать его, а в случае его отсутствия - запускать соответствующее приложение. А раз уж есть возможность перехода к приложению для его кратковременного использования, необходима и функция "возврата к бизнес-деятельности", от которой пользователь только что отвлёкся. И такой механизм также имеется - скрипт app.lua (подробности использования этого скрипта Вы можете найти непосредственно в комментариях к нему), также доступный на сайте Ion3. А пример использования данного скрипта в соответствии с вышеизложенными идеями и подходами, а также простейший способ реализации функции "возврата" (путём закрытия активного scratchpad-а) можно посмотреть в моей предыдущей заметке, где Вы также найдёте пару советов, которые могут оказаться крайне полезными, если Вы решите опробовать описанный мною подход на практике.

21 ноября, 2006

Небольшое ноухау для ion3

Подумалось... Надо бы заметки и покороче писать. Не всё ж полноценные статьи строчить.



Приступим.

Вводная такова: на рабочем месте я использую оконный менеджер Ion3. Начну с того, что для перехода к нужным мне приложениям (например к любимому словарику) я с большим удовольствием использую замечательный скрипт app.lua из коллекции вкусностей для Ion3 (тем паче, что сегодня утром благодаря моим небольшим усилиям он стал ещё лучше и функциональнее, надеюсь на скорое появление патча в репозитории). И использование это выражается в keybinding-ах примерно следующего характера:

defbindings("WMPlex.toplevel", {

kpress(ALTMETA.."D",

"app.byclass('stardict', 'Stardict', _)"),

})



Ну а с помошью следующего фрагмента конфига:

defwinprop {

class = 'Stardict',

instance = 'stardict',

target = 'tools_sp',

jumpto = true,

winlist_ignore = true,

}



запускаемый словарик самостоятельно отправляется при запуске на "своё место". Многие уже догадались по предыдущему фрагменту конфига, что "местом" для данного приложения, как и для многих других, является соответствующий named scratchpad. Но есть проблема - всяческих скратчпадов у меня 5 штук (и не факт, что это конечное их число). И разумеется, я постоянно путаюсь, какой же кнопкой закрывается тот скратчпад, который у меня сейчас активен. Сегодня утром мне это надоело. И был придуман следующий keybinding:

defbindings("WMFrame", {

kpress( META.."Escape",

"mod_sp.set_shown(

ioncore.lookup_region(_:name(), 'WFrame'),

'unset' )" ),

})



Этот несложный биндинг "прячет" любой активный скратчпад. Вероятно, он может иметь побочный эффект при использовании его "не по назначению", но сей факт меня, честно сказать, не сильно беспокоит.



Кроме того, поделюсь ещё одной маленькой полезностью, связанной также с использованием большого количества скратчпадов. Сложность состоит в том, что они перекрывают друг друга не в порядке открытия. То есть, если у вас открыт скратчпад со словарём, а в этот момент вы открываете скратчпад с jabber-клиентом, то он вполне может оказаться "под" словариком. Или наоборот... в общем, ситуации всякие бывают, учитывая многообразие геометрий скратчпадов (во всяком случае у меня). И пришлось озадачиться поиском функций, которые позволили бы управлять "слоями" или даже "наслоениями" скратчпадов. Таковые были найдены, "забиндены" и сейчас будут представлены Вашему вниманию:

defbindings("WMFrame", {

kpress( META.."L",

"WRegion.rqorder(_, 'back')" ),

kpress( META.."U",

"WRegion.rqorder(_, 'front')" ),

})



Как несложно догадаться, нажатие Meta+L отправляет активный скратчпад "под" все остальные, а Meta+U "поднимает" его над всеми другими.



PS: вышеупомянутый скрипт app.lua отныне может искать запущенное приложение не только по строке заголовка или Window-class, но также и по атрибуту Window-instance, что особенно полезно в некоторых случаях. Каких? Об этом читайте в следующей заметке.