home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / gimp / 2.0 / python / gimpfu.py < prev    next >
Encoding:
Python Source  |  2006-07-10  |  20.2 KB  |  628 lines

  1. #   Gimp-Python - allows the writing of Gimp plugins in Python.
  2. #   Copyright (C) 1997  James Henstridge <james@daa.com.au>
  3. #
  4. #   This program is free software; you can redistribute it and/or modify
  5. #   it under the terms of the GNU General Public License as published by
  6. #   the Free Software Foundation; either version 2 of the License, or
  7. #   (at your option) any later version.
  8. #
  9. #   This program is distributed in the hope that it will be useful,
  10. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #   GNU General Public License for more details.
  13. #
  14. #   You should have received a copy of the GNU General Public License
  15. #   along with this program; if not, write to the Free Software
  16. #   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  
  18. '''Simple interface to writing GIMP plugins in python.
  19.  
  20. Instead of worrying about all the user interaction, saving last used values
  21. and everything, the gimpfu module can take care of it for you.  It provides
  22. a simple register() function that will register your plugin if needed, and
  23. cause your plugin function to be called when needed.
  24.  
  25. Gimpfu will also handle showing a user interface for editing plugin parameters
  26. if the plugin is called interactively, and will also save the last used
  27. parameters, so the RUN_WITH_LAST_VALUES run_type will work correctly.  It
  28. will also make sure that the displays are flushed on completion if the plugin
  29. was run interactively.
  30.  
  31. When registering the plugin, you do not need to worry about specifying
  32. the run_type parameter.  And if the plugin is an image plugin (the menu
  33. path starts with <Image>/), the image and drawable parameters are also
  34. automatically added.
  35.  
  36. A typical gimpfu plugin would look like this:
  37.   from gimpfu import *
  38.  
  39.   def plugin_func(image, drawable, args):
  40.               #do what plugins do best
  41.   register(
  42.               "plugin_func",
  43.               "blurb",
  44.               "help message",
  45.               "author",
  46.               "copyright",
  47.               "year",
  48.               "<Image>/Somewhere/My plugin",
  49.               "*",
  50.               [(PF_STRING, "arg", "The argument", "default-value")],
  51.               [],
  52.               plugin_func)
  53.   main()
  54.  
  55. The call to "from gimpfu import *" will import all the gimp constants into
  56. the plugin namespace, and also import the symbols gimp, pdb, register and
  57. main.  This should be just about all any plugin needs.  You can use any
  58. of the PF_* constants below as parameter types, and an appropriate user
  59. interface element will be displayed when the plugin is run in interactive
  60. mode.  Note that the the PF_SPINNER and PF_SLIDER types expect a fifth
  61. element in their description tuple -- a 3-tuple of the form (lower,upper,step),
  62. which defines the limits for the slider or spinner.'''
  63.  
  64. import string as _string
  65. import gimp
  66. from gimpenums import *
  67. pdb = gimp.pdb
  68.  
  69. class error(RuntimeError):pass
  70. class CancelError(RuntimeError):pass
  71.  
  72. PF_INT8        = PDB_INT8
  73. PF_INT16       = PDB_INT16
  74. PF_INT32       = PDB_INT32
  75. PF_INT         = PF_INT32
  76. PF_FLOAT       = PDB_FLOAT
  77. PF_STRING      = PDB_STRING
  78. PF_VALUE       = PF_STRING
  79. #PF_INT8ARRAY   = PDB_INT8ARRAY
  80. #PF_INT16ARRAY  = PDB_INT16ARRAY
  81. #PF_INT32ARRAY  = PDB_INT32ARRAY
  82. #PF_INTARRAY    = PF_INT32ARRAY
  83. #PF_FLOATARRAY  = PDB_FLOATARRAY
  84. #PF_STRINGARRAY = PDB_STRINGARRAY
  85. PF_COLOR       = PDB_COLOR
  86. PF_COLOUR      = PF_COLOR
  87. PF_REGION      = PDB_REGION
  88. #PF_DISPLAY     = PDB_DISPLAY
  89. PF_IMAGE       = PDB_IMAGE
  90. PF_LAYER       = PDB_LAYER
  91. PF_CHANNEL     = PDB_CHANNEL
  92. PF_DRAWABLE    = PDB_DRAWABLE
  93. #PF_SELECTION   = PDB_SELECTION
  94. #PF_BOUNDARY    = PDB_BOUNDARY
  95. #PF_PATH        = PDB_PATH
  96. #PF_STATUS      = PDB_STATUS
  97.  
  98. PF_TOGGLE      = 1000
  99. PF_BOOL        = PF_TOGGLE
  100. PF_SLIDER      = 1001
  101. PF_SPINNER     = 1002
  102. PF_ADJUSTMENT  = PF_SPINNER
  103.  
  104. PF_FONT        = 1003
  105. PF_FILE        = 1004
  106. PF_BRUSH       = 1005
  107. PF_PATTERN     = 1006
  108. PF_GRADIENT    = 1007
  109. PF_RADIO       = 1008
  110. PF_TEXT        = 1009
  111. PF_PALETTE     = 1010
  112.  
  113. _type_mapping = {
  114.     PF_INT8        : PDB_INT8,
  115.     PF_INT16       : PDB_INT16,
  116.     PF_INT32       : PDB_INT32,
  117.     PF_FLOAT       : PDB_FLOAT,
  118.     PF_STRING      : PDB_STRING,
  119.     #PF_INT8ARRAY   : PDB_INT8ARRAY,
  120.     #PF_INT16ARRAY  : PDB_INT16ARRAY,
  121.     #PF_INT32ARRAY  : PDB_INT32ARRAY,
  122.     #PF_FLOATARRAY  : PDB_FLOATARRAY,
  123.     #PF_STRINGARRAY : PDB_STRINGARRAY,
  124.     PF_COLOUR      : PDB_COLOR,
  125.     PF_REGION      : PDB_REGION,
  126.     PF_IMAGE       : PDB_IMAGE,
  127.     PF_LAYER       : PDB_LAYER,
  128.     PF_CHANNEL     : PDB_CHANNEL,
  129.     PF_DRAWABLE    : PDB_DRAWABLE,
  130.  
  131.     PF_TOGGLE      : PDB_INT32,
  132.     PF_SLIDER      : PDB_FLOAT,
  133.     PF_SPINNER     : PDB_INT32,
  134.  
  135.     PF_FONT        : PDB_STRING,
  136.     PF_FILE        : PDB_STRING,
  137.     PF_BRUSH       : PDB_STRING,
  138.     PF_PATTERN     : PDB_STRING,
  139.     PF_GRADIENT    : PDB_STRING,
  140.     PF_RADIO       : PDB_STRING,
  141.     PF_TEXT        : PDB_STRING,
  142.     PF_PALETTE     : PDB_STRING,
  143. }
  144.  
  145. _registered_plugins_ = {}
  146.  
  147. def register(func_name, blurb, help, author, copyright, date, menupath,
  148.                  imagetypes, params, results, function,
  149.                  on_query=None, on_run=None):
  150.     '''This is called to register a new plugin.'''
  151.     # First perform some sanity checks on the data
  152.     def letterCheck(str):
  153.         allowed = _string.letters + _string.digits + '_'
  154.         for ch in str:
  155.             if not ch in allowed:
  156.                     return 0
  157.         else:
  158.             return 1
  159.     if not letterCheck(func_name):
  160.         raise error, "function name contains illegal characters"
  161.     for ent in params:
  162.         if len(ent) < 4:
  163.             raise error, ("parameter definition must contain at least 4 "
  164.                         "elements (%s given: %s)" % (len(ent), ent))
  165.         if type(ent[0]) != type(42):
  166.             raise error, "parameter types must be integers"
  167.         if not letterCheck(ent[1]):
  168.             raise error, "parameter name contains illegal characters"
  169.     for ent in results:
  170.         if len(ent) < 3:
  171.             raise error, ("result definition must contain at least 3 elements "
  172.                         "(%s given: %s)" % (len(ent), ent))
  173.         if type(ent[0]) != type(42):
  174.             raise error, "result types must be integers"
  175.         if not letterCheck(ent[1]):
  176.             raise error, "result name contains illegal characters"
  177.     if menupath[:8] == '<Image>/' or \
  178.        menupath[:7] == '<Load>/' or \
  179.        menupath[:7] == '<Save>/' or \
  180.        menupath[:10] == '<Toolbox>/':
  181.         plugin_type = PLUGIN
  182.     else:
  183.         raise error, "Invalid menu path"
  184.  
  185.     if not func_name[:7] == 'python_' and \
  186.        not func_name[:10] == 'extension_' and \
  187.        not func_name[:8] == 'plug_in_' and \
  188.        not func_name[:5] == 'file_':
  189.            func_name = 'python_fu_' + func_name
  190.  
  191.     _registered_plugins_[func_name] = (blurb, help, author, copyright,
  192.                                        date, menupath, imagetypes,
  193.                                        plugin_type, params, results,
  194.                                        function, on_query, on_run)
  195.  
  196. file_params = [(PDB_STRING, "filename", "The name of the file"),
  197.                (PDB_STRING, "raw_filename", "The name of the file")]
  198.  
  199. def _query():
  200.     for plugin in _registered_plugins_.keys():
  201.         (blurb, help, author, copyright, date,
  202.          menupath, imagetypes, plugin_type,
  203.          params, results, function,
  204.          on_query, on_run) = _registered_plugins_[plugin]
  205.  
  206.         fn = lambda x: (_type_mapping[x[0]], x[1], x[2])
  207.         params = map(fn, params)
  208.         # add the run mode argument ...
  209.         params.insert(0, (PDB_INT32, "run_mode",
  210.                                     "Interactive, Non-Interactive"))
  211.         if plugin_type == PLUGIN:
  212.             if menupath[:7] == '<Load>/':
  213.                 params[1:1] = file_params
  214.             elif menupath[:10] != '<Toolbox>/':
  215.                 params.insert(1, (PDB_IMAGE, "image",
  216.                                   "The image to work on"))
  217.                 params.insert(2, (PDB_DRAWABLE, "drawable",
  218.                                   "The drawable to work on"))
  219.                 if menupath[:7] == '<Save>/':
  220.                     params[3:3] = file_params
  221.  
  222.         results = map(fn, results)
  223.         gimp.install_procedure(plugin, blurb, help, author, copyright,
  224.                                date, menupath, imagetypes, plugin_type,
  225.                                params, results)
  226.         if on_query:
  227.             on_query()
  228.  
  229. def _get_defaults(func_name):
  230.     import gimpshelf
  231.     (blurb, help, author, copyright, date,
  232.      menupath, imagetypes, plugin_type,
  233.      params, results, function,
  234.      on_query, on_run) = _registered_plugins_[func_name]
  235.  
  236.     key = "python-fu-save--" + func_name
  237.     if gimpshelf.shelf.has_key(key):
  238.         return gimpshelf.shelf[key]
  239.     else:
  240.         # return the default values
  241.         return map(lambda x: x[3], params)
  242.  
  243. def _set_defaults(func_name, defaults):
  244.     import gimpshelf
  245.  
  246.     key = "python-fu-save--" + func_name
  247.     gimpshelf.shelf[key] = defaults
  248.  
  249. def _interact(func_name, start_params):
  250.     (blurb, help, author, copyright, date,
  251.      menupath, imagetypes, plugin_type,
  252.      params, results, function,
  253.      on_query, on_run) = _registered_plugins_[func_name]
  254.  
  255.     def run_script(run_params):
  256.         params = start_params + tuple(run_params)
  257.         return apply(function, params)
  258.  
  259.     # short circuit for no parameters ...
  260.     if len(params) == 0:
  261.          return run_script([])
  262.  
  263.     import pygtk
  264.     pygtk.require('2.0')
  265.  
  266.     import gtk
  267.     import gimpui
  268.  
  269.     gtk.rc_parse(gimp.gtkrc())
  270.  
  271.     defaults = _get_defaults(func_name)
  272.  
  273.     class EntryValueError(Exception):
  274.         pass
  275.  
  276.     def error_dialog(parent, msg):
  277.         dlg = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT,
  278.                                         gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE,
  279.                                         msg)
  280.         dlg.run()
  281.         dlg.destroy()
  282.  
  283.     # define a mapping of param types to edit objects ...
  284.     class StringEntry(gtk.Entry):
  285.         def __init__(self, default=''):
  286.             gtk.Entry.__init__(self)
  287.             self.set_text(str(default))
  288.         def get_value(self):
  289.             return self.get_text()
  290.  
  291.     class TextEntry(gtk.ScrolledWindow):
  292.         def __init__ (self, default=''):
  293.             gtk.ScrolledWindow.__init__(self)
  294.             self.set_shadow_type(gtk.SHADOW_IN)
  295.             
  296.             self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  297.             self.set_size_request(100, -1)
  298.  
  299.             self.view = gtk.TextView()
  300.             self.add(self.view)
  301.             self.view.show()
  302.  
  303.             self.buffer = self.view.get_buffer()
  304.  
  305.             self.set_value(str(default))
  306.             
  307.         def set_value (self, text):
  308.             self.buffer.set_text(text)
  309.         def get_value(self):
  310.             return self.buffer.get_text(self.buffer.get_start_iter(),
  311.                                         self.buffer.get_end_iter())
  312.  
  313.     class IntEntry(StringEntry):
  314.         def get_value(self):
  315.             try:
  316.                 return int(self.get_text())
  317.             except ValueError, e:
  318.                 raise EntryValueError, e.args
  319.     class FloatEntry(StringEntry):
  320.             def get_value(self):
  321.                 try:
  322.                     return float(self.get_text())
  323.                 except ValueError, e:
  324.                     raise EntryValueError, e.args
  325. #    class ArrayEntry(StringEntry):
  326. #            def get_value(self):
  327. #                return eval(self.get_text(), {}, {})
  328.     class SliderEntry(gtk.HScale):
  329.         # bounds is (upper, lower, step)
  330.         def __init__(self, default=0, bounds=(0, 100, 5)):
  331.             self.adj = gtk.Adjustment(default, bounds[0],
  332.                                       bounds[1], bounds[2],
  333.                                       bounds[2], 0)
  334.             gtk.HScale.__init__(self, self.adj)
  335.         def get_value(self):
  336.             return self.adj.value
  337.     class SpinnerEntry(gtk.SpinButton):
  338.         # bounds is (upper, lower, step)
  339.         def __init__(self, default=0, bounds=(0, 100, 5)):
  340.             self.adj = gtk.Adjustment(default, bounds[0],
  341.                                         bounds[1], bounds[2],
  342.                                         bounds[2], 0)
  343.             gtk.SpinButton.__init__(self, self.adj, 1, 0)
  344.         def get_value(self):
  345.             try:
  346.                 return int(self.get_text())
  347.             except ValueError, e:
  348.                 raise EntryValueError, e.args
  349.     class ToggleEntry(gtk.ToggleButton):
  350.         def __init__(self, default=0):
  351.             gtk.ToggleButton.__init__(self)
  352.             self.label = gtk.Label("No")
  353.             self.add(self.label)
  354.             self.label.show()
  355.             self.connect("toggled", self.changed)
  356.             self.set_active(default)
  357.         def changed(self, tog):
  358.             if tog.get_active():
  359.                 self.label.set_text("Yes")
  360.             else:
  361.                 self.label.set_text("No")
  362.         def get_value(self):
  363.             return self.get_active()
  364.     class RadioEntry(gtk.Frame):
  365.         def __init__(self, default=0, items=(("Yes", 1), ("No", 0))):
  366.             gtk.Frame.__init__(self)
  367.             box = gtk.VBox(gtk.FALSE, 5)
  368.             self.add(box)
  369.             box.show()
  370.             button = None
  371.             for (label, value) in items:
  372.                 button = gtk.RadioButton(button, label)
  373.                 button.connect("toggled", self.changed, value)
  374.                 box.pack_start(button)
  375.                 button.show()
  376.                 if value == default:
  377.                     button.set_active(gtk.TRUE)
  378.                     self.active_value = value
  379.         def changed(self, radio, value):
  380.             if radio.get_active():
  381.                 self.active_value = value
  382.         def get_value(self):
  383.             return self.active_value
  384.  
  385.     _edit_mapping = {
  386.             PF_INT8        : IntEntry,
  387.             PF_INT16       : IntEntry,
  388.             PF_INT32       : IntEntry,
  389.             PF_FLOAT       : FloatEntry,
  390.             PF_STRING      : StringEntry,
  391.             #PF_INT8ARRAY   : ArrayEntry,
  392.             #PF_INT16ARRAY  : ArrayEntry,
  393.             #PF_INT32ARRAY  : ArrayEntry,
  394.             #PF_FLOATARRAY  : ArrayEntry,
  395.             #PF_STRINGARRAY : ArrayEntry,
  396.             PF_COLOUR      : gimpui.ColourSelector,
  397.             PF_REGION      : IntEntry,  # should handle differently ...
  398.             PF_IMAGE       : gimpui.ImageSelector,
  399.             PF_LAYER       : gimpui.LayerSelector,
  400.             PF_CHANNEL     : gimpui.ChannelSelector,
  401.             PF_DRAWABLE    : gimpui.DrawableSelector,
  402.  
  403.             PF_TOGGLE      : ToggleEntry,
  404.             PF_SLIDER      : SliderEntry,
  405.             PF_SPINNER     : SpinnerEntry,
  406.             PF_RADIO       : RadioEntry,
  407.  
  408.             PF_FONT        : gimpui.FontSelector,
  409.             PF_FILE        : gimpui.FileSelector,
  410.             PF_BRUSH       : gimpui.BrushSelector,
  411.             PF_PATTERN     : gimpui.PatternSelector,
  412.             PF_GRADIENT    : gimpui.GradientSelector,
  413.             PF_PALETTE     : gimpui.PaletteSelector,
  414.             PF_TEXT        : TextEntry
  415.     }
  416.  
  417.     if on_run:
  418.         on_run()
  419.  
  420.     need_progress = menupath[:8] != '<Image>/'
  421.  
  422.     tooltips = gtk.Tooltips()
  423.  
  424.     dialog = gtk.Dialog(func_name, None, 0,
  425.                         (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
  426.                         gtk.STOCK_OK, gtk.RESPONSE_OK))
  427.  
  428.     hbox = gtk.HBox(gtk.FALSE, 5)
  429.     hbox.set_border_width(5)
  430.     dialog.vbox.pack_start(hbox, expand=gtk.FALSE)
  431.     hbox.show()
  432.  
  433.     table = gtk.Table(len(params), 2, gtk.FALSE)
  434.     table.set_border_width(5)
  435.     table.set_row_spacings(4)
  436.     table.set_col_spacings(10)
  437.     hbox.pack_end(table, expand=gtk.FALSE)
  438.     table.show()
  439.  
  440.     vbox = gtk.VBox(gtk.FALSE, 10)
  441.     hbox.pack_start(vbox, expand=gtk.FALSE)
  442.     vbox.show()
  443.  
  444.     pix = _get_logo()
  445.     if pix:
  446.         vbox.pack_start(pix, expand=gtk.FALSE)
  447.         pix.show()
  448.  
  449.     label = gtk.Label(blurb)
  450.     label.set_line_wrap(gtk.TRUE)
  451.     label.set_justify(gtk.JUSTIFY_LEFT)
  452.     label.set_size_request(100, -1)
  453.     vbox.pack_start(label, expand=gtk.FALSE)
  454.     label.show()
  455.  
  456.     progress_callback = None
  457.  
  458.     def response(dlg, id):
  459.         if id == gtk.RESPONSE_OK:
  460.             params = []
  461.  
  462.             try:
  463.                 for wid in edit_wids:
  464.                     params.append(wid.get_value())
  465.             except EntryValueError:
  466.                 error_dialog(dialog, 'Invalid input for "%s"' % wid.desc)
  467.             else:
  468.                 _set_defaults(func_name, params)
  469.                 dialog.res = run_script(params)
  470.  
  471.         if progress_callback:
  472.             gimp.progress_uninstall(progress_callback)
  473.  
  474.         gtk.main_quit()
  475.  
  476.     dialog.connect("response", response)
  477.  
  478.     edit_wids = []
  479.     for i in range(len(params)):
  480.         pf_type = params[i][0]
  481.         name = params[i][1]
  482.         desc = params[i][2]
  483.         def_val = defaults[i]
  484.  
  485.         label = gtk.Label(desc)
  486.         label.set_alignment(1.0, 0.5)
  487.         table.attach(label, 1,2, i,i+1, xoptions=gtk.FILL)
  488.         label.show()
  489.  
  490.         if pf_type in (PF_SPINNER, PF_SLIDER, PF_RADIO):
  491.             wid = _edit_mapping[pf_type](def_val, params[i][4])
  492.         else:
  493.             wid = _edit_mapping[pf_type](def_val)
  494.         
  495.         table.attach(wid, 2,3, i,i+1, yoptions=0)
  496.         if pf_type != PF_TEXT:
  497.             tooltips.set_tip(wid, desc, None)         
  498.         else:
  499.             #Attach tip to TextView, not to ScrolledWindow
  500.             tooltips.set_tip(wid.view, desc, None)         
  501.         wid.show()
  502.  
  503.         wid.desc = desc
  504.         edit_wids.append(wid)
  505.  
  506.     if need_progress:
  507.         frame = gtk.Frame("Script Progress")
  508.         frame.set_border_width(5)
  509.         dialog.vbox.pack_start(frame)
  510.         frame.show()
  511.  
  512.         vbox = gtk.VBox(gtk.FALSE, 5)
  513.         vbox.set_border_width(5)
  514.         frame.add(vbox)
  515.         vbox.show()
  516.  
  517.         progress_label = gtk.Label("(none)")
  518.         progress_label.set_alignment(0.0, 0.5)
  519.         vbox.pack_start(progress_label)
  520.         progress_label.show()
  521.  
  522.         progress = gtk.ProgressBar()
  523.         progress.set_text(" ")
  524.         vbox.pack_start(progress)
  525.         progress.show()
  526.  
  527.         def progress_update(message=-1, fraction=None):
  528.             if message == -1:
  529.                 pass
  530.             elif message:
  531.                 progress.set_text(message)
  532.             else:
  533.                 progress.set_text(" ")
  534.  
  535.             if fraction is not None:
  536.                 progress.set_fraction(fraction)
  537.  
  538.             while gtk.events_pending():
  539.                 gtk.main_iteration()
  540.  
  541.         def progress_start(message, cancelable):
  542.             progress_update(message, 0.0)
  543.  
  544.         def progress_end():
  545.             progress_update(None, 0.0)
  546.  
  547.         def progress_text(message):
  548.             progress_update(message)
  549.  
  550.         def progress_value(percentage):
  551.             progress_update(fraction=percentage)
  552.  
  553.         progress_callback = gimp.progress_install(progress_start, progress_end,
  554.                                                   progress_text, progress_value)
  555.  
  556.     tooltips.enable()
  557.     dialog.show()
  558.  
  559.     gtk.main()
  560.  
  561.     if hasattr(dialog, 'res'):
  562.         res = dialog.res
  563.         dialog.destroy()
  564.         return res
  565.     else:
  566.         dialog.destroy()
  567.         raise CancelError
  568.  
  569. def _run(func_name, params):
  570.     run_mode = params[0]
  571.     plugin_type = _registered_plugins_[func_name][7]
  572.     menupath = _registered_plugins_[func_name][5]
  573.     func = _registered_plugins_[func_name][10]
  574.  
  575.     if plugin_type == PLUGIN and menupath[:10] != '<Toolbox>/':
  576.         if menupath[:7] == '<Save>/':
  577.             end = 5
  578.         else:
  579.             end = 3
  580.  
  581.         start_params = params[1:end]
  582.         extra_params = params[end:]
  583.     else:
  584.         start_params = ()
  585.         extra_params = params[1:]
  586.  
  587.     if run_mode == RUN_INTERACTIVE:
  588.         try:
  589.             res = _interact(func_name, start_params)
  590.         except CancelError:
  591.             return
  592.     else:
  593.         if run_mode == RUN_WITH_LAST_VALS:
  594.             extra_params = _get_defaults(func_name)
  595.  
  596.         params = start_params + tuple(extra_params)
  597.         res = apply(func, params)
  598.  
  599.     if run_mode != RUN_NONINTERACTIVE:
  600.         gimp.displays_flush()
  601.  
  602.     return res
  603.  
  604. def main():
  605.     '''This should be called after registering the plugin.'''
  606.     gimp.main(None, None, _query, _run)
  607.  
  608. def fail(msg):
  609.     '''Display and error message and quit'''
  610.     gimp.message(msg)
  611.     raise error, msg
  612.  
  613. def _get_logo():
  614.     import gtk, gobject
  615.  
  616.     import os.path
  617.     logofile = os.path.join(os.path.dirname(__file__), 'pygimp-logo.png')
  618.  
  619.     try:
  620.         pixbuf = gtk.gdk.pixbuf_new_from_file(logofile)
  621.     except gobject.GError, e:
  622.         return None
  623.  
  624.     image = gtk.Image()
  625.     image.set_from_pixbuf(pixbuf)
  626.  
  627.     return image
  628.