Создание апплета GNOME

Создание апплета GNOME


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

Сам диалог настройки ничего не делает, он лишь изменяет значение соответствующего параметра в GConf (/system/proxy/mode), а программы, использующие прокси, следят за значением этого параметра. Поэтому, для того чтобы включить или выключить прокси, апплету достаточно изменить нужное значение в GConf.

У GConf есть как положительные, так и отрицательные стороны. Из положительных хочу отметить такие приятные вещи как:

  • информирование всех "подписанных" на параметр программ об изменении его значения (внешне это выглядит так: открываете диалог "Параметры прокси-серверов", меняете при помощи Python значение нужного параметра и переключатель в диалоге сам "прыгает" на нужную позицию)
  • глобальность изменения: не нужно думать о том, что нужно еще проставить значение переменной http_proxy для wget - GConf делает это автоматически. Ну а то, что все GNOME-программы берут настройки о использовании/не использовании прокси из GConf, я думаю, понятно без объяснений.
  • Из отрицательных я выделяю:

    • gconfd "гадит" в журналы. Мне не нравится, что gconfd пишет в общесистемный журнал (/var/log/messages) на русском языке.
    • несогласованность настроек различных программ. Например, Gajim и Firefox используют собственные настройки соединений. И если для Gajim можно найти оправдание (поддержка нескольких аккаунтов), то для Firefox я не вижу причин игнорировать GConf. Хотя для Gajim адекватен был бы выбор между "использовать глобальные настройки Gnome" и "использовать отдельные настройки для соединений".
    • невозможность (или просто я не знаю о таком) изменить настройки только для отдельных приложений
    • Прежде чем писать код, советую "поиграться" в интерактивной сессии (в качестве индикатора о смене настроек можно использовать диалог "Параметры прокси-сервера", либо редактор `gconf-editor`, но на мой взгляд, диалог прокси более показателен)


      >>> import gconf >>> gc = gconf.client_get_default() >>> gc.get_string('/system/proxy/mode') 'none'

      >>> gc.set_string('/system/proxy/mode', 'manual') True >>> gc.get_string() 'manual'



      Что происходит, если попытаться получить значение несуществующего ключа, или извлечь значение не того типа, предлагаю изучить самостоятельно, вооружившись gconf-editor и Python.

      Что касается возможных значений ключа ‘/system/proxy/mode’, то допустимые значения здесь таковы: none, manual, auto. Если значение не входит в список разрешенных, оно интерпретируется как none.

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

      В коде изложено всё вышесказанное:

      class ProxyGconfClient(object): """Get/set proxy states""" proxy_dir = "/system/proxy"

      proxy_key = "/system/proxy/mode" on_state = 'manual' off_state = 'none'

      def __init__(self, callback=None): """ GConf client for getting/setting proxy states

      @param callback: callback function. Executing when proxy state changed. It calls with params: * client - GConf client * cnxn_id - connection ID * entry - changed entry * params - additional params @type callback: callable """ if callback is None: callback = lambda client, cnxn_id, entry, params: None # make connection to GConfD self.client = gconf.client_get_default() # add proxy_dir for inspection, without preload self.client.add_dir(self.proxy_dir, gconf.CLIENT_PRELOAD_NONE) # add callback for notifying about changes self.client.notify_add(self.proxy_key, callback)

      def get_state(self): """Returns state of proxy""" return self.client.get_string(self.proxy_key)

      def set_state(self, value): """

      Set state of proxy

      @param value: state of proxy, may be * 'none' - direct connection, proxy off * 'manual' - manual settings, proxy on * 'auto' - auto settings, proxy on if value neither 'manual', no 'auto', it means direct connection, i.e.proxy off. @raise RuntimeError: cannot set value to GConf's key """ if not self.client.set_string(self.proxy_key, value): raise RuntimeError("Unable to change key %s" % self.proxy_key)

      def on(self): """Turn proxy on (i.e. set proxy mode 'manual')""" self.set_state(self.on_state)

      def is_on(self): """Is proxy on? (i.e. proxy in 'manual' mode)""" return self.get_state() == self.on_state

      def off(self): """Turn proxy off (i.e. set direct connection)"""

      self.set_state(self.off_state)



      Содержание раздела