portrait

Поиск



[software] [catdoc] [tcl] [geography] [old things]

True Unix GUI 2.0

Когда-то давно я написал статью True Unix GUI по поводу того, как же должен быть устроен интерфейс пользователя для того, чтобы сохранить все достоинства командной строки Unix, но при этом максимально поддержать решение тех задач, которые стоят перед современным пользователем.

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

Сейчас попробую решить более простую задачу - описать, как может быть устроена консистентная по интерфейсу система приложений для unix, лишенная основных недостатков существующих desktop environments - нестабильности, сложности в программировании etc.

Бэкграунд

Чего хочет от интерфейса компьютерной системы пользователь? Насколько я понимаю, прежде всего он хочет, чтобы его не заставляли думать. Если какие-то действия повторяются достаточно часто, чтобы они превратились в пальцевые привычки, например, открытие файла через стандартный диалог, или клик правой кнопкой, они должны работать независимо от того, с каким приложением пользователь сейчас работает. То есть интерфейс должен быть консистентным. И хотим мы этого или нет, эти привычки сформированы в рамках CUA-парадигмы интерфейса

Сейчас это в основном достигается путем убирания этих функций в развесистые библиотеки интерфейсных тулкитов.

Тулкиты получаются большими, API развесистыми, развитие приводит к нарушению обратной совместимости и т.д. Более-менее приличных результатов на этом пути удается добиться только большим коммерческим фирмам вроде Apple и Microsoft, которые могут себе позволить затраты на Q&A, превышающие затраты на разработку, могут выставлять жесткие требования к 3-rd party разработчикам и т.д. И все равно получается плохо.

В мире OpenSource все еще хуже. Нельзя заставить независимого разработчика соблюдать HIG, если этот HIG ему не нравится.

Независимые разработчики, это как правило, люди с более сложными привычками, чем простые пользователи. Серьезного разработчика не устроит в качестве редактора pico или mcedit - ему подавай vim или emacs с совершенно ужасными для простого пользователя клавишными командами. Зато мощный и удобный для пользователя привычного.

Еще хорошему разработчику нужно понимать, что делает тот кусок софта, который он разрабатывает. А когда этот кусок софта зависит от кучи библиотек, да эти библиотеки по собственной инициативе плодят потоки выполнения, да взаимодействуют не слишком документированным образом с прочими компонентами системы, картину мира приходится ограничивать искусственно. В результате возникают такие вещи как "я тут нашел замечательный framework, я правда в нем нифига не разобрался, но смотрите как здорово получилось". Для меня подобное заявление разработчика - однозначный show-stopper. Использовать такую программу нельзя. Но других-то нет. Писать надежные программы почти что разучились. А пользователь хочет фич.

По-моему, в конце первого десятилетия XXI века стремление ко множеству фич - атавизм, подбный неконтролируемой любви некоторых приматов к соли. Прошли давно те времена, когда в типичном местообитании приматов соли был дефицит. Её давно уже научились добывать и из моря, и из земли в любых требуемых количествах. Но вот отвыкнуть солить все подряд мы не можем. Биология так быстро не перестраивается

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

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

Надо как-то эту ситуацию менять

Требования

  1. Максимальная независимость всех компонент. С одной стороны должна быть возможность обработать практически любую ошибку и не потерять пользовательских данных, с другой - если мне не нравится диалог открытия файлов, я должен иметь возможность заменить его на более другой (благо в дистрибутиве их полно разных) без перекомпиляции (и тем более, переписывания) всех программ, которыми я пользуюсь.
  2. Наличие одного решения для каждой задачи. Если посмотреть сколько реализаций протокола HTTP есть в типичной пользовательской системе - можно прийти в ужас. Нет, я не против того, чтобы в дистрибутиве были несколько реализаций, чтобы я мог выбрать наиболее меня устраивающую, или даже установленных одновременно, чтобы выбирать можно было в момент использования. Но вот нет - та или иная реализация намертво встроена в каждую программу или библиотеку языка программирования.
  3. Возможность писать на любом языке программирования. Современный подход приводит к тому, что большая часть функциональности реализована в виде стандартных библиотек с интерфейсом языка C или C++. Встроить эти библиотеки в более высокоуровневый язык не всегда тривиально, особенно если речь идет о языке, уже имеющем свои представления о цикле обработки событий и менеджмете памяти.
  4. Сетевая прозрачность. Как правило, в Unix используется какой-нибудь протокол удаленного выполнения команд, например ssh, который позволяет вполне естественным образом выполнять программу (в том числе и имеющую GUI) на удаленной машине, получая её результаты на локальный дисплей. Как правило, этот протокол имеет еще и удобные встроенные средства авторизации. Тем не менее, почти никогда, кроме некоторых продвинутых imap-клиентов, эта возможность не используется для доступа к данным хранящимся на удаленной машине - используется прямое TCP-соединение, у которого могут быть проблемы с файрволлами, требуется отдельная авторизация (а про ident-протокол в наше время можно смело забыть).
  5. Виртуальная файловая система. То что файлы могут лежать не только в локальной файловой системе, но и в удаленной, доступной либо по протоколу выполнения команд, либо по протоколу сетевой файловой системы, на каком-нибудь мобильном устройстве, в архиве, на съемном носителе etc, знают все. Но ситуация с VFS оставляет желать лучшего.
  6. Понятие логической консоли. Когда-то давно, все чем располагал пользователь для обмена информацией с компьютером, было дисплей, клавиатура да мышь. Именно этот набор устройств поддерживает в норме протокол X11 (хотя там понятие позиционирующего устройства несколько шире, чем «мышь»). В современных условиях это давно не так. Во-первых, есть микрофон и колонки. И где бы пользователь не запустил программу, работать она должна ровно с теми колонками, которые расположены рядом (или вообще вмонтированы в) дисплеем этого пользователя. Во-вторых, есть сканеры, цифровые фотоаппараты, веб-камеры, и прочие источники данных, которые как-то связаны с физическим расположением пользователя. Есть еще и съемные носители, которые не только источник данных, и их получатель. И тоже находятся там же, где и пользователь. Впрочем, съемный носитель - частный случай виртуальной файловой системы
  7. Архитектура

    Поскольку внизу у нас таки Unix, архитектуру следует основывать на том, что Unix умеет хорошо, на том что описано во всех книжках по программированию. Это - командная строка и пайпы.

    Мощность современных компьютеров весьма велика. И зачастую запуск отдельного процесса является допустимым оверхедом для любой интерактивной операции. В конце концов, это было допустимым оверхедом во времена Кернигана и Пайка, когда компьютеры были гораздо слабее. Конечно, запуск современной программы с кучей библиотек, встроенными интерпретаторами et cetera, et cetera обходится гораздо дороже, чем запуск утилиты cat, но кто сказал, что компоненты выполняющие стандартные фунции должны быть «современными программами» в этом смысле слова?

    Если предположить, что нам не жалко породить отдельный GUI-процесс для операции выбора открываемого файла, то в программе вызов этого диалога будет выглядеть как

    f=popen("filedialog","r");
    fgets(f,filename,sizeof(filename);
    pclose(f);
    
    Исполняемый файл filedialog может быть либо
    #!/bin/sh
    exec zenity --file-dialog
    
    либо
    #!/usr/bin/wish
    puts [tkGetOpenFile]
    
    это уж как вам больше нравится. Управлять набором подобных утилит можно либо с помощью механизма аналогичного дебиановским alternatives, либо с помощью специального каталога в ${HOME}, например ~/components, где лежат симлинки или скрипты, делающие то, что нравится текущему пользователю.

    Вот поменяли одну симлинку, и сразу ВО ВСЕХ программах изменился диалог открытия файлов. Независимо от того, какую GUI-библиотеку использует сама программа.

    А если вы пользуетесь каким-нибудь продвинутым файл-менеджером, который много чего умеет, ваш скрипт filedialog может пообщаться с этим файлменеджером (через unix-domain socket, через X-овый ICCCM, как угодно) и открыть его панель со всеми его возможностями.

    Как реализовать таким же образом progress-bar см в той же zenity.

    А ведь можно вынести в подобного рода компоненты и более сложные операции. Поиск по тексту, например. Основная программа выдирает из своего формата данных искабельный текст, и скармливает компоненту, который возвращает "найдено/не найдено" (а если найдено, то смещение от последнего блока текста). В результате, с каким бы форматом данных мы не работали, хоть с html, хоть postscript, диалоговое окно поиска имеет одинаковые опции, поддерживает одинаковый синтаксис регулярных выражений etc.

    Еще можно оторвать от приложений систему главного меню, вынеся её в отдельную программу. Здесь, пожалуй, пайпы будут не самым удобным механизмом межпроцессной коммуникации, лучше использовать передачу событий X11, но зато эта конструкция позволяет полноценно реализовать интерфейсную парадигму МакОС, где меню не вверху окна, а в верху экрана. Это очень удобно, потому что для того, чтобы попасть мышью в верхнюю строчку экран, не надо прицеливаться. Просто резко дергаешь руку вверх, мимо границы экрана не промахнешься. А можно не реализовывать. В такой концепции создание меню приложений - функция window manager-а, а тот уж может выбирать, рисовать меню в верхней строке или в рамке текущего окна. Ему доступно и то, и другое.

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

    Дабы не изобреть велосипедов, вспомним, что у Xt-приложений есть замечательный ресурс translations, который позволяет связывать прикладные функции с клавиатурными событиями. На уровне пользовательской, per-display, per-site или per-application конфигурации. Аналогичным образом должны обрабатываться и события от менеджера меню.