summaryrefslogtreecommitdiffstats
path: root/gobject
diff options
context:
space:
mode:
authorJohannes Hölzl <johannes.hoelzl@gmx.de>2006-04-29 18:58:20 +0000
committerJohan Dahlin <johan@src.gnome.org>2006-04-29 18:58:20 +0000
commit6896d50402332dcac8d079d48d22e30c3e0f7231 (patch)
tree626e46020f2134d9254a7f190ff7fba59310cad3 /gobject
parentcd01d8f09504748a17e1e7ae68ada9d4edaf23fe (diff)
downloadpygobject-6896d50402332dcac8d079d48d22e30c3e0f7231.tar.gz
pygobject-6896d50402332dcac8d079d48d22e30c3e0f7231.tar.xz
pygobject-6896d50402332dcac8d079d48d22e30c3e0f7231.zip
reviewed by: Johan Dahlin <jdahlin@async.com.br>
2006-04-29 Johannes Hölzl <johannes.hoelzl@gmx.de> reviewed by: Johan Dahlin <jdahlin@async.com.br> * examples/Makefile.am: * examples/option.py: * gobject/Makefile.am: * gobject/gobjectmodule.c: (init_gobject): * gobject/option.py: * gobject/pygobject-private.h: * gobject/pygoptioncontext.c: (pyg_option_context_init), (pyg_option_context_dealloc), (pyg_option_context_parse), (pyg_option_context_set_help_enabled), (pyg_option_context_get_help_enabled), (pyg_option_context_set_ignore_unknown_options), (pyg_option_context_get_ignore_unknown_options), (pyg_option_context_set_main_group), (pyg_option_context_get_main_group), (pyg_option_context_add_group), (pyg_option_context_compare), (pyg_option_context_new): * gobject/pygoptiongroup.c: (check_if_owned), (destroy_g_group), (pyg_option_group_init), (pyg_option_group_dealloc), (arg_func), (pyg_option_group_add_entries), (pyg_option_group_set_translation_domain), (pyg_option_group_compare), (pyg_option_group_transfer_group), (pyg_option_group_new): * tests/test_option.py: Add support for GOption, fixes #163645
Diffstat (limited to 'gobject')
-rw-r--r--gobject/Makefile.am6
-rw-r--r--gobject/gobjectmodule.c17
-rw-r--r--gobject/option.py300
-rw-r--r--gobject/pygobject-private.h23
-rw-r--r--gobject/pygoptioncontext.c332
-rw-r--r--gobject/pygoptiongroup.c344
6 files changed, 1020 insertions, 2 deletions
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index aa7cae7..451fecb 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -9,7 +9,7 @@ pkgpyexecdir = $(pyexecdir)/gtk-2.0
# gobject python scripts
pygobjectdir = $(pkgpyexecdir)/gobject
-pygobject_PYTHON = __init__.py
+pygobject_PYTHON = __init__.py option.py
pygobject_LTLIBRARIES = _gobject.la
@@ -36,7 +36,9 @@ _gobject_la_SOURCES = \
pygpointer.c \
pygiochannel.c \
pygsource.c \
- pygtype.c
+ pygtype.c \
+ pygoptioncontext.c \
+ pygoptiongroup.c
if PLATFORM_WIN32
_gobject_la_CFLAGS += -DPLATFORM_WIN32
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c
index c151a78..eb958b3 100644
--- a/gobject/gobjectmodule.c
+++ b/gobject/gobjectmodule.c
@@ -3101,6 +3101,9 @@ init_gobject(void)
REGISTER_TYPE(d, PyGTimeout_Type, "Timeout");
REGISTER_TYPE(d, PyGPollFD_Type, "PollFD");
+ REGISTER_TYPE(d, PyGOptionContext_Type, "OptionContext");
+ REGISTER_TYPE(d, PyGOptionGroup_Type, "OptionGroup");
+
/* glib version */
tuple = Py_BuildValue ("(iii)", glib_major_version, glib_minor_version,
glib_micro_version);
@@ -3167,7 +3170,21 @@ init_gobject(void)
addint(IO_FLAG_GET_MASK);
addint(IO_FLAG_SET_MASK);
+ addint(OPTION_FLAG_HIDDEN);
+ addint(OPTION_FLAG_IN_MAIN);
+ addint(OPTION_FLAG_REVERSE);
+ addint(OPTION_FLAG_NO_ARG);
+ addint(OPTION_FLAG_FILENAME);
+ addint(OPTION_FLAG_OPTIONAL_ARG);
+ addint(OPTION_FLAG_NOALIAS);
+
+ addint(OPTION_ERROR_UNKNOWN_OPTION);
+ addint(OPTION_ERROR_BAD_VALUE);
+ addint(OPTION_ERROR_FAILED);
+
#undef addint
+
+ PyModule_AddStringConstant(m, "OPTION_REMAINING", G_OPTION_REMAINING);
PyModule_AddIntConstant(m, "SPAWN_LEAVE_DESCRIPTORS_OPEN",
G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
diff --git a/gobject/option.py b/gobject/option.py
new file mode 100644
index 0000000..4abfee4
--- /dev/null
+++ b/gobject/option.py
@@ -0,0 +1,300 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# pygobject - Python bindings for the GObject library
+# Copyright (C) 2006 Johannes Hoelzl
+#
+# gobject/option.py: GOption command line parser
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+"""GOption command line parser
+
+Extends optparse to use the GOptionGroup, GOptionEntry and GOptionContext
+objects. So it is possible to use the gtk, gnome_program and gstreamer command
+line groups and contexts.
+
+Use this interface instead of the raw wrappers of GOptionContext and
+GOptionGroup in gobject.
+"""
+
+import sys
+import optparse
+from optparse import OptionError
+import _gobject as gobject
+
+__all__ = [
+ "OptionError",
+ "Option",
+ "OptionGroup",
+ "OptionParser",
+ "make_option",
+]
+
+class Option(optparse.Option):
+ """Represents a command line option
+
+ To use the extended possibilities of the GOption API Option
+ (and make_option) are extended with new types and attributes.
+
+ Types:
+ filename The supplied arguments are read as filename, GOption
+ parses this type in with the GLib filename encoding.
+
+ Attributes:
+ optional_arg This does not need a arguement, but it can be supplied.
+ hidden The help list does not show this option
+ in_main This option apears in the main group, this should only
+ be used for backwards compatibility.
+
+ Use Option.REMAINING as option name to get all positional arguments.
+
+ NOTE: Every argument to an option is passed as utf-8 coded string, the only
+ exception are options which use the 'filename' type, its arguments
+ are passed as strings in the GLib filename encoding.
+
+ For further help, see optparse.Option.
+ """
+ TYPES = optparse.Option.TYPES + (
+ 'filename',
+ )
+
+ ATTRS = optparse.Option.ATTRS + [
+ 'hidden',
+ 'in_main',
+ 'optional_arg',
+ ]
+
+ REMAINING = '--' + gobject.OPTION_REMAINING
+
+ def __init__(self, *args, **kwargs):
+ optparse.Option.__init__(self, *args, **kwargs)
+ if not self._long_opts:
+ raise ValueError("%s at least one long option name.")
+
+ if len(self._long_opts) < len(self._short_opts):
+ raise ValueError("%s at least more long option names than short option names.")
+
+ if not self.help:
+ raise ValueError("%s needs a help message.", self._long_opts[0])
+
+
+ def _set_opt_string(self, opts):
+ if self.REMAINING in opts:
+ self._long_opts.append(self.REMAINING)
+ optparse.Option._set_opt_string(self, opts)
+ if len(self._short_opts) > len(self._long_opts):
+ raise OptionError("goption.Option needs more long option names "
+ "than short option names")
+
+ def _to_goptionentries(self):
+ flags = 0
+
+ if self.hidden:
+ self.flags |= gobject.OPTION_FLAG_HIDDEN
+
+ if self.in_main:
+ self.flags |= gobject.OPTION_FLAG_IN_MAIN
+
+ if self.takes_value():
+ if self.optional_arg:
+ flags |= gobject.OPTION_FLAG_OPTIONAL_ARG
+ else:
+ flags |= gobject.OPTION_FLAG_NO_ARG
+
+ if self.type == 'filename':
+ flags |= gobject.OPTION_FLAG_FILENAME
+
+ for (long_name, short_name) in zip(self._long_opts, self._short_opts):
+ yield (long_name[2:], short_name[1], flags, self.help, self.metavar)
+
+ for long_name in self._long_opts[len(self._short_opts):]:
+ yield (long_name[2:], '\0', flags, self.help, self.metavar)
+
+class OptionGroup(optparse.OptionGroup):
+ """A group of command line options.
+
+ Arguements:
+ name: The groups name, used to create the --help-{name} option
+ description: Shown as title of the groups help view
+ help_description: Shown as help to the --help-{name} option
+ option_list: The options used in this group, must be option.Option()
+ defaults: A dicitionary of default values
+ translation_domain: Sets the translation domain for gettext().
+
+ NOTE: This OptionGroup does not exactly map the optparse.OptionGroup
+ interface. There is no parser object to supply, but it is possible
+ to set default values and option_lists. Also the default values and
+ values are not shared with the OptionParser.
+
+ To pass a OptionGroup into a function which expects a GOptionGroup (e.g.
+ gnome_program_init() ). OptionGroup.get_option_group() can be used.
+
+ For further help, see optparse.OptionGroup.
+ """
+ def __init__(self, name, description, help_description="",
+ option_list=None, defaults=None,
+ translation_domain=None):
+ optparse.OptionContainer.__init__(self, Option, 'error', description)
+ self.name = name
+ self.parser = None
+ self.help_description = help_description
+ if defaults:
+ self.defaults = defaults
+
+ self.values = None
+
+ self.translation_domain = translation_domain
+
+ for option in option_list:
+ self.add_option(option)
+
+ def _create_option_list(self):
+ self.option_list = []
+ self._create_option_mappings()
+
+ def _to_goptiongroup(self, parser):
+ def callback(option_name, option_value, group):
+ if option_name.startswith('--'):
+ opt = self._long_opt[option_name]
+ else:
+ opt = self._short_opt[option_name]
+ opt.process(option_name, option_value, self.values, parser)
+
+ group = gobject.OptionGroup(self.name, self.description,
+ self.help_description, callback)
+ if self.translation_domain:
+ group.set_translation_domain(self.translation_domain)
+
+ entries = []
+ for option in self.option_list:
+ entries.extend(option._to_goptionentries())
+ group.add_entries(entries)
+
+ return group
+
+ def get_option_group(self, parser = None):
+ """ Returns the corresponding GOptionGroup object.
+
+ Can be used as parameter for gnome_program_init(), gtk_init().
+ """
+ self.set_values_to_defaults()
+ return self._to_goptiongroup(parser)
+
+ def set_values_to_defaults(self):
+ for option in self.option_list:
+ default = self.defaults.get(option.dest)
+ if isinstance(default, basestring):
+ opt_str = option.get_opt_string()
+ self.defaults[option.dest] = option.check_value(opt_str, default)
+ self.values = optparse.Values(self.defaults)
+
+class OptionParser(optparse.OptionParser):
+ """Command line parser with GOption support.
+
+ NOTE: The OptionParser interface is not the exactly the same as the
+ optparse.OptionParser interface. Especially the usage parameter
+ is only used to show the metavar of the arguements.
+
+ Attribues:
+ help_enabled: The --help, --help-all and --help-{group}
+ options are enabled (default).
+ ignore_unknown_options: Do not throw a exception when a option is not
+ knwon, the option will be in the result list.
+
+ OptionParser.add_option_group() does not only accept OptionGroup instances
+ but also gobject.OptionGroup, which is returned by gtk_get_option_group().
+
+ Only gobject.option.OptionGroup and gobject.option.Option instances should
+ be passed as groups and options.
+
+ For further help, see optparse.OptionParser.
+ """
+
+ def __init__(self, *args, **kwargs):
+ if 'option_class' not in kwargs:
+ kwargs['option_class'] = Option
+ self.help_enabled = kwargs.pop('help_enabled', True)
+ self.ignore_unknown_options = kwargs.pop('ignore_unknown_options', False)
+ optparse.OptionParser.__init__(self, add_help_option=False, *args, **kwargs)
+
+ def set_usage(self, usage):
+ if usage is None:
+ self.usage = ''
+ elif usage.startswith("%prog"):
+ self.usage = usage[len("%prog"):]
+ else:
+ self.usage = usage
+
+ def _to_goptioncontext(self, values):
+ if self.description:
+ parameter_string = self.usage + " - " + self.description
+ else:
+ parameter_string = self.usage
+ context = gobject.OptionContext(parameter_string)
+ context.set_help_enabled(self.help_enabled)
+ context.set_ignore_unknown_options(self.ignore_unknown_options)
+
+ for option_group in self.option_groups:
+ if isinstance(option_group, gobject.OptionGroup):
+ g_group = option_group
+ else:
+ g_group = option_group.get_option_group(self)
+ context.add_group(g_group)
+
+ def callback(option_name, option_value, group):
+ if option_name.startswith('--'):
+ opt = self._long_opt[option_name]
+ else:
+ opt = self._short_opt[option_name]
+ opt.process(option_name, option_value, values, self)
+
+ main_group = gobject.OptionGroup(None, None, None, callback)
+ main_entries = []
+ for option in self.option_list:
+ main_entries.extend(option._to_goptionentries())
+ main_group.add_entries(main_entries)
+ context.set_main_group(main_group)
+
+ return context
+
+ def add_option_group(self, *args, **kwargs):
+ if isinstance(args[0], basestring):
+ optparse.OptionParser.add_option_group(self,
+ OptionGroup(self, *args, **kwargs))
+ return
+ elif len(args) == 1 and not kwargs:
+ if isinstance(args[0], OptionGroup):
+ if not args[0].parser:
+ args[0].parser = self
+ if args[0].parser is not self:
+ raise ValueError("invalid OptionGroup (wrong parser)")
+ if isinstance(args[0], gobject.OptionGroup):
+ self.option_groups.append(args[0])
+ return
+ optparse.OptionParser.add_option_group(self, *args, **kwargs)
+
+ def _get_all_options(self):
+ options = self.option_list[:]
+ for group in self.option_groups:
+ if isinstance(group, optparse.OptionGroup):
+ options.extend(group.option_list)
+ return options
+
+ def _process_args(self, largs, rargs, values):
+ context = self._to_goptioncontext(values)
+ largs.extend(context.parse([sys.argv[0]] + rargs))
+
+
+make_option = Option
diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h
index b6f3cd2..20ed244 100644
--- a/gobject/pygobject-private.h
+++ b/gobject/pygobject-private.h
@@ -218,4 +218,27 @@ typedef struct
} PyGPollFD;
+/* pygoption.c */
+extern PyTypeObject PyGOptionContext_Type;
+extern PyTypeObject PyGOptionGroup_Type;
+
+typedef struct {
+ PyObject_HEAD
+ GOptionGroup *group;
+ gboolean other_owner, is_in_context;
+ PyObject *callback;
+ GSList *strings; /* all strings added with the entries, are freed on
+ GOptionGroup.destroy() */
+} PyGOptionGroup;
+
+typedef struct {
+ PyObject_HEAD
+ PyGOptionGroup *main_group;
+ GOptionContext *context;
+} PyGOptionContext;
+
+PyObject * pyg_option_context_new (GOptionContext * context);
+PyObject * pyg_option_group_new (GOptionGroup * group);
+GOptionGroup *pyg_option_group_transfer_group(PyGOptionGroup *self);
+
#endif
diff --git a/gobject/pygoptioncontext.c b/gobject/pygoptioncontext.c
new file mode 100644
index 0000000..6e592f6
--- /dev/null
+++ b/gobject/pygoptioncontext.c
@@ -0,0 +1,332 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * pygtk- Python bindings for the GTK toolkit.
+ * Copyright (C) 2006 Johannes Hoelzl
+ *
+ * pygoptioncontext.c: GOptionContext wrapper
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "pygobject-private.h"
+
+static int
+pyg_option_context_init(PyGOptionContext *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ char *parameter_string;
+ if (!PyArg_ParseTuple(args, "s:gobject.GOptionContext.__init__",
+ &parameter_string))
+ return -1;
+
+ self->context = g_option_context_new(parameter_string);
+ return 0;
+}
+
+static void
+pyg_option_context_dealloc(PyGOptionContext *self)
+{
+ Py_CLEAR(self->main_group);
+
+ if (self->context != NULL)
+ {
+ GOptionContext *tmp = self->context;
+ self->context = NULL;
+ g_option_context_free(tmp);
+ }
+
+ PyObject_Del(self);
+}
+
+static PyObject *
+pyg_option_context_parse(PyGOptionContext *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "argv", NULL };
+ PyObject *arg;
+ PyObject *new_argv, *argv;
+ gssize argv_length, pos;
+ char **argv_content, **original;
+ GError *error = NULL;
+ gboolean result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionContext.parse",
+ kwlist, &argv))
+ return NULL;
+
+ if (!PyList_Check(argv))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "GOptionContext.parse expects a list of strings.");
+ return NULL;
+ }
+
+ argv_length = PyList_Size(argv);
+ if (argv_length == -1)
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "GOptionContext.parse expects a list of strings.");
+ return NULL;
+ }
+
+ argv_content = g_new(char*, argv_length + 1);
+ argv_content[argv_length] = NULL;
+ for (pos = 0; pos < argv_length; pos++)
+ {
+ arg = PyList_GetItem(argv, pos);
+ argv_content[pos] = g_strdup(PyString_AsString(arg));
+ if (argv_content[pos] == NULL)
+ {
+ g_strfreev(argv_content);
+ return NULL;
+ }
+ }
+ original = g_strdupv(argv_content);
+
+ pyg_begin_allow_threads;
+ result = g_option_context_parse(self->context, &argv_length, &argv_content,
+ &error);
+ pyg_end_allow_threads;
+
+ if (!result)
+ {
+ g_free(argv_content);
+ g_strfreev(original);
+ pyg_error_check(&error);
+ return NULL;
+ }
+
+ new_argv = PyList_New(g_strv_length(argv_content));
+ for (pos = 0; pos < argv_length; pos++)
+ {
+ arg = PyString_FromString(argv_content[pos]);
+ PyList_SetItem(new_argv, pos, arg);
+ }
+
+ g_strfreev(original);
+ g_free(argv_content);
+ return new_argv;
+}
+
+static PyObject *
+pyg_option_context_set_help_enabled(PyGOptionContext *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "help_enable", NULL };
+ PyObject *help_enabled;
+ if (! PyArg_ParseTupleAndKeywords(args, kwargs,
+ "O:GOptionContext.set_help_enabled",
+ kwlist, &help_enabled))
+ return NULL;
+ g_option_context_set_help_enabled(self->context, PyObject_IsTrue(help_enabled));
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+pyg_option_context_get_help_enabled(PyGOptionContext *self)
+{
+ return PyBool_FromLong(g_option_context_get_help_enabled(self->context));
+}
+
+static PyObject *
+pyg_option_context_set_ignore_unknown_options(PyGOptionContext *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "ignore_unknown_options", NULL };
+ PyObject *ignore_unknown_options;
+ if (! PyArg_ParseTupleAndKeywords(args, kwargs,
+ "O:GOptionContext.set_ignore_unknown_options",
+ kwlist, &ignore_unknown_options))
+ return NULL;
+ g_option_context_set_ignore_unknown_options(self->context,
+ PyObject_IsTrue(ignore_unknown_options));
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+pyg_option_context_get_ignore_unknown_options(PyGOptionContext *self)
+{
+ return PyBool_FromLong(
+ g_option_context_get_ignore_unknown_options(self->context));
+}
+
+static PyObject *
+pyg_option_context_set_main_group(PyGOptionContext *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "group", NULL };
+ GOptionGroup *g_group;
+ PyObject *group;
+ if (! PyArg_ParseTupleAndKeywords(args, kwargs,
+ "O:GOptionContext.set_main_group",
+ kwlist, &group))
+ return NULL;
+ if (PyObject_IsInstance(group, (PyObject*) &PyGOptionGroup_Type) != 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "GOptionContext.set_main_group expects a GOptionGroup.");
+ return NULL;
+ }
+ g_group = pyg_option_group_transfer_group((PyGOptionGroup*) group);
+ if (g_group == NULL)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Group is already in a OptionContext.");
+ return NULL;
+ }
+
+ g_option_context_set_main_group(self->context, g_group);
+ Py_INCREF(group);
+ self->main_group = (PyGOptionGroup*) group;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+pyg_option_context_get_main_group(PyGOptionContext *self)
+{
+ if (self->main_group == NULL)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ Py_INCREF(self->main_group);
+ return (PyObject*) self->main_group;
+}
+
+static PyObject *
+pyg_option_context_add_group(PyGOptionContext *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "group", NULL };
+ GOptionGroup *g_group;
+ PyObject *group;
+ if (! PyArg_ParseTupleAndKeywords(args, kwargs,
+ "O:GOptionContext.add_group",
+ kwlist, &group))
+ return NULL;
+ if (PyObject_IsInstance(group, (PyObject*) &PyGOptionGroup_Type) != 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "GOptionContext.add_group expects a GOptionGroup.");
+ return NULL;
+ }
+ g_group = pyg_option_group_transfer_group((PyGOptionGroup*) group);
+ if (g_group == NULL)
+ {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Group is already in a OptionContext.");
+ return NULL;
+ }
+ Py_INCREF(group);
+ g_option_context_add_group(self->context, g_group);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static int
+pyg_option_context_compare(PyGOptionContext *self, PyGOptionContext *context)
+{
+ if (self->context == context->context) return 0;
+ if (self->context > context->context)
+ return 1;
+ return -1;
+}
+
+static PyMethodDef pyg_option_context_methods[] = {
+ { "parse", (PyCFunction)pyg_option_context_parse, METH_VARARGS | METH_KEYWORDS },
+ { "set_help_enabled", (PyCFunction)pyg_option_context_set_help_enabled, METH_VARARGS | METH_KEYWORDS },
+ { "get_help_enabled", (PyCFunction)pyg_option_context_get_help_enabled, METH_NOARGS },
+ { "set_ignore_unknown_options", (PyCFunction)pyg_option_context_set_ignore_unknown_options, METH_VARARGS | METH_KEYWORDS },
+ { "get_ignore_unknown_options", (PyCFunction)pyg_option_context_get_ignore_unknown_options, METH_NOARGS },
+ { "set_main_group", (PyCFunction)pyg_option_context_set_main_group, METH_VARARGS | METH_KEYWORDS },
+ { "get_main_group", (PyCFunction)pyg_option_context_get_main_group, METH_NOARGS },
+ { "add_group", (PyCFunction)pyg_option_context_add_group, METH_VARARGS | METH_KEYWORDS },
+ { NULL, NULL, 0 },
+};
+
+PyTypeObject PyGOptionContext_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "gobject.OptionContext",
+ sizeof(PyGMainContext),
+ 0,
+ /* methods */
+ (destructor)pyg_option_context_dealloc,
+ (printfunc)0,
+ (getattrfunc)0,
+ (setattrfunc)0,
+ (cmpfunc)pyg_option_context_compare,
+ (reprfunc)0,
+ 0,
+ 0,
+ 0,
+ (hashfunc)0,
+ (ternaryfunc)0,
+ (reprfunc)0,
+ (getattrofunc)0,
+ (setattrofunc)0,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ NULL,
+ (traverseproc)0,
+ (inquiry)0,
+ (richcmpfunc)0,
+ 0,
+ (getiterfunc)0,
+ (iternextfunc)0,
+ pyg_option_context_methods,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ (descrgetfunc)0,
+ (descrsetfunc)0,
+ 0,
+ (initproc)pyg_option_context_init,
+};
+
+/**
+ * pyg_option_context_new:
+ * @context: a GOptionContext
+ *
+ * Returns: A new GOptionContext wrapper.
+ */
+PyObject *
+pyg_option_context_new (GOptionContext *context)
+{
+ PyGOptionContext *self;
+
+ self = (PyGOptionContext *)PyObject_NEW(PyGOptionContext,
+ &PyGOptionContext_Type);
+ if (self == NULL)
+ return NULL;
+
+ self->context = context;
+ self->main_group = NULL;
+
+ return (PyObject *)self;
+}
diff --git a/gobject/pygoptiongroup.c b/gobject/pygoptiongroup.c
new file mode 100644
index 0000000..4b284c6
--- /dev/null
+++ b/gobject/pygoptiongroup.c
@@ -0,0 +1,344 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * pygtk- Python bindings for the GTK toolkit.
+ * Copyright (C) 2006 Johannes Hoelzl
+ *
+ * pygoptiongroup.c: GOptionContext and GOptionGroup wrapper
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "pygobject-private.h"
+
+static gboolean
+check_if_owned(PyGOptionGroup *self)
+{
+ if (self->other_owner)
+ {
+ PyErr_SetString(PyExc_ValueError, "The GOptionGroup was not created by "
+ "gobject.OptionGroup(), so operation is not possible.");
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static void destroy_g_group(PyGOptionGroup *self)
+{
+ PyGILState_STATE state;
+ state = pyg_gil_state_ensure();
+
+ self->group = NULL;
+ Py_CLEAR(self->callback);
+ g_slist_foreach(self->strings, (GFunc) g_free, NULL);
+ g_slist_free(self->strings);
+ self->strings = NULL;
+
+ if (self->is_in_context)
+ {
+ Py_DECREF(self);
+ }
+
+ pyg_gil_state_release(state);
+}
+
+static int
+pyg_option_group_init(PyGOptionGroup *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "name", "description", "help_description",
+ "callback", NULL };
+ char *name, *description, *help_description;
+ PyObject *callback;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zzzO:GOptionGroup.__init__",
+ kwlist, &name, &description,
+ &help_description, &callback))
+ return -1;
+
+ self->group = g_option_group_new(name, description, help_description,
+ self, (GDestroyNotify) destroy_g_group);
+ self->other_owner = FALSE;
+ self->is_in_context = FALSE;
+
+ Py_INCREF(callback);
+ self->callback = callback;
+
+ return 0;
+}
+
+static void
+pyg_option_group_dealloc(PyGOptionGroup *self)
+{
+ if (!self->other_owner && !self->is_in_context)
+ {
+ GOptionGroup *tmp = self->group;
+ g_assert(tmp != NULL);
+ self->group = NULL;
+ g_option_group_free(tmp);
+ }
+
+ PyObject_Del(self);
+}
+
+static gboolean
+arg_func(const gchar *option_name,
+ const gchar *value,
+ PyGOptionGroup *self,
+ GError *error)
+{
+ PyObject *ret;
+ PyGILState_STATE state;
+
+ state = pyg_gil_state_ensure();
+
+ if (value == NULL)
+ ret = PyObject_CallFunction(self->callback, "sOO",
+ option_name, Py_None, self);
+ else
+ ret = PyObject_CallFunction(self->callback, "ssO",
+ option_name, value, self);
+
+ if (ret == NULL)
+ PyErr_Print();
+
+ pyg_gil_state_release(state);
+
+ if (ret == NULL)
+ return FALSE;
+
+ Py_DECREF(ret);
+ return TRUE;
+}
+
+static PyObject *
+pyg_option_group_add_entries(PyGOptionGroup *self, PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "entries", NULL };
+ gssize entry_count, pos;
+ PyObject *entry_tuple, *list;
+ GOptionEntry *entries;
+
+ if (check_if_owned(self)) return NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionGroup.add_entries",
+ kwlist, &list))
+ return NULL;
+
+ if (!PyList_Check(list))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "GOptionGroup.add_entries expected a list of entries");
+ return NULL;
+ }
+
+ entry_count = PyList_Size(list);
+ if (entry_count == -1)
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "GOptionGroup.add_entries expected a list of entries");
+ return NULL;
+ }
+
+ entries = g_new0(GOptionEntry, entry_count + 1);
+ for (pos = 0; pos < entry_count; pos++)
+ {
+ gchar *long_name, *description, *arg_description;
+ entry_tuple = PyList_GetItem(list, pos);
+ if (!PyTuple_Check(entry_tuple))
+ {
+ PyErr_SetString(PyExc_TypeError, "GOptionGroup.add_entries "
+ "expected a list of entries");
+ g_free(entries);
+ return NULL;
+ }
+ if (!PyArg_ParseTuple(entry_tuple, "scisz",
+ &long_name,
+ &(entries[pos].short_name),
+ &(entries[pos].flags),
+ &description,
+ &arg_description))
+ {
+ PyErr_SetString(PyExc_TypeError, "GOptionGroup.add_entries "
+ "expected a list of entries");
+ g_free(entries);
+ return NULL;
+ }
+ long_name = g_strdup(long_name);
+ self->strings = g_slist_prepend(self->strings, long_name);
+ entries[pos].long_name = long_name;
+
+ description = g_strdup(description);
+ self->strings = g_slist_prepend(self->strings, description);
+ entries[pos].description = description;
+
+ arg_description = g_strdup(arg_description);
+ self->strings = g_slist_prepend(self->strings, arg_description);
+ entries[pos].arg_description = arg_description;
+
+ entries[pos].arg = G_OPTION_ARG_CALLBACK;
+ entries[pos].arg_data = arg_func;
+ }
+
+ g_option_group_add_entries(self->group, entries);
+
+ g_free(entries);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject *
+pyg_option_group_set_translation_domain(PyGOptionGroup *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { "domain", NULL };
+ char *domain;
+ if (check_if_owned(self)) return NULL;
+
+ if (self->group == NULL)
+ {
+ PyErr_SetString(PyExc_RuntimeError,
+ "The corresponding GOptionGroup was already freed, "
+ "probably through the release of GOptionContext");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "z:GOptionGroup.set_translate_domain",
+ kwlist, &domain))
+ return NULL;
+ g_option_group_set_translation_domain(self->group, domain);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static int
+pyg_option_group_compare(PyGOptionGroup *self, PyGOptionGroup *group)
+{
+ if (self->group == group->group) return 0;
+ if (self->group > group->group)
+ return 1;
+ return -1;
+}
+
+static PyMethodDef pyg_option_group_methods[] = {
+ { "add_entries", (PyCFunction)pyg_option_group_add_entries, METH_VARARGS | METH_KEYWORDS },
+ { "set_translation_domain", (PyCFunction)pyg_option_group_set_translation_domain, METH_VARARGS | METH_KEYWORDS },
+ { NULL, NULL, 0 },
+};
+
+PyTypeObject PyGOptionGroup_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "gobject.OptionGroup",
+ sizeof(PyGOptionGroup),
+ 0,
+ /* methods */
+ (destructor)pyg_option_group_dealloc,
+ (printfunc)0,
+ (getattrfunc)0,
+ (setattrfunc)0,
+ (cmpfunc)pyg_option_group_compare,
+ (reprfunc)0,
+ 0,
+ 0,
+ 0,
+ (hashfunc)0,
+ (ternaryfunc)0,
+ (reprfunc)0,
+ (getattrofunc)0,
+ (setattrofunc)0,
+ 0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ NULL,
+ (traverseproc)0,
+ (inquiry)0,
+ (richcmpfunc)0,
+ 0,
+ (getiterfunc)0,
+ (iternextfunc)0,
+ pyg_option_group_methods,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ (descrgetfunc)0,
+ (descrsetfunc)0,
+ 0,
+ (initproc)pyg_option_group_init,
+};
+
+/**
+ * pyg_option_group_transfer_group:
+ * @group: a GOptionGroup wrapper
+ *
+ * This is used to transfer the GOptionGroup to a GOptionContext. After this
+ * is called, the calle must handle the release of the GOptionGroup.
+ *
+ * When #NULL is returned, the GOptionGroup was already transfered.
+ *
+ * Returns: Either #NULL or the wrapped GOptionGroup.
+ */
+GOptionGroup *
+pyg_option_group_transfer_group(PyGOptionGroup *self)
+{
+ if (self->is_in_context) return NULL;
+ self->is_in_context = TRUE;
+
+ /* Here we increase the reference count of the PyGOptionGroup, because now
+ * the GOptionContext holds an reference to us (it is the userdata passed
+ * to g_option_group_new().
+ *
+ * The GOptionGroup is freed with the GOptionContext.
+ *
+ * We set it here because if we would do this in the init method we would
+ * hold two references and the PyGOptionGroup would never be freed.
+ */
+ Py_INCREF(self);
+
+ return self->group;
+}
+
+/**
+ * pyg_option_group_new:
+ * @group: a GOptionGroup
+ *
+ * The returned GOptionGroup can't be used to set any hooks, translation domains
+ * or add entries. It's only intend is, to use for GOptionContext.add_group().
+ *
+ * Returns: the GOptionGroup wrapper.
+ */
+PyObject *
+pyg_option_group_new (GOptionGroup *group)
+{
+ PyGOptionGroup *self;
+
+ self = (PyGOptionGroup *)PyObject_NEW(PyGOptionGroup,
+ &PyGOptionGroup_Type);
+ if (self == NULL)
+ return NULL;
+
+ self->group = group;
+ self->other_owner = TRUE;
+ self->is_in_context = FALSE;
+
+ return (PyObject *)self;
+}