summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjell.ahlstedt@bredband.net>2014-05-12 19:56:44 +0200
committerKjell Ahlstedt <kjell.ahlstedt@bredband.net>2014-05-12 19:56:44 +0200
commit122282ab161dfd4fdca75406308291c5599fd990 (patch)
tree34eacea54a59f8740c5deb11e115efbaec80b76d
parent149cf07c6952a876f2a7946508bc18de7dfcbc30 (diff)
downloadglibmm-122282ab161dfd4fdca75406308291c5599fd990.tar.gz
Gio::Application: Add add_main_option_entry() and enum OptionType
* gio/src/application.[hg|ccg]: Add add_main_option_entry() and enum Application::OptionType. Bug #727822.
-rw-r--r--gio/src/application.ccg78
-rw-r--r--gio/src/application.hg106
2 files changed, 166 insertions, 18 deletions
diff --git a/gio/src/application.ccg b/gio/src/application.ccg
index 0ca8245d..a04d9ba5 100644
--- a/gio/src/application.ccg
+++ b/gio/src/application.ccg
@@ -22,9 +22,38 @@
#include <giomm/actiongroup.h>
#include <giomm/init.h>
#include <cstring> // std::memset()
+#include <vector>
-namespace
+namespace // anonymous
{
+//TODO: At the next ABI break, implement the pimpl idiom. Then we need not use
+// a GQuark for ExtraApplicationData, which should be renamed to
+// struct Gio::Application::Impl.
+// These are new data members that can't be added to Gio::Application now,
+// because it would break ABI.
+struct ExtraApplicationData
+{
+ std::vector<gchar*> option_entry_strings;
+
+ ~ExtraApplicationData()
+ {
+ for (std::vector<gchar*>::iterator iter = option_entry_strings.begin();
+ iter != option_entry_strings.end(); ++iter)
+ {
+ g_free(*iter);
+ *iter = 0;
+ }
+ }
+};
+
+GQuark quark_extra_application_data =
+ g_quark_from_static_string("glibmm__Gio::Application::quark_extra_application_data");
+
+void Application_delete_extra_application_data(gpointer data)
+{
+ ExtraApplicationData* extra_application_data = static_cast<ExtraApplicationData*>(data);
+ delete extra_application_data;
+}
static void Application_signal_open_callback(GApplication* self, GFile** files,
gint n_files, const gchar* hint, void* data)
@@ -99,7 +128,7 @@ static const Glib::SignalProxyInfo Application_signal_open_info =
(GCallback) &Application_signal_open_notify_callback
};
-}
+} // anonymous namespace
namespace Gio
{
@@ -208,16 +237,49 @@ void Application::open(const Glib::RefPtr<Gio::File>& file, const Glib::ustring&
open(files, hint);
}
-/*
-void Application::add_main_option_entry(Glib::OptionEntry& entry)
+void Application::add_main_option_entry(OptionType arg_type, const Glib::ustring& long_name,
+ gchar short_name, const Glib::ustring& description, const Glib::ustring& arg_description, int flags)
{
- //Create a temporary array, just so we can give the correct thing to g_application_add_main_option_entries():
+ // Create a temporary array, just so we can give the correct thing to g_application_add_main_option_entries():
GOptionEntry array[2];
- array[0] = *(entry.gobj()); //Copy contents.
- std::memset(&array[1], 0, sizeof(GOptionEntry));
+ std::memset(array, 0, 2 * sizeof(GOptionEntry)); // null-termination
+
+ // g_application_add_main_option_entries() does not take its own copy
+ // of the strings. We must keep them alive, and keep pointers to them,
+ // so we can delete them when the Application instance is deleted.
+
+ // GOptionEntry.long_name must be set, even if it's an empty string.
+ gchar* lname = g_strdup(long_name.c_str());
+ gchar* desc = description.empty() ? 0 : g_strdup(description.c_str());
+ gchar* arg_desc = arg_description.empty() ? 0 : g_strdup(arg_description.c_str());
+
+ ExtraApplicationData* extra_application_data =
+ static_cast<ExtraApplicationData*>(g_object_get_qdata(gobject_, quark_extra_application_data));
+ if (!extra_application_data)
+ {
+ extra_application_data = new ExtraApplicationData();
+ g_object_set_qdata_full(gobject_, quark_extra_application_data, extra_application_data,
+ Application_delete_extra_application_data);
+ }
+
+ extra_application_data->option_entry_strings.push_back(lname);
+ if (desc)
+ extra_application_data->option_entry_strings.push_back(desc);
+ if (arg_desc)
+ extra_application_data->option_entry_strings.push_back(arg_desc);
+
+ // Fill in array[0].
+ array[0].arg = (GOptionArg)arg_type;
+ array[0].long_name = lname;
+ array[0].short_name = short_name;
+ array[0].description = desc;
+ array[0].arg_description = arg_desc;
+ array[0].flags = flags;
+ // We ensure that this is null to ensure that it is not used,
+ // telling GApplication to put the parsed value in the options VariantDict instead.
+ array[0].arg_data = 0;
g_application_add_main_option_entries(gobj(), array);
}
-*/
} // namespace Gio
diff --git a/gio/src/application.hg b/gio/src/application.hg
index ac96e0cb..e926744e 100644
--- a/gio/src/application.hg
+++ b/gio/src/application.hg
@@ -27,7 +27,7 @@
#include <giomm/applicationcommandline.h>
#include <giomm/file.h>
#include <glibmm/object.h>
-//#include <glibmm/optiongroup.h>
+#include <glibmm/optionentry.h>
#include <glibmm/variant.h>
#include <glibmm/variantdict.h>
#include <giomm/dbusconnection.h>
@@ -104,6 +104,31 @@ protected:
_IGNORE(g_application_new)
public:
+ /** The OptionType enum values determine the expected type of a command line option.
+ * If an option expects an extra argument, it can be specified in several ways;
+ * with a short option: "-x arg", with a long option: "--name arg" or combined
+ * in a single argument: "--name=arg". All option types except OPTION_TYPE_BOOL
+ * expect an extra argument. OPTION_TYPE_STRING_VECTOR and
+ * OPTION_TYPE_FILENAME_VECTOR accept more than one extra argument.
+ *
+ * The descriptions of the enum values show what type of Glib::Variant<>
+ * is stored in a Glib::VariantDict.
+ *
+ * @ingroup glibmmEnums
+ */
+ enum OptionType
+ {
+ OPTION_TYPE_BOOL, ///< bool
+ OPTION_TYPE_STRING, ///< Glib::ustring
+ OPTION_TYPE_INT, ///< gint32
+ //OPTION_TYPE_CALLBACK,
+ OPTION_TYPE_FILENAME = OPTION_TYPE_INT+2, ///< std::string
+ OPTION_TYPE_STRING_VECTOR, ///< std::vector<Glib::ustring>
+ OPTION_TYPE_FILENAME_VECTOR, ///< std::vector<std::string>
+ OPTION_TYPE_DOUBLE, ///< double
+ OPTION_TYPE_INT64 ///< gint64
+ };
+
/** Creates an application instance.
* If no application ID is given then some features (most notably application uniqueness) will be disabled.
*
@@ -131,16 +156,78 @@ public:
_WRAP_METHOD(void set_action_group(const Glib::RefPtr<ActionGroup>& action_group), g_application_set_action_group)
-
- //TODO: We need to be able to add a group, not just some entries,
+ //Note: We would like to add a group, not just some entries,
//so we can do pre and post parsing. See https://bugzilla.gnome.org/show_bug.cgi?id=727602
- //
- //TODO: Custom write the documentation for this method?
- //_WRAP_METHOD_DOCS_ONLY(g_application_add_main_option_entries)
- //void add_main_option_entry(Glib::OptionEntry& entry);
- //_IGNORE(g_application_add_main_option_entries)
+ //but instead we need to use the VariantDict passed to the handle_local_options signal
+ //and provided by ApplicationCommandLine::get_options_dict() in on_command_line().
+
+ /** Adds a main option entry to be handled by the Application.
+ *
+ * This function is comparable to Glib::OptionGroup::add_entry() +
+ * Glib::OptionContext::set_main_group().
+ *
+ * After the commandline arguments are parsed, the
+ * signal_handle_local_options() signal will be emitted. At this
+ * point, the application can inspect the parsed values.
+ *
+ * Unlike OptionGroup + OptionContext, Application packs the arguments
+ * into a Glib::VariantDict which is passed to the
+ * signal_handle_local_options() handler, where it can be
+ * inspected and modified. If Gio::APPLICATION_HANDLES_COMMAND_LINE is
+ * set, then the resulting dictionary is sent to the primary instance,
+ * where Gio::ApplicationCommandLine::get_options_dict() will return it.
+ * This "packing" is done according to the type of the argument --
+ * booleans for normal flags, Glib::ustring's for strings, std::string's for
+ * filenames, etc. The packing only occurs if the flag is given (ie: we
+ * do not pack a "false" Variant in the case that a flag is missing).
+ *
+ * In general, it is recommended that all commandline arguments are
+ * parsed locally. The options dictionary should then be used to
+ * transmit the result of the parsing to the primary instance, where
+ * Glib::VariantDict::lookup_value() can be used. For local options, it is
+ * possible to consult (and potentially remove) the option from the options dictionary.
+ *
+ * This function is new in GLib 2.40. Before then, the only real choice
+ * was to send all of the commandline arguments (options and all) to the
+ * primary instance for handling. Application ignored them completely
+ * on the local side. Calling this function "opts in" to the new
+ * behaviour, and in particular, means that unrecognised options will be
+ * treated as errors. Unrecognised options have never been ignored when
+ * Gio::APPLICATION_HANDLES_COMMAND_LINE is unset.
+ *
+ * If signal_handle_local_options() needs to see the list of
+ * filenames, then the use of G_OPTION_REMAINING as @a long_name is recommended.
+ * G_OPTION_REMAINING can be used as a key into
+ * the options dictionary. If you do use G_OPTION_REMAINING then you
+ * need to handle these arguments for yourself because once they are
+ * consumed, they will no longer be visible to the default handling
+ * (which treats them as filenames to be opened).
+ *
+ * @newin{2,42}
+ *
+ * @param arg_type A Gio::Application::OptionType.
+ * @param long_name The long name of an option can be used to specify it
+ * in a commandline as `--long_name`. Every option must have a
+ * long name.
+ * @param short_name If an option has a short name, it can be specified
+ * `-short_name` in a commandline. @a short_name must be a printable
+ * ASCII character different from '-', or '\0' if the option has no
+ * short name.
+ * @param description The description for the option in `--help` output.
+ * @param arg_description The placeholder to use for the extra argument parsed
+ * by the option in `--help` output.
+ * @param flags Flags from Glib::OptionEntry::Flags. Do not set FLAG_FILENAME.
+ * Character encoding is chosen with @a arg_type.
+ */
+ void add_main_option_entry(OptionType arg_type, const Glib::ustring& long_name,
+ gchar short_name = '\0', const Glib::ustring& description = Glib::ustring(),
+ const Glib::ustring& arg_description = Glib::ustring(), int flags = 0);
+ _IGNORE(g_application_add_main_option_entries)
- //TODO: _WRAP_METHOD(void add_option_group(Glib::OptionGroup& group), g_application_add_option_group)
+ // _WRAP_METHOD(void add_option_group(Glib::OptionGroup& group), g_application_add_option_group)
+ // add_option_group() is probably not very useful. If implemented, it must probably
+ // be custom-implemented. See https://bugzilla.gnome.org/show_bug.cgi?id=727822#c10
+ _IGNORE(g_application_add_option_group)
_WRAP_METHOD(bool is_registered() const, g_application_get_is_registered)
_WRAP_METHOD(bool is_remote() const, g_application_get_is_remote)
@@ -274,5 +361,4 @@ private:
const Glib::Class& custom_class_init();
};
-
} // namespace Gio