#!@PYTHON@ # vim: set ts=4 sw=4 et: # # Copyright (C) 2009 Novell, Inc. # # Authors: Vincent Untz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # import optparse import os import shutil import sys import urllib import ConfigParser try: import matecomponent has_matecomponent = True except ImportError: has_matecomponent = False import mateconf PANEL_SCHEMAS_OBJECTS_DIR='/schemas/apps/panel/objects' PANEL_TOPLEVELS_DIR='/apps/panel/toplevels' PANEL_TOPLEVELS_KEY='/apps/panel/general/toplevel_id_list' MATE_PANEL_APPLETS_DIR='/apps/panel/applets' MATE_PANEL_APPLETS_KEY='/apps/panel/general/applet_id_list' PANEL_OBJECTS_DIR='/apps/panel/objects' PANEL_OBJECTS_KEY='/apps/panel/general/object_id_list' PANEL_LAUNCHER_USER_DIR=os.path.join(os.path.expanduser('~'), '.mate2', 'panel2.d', 'default', 'launchers') PANEL_TYPE_NONE = 0 PANEL_TYPE_APPLET = 1 PANEL_TYPE_LAUNCHER = 2 MATE_PANEL_APPLETS_EXTENSION='.mate-panel-applet' MATE_PANEL_APPLETS_PATH='@MATE_PANEL_APPLETS_DIR@' MATE_PANEL_APPLET_FACTORY_GROUP='Applet Factory' class PanelAddException(Exception): pass class PanelAdder: def __init__(self, toplevel, position, right_stick, applet_iid = None, launcher_path = None, copy_launcher = False): self.toplevel = toplevel self.position = position self.right_stick = right_stick # FIXME workaround: -1 and right_click don't play well together. Just # use an arbitrary value so that the applet ends up at the left of all # right-click applets (it'd be surprising to have a config with more # than 10 applets...) if self.right_stick and self.position < 0: self.position = 10 self.type = PANEL_TYPE_NONE self.applet_iid = None self.launcher_path = None self.copy_launcher = False self.client = None if applet_iid: self._set_applet_iid(applet_iid) self.type = PANEL_TYPE_APPLET elif launcher_path: self._set_launcher_path(launcher_path) self.copy_launcher = copy_launcher self.type = PANEL_TYPE_LAUNCHER def _panel_get_subdirs(self, key): return [ os.path.basename(s) for s in self.client.all_dirs(key) ] def _panel_get_list(self, key): list_v = self.client.get(key) if not list_v: return [] if list_v.type != mateconf.VALUE_LIST or list_v.get_list_type() != mateconf.VALUE_STRING: return [] return [ v.get_string() for v in list_v.get_list() ] def _toplevel_id_ensure(self): toplevel_subdirs = self._panel_get_subdirs(PANEL_TOPLEVELS_DIR) toplevel_id_list = self._panel_get_list(PANEL_TOPLEVELS_KEY) if self.toplevel: if not self.toplevel in toplevel_subdirs or not self.toplevel in toplevel_id_list: raise PanelAddException('%s is not an existing panel identifier' % self.toplevel) else: for toplevel in toplevel_id_list: if toplevel in toplevel_subdirs: self.toplevel = toplevel return raise PanelAddException('Cannot find a panel identifier') def _get_applet_list(self): dirs = os.getenv('MATE_PANEL_APPLETS_DIR') if not dirs: dirs = MATE_PANEL_APPLETS_PATH retval = [] dups = [] for path in dirs.split(":"): if not os.path.isdir(path): continue if path in dups: continue dups.append(path) for f in os.listdir(path): if not f.endswith(MATE_PANEL_APPLETS_EXTENSION): continue config = ConfigParser.RawConfigParser() try: config.read(os.path.join(path, f)) except ConfigParser.ParsingError: continue fid = config.get(MATE_PANEL_APPLET_FACTORY_GROUP, 'Id') retval.extend(["%s::%s" % (fid, s) for s in config.sections() if s != MATE_PANEL_APPLET_FACTORY_GROUP]) return retval def _set_applet_iid(self, applet_iid): if not applet_iid: raise PanelAddException('No applet specified') applets = self._get_applet_list () if not applet_iid in applets: if has_matecomponent: applets = matecomponent.activation.query ("has_all (repo_ids, ['IDL:MateComponent/Control:1.0', 'IDL:MATE/Vertigo/MatePanelAppletShell:1.0'])") if not applet_iid in [ a.iid for a in applets ]: raise PanelAddException('%s is not a valid applet' % applet_iid) else: raise PanelAddException('%s is not a valid applet' % applet_iid) self.applet_iid = applet_iid def _set_launcher_path(self, launcher_path): if not launcher_path: raise PanelAddException('No launcher specified') if not launcher_path.endswith('.desktop'): raise PanelAddException('%s does not have a .desktop extension' % launcher_path) if not os.path.exists(launcher_path): raise PanelAddException('%s is not an existing launcher' % launcher_path) self.launcher_path = launcher_path def _object_id_find_unused(self): if self.type == PANEL_TYPE_APPLET: subdirs = self._panel_get_subdirs(MATE_PANEL_APPLETS_DIR) id_list = self._panel_get_list(MATE_PANEL_APPLETS_KEY) prefix = 'applet' else: subdirs = self._panel_get_subdirs(PANEL_OBJECTS_DIR) id_list = self._panel_get_list(PANEL_OBJECTS_KEY) prefix = 'object' i = 0 while i < 1000: id = '%s_%d' % (prefix, i) if id not in subdirs and id not in id_list: return id i += 1 return None def _launcher_find_unused(self): basename = os.path.basename(self.launcher_path) if not os.path.exists(os.path.join(PANEL_LAUNCHER_USER_DIR, basename)): return basename dot = basename.rfind('.') prefix = basename[:dot] extension = basename[dot:] i = 0 while i < 1000: basename = '%s-%d%s' % (prefix, i, extension) if not os.path.exists(os.path.join(PANEL_LAUNCHER_USER_DIR, basename)): return basename i += 1 raise PanelAddException('Copying %s would overwrite existing launchers' % self.launcher_path) def _associate_schemas(self, engine, schema_dir, dest_dir): entries = self.client.all_entries(schema_dir) for entry in entries: dest_key = os.path.basename(entry.key) engine.associate_schema(os.path.join(dest_dir, dest_key), entry.key) subdirs = self.client.all_dirs(schema_dir) for subdir in subdirs: dest_subdir = os.path.join(subdir) self._associate_schemas(engine, subdir, os.path.join(dest_dir, dest_subdir)) def run(self): self.client = mateconf.client_get_default () self._toplevel_id_ensure() id = self._object_id_find_unused() if not id: raise PanelAddException('No identifier available for the new object') if self.type == PANEL_TYPE_APPLET: dir = os.path.join(MATE_PANEL_APPLETS_DIR, id) elif self.type == PANEL_TYPE_LAUNCHER: dir = os.path.join(PANEL_OBJECTS_DIR, id) if self.copy_launcher: try: if not os.path.exists(PANEL_LAUNCHER_USER_DIR): os.makedirs(PANEL_LAUNCHER_USER_DIR) unused = self._launcher_find_unused() dest = os.path.join (PANEL_LAUNCHER_USER_DIR, unused) shutil.copyfile(self.launcher_path, dest) launcher_location = unused except (OSError, IOError), e: raise PanelAddException('Cannot copy launcher: %s' % e) else: launcher_location = 'file://' + urllib.pathname2url(os.path.realpath(self.launcher_path)) else: raise PanelAddException('Unknown panel object type %d' % self.type) engine = mateconf.engine_get_default() self._associate_schemas(engine, PANEL_SCHEMAS_OBJECTS_DIR, dir) self.client.set_string(os.path.join(dir, 'toplevel_id'), self.toplevel) self.client.set_int(os.path.join(dir, 'position'), self.position) self.client.set_bool(os.path.join(dir, 'panel_right_stick'), self.right_stick) if self.type == PANEL_TYPE_APPLET: self.client.set_string(os.path.join(dir, 'object_type'), 'matecomponent-applet') self.client.set_string(os.path.join(dir, 'applet_iid'), self.applet_iid) id_list = self._panel_get_list(MATE_PANEL_APPLETS_KEY) id_list.append(id) self.client.set_list(MATE_PANEL_APPLETS_KEY, mateconf.VALUE_STRING, id_list) elif self.type == PANEL_TYPE_LAUNCHER: self.client.set_string(os.path.join(dir, 'object_type'), 'launcher-object') self.client.set_string(os.path.join(dir, 'launcher_location'), launcher_location) id_list = self._panel_get_list(PANEL_OBJECTS_KEY) id_list.append(id) self.client.set_list(PANEL_OBJECTS_KEY, mateconf.VALUE_STRING, id_list) else: raise PanelAddException('Unknown panel object type %d' % self.type) def main(args): parser = optparse.OptionParser() parser.add_option('--applet', dest='applet', help='Applet to add') parser.add_option('--copy-launcher', dest='copy_launcher', action='store_true', default=False, help='Copy the launcher to the user directory') parser.add_option('--launcher', dest='launcher', help='Launcher to add') parser.add_option('--panel', dest='toplevel', help='Identifier of the panel where to add the applet') parser.add_option('--position', dest='position', help='Position on the panel where to add the applet') parser.add_option('--right-stick', dest='right_stick', action='store_true', default=False, help='Make the applet right-aligned on the panel') (options, args) = parser.parse_args() if not options.applet and not options.launcher: print parser.format_help() return 1 if options.applet and options.launcher: raise PanelAddException('Cannot add an applet and a launcher at the same time') if options.position: try: position = int(options.position) except ValueError: raise PanelAddException('%s is not an integer, required for position' % options.position) else: position = -1 adder = PanelAdder(options.toplevel, position, options.right_stick, options.applet, options.launcher, options.copy_launcher) adder.run() if __name__ == '__main__': try: main(sys.argv) except PanelAddException, e: print >> sys.stderr, e sys.exit(1) except KeyboardInterrupt: pass